19
19
from readthedocs .analytics .utils import get_client_ip
20
20
from readthedocs .audit .models import AuditLog
21
21
from readthedocs .builds .constants import EXTERNAL , INTERNAL
22
- from readthedocs .core .resolver import resolve
22
+ from readthedocs .core .resolver import resolve , resolver
23
+ from readthedocs .core .utils .url import join_url_path
23
24
from readthedocs .projects .constants import MEDIA_TYPE_HTML
24
25
from readthedocs .proxito .constants import RedirectType
25
26
from readthedocs .redirects .exceptions import InfiniteRedirectException
@@ -331,10 +332,8 @@ def canonical_redirect(
331
332
self ,
332
333
request ,
333
334
final_project ,
334
- version_slug ,
335
- filename ,
336
335
redirect_type ,
337
- is_external_version = False ,
336
+ external_version_slug = None ,
338
337
):
339
338
"""
340
339
Return a redirect to the canonical domain including scheme.
@@ -352,34 +351,30 @@ def canonical_redirect(
352
351
353
352
:param request: Request object.
354
353
:param final_project: The current project being served.
355
- :param version_slug: The current version slug being served.
356
- :param filename: The filename being served.
357
354
:param redirect_type: The type of canonical redirect (https, canonical-cname, subproject-main-domain)
358
- :param external: If the version is from a pull request preview.
355
+ :param external_version_slug: The version slug if the request is from a pull request preview.
359
356
"""
360
357
from_url = request .build_absolute_uri ()
361
358
parsed_from = urlparse (from_url )
362
359
363
360
if redirect_type == RedirectType .http_to_https :
364
361
to = parsed_from ._replace (scheme = "https" ).geturl ()
365
- elif redirect_type in [
366
- RedirectType .to_canonical_domain ,
367
- RedirectType .subproject_to_main_domain ,
368
- ]:
369
- to = resolve (
362
+ elif redirect_type == RedirectType .to_canonical_domain :
363
+ canonical_domain = final_project .get_canonical_custom_domain ()
364
+ protocol = "https" if canonical_domain .https else "http"
365
+ to = parsed_from ._replace (
366
+ scheme = protocol , netloc = canonical_domain .domain
367
+ ).geturl ()
368
+ elif redirect_type == RedirectType .subproject_to_main_domain :
369
+ project_doc_root = resolver .resolve_root (
370
370
project = final_project ,
371
- version_slug = version_slug ,
372
- filename = filename ,
373
- query_params = parsed_from .query ,
374
- external = is_external_version ,
371
+ external_version_slug = external_version_slug ,
375
372
)
376
- # When a canonical redirect is done, only change the domain.
377
- if redirect_type == RedirectType .to_canonical_domain :
378
- parsed_to = urlparse (to )
379
- to = parsed_from ._replace (
380
- scheme = parsed_to .scheme ,
381
- netloc = parsed_to .netloc ,
382
- ).geturl ()
373
+ parsed_doc_root = urlparse (project_doc_root )
374
+ to = parsed_doc_root ._replace (
375
+ path = join_url_path (parsed_doc_root .path , parsed_from .path ),
376
+ query = parsed_from .query ,
377
+ ).geturl ()
383
378
else :
384
379
raise NotImplementedError
385
380
@@ -391,7 +386,11 @@ def canonical_redirect(
391
386
)
392
387
raise InfiniteRedirectException ()
393
388
394
- log .info ('Canonical Redirect.' , host = request .get_host (), from_url = filename , to_url = to )
389
+ log .info (
390
+ "Canonical Redirect." , host = request .get_host (), from_url = from_url , to_url = to
391
+ )
392
+ # Canocanical redirects can be cached, since the final URL will check for authz.
393
+ self .cache_request = True
395
394
resp = HttpResponseRedirect (to )
396
395
resp ["X-RTD-Redirect" ] = redirect_type .name
397
396
return resp
0 commit comments