Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"@standard-server/peer": "workspace:*",
"@standard-server/shared": "workspace:*",
"@types/express": "^5.0.6",
"@types/express4": "npm:@types/express@^4.17.25",
"@types/node": "^26.4.1",
"@types/ws": "^8.18.1",
"@vitest/coverage-v8": "^4.1.10",
Expand All @@ -43,6 +44,7 @@
"eslint-plugin-ban": "^2.0.0",
"eslint-plugin-format": "^2.0.1",
"express": "^5.2.1",
"express4": "npm:express@^4.22.3",
"fastify": "^5.11.0",
"h3": "2.0.1-rc.26",
"lint-staged": "^17.3.0",
Expand Down
33 changes: 32 additions & 1 deletion packages/node/src/body.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { NodeHttpRequest } from './types'
import { Buffer } from 'node:buffer'
import http2 from 'node:http2'
import { Readable } from 'node:stream'
import { text } from 'node:stream/consumers'
import * as StandardServerModule from '@standard-server/core'
import { toFetchHeaders } from '@standard-server/fetch'
import { isAsyncIteratorObject } from '@standard-server/shared'
Expand Down Expand Up @@ -151,7 +152,9 @@ describe('toStandardBody', () => {
let standardBody: StandardBody = {} as any

await request(async (req: IncomingMessage, res: ServerResponse) => {
// @ts-expect-error fake body is parsed
// fake an upstream parser: consume the stream, then assign the parsed body
await text(req)
// @ts-expect-error fake body is parsed
req.body = { value: 123 }
standardBody = await toStandardBody(req)
res.end()
Expand All @@ -162,6 +165,34 @@ describe('toStandardBody', () => {

expect(standardBody).toEqual({ value: 123 })
})

// body-parser 1.x (express 4) assigns `{}` to every request, even the ones it leaves unread
it('ignore body assigned without consuming the stream', async () => {
let standardBody: any

await request(async (req: IncomingMessage, res: ServerResponse) => {
// @ts-expect-error fake body is assigned
req.body = {}
standardBody = await toStandardBody(req)
res.end()
})
.post('/')
.set('standard-server', 'file')
.send(Buffer.from('foo'))

expect(standardBody).toBeInstanceOf(File)
expect(await standardBody.text()).toBe('foo')

await request(async (req: IncomingMessage, res: ServerResponse) => {
// @ts-expect-error fake body is assigned
req.body = {}
standardBody = await toStandardBody(req)
res.end()
})
.get('/')

expect(standardBody).toBe(undefined)
})
})

describe('handle utf-8 characters split across stream chunks', () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/node/src/body.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export async function toStandardBody(
options: ToStandardBodyOptions = {},
): Promise<StandardBody> {
// body's already parsed by upstream framework like express, ...
if (req.body !== undefined) {
if (req.body !== undefined && !req.readable) {
return req.body
}

Expand Down
1 change: 1 addition & 0 deletions packages/node/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export type NodeHttpRequest = (IncomingMessage | Http2ServerRequest) & {

/**
* Body might already parsed by upstream framework like express.js, ...
* Only used once the request stream has been consumed.
*/
body?: unknown
}
Expand Down
Loading
Loading