@@ -198,7 +198,9 @@ export async function imageOptimizer(
198
198
199
199
res . statusCode = upstreamRes . status
200
200
upstreamBuffer = Buffer . from ( await upstreamRes . arrayBuffer ( ) )
201
- upstreamType = upstreamRes . headers . get ( 'Content-Type' )
201
+ upstreamType =
202
+ detectContentType ( upstreamBuffer ) ||
203
+ upstreamRes . headers . get ( 'Content-Type' )
202
204
maxAge = getMaxAge ( upstreamRes . headers . get ( 'Cache-Control' ) )
203
205
} else {
204
206
try {
@@ -252,7 +254,8 @@ export async function imageOptimizer(
252
254
res . statusCode = mockRes . statusCode
253
255
254
256
upstreamBuffer = Buffer . concat ( resBuffers )
255
- upstreamType = mockRes . getHeader ( 'Content-Type' )
257
+ upstreamType =
258
+ detectContentType ( upstreamBuffer ) || mockRes . getHeader ( 'Content-Type' )
256
259
maxAge = getMaxAge ( mockRes . getHeader ( 'Cache-Control' ) )
257
260
} catch ( err ) {
258
261
res . statusCode = 500
@@ -273,7 +276,6 @@ export async function imageOptimizer(
273
276
return { finished : true }
274
277
}
275
278
276
- // If upstream type is not a valid image type, return 400 error.
277
279
if ( ! upstreamType . startsWith ( 'image/' ) ) {
278
280
res . statusCode = 400
279
281
res . end ( "The requested resource isn't a valid image." )
@@ -426,6 +428,38 @@ function parseCacheControl(str: string | null): Map<string, string> {
426
428
return map
427
429
}
428
430
431
+ /**
432
+ * Inspects the first few bytes of a buffer to determine if
433
+ * it matches the "magic number" of known file signatures.
434
+ * https://en.wikipedia.org/wiki/List_of_file_signatures
435
+ */
436
+ function detectContentType ( buffer : Buffer ) {
437
+ if ( [ 0xff , 0xd8 , 0xff ] . every ( ( b , i ) => buffer [ i ] === b ) ) {
438
+ return JPEG
439
+ }
440
+ if (
441
+ [ 0x89 , 0x50 , 0x4e , 0x47 , 0x0d , 0x0a , 0x1a , 0x0a ] . every (
442
+ ( b , i ) => buffer [ i ] === b
443
+ )
444
+ ) {
445
+ return PNG
446
+ }
447
+ if ( [ 0x47 , 0x49 , 0x46 , 0x38 ] . every ( ( b , i ) => buffer [ i ] === b ) ) {
448
+ return GIF
449
+ }
450
+ if (
451
+ [ 0x52 , 0x49 , 0x46 , 0x46 , 0 , 0 , 0 , 0 , 0x57 , 0x45 , 0x42 , 0x50 ] . every (
452
+ ( b , i ) => ! b || buffer [ i ] === b
453
+ )
454
+ ) {
455
+ return WEBP
456
+ }
457
+ if ( [ 0x3c , 0x3f , 0x78 , 0x6d , 0x6c ] . every ( ( b , i ) => buffer [ i ] === b ) ) {
458
+ return SVG
459
+ }
460
+ return null
461
+ }
462
+
429
463
export function getMaxAge ( str : string | null ) : number {
430
464
const minimum = 60
431
465
const map = parseCacheControl ( str )
0 commit comments