Skip to content

Commit 706e192

Browse files
committed
Move new implementation up (ServeError404 view)
1 parent e33a56e commit 706e192

File tree

1 file changed

+127
-130
lines changed

1 file changed

+127
-130
lines changed

readthedocs/proxito/views/serve.py

+127-130
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,133 @@ def get(self, request, proxito_path):
374374
"""
375375
log.bind(proxito_path=proxito_path)
376376
log.debug('Executing 404 handler.')
377-
return self.get_using_unresolver(request, proxito_path)
377+
unresolved_domain = request.unresolved_domain
378+
# We force all storage calls to use the external versions storage,
379+
# since we are serving an external version.
380+
# The version that results from the unresolve_path() call already is
381+
# validated to use the correct manager, this is here to add defense in
382+
# depth against serving the wrong version.
383+
if unresolved_domain.is_from_external_domain:
384+
self.version_type = EXTERNAL
385+
386+
project = None
387+
version = None
388+
# If we weren't able to resolve a filename,
389+
# then the path is the filename.
390+
filename = proxito_path
391+
lang_slug = None
392+
version_slug = None
393+
# Try to map the current path to a project/version/filename.
394+
# If that fails, we fill the variables with the information we have
395+
# available in the exceptions.
396+
397+
contextualized_404_class = ContextualizedHttp404
398+
399+
try:
400+
unresolved = unresolver.unresolve_path(
401+
unresolved_domain=unresolved_domain,
402+
path=proxito_path,
403+
append_indexhtml=False,
404+
)
405+
project = unresolved.project
406+
version = unresolved.version
407+
filename = unresolved.filename
408+
lang_slug = project.language
409+
version_slug = version.slug
410+
contextualized_404_class = ProjectFilenameHttp404
411+
except VersionNotFoundError as exc:
412+
project = exc.project
413+
lang_slug = project.language
414+
version_slug = exc.version_slug
415+
filename = exc.filename
416+
contextualized_404_class = ProjectVersionHttp404
417+
except TranslationNotFoundError as exc:
418+
project = exc.project
419+
lang_slug = exc.language
420+
version_slug = exc.version_slug
421+
filename = exc.filename
422+
contextualized_404_class = ProjectTranslationHttp404
423+
except TranslationWithoutVersionError as exc:
424+
project = exc.project
425+
lang_slug = exc.language
426+
# TODO: Use a contextualized 404
427+
except InvalidExternalVersionError as exc:
428+
project = exc.project
429+
# TODO: Use a contextualized 404
430+
except InvalidPathForVersionedProjectError as exc:
431+
project = exc.project
432+
filename = exc.path
433+
# TODO: Use a contextualized 404
434+
435+
log.bind(
436+
project_slug=project.slug,
437+
version_slug=version_slug,
438+
)
439+
440+
# TODO: find a better way to pass this to the middleware.
441+
request.path_project_slug = project.slug
442+
request.path_version_slug = version_slug
443+
444+
# If we were able to resolve to a valid version, it means that the
445+
# current file doesn't exist. So we check if we can redirect to its
446+
# index file if it exists before doing anything else.
447+
# This is /en/latest/foo -> /en/latest/foo/index.html.
448+
if version:
449+
response = self._get_index_file_redirect(
450+
request=request,
451+
project=project,
452+
version=version,
453+
filename=filename,
454+
full_path=proxito_path,
455+
)
456+
if response:
457+
return response
458+
459+
# Check and perform redirects on 404 handler
460+
# NOTE: this redirect check must be done after trying files like
461+
# ``index.html`` and ``README.html`` to emulate the behavior we had when
462+
# serving directly from NGINX without passing through Python.
463+
redirect_path, http_status = self.get_redirect(
464+
project=project,
465+
lang_slug=lang_slug,
466+
version_slug=version_slug,
467+
filename=filename,
468+
full_path=proxito_path,
469+
)
470+
if redirect_path and http_status:
471+
try:
472+
return self.get_redirect_response(
473+
request, redirect_path, proxito_path, http_status
474+
)
475+
except InfiniteRedirectException:
476+
# ``get_redirect_response`` raises this when it's redirecting back to itself.
477+
# We can safely ignore it here because it's logged in ``canonical_redirect``,
478+
# and we don't want to issue infinite redirects.
479+
pass
480+
481+
# Register 404 pages into our database for user's analytics
482+
self._register_broken_link(
483+
project=project,
484+
version=version,
485+
path=filename,
486+
full_path=proxito_path,
487+
)
488+
489+
response = self._get_custom_404_page(
490+
request=request,
491+
project=project,
492+
version=version,
493+
)
494+
if response:
495+
return response
496+
497+
# Don't use the custom 404 page, use our general contextualized 404 response
498+
# Several additional context variables can be added if the templates
499+
# or other error handling is developed (version, language, filename).
500+
raise contextualized_404_class(
501+
project=project,
502+
path_not_found=proxito_path,
503+
)
378504

379505
def _register_broken_link(self, project, version, path, full_path):
380506
try:
@@ -526,135 +652,6 @@ def _get_index_file_redirect(self, request, project, version, filename, full_pat
526652

527653
return None
528654

529-
def get_using_unresolver(self, request, proxito_path):
530-
unresolved_domain = request.unresolved_domain
531-
# We force all storage calls to use the external versions storage,
532-
# since we are serving an external version.
533-
# The version that results from the unresolve_path() call already is
534-
# validated to use the correct manager, this is here to add defense in
535-
# depth against serving the wrong version.
536-
if unresolved_domain.is_from_external_domain:
537-
self.version_type = EXTERNAL
538-
539-
project = None
540-
version = None
541-
# If we weren't able to resolve a filename,
542-
# then the path is the filename.
543-
filename = proxito_path
544-
lang_slug = None
545-
version_slug = None
546-
# Try to map the current path to a project/version/filename.
547-
# If that fails, we fill the variables with the information we have
548-
# available in the exceptions.
549-
550-
contextualized_404_class = ContextualizedHttp404
551-
552-
try:
553-
unresolved = unresolver.unresolve_path(
554-
unresolved_domain=unresolved_domain,
555-
path=proxito_path,
556-
append_indexhtml=False,
557-
)
558-
project = unresolved.project
559-
version = unresolved.version
560-
filename = unresolved.filename
561-
lang_slug = project.language
562-
version_slug = version.slug
563-
contextualized_404_class = ProjectFilenameHttp404
564-
except VersionNotFoundError as exc:
565-
project = exc.project
566-
lang_slug = project.language
567-
version_slug = exc.version_slug
568-
filename = exc.filename
569-
contextualized_404_class = ProjectVersionHttp404
570-
except TranslationNotFoundError as exc:
571-
project = exc.project
572-
lang_slug = exc.language
573-
version_slug = exc.version_slug
574-
filename = exc.filename
575-
contextualized_404_class = ProjectTranslationHttp404
576-
except TranslationWithoutVersionError as exc:
577-
project = exc.project
578-
lang_slug = exc.language
579-
# TODO: Use a contextualized 404
580-
except InvalidExternalVersionError as exc:
581-
project = exc.project
582-
# TODO: Use a contextualized 404
583-
except InvalidPathForVersionedProjectError as exc:
584-
project = exc.project
585-
filename = exc.path
586-
# TODO: Use a contextualized 404
587-
588-
log.bind(
589-
project_slug=project.slug,
590-
version_slug=version_slug,
591-
)
592-
593-
# TODO: find a better way to pass this to the middleware.
594-
request.path_project_slug = project.slug
595-
request.path_version_slug = version_slug
596-
597-
# If we were able to resolve to a valid version, it means that the
598-
# current file doesn't exist. So we check if we can redirect to its
599-
# index file if it exists before doing anything else.
600-
# This is /en/latest/foo -> /en/latest/foo/index.html.
601-
if version:
602-
response = self._get_index_file_redirect(
603-
request=request,
604-
project=project,
605-
version=version,
606-
filename=filename,
607-
full_path=proxito_path,
608-
)
609-
if response:
610-
return response
611-
612-
# Check and perform redirects on 404 handler
613-
# NOTE: this redirect check must be done after trying files like
614-
# ``index.html`` and ``README.html`` to emulate the behavior we had when
615-
# serving directly from NGINX without passing through Python.
616-
redirect_path, http_status = self.get_redirect(
617-
project=project,
618-
lang_slug=lang_slug,
619-
version_slug=version_slug,
620-
filename=filename,
621-
full_path=proxito_path,
622-
)
623-
if redirect_path and http_status:
624-
try:
625-
return self.get_redirect_response(
626-
request, redirect_path, proxito_path, http_status
627-
)
628-
except InfiniteRedirectException:
629-
# ``get_redirect_response`` raises this when it's redirecting back to itself.
630-
# We can safely ignore it here because it's logged in ``canonical_redirect``,
631-
# and we don't want to issue infinite redirects.
632-
pass
633-
634-
# Register 404 pages into our database for user's analytics
635-
self._register_broken_link(
636-
project=project,
637-
version=version,
638-
path=filename,
639-
full_path=proxito_path,
640-
)
641-
642-
response = self._get_custom_404_page(
643-
request=request,
644-
project=project,
645-
version=version,
646-
)
647-
if response:
648-
return response
649-
650-
# Don't use the custom 404 page, use our general contextualized 404 response
651-
# Several additional context variables can be added if the templates
652-
# or other error handling is developed (version, language, filename).
653-
raise contextualized_404_class(
654-
project=project,
655-
path_not_found=proxito_path,
656-
)
657-
658655

659656
class ServeError404(SettingsOverrideObject):
660657
_default_class = ServeError404Base

0 commit comments

Comments
 (0)