27
27
)
28
28
from readthedocs .core .utils import get_cache_tag
29
29
from readthedocs .projects .models import Feature , Project
30
+ from readthedocs .proxito .cache import add_cache_tags , cache_response , private_response
31
+ from readthedocs .proxito .redirects import redirect_to_https
30
32
31
33
log = structlog .get_logger (__name__ )
32
34
@@ -63,15 +65,14 @@ def add_proxito_headers(self, request, response):
63
65
response ['X-RTD-Path' ] = path
64
66
65
67
# Include the project & project-version so we can do larger purges if needed
66
- cache_tag = response .get ('Cache-Tag' )
67
- cache_tags = [cache_tag ] if cache_tag else []
68
+ cache_tags = []
68
69
if project_slug :
69
70
cache_tags .append (project_slug )
70
71
if version_slug :
71
72
cache_tags .append (get_cache_tag (project_slug , version_slug ))
72
73
73
74
if cache_tags :
74
- response [ 'Cache-Tag' ] = ',' . join ( cache_tags )
75
+ add_cache_tags ( response , cache_tags )
75
76
76
77
unresolved_domain = request .unresolved_domain
77
78
if unresolved_domain :
@@ -167,22 +168,20 @@ def add_cache_headers(self, request, response):
167
168
168
169
See https://developers.cloudflare.com/cache/about/cdn-cache-control.
169
170
"""
170
- cdn_cache_header = "CDN-Cache-Control"
171
171
unresolved_domain = request .unresolved_domain
172
172
# Never trust projects resolving from the X-RTD-Slug header,
173
173
# we don't want to cache their content on domains from other
174
174
# projects, see GHSA-mp38-vprc-7hf5.
175
175
if unresolved_domain and unresolved_domain .is_from_http_header :
176
- response . headers [ cdn_cache_header ] = "private"
176
+ private_response ( response , force = True )
177
177
# SECURITY: Return early, we never want to cache this response.
178
178
return
179
179
180
- # Set the key only if it hasn't already been set by the view.
181
- if cdn_cache_header not in response .headers :
182
- default_cache_level = (
183
- "private" if settings .ALLOW_PRIVATE_REPOS else "public"
184
- )
185
- response .headers [cdn_cache_header ] = default_cache_level
180
+ # Mark the response as private or cache it, if it hasn't been marked as so already.
181
+ if settings .ALLOW_PRIVATE_REPOS :
182
+ private_response (response , force = False )
183
+ else :
184
+ cache_response (response , force = False )
186
185
187
186
def _set_request_attributes (self , request , unresolved_domain ):
188
187
"""
@@ -233,6 +232,10 @@ def process_request(self, request): # noqa
233
232
234
233
self ._set_request_attributes (request , unresolved_domain )
235
234
235
+ response = self ._get_https_redirect (request )
236
+ if response :
237
+ return response
238
+
236
239
# Remove multiple slashes from URL's
237
240
if '//' in request .path :
238
241
url_parsed = urlparse (request .get_full_path ())
@@ -250,7 +253,9 @@ def process_request(self, request): # noqa
250
253
from_url = request .get_full_path (),
251
254
to_url = final_url ,
252
255
)
253
- return redirect (final_url )
256
+ response = redirect (final_url )
257
+ cache_response (response , cache_tags = [unresolved_domain .project .slug ])
258
+ return response
254
259
255
260
project = unresolved_domain .project
256
261
log .debug (
@@ -286,6 +291,37 @@ def add_hosting_integrations_headers(self, request, response):
286
291
if project .has_feature (Feature .HOSTING_INTEGRATIONS ):
287
292
response ["X-RTD-Hosting-Integrations" ] = "true"
288
293
294
+ def _get_https_redirect (self , request ):
295
+ """
296
+ Get a redirect response if the request should be redirected to HTTPS.
297
+
298
+ A request should be redirected to HTTPS if any of the following conditions are met:
299
+
300
+ - It's from a custom domain and the domain has HTTPS enabled.
301
+ - It's from a public domain, and the public domain uses HTTPS.
302
+ """
303
+ if request .is_secure ():
304
+ # The request is already HTTPS, so we skip redirecting it.
305
+ return None
306
+
307
+ unresolved_domain = request .unresolved_domain
308
+
309
+ # HTTPS redirect for custom domains.
310
+ if unresolved_domain .is_from_custom_domain :
311
+ domain = unresolved_domain .domain
312
+ if domain .https :
313
+ return redirect_to_https (request , project = unresolved_domain .project )
314
+ return None
315
+
316
+ # HTTPS redirect for public domains.
317
+ if (
318
+ unresolved_domain .is_from_public_domain
319
+ or unresolved_domain .is_from_external_domain
320
+ ) and settings .PUBLIC_DOMAIN_USES_HTTPS :
321
+ return redirect_to_https (request , project = unresolved_domain .project )
322
+
323
+ return None
324
+
289
325
def process_response (self , request , response ): # noqa
290
326
self .add_proxito_headers (request , response )
291
327
self .add_cache_headers (request , response )
0 commit comments