0
# Cache Controller
1
2
RFC 9111 compliant cache controller that implements HTTP caching logic, determines response cacheability, validates cached responses, and handles cache directives from HTTP headers.
3
4
## Capabilities
5
6
### Cache Controller
7
8
The main controller class that implements HTTP caching specification logic for determining what to cache and when to serve cached responses.
9
10
```python { .api }
11
class Controller:
12
def __init__(self, *, cacheable_methods=None, cacheable_status_codes=None,
13
cache_private=True, allow_heuristics=False, clock=None,
14
allow_stale=False, always_revalidate=False, force_cache=False,
15
key_generator=None):
16
"""
17
Initialize cache controller with caching policies.
18
19
Parameters:
20
- cacheable_methods: HTTP methods to cache (defaults to ["GET"])
21
- cacheable_status_codes: Status codes to cache (defaults to [200, 301, 308])
22
- cache_private: Whether to cache responses with private directives
23
- allow_heuristics: Enable heuristic caching for responses without explicit cache headers
24
- clock: Custom clock implementation for time-based operations
25
- allow_stale: Whether to serve stale responses when allowed
26
- always_revalidate: Always revalidate cached responses
27
- force_cache: Force caching regardless of cache headers
28
- key_generator: Custom function for generating cache keys
29
"""
30
```
31
32
**Usage Examples:**
33
34
```python
35
import hishel
36
37
# Default controller (GET requests, status codes 200/301/308)
38
controller = hishel.Controller()
39
40
# Conservative caching (only explicitly cacheable responses)
41
controller = hishel.Controller(
42
cacheable_methods=["GET", "HEAD"],
43
cacheable_status_codes=[200],
44
cache_private=False,
45
allow_heuristics=False
46
)
47
48
# Aggressive caching with heuristics
49
controller = hishel.Controller(
50
cacheable_methods=["GET", "HEAD", "POST"],
51
cacheable_status_codes=[200, 201, 204, 301, 308, 404],
52
allow_heuristics=True,
53
allow_stale=True
54
)
55
56
# Always revalidate for critical applications
57
controller = hishel.Controller(
58
always_revalidate=True,
59
force_cache=False
60
)
61
62
# Use with cache client
63
with hishel.CacheClient(controller=controller) as client:
64
response = client.get("https://api.example.com/data")
65
```
66
67
### Cacheability Determination
68
69
Method to determine if a response can be cached based on request/response headers and controller configuration.
70
71
```python { .api }
72
def is_cachable(self, request: Request, response: Response) -> bool:
73
"""
74
Determine whether the response may be cached.
75
76
Parameters:
77
- request: HTTP request object
78
- response: HTTP response object
79
80
Returns:
81
- bool: True if response can be cached, False otherwise
82
83
Implements RFC 9111 Section 3 logic for storing responses in caches.
84
"""
85
```
86
87
**Usage Examples:**
88
89
```python
90
from httpcore import Request, Response
91
import hishel
92
93
controller = hishel.Controller()
94
95
# Check if response is cacheable
96
request = Request(b"GET", b"https://api.example.com/data")
97
response = Response(200, [(b"cache-control", b"max-age=3600")])
98
99
if controller.is_cachable(request, response):
100
print("Response can be cached")
101
else:
102
print("Response should not be cached")
103
```
104
105
### Cache Response Construction
106
107
Method to construct responses from cache, handling validation, freshness checks, and conditional requests.
108
109
```python { .api }
110
def construct_response_from_cache(self, request: Request, response: Response,
111
original_request: Request) -> Request | Response | None:
112
"""
113
Determine how to use a cached response for the current request.
114
115
Parameters:
116
- request: Current HTTP request
117
- response: Cached HTTP response
118
- original_request: Original request that created the cached response
119
120
Returns:
121
- Response: Cached response is valid and can be used
122
- Request: Cached response needs revalidation (returns conditional request)
123
- None: Cached response cannot be used
124
125
Implements RFC 9111 Section 4 logic for constructing responses from caches.
126
"""
127
```
128
129
### Validation Response Handling
130
131
Method to handle validation responses, particularly 304 Not Modified responses.
132
133
```python { .api }
134
def handle_validation_response(self, old_response: Response, new_response: Response) -> Response:
135
"""
136
Handle incoming validation response from server.
137
138
Parameters:
139
- old_response: Previously cached response
140
- new_response: Validation response from server
141
142
Returns:
143
- Response: Updated response (old response with new headers for 304,
144
or new response for other status codes)
145
146
Implements RFC 9111 Section 4.3.4 logic for handling validation responses.
147
"""
148
```
149
150
**Usage Examples:**
151
152
```python
153
# Handle 304 Not Modified response
154
cached_response = Response(200, [(b"etag", b'"abc123"')])
155
validation_response = Response(304, [(b"cache-control", b"max-age=7200")])
156
157
updated_response = controller.handle_validation_response(
158
cached_response,
159
validation_response
160
)
161
# Returns cached_response with updated headers from validation_response
162
```
163
164
## Cache Key Generation
165
166
The controller uses a default key generation strategy but supports custom key generators:
167
168
```python
169
import hashlib
170
from httpcore import Request
171
172
def custom_key_generator(request: Request, body: bytes = b"") -> str:
173
"""
174
Generate cache key from request and body.
175
176
Parameters:
177
- request: HTTP request object
178
- body: Request body bytes
179
180
Returns:
181
- str: Cache key for the request
182
"""
183
# Custom logic here
184
url = request.url
185
method = request.method
186
return hashlib.sha256(method + url + body).hexdigest()
187
188
controller = hishel.Controller(key_generator=custom_key_generator)
189
```
190
191
## Caching Constants
192
193
```python { .api }
194
HEURISTICALLY_CACHEABLE_STATUS_CODES: tuple[int, ...] = (
195
200, 203, 204, 206, 300, 301, 308, 404, 405, 410, 414, 501
196
)
197
```
198
199
Status codes that are considered cacheable when heuristic caching is enabled and no explicit cache headers are present.
200
201
## Clock Implementations
202
203
Custom clock implementations for testing and time manipulation:
204
205
```python { .api }
206
class BaseClock:
207
def now(self) -> int:
208
"""Return current timestamp as integer seconds"""
209
210
class Clock(BaseClock):
211
def now(self) -> int:
212
"""Return current Unix timestamp"""
213
```
214
215
**Usage Examples:**
216
217
```python
218
import time
219
220
class TestClock(hishel.BaseClock):
221
def __init__(self, fixed_time=None):
222
self.fixed_time = fixed_time or time.time()
223
224
def now(self):
225
return int(self.fixed_time)
226
227
# Use custom clock for testing
228
test_clock = TestClock(fixed_time=1609459200) # 2021-01-01
229
controller = hishel.Controller(clock=test_clock)
230
```
231
232
## Cache Behavior Control
233
234
The controller provides fine-grained control over caching behavior:
235
236
- **Method-based caching**: Control which HTTP methods are cached
237
- **Status code filtering**: Specify which response status codes to cache
238
- **Private response handling**: Control caching of responses with Cache-Control: private
239
- **Heuristic caching**: Enable caching based on heuristics when no explicit cache headers
240
- **Stale response serving**: Allow serving stale responses when permitted
241
- **Forced revalidation**: Always revalidate cached responses
242
- **Forced caching**: Cache responses regardless of cache headers
243
- **Custom key generation**: Use custom logic for generating cache keys