Skip to content

Commit

Permalink
Addons + Proxito: return X-RTD-Resolver-Filename and inject via CF
Browse files Browse the repository at this point in the history
Return `X-RTD-Resolver-Filename` from El Proxito and inject it as HTML `meta`
tag from Cloudflare Worker.

Required by readthedocs/addons#211
  • Loading branch information
humitos committed Feb 8, 2024
1 parent 44f0837 commit b12787d
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 7 deletions.
14 changes: 9 additions & 5 deletions dockerfiles/force-readthedocs-addons.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ async function handleRequest(request) {
// get project/version slug from headers inject by El Proxito
const projectSlug = originalResponse.headers.get("x-rtd-project") || "";
const versionSlug = originalResponse.headers.get("x-rtd-version") || "";
const resolverFilename = originalResponse.headers.get("x-rtd-resolver-filename") || "";

// check to decide whether or not inject the new beta addons:
//
Expand Down Expand Up @@ -103,7 +104,7 @@ async function handleRequest(request) {
// .on(readthedocsDataParse, new removeElement())
// .on(readthedocsData, new removeElement())
.on("head", new addPreloads())
.on("head", new addProjectVersionSlug(projectSlug, versionSlug))
.on("head", new addMetaTags(projectSlug, versionSlug, resolverFilename))
.transform(originalResponse)
);
}
Expand All @@ -116,7 +117,7 @@ async function handleRequest(request) {
if (forceAddons === "false" && injectHostingIntegrations === "true") {
return new HTMLRewriter()
.on("head", new addPreloads())
.on("head", new addProjectVersionSlug(projectSlug, versionSlug))
.on("head", new addMetaTags(projectSlug, versionSlug, resolverFilename))
.transform(originalResponse);
}
}
Expand Down Expand Up @@ -155,22 +156,25 @@ class addPreloads {
}
}

class addProjectVersionSlug {
constructor(projectSlug, versionSlug) {
class addMetaTags {
constructor(projectSlug, versionSlug, resolverFilename) {
this.projectSlug = projectSlug;
this.versionSlug = versionSlug;
this.resolverFilename = resolverFilename;
}

element(element) {
console.log(
`addProjectVersionSlug. projectSlug=${this.projectSlug} versionSlug=${this.versionSlug}`,
`addMetaTags. projectSlug=${this.projectSlug} versionSlug=${this.versionSlug} resolverFilename=${this.resolverFilename}`,
);
if (this.projectSlug && this.versionSlug) {
const metaProject = `<meta name="readthedocs-project-slug" content="${this.projectSlug}" />`;
const metaVersion = `<meta name="readthedocs-version-slug" content="${this.versionSlug}" />`;
const metaResolverFilename = `<meta name="readthedocs-resolver-filename" content="${this.resolverFilename}" />`;

element.append(metaProject, { html: true });
element.append(metaVersion, { html: true });
element.append(metaResolverFilename, { html: true });
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions dockerfiles/nginx/proxito.conf.template
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ server {
add_header X-RTD-Project-Method $rtd_project_method always;
set $rtd_redirect $upstream_http_x_rtd_redirect;
add_header X-RTD-Redirect $rtd_redirect always;
set $rtd_resolver_filename $upstream_http_x_rtd_resolver_filename;
add_header X-RTD-Resolver-Filename $rtd_resolver_filename always;
set $cdn_cache_control $upstream_http_cdn_cache_control;
add_header CDN-Cache-Control $cdn_cache_control always;
set $cache_tag $upstream_http_cache_tag;
Expand Down
22 changes: 20 additions & 2 deletions readthedocs/proxito/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@
from readthedocs.core.unresolver import (
InvalidCustomDomainError,
InvalidExternalDomainError,
InvalidPathForVersionedProjectError,
InvalidSubdomainError,
InvalidXRTDSlugHeaderError,
SuspiciousHostnameError,
unresolve,
unresolver,
)
from readthedocs.core.utils import get_cache_tag
Expand Down Expand Up @@ -187,17 +189,19 @@ def add_cache_headers(self, request, response):
else:
cache_response(response, force=False)

def _set_request_attributes(self, request, unresolved_domain):
def _set_request_attributes(self, request, unresolved_domain, unresolved_url):
"""
Set attributes in the request from the unresolved domain.
- Set ``request.unresolved_domain`` to the unresolved domain.
"""
request.unresolved_domain = unresolved_domain
request.unresolved_url = unresolved_url

def process_request(self, request): # noqa
# Initialize our custom request attributes.
request.unresolved_domain = None
request.unresolved_url = None

skip = any(request.path.startswith(reverse(view)) for view in self.skip_views)
if skip:
Expand Down Expand Up @@ -229,7 +233,12 @@ def process_request(self, request): # noqa
except InvalidXRTDSlugHeaderError as exc:
raise SuspiciousOperation("Invalid X-RTD-Slug header.") from exc

self._set_request_attributes(request, unresolved_domain)
try:
unresolved_url = unresolve(request.build_absolute_uri())
except InvalidPathForVersionedProjectError:
unresolved_url = None

self._set_request_attributes(request, unresolved_domain, unresolved_url)

response = self._get_https_redirect(request)
if response:
Expand Down Expand Up @@ -367,11 +376,20 @@ def _get_https_redirect(self, request):

return None

def add_resolver_headers(self, request, response):
# TODO: find a better way to re-use the unresolved URL so we don't
# query the db multiple times on the same request.
# https://github.com/readthedocs/readthedocs.org/issues/10456
if request.unresolved_url is not None:
# TODO: add more ``X-RTD-Resolver-*`` headers
response["X-RTD-Resolver-Filename"] = request.unresolved_url.filename

def process_response(self, request, response): # noqa
self.add_proxito_headers(request, response)
self.add_cache_headers(request, response)
self.add_hsts_headers(request, response)
self.add_user_headers(request, response)
self.add_hosting_integrations_headers(request, response)
self.add_resolver_headers(request, response)
self.add_cors_headers(request, response)
return response

0 comments on commit b12787d

Please sign in to comment.