Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
178 changes: 178 additions & 0 deletions querystring-cleaner.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
// These querystring keys are stripped from the request as they are generally not
// needed by the origin.
const STRIP_QUERYSTRING_KEYS = [
// UTM
"utm_id",
"utm_source",
"utm_campaign",
"utm_medium",
"utm_term",
"utm_content",
"utm_source_platform",
"utm_creative_format",
"utm_marketing_tactic",

"gclid",
"wbraid",
"gbraid",
"fbclid",
"dm_i", // DotDigital
"msclkid",
"al_applink_data", // Meta outbound app links

// https://docs.flying-press.com/cache/ignore-query-strings
"age-verified",
"ao_noptimize",
"usqp",
"cn-reloaded",
"sscid",
"ef_id",
"_bta_tid",
"_bta_c",
"fb_action_ids",
"fb_action_types",
"fb_source",
"_ga",
"adid",
"_gl",
"gclsrc",
"gdfms",
"gdftrk",
"gdffi",
"_ke",
"trk_contact",
"trk_msg",
"trk_module",
"trk_sid",
"mc_cid",
"mc_eid",
"mkwid",
"pcrid",
"mtm_source",
"mtm_medium",
"mtm_campaign",
"mtm_keyword",
"mtm_cid",
"mtm_content",
"epik",
"pp",
"pk_source",
"pk_medium",
"pk_campaign",
"pk_keyword",
"pk_cid",
"pk_content",
"redirect_log_mongo_id",
"redirect_mongo_id",
"sb_referer_host",
];

const INCLUDE_QUERYSTRING_KEYS = [];

// If this is true, the querystring keys stripped from the request will be
// addeed to any Location header served by a redirect.
const REPLACE_STRIPPED_QUERYSTRING_ON_REDIRECT_LOCATION = false;

// If this is true, querystring key are stripped if they have no value eg. ?foo
// Disabled by default, but highly recommended
const STRIP_VALUELESS_QUERYSTRING_KEYS = false;

addEventListener("fetch", (event) => {
event.respondWith(main(event));
});

async function main(event) {
const [request, strippedParams] = filterQuerystring(event.request);

let response = await fetch(request);

if (REPLACE_STRIPPED_QUERYSTRING_ON_REDIRECT_LOCATION) {
response = replaceStrippedQsOnRedirectResponse(response, strippedParams);
}

return response;
}

/*
* Request Utilities
*/

function filterQuerystring(request) {
const removed = {};
const url = new URL(request.url);

url.searchParams.entries().forEach(([key, value]) => {
const isBlocked = STRIP_QUERYSTRING_KEYS.includes(key);
const isNotAllowed =
INCLUDE_QUERYSTRING_KEYS.length &&
!INCLUDE_QUERYSTRING_KEYS.includes(key);

if (
isBlocked ||
isNotAllowed ||
(STRIP_VALUELESS_QUERYSTRING_KEYS && !value)
) {
url.searchParams.delete(key);
removed[key] = value || "";
}
});

return [new Request(url, request), removed];
}

/**
* Response Utilities
*/

function replaceStrippedQsOnRedirectResponse(response, strippedParams) {
/**
* Given an existing Response, and an object of stripped querystring keys,
* determine if the response is a redirect.
* If it is, add the stripped querystrings to the location header.
* This allows us to persist tracking querystrings (like UTM) over redirects.
*/

if ([301, 302, 307, 308].includes(response.status)) {
const redirectResponse = new Response(response.body, response);
const locationHeaderValue = redirectResponse.headers.get("location");
let locationUrl;

if (!locationHeaderValue) {
return redirectResponse;
}

const isAbsolute = isUrlAbsolute(locationHeaderValue);

if (!isAbsolute) {
// If the Location URL isn't absolute, we need to provide a Host so we can use
// a URL object.
locationUrl = new URL(locationHeaderValue, "http://www.example.com");
} else {
locationUrl = new URL(locationHeaderValue);
}

Object.entries(strippedParams).forEach(([key, value]) =>
locationUrl.searchParams.append(key, value)
);

let newLocation;

if (isAbsolute) {
newLocation = locationUrl.toString();
} else {
newLocation = `${locationUrl.pathname}${locationUrl.search}`;
}

redirectResponse.headers.set("location", newLocation);
return redirectResponse;
}

return response;
}

/**
* URL Utilities
*/
function isUrlAbsolute(url) {
return url.indexOf("://") > 0 || url.indexOf("//") === 0;
}
Loading