Skip to content

Commit 105a5cf

Browse files
authored
fix: re-read request body from incoming.rawBody if available (#223)
In some environments (e.g. firebase functions), the body is already consumed, but we can re-read the request body from `incoming.rawBody` in that case.
1 parent 460a7c5 commit 105a5cf

File tree

2 files changed

+38
-3
lines changed

2 files changed

+38
-3
lines changed

src/request.ts

+13-2
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,19 @@ const newRequestFromIncoming = (
7474
}
7575

7676
if (!(method === 'GET' || method === 'HEAD')) {
77-
// lazy-consume request body
78-
init.body = Readable.toWeb(incoming) as ReadableStream<Uint8Array>
77+
if ('rawBody' in incoming && incoming.rawBody instanceof Buffer) {
78+
// In some environments (e.g. firebase functions), the body is already consumed.
79+
// So we need to re-read the request body from `incoming.rawBody` if available.
80+
init.body = new ReadableStream({
81+
start(controller) {
82+
controller.enqueue(incoming.rawBody)
83+
controller.close()
84+
},
85+
})
86+
} else {
87+
// lazy-consume request body
88+
init.body = Readable.toWeb(incoming) as ReadableStream<Uint8Array>
89+
}
7990
}
8091

8192
return new Request(url, init)

test/request.test.ts

+25-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import type { IncomingMessage } from 'node:http'
1+
import { IncomingMessage } from 'node:http'
2+
import { Socket } from 'node:net'
23
import {
34
newRequest,
45
Request as LightweightRequest,
@@ -112,6 +113,29 @@ describe('Request', () => {
112113
} as IncomingMessage)
113114
}).toThrow(RequestError)
114115
})
116+
117+
it('Should be create request body from `req.rawBody` if it exists', async () => {
118+
const rawBody = Buffer.from('foo')
119+
const socket = new Socket()
120+
const incomingMessage = new IncomingMessage(socket)
121+
incomingMessage.method = 'POST'
122+
incomingMessage.headers = {
123+
host: 'localhost',
124+
}
125+
incomingMessage.url = '/foo.txt'
126+
;(incomingMessage as IncomingMessage & { rawBody: Buffer }).rawBody = rawBody
127+
incomingMessage.push(rawBody)
128+
incomingMessage.push(null)
129+
130+
for await (const chunk of incomingMessage) {
131+
// consume body
132+
expect(chunk).toBeDefined()
133+
}
134+
135+
const req = newRequest(incomingMessage)
136+
const text = await req.text()
137+
expect(text).toBe('foo')
138+
})
115139
})
116140

117141
describe('GlobalRequest', () => {

0 commit comments

Comments
 (0)