3
3
// applied after this worker runs.
4
4
5
5
// When any cookie in this list is present in the request, cache will be skipped
6
- const PRIVATE_COOKIES = [ 'sessionid' , 'csrftoken' ] ;
6
+ const PRIVATE_COOKIES = [ 'sessionid' ] ;
7
+
8
+ // Cookies to include in the cache key
9
+ const VARY_COOKIES = [ 'torchbox-mode' ] ;
10
+
11
+ // Request headers to include in the cache key.
12
+ // Note: Do not add `cookie` to this list!
13
+ const VARY_HEADERS = [
14
+ 'X-Requested-With' ,
15
+
16
+ // HTMX
17
+ 'HX-Boosted' ,
18
+ 'HX-Current-URL' ,
19
+ 'HX-History-Restore-Request' ,
20
+ 'HX-Prompt' ,
21
+ 'HX-Request' ,
22
+ 'HX-Target' ,
23
+ 'HX-Trigger-Name' ,
24
+ 'HX-Trigger' ,
25
+ ] ;
7
26
8
27
// These querystring keys are stripped from the request as they are generally not
9
28
// needed by the origin.
@@ -84,8 +103,9 @@ addEventListener('fetch', (event) => {
84
103
85
104
async function main ( event ) {
86
105
const cache = caches . default ;
87
- let request = event . request ;
106
+ let { request } = event ;
88
107
let strippedParams ;
108
+ // eslint-disable-next-line prefer-const
89
109
[ request , strippedParams ] = stripQuerystring ( request ) ;
90
110
91
111
if ( ! requestIsCachable ( request ) ) {
@@ -136,18 +156,29 @@ function responseIsCachable(response) {
136
156
137
157
function getCachingRequest ( request ) {
138
158
/**
139
- * When needed, modify a request for use as the cache key.
159
+ * Create a new request for use as a cache key.
140
160
*
141
161
* Note: Modifications to this request are not sent upstream.
142
162
*/
163
+
143
164
const cookies = getCookies ( request ) ;
144
165
145
166
const requestURL = new URL ( request . url ) ;
146
167
147
- // Cache based on the mode
148
- requestURL . searchParams . set (
149
- 'cookie-torchbox-mode' ,
150
- cookies [ 'torchbox-mode' ] || 'dark' ,
168
+ // Include specified cookies in cache key
169
+ VARY_COOKIES . forEach ( ( cookieName ) =>
170
+ requestURL . searchParams . set (
171
+ `cookie-${ cookieName } ` ,
172
+ cookies [ cookieName ] || '' ,
173
+ ) ,
174
+ ) ;
175
+
176
+ // Include specified headers in cache key
177
+ VARY_HEADERS . forEach ( ( headerName ) =>
178
+ requestURL . searchParams . set (
179
+ `header-${ headerName } ` ,
180
+ request . headers . get ( headerName ) || '' ,
181
+ ) ,
151
182
) ;
152
183
153
184
return new Request ( requestURL , request ) ;
@@ -167,7 +198,7 @@ function stripQuerystring(request) {
167
198
url . searchParams . has ( v ) ,
168
199
) ;
169
200
170
- let strippedParams = { } ;
201
+ const strippedParams = { } ;
171
202
172
203
if ( stripKeys . length ) {
173
204
stripKeys . reduce ( ( acc , key ) => {
@@ -179,12 +210,12 @@ function stripQuerystring(request) {
179
210
180
211
if ( STRIP_VALUELESS_QUERYSTRING_KEYS ) {
181
212
// Strip query params without values to avoid unnecessary cache misses
182
- for ( const [ key , value ] of url . searchParams . entries ( ) ) {
213
+ url . searchParams . entries ( ) . forEach ( ( [ key , value ] ) => {
183
214
if ( ! value ) {
184
215
url . searchParams . delete ( key ) ;
185
216
strippedParams [ key ] = '' ;
186
217
}
187
- }
218
+ } ) ;
188
219
}
189
220
190
221
return [ new Request ( url , request ) , strippedParams ] ;
@@ -194,20 +225,12 @@ function hasPrivateCookie(request) {
194
225
/*
195
226
* Given a Request, determine if one of the 'private' cookies are present.
196
227
*/
197
- const cookieHeader = request . headers . get ( 'Cookie' ) ;
198
- if ( ! cookieHeader ) {
199
- return false ;
200
- }
201
-
202
228
const allCookies = getCookies ( request ) ;
203
229
204
230
// Check if any of the private cookies are present and have a non-empty value
205
- for ( const cookieName of PRIVATE_COOKIES ) {
206
- if ( cookieName in allCookies && allCookies [ cookieName ] ) {
207
- return true ;
208
- }
209
- }
210
- return false ;
231
+ return PRIVATE_COOKIES . some (
232
+ ( cookieName ) => cookieName in allCookies && allCookies [ cookieName ] ,
233
+ ) ;
211
234
}
212
235
213
236
function getCookies ( request ) {
@@ -236,14 +259,14 @@ function replaceStrippedQsOnRedirectResponse(response, strippedParams) {
236
259
* If it is, add the stripped querystrings to the location header.
237
260
* This allows us to persist tracking querystrings (like UTM) over redirects.
238
261
*/
239
- response = new Response ( response . body , response ) ;
240
262
241
263
if ( [ 301 , 302 ] . includes ( response . status ) ) {
242
- const locationHeaderValue = response . headers . get ( 'location' ) ;
264
+ const redirectResponse = new Response ( response . body , response ) ;
265
+ const locationHeaderValue = redirectResponse . headers . get ( 'location' ) ;
243
266
let locationUrl ;
244
267
245
268
if ( ! locationHeaderValue ) {
246
- return response ;
269
+ return redirectResponse ;
247
270
}
248
271
249
272
const isAbsolute = isUrlAbsolute ( locationHeaderValue ) ;
@@ -259,9 +282,9 @@ function replaceStrippedQsOnRedirectResponse(response, strippedParams) {
259
282
locationUrl = new URL ( locationHeaderValue ) ;
260
283
}
261
284
262
- for ( const [ key , value ] of Object . entries ( strippedParams ) ) {
263
- locationUrl . searchParams . append ( key , value ) ;
264
- }
285
+ Object . entries ( strippedParams ) . forEach ( ( [ key , value ] ) =>
286
+ locationUrl . searchParams . append ( key , value ) ,
287
+ ) ;
265
288
266
289
let newLocation ;
267
290
@@ -271,7 +294,8 @@ function replaceStrippedQsOnRedirectResponse(response, strippedParams) {
271
294
newLocation = `${ locationUrl . pathname } ${ locationUrl . search } ` ;
272
295
}
273
296
274
- response . headers . set ( 'location' , newLocation ) ;
297
+ redirectResponse . headers . set ( 'location' , newLocation ) ;
298
+ return redirectResponse ;
275
299
}
276
300
277
301
return response ;
0 commit comments