From b231b6eea380da5463c691a9a710fb456a9ec49b Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Wed, 1 Feb 2023 20:25:08 -0500 Subject: [PATCH 1/6] Refactor proxito middleware --- readthedocs/core/unresolver.py | 78 +++++++++++----- readthedocs/proxito/middleware.py | 147 +++++++++++++++--------------- 2 files changed, 126 insertions(+), 99 deletions(-) diff --git a/readthedocs/core/unresolver.py b/readthedocs/core/unresolver.py index 15e04dcf92d..299dd984652 100644 --- a/readthedocs/core/unresolver.py +++ b/readthedocs/core/unresolver.py @@ -1,5 +1,6 @@ import re from dataclasses import dataclass +from enum import Enum, auto from urllib.parse import ParseResult, urlparse import structlog @@ -17,19 +18,24 @@ class UnresolverError(Exception): pass -class SuspiciousHostnameError(UnresolverError): +class DomainError(UnresolverError): + def __init__(self, domain): + self.domain = domain + + +class SuspiciousHostnameError(DomainError): pass -class InvalidSubdomainError(UnresolverError): +class InvalidSubdomainError(DomainError): pass -class InvalidExternalDomainError(UnresolverError): +class InvalidExternalDomainError(DomainError): pass -class InvalidCustomDomainError(UnresolverError): +class InvalidCustomDomainError(DomainError): pass @@ -53,6 +59,21 @@ class UnresolvedURL: external: bool = False +class OriginType(Enum): + custom_domain = auto() + public_domain = auto() + external_domain = auto() + http_header = auto() + + +@dataclass(slots=True) +class UnresolvedDomain: + origin: OriginType + project: Project + domain: Domain = None + external_version_slug: str = None + + class Unresolver: # This pattern matches: # - /en @@ -98,19 +119,17 @@ def unresolve(self, url, append_indexhtml=True): """ parsed = urlparse(url) domain = self.get_domain_from_host(parsed.netloc) - parent_project, domain_object, external_version_slug = self.unresolve_domain( - domain - ) + unresolved_domain = self.unresolve_domain(domain) current_project, version, filename = self._unresolve_path( - parent_project=parent_project, + parent_project=unresolved_domain.project, path=parsed.path, - external_version_slug=external_version_slug, + external_version_slug=unresolved_domain.external_version_slug, ) # Make sure we are serving the external version from the subdomain. - if external_version_slug and version: - if external_version_slug != version.slug: + if unresolved_domain.origin == OriginType.external_domain and version: + if unresolved_domain.external_version_slug != version.slug: log.warning( "Invalid version for external domain.", domain=domain, @@ -133,13 +152,13 @@ def unresolve(self, url, append_indexhtml=True): filename += "index.html" return UnresolvedURL( - parent_project=parent_project, - project=current_project or parent_project, + parent_project=unresolved_domain.project, + project=current_project or unresolved_domain.project, version=version, filename=filename, parsed_url=parsed, - domain=domain_object, - external=bool(external_version_slug), + domain=unresolved_domain.domain, + external=unresolved_domain.origin == OriginType.external_domain, ) @staticmethod @@ -341,12 +360,15 @@ def unresolve_domain(self, domain): if public_domain == root_domain: project_slug = subdomain log.debug("Public domain.", domain=domain) - return self._resolve_project_slug(project_slug), None, None + return UnresolvedDomain( + origin=OriginType.public_domain, + project=self._resolve_project_slug(project_slug, domain), + ) # NOTE: This can catch some possibly valid domains (docs.readthedocs.io.com) # for example, but these might be phishing, so let's block them for now. log.warning("Weird variation of our domain.", domain=domain) - raise SuspiciousHostnameError() + raise SuspiciousHostnameError(domain=domain) # Serve PR builds on external_domain host. if external_domain in domain: @@ -354,17 +376,21 @@ def unresolve_domain(self, domain): try: project_slug, version_slug = subdomain.rsplit("--", maxsplit=1) log.debug("External versions domain.", domain=domain) - return self._resolve_project_slug(project_slug), None, version_slug + return UnresolvedDomain( + origin=OriginType.external_domain, + project=self._resolve_project_slug(project_slug, domain), + external_version_slug=version_slug, + ) except ValueError: log.info( "Invalid format of external versions domain.", domain=domain ) - raise InvalidExternalDomainError() + raise InvalidExternalDomainError(domain=domain) # NOTE: This can catch some possibly valid domains (docs.readthedocs.build.com) # for example, but these might be phishing, so let's block them for now. log.warning("Weird variation of our domain.", domain=domain) - raise SuspiciousHostnameError() + raise SuspiciousHostnameError(domain=domain) # Custom domain. domain_object = ( @@ -372,17 +398,21 @@ def unresolve_domain(self, domain): ) if not domain_object: log.info("Invalid domain.", domain=domain) - raise InvalidCustomDomainError() + raise InvalidCustomDomainError(domain=domain) log.debug("Custom domain.", domain=domain) - return domain_object.project, domain_object, None + return UnresolvedDomain( + origin=OriginType.custom_domain, + project=domain_object.project, + domain=domain_object, + ) - def _resolve_project_slug(self, slug): + def _resolve_project_slug(self, slug, domain): """Get the project from the slug or raise an exception if not found.""" try: return Project.objects.get(slug=slug) except Project.DoesNotExist: - raise InvalidSubdomainError() + raise InvalidSubdomainError(domain=domain) unresolver = Unresolver() diff --git a/readthedocs/proxito/middleware.py b/readthedocs/proxito/middleware.py index 2d93a0989ec..f99770b1749 100644 --- a/readthedocs/proxito/middleware.py +++ b/readthedocs/proxito/middleware.py @@ -20,17 +20,19 @@ InvalidCustomDomainError, InvalidExternalDomainError, InvalidSubdomainError, + OriginType, SuspiciousHostnameError, + UnresolvedDomain, unresolver, ) from readthedocs.core.utils import get_cache_tag from readthedocs.projects.models import Domain, Project, ProjectRelationship from readthedocs.proxito import constants -log = structlog.get_logger(__name__) # noqa +log = structlog.get_logger(__name__) -def map_host_to_project(request): # pylint: disable=too-many-return-statements +def map_host_to_project(request): """ Take the request and map the host to the proper project. @@ -49,76 +51,16 @@ def map_host_to_project(request): # pylint: disable=too-many-return-statements host = unresolver.get_domain_from_host(request.get_host()) # Explicit Project slug being passed in. - if "HTTP_X_RTD_SLUG" in request.META: - project_slug = request.headers["X-RTD-Slug"].lower() - project = Project.objects.filter(slug=project_slug).first() + header_project_slug = request.headers.get("X-RTD-Slug", "").lower() + if header_project_slug: + project = Project.objects.filter(slug=header_project_slug).first() if project: - request.rtdheader = True - log.info('Setting project based on X_RTD_SLUG header.', project_slug=project_slug) - return project + log.info( + "Setting project based on X_RTD_SLUG header.", project_slug=project.slug + ) + return UnresolvedDomain(origin=OriginType.http_header, project=project) - try: - project, domain_object, external_version_slug = unresolver.unresolve_domain( - host - ) - except SuspiciousHostnameError: - log.warning("Weird variation on our hostname.", host=host) - return render( - request, - "core/dns-404.html", - context={"host": host}, - status=400, - ) - except (InvalidSubdomainError, InvalidExternalDomainError): - log.debug("Invalid project set on the subdomain.") - raise Http404 - except InvalidCustomDomainError: - # Some person is CNAMEing to us without configuring a domain - 404. - log.debug("CNAME 404.", host=host) - return render(request, "core/dns-404.html", context={"host": host}, status=404) - - # Custom domain. - if domain_object: - request.cname = True - request.domain = domain_object - log.debug('Proxito CNAME.', host=host) - - if domain_object.https and not request.is_secure(): - # Redirect HTTP -> HTTPS (302) for this custom domain. - log.debug('Proxito CNAME HTTPS Redirect.', host=host) - request.canonicalize = constants.REDIRECT_HTTPS - - # NOTE: consider redirecting non-canonical custom domains to the canonical one - # Whether that is another custom domain or the public domain - - return project - - # Pull request previews. - if external_version_slug: - request.external_domain = True - request.host_version_slug = external_version_slug - log.debug("Proxito External Version Domain.", host=host) - return project - - # Normal doc serving. - request.subdomain = True - log.debug("Proxito Public Domain.", host=host) - if ( - Domain.objects.filter(project=project) - .filter( - canonical=True, - https=True, - ) - .exists() - ): - log.debug("Proxito Public Domain -> Canonical Domain Redirect.", host=host) - request.canonicalize = constants.REDIRECT_CANONICAL_CNAME - elif ProjectRelationship.objects.filter(child=project).exists(): - log.debug( - "Proxito Public Domain -> Subproject Main Domain Redirect.", host=host - ) - request.canonicalize = constants.REDIRECT_SUBPROJECT_MAIN_DOMAIN - return project + return unresolver.unresolve_domain(host) class ProxitoMiddleware(MiddlewareMixin): @@ -258,6 +200,45 @@ def add_cache_headers(self, request, response): # Set the key to private only if it hasn't already been set by the view. response.headers.setdefault('CDN-Cache-Control', 'private') + def _set_request_attributes(self, request, unresolved_domain): + # TODO: Set the unresolved_domain in the request instead of each of these. + origin = unresolved_domain.origin + project = unresolved_domain.project + if origin == OriginType.http_header: + request.rtdheader = True + elif origin == OriginType.custom_domain: + domain = unresolved_domain.domain + request.cname = True + request.domain = domain + if domain.https and not request.is_secure(): + # Redirect HTTP -> HTTPS (302) for this custom domain. + log.debug("Proxito CNAME HTTPS Redirect.", domain=domain.domain) + request.canonicalize = constants.REDIRECT_HTTPS + elif origin == OriginType.external_domain: + request.external_domain = True + request.host_version_slug = unresolved_domain.external_version_slug + elif origin == OriginType.public_domain: + request.subdomain = True + canonical_domain = ( + Domain.objects.filter(project=project) + .filter(canonical=True, https=True) + .exists() + ) + if canonical_domain: + log.debug( + "Proxito Public Domain -> Canonical Domain Redirect.", + project_slug=project.slug, + ) + request.canonicalize = constants.REDIRECT_CANONICAL_CNAME + elif ProjectRelationship.objects.filter(child=project).exists(): + log.debug( + "Proxito Public Domain -> Subproject Main Domain Redirect.", + project_slug=project.slug, + ) + request.canonicalize = constants.REDIRECT_SUBPROJECT_MAIN_DOMAIN + else: + raise NotImplementedError + def process_request(self, request): # noqa skip = any( request.path.startswith(reverse(view)) @@ -272,11 +253,27 @@ def process_request(self, request): # noqa log.debug('Not processing Proxito middleware') return None - ret = map_host_to_project(request) + try: + unresolved_domain = map_host_to_project(request) + except SuspiciousHostnameError as e: + log.warning("Weird variation on our hostname.", domain=e.domain) + return render( + request, + "core/dns-404.html", + context={"host": e.domain}, + status=400, + ) + except (InvalidSubdomainError, InvalidExternalDomainError): + log.debug("Invalid project set on the subdomain.") + raise Http404 + except InvalidCustomDomainError as e: + # Some person is CNAMEing to us without configuring a domain - 404. + log.debug("CNAME 404.", domain=e.domain) + return render( + request, "core/dns-404.html", context={"host": e.domain}, status=404 + ) - # Handle returning a response - if hasattr(ret, 'status_code'): - return ret + self._set_request_attributes(request, unresolved_domain) # Remove multiple slashes from URL's if '//' in request.path: @@ -297,7 +294,7 @@ def process_request(self, request): # noqa ) return redirect(final_url) - project = ret + project = unresolved_domain.project log.debug( 'Proxito Project.', project_slug=project.slug, From b64f9a7143ea24c771925e78ebdddd5d4fb03f7c Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Wed, 1 Feb 2023 20:45:13 -0500 Subject: [PATCH 2/6] Move method from middleware to unresolver --- readthedocs/core/unresolver.py | 29 +++++++++++++++++++++++++ readthedocs/proxito/middleware.py | 36 ++----------------------------- 2 files changed, 31 insertions(+), 34 deletions(-) diff --git a/readthedocs/core/unresolver.py b/readthedocs/core/unresolver.py index 299dd984652..9b4fd3538a6 100644 --- a/readthedocs/core/unresolver.py +++ b/readthedocs/core/unresolver.py @@ -414,6 +414,35 @@ def _resolve_project_slug(self, slug, domain): except Project.DoesNotExist: raise InvalidSubdomainError(domain=domain) + def unresolve_domain_from_request(self, request): + """ + Take the request and map the host to the proper project. + + We check, in order: + + * The ``HTTP_X_RTD_SLUG`` host header for explicit Project mapping + - This sets ``request.rtdheader`` True + * The ``PUBLIC_DOMAIN`` where we can use the subdomain as the project name + - This sets ``request.subdomain`` True + * The hostname without port information, which maps to ``Domain`` objects + - This sets ``request.cname`` True + * The domain is the canonical one and using HTTPS if supported + - This sets ``request.canonicalize`` with the value as the reason + """ + # Explicit Project slug being passed in. + header_project_slug = request.headers.get("X-RTD-Slug", "").lower() + if header_project_slug: + project = Project.objects.filter(slug=header_project_slug).first() + if project: + log.info( + "Setting project based on X_RTD_SLUG header.", + project_slug=project.slug, + ) + return UnresolvedDomain(origin=OriginType.http_header, project=project) + + host = self.get_domain_from_host(request.get_host()) + return unresolver.unresolve_domain(host) + unresolver = Unresolver() unresolve = unresolver.unresolve diff --git a/readthedocs/proxito/middleware.py b/readthedocs/proxito/middleware.py index f99770b1749..955ff1afc1d 100644 --- a/readthedocs/proxito/middleware.py +++ b/readthedocs/proxito/middleware.py @@ -22,47 +22,15 @@ InvalidSubdomainError, OriginType, SuspiciousHostnameError, - UnresolvedDomain, unresolver, ) from readthedocs.core.utils import get_cache_tag -from readthedocs.projects.models import Domain, Project, ProjectRelationship +from readthedocs.projects.models import Domain, ProjectRelationship from readthedocs.proxito import constants log = structlog.get_logger(__name__) -def map_host_to_project(request): - """ - Take the request and map the host to the proper project. - - We check, in order: - - * The ``HTTP_X_RTD_SLUG`` host header for explicit Project mapping - - This sets ``request.rtdheader`` True - * The ``PUBLIC_DOMAIN`` where we can use the subdomain as the project name - - This sets ``request.subdomain`` True - * The hostname without port information, which maps to ``Domain`` objects - - This sets ``request.cname`` True - * The domain is the canonical one and using HTTPS if supported - - This sets ``request.canonicalize`` with the value as the reason - """ - - host = unresolver.get_domain_from_host(request.get_host()) - - # Explicit Project slug being passed in. - header_project_slug = request.headers.get("X-RTD-Slug", "").lower() - if header_project_slug: - project = Project.objects.filter(slug=header_project_slug).first() - if project: - log.info( - "Setting project based on X_RTD_SLUG header.", project_slug=project.slug - ) - return UnresolvedDomain(origin=OriginType.http_header, project=project) - - return unresolver.unresolve_domain(host) - - class ProxitoMiddleware(MiddlewareMixin): """The actual middleware we'll be using in prod.""" @@ -254,7 +222,7 @@ def process_request(self, request): # noqa return None try: - unresolved_domain = map_host_to_project(request) + unresolved_domain = unresolver.unresolve_domain_from_request(request) except SuspiciousHostnameError as e: log.warning("Weird variation on our hostname.", domain=e.domain) return render( From 150c0522cbe68c1b0b1e87e216457b206fedafcd Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Thu, 2 Feb 2023 11:47:23 -0500 Subject: [PATCH 3/6] Linter --- readthedocs/core/unresolver.py | 26 ++++++++++++-------------- readthedocs/proxito/middleware.py | 25 ++++++++++++++++++------- 2 files changed, 30 insertions(+), 21 deletions(-) diff --git a/readthedocs/core/unresolver.py b/readthedocs/core/unresolver.py index 9b4fd3538a6..74c4386bc94 100644 --- a/readthedocs/core/unresolver.py +++ b/readthedocs/core/unresolver.py @@ -60,6 +60,9 @@ class UnresolvedURL: class OriginType(Enum): + + """From where the custom domain was resolved.""" + custom_domain = auto() public_domain = auto() external_domain = auto() @@ -344,8 +347,7 @@ def unresolve_domain(self, domain): Unresolve domain by extracting relevant information from it. :param str domain: Domain to extract the information from. - :returns: A tuple with: the project, domain object, and the - external version slug if the domain is from an external version. + :returns: A UnresolvedDomain object. """ public_domain = self.get_domain_from_host(settings.PUBLIC_DOMAIN) external_domain = self.get_domain_from_host( @@ -416,18 +418,14 @@ def _resolve_project_slug(self, slug, domain): def unresolve_domain_from_request(self, request): """ - Take the request and map the host to the proper project. - - We check, in order: - - * The ``HTTP_X_RTD_SLUG`` host header for explicit Project mapping - - This sets ``request.rtdheader`` True - * The ``PUBLIC_DOMAIN`` where we can use the subdomain as the project name - - This sets ``request.subdomain`` True - * The hostname without port information, which maps to ``Domain`` objects - - This sets ``request.cname`` True - * The domain is the canonical one and using HTTPS if supported - - This sets ``request.canonicalize`` with the value as the reason + Unresolve domain by extracting relevant information from the request. + + We first check if the ``X-RTD-Slug`` header has been set for explicit + project mapping, otherwise we unresolve by calling `self.unresolve_domain` + on the host. + + :param request: Request to extract the information from. + :returns: A UnresolvedDomain object. """ # Explicit Project slug being passed in. header_project_slug = request.headers.get("X-RTD-Slug", "").lower() diff --git a/readthedocs/proxito/middleware.py b/readthedocs/proxito/middleware.py index 955ff1afc1d..ccd519ed496 100644 --- a/readthedocs/proxito/middleware.py +++ b/readthedocs/proxito/middleware.py @@ -169,7 +169,18 @@ def add_cache_headers(self, request, response): response.headers.setdefault('CDN-Cache-Control', 'private') def _set_request_attributes(self, request, unresolved_domain): - # TODO: Set the unresolved_domain in the request instead of each of these. + """ + Set attributes in the request from the unresolved domain. + + - If the project was extracted from the ``X-RTD-Slug`` header, + we set ``request.rtdheader`` to `True`. + - If the project was extracted from the public domain, + we set ``request.subdomain`` to `True`. + - If the project was extracted from a custom domain, + we set ``request.cname`` to `True`. + - If the domain needs to redirect, set the canonicalize attribute accordingly. + """ + # TODO: Set the unresolved domain in the request instead of each of these attributes. origin = unresolved_domain.origin project = unresolved_domain.project if origin == OriginType.http_header: @@ -223,22 +234,22 @@ def process_request(self, request): # noqa try: unresolved_domain = unresolver.unresolve_domain_from_request(request) - except SuspiciousHostnameError as e: - log.warning("Weird variation on our hostname.", domain=e.domain) + except SuspiciousHostnameError as exc: + log.warning("Weird variation on our hostname.", domain=exc.domain) return render( request, "core/dns-404.html", - context={"host": e.domain}, + context={"host": exc.domain}, status=400, ) except (InvalidSubdomainError, InvalidExternalDomainError): log.debug("Invalid project set on the subdomain.") raise Http404 - except InvalidCustomDomainError as e: + except InvalidCustomDomainError as exc: # Some person is CNAMEing to us without configuring a domain - 404. - log.debug("CNAME 404.", domain=e.domain) + log.debug("CNAME 404.", domain=exc.domain) return render( - request, "core/dns-404.html", context={"host": e.domain}, status=404 + request, "core/dns-404.html", context={"host": exc.domain}, status=404 ) self._set_request_attributes(request, unresolved_domain) From ebf3f7fcf9cfad829688870d87be5080649135ad Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Mon, 13 Feb 2023 17:54:29 -0500 Subject: [PATCH 4/6] Rename enum --- readthedocs/core/unresolver.py | 19 +++++++++++-------- readthedocs/proxito/middleware.py | 12 ++++++------ 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/readthedocs/core/unresolver.py b/readthedocs/core/unresolver.py index 74c4386bc94..54b71770483 100644 --- a/readthedocs/core/unresolver.py +++ b/readthedocs/core/unresolver.py @@ -59,7 +59,7 @@ class UnresolvedURL: external: bool = False -class OriginType(Enum): +class DomainSourceType(Enum): """From where the custom domain was resolved.""" @@ -71,7 +71,7 @@ class OriginType(Enum): @dataclass(slots=True) class UnresolvedDomain: - origin: OriginType + source: DomainSourceType project: Project domain: Domain = None external_version_slug: str = None @@ -131,7 +131,7 @@ def unresolve(self, url, append_indexhtml=True): ) # Make sure we are serving the external version from the subdomain. - if unresolved_domain.origin == OriginType.external_domain and version: + if unresolved_domain.source == DomainSourceType.external_domain and version: if unresolved_domain.external_version_slug != version.slug: log.warning( "Invalid version for external domain.", @@ -161,7 +161,7 @@ def unresolve(self, url, append_indexhtml=True): filename=filename, parsed_url=parsed, domain=unresolved_domain.domain, - external=unresolved_domain.origin == OriginType.external_domain, + external=unresolved_domain.source == DomainSourceType.external_domain, ) @staticmethod @@ -363,7 +363,7 @@ def unresolve_domain(self, domain): project_slug = subdomain log.debug("Public domain.", domain=domain) return UnresolvedDomain( - origin=OriginType.public_domain, + source=DomainSourceType.public_domain, project=self._resolve_project_slug(project_slug, domain), ) @@ -379,7 +379,7 @@ def unresolve_domain(self, domain): project_slug, version_slug = subdomain.rsplit("--", maxsplit=1) log.debug("External versions domain.", domain=domain) return UnresolvedDomain( - origin=OriginType.external_domain, + source=DomainSourceType.external_domain, project=self._resolve_project_slug(project_slug, domain), external_version_slug=version_slug, ) @@ -404,7 +404,7 @@ def unresolve_domain(self, domain): log.debug("Custom domain.", domain=domain) return UnresolvedDomain( - origin=OriginType.custom_domain, + source=DomainSourceType.custom_domain, project=domain_object.project, domain=domain_object, ) @@ -436,7 +436,10 @@ def unresolve_domain_from_request(self, request): "Setting project based on X_RTD_SLUG header.", project_slug=project.slug, ) - return UnresolvedDomain(origin=OriginType.http_header, project=project) + return UnresolvedDomain( + source=DomainSourceType.http_header, + project=project, + ) host = self.get_domain_from_host(request.get_host()) return unresolver.unresolve_domain(host) diff --git a/readthedocs/proxito/middleware.py b/readthedocs/proxito/middleware.py index ccd519ed496..77d961db3e4 100644 --- a/readthedocs/proxito/middleware.py +++ b/readthedocs/proxito/middleware.py @@ -17,10 +17,10 @@ from django.utils.deprecation import MiddlewareMixin from readthedocs.core.unresolver import ( + DomainSourceType, InvalidCustomDomainError, InvalidExternalDomainError, InvalidSubdomainError, - OriginType, SuspiciousHostnameError, unresolver, ) @@ -181,11 +181,11 @@ def _set_request_attributes(self, request, unresolved_domain): - If the domain needs to redirect, set the canonicalize attribute accordingly. """ # TODO: Set the unresolved domain in the request instead of each of these attributes. - origin = unresolved_domain.origin + source = unresolved_domain.source project = unresolved_domain.project - if origin == OriginType.http_header: + if source == DomainSourceType.http_header: request.rtdheader = True - elif origin == OriginType.custom_domain: + elif source == DomainSourceType.custom_domain: domain = unresolved_domain.domain request.cname = True request.domain = domain @@ -193,10 +193,10 @@ def _set_request_attributes(self, request, unresolved_domain): # Redirect HTTP -> HTTPS (302) for this custom domain. log.debug("Proxito CNAME HTTPS Redirect.", domain=domain.domain) request.canonicalize = constants.REDIRECT_HTTPS - elif origin == OriginType.external_domain: + elif source == DomainSourceType.external_domain: request.external_domain = True request.host_version_slug = unresolved_domain.external_version_slug - elif origin == OriginType.public_domain: + elif source == DomainSourceType.public_domain: request.subdomain = True canonical_domain = ( Domain.objects.filter(project=project) From d8b27fb1827107514a0222d304a8a07325d2e4e8 Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Mon, 13 Feb 2023 17:57:34 -0500 Subject: [PATCH 5/6] Update docstring --- readthedocs/core/unresolver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readthedocs/core/unresolver.py b/readthedocs/core/unresolver.py index 54b71770483..883de1ce266 100644 --- a/readthedocs/core/unresolver.py +++ b/readthedocs/core/unresolver.py @@ -61,7 +61,7 @@ class UnresolvedURL: class DomainSourceType(Enum): - """From where the custom domain was resolved.""" + """Where the custom domain was resolved from.""" custom_domain = auto() public_domain = auto() From 7bed72d173d2659c23764c344bf1b952941bc717 Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Mon, 13 Feb 2023 19:21:20 -0500 Subject: [PATCH 6/6] Rename --- readthedocs/core/unresolver.py | 4 ++-- readthedocs/proxito/middleware.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/readthedocs/core/unresolver.py b/readthedocs/core/unresolver.py index ff78c2d8d01..9fc3dd79e03 100644 --- a/readthedocs/core/unresolver.py +++ b/readthedocs/core/unresolver.py @@ -18,7 +18,7 @@ class UnresolverError(Exception): pass -class InvalidXRTDSlugHeader(UnresolverError): +class InvalidXRTDSlugHeaderError(UnresolverError): pass @@ -455,7 +455,7 @@ def unresolve_domain_from_request(self, request): "X-RTD-Header passed for project without it enabled.", project_slug=header_project_slug, ) - raise InvalidXRTDSlugHeader + raise InvalidXRTDSlugHeaderError return unresolver.unresolve_domain(host) diff --git a/readthedocs/proxito/middleware.py b/readthedocs/proxito/middleware.py index c7d3fe16be9..a72a967857f 100644 --- a/readthedocs/proxito/middleware.py +++ b/readthedocs/proxito/middleware.py @@ -22,7 +22,7 @@ InvalidCustomDomainError, InvalidExternalDomainError, InvalidSubdomainError, - InvalidXRTDSlugHeader, + InvalidXRTDSlugHeaderError, SuspiciousHostnameError, unresolver, ) @@ -262,7 +262,7 @@ def process_request(self, request): # noqa return render( request, "core/dns-404.html", context={"host": exc.domain}, status=404 ) - except InvalidXRTDSlugHeader: + except InvalidXRTDSlugHeaderError: raise SuspiciousOperation("Invalid X-RTD-Slug header.") self._set_request_attributes(request, unresolved_domain)