Skip to content

Commit a9c3cd2

Browse files
committed
refactor: Improve compatibility with standard Request object
1 parent e0c57d2 commit a9c3cd2

3 files changed

Lines changed: 40 additions & 7 deletions

File tree

src/listener.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type { Http2ServerRequest, Http2ServerResponse } from 'node:http2'
33
import type { FetchCallback } from './types'
44
import './globals'
55
import { cacheKey } from './response'
6-
import { requestPrototype } from './request'
6+
import { newRequest } from './request'
77
import { writeFromReadableStream, buildOutgoingHttpHeaders } from './utils'
88

99
const regBuffer = /^no$/i
@@ -108,10 +108,7 @@ export const getRequestListener = (fetchCallback: FetchCallback) => {
108108

109109
// `fetchCallback()` requests a Request object, but global.Request is expensive to generate,
110110
// so generate a pseudo Request object with only the minimum required information.
111-
const req = Object.create(requestPrototype)
112-
req.method = incoming.method || 'GET'
113-
req.url = `http://${incoming.headers.host}${incoming.url}`
114-
req.incoming = incoming
111+
const req = newRequest(incoming)
115112

116113
try {
117114
res = fetchCallback(req) as Response | Promise<Response>

src/request.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,19 @@ const newRequestFromIncoming = (
3232

3333
const getRequestCache = Symbol('getRequestCache')
3434
const requestCache = Symbol('requestCache')
35+
const incomingKey = Symbol('incomingKey')
36+
37+
const requestPrototype: Record<string | symbol, any> = {
38+
get method() {
39+
return this[incomingKey].method || 'GET'
40+
},
41+
42+
get url() {
43+
return `http://${this[incomingKey].headers.host}${this[incomingKey].url}`
44+
},
3545

36-
export const requestPrototype: Record<string | symbol, any> = {
3746
[getRequestCache]() {
38-
return (this[requestCache] ||= newRequestFromIncoming(this.method, this.url, this.incoming))
47+
return (this[requestCache] ||= newRequestFromIncoming(this.method, this.url, this[incomingKey]))
3948
},
4049
}
4150
;[
@@ -65,3 +74,10 @@ export const requestPrototype: Record<string | symbol, any> = {
6574
},
6675
})
6776
})
77+
Object.setPrototypeOf(requestPrototype, global.Request.prototype)
78+
79+
export const newRequest = (incoming: IncomingMessage | Http2ServerRequest) => {
80+
const req = Object.create(requestPrototype)
81+
req[incomingKey] = incoming
82+
return req
83+
};

test/request.test.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { IncomingMessage } from 'node:http'
2+
import { newRequest } from '../src/request'
3+
4+
describe('Request', () => {
5+
it('Compatibility with standard Request object', async () => {
6+
const req = newRequest({
7+
method: 'GET',
8+
url: '/',
9+
headers: {
10+
host: 'localhost',
11+
},
12+
rawHeaders: ['host', 'localhost'],
13+
} as IncomingMessage)
14+
15+
expect(req).toBeInstanceOf(global.Request)
16+
expect(req.method).toBe('GET')
17+
expect(req.url).toBe('http://localhost/')
18+
expect(req.headers.get('host')).toBe('localhost')
19+
})
20+
})

0 commit comments

Comments
 (0)