0
# HTTP Headers
1
2
Cache-Control and Vary header parsing and representation with RFC 9111 compliant validation and directive handling. These classes provide structured access to HTTP caching headers.
3
4
## Capabilities
5
6
### Cache-Control Header
7
8
Class representing Cache-Control header directives with validation and parsing functionality.
9
10
```python { .api }
11
class CacheControl:
12
def __init__(self, *, immutable=False, max_age=None, max_stale=None,
13
min_fresh=None, must_revalidate=False, must_understand=False,
14
no_cache=False, no_store=False, no_transform=False,
15
only_if_cached=False, private=False, proxy_revalidate=False,
16
public=False, s_maxage=None):
17
"""
18
Represent Cache-Control header directives.
19
20
Parameters:
21
- immutable: Response will not change over time (RFC 8246)
22
- max_age: Maximum age in seconds for cached response
23
- max_stale: Client will accept stale response up to specified seconds
24
- min_fresh: Client wants response fresh for at least specified seconds
25
- must_revalidate: Must revalidate stale responses
26
- must_understand: Override no-store under certain circumstances
27
- no_cache: Must revalidate before using cached response
28
- no_store: Must not store request or response
29
- no_transform: Must not transform response content
30
- only_if_cached: Only use cached response, don't contact server
31
- private: Response is private to single user
32
- proxy_revalidate: Shared caches must revalidate
33
- public: Response may be cached by any cache
34
- s_maxage: Maximum age for shared caches
35
"""
36
```
37
38
**Usage Examples:**
39
40
```python
41
import hishel
42
43
# Create Cache-Control directives
44
cache_control = hishel.CacheControl(
45
max_age=3600, # 1 hour
46
public=True, # Can be cached by any cache
47
must_revalidate=True # Must revalidate when stale
48
)
49
50
# Access individual directives
51
print(cache_control.max_age) # 3600
52
print(cache_control.public) # True
53
print(cache_control.no_cache) # False
54
55
# Private cache directives
56
private_cache = hishel.CacheControl(
57
max_age=1800, # 30 minutes
58
private=True, # Private to single user
59
no_store=False # Can be stored
60
)
61
```
62
63
### Cache-Control Validation
64
65
Class method for validating and normalizing Cache-Control directives from parsed headers.
66
67
```python { .api }
68
@classmethod
69
def validate(cls, directives: dict[str, Any]) -> dict[str, Any]:
70
"""
71
Validate and normalize Cache-Control directives.
72
73
Parameters:
74
- directives: Dictionary of directive names to values
75
76
Returns:
77
- Validated and normalized directives dictionary
78
79
Raises:
80
- ValidationError: If directive values are invalid
81
"""
82
```
83
84
### Cache-Control Parsing
85
86
Function to parse Cache-Control header values into a CacheControl object.
87
88
```python { .api }
89
def parse_cache_control(cache_control_values: list[str]) -> CacheControl:
90
"""
91
Parse Cache-Control header values into structured representation.
92
93
Parameters:
94
- cache_control_values: List of Cache-Control header value strings
95
96
Returns:
97
- CacheControl object with parsed directives
98
99
Raises:
100
- ParseError: If header values cannot be parsed
101
"""
102
```
103
104
**Usage Examples:**
105
106
```python
107
import hishel
108
109
# Parse Cache-Control header
110
header_values = ["max-age=3600, public", "must-revalidate"]
111
cache_control = hishel.parse_cache_control(header_values)
112
113
print(cache_control.max_age) # 3600
114
print(cache_control.public) # True
115
print(cache_control.must_revalidate) # True
116
117
# Parse complex directives
118
complex_header = ['no-cache="Set-Cookie, Authorization", max-age=0']
119
cache_control = hishel.parse_cache_control([complex_header])
120
print(cache_control.no_cache) # ['Set-Cookie', 'Authorization']
121
122
# Handle quoted values
123
quoted_header = ['private="user-info", s-maxage=7200']
124
cache_control = hishel.parse_cache_control([quoted_header])
125
print(cache_control.private) # ['user-info']
126
print(cache_control.s_maxage) # 7200
127
```
128
129
### Vary Header
130
131
Class representing HTTP Vary header for content negotiation caching.
132
133
```python { .api }
134
class Vary:
135
def __init__(self, values: list[str]):
136
"""
137
Represent Vary header field names.
138
139
Parameters:
140
- values: List of header field names that affect response content
141
"""
142
143
@classmethod
144
def from_value(cls, vary_values: list[str]) -> "Vary":
145
"""
146
Create Vary object from header value strings.
147
148
Parameters:
149
- vary_values: List of Vary header value strings
150
151
Returns:
152
- Vary object with parsed field names
153
"""
154
```
155
156
**Usage Examples:**
157
158
```python
159
import hishel
160
161
# Create Vary header from field names
162
vary = hishel.Vary(values=["Accept", "Accept-Encoding", "User-Agent"])
163
164
# Parse from header values
165
vary_headers = ["Accept, Accept-Encoding", "User-Agent"]
166
vary = hishel.Vary.from_value(vary_headers)
167
168
# Access field names
169
print(vary._values) # ['Accept', 'Accept-Encoding', 'User-Agent']
170
171
# Handle wildcard
172
wildcard_vary = hishel.Vary.from_value(["*"])
173
print(wildcard_vary._values) # ['*']
174
```
175
176
## Header Directive Reference
177
178
### Time-based Directives
179
180
Time values are specified in seconds:
181
182
- **max-age**: Maximum time response is considered fresh
183
- **s-maxage**: Maximum time for shared caches (overrides max-age)
184
- **max-stale**: Client accepts stale response up to specified time
185
- **min-fresh**: Client wants response fresh for at least specified time
186
187
### Boolean Directives
188
189
Directives that are either present (True) or absent (False):
190
191
- **immutable**: Response content will never change
192
- **must-revalidate**: Must revalidate stale responses with origin server
193
- **must-understand**: Special handling for must-understand responses
194
- **no-store**: Must not store request or any response
195
- **no-transform**: Must not modify response content
196
- **only-if-cached**: Only return cached response, don't contact server
197
- **proxy-revalidate**: Shared caches must revalidate
198
- **public**: Response may be cached by any cache
199
200
### List Directives
201
202
Directives that can have optional field name lists:
203
204
- **no-cache**: Must revalidate (optionally only specified headers)
205
- **private**: Response is private (optionally only specified headers)
206
207
## Error Handling
208
209
Header parsing can raise specific exceptions:
210
211
```python { .api }
212
class CacheControlError(Exception):
213
"""Base exception for Cache-Control processing"""
214
215
class ParseError(CacheControlError):
216
"""Exception raised when parsing Cache-Control header fails"""
217
218
class ValidationError(CacheControlError):
219
"""Exception raised when validating Cache-Control directives fails"""
220
```
221
222
**Usage Examples:**
223
224
```python
225
import hishel
226
227
try:
228
# Invalid directive value
229
cache_control = hishel.parse_cache_control(["max-age=invalid"])
230
except hishel.ValidationError as e:
231
print(f"Validation error: {e}")
232
233
try:
234
# Malformed header
235
cache_control = hishel.parse_cache_control(['max-age="unclosed quote'])
236
except hishel.ParseError as e:
237
print(f"Parse error: {e}")
238
```
239
240
## Advanced Usage
241
242
### Custom Directive Handling
243
244
```python
245
import hishel
246
247
# Parse headers and inspect all directives
248
cache_control = hishel.parse_cache_control([
249
"max-age=3600, public, custom-directive=value"
250
])
251
252
# Access standard directives
253
print(cache_control.max_age) # 3600
254
print(cache_control.public) # True
255
256
# Custom directives are not directly accessible
257
# but are preserved in the parsing process
258
```
259
260
### Integration with HTTP Libraries
261
262
```python
263
import httpx
264
import hishel
265
266
# Extract Cache-Control from response
267
response = httpx.get("https://api.example.com/data")
268
cache_control_headers = [
269
value.decode() for key, value in response.headers.raw
270
if key.lower() == b'cache-control'
271
]
272
273
if cache_control_headers:
274
cache_control = hishel.parse_cache_control(cache_control_headers)
275
print(f"Max age: {cache_control.max_age}")
276
print(f"Public: {cache_control.public}")
277
```
278
279
### Content Negotiation with Vary
280
281
```python
282
import hishel
283
284
# Handle content negotiation caching
285
vary = hishel.Vary.from_value(["Accept", "Accept-Language"])
286
287
# In cache key generation, these headers would be considered:
288
# - Accept: application/json vs text/html
289
# - Accept-Language: en-US vs fr-FR
290
# Each combination gets its own cache entry
291
```