@@ -694,7 +694,10 @@ export async function optimizeImage({
694694 return optimizedBuffer
695695}
696696
697- export async function fetchExternalImage ( href : string ) : Promise < ImageUpstream > {
697+ export async function fetchExternalImage (
698+ href : string ,
699+ maximumResponseBody : number
700+ ) : Promise < ImageUpstream > {
698701 const res = await fetch ( href , {
699702 signal : AbortSignal . timeout ( 7_000 ) ,
700703 } ) . catch ( ( err ) => err as Error )
@@ -719,7 +722,35 @@ export async function fetchExternalImage(href: string): Promise<ImageUpstream> {
719722 )
720723 }
721724
722- const buffer = Buffer . from ( await res . arrayBuffer ( ) )
725+ if ( ! res . body ) {
726+ Log . error ( 'upstream image response is empty for' , href )
727+ throw new ImageError (
728+ 400 ,
729+ '"url" parameter is valid but upstream response is invalid'
730+ )
731+ }
732+
733+ const chunks : Buffer [ ] = [ ]
734+ let totalSize = 0
735+
736+ for await ( const c of res . body ) {
737+ const chunk = Buffer . from ( c )
738+ totalSize += chunk . byteLength
739+ if ( totalSize > maximumResponseBody ) {
740+ Log . error (
741+ 'upstream image response exceeded maximum size for' ,
742+ href ,
743+ totalSize
744+ )
745+ throw new ImageError (
746+ 413 ,
747+ '"url" parameter is valid but upstream response is invalid'
748+ )
749+ }
750+ chunks . push ( chunk )
751+ }
752+
753+ const buffer = Buffer . concat ( chunks )
723754 const contentType = res . headers . get ( 'Content-Type' )
724755 const cacheControl = res . headers . get ( 'Cache-Control' )
725756 const etag = extractEtag ( res . headers . get ( 'ETag' ) , buffer )
0 commit comments