def canonical_redirect(self, request, final_project, version_slug, filename): """ Return a redirect to the canonical domain including scheme. This is normally used HTTP -> HTTPS redirects or redirects to/from custom domains. """ full_path = request.get_full_path() urlparse_result = urlparse(full_path) to = resolve( project=final_project, version_slug=version_slug, filename=filename, query_params=urlparse_result.query, external=hasattr(request, 'external_domain'), ) if full_path == to: # check that we do have a response and avoid infinite redirect log.warning( 'Infinite Redirect: FROM URL is the same than TO URL. url=%s', to, ) raise InfiniteRedirectException() log.info('Canonical Redirect: host=%s, from=%s, to=%s', request.get_host(), filename, to) resp = HttpResponseRedirect(to) resp['X-RTD-Redirect'] = getattr(request, 'canonicalize', 'unknown') return resp
def canonical_redirect(self, request, final_project, version_slug, filename): """ Return a redirect to the canonical domain including scheme. The following cases are covered: - Redirect a custom domain from http to https (if supported) http://project.rtd.io/ -> https://project.rtd.io/ - Redirect a domain to a canonical domain (http or https). http://project.rtd.io/ -> https://docs.test.com/ http://project.rtd.io/foo/bar/ -> https://docs.test.com/foo/bar/ - Redirect from a subproject domain to the main domain https://subproject.rtd.io/en/latest/foo -> https://main.rtd.io/projects/subproject/en/latest/foo # noqa https://subproject.rtd.io/en/latest/foo -> https://docs.test.com/projects/subproject/en/latest/foo # noqa """ from_url = request.build_absolute_uri() parsed_from = urlparse(from_url) redirect_type = getattr(request, 'canonicalize', None) if redirect_type == REDIRECT_HTTPS: to = parsed_from._replace(scheme='https').geturl() else: to = resolve( project=final_project, version_slug=version_slug, filename=filename, query_params=parsed_from.query, external=hasattr(request, 'external_domain'), ) # When a canonical redirect is done, only change the domain. if redirect_type == REDIRECT_CANONICAL_CNAME: parsed_to = urlparse(to) to = parsed_from._replace( scheme=parsed_to.scheme, netloc=parsed_to.netloc, ).geturl() if from_url == to: # check that we do have a response and avoid infinite redirect log.warning( 'Infinite Redirect: FROM URL is the same than TO URL.', url=to, ) raise InfiniteRedirectException() log.info('Canonical Redirect.', host=request.get_host(), from_url=filename, to_url=to) resp = HttpResponseRedirect(to) resp['X-RTD-Redirect'] = getattr(request, 'canonicalize', 'unknown') return resp
def get_redirect_response(self, request, redirect_path, proxito_path, http_status): """ Build the response for the ``redirect_path``, ``proxito_path`` and its ``http_status``. :returns: redirect respose with the correct path :rtype: HttpResponseRedirect or HttpResponsePermanentRedirect """ schema, netloc, path, params, query, fragments = urlparse(proxito_path) # `proxito_path` doesn't include query params. query = urlparse(request.get_full_path()).query new_path = urlunparse( (schema, netloc, redirect_path, params, query, fragments)) # Re-use the domain and protocol used in the current request. # Redirects shouldn't change the domain, version or language. # However, if the new_path is already an absolute URI, just use it new_path = request.build_absolute_uri(new_path) log.info( 'Redirecting: from=%s to=%s http_status=%s', request.build_absolute_uri(proxito_path), new_path, http_status, ) if request.build_absolute_uri(proxito_path) == new_path: # check that we do have a response and avoid infinite redirect log.warning( 'Infinite Redirect: FROM URL is the same than TO URL. url=%s', new_path, ) raise InfiniteRedirectException() if http_status and http_status == 301: resp = HttpResponsePermanentRedirect(new_path) else: resp = HttpResponseRedirect(new_path) # Add a user-visible header to make debugging easier resp['X-RTD-Redirect'] = 'user' return resp