Skip to content

Commit

Permalink
fix: re-read request body from incoming.rawBody if available (#223)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
usualoma authored Jan 30, 2025
1 parent 460a7c5 commit 105a5cf
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 3 deletions.
15 changes: 13 additions & 2 deletions src/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,19 @@ const newRequestFromIncoming = (
}

if (!(method === 'GET' || method === 'HEAD')) {
// lazy-consume request body
init.body = Readable.toWeb(incoming) as ReadableStream<Uint8Array>
if ('rawBody' in incoming && incoming.rawBody instanceof Buffer) {
// In some environments (e.g. firebase functions), the body is already consumed.
// So we need to re-read the request body from `incoming.rawBody` if available.
init.body = new ReadableStream({
start(controller) {
controller.enqueue(incoming.rawBody)
controller.close()
},
})
} else {
// lazy-consume request body
init.body = Readable.toWeb(incoming) as ReadableStream<Uint8Array>
}
}

return new Request(url, init)
Expand Down
26 changes: 25 additions & 1 deletion test/request.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { IncomingMessage } from 'node:http'
import { IncomingMessage } from 'node:http'
import { Socket } from 'node:net'
import {
newRequest,
Request as LightweightRequest,
Expand Down Expand Up @@ -112,6 +113,29 @@ describe('Request', () => {
} as IncomingMessage)
}).toThrow(RequestError)
})

it('Should be create request body from `req.rawBody` if it exists', async () => {
const rawBody = Buffer.from('foo')
const socket = new Socket()
const incomingMessage = new IncomingMessage(socket)
incomingMessage.method = 'POST'
incomingMessage.headers = {
host: 'localhost',
}
incomingMessage.url = '/foo.txt'
;(incomingMessage as IncomingMessage & { rawBody: Buffer }).rawBody = rawBody
incomingMessage.push(rawBody)
incomingMessage.push(null)

for await (const chunk of incomingMessage) {
// consume body
expect(chunk).toBeDefined()
}

const req = newRequest(incomingMessage)
const text = await req.text()
expect(text).toBe('foo')
})
})

describe('GlobalRequest', () => {
Expand Down

0 comments on commit 105a5cf

Please sign in to comment.