-
Notifications
You must be signed in to change notification settings - Fork 22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
cache-bypass-on-cookie: The set-cookie header is not propagated from server when bypassing cache #12
Comments
I have a CF worker based on this code and just tested for this. I am seeing the same behavior of the set-cookie header not making it through. Just looking at the code, I can't see what the problem might be. The Response object has no special property for cookies, it's just the headers as a whole that get populated in the constructor. https://developers.cloudflare.com/workers/runtime-apis/response Seems strange that all the other headers get populated but not set-cookie. |
I was trying to fix this by setting I ended up with reversing the behaviour - setting /**
* Main worker entry point.
*/
addEventListener("fetch", event => {
//event.passThroughOnException();
const request = event.request;
if (!bypassCache(request)) {
event.respondWith(handleRequest(request));
}
});
/**
* Do all of the work to bypass the cache
* @param {Request} request - Original request
*/
async function handleRequest(request) {
// Clone the request so we can add a no-cache, no-store Cache-Control request header.
let init = {
method: request.method,
headers: [...request.headers],
redirect: "manual",
body: request.body,
cf: { cacheTtl: 86400 }
};
// Use a unique URL (query params) to make SURE the cache is busted for this request
let uniqueUrl = await generateUniqueUrl(request);
let newRequest = new Request(uniqueUrl, init);
newRequest.headers.set('cache-control', 'max-age=86400');
// newRequest.headers.set('Cache-Control', request.headers.get('Cache-Control'));
// newRequest.headers.set('Date', request.headers.get('Date'));
// For debugging, clone the response and add some debug headers
let response = await fetch(newRequest);
let newResponse = new Response(response.body, response);
newResponse.headers.set('X-Bypass-Cache', 'Forced');
return newResponse;
}
/**
* Determine if the given request needs to bypass the cache.
* @param {Request} request - inbound request.
* @returns {bool} true if the cache should be bypassed
*/
function bypassCache(request) {
let needsBypass = false;
// Bypass the cache for all requests to a URL that matches any of the URL path bypass patterns
const url = new URL(request.url);
const path = url.pathname + url.search;
if (NO_BYPASS_URL_PATTERNS.length) {
for (let pattern of NO_BYPASS_URL_PATTERNS) {
if (path.match(pattern)) {
return true;
}
}
}
if (BYPASS_URL_PATTERNS.length) {
for (let pattern of BYPASS_URL_PATTERNS) {
if (path.match(pattern)) {
needsBypass = true;
break;
}
}
}
// Bypass the cache if the request contains a cookie that starts with one of the pre-configured prefixes
if (!needsBypass) {
const cookieHeader = request.headers.get('cookie');
if (cookieHeader && cookieHeader.length && BYPASS_COOKIE_PREFIXES.length) {
const cookies = cookieHeader.split(';');
for (let cookie of cookies) {
// If cache-cookie is set, drive cache explicitly
if(cookie.trim() == 'cache-cookie=no-cache'){
return true;
};
if(cookie.trim() == 'cache-cookie=cache'){
return false;
};
// See if the cookie starts with any of the logged-in user prefixes
for (let prefix of BYPASS_COOKIE_PREFIXES) {
if (cookie.trim().startsWith(prefix)) {
needsBypass = true;
break;
}
}
if (needsBypass) {
break;
}
}
}
}
return needsBypass;
}
/**
* Generate a unique URL so it will never match in the cache.
* This is a bit of a hack since there is no way to explicitly bypass the Cloudflare cache (yet)
* and requires that the origin will ignore unknown query parameters.
* @param {Request} request - Original request
*/
async function generateUniqueUrl(request) {
let url = request.url;
if (url.indexOf('?') >= 0) {
url += '&';
} else {
url += '?';
}
url += 'force_cache=true';
return url;
} |
The response handling looks the same. Do you see the set-cookie header coming through with this code? Your code looks similar to mine, in that I didn't go for the unique URL approach to forcing cache bypass. By coincidence I noticed a problem today with redirects not working because of the cache bypass query string being appended, so I made a change to work around that today (the 404 part). /*
This script is based on
https://github.com/pmeenan/cf-workers/blob/master/cache-bypass-on-cookie/cache-bypass-on-cookie.js
*/
// Cookie prefixes that cause a request to bypass the cache when present.
const BYPASS_COOKIE_PREFIXES = [
"wordpress_logged_in_"
];
// URL paths to bypass the cache (each pattern is a regex)
const BYPASS_URL_PATTERNS = [
/^\/reviews\/[^\/]+\/$/,
/^\/b\/[^\/]+\/$/
];
/**
* Main worker entry point.
*/
addEventListener("fetch", event => {
const request = event.request;
if (bypassCache(request)) {
event.respondWith(handleRequest(request));
}
});
/**
* Do all of the work to bypass the cache
* @param {Request} request - Original request
*/
async function handleRequest(request) {
// Clone the request so we can add a no-cache, no-store Cache-Control request header.
let init = {
method: request.method,
headers: [...request.headers],
redirect: "manual",
body: request.body,
cf: { cacheTtl: 0 }
};
// Use a new URL to tell CF not to use the cache
let newUrl = await generateNewUrl(request);
let newRequest = new Request(newUrl, init);
newRequest.headers.set('Cache-Control', 'no-cache, no-store');
// Clone the response and add a response header
let response = await fetch(newRequest);
if(response.status == 404) {
// Try again without ?bypasscache=1 parameter
// The parameter means that Yoast redirect rules don't match so Yoast redirects will never work for logged in users
newRequest = new Request(request.url, init);
newRequest.headers.set('Cache-Control', 'no-cache, no-store');
response = await fetch(newRequest);
}
let newResponse = new Response(response.body, response);
newResponse.headers.set('X-Cookie-Bypass', 'Logged In');
return newResponse;
}
/**
* Determine if the given request needs to bypass the cache.
* @param {Request} request - inbound request.
* @returns {bool} true if the cache should be bypassed
*/
function bypassCache(request) {
let needsBypass = false;
// Only bypass for requests to URLs that match one of the URL path patterns
const url = new URL(request.url);
const path = url.pathname; // + url.search
let urlBypass = false;
if (BYPASS_URL_PATTERNS.length) {
for (let pattern of BYPASS_URL_PATTERNS) {
if (path.match(pattern)) {
urlBypass = true;
break;
}
}
}
// Only bypass if the request contains a cookie that starts with one of the pre-configured prefixes
let cookieBypass = false;
if (urlBypass) {
const cookieHeader = request.headers.get('cookie');
if (cookieHeader && cookieHeader.length && BYPASS_COOKIE_PREFIXES.length) {
const cookies = cookieHeader.split(';');
for (let cookie of cookies) {
// See if the cookie starts with any of the logged-in user prefixes
for (let prefix of BYPASS_COOKIE_PREFIXES) {
if (cookie.trim().startsWith(prefix)) {
cookieBypass = true;
break;
}
}
if (cookieBypass) {
break;
}
}
}
}
needsBypass = urlBypass && cookieBypass;
return needsBypass;
}
/**
* Generate new URL
* @param {Request} request - Original request
*/
async function generateNewUrl(request) {
let url = request.url;
if (url.indexOf('?') >= 0) {
url += '&';
} else {
url += '?';
}
url += 'bypasscache=1';
return url;
} |
@Salubritas With the reversed behaviour the With the approach I tried at first (those commits) I did see the original |
The
set-cookie
header is not propagated from server when bypassing cache in cache-bypass-on-cookie.The text was updated successfully, but these errors were encountered: