Implementation of the Digest HTTP headers according to RFC 3230.
Project description
Introduction
A small library to provide the server and client side methods to require, negotiation and generate Digest HTTP headers as per RFC 3230.
Clients can generate Digest headers of the form: Digest: SHA-256=xyz, MD5=abc. Server can require certain algorithms by sending Want-Digest headers of the form: Want-Digest: SHA-256, SHA;q=0.5, MD5;q=0.
Installation
Install using pip:
pip install rfc3230-digest-headers
Overview of the protocol
The protocol works as follows:
- Client and server agree on what the
instancebytes are for the endpoint in question. Usually the request body or the content of the resource before applying transformations. - Client sends request
- If the client did not directly send a valid
Digest, the server responds withWant-Digestheader to indicate which algorithms it supports.- Form of the
Want-Digestheader:Want-Digest: SHA-256, SHA;q=0.5, MD5;q=0 - The server can specify
qvaluesto indicate preference of algorithms. - No value equals
q=1.0. q=0means "do not use this algorithm".
- Form of the
- Client generates
Digestheader using one of the supported algorithms and sends it in the request.- Form of the
Digestheader:Digest: SHA-256=xyz, MD5=abc
- Form of the
- Server verifies the
Digestheader and processes the request.
Usage
The library provides only one enum class, DigestHeaderAlgorithm, which can be used by server and client to fully specify, negotiate and generate Digest HTTP headers.
You do not use these algorithms directly, but instead have to use a couple of static methods provided by the enum class.
Example: Generate a Digest header
The client generates a Digest for their instance.
from rfc3230_digest_headers import DigestHeaderAlgorithm
instance_bytes = b"Hello, World!"
header = DigestHeaderAlgorithm.make_digest_header(
instance=instance_bytes,
algorithms=[DigestHeaderAlgorithm.SHA256, DigestHeaderAlgorithm.MD5]
)
print(header.header_name) # "Digest"
print(header.header_value) # "SHA-256=..., MD5=..."
Usage: Verify a Digest header
The server receives a request with a Digest header and verifies it.
from rfc3230_digest_headers import DigestHeaderAlgorithm
instance_bytes = b"Hello, World!"
request_headers = {"Digest": "SHA-256=..., MD5=..."}
is_valid, want_digest_header_should_be_added = DigestHeaderAlgorithm.verify_request(
request_headers=request_headers,
instance=instance_bytes,
qvalues={
DigestHeaderAlgorithm.SHA256: 1.0,
DigestHeaderAlgorithm.SHA: 0.5,
DigestHeaderAlgorithm.MD5: 0.0 # If the client sends MD5, they will receive an error
},
)
print(is_valid) # True if the Digest header is valid
print(want_digest_header_should_be_added) # None if valid, otherwise contains the `Want-Digest` header to be sent to the client for negotiation
Usage: Server-side negotiation of algorithms
The server can indicate which algorithms the endpoint requires by sending a Want-Digest header. The header is automatically generated when attempting to verify invalid request headers. In the following example, the client sends a Digest header with an unsupported algorithm (MD5 with a q-value of 0.0), so the server responds with a Want-Digest header indicating which algorithms are supported.
from rfc3230_digest_headers import DigestHeaderAlgorithm
# Fake request from client without an invalid Digest header
instance_bytes = b"Hello, World!"
request_headers = {"Digest": "SHA-256=..., MD5=..."}
is_valid, want_digest_header_should_be_added = DigestHeaderAlgorithm.verify_request(
request_headers=request_headers,
instance=instance_bytes,
qvalues={
DigestHeaderAlgorithm.SHA256: 1.0,
DigestHeaderAlgorithm.SHA: 0.5,
DigestHeaderAlgorithm.MD5: 0.0 # If the client sends MD5, they will receive an error
},
)
if want_digest_header_should_be_added:
print(want_digest_header_should_be_added.header_name) # "Want-Digest"
print(want_digest_header_should_be_added.header_value) # "SHA-256, SHA;q=0.5, MD5;q=0"
# Send the response with the generated Want-Digest header
...
Usage: Client-side negotiation of algorithms
When an endpoint responds with a Want-Digest header, the client can parse it and generate a valid Digest header. In the following example, imagine that we initially sent a request with b'Hello, World!' as body, and the server responded with an HTTP error code and a Want-Digest header. The client sees that its original request failed, and that the server wants a Digest header. The client then generates a valid Digest header using the highest priority algorithm from the Want-Digest header and re-sends the request.
from rfc3230_digest_headers import DigestHeaderAlgorithm
# Fake response from server with Want-Digest header
instance_bytes = b"Hello, World!"
want_digest_header_value = "SHA-256, SHA;q=0.5, MD5;q=0"
# Parse the response and generate a valid Digest header (if possible)
header = DigestHeaderAlgorithm.handle_want_digest_header(
instance=instance_bytes,
want_digest_header=want_digest_header_value,
algorithms="auto" # Use the highest priority algorithm from Want-Digest
)
print(header.header_name) # "Digest"
print(header.header_value) # "sha-256=..."
# re-send the request with the generated Digest header
...
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file rfc3230_digest_headers-1.0.2.tar.gz.
File metadata
- Download URL: rfc3230_digest_headers-1.0.2.tar.gz
- Upload date:
- Size: 8.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4e8b17c086ab5a371cdb9807e165febb66c5c27cb348f02f73daef2af944c0f1
|
|
| MD5 |
20005ed5560e829c6135c009edf9a8c2
|
|
| BLAKE2b-256 |
c5cb1465d26249dbff41d2a78aa45b5884becbb9f6280767d392acc4843bc685
|
Provenance
The following attestation bundles were made for rfc3230_digest_headers-1.0.2.tar.gz:
Publisher:
publish.yml on Mari6814/py-rfc3230-digest-headers
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rfc3230_digest_headers-1.0.2.tar.gz -
Subject digest:
4e8b17c086ab5a371cdb9807e165febb66c5c27cb348f02f73daef2af944c0f1 - Sigstore transparency entry: 543405739
- Sigstore integration time:
-
Permalink:
Mari6814/py-rfc3230-digest-headers@851908674fecb0b666d7008a400b61c59596ac8f -
Branch / Tag:
refs/tags/v1.0.2 - Owner: https://github.com/Mari6814
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@851908674fecb0b666d7008a400b61c59596ac8f -
Trigger Event:
release
-
Statement type:
File details
Details for the file rfc3230_digest_headers-1.0.2-py3-none-any.whl.
File metadata
- Download URL: rfc3230_digest_headers-1.0.2-py3-none-any.whl
- Upload date:
- Size: 12.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4958ea6fa7a459b3bb16f36a6eb68b2b46374c301199c37f6c35cb8b8a5453ac
|
|
| MD5 |
da1fe9b84e29ca193fef33be8a7105be
|
|
| BLAKE2b-256 |
4a2d149a833bea2664df3bc987168c11f7590dc9416c05455347f0cb71d8ec0c
|
Provenance
The following attestation bundles were made for rfc3230_digest_headers-1.0.2-py3-none-any.whl:
Publisher:
publish.yml on Mari6814/py-rfc3230-digest-headers
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rfc3230_digest_headers-1.0.2-py3-none-any.whl -
Subject digest:
4958ea6fa7a459b3bb16f36a6eb68b2b46374c301199c37f6c35cb8b8a5453ac - Sigstore transparency entry: 543405743
- Sigstore integration time:
-
Permalink:
Mari6814/py-rfc3230-digest-headers@851908674fecb0b666d7008a400b61c59596ac8f -
Branch / Tag:
refs/tags/v1.0.2 - Owner: https://github.com/Mari6814
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@851908674fecb0b666d7008a400b61c59596ac8f -
Trigger Event:
release
-
Statement type: