http-fields 0.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- http_fields/__init__.py +193 -0
- http_fields/accept.py +37 -0
- http_fields/acceptcharset.py +48 -0
- http_fields/acceptencoding.py +42 -0
- http_fields/acceptlanguage.py +47 -0
- http_fields/acceptranges.py +35 -0
- http_fields/accesscontrol.py +197 -0
- http_fields/age.py +34 -0
- http_fields/allow.py +46 -0
- http_fields/altsvc.py +70 -0
- http_fields/authbases.py +79 -0
- http_fields/authenticationinfo.py +19 -0
- http_fields/authorization.py +23 -0
- http_fields/cachecontrol.py +119 -0
- http_fields/cachestatus.py +12 -0
- http_fields/connection.py +35 -0
- http_fields/contentdigest.py +19 -0
- http_fields/contentdisposition.py +66 -0
- http_fields/contentencoding.py +45 -0
- http_fields/contentlanguage.py +38 -0
- http_fields/contentlength.py +34 -0
- http_fields/contentlocation.py +24 -0
- http_fields/contentrange.py +74 -0
- http_fields/contenttype.py +104 -0
- http_fields/cookie.py +38 -0
- http_fields/date.py +17 -0
- http_fields/dateheader.py +32 -0
- http_fields/entitytaglist.py +39 -0
- http_fields/etag.py +46 -0
- http_fields/expect.py +52 -0
- http_fields/expires.py +17 -0
- http_fields/forwarded.py +36 -0
- http_fields/fromheader.py +42 -0
- http_fields/header.py +250 -0
- http_fields/host.py +44 -0
- http_fields/ifmatch.py +24 -0
- http_fields/ifmodifiedsince.py +17 -0
- http_fields/ifnonematch.py +24 -0
- http_fields/ifrange.py +49 -0
- http_fields/ifunmodifiedsince.py +17 -0
- http_fields/lastmodified.py +17 -0
- http_fields/link.py +35 -0
- http_fields/location.py +24 -0
- http_fields/maxforwards.py +32 -0
- http_fields/origin.py +42 -0
- http_fields/parsedobjs.py +62 -0
- http_fields/prefer.py +64 -0
- http_fields/priority.py +55 -0
- http_fields/productlistheader.py +33 -0
- http_fields/proxyauthenticate.py +17 -0
- http_fields/proxyauthenticationinfo.py +17 -0
- http_fields/proxyauthorization.py +17 -0
- http_fields/proxystatus.py +12 -0
- http_fields/py.typed +0 -0
- http_fields/range.py +37 -0
- http_fields/referer.py +24 -0
- http_fields/retryafter.py +45 -0
- http_fields/server.py +18 -0
- http_fields/setcookie.py +419 -0
- http_fields/stricttransportsecurity.py +96 -0
- http_fields/structuredfields.py +356 -0
- http_fields/structuredheaders.py +90 -0
- http_fields/te.py +36 -0
- http_fields/trailer.py +44 -0
- http_fields/upgrade.py +35 -0
- http_fields/uriheader.py +36 -0
- http_fields/useragent.py +18 -0
- http_fields/vary.py +40 -0
- http_fields/via.py +35 -0
- http_fields/visitors/__init__.py +1 -0
- http_fields/visitors/rfc3986.py +195 -0
- http_fields/visitors/rfc6265.py +62 -0
- http_fields/visitors/rfc6266.py +234 -0
- http_fields/visitors/rfc7230.py +80 -0
- http_fields/visitors/rfc7239.py +43 -0
- http_fields/visitors/rfc7240.py +77 -0
- http_fields/visitors/rfc7838.py +77 -0
- http_fields/visitors/rfc8288.py +56 -0
- http_fields/visitors/rfc9110/__init__.py +117 -0
- http_fields/visitors/rfc9110/_base.py +71 -0
- http_fields/visitors/rfc9110/accept.py +135 -0
- http_fields/visitors/rfc9110/acceptcharset.py +26 -0
- http_fields/visitors/rfc9110/acceptencoding.py +76 -0
- http_fields/visitors/rfc9110/acceptlanguage.py +55 -0
- http_fields/visitors/rfc9110/acceptranges.py +13 -0
- http_fields/visitors/rfc9110/allow.py +13 -0
- http_fields/visitors/rfc9110/authenticationinfo.py +19 -0
- http_fields/visitors/rfc9110/authorization.py +77 -0
- http_fields/visitors/rfc9110/authparam.py +40 -0
- http_fields/visitors/rfc9110/authscheme.py +17 -0
- http_fields/visitors/rfc9110/challenge.py +57 -0
- http_fields/visitors/rfc9110/comment.py +99 -0
- http_fields/visitors/rfc9110/connection.py +13 -0
- http_fields/visitors/rfc9110/contentlanguage.py +21 -0
- http_fields/visitors/rfc9110/contentlength.py +9 -0
- http_fields/visitors/rfc9110/contentrange.py +70 -0
- http_fields/visitors/rfc9110/contenttype.py +52 -0
- http_fields/visitors/rfc9110/date.py +12 -0
- http_fields/visitors/rfc9110/entitytag.py +66 -0
- http_fields/visitors/rfc9110/etag.py +12 -0
- http_fields/visitors/rfc9110/field.py +15 -0
- http_fields/visitors/rfc9110/host.py +32 -0
- http_fields/visitors/rfc9110/httpdate.py +167 -0
- http_fields/visitors/rfc9110/ifmatch.py +24 -0
- http_fields/visitors/rfc9110/ifmodifiedsince.py +12 -0
- http_fields/visitors/rfc9110/ifnonematch.py +26 -0
- http_fields/visitors/rfc9110/ifunmodifiedsince.py +12 -0
- http_fields/visitors/rfc9110/lastmodified.py +14 -0
- http_fields/visitors/rfc9110/location.py +9 -0
- http_fields/visitors/rfc9110/parameters.py +124 -0
- http_fields/visitors/rfc9110/product.py +39 -0
- http_fields/visitors/rfc9110/quotedstring.py +66 -0
- http_fields/visitors/rfc9110/range.py +100 -0
- http_fields/visitors/rfc9110/rangeunit.py +17 -0
- http_fields/visitors/rfc9110/retryafter.py +20 -0
- http_fields/visitors/rfc9110/server.py +16 -0
- http_fields/visitors/rfc9110/te.py +83 -0
- http_fields/visitors/rfc9110/token.py +18 -0
- http_fields/visitors/rfc9110/token68.py +18 -0
- http_fields/visitors/rfc9110/type.py +17 -0
- http_fields/visitors/rfc9110/upgrade.py +57 -0
- http_fields/visitors/rfc9110/useragent.py +16 -0
- http_fields/visitors/rfc9110/vary.py +10 -0
- http_fields/visitors/rfc9110/via.py +86 -0
- http_fields/visitors/rfc9110/weight.py +40 -0
- http_fields/visitors/rfc9110/wwwauthenticate.py +21 -0
- http_fields/visitors/rfc9111.py +92 -0
- http_fields/wwwauthenticate.py +24 -0
- http_fields-0.1.1.dist-info/METADATA +88 -0
- http_fields-0.1.1.dist-info/RECORD +132 -0
- http_fields-0.1.1.dist-info/WHEEL +4 -0
- http_fields-0.1.1.dist-info/licenses/LICENSE.txt +16 -0
http_fields/__init__.py
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
"""Header classes. All classes intended for public use are imported here."""
|
|
2
|
+
|
|
3
|
+
__all__ = [
|
|
4
|
+
"Accept",
|
|
5
|
+
"AcceptCharset",
|
|
6
|
+
"AcceptLanguage",
|
|
7
|
+
"AcceptEncoding",
|
|
8
|
+
"AcceptRanges",
|
|
9
|
+
"AccessControlAllowCredentials",
|
|
10
|
+
"AccessControlAllowHeaders",
|
|
11
|
+
"AccessControlAllowMethods",
|
|
12
|
+
"AccessControlAllowOrigin",
|
|
13
|
+
"AccessControlExposeHeaders",
|
|
14
|
+
"AccessControlMaxAge",
|
|
15
|
+
"AccessControlRequestHeaders",
|
|
16
|
+
"AccessControlRequestMethod",
|
|
17
|
+
"Age",
|
|
18
|
+
"Allow",
|
|
19
|
+
"AltSvc",
|
|
20
|
+
"AltUsed",
|
|
21
|
+
"AuthenticationInfo",
|
|
22
|
+
"Authorization",
|
|
23
|
+
"AuthParam",
|
|
24
|
+
"CacheControl",
|
|
25
|
+
"CacheDirective",
|
|
26
|
+
"CacheStatus",
|
|
27
|
+
"Connection",
|
|
28
|
+
"ContentDigest",
|
|
29
|
+
"ContentDisposition",
|
|
30
|
+
"ContentEncoding",
|
|
31
|
+
"ContentLanguage",
|
|
32
|
+
"ContentLength",
|
|
33
|
+
"ContentLocation",
|
|
34
|
+
"ContentRange",
|
|
35
|
+
"ContentType",
|
|
36
|
+
"Cookie",
|
|
37
|
+
"CustomHeader",
|
|
38
|
+
"Date",
|
|
39
|
+
"EntityTag",
|
|
40
|
+
"ETag",
|
|
41
|
+
"Expect",
|
|
42
|
+
"Expires",
|
|
43
|
+
"Forwarded",
|
|
44
|
+
"From",
|
|
45
|
+
"Header",
|
|
46
|
+
"Host",
|
|
47
|
+
"IfMatch",
|
|
48
|
+
"IfModifiedSince",
|
|
49
|
+
"IfNoneMatch",
|
|
50
|
+
"IfRange",
|
|
51
|
+
"IfUnmodifiedSince",
|
|
52
|
+
"LanguageTag",
|
|
53
|
+
"LastModified",
|
|
54
|
+
"Link",
|
|
55
|
+
"Location",
|
|
56
|
+
"MaxForwards",
|
|
57
|
+
"MediaType",
|
|
58
|
+
"Origin",
|
|
59
|
+
"Prefer",
|
|
60
|
+
"PreferenceApplied",
|
|
61
|
+
"Priority",
|
|
62
|
+
"RangeUnit",
|
|
63
|
+
"NonNegativeInt",
|
|
64
|
+
"Protocol",
|
|
65
|
+
"ProxyAuthenticate",
|
|
66
|
+
"ProxyAuthenticationInfo",
|
|
67
|
+
"ProxyAuthorization",
|
|
68
|
+
"ProxyStatus",
|
|
69
|
+
"Range",
|
|
70
|
+
"Referer",
|
|
71
|
+
"ReprDigest",
|
|
72
|
+
"RetryAfter",
|
|
73
|
+
"Server",
|
|
74
|
+
"SetCookie",
|
|
75
|
+
"StrictTransportSecurity",
|
|
76
|
+
"TCoding",
|
|
77
|
+
"TE",
|
|
78
|
+
"Trailer",
|
|
79
|
+
"Upgrade",
|
|
80
|
+
"UserAgent",
|
|
81
|
+
"Vary",
|
|
82
|
+
"Via",
|
|
83
|
+
"WWWAuthenticate",
|
|
84
|
+
"ExtValue",
|
|
85
|
+
"CookiePair",
|
|
86
|
+
"AltValue",
|
|
87
|
+
"ForwardedElement",
|
|
88
|
+
"IntRange",
|
|
89
|
+
"LinkValue",
|
|
90
|
+
"Preference",
|
|
91
|
+
"SuffixRange",
|
|
92
|
+
"ViaElement",
|
|
93
|
+
"WeightedCoding",
|
|
94
|
+
"WeightedLanguageRange",
|
|
95
|
+
# Leaf types for strict list-header construction (e.g. Connection(Token("keep-alive"))).
|
|
96
|
+
"CorsFieldName",
|
|
97
|
+
"CorsMethod",
|
|
98
|
+
"Expectation",
|
|
99
|
+
"FieldName",
|
|
100
|
+
"Method",
|
|
101
|
+
"Token",
|
|
102
|
+
]
|
|
103
|
+
|
|
104
|
+
from http_fields.accept import Accept
|
|
105
|
+
from http_fields.acceptcharset import AcceptCharset
|
|
106
|
+
from http_fields.acceptencoding import AcceptEncoding, WeightedCoding
|
|
107
|
+
from http_fields.acceptlanguage import AcceptLanguage
|
|
108
|
+
from http_fields.acceptranges import AcceptRanges
|
|
109
|
+
from http_fields.accesscontrol import (
|
|
110
|
+
AccessControlAllowCredentials,
|
|
111
|
+
AccessControlAllowHeaders,
|
|
112
|
+
AccessControlAllowMethods,
|
|
113
|
+
AccessControlAllowOrigin,
|
|
114
|
+
AccessControlExposeHeaders,
|
|
115
|
+
AccessControlMaxAge,
|
|
116
|
+
AccessControlRequestHeaders,
|
|
117
|
+
AccessControlRequestMethod,
|
|
118
|
+
CorsFieldName,
|
|
119
|
+
CorsMethod,
|
|
120
|
+
)
|
|
121
|
+
from http_fields.age import Age
|
|
122
|
+
from http_fields.allow import Allow, Method
|
|
123
|
+
from http_fields.altsvc import AltSvc, AltUsed
|
|
124
|
+
from http_fields.authenticationinfo import AuthenticationInfo
|
|
125
|
+
from http_fields.authorization import Authorization
|
|
126
|
+
from http_fields.cachecontrol import CacheControl, CacheDirective
|
|
127
|
+
from http_fields.cachestatus import CacheStatus
|
|
128
|
+
from http_fields.connection import Connection
|
|
129
|
+
from http_fields.contentdigest import ContentDigest, ReprDigest
|
|
130
|
+
from http_fields.contentdisposition import ContentDisposition, ExtValue
|
|
131
|
+
from http_fields.contentencoding import ContentEncoding
|
|
132
|
+
from http_fields.contentlanguage import ContentLanguage
|
|
133
|
+
from http_fields.contentlength import ContentLength
|
|
134
|
+
from http_fields.contentlocation import ContentLocation
|
|
135
|
+
from http_fields.contentrange import ContentRange
|
|
136
|
+
from http_fields.contenttype import ContentType
|
|
137
|
+
from http_fields.cookie import Cookie, CookiePair
|
|
138
|
+
from http_fields.date import Date
|
|
139
|
+
from http_fields.etag import ETag
|
|
140
|
+
from http_fields.expect import Expect, Expectation
|
|
141
|
+
from http_fields.expires import Expires
|
|
142
|
+
from http_fields.forwarded import Forwarded
|
|
143
|
+
from http_fields.fromheader import From
|
|
144
|
+
from http_fields.header import CustomHeader, Header
|
|
145
|
+
from http_fields.host import Host
|
|
146
|
+
from http_fields.ifmatch import IfMatch
|
|
147
|
+
from http_fields.ifmodifiedsince import IfModifiedSince
|
|
148
|
+
from http_fields.ifnonematch import IfNoneMatch
|
|
149
|
+
from http_fields.ifrange import IfRange
|
|
150
|
+
from http_fields.ifunmodifiedsince import IfUnmodifiedSince
|
|
151
|
+
from http_fields.lastmodified import LastModified
|
|
152
|
+
from http_fields.link import Link
|
|
153
|
+
from http_fields.location import Location
|
|
154
|
+
from http_fields.maxforwards import MaxForwards
|
|
155
|
+
from http_fields.origin import Origin
|
|
156
|
+
from http_fields.parsedobjs import NonNegativeInt
|
|
157
|
+
from http_fields.prefer import Prefer, PreferenceApplied
|
|
158
|
+
from http_fields.priority import Priority
|
|
159
|
+
from http_fields.proxyauthenticate import ProxyAuthenticate
|
|
160
|
+
from http_fields.proxyauthenticationinfo import ProxyAuthenticationInfo
|
|
161
|
+
from http_fields.proxyauthorization import ProxyAuthorization
|
|
162
|
+
from http_fields.proxystatus import ProxyStatus
|
|
163
|
+
from http_fields.range import Range
|
|
164
|
+
from http_fields.referer import Referer
|
|
165
|
+
from http_fields.retryafter import RetryAfter
|
|
166
|
+
from http_fields.server import Server
|
|
167
|
+
from http_fields.setcookie import SetCookie
|
|
168
|
+
from http_fields.stricttransportsecurity import StrictTransportSecurity
|
|
169
|
+
from http_fields.te import TE
|
|
170
|
+
from http_fields.trailer import Trailer
|
|
171
|
+
from http_fields.upgrade import Upgrade
|
|
172
|
+
from http_fields.useragent import UserAgent
|
|
173
|
+
from http_fields.vary import Vary
|
|
174
|
+
from http_fields.via import Via
|
|
175
|
+
from http_fields.visitors.rfc7239 import ForwardedElement
|
|
176
|
+
from http_fields.visitors.rfc7240 import Preference
|
|
177
|
+
from http_fields.visitors.rfc7838 import AltValue
|
|
178
|
+
from http_fields.visitors.rfc8288 import LinkValue
|
|
179
|
+
from http_fields.visitors.rfc9110 import (
|
|
180
|
+
AuthParam,
|
|
181
|
+
EntityTag,
|
|
182
|
+
FieldName,
|
|
183
|
+
MediaType,
|
|
184
|
+
RangeUnit,
|
|
185
|
+
Token,
|
|
186
|
+
WeightedLanguageRange,
|
|
187
|
+
)
|
|
188
|
+
from http_fields.visitors.rfc9110.contentlanguage import LanguageTag
|
|
189
|
+
from http_fields.visitors.rfc9110.range import IntRange, SuffixRange
|
|
190
|
+
from http_fields.visitors.rfc9110.te import TCoding
|
|
191
|
+
from http_fields.visitors.rfc9110.upgrade import Protocol
|
|
192
|
+
from http_fields.visitors.rfc9110.via import ViaElement
|
|
193
|
+
from http_fields.wwwauthenticate import WWWAuthenticate
|
http_fields/accept.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""Accept header class."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import ClassVar
|
|
5
|
+
|
|
6
|
+
from abnf import Rule
|
|
7
|
+
from abnf.grammars import rfc9110
|
|
8
|
+
from typing_extensions import Self
|
|
9
|
+
|
|
10
|
+
from http_fields.header import Header
|
|
11
|
+
from http_fields.visitors.rfc9110 import AcceptType, AcceptVisitor
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass(frozen=True)
|
|
15
|
+
class Accept(Header):
|
|
16
|
+
"""Accept header, as defined by RFC 9110.
|
|
17
|
+
|
|
18
|
+
An Accept header may have an empty value (``Accept:``), which is treated as accepting
|
|
19
|
+
any media type. RFC 9110 no longer includes ext-params (accept-ext) in the grammar.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
name: ClassVar[str] = "Accept"
|
|
23
|
+
rule: ClassVar[Rule] = rfc9110.Rule("Accept")
|
|
24
|
+
visitor: ClassVar[AcceptVisitor] = AcceptVisitor()
|
|
25
|
+
|
|
26
|
+
accept_types: tuple[AcceptType, ...]
|
|
27
|
+
|
|
28
|
+
def __init__(self, *accept_types: AcceptType) -> None:
|
|
29
|
+
object.__setattr__(self, "accept_types", tuple(accept_types))
|
|
30
|
+
|
|
31
|
+
@classmethod
|
|
32
|
+
def parse(cls, value: str) -> Self:
|
|
33
|
+
return cls(*cls.visitor.visit(cls._node(value)))
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def value(self) -> str:
|
|
37
|
+
return ", ".join(str(accept_type) for accept_type in self.accept_types)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""Accept-Charset header class."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import ClassVar
|
|
5
|
+
|
|
6
|
+
from abnf import Rule
|
|
7
|
+
from abnf.grammars import rfc9110
|
|
8
|
+
from typing_extensions import Self
|
|
9
|
+
|
|
10
|
+
from http_fields.header import Header
|
|
11
|
+
from http_fields.visitors.rfc9110 import AcceptCharsetVisitor, Token, Weight
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _as_weight(value: float | Weight | None) -> Weight | None:
|
|
15
|
+
"""Normalize a weight argument to a Weight or None. A numeric 0 is a valid weight
|
|
16
|
+
("not acceptable"), so only None means "no weight specified"."""
|
|
17
|
+
if isinstance(value, Weight):
|
|
18
|
+
return value
|
|
19
|
+
if isinstance(value, (int, float)) and not isinstance(value, bool):
|
|
20
|
+
return Weight(float(value))
|
|
21
|
+
return None
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass(frozen=True)
|
|
25
|
+
class AcceptCharset(Header):
|
|
26
|
+
"""Accept-Charset header, as defined by RFC 9110."""
|
|
27
|
+
|
|
28
|
+
name: ClassVar[str] = "accept-charset"
|
|
29
|
+
rule: ClassVar[Rule] = rfc9110.Rule("Accept-Charset")
|
|
30
|
+
visitor: ClassVar[AcceptCharsetVisitor] = AcceptCharsetVisitor()
|
|
31
|
+
|
|
32
|
+
charsets: tuple[tuple[Token, Weight | None], ...]
|
|
33
|
+
|
|
34
|
+
def __init__(self, *charsets: tuple[str, float | Weight | None]) -> None:
|
|
35
|
+
object.__setattr__(
|
|
36
|
+
self, "charsets", tuple((Token(c), _as_weight(w)) for c, w in charsets)
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
@classmethod
|
|
40
|
+
def parse(cls, value: str) -> Self:
|
|
41
|
+
return cls(*cls.visitor.visit(cls._node(value)))
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def value(self) -> str:
|
|
45
|
+
return ", ".join(
|
|
46
|
+
f"{charset}" + (f";{weight}" if weight is not None else "")
|
|
47
|
+
for charset, weight in self.charsets
|
|
48
|
+
)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Accept-Encoding header class."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import ClassVar
|
|
5
|
+
|
|
6
|
+
from abnf import Rule
|
|
7
|
+
from abnf.grammars import rfc9110
|
|
8
|
+
from typing_extensions import Self
|
|
9
|
+
|
|
10
|
+
from http_fields.header import Header
|
|
11
|
+
from http_fields.visitors.rfc9110 import AcceptEncodingVisitor, Weight, WeightedCoding
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass(frozen=True)
|
|
15
|
+
class AcceptEncoding(Header):
|
|
16
|
+
"""Accept-Encoding header, as defined by RFC 9110."""
|
|
17
|
+
|
|
18
|
+
name: ClassVar[str] = "accept-encoding"
|
|
19
|
+
rule: ClassVar[Rule] = rfc9110.Rule("Accept-Encoding")
|
|
20
|
+
visitor: ClassVar[AcceptEncodingVisitor] = AcceptEncodingVisitor()
|
|
21
|
+
|
|
22
|
+
codings: tuple[WeightedCoding, ...]
|
|
23
|
+
|
|
24
|
+
def __init__(
|
|
25
|
+
self, *codings: WeightedCoding | tuple[str, float | Weight | None]
|
|
26
|
+
) -> None:
|
|
27
|
+
object.__setattr__(
|
|
28
|
+
self,
|
|
29
|
+
"codings",
|
|
30
|
+
tuple(
|
|
31
|
+
c if isinstance(c, WeightedCoding) else WeightedCoding(*c)
|
|
32
|
+
for c in codings
|
|
33
|
+
),
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
def parse(cls, value: str) -> Self:
|
|
38
|
+
return cls(*cls.visitor.visit(cls._node(value)))
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def value(self) -> str:
|
|
42
|
+
return ", ".join(str(coding) for coding in self.codings)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""Accept-Language header class."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import ClassVar
|
|
5
|
+
|
|
6
|
+
from abnf import Rule
|
|
7
|
+
from abnf.grammars import rfc9110
|
|
8
|
+
from typing_extensions import Self
|
|
9
|
+
|
|
10
|
+
from http_fields.header import Header
|
|
11
|
+
from http_fields.visitors.rfc9110 import (
|
|
12
|
+
AcceptLanguageVisitor,
|
|
13
|
+
Weight,
|
|
14
|
+
WeightedLanguageRange,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass(frozen=True)
|
|
19
|
+
class AcceptLanguage(Header):
|
|
20
|
+
"""Accept-Language header, as defined by RFC 9110."""
|
|
21
|
+
|
|
22
|
+
name: ClassVar[str] = "accept-language"
|
|
23
|
+
rule: ClassVar[Rule] = rfc9110.Rule("Accept-Language")
|
|
24
|
+
visitor: ClassVar[AcceptLanguageVisitor] = AcceptLanguageVisitor()
|
|
25
|
+
|
|
26
|
+
language_ranges: tuple[WeightedLanguageRange, ...]
|
|
27
|
+
|
|
28
|
+
def __init__(
|
|
29
|
+
self,
|
|
30
|
+
*language_ranges: WeightedLanguageRange | tuple[str, float | Weight | None],
|
|
31
|
+
) -> None:
|
|
32
|
+
object.__setattr__(
|
|
33
|
+
self,
|
|
34
|
+
"language_ranges",
|
|
35
|
+
tuple(
|
|
36
|
+
r if isinstance(r, WeightedLanguageRange) else WeightedLanguageRange(*r)
|
|
37
|
+
for r in language_ranges
|
|
38
|
+
),
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
@classmethod
|
|
42
|
+
def parse(cls, value: str) -> Self:
|
|
43
|
+
return cls(*cls.visitor.visit(cls._node(value)))
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def value(self) -> str:
|
|
47
|
+
return ", ".join(str(r) for r in self.language_ranges)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""AcceptRanges header class."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import ClassVar
|
|
5
|
+
|
|
6
|
+
from abnf import Rule
|
|
7
|
+
from abnf.grammars import rfc9110
|
|
8
|
+
from typing_extensions import Self
|
|
9
|
+
|
|
10
|
+
from http_fields.header import Header
|
|
11
|
+
from http_fields.visitors.rfc9110 import AcceptRangesVisitor, RangeUnit
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass(frozen=True)
|
|
15
|
+
class AcceptRanges(Header):
|
|
16
|
+
"""Accept-Ranges header, as defined by RFC 9110."""
|
|
17
|
+
|
|
18
|
+
name: ClassVar[str] = "accept-ranges"
|
|
19
|
+
rule: ClassVar[Rule] = rfc9110.Rule("accept-ranges")
|
|
20
|
+
visitor: ClassVar[AcceptRangesVisitor] = AcceptRangesVisitor()
|
|
21
|
+
|
|
22
|
+
range_units: tuple[RangeUnit, ...]
|
|
23
|
+
|
|
24
|
+
def __init__(self, *range_units: RangeUnit) -> None:
|
|
25
|
+
object.__setattr__(self, "range_units", tuple(range_units))
|
|
26
|
+
|
|
27
|
+
@classmethod
|
|
28
|
+
def parse(cls, value: str) -> Self:
|
|
29
|
+
return cls(
|
|
30
|
+
*(RangeUnit(r, parse=False) for r in cls.visitor.visit(cls._node(value)))
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def value(self) -> str:
|
|
35
|
+
return ",".join(self.range_units)
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"""Access-Control-* (CORS) header classes, as defined by the Fetch standard.
|
|
2
|
+
|
|
3
|
+
The grammar comes from abnf's ``cors`` module.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from typing import ClassVar
|
|
8
|
+
|
|
9
|
+
from abnf import Rule
|
|
10
|
+
from abnf.grammars import cors
|
|
11
|
+
from typing_extensions import Self
|
|
12
|
+
|
|
13
|
+
from http_fields.header import Header
|
|
14
|
+
from http_fields.parsedobjs import NonNegativeInt, ParsedStr
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class CorsMethod(ParsedStr):
|
|
18
|
+
"""A CORS method token. Self-validating."""
|
|
19
|
+
|
|
20
|
+
parser = cors.Rule("method")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class CorsFieldName(ParsedStr):
|
|
24
|
+
"""A CORS field-name. Self-validating."""
|
|
25
|
+
|
|
26
|
+
parser = cors.Rule("field-name")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class AllowedOrigin(ParsedStr):
|
|
30
|
+
"""An Access-Control-Allow-Origin value (an origin, ``null``, or ``*``). Self-validating."""
|
|
31
|
+
|
|
32
|
+
parser = cors.Rule("Access-Control-Allow-Origin")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class RequestedMethod(ParsedStr):
|
|
36
|
+
"""An Access-Control-Request-Method value (a single method). Self-validating."""
|
|
37
|
+
|
|
38
|
+
parser = cors.Rule("Access-Control-Request-Method")
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
__all__ = [
|
|
42
|
+
"AccessControlAllowCredentials",
|
|
43
|
+
"AccessControlAllowHeaders",
|
|
44
|
+
"AccessControlAllowMethods",
|
|
45
|
+
"AccessControlAllowOrigin",
|
|
46
|
+
"AccessControlExposeHeaders",
|
|
47
|
+
"AccessControlMaxAge",
|
|
48
|
+
"AccessControlRequestHeaders",
|
|
49
|
+
"AccessControlRequestMethod",
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@dataclass(frozen=True)
|
|
54
|
+
class _CorsList(Header):
|
|
55
|
+
"""Base for CORS headers that are a comma-separated list of tokens (methods or
|
|
56
|
+
field-names). Subclasses set ``name``/``rule`` and ``item_type`` (the self-validating
|
|
57
|
+
ParsedStr type of each list item)."""
|
|
58
|
+
|
|
59
|
+
item_type: ClassVar[type[ParsedStr]]
|
|
60
|
+
|
|
61
|
+
# Subclasses narrow this to their item_type so the field-type check is strict.
|
|
62
|
+
items: tuple[ParsedStr, ...]
|
|
63
|
+
|
|
64
|
+
def __init__(self, *items: ParsedStr) -> None:
|
|
65
|
+
object.__setattr__(self, "items", tuple(items))
|
|
66
|
+
|
|
67
|
+
@classmethod
|
|
68
|
+
def parse(cls, value: str) -> Self:
|
|
69
|
+
node = cls._node(value)
|
|
70
|
+
it = cls.item_type
|
|
71
|
+
return cls(
|
|
72
|
+
*(
|
|
73
|
+
it(c.value, parse=False)
|
|
74
|
+
for c in node.children
|
|
75
|
+
if c.name == it.parser.name
|
|
76
|
+
)
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
@property
|
|
80
|
+
def value(self) -> str:
|
|
81
|
+
return ", ".join(self.items)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class AccessControlAllowMethods(_CorsList):
|
|
85
|
+
"""Access-Control-Allow-Methods header."""
|
|
86
|
+
|
|
87
|
+
name: ClassVar[str] = "access-control-allow-methods"
|
|
88
|
+
rule: ClassVar[Rule] = cors.Rule("Access-Control-Allow-Methods")
|
|
89
|
+
item_type = CorsMethod
|
|
90
|
+
items: tuple[CorsMethod, ...]
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class AccessControlAllowHeaders(_CorsList):
|
|
94
|
+
"""Access-Control-Allow-Headers header."""
|
|
95
|
+
|
|
96
|
+
name: ClassVar[str] = "access-control-allow-headers"
|
|
97
|
+
rule: ClassVar[Rule] = cors.Rule("Access-Control-Allow-Headers")
|
|
98
|
+
item_type = CorsFieldName
|
|
99
|
+
items: tuple[CorsFieldName, ...]
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class AccessControlExposeHeaders(_CorsList):
|
|
103
|
+
"""Access-Control-Expose-Headers header."""
|
|
104
|
+
|
|
105
|
+
name: ClassVar[str] = "access-control-expose-headers"
|
|
106
|
+
rule: ClassVar[Rule] = cors.Rule("Access-Control-Expose-Headers")
|
|
107
|
+
item_type = CorsFieldName
|
|
108
|
+
items: tuple[CorsFieldName, ...]
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class AccessControlRequestHeaders(_CorsList):
|
|
112
|
+
"""Access-Control-Request-Headers header."""
|
|
113
|
+
|
|
114
|
+
name: ClassVar[str] = "access-control-request-headers"
|
|
115
|
+
rule: ClassVar[Rule] = cors.Rule("Access-Control-Request-Headers")
|
|
116
|
+
item_type = CorsFieldName
|
|
117
|
+
items: tuple[CorsFieldName, ...]
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
@dataclass(frozen=True)
|
|
121
|
+
class AccessControlAllowOrigin(Header):
|
|
122
|
+
"""Access-Control-Allow-Origin header (an origin, ``null``, or ``*``)."""
|
|
123
|
+
|
|
124
|
+
name: ClassVar[str] = "access-control-allow-origin"
|
|
125
|
+
rule: ClassVar[Rule] = cors.Rule("Access-Control-Allow-Origin")
|
|
126
|
+
|
|
127
|
+
origin: AllowedOrigin
|
|
128
|
+
|
|
129
|
+
def __init__(self, origin: str) -> None:
|
|
130
|
+
object.__setattr__(self, "origin", AllowedOrigin(origin))
|
|
131
|
+
|
|
132
|
+
@classmethod
|
|
133
|
+
def parse(cls, value: str) -> Self:
|
|
134
|
+
return cls(value)
|
|
135
|
+
|
|
136
|
+
@property
|
|
137
|
+
def value(self) -> str:
|
|
138
|
+
return self.origin
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
@dataclass(frozen=True)
|
|
142
|
+
class AccessControlRequestMethod(Header):
|
|
143
|
+
"""Access-Control-Request-Method header (a single method)."""
|
|
144
|
+
|
|
145
|
+
name: ClassVar[str] = "access-control-request-method"
|
|
146
|
+
rule: ClassVar[Rule] = cors.Rule("Access-Control-Request-Method")
|
|
147
|
+
|
|
148
|
+
method: RequestedMethod
|
|
149
|
+
|
|
150
|
+
def __init__(self, method: str) -> None:
|
|
151
|
+
object.__setattr__(self, "method", RequestedMethod(method))
|
|
152
|
+
|
|
153
|
+
@classmethod
|
|
154
|
+
def parse(cls, value: str) -> Self:
|
|
155
|
+
return cls(value)
|
|
156
|
+
|
|
157
|
+
@property
|
|
158
|
+
def value(self) -> str:
|
|
159
|
+
return self.method
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
@dataclass(frozen=True)
|
|
163
|
+
class AccessControlMaxAge(Header):
|
|
164
|
+
"""Access-Control-Max-Age header (delta-seconds)."""
|
|
165
|
+
|
|
166
|
+
name: ClassVar[str] = "access-control-max-age"
|
|
167
|
+
rule: ClassVar[Rule] = cors.Rule("Access-Control-Max-Age")
|
|
168
|
+
|
|
169
|
+
max_age: NonNegativeInt
|
|
170
|
+
|
|
171
|
+
def __init__(self, max_age: int) -> None:
|
|
172
|
+
object.__setattr__(self, "max_age", NonNegativeInt(max_age))
|
|
173
|
+
|
|
174
|
+
@classmethod
|
|
175
|
+
def parse(cls, value: str) -> Self:
|
|
176
|
+
return cls(NonNegativeInt(cls._node(value).value))
|
|
177
|
+
|
|
178
|
+
@property
|
|
179
|
+
def value(self) -> str:
|
|
180
|
+
return str(self.max_age)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
@dataclass(frozen=True)
|
|
184
|
+
class AccessControlAllowCredentials(Header):
|
|
185
|
+
"""Access-Control-Allow-Credentials header (always the literal ``true``)."""
|
|
186
|
+
|
|
187
|
+
name: ClassVar[str] = "access-control-allow-credentials"
|
|
188
|
+
rule: ClassVar[Rule] = cors.Rule("Access-Control-Allow-Credentials")
|
|
189
|
+
|
|
190
|
+
@classmethod
|
|
191
|
+
def parse(cls, value: str) -> Self:
|
|
192
|
+
cls._node(value) # validates the value is "true"
|
|
193
|
+
return cls()
|
|
194
|
+
|
|
195
|
+
@property
|
|
196
|
+
def value(self) -> str:
|
|
197
|
+
return "true"
|
http_fields/age.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""Age header class."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import ClassVar
|
|
5
|
+
|
|
6
|
+
from abnf import Rule
|
|
7
|
+
from abnf.grammars import rfc9111
|
|
8
|
+
from typing_extensions import Self
|
|
9
|
+
|
|
10
|
+
from http_fields.header import Header
|
|
11
|
+
from http_fields.parsedobjs import NonNegativeInt
|
|
12
|
+
from http_fields.visitors.rfc9111 import AgeVisitor
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass(frozen=True)
|
|
16
|
+
class Age(Header):
|
|
17
|
+
"""Age header, as defined by RFC 9111."""
|
|
18
|
+
|
|
19
|
+
name: ClassVar[str] = "age"
|
|
20
|
+
rule: ClassVar[Rule] = rfc9111.Rule("Age")
|
|
21
|
+
visitor: ClassVar[AgeVisitor] = AgeVisitor()
|
|
22
|
+
|
|
23
|
+
seconds: NonNegativeInt
|
|
24
|
+
|
|
25
|
+
def __init__(self, seconds: int) -> None:
|
|
26
|
+
object.__setattr__(self, "seconds", NonNegativeInt(seconds))
|
|
27
|
+
|
|
28
|
+
@classmethod
|
|
29
|
+
def parse(cls, value: str) -> Self:
|
|
30
|
+
return cls(cls.visitor.visit(cls._node(value)))
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def value(self) -> str:
|
|
34
|
+
return str(self.seconds)
|
http_fields/allow.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""Allow header class."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import ClassVar
|
|
5
|
+
|
|
6
|
+
from abnf import Rule
|
|
7
|
+
from abnf.grammars import rfc9110
|
|
8
|
+
from typing_extensions import Self
|
|
9
|
+
|
|
10
|
+
from http_fields.header import Header
|
|
11
|
+
from http_fields.parsedobjs import ParsedStr
|
|
12
|
+
from http_fields.visitors.rfc9110 import AllowVisitor
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Method(ParsedStr):
|
|
16
|
+
"""An HTTP method (a token). Methods are case-sensitive (RFC 9110 section 9.1),
|
|
17
|
+
unlike the caseless :class:`Token`."""
|
|
18
|
+
|
|
19
|
+
parser = rfc9110.Rule("token")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dataclass(frozen=True)
|
|
23
|
+
class Allow(Header):
|
|
24
|
+
"""Allow header, as defined by RFC 9110.
|
|
25
|
+
|
|
26
|
+
Allow: GET, POST, OPTIONS
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
name: ClassVar[str] = "Allow"
|
|
30
|
+
rule: ClassVar[Rule] = rfc9110.Rule("Allow")
|
|
31
|
+
visitor: ClassVar[AllowVisitor] = AllowVisitor()
|
|
32
|
+
|
|
33
|
+
methods: tuple[Method, ...]
|
|
34
|
+
|
|
35
|
+
def __init__(self, *methods: Method) -> None:
|
|
36
|
+
object.__setattr__(self, "methods", tuple(methods))
|
|
37
|
+
|
|
38
|
+
@classmethod
|
|
39
|
+
def parse(cls, value: str) -> Self:
|
|
40
|
+
return cls(
|
|
41
|
+
*(Method(m, parse=False) for m in cls.visitor.visit(cls._node(value)))
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def value(self) -> str:
|
|
46
|
+
return ",".join(self.methods)
|