@@ -72,6 +72,25 @@ type FindAssetEntryForPath<AssetEntry> = (
7272 path : string
7373) => Promise < null | AssetEntry > ;
7474
75+ function generateETagHeader ( assetKey : string ) {
76+ // https://support.cloudflare.com/hc/en-us/articles/218505467-Using-ETag-Headers-with-Cloudflare
77+ // We sometimes remove etags unless they are wrapped in quotes
78+ const strongETag = `"${ assetKey } "` ;
79+ const weakETag = `W/"${ assetKey } "` ;
80+ return { strongETag, weakETag } ;
81+ }
82+
83+ function checkIfNoneMatch (
84+ request : Request ,
85+ strongETag : string ,
86+ weakETag : string
87+ ) {
88+ const ifNoneMatch = request . headers . get ( "if-none-match" ) ;
89+
90+ // We sometimes downgrade strong etags to a weak ones, so we need to check for both
91+ return ifNoneMatch === weakETag || ifNoneMatch === strongETag ;
92+ }
93+
7594type ServeAsset < AssetEntry > = (
7695 assetEntry : AssetEntry ,
7796 options ?: { preserve : boolean }
@@ -80,7 +99,10 @@ type ServeAsset<AssetEntry> = (
8099type CacheStatus = "hit" | "miss" ;
81100type CacheResult < A extends string > = `${A } -${CacheStatus } `;
82101export type HandlerMetrics = {
83- preservationCacheResult ?: CacheResult < "checked" > | "disabled" ;
102+ preservationCacheResult ?:
103+ | CacheResult < "checked" >
104+ | "not-modified"
105+ | "disabled" ;
84106 earlyHintsResult ?: CacheResult < "used" | "notused" > | "disabled" ;
85107} ;
86108
@@ -518,22 +540,16 @@ export async function generateHandler<
518540
519541 const assetKey = getAssetKey ( servingAssetEntry , content ) ;
520542
521- // https://support.cloudflare.com/hc/en-us/articles/218505467-Using-ETag-Headers-with-Cloudflare
522- // We sometimes remove etags unless they are wrapped in quotes
523- const etag = `"${ assetKey } "` ;
524- const weakEtag = `W/${ etag } ` ;
525-
526- const ifNoneMatch = request . headers . get ( "if-none-match" ) ;
527-
528- // We sometimes downgrade strong etags to a weak ones, so we need to check for both
529- if ( ifNoneMatch === weakEtag || ifNoneMatch === etag ) {
543+ const { strongETag, weakETag } = generateETagHeader ( assetKey ) ;
544+ const isIfNoneMatch = checkIfNoneMatch ( request , strongETag , weakETag ) ;
545+ if ( isIfNoneMatch ) {
530546 return new NotModifiedResponse ( ) ;
531547 }
532548
533549 try {
534550 const asset = await fetchAsset ( assetKey ) ;
535551 const headers : Record < string , string > = {
536- etag,
552+ etag : strongETag ,
537553 "content-type" : asset . contentType ,
538554 } ;
539555 let encodeBody : BodyEncoding = "automatic" ;
@@ -654,6 +670,19 @@ export async function generateHandler<
654670 return new Response ( null , preservedResponse ) ;
655671 }
656672 if ( assetKey ) {
673+ const { strongETag, weakETag } = generateETagHeader ( assetKey ) ;
674+ const isIfNoneMatch = checkIfNoneMatch (
675+ request ,
676+ strongETag ,
677+ weakETag
678+ ) ;
679+ if ( isIfNoneMatch ) {
680+ if ( setMetrics ) {
681+ setMetrics ( { preservationCacheResult : "not-modified" } ) ;
682+ }
683+ return new NotModifiedResponse ( ) ;
684+ }
685+
657686 const asset = await fetchAsset ( assetKey ) ;
658687
659688 if ( asset ) {
0 commit comments