11'use strict'
22
33const http = require ( 'node:http' )
4- const { Writable, Readable } = require ( 'node:stream' )
4+ const { Writable, Readable, addAbortSignal } = require ( 'node:stream' )
55const util = require ( 'node:util' )
66
77const setCookie = require ( 'set-cookie-parser' )
88
99function Response ( req , onEnd , reject ) {
1010 http . ServerResponse . call ( this , req )
1111
12- this . _lightMyRequest = { headers : null , trailers : { } , payloadChunks : [ ] }
12+ if ( req . _lightMyRequest ?. payloadAsStream ) {
13+ this . _lightMyRequest = { headers : null , trailers : { } , stream : new Readable ( { read ( ) { } } ) }
14+ const signal = req . _lightMyRequest . signal
15+
16+ if ( signal ) {
17+ addAbortSignal ( signal , this . _lightMyRequest . stream )
18+ }
19+ } else {
20+ this . _lightMyRequest = { headers : null , trailers : { } , payloadChunks : [ ] }
21+ }
1322 // This forces node@8 to always render the headers
1423 this . setHeader ( 'foo' , 'bar' ) ; this . removeHeader ( 'foo' )
1524
@@ -26,21 +35,37 @@ function Response (req, onEnd, reject) {
2635 }
2736 process . nextTick ( ( ) => onEnd ( null , payload ) )
2837 }
38+ this . _lightMyRequest . onEndSuccess = onEndSuccess
2939
3040 const onEndFailure = ( err ) => {
3141 if ( called ) return
3242 called = true
33- if ( this . _promiseCallback ) {
34- return process . nextTick ( ( ) => reject ( err ) )
43+ if ( this . _lightMyRequest . stream ) {
44+ const res = generatePayload ( this )
45+ res . raw . req = req
46+ this . _lightMyRequest . stream . _read = function ( ) {
47+ this . destroy ( err || new Error ( 'premature close' ) )
48+ }
49+ onEndSuccess ( res )
50+ } else {
51+ if ( this . _promiseCallback ) {
52+ return process . nextTick ( ( ) => reject ( err ) )
53+ }
54+ process . nextTick ( ( ) => onEnd ( err , null ) )
3555 }
36- process . nextTick ( ( ) => onEnd ( err , null ) )
3756 }
3857
39- this . once ( 'finish' , ( ) => {
40- const res = generatePayload ( this )
41- res . raw . req = req
42- onEndSuccess ( res )
43- } )
58+ if ( this . _lightMyRequest . stream ) {
59+ this . once ( 'finish' , ( ) => {
60+ this . _lightMyRequest . stream . push ( null )
61+ } )
62+ } else {
63+ this . once ( 'finish' , ( ) => {
64+ const res = generatePayload ( this )
65+ res . raw . req = req
66+ onEndSuccess ( res )
67+ } )
68+ }
4469
4570 this . connection . once ( 'error' , onEndFailure )
4671
@@ -64,6 +89,10 @@ Response.prototype.writeHead = function () {
6489
6590 copyHeaders ( this )
6691
92+ if ( this . _lightMyRequest . stream ) {
93+ this . _lightMyRequest . onEndSuccess ( generatePayload ( this ) )
94+ }
95+
6796 return result
6897}
6998
@@ -72,7 +101,11 @@ Response.prototype.write = function (data, encoding, callback) {
72101 clearTimeout ( this . timeoutHandle )
73102 }
74103 http . ServerResponse . prototype . write . call ( this , data , encoding , callback )
75- this . _lightMyRequest . payloadChunks . push ( Buffer . from ( data , encoding ) )
104+ if ( this . _lightMyRequest . stream ) {
105+ this . _lightMyRequest . stream . push ( Buffer . from ( data , encoding ) )
106+ } else {
107+ this . _lightMyRequest . payloadChunks . push ( Buffer . from ( data , encoding ) )
108+ }
76109 return true
77110}
78111
@@ -129,22 +162,32 @@ function generatePayload (response) {
129162 }
130163 }
131164
132- // Prepare payload and trailers
133- const rawBuffer = Buffer . concat ( response . _lightMyRequest . payloadChunks )
134- res . rawPayload = rawBuffer
135-
136- // we keep both of them for compatibility reasons
137- res . payload = rawBuffer . toString ( )
138- res . body = res . payload
139165 res . trailers = response . _lightMyRequest . trailers
140166
141- // Prepare payload parsers
142- res . json = function parseJsonPayload ( ) {
143- return JSON . parse ( res . payload )
167+ if ( response . _lightMyRequest . payloadChunks ) {
168+ // Prepare payload and trailers
169+ const rawBuffer = Buffer . concat ( response . _lightMyRequest . payloadChunks )
170+ res . rawPayload = rawBuffer
171+
172+ // we keep both of them for compatibility reasons
173+ res . payload = rawBuffer . toString ( )
174+ res . body = res . payload
175+
176+ // Prepare payload parsers
177+ res . json = function parseJsonPayload ( ) {
178+ return JSON . parse ( res . payload )
179+ }
180+ } else {
181+ res . json = function ( ) {
182+ throw new Error ( 'Response payload is not available with payloadAsStream: true' )
183+ }
144184 }
145185
146186 // Provide stream Readable for advanced user
147187 res . stream = function streamPayload ( ) {
188+ if ( response . _lightMyRequest . stream ) {
189+ return response . _lightMyRequest . stream
190+ }
148191 return Readable . from ( response . _lightMyRequest . payloadChunks )
149192 }
150193
@@ -179,7 +222,7 @@ function copyHeaders (response) {
179222 // Add raw headers
180223 ; [ 'Date' , 'Connection' , 'Transfer-Encoding' ] . forEach ( ( name ) => {
181224 const regex = new RegExp ( '\\r\\n' + name + ': ([^\\r]*)\\r\\n' )
182- const field = response . _header . match ( regex )
225+ const field = response . _header ? .match ( regex )
183226 if ( field ) {
184227 response . _lightMyRequest . headers [ name . toLowerCase ( ) ] = field [ 1 ]
185228 }
0 commit comments