@@ -110,6 +110,15 @@ function getExpirationTtl(
110110 }
111111}
112112
113+ // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag#syntax
114+ const etagRegexp = / ^ ( W \/ ) ? " ( .+ ) " $ / ;
115+ export function parseETag ( value : string ) : string | undefined {
116+ // As we only use this for `If-None-Match` handling, which always use the weak
117+ // comparison algorithm, ignore "W/" directives:
118+ // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-None-Match
119+ return etagRegexp . exec ( value . trim ( ) ) ?. [ 2 ] ?? undefined ;
120+ }
121+
113122// https://datatracker.ietf.org/doc/html/rfc7231#section-7.1.1.1
114123const utcDateRegexp =
115124 / ^ ( M o n | T u e | W e d | T h u | F r i | S a t | S u n ) , \d \d ( J a n | F e b | M a r | A p r | M a y | J u n | J u l | A u g | S e p | O c t | N o v | D e c ) \d \d \d \d \d \d : \d \d : \d \d G M T $ / ;
@@ -123,22 +132,39 @@ function getMatchResponse(
123132 resHeaders : Headers ,
124133 resBody : Uint8Array
125134) : Response {
126- // If `If-Modified-Since` is set, perform a conditional request
135+ // If `If-None-Match` is set, perform a conditional request:
136+ // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-None-Match
137+ const reqIfNoneMatchHeader = reqHeaders . get ( "If-None-Match" ) ;
138+ const resETagHeader = resHeaders . get ( "ETag" ) ;
139+ if ( reqIfNoneMatchHeader !== null && resETagHeader !== null ) {
140+ const resETag = parseETag ( resETagHeader ) ;
141+ if ( resETag !== undefined ) {
142+ if ( reqIfNoneMatchHeader . trim ( ) === "*" ) {
143+ return new Response ( null , { status : 304 , headers : resHeaders } ) ;
144+ }
145+ for ( const reqIfNoneMatch of reqIfNoneMatchHeader . split ( "," ) ) {
146+ if ( resETag === parseETag ( reqIfNoneMatch ) ) {
147+ return new Response ( null , { status : 304 , headers : resHeaders } ) ;
148+ }
149+ }
150+ }
151+ }
152+
153+ // If `If-Modified-Since` is set, perform a conditional request:
154+ // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Modified-Since
127155 const reqIfModifiedSinceHeader = reqHeaders . get ( "If-Modified-Since" ) ;
128156 const resLastModifiedHeader = resHeaders . get ( "Last-Modified" ) ;
129157 if ( reqIfModifiedSinceHeader !== null && resLastModifiedHeader !== null ) {
130158 const reqIfModifiedSince = parseUTCDate ( reqIfModifiedSinceHeader ) ;
131159 const resLastModified = parseUTCDate ( resLastModifiedHeader ) ;
132160 // Comparison of NaN's (invalid dates), will always result in `false`
133161 if ( resLastModified <= reqIfModifiedSince ) {
134- return new Response ( null , {
135- status : 304 , // Not Modified
136- headers : resHeaders ,
137- } ) ;
162+ return new Response ( null , { status : 304 , headers : resHeaders } ) ;
138163 }
139164 }
140165
141- // If `Range` is set, return a partial response
166+ // If `Range` is set, return a partial response:
167+ // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Range
142168 const reqRangeHeader = reqHeaders . get ( "Range" ) ;
143169 if ( reqRangeHeader !== null ) {
144170 return _getRangeResponse ( reqRangeHeader , resStatus , resHeaders , resBody ) ;
0 commit comments