Skip to content

Commit f6f86a6

Browse files
authored
Support list as a value for no-cache and private directives (#615)
1 parent c7580a6 commit f6f86a6

File tree

2 files changed

+64
-27
lines changed

2 files changed

+64
-27
lines changed

blacksheep/server/headers/cache.py

Lines changed: 43 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import inspect
77
from functools import wraps
8-
from typing import Optional
8+
from typing import List, Optional, Union
99

1010
from blacksheep import Request, Response
1111
from blacksheep.server.normalization import ensure_response
@@ -15,11 +15,11 @@ def write_cache_control_response_header(
1515
*,
1616
max_age: Optional[int] = None,
1717
shared_max_age: Optional[int] = None,
18-
no_cache: Optional[bool] = None,
18+
no_cache: Union[bool, List[str], None] = None,
1919
no_store: Optional[bool] = None,
2020
must_revalidate: Optional[bool] = None,
2121
proxy_revalidate: Optional[bool] = None,
22-
private: Optional[bool] = None,
22+
private: Union[bool, List[str], None] = None,
2323
public: Optional[bool] = None,
2424
must_understand: Optional[bool] = None,
2525
no_transform: Optional[bool] = None,
@@ -36,16 +36,18 @@ def write_cache_control_response_header(
3636
max age in seconds
3737
shared_max_age: int | None
3838
optional shared max age in seconds
39-
no_cache: bool | None
40-
enables no-cache
39+
no_cache: bool | list[str] | None
40+
enables no-cache; if a list of field names is provided, they will be added
41+
as field-names (e.g., no-cache="Set-Cookie, Authorization")
4142
no_store: bool | None
4243
enables no-store
4344
must_revalidate: bool | None
4445
enables must-revalidate
4546
proxy_revalidate: bool | None
4647
enables proxy-revalidate
47-
private: bool | None
48-
enables private
48+
private: bool | list[str] | None
49+
enables private; if a list of field names is provided, they will be added
50+
as field-names (e.g., private="Set-Cookie, Authorization")
4951
public: bool | None
5052
enables public
5153
must_understand: bool | None
@@ -73,7 +75,11 @@ def extend(part: bytes):
7375
value.extend(part)
7476

7577
if private:
76-
extend(b"private")
78+
if isinstance(private, list):
79+
field_names = ", ".join(private)
80+
extend(f'private="{field_names}"'.encode("ascii"))
81+
else:
82+
extend(b"private")
7783

7884
if public:
7985
extend(b"public")
@@ -85,7 +91,11 @@ def extend(part: bytes):
8591
extend(f"s-maxage={shared_max_age}".encode("ascii"))
8692

8793
if no_cache:
88-
extend(b"no-cache")
94+
if isinstance(no_cache, list):
95+
field_names = ", ".join(no_cache)
96+
extend(f'no-cache="{field_names}"'.encode("ascii"))
97+
else:
98+
extend(b"no-cache")
8999

90100
if must_revalidate:
91101
extend(b"must-revalidate")
@@ -124,16 +134,18 @@ class CacheControlHeaderValue:
124134
max age in seconds
125135
shared_max_age: int | None
126136
optional shared max age in seconds
127-
no_cache: bool | None
128-
enables no-cache
137+
no_cache: bool | list[str] | None
138+
enables no-cache; if a list of field names is provided, they will be added
139+
as field-names (e.g., no-cache="Set-Cookie, Authorization")
129140
no_store: bool | None
130141
enables no-store
131142
must_revalidate: bool | None
132143
enables must-revalidate
133144
proxy_revalidate: bool | None
134145
enables proxy-revalidate
135-
private: bool | None
136-
enables private
146+
private: bool | list[str] | None
147+
enables private; if a list of field names is provided, they will be added
148+
as field-names (e.g., private="Set-Cookie, Authorization")
137149
public: bool | None
138150
enables public
139151
must_understand: bool | None
@@ -156,11 +168,11 @@ def __init__(
156168
*,
157169
max_age: Optional[int] = None,
158170
shared_max_age: Optional[int] = None,
159-
no_cache: Optional[bool] = None,
171+
no_cache: Union[bool, List[str], None] = None,
160172
no_store: Optional[bool] = None,
161173
must_revalidate: Optional[bool] = None,
162174
proxy_revalidate: Optional[bool] = None,
163-
private: Optional[bool] = None,
175+
private: Union[bool, List[str], None] = None,
164176
public: Optional[bool] = None,
165177
must_understand: Optional[bool] = None,
166178
no_transform: Optional[bool] = None,
@@ -188,11 +200,11 @@ def __init__(
188200
def cache_control(
189201
max_age: Optional[int] = None,
190202
shared_max_age: Optional[int] = None,
191-
no_cache: Optional[bool] = None,
203+
no_cache: Union[bool, List[str], None] = None,
192204
no_store: Optional[bool] = None,
193205
must_revalidate: Optional[bool] = None,
194206
proxy_revalidate: Optional[bool] = None,
195-
private: Optional[bool] = None,
207+
private: Union[bool, List[str], None] = None,
196208
public: Optional[bool] = None,
197209
must_understand: Optional[bool] = None,
198210
no_transform: Optional[bool] = None,
@@ -210,16 +222,18 @@ def cache_control(
210222
max age in seconds
211223
shared_max_age: int | None
212224
optional shared max age in seconds
213-
no_cache: bool | None
214-
enables no-cache
225+
no_cache: bool | list[str] | None
226+
enables no-cache; if a list of field names is provided, they will be added
227+
as field-names (e.g., no-cache="Set-Cookie, Authorization")
215228
no_store: bool | None
216229
enables no-store
217230
must_revalidate: bool | None
218231
enables must-revalidate
219232
proxy_revalidate: bool | None
220233
enables proxy-revalidate
221-
private: bool | None
222-
enables private
234+
private: bool | list[str] | None
235+
enables private; if a list of field names is provided, they will be added
236+
as field-names (e.g., private="Set-Cookie, Authorization")
223237
public: bool | None
224238
enables public
225239
must_understand: bool | None
@@ -287,16 +301,18 @@ class CacheControlMiddleware:
287301
max age in seconds
288302
shared_max_age: int | None
289303
optional shared max age in seconds
290-
no_cache: bool | None
291-
enables no-cache
304+
no_cache: bool | list[str] | None
305+
enables no-cache; if a list of field names is provided, they will be added
306+
as field-names (e.g., no-cache="Set-Cookie, Authorization")
292307
no_store: bool | None
293308
enables no-store
294309
must_revalidate: bool | None
295310
enables must-revalidate
296311
proxy_revalidate: bool | None
297312
enables proxy-revalidate
298-
private: bool | None
299-
enables private
313+
private: bool | list[str] | None
314+
enables private; if a list of field names is provided, they will be added
315+
as field-names (e.g., private="Set-Cookie, Authorization")
300316
public: bool | None
301317
enables public
302318
must_understand: bool | None
@@ -316,11 +332,11 @@ def __init__(
316332
*,
317333
max_age: Optional[int] = None,
318334
shared_max_age: Optional[int] = None,
319-
no_cache: Optional[bool] = None,
335+
no_cache: Union[bool, List[str], None] = None,
320336
no_store: Optional[bool] = None,
321337
must_revalidate: Optional[bool] = None,
322338
proxy_revalidate: Optional[bool] = None,
323-
private: Optional[bool] = None,
339+
private: Union[bool, List[str], None] = None,
324340
public: Optional[bool] = None,
325341
must_understand: Optional[bool] = None,
326342
no_transform: Optional[bool] = None,

tests/test_caching.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,27 @@
3535
{"max_age": 604800, "stale_if_error": 86400},
3636
b"max-age=604800, stale-if-error=86400",
3737
),
38+
# Test list support for private directive
39+
({"private": ["Set-Cookie"]}, b'private="Set-Cookie"'),
40+
(
41+
{"private": ["Set-Cookie", "Authorization"]},
42+
b'private="Set-Cookie, Authorization"',
43+
),
44+
# Test list support for no-cache directive
45+
({"no_cache": ["Set-Cookie"]}, b'no-cache="Set-Cookie"'),
46+
(
47+
{"no_cache": ["Set-Cookie", "Authorization"]},
48+
b'no-cache="Set-Cookie, Authorization"',
49+
),
50+
# Test combined list support
51+
(
52+
{"private": ["Set-Cookie"], "max_age": 3600},
53+
b'private="Set-Cookie", max-age=3600',
54+
),
55+
(
56+
{"no_cache": ["Authorization"], "no_store": True},
57+
b'no-cache="Authorization", no-store',
58+
),
3859
]
3960

4061

0 commit comments

Comments
 (0)