/origin.js Secret
Last active
December 15, 2022 13:11
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Configure this | |
const swAdnToken = "XXXXXXX"; // Set the ADN token provided by Botify | |
const swAllowedUrls = []; // Set something like https://mysubdomain.mydomain.com/mypages (in lower case) to restrict SW to urls starting with these values | |
const swRewriteOrigin = ""; // Set something like https://www.mydomain.com | |
const swDomain = "XXXXXXXX.sw.adn.cloud"; // Set the SpeedWorkers domain name provided by Botify (no "https://" or trailing "/" here, only the domain) | |
const swPort = 443; | |
const swProtocol = "https"; | |
const swSslProtocols = ["TLSv1", "TLSv1.1", "TLSv1.2"]; | |
const swReadTimeoutSec = 15; | |
const swKeepaliveTimeoutSec = 60; | |
const swCustomHeaders = {}; // Use this format: "user-agent": [ { "value": "ExampleCustomUserAgent/1.X.0"}], ... // https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-event-structure.html#request-event-fields-request-headers | |
// Don't touch this | |
const swAgent = "CloudFrontInterceptor/1.1"; | |
const swIgnored = ["/css/", "/fonts/", "/images/", "/js/", "/scss/", ".bmp", ".css", ".csv", ".doc", ".docx", ".eot", ".gif", ".ico", ".ief", ".jpe", ".jpeg", ".jpg", ".js", ".json", ".less", ".map", ".m1v", ".mov", ".mp2", ".mp3", ".mp4", ".mpa", ".mpe", ".mpeg", ".mpg", ".otf", ".ott", ".ogv", ".pbm", ".pdf", ".pgm", ".png", ".ppm", ".pnm", ".ppt", ".pps", ".ps", ".qt", ".ras", ".rdf", ".rgb", ".rss", ".svg", ".swf", ".tiff", ".tif", ".tsv", ".ttf", ".txt", ".vcf", ".wav", ".webm", ".woff", ".woff2", ".xbm", ".xlm", ".xls", ".xml", ".xpdl", ".xpm", ".xwd"]; // in lower case | |
// Set to true if you want debug logs | |
const debug = true | |
exports.handler = (event, context, callback) => { | |
const request = event.Records[0].cf.request; | |
// Ignore web sockets | |
// Ignore web sockets | |
if (request.headers["Upgrade"] === "websocket") { | |
log("websocket, ignoring request") | |
callback(null, request); | |
return; | |
} | |
// Only filter GETs and HEADs | |
const requestMethod = request.method | |
if (requestMethod !== "GET" && requestMethod !== "HEAD") { | |
log("not a GET/HEAD method, ignoring"); | |
callback(null, request); | |
return; | |
} | |
// We need a way to know if the request comes from a bot or a user | |
// If the request doesn't come from a bot, let it reach the fallback origin without SW | |
if ( | |
request.headers["x-sw-request-type"] === undefined | |
|| (request.headers["x-sw-request-type"] !== undefined && !request.headers["x-sw-request-type"][0].value.startsWith("bot")) | |
) | |
{ | |
delete request.headers["x-sw-request-type"]; | |
log("not a bot (or missing x-sw-request-type header), ignoring"); | |
callback(null, request); | |
return; | |
} | |
delete request.headers["x-sw-request-type"]; | |
// We need the host from the Viewer Request Lambda, or at least a rewrite origin value! | |
if (request.headers["x-sw-host"] === undefined && (swRewriteOrigin === undefined || swRewriteOrigin === "")) | |
{ | |
log("missing x-sw-host, no viewer request lambda?"); | |
callback(null, request); | |
return; | |
} | |
// Retrieve original host set by the viewer request lambda | |
let originalHost = ""; | |
if (request.headers["x-sw-host"] !== undefined) { | |
originalHost = request.headers["x-sw-host"][0].value; | |
delete request.headers["x-sw-host"]; | |
} | |
// Rebuild the complete uri | |
let url = "https://" + originalHost; | |
if (swRewriteOrigin !== undefined && swRewriteOrigin !== "") { | |
url = swRewriteOrigin; | |
} | |
url += request.uri; | |
if (request.querystring !== "") | |
{ | |
url += "?" + request.querystring; | |
} | |
// Ignore requests which url doesn't start with one of the url SW is enabled | |
if (!isUrlAllowed(url)) | |
{ | |
log("url (" + url + ") not allowed, ignoring"); | |
callback(null, request); | |
return; | |
} | |
// Ignore resources that are not handled by SW | |
if (ignorePath(url)) | |
{ | |
log("path " + url + " ignored"); | |
callback(null, request); | |
return; | |
} | |
// The request comes from a bot, send it to SW | |
log("calling SW to get " + url); | |
// Restore user-agent header (to replace Amazon CloudFront user-agent...) | |
// If you don't use the viewer request, please make sure you whitelisted the User-Agent header in the CloudFront conf | |
if (request.headers["x-sw-user-agent"] !== undefined) { | |
request.headers['user-agent'] = [{ key: 'User-Agent', value: request.headers["x-sw-user-agent"][0].value }]; | |
delete request.headers["x-sw-user-agent"]; | |
} | |
request.headers["host"] = [{ key: "host", value: swDomain }]; | |
request.origin = { | |
custom: { | |
domainName: swDomain, | |
port: swPort, | |
protocol: swProtocol, | |
sslProtocols: swSslProtocols, | |
readTimeout: swReadTimeoutSec, | |
keepaliveTimeout: swKeepaliveTimeoutSec, | |
customHeaders: swCustomHeaders | |
} | |
}; | |
request.origin.custom.customHeaders["x-sw-agent"] = [{ key: "x-sw-agent", value: swAgent }]; | |
request.origin.custom.customHeaders["x-sw-client-ip"] = [{ key: "x-sw-client-ip", value: request.clientIp }]; | |
request.origin.custom.customHeaders["x-sw-uri"] = [{ key: "x-sw-uri", value: url }]; | |
request.origin.custom.customHeaders["x-sw-adn-token"] = [{ key: "x-sw-adn-token", value: swAdnToken }]; | |
callback(null, request); | |
}; | |
function log(msg) { | |
if (debug) { | |
console.log(msg) | |
} | |
} | |
// Returns true if the url contains a path sw should ignore | |
function ignorePath(url) | |
{ | |
for (let i = 0; i < swIgnored.length; i++) | |
{ | |
if (url.toLowerCase().includes(swIgnored[i])) | |
return true; | |
} | |
return false; | |
} | |
// Returns true if the url belongs to (starts with) an allowed url | |
function isUrlAllowed(url) { | |
if (swAllowedUrls.length === 0) | |
return true; | |
for (let i = 0; i < swAllowedUrls.length; i++) | |
{ | |
if (url.toLowerCase().startsWith(swAllowedUrls[i])) | |
return true; | |
} | |
return false; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment