0
# Cookie Management
1
2
Cookie handling utilities for creating scoped cookies and managing cookie jars with proper domain and security attribute handling. treq provides convenient functions for working with HTTP cookies in Twisted applications.
3
4
## Capabilities
5
6
### Scoped Cookie Creation
7
8
Creates cookies properly scoped to a URL's origin with appropriate security attributes.
9
10
```python { .api }
11
def scoped_cookie(origin, name, value):
12
"""
13
Create a cookie scoped to a given URL's origin.
14
15
The cookie is automatically configured with appropriate domain, port,
16
and security settings based on the origin URL. HTTPS origins result
17
in secure cookies that won't be sent over HTTP.
18
19
Parameters:
20
- origin: str or EncodedURL - URL specifying domain and port for cookie
21
- name: str - Cookie name
22
- value: str - Cookie value
23
24
Returns:
25
Cookie - Cookie object ready for insertion into CookieJar
26
"""
27
```
28
29
### Cookie Search
30
31
Searches cookie jars for cookies matching specified criteria.
32
33
```python { .api }
34
def search(jar, *, domain, name=None):
35
"""
36
Search for cookies in a cookie jar.
37
38
Finds cookies that match the given domain and optionally
39
a specific cookie name.
40
41
Parameters:
42
- jar: CookieJar - Cookie jar to search
43
- domain: str - Domain to match (keyword-only parameter)
44
- name: str or None - Specific cookie name to find (optional)
45
46
Returns:
47
Iterator of Cookie objects matching the criteria
48
"""
49
```
50
51
## Usage Examples
52
53
### Basic Cookie Management
54
55
```python
56
from treq.cookies import scoped_cookie, search
57
from http.cookiejar import CookieJar
58
import treq
59
from twisted.internet import defer
60
61
@defer.inlineCallbacks
62
def basic_cookie_usage():
63
# Create a cookie jar
64
jar = CookieJar()
65
66
# Create scoped cookies
67
session_cookie = scoped_cookie("https://example.com", "session", "abc123")
68
preference_cookie = scoped_cookie("https://example.com", "theme", "dark")
69
70
# Add cookies to jar
71
jar.set_cookie(session_cookie)
72
jar.set_cookie(preference_cookie)
73
74
# Use cookies in requests
75
response = yield treq.get("https://example.com/profile", cookies=jar)
76
77
# Search for specific cookies
78
session_cookies = list(search(jar, domain="example.com", name="session"))
79
print(f"Found {len(session_cookies)} session cookies")
80
81
# Search for all cookies from domain
82
all_cookies = list(search(jar, domain="example.com"))
83
print(f"Total cookies for example.com: {len(all_cookies)}")
84
```
85
86
### Secure Cookie Handling
87
88
```python
89
from treq.cookies import scoped_cookie
90
from http.cookiejar import CookieJar
91
92
def setup_secure_cookies():
93
jar = CookieJar()
94
95
# HTTPS origin creates secure cookie
96
secure_cookie = scoped_cookie("https://secure-api.com", "api_token", "secret123")
97
print(f"Secure cookie: {secure_cookie.secure}") # True
98
99
# HTTP origin creates non-secure cookie
100
basic_cookie = scoped_cookie("http://local-dev.com", "debug", "enabled")
101
print(f"Basic cookie secure: {basic_cookie.secure}") # False
102
103
jar.set_cookie(secure_cookie)
104
jar.set_cookie(basic_cookie)
105
106
return jar
107
108
@defer.inlineCallbacks
109
def use_secure_cookies():
110
jar = setup_secure_cookies()
111
112
# Secure cookie sent to HTTPS endpoint
113
response = yield treq.get("https://secure-api.com/data", cookies=jar)
114
115
# Non-secure cookie sent to HTTP endpoint
116
response = yield treq.get("http://local-dev.com/debug", cookies=jar)
117
```
118
119
### Session Management with Cookies
120
121
```python
122
from treq.cookies import scoped_cookie, search
123
from http.cookiejar import CookieJar
124
from treq.client import HTTPClient
125
from twisted.web.client import Agent
126
127
class SessionManager:
128
def __init__(self, base_url):
129
self.base_url = base_url
130
self.jar = CookieJar()
131
self.client = HTTPClient(Agent(reactor), cookiejar=self.jar)
132
133
@defer.inlineCallbacks
134
def login(self, username, password):
135
"""Login and establish session."""
136
response = yield self.client.post(
137
f"{self.base_url}/login",
138
data={'username': username, 'password': password}
139
)
140
141
if response.code == 200:
142
# Session cookie automatically stored in jar
143
# Extract domain from base_url for search
144
from urllib.parse import urlparse
145
domain = urlparse(self.base_url).netloc
146
session_cookies = list(search(self.jar, domain=domain, name="session"))
147
if session_cookies:
148
print("Login successful - session established")
149
return True
150
151
print("Login failed")
152
return False
153
154
@defer.inlineCallbacks
155
def make_authenticated_request(self, path):
156
"""Make request with session cookies."""
157
response = yield self.client.get(f"{self.base_url}{path}")
158
return response
159
160
def logout(self):
161
"""Clear session cookies."""
162
# Remove all cookies for this domain
163
from urllib.parse import urlparse
164
domain = urlparse(self.base_url).netloc
165
cookies_to_remove = list(search(self.jar, domain=domain))
166
for cookie in cookies_to_remove:
167
self.jar.clear(cookie.domain, cookie.path, cookie.name)
168
169
@defer.inlineCallbacks
170
def session_example():
171
session = SessionManager("https://api.example.com")
172
173
# Login
174
success = yield session.login("user", "password")
175
if success:
176
# Make authenticated requests
177
profile = yield session.make_authenticated_request("/profile")
178
data = yield profile.json()
179
print(f"User profile: {data}")
180
181
# Logout
182
session.logout()
183
```
184
185
### Cross-Domain Cookie Management
186
187
```python
188
from treq.cookies import scoped_cookie, search
189
from http.cookiejar import CookieJar
190
191
@defer.inlineCallbacks
192
def cross_domain_cookies():
193
jar = CookieJar()
194
195
# Create cookies for different domains
196
domains = [
197
"https://api.service1.com",
198
"https://api.service2.com",
199
"https://subdomain.service1.com"
200
]
201
202
for domain in domains:
203
cookie = scoped_cookie(domain, "api_key", f"key_{domain.split('.')[1]}")
204
jar.set_cookie(cookie)
205
206
# Search cookies by domain
207
for domain_url in domains:
208
from urllib.parse import urlparse
209
domain = urlparse(domain_url).netloc
210
cookies = list(search(jar, domain=domain))
211
print(f"{domain_url}: {len(cookies)} cookies")
212
213
# Make requests with domain-specific cookies
214
response = yield treq.get(f"{domain}/data", cookies=jar)
215
```
216
217
### Cookie Expiration and Cleanup
218
219
```python
220
from treq.cookies import scoped_cookie, search
221
from http.cookiejar import CookieJar
222
import time
223
224
def create_expiring_cookie(origin, name, value, max_age_seconds):
225
"""Create a cookie with expiration."""
226
cookie = scoped_cookie(origin, name, value)
227
228
# Set expiration time
229
cookie.expires = int(time.time()) + max_age_seconds
230
return cookie
231
232
@defer.inlineCallbacks
233
def cookie_expiration_example():
234
jar = CookieJar()
235
236
# Create short-lived cookie (expires in 60 seconds)
237
temp_cookie = create_expiring_cookie(
238
"https://example.com",
239
"temp_token",
240
"xyz789",
241
60
242
)
243
jar.set_cookie(temp_cookie)
244
245
# Create long-lived cookie (expires in 1 hour)
246
persistent_cookie = create_expiring_cookie(
247
"https://example.com",
248
"user_id",
249
"12345",
250
3600
251
)
252
jar.set_cookie(persistent_cookie)
253
254
# Use cookies immediately
255
response = yield treq.get("https://example.com/api", cookies=jar)
256
257
# Later, check for expired cookies
258
def cleanup_expired_cookies():
259
current_time = time.time()
260
expired_cookies = []
261
262
for cookie in search(jar, domain="example.com"):
263
if cookie.expires and cookie.expires < current_time:
264
expired_cookies.append(cookie)
265
266
# Remove expired cookies
267
for cookie in expired_cookies:
268
jar.clear(cookie.domain, cookie.path, cookie.name)
269
270
print(f"Removed {len(expired_cookies)} expired cookies")
271
272
# Call cleanup periodically
273
cleanup_expired_cookies()
274
```
275
276
### Advanced Cookie Configuration
277
278
```python
279
from http.cookiejar import Cookie, CookieJar
280
from hyperlink import EncodedURL
281
282
def create_advanced_cookie(url, name, value, **kwargs):
283
"""Create cookie with advanced options."""
284
url_obj = EncodedURL.from_text(url) if isinstance(url, str) else url
285
286
cookie = Cookie(
287
version=0,
288
name=name,
289
value=value,
290
port=None,
291
port_specified=False,
292
domain=url_obj.host,
293
domain_specified=True,
294
domain_initial_dot=False,
295
path=kwargs.get('path', '/'),
296
path_specified=True,
297
secure=url_obj.scheme == 'https',
298
expires=kwargs.get('expires'),
299
discard=kwargs.get('discard', False),
300
comment=kwargs.get('comment'),
301
comment_url=kwargs.get('comment_url'),
302
rest={}
303
)
304
305
return cookie
306
307
@defer.inlineCallbacks
308
def advanced_cookie_usage():
309
jar = CookieJar()
310
311
# Cookie with specific path
312
api_cookie = create_advanced_cookie(
313
"https://example.com",
314
"api_session",
315
"session123",
316
path="/api/"
317
)
318
jar.set_cookie(api_cookie)
319
320
# Cookie that should be discarded when session ends
321
temp_cookie = create_advanced_cookie(
322
"https://example.com",
323
"temp_data",
324
"temporary",
325
discard=True
326
)
327
jar.set_cookie(temp_cookie)
328
329
# Use cookies with path-specific behavior
330
api_response = yield treq.get("https://example.com/api/data", cookies=jar)
331
home_response = yield treq.get("https://example.com/", cookies=jar)
332
333
# API endpoint gets both cookies, home page gets only non-path-specific cookies
334
```
335
336
## Types
337
338
Cookie-related types:
339
340
```python { .api }
341
# Cookie types from standard library
342
from http.cookiejar import Cookie, CookieJar
343
344
# URL types for origins
345
from hyperlink import EncodedURL
346
OriginType = Union[str, EncodedURL]
347
348
# Cookie search results
349
from typing import Iterator
350
CookieIterator = Iterator[Cookie]
351
352
# Cookie attributes
353
CookieName = str
354
CookieValue = str
355
```
356
357
## Cookie Security Best Practices
358
359
### Secure Cookie Attributes
360
361
- **Secure flag**: Automatically set for HTTPS origins
362
- **HttpOnly**: Consider setting for sensitive cookies to prevent XSS access
363
- **SameSite**: Configure appropriate SameSite policy for CSRF protection
364
- **Domain scoping**: Use scoped_cookie() for proper domain restriction
365
366
### Cookie Management
367
368
- **Expiration**: Set appropriate expiration times for different cookie types
369
- **Cleanup**: Regularly remove expired cookies to prevent jar bloat
370
- **Storage**: Be mindful of cookie storage limits (4KB per cookie, ~300 per domain)
371
- **Privacy**: Clear sensitive cookies when no longer needed
372
373
### Cross-Origin Considerations
374
375
- **Domain matching**: Understand how cookies are scoped to domains and subdomains
376
- **Path restrictions**: Use path attributes to limit cookie scope
377
- **Protocol security**: Secure cookies won't be sent over HTTP
378
- **Third-party cookies**: Be aware of browser third-party cookie policies
379
380
### Integration with treq
381
382
- **Automatic handling**: treq automatically handles cookies when CookieJar is provided
383
- **Manual control**: Use scoped_cookie() for precise cookie creation
384
- **Session persistence**: Combine with HTTPClient for persistent sessions
385
- **Testing**: Use cookie utilities in testing to simulate various cookie scenarios