Skip to content

Commit 794c819

Browse files
author
Rob Hudson
committed
Replace HttpResponse type with HttpResponseBase
1 parent c2a4317 commit 794c819

File tree

9 files changed

+55
-44
lines changed

9 files changed

+55
-44
lines changed

csp/checks.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import annotations
2+
23
import pprint
3-
from typing import Dict, Tuple, Any, Optional, Sequence, TYPE_CHECKING, List
4+
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Sequence, Tuple
45

56
from django.conf import settings
67
from django.core.checks import Error

csp/context_processors.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import annotations
2-
from typing import Dict, Literal, TYPE_CHECKING
2+
3+
from typing import TYPE_CHECKING, Dict, Literal
34

45
if TYPE_CHECKING:
56
from django.http import HttpRequest

csp/contrib/rate_limiting.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
11
from __future__ import annotations
2-
from typing import TYPE_CHECKING
2+
33
import random
4+
from typing import TYPE_CHECKING
45

56
from django.conf import settings
67

78
from csp.middleware import CSPMiddleware
89
from csp.utils import build_policy
910

1011
if TYPE_CHECKING:
11-
from django.http import HttpRequest, HttpResponse
12+
from django.http import HttpRequest, HttpResponseBase
1213

1314

1415
class RateLimitedCSPMiddleware(CSPMiddleware):
1516
"""A CSP middleware that rate-limits the number of violation reports sent
1617
to report-uri by excluding it from some requests."""
1718

18-
def build_policy(self, request: HttpRequest, response: HttpResponse) -> str:
19+
def build_policy(self, request: HttpRequest, response: HttpResponseBase) -> str:
1920
config = getattr(response, "_csp_config", None)
2021
update = getattr(response, "_csp_update", None)
2122
replace = getattr(response, "_csp_replace", {})
@@ -33,7 +34,7 @@ def build_policy(self, request: HttpRequest, response: HttpResponse) -> str:
3334

3435
return build_policy(config=config, update=update, replace=replace, nonce=nonce)
3536

36-
def build_policy_ro(self, request: HttpRequest, response: HttpResponse) -> str:
37+
def build_policy_ro(self, request: HttpRequest, response: HttpResponseBase) -> str:
3738
config = getattr(response, "_csp_config_ro", None)
3839
update = getattr(response, "_csp_update_ro", None)
3940
replace = getattr(response, "_csp_replace_ro", {})

csp/decorators.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
from functools import wraps
2-
from typing import Callable, Optional, Any, Dict, List
3-
from django.http import HttpRequest, HttpResponse
2+
from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional
43

5-
# A generic Django view function
6-
_VIEW_T = Callable[[HttpRequest], HttpResponse]
7-
_VIEW_DECORATOR_T = Callable[[_VIEW_T], _VIEW_T]
4+
if TYPE_CHECKING:
5+
from django.http import HttpRequest, HttpResponseBase
6+
7+
# A generic Django view function
8+
_VIEW_T = Callable[[HttpRequest], HttpResponseBase]
9+
_VIEW_DECORATOR_T = Callable[[_VIEW_T], _VIEW_T]
810

911

1012
def csp_exempt(REPORT_ONLY: Optional[bool] = None) -> _VIEW_DECORATOR_T:
@@ -18,7 +20,7 @@ def csp_exempt(REPORT_ONLY: Optional[bool] = None) -> _VIEW_DECORATOR_T:
1820

1921
def decorator(f: _VIEW_T) -> _VIEW_T:
2022
@wraps(f)
21-
def _wrapped(*a: Any, **kw: Any) -> HttpResponse:
23+
def _wrapped(*a: Any, **kw: Any) -> HttpResponseBase:
2224
resp = f(*a, **kw)
2325
if REPORT_ONLY:
2426
setattr(resp, "_csp_exempt_ro", True)
@@ -44,7 +46,7 @@ def csp_update(config: Optional[Dict[str, Any]] = None, REPORT_ONLY: bool = Fals
4446

4547
def decorator(f: _VIEW_T) -> _VIEW_T:
4648
@wraps(f)
47-
def _wrapped(*a: Any, **kw: Any) -> HttpResponse:
49+
def _wrapped(*a: Any, **kw: Any) -> HttpResponseBase:
4850
resp = f(*a, **kw)
4951
if REPORT_ONLY:
5052
setattr(resp, "_csp_update_ro", config)
@@ -63,7 +65,7 @@ def csp_replace(config: Optional[Dict[str, Any]] = None, REPORT_ONLY: bool = Fal
6365

6466
def decorator(f: _VIEW_T) -> _VIEW_T:
6567
@wraps(f)
66-
def _wrapped(*a: Any, **kw: Any) -> HttpResponse:
68+
def _wrapped(*a: Any, **kw: Any) -> HttpResponseBase:
6769
resp = f(*a, **kw)
6870
if REPORT_ONLY:
6971
setattr(resp, "_csp_replace_ro", config)
@@ -87,7 +89,7 @@ def csp(config: Optional[Dict[str, Any]] = None, REPORT_ONLY: bool = False, **kw
8789

8890
def decorator(f: _VIEW_T) -> _VIEW_T:
8991
@wraps(f)
90-
def _wrapped(*a: Any, **kw: Any) -> HttpResponse:
92+
def _wrapped(*a: Any, **kw: Any) -> HttpResponseBase:
9193
resp = f(*a, **kw)
9294
if REPORT_ONLY:
9395
setattr(resp, "_csp_config_ro", processed_config)

csp/extensions/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import annotations
2-
from typing import Callable, TYPE_CHECKING, Any
2+
3+
from typing import TYPE_CHECKING, Any, Callable
34

45
from jinja2 import nodes
56
from jinja2.ext import Extension

csp/middleware.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from __future__ import annotations
2+
23
import base64
34
import http.client as http_client
45
import os
@@ -13,7 +14,7 @@
1314
from csp.utils import build_policy
1415

1516
if TYPE_CHECKING:
16-
from django.http import HttpRequest, HttpResponse
17+
from django.http import HttpRequest, HttpResponseBase
1718

1819

1920
class CSPMiddleware(MiddlewareMixin):
@@ -39,7 +40,7 @@ def process_request(self, request: HttpRequest) -> None:
3940
nonce = partial(self._make_nonce, request)
4041
setattr(request, "csp_nonce", SimpleLazyObject(nonce))
4142

42-
def process_response(self, request: HttpRequest, response: HttpResponse) -> HttpResponse:
43+
def process_response(self, request: HttpRequest, response: HttpResponseBase) -> HttpResponseBase:
4344
# Check for debug view
4445
exempted_debug_codes = (
4546
http_client.INTERNAL_SERVER_ERROR,
@@ -72,14 +73,14 @@ def process_response(self, request: HttpRequest, response: HttpResponse) -> Http
7273

7374
return response
7475

75-
def build_policy(self, request: HttpRequest, response: HttpResponse) -> str:
76+
def build_policy(self, request: HttpRequest, response: HttpResponseBase) -> str:
7677
config = getattr(response, "_csp_config", None)
7778
update = getattr(response, "_csp_update", None)
7879
replace = getattr(response, "_csp_replace", None)
7980
nonce = getattr(request, "_csp_nonce", None)
8081
return build_policy(config=config, update=update, replace=replace, nonce=nonce)
8182

82-
def build_policy_ro(self, request: HttpRequest, response: HttpResponse) -> str:
83+
def build_policy_ro(self, request: HttpRequest, response: HttpResponseBase) -> str:
8384
config = getattr(response, "_csp_config_ro", None)
8485
update = getattr(response, "_csp_update_ro", None)
8586
replace = getattr(response, "_csp_replace_ro", None)

csp/templatetags/csp.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
from __future__ import annotations
2+
23
from typing import TYPE_CHECKING, Optional
4+
35
from django import template
46
from django.template.base import token_kwargs
57

68
from csp.utils import build_script_tag
79

810
if TYPE_CHECKING:
9-
from django.template.base import NodeList, FilterExpression, Token, Parser
11+
from django.template.base import FilterExpression, NodeList, Parser, Token
1012
from django.template.context import Context
1113

1214
register = template.Library()

csp/tests/test_decorators.py

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from __future__ import annotations
2+
23
from typing import TYPE_CHECKING
34

45
import pytest
@@ -12,14 +13,14 @@
1213
from csp.tests.utils import response
1314

1415
if TYPE_CHECKING:
15-
from django.http import HttpRequest
16+
from django.http import HttpRequest, HttpResponseBase
1617

1718
mw = CSPMiddleware(response())
1819

1920

2021
def test_csp_exempt() -> None:
2122
@csp_exempt()
22-
def view(request: HttpRequest) -> HttpResponse:
23+
def view(request: HttpRequest) -> HttpResponseBase:
2324
return HttpResponse()
2425

2526
response = view(RequestFactory().get("/"))
@@ -29,7 +30,7 @@ def view(request: HttpRequest) -> HttpResponse:
2930

3031
def test_csp_exempt_ro() -> None:
3132
@csp_exempt(REPORT_ONLY=True)
32-
def view(request: HttpRequest) -> HttpResponse:
33+
def view(request: HttpRequest) -> HttpResponseBase:
3334
return HttpResponse()
3435

3536
response = view(RequestFactory().get("/"))
@@ -41,7 +42,7 @@ def view(request: HttpRequest) -> HttpResponse:
4142
def test_csp_update() -> None:
4243
request = RequestFactory().get("/")
4344

44-
def view_without_decorator(request: HttpRequest) -> HttpResponse:
45+
def view_without_decorator(request: HttpRequest) -> HttpResponseBase:
4546
return HttpResponse()
4647

4748
response = view_without_decorator(request)
@@ -51,7 +52,7 @@ def view_without_decorator(request: HttpRequest) -> HttpResponse:
5152
assert policy_list == ["default-src 'self'", "img-src foo.com"]
5253

5354
@csp_update({"img-src": ["bar.com", NONCE]})
54-
def view_with_decorator(request: HttpRequest) -> HttpResponse:
55+
def view_with_decorator(request: HttpRequest) -> HttpResponseBase:
5556
return HttpResponse()
5657

5758
response = view_with_decorator(request)
@@ -74,7 +75,7 @@ def view_with_decorator(request: HttpRequest) -> HttpResponse:
7475
def test_csp_update_ro() -> None:
7576
request = RequestFactory().get("/")
7677

77-
def view_without_decorator(request: HttpRequest) -> HttpResponse:
78+
def view_without_decorator(request: HttpRequest) -> HttpResponseBase:
7879
return HttpResponse()
7980

8081
response = view_without_decorator(request)
@@ -84,7 +85,7 @@ def view_without_decorator(request: HttpRequest) -> HttpResponse:
8485
assert policy_list == ["default-src 'self'", "img-src foo.com"]
8586

8687
@csp_update({"img-src": ["bar.com", NONCE]}, REPORT_ONLY=True)
87-
def view_with_decorator(request: HttpRequest) -> HttpResponse:
88+
def view_with_decorator(request: HttpRequest) -> HttpResponseBase:
8889
return HttpResponse()
8990

9091
response = view_with_decorator(request)
@@ -107,7 +108,7 @@ def view_with_decorator(request: HttpRequest) -> HttpResponse:
107108
def test_csp_replace() -> None:
108109
request = RequestFactory().get("/")
109110

110-
def view_without_decorator(request: HttpRequest) -> HttpResponse:
111+
def view_without_decorator(request: HttpRequest) -> HttpResponseBase:
111112
return HttpResponse()
112113

113114
response = view_without_decorator(request)
@@ -117,7 +118,7 @@ def view_without_decorator(request: HttpRequest) -> HttpResponse:
117118
assert policy_list == ["default-src 'self'", "img-src foo.com"]
118119

119120
@csp_replace({"img-src": ["bar.com"]})
120-
def view_with_decorator(request: HttpRequest) -> HttpResponse:
121+
def view_with_decorator(request: HttpRequest) -> HttpResponseBase:
121122
return HttpResponse()
122123

123124
response = view_with_decorator(request)
@@ -134,7 +135,7 @@ def view_with_decorator(request: HttpRequest) -> HttpResponse:
134135
assert policy_list == ["default-src 'self'", "img-src foo.com"]
135136

136137
@csp_replace({"img-src": None})
137-
def view_removing_directive(request: HttpRequest) -> HttpResponse:
138+
def view_removing_directive(request: HttpRequest) -> HttpResponseBase:
138139
return HttpResponse()
139140

140141
response = view_removing_directive(request)
@@ -148,7 +149,7 @@ def view_removing_directive(request: HttpRequest) -> HttpResponse:
148149
def test_csp_replace_ro() -> None:
149150
request = RequestFactory().get("/")
150151

151-
def view_without_decorator(request: HttpRequest) -> HttpResponse:
152+
def view_without_decorator(request: HttpRequest) -> HttpResponseBase:
152153
return HttpResponse()
153154

154155
response = view_without_decorator(request)
@@ -158,7 +159,7 @@ def view_without_decorator(request: HttpRequest) -> HttpResponse:
158159
assert policy_list == ["default-src 'self'", "img-src foo.com"]
159160

160161
@csp_replace({"img-src": ["bar.com"]}, REPORT_ONLY=True)
161-
def view_with_decorator(request: HttpRequest) -> HttpResponse:
162+
def view_with_decorator(request: HttpRequest) -> HttpResponseBase:
162163
return HttpResponse()
163164

164165
response = view_with_decorator(request)
@@ -175,7 +176,7 @@ def view_with_decorator(request: HttpRequest) -> HttpResponse:
175176
assert policy_list == ["default-src 'self'", "img-src foo.com"]
176177

177178
@csp_replace({"img-src": None}, REPORT_ONLY=True)
178-
def view_removing_directive(request: HttpRequest) -> HttpResponse:
179+
def view_removing_directive(request: HttpRequest) -> HttpResponseBase:
179180
return HttpResponse()
180181

181182
response = view_removing_directive(request)
@@ -188,7 +189,7 @@ def view_removing_directive(request: HttpRequest) -> HttpResponse:
188189
def test_csp() -> None:
189190
request = RequestFactory().get("/")
190191

191-
def view_without_decorator(request: HttpRequest) -> HttpResponse:
192+
def view_without_decorator(request: HttpRequest) -> HttpResponseBase:
192193
return HttpResponse()
193194

194195
response = view_without_decorator(request)
@@ -198,7 +199,7 @@ def view_without_decorator(request: HttpRequest) -> HttpResponse:
198199
assert policy_list == ["default-src 'self'"]
199200

200201
@csp({"img-src": ["foo.com"], "font-src": ["bar.com"]})
201-
def view_with_decorator(request: HttpRequest) -> HttpResponse:
202+
def view_with_decorator(request: HttpRequest) -> HttpResponseBase:
202203
return HttpResponse()
203204

204205
response = view_with_decorator(request)
@@ -218,7 +219,7 @@ def view_with_decorator(request: HttpRequest) -> HttpResponse:
218219
def test_csp_ro() -> None:
219220
request = RequestFactory().get("/")
220221

221-
def view_without_decorator(request: HttpRequest) -> HttpResponse:
222+
def view_without_decorator(request: HttpRequest) -> HttpResponseBase:
222223
return HttpResponse()
223224

224225
response = view_without_decorator(request)
@@ -229,7 +230,7 @@ def view_without_decorator(request: HttpRequest) -> HttpResponse:
229230

230231
@csp({"img-src": ["foo.com"], "font-src": ["bar.com"]}, REPORT_ONLY=True)
231232
@csp({}) # CSP with no directives effectively removes the header.
232-
def view_with_decorator(request: HttpRequest) -> HttpResponse:
233+
def view_with_decorator(request: HttpRequest) -> HttpResponseBase:
233234
return HttpResponse()
234235

235236
response = view_with_decorator(request)
@@ -251,7 +252,7 @@ def test_csp_string_values() -> None:
251252
request = RequestFactory().get("/")
252253

253254
@csp({"img-src": "foo.com", "font-src": "bar.com"})
254-
def view_with_decorator(request: HttpRequest) -> HttpResponse:
255+
def view_with_decorator(request: HttpRequest) -> HttpResponseBase:
255256
return HttpResponse()
256257

257258
response = view_with_decorator(request)
@@ -268,7 +269,7 @@ def test_csp_exempt_error() -> None:
268269
with pytest.raises(RuntimeError) as excinfo:
269270
# Ignore type error since we're checking for the exception raised for 3.x syntax
270271
@csp_exempt # type: ignore
271-
def view(request: HttpRequest) -> HttpResponse:
272+
def view(request: HttpRequest) -> HttpResponseBase:
272273
return HttpResponse()
273274

274275
assert "Incompatible `csp_exempt` decorator usage" in str(excinfo.value)
@@ -278,7 +279,7 @@ def test_csp_update_error() -> None:
278279
with pytest.raises(RuntimeError) as excinfo:
279280

280281
@csp_update(IMG_SRC="bar.com")
281-
def view(request: HttpRequest) -> HttpResponse:
282+
def view(request: HttpRequest) -> HttpResponseBase:
282283
return HttpResponse()
283284

284285
assert "Incompatible `csp_update` decorator arguments" in str(excinfo.value)
@@ -288,7 +289,7 @@ def test_csp_replace_error() -> None:
288289
with pytest.raises(RuntimeError) as excinfo:
289290

290291
@csp_replace(IMG_SRC="bar.com")
291-
def view(request: HttpRequest) -> HttpResponse:
292+
def view(request: HttpRequest) -> HttpResponseBase:
292293
return HttpResponse()
293294

294295
assert "Incompatible `csp_replace` decorator arguments" in str(excinfo.value)
@@ -298,7 +299,7 @@ def test_csp_error() -> None:
298299
with pytest.raises(RuntimeError) as excinfo:
299300

300301
@csp(IMG_SRC=["bar.com"])
301-
def view(request: HttpRequest) -> HttpResponse:
302+
def view(request: HttpRequest) -> HttpResponseBase:
302303
return HttpResponse()
303304

304305
assert "Incompatible `csp` decorator arguments" in str(excinfo.value)

csp/tests/utils.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import annotations
2+
23
from abc import ABC, abstractmethod
3-
from typing import Dict, Optional, TYPE_CHECKING, Callable, Any, Tuple
4+
from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, Tuple
45

56
from django.http import HttpResponse
67
from django.template import Context, Template, engines

0 commit comments

Comments
 (0)