Skip to content

Commit 1396849

Browse files
authored
Run iri_to_uri on header values (#11439)
* Run iri_to_uri on header values This fixes #11403 * Escape in the right place * Remove _convert_to_charset logic and fix test
1 parent 031b6dc commit 1396849

File tree

3 files changed

+27
-19
lines changed

3 files changed

+27
-19
lines changed

readthedocs/proxito/middleware.py

+4-18
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@
1515
)
1616
from django.conf import settings
1717
from django.core.exceptions import SuspiciousOperation
18-
from django.http.response import BadHeaderError, ResponseHeaders
1918
from django.shortcuts import redirect
2019
from django.urls import reverse
2120
from django.utils.deprecation import MiddlewareMixin
21+
from django.utils.encoding import iri_to_uri
2222
from django.utils.html import escape
2323

2424
from readthedocs.builds.models import Version
@@ -373,23 +373,9 @@ def _get_https_redirect(self, request):
373373
def add_resolver_headers(self, request, response):
374374
if request.unresolved_url is not None:
375375
# TODO: add more ``X-RTD-Resolver-*`` headers
376-
header_value = escape(request.unresolved_url.filename)
377-
try:
378-
# Use Django internals to validate the header's value before injecting it.
379-
ResponseHeaders({})._convert_to_charset(
380-
header_value,
381-
"latin-1",
382-
mime_encode=True,
383-
)
384-
385-
response["X-RTD-Resolver-Filename"] = header_value
386-
except BadHeaderError:
387-
# Skip adding the header because it fails validation
388-
log.info(
389-
"Skip adding X-RTD-Resolver-Filename header due to invalid value.",
390-
filename=request.unresolved_url.filename,
391-
value=header_value,
392-
)
376+
uri_filename = iri_to_uri(request.unresolved_url.filename)
377+
header_value = escape(uri_filename)
378+
response["X-RTD-Resolver-Filename"] = header_value
393379

394380
def process_response(self, request, response): # noqa
395381
self.add_proxito_headers(request, response)

readthedocs/proxito/tests/test_headers.py

+23
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,29 @@ def test_serve_headers_with_path(self):
7575
"/proxito/media/html/project/latest/guides/jupyter/gallery.html",
7676
)
7777

78+
# refs https://read-the-docs.sentry.io/issues/5019718893/
79+
def test_serve_headers_with_unicode(self):
80+
r = self.client.get(
81+
"/en/latest/tutorial_1installation.htmlReview%20of%20Failures%20of%0BReview%20of%20Failures%20of%0BPhotovoltaic%20Moduleshotovoltaic%20Modules",
82+
secure=True,
83+
headers={"host": "project.dev.readthedocs.io"},
84+
)
85+
self.assertEqual(r.status_code, 200)
86+
self.assertEqual(r["Cache-Tag"], "project,project:latest")
87+
self.assertEqual(r["X-RTD-Domain"], "project.dev.readthedocs.io")
88+
self.assertEqual(r["X-RTD-Project"], "project")
89+
self.assertEqual(r["X-RTD-Project-Method"], "public_domain")
90+
self.assertEqual(r["X-RTD-Version"], "latest")
91+
self.assertEqual(r["X-RTD-version-Method"], "path")
92+
self.assertEqual(
93+
r["X-RTD-Resolver-Filename"],
94+
"/tutorial_1installation.htmlReview%20of%20Failures%20of%0BReview%20of%20Failures%20of%0BPhotovoltaic%20Moduleshotovoltaic%20Modules",
95+
)
96+
self.assertEqual(
97+
r["X-RTD-Path"],
98+
"/proxito/media/html/project/latest/tutorial_1installation.htmlReview%20of%20Failures%20of%0BReview%20of%20Failures%20of%0BPhotovoltaic%20Moduleshotovoltaic%20Modules",
99+
)
100+
78101
def test_subproject_serve_headers(self):
79102
r = self.client.get(
80103
"/projects/subproject/en/latest/",

readthedocs/proxito/tests/test_old_redirects.py

-1
Original file line numberDiff line numberDiff line change
@@ -1397,7 +1397,6 @@ def test_redirect_exact_with_wildcard_crossdomain(self):
13971397
r = self.client.get(url, headers={"host": "project.dev.readthedocs.io"})
13981398
self.assertEqual(r.status_code, 302, url)
13991399
self.assertEqual(r["Location"], expected_location, url)
1400-
self.assertNotIn("X-RTD-Resolver-Filename", r.headers)
14011400

14021401
def test_redirect_html_to_clean_url_crossdomain(self):
14031402
"""

0 commit comments

Comments
 (0)