Skip to content

Commit 86fda57

Browse files
stsewdhumitos
andauthored
404: skip not built versions (#10681)
- Don't check for index files - Don't check for custom 404 pages Since if the version is marked as not built, there aren't any files to check. --------- Co-authored-by: Manuel Kaufmann <[email protected]>
1 parent b1b9704 commit 86fda57

File tree

2 files changed

+99
-8
lines changed

2 files changed

+99
-8
lines changed

readthedocs/proxito/tests/test_full.py

+82
Original file line numberDiff line numberDiff line change
@@ -1007,6 +1007,88 @@ def test_redirects_to_correct_index_ending_without_slash(self):
10071007
self.assertEqual(response['location'], '/en/fancy-version/not-found/README.html')
10081008

10091009
@mock.patch.object(BuildMediaFileSystemStorageTest, 'open')
1010+
def test_404_index_redirect_skips_not_built_versions(self, storage_open):
1011+
self.version.built = False
1012+
self.version.save()
1013+
get(
1014+
HTMLFile,
1015+
project=self.project,
1016+
version=self.version,
1017+
path="foo/index.html",
1018+
name="index.html",
1019+
)
1020+
1021+
response = self.client.get(
1022+
reverse(
1023+
"proxito_404_handler",
1024+
kwargs={"proxito_path": "/en/latest/foo"},
1025+
),
1026+
headers={"host": "project.readthedocs.io"},
1027+
)
1028+
self.assertEqual(response.status_code, 404)
1029+
storage_open.assert_not_called()
1030+
1031+
@mock.patch.object(BuildMediaFileSystemStorageTest, "open")
1032+
def test_custom_404_skips_not_built_versions(self, storage_open):
1033+
self.version.built = False
1034+
self.version.save()
1035+
1036+
fancy_version = fixture.get(
1037+
Version,
1038+
slug="fancy-version",
1039+
privacy_level=constants.PUBLIC,
1040+
active=True,
1041+
built=False,
1042+
project=self.project,
1043+
)
1044+
1045+
get(
1046+
HTMLFile,
1047+
project=self.project,
1048+
version=self.version,
1049+
path="404.html",
1050+
name="404.html",
1051+
)
1052+
1053+
get(
1054+
HTMLFile,
1055+
project=self.project,
1056+
version=fancy_version,
1057+
path="404.html",
1058+
name="404.html",
1059+
)
1060+
1061+
response = self.client.get(
1062+
reverse(
1063+
"proxito_404_handler",
1064+
kwargs={"proxito_path": "/en/fancy-version/not-found"},
1065+
),
1066+
headers={"host": "project.readthedocs.io"},
1067+
)
1068+
self.assertEqual(response.status_code, 404)
1069+
storage_open.assert_not_called()
1070+
1071+
@mock.patch.object(BuildMediaFileSystemStorageTest, "open")
1072+
def test_custom_404_doesnt_exist_in_storage(self, storage_open):
1073+
storage_open.side_effect = FileNotFoundError
1074+
get(
1075+
HTMLFile,
1076+
project=self.project,
1077+
version=self.version,
1078+
path="404.html",
1079+
name="404.html",
1080+
)
1081+
response = self.client.get(
1082+
reverse(
1083+
"proxito_404_handler",
1084+
kwargs={"proxito_path": "/en/latest/not-found"},
1085+
),
1086+
headers={"host": "project.readthedocs.io"},
1087+
)
1088+
self.assertEqual(response.status_code, 404)
1089+
storage_open.assert_called_once_with("html/project/latest/404.html")
1090+
1091+
@mock.patch.object(BuildMediaFileSystemStorageTest, "open")
10101092
def test_404_storage_serves_custom_404_sphinx_single_html(self, storage_open):
10111093
self.project.versions.update(active=True, built=True)
10121094
fancy_version = fixture.get(

readthedocs/proxito/views/serve.py

+17-8
Original file line numberDiff line numberDiff line change
@@ -444,8 +444,10 @@ def get(self, request, proxito_path):
444444
# If we were able to resolve to a valid version, it means that the
445445
# current file doesn't exist. So we check if we can redirect to its
446446
# index file if it exists before doing anything else.
447+
# If the version isn't marked as built, we don't check for index files,
448+
# since the version doesn't have any files.
447449
# This is /en/latest/foo -> /en/latest/foo/index.html.
448-
if version:
450+
if version and version.built:
449451
response = self._get_index_file_redirect(
450452
request=request,
451453
project=project,
@@ -549,15 +551,18 @@ def _get_custom_404_page(self, request, project, version=None):
549551
550552
We check for a 404.html or 404/index.html file.
551553
554+
We don't check for a custom 404 page in versions that aren't marked as built,
555+
since they don't have any files.
556+
552557
If a 404 page is found, we return a response with the content of that file,
553558
`None` otherwise.
554559
"""
555-
versions_404 = [version] if version else []
560+
versions_404 = [version] if version and version.built else []
556561
if not version or version.slug != project.default_version:
557562
default_version = project.versions.filter(
558563
slug=project.default_version
559564
).first()
560-
if default_version:
565+
if default_version and default_version.built:
561566
versions_404.append(default_version)
562567

563568
if not versions_404:
@@ -594,11 +599,15 @@ def _get_custom_404_page(self, request, project, version=None):
594599
version_slug_404=version_404.slug,
595600
storage_filename_path=storage_filename_path,
596601
)
597-
resp = HttpResponse(
598-
build_media_storage.open(storage_filename_path).read()
599-
)
600-
resp.status_code = 404
601-
return resp
602+
try:
603+
content = build_media_storage.open(storage_filename_path).read()
604+
return HttpResponse(content, status=404)
605+
except FileNotFoundError:
606+
log.warning(
607+
"File not found in storage. File out of sync with DB.",
608+
file=storage_filename_path,
609+
)
610+
return None
602611
return None
603612

604613
def _get_index_file_redirect(self, request, project, version, filename, full_path):

0 commit comments

Comments
 (0)