Skip to content

Commit 5d8da3b

Browse files
committed
perf: replace global.Response with a proxy object.
1 parent 443c3ab commit 5d8da3b

1 file changed

Lines changed: 96 additions & 38 deletions

File tree

src/listener.ts

Lines changed: 96 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,80 @@ import { writeFromReadableStream } from './utils'
88
const regBuffer = /^no$/i
99
const regContentType = /^(application\/json\b|text\/(?!event-stream\b))/i
1010

11-
class CustomResponse extends global.Response {
12-
public __cache: [string, Record<string, string>] | undefined
13-
constructor(body: BodyInit | null, init?: ResponseInit) {
14-
super(body, init)
15-
if (typeof body === 'string' && !(init?.headers instanceof Headers)) {
16-
this.__cache = [body, (init?.headers || {}) as Record<string, string>]
17-
}
18-
}
19-
get headers() {
20-
// discard cache if headers are retrieved as they may change
11+
const globalResponse = global.Response
12+
const responsePrototype: Record<string, any> = {
13+
getResponseCache() {
2114
this.__cache = undefined
22-
return super.headers
23-
}
15+
return (this.responseCache ||= new globalResponse(this.body, this.init))
16+
},
17+
get body() {
18+
return this.getResponseCache().body
19+
},
20+
get bodyUsed() {
21+
return this.getResponseCache().bodyUsed
22+
},
23+
get headers() {
24+
return this.getResponseCache().headers
25+
},
26+
get ok() {
27+
return this.getResponseCache().ok
28+
},
29+
get redirected() {
30+
return this.getResponseCache().redirected
31+
},
32+
get statusText() {
33+
return this.getResponseCache().statusText
34+
},
35+
get trailers() {
36+
return this.getResponseCache().trailers
37+
},
38+
get type() {
39+
return this.getResponseCache().type
40+
},
41+
get url() {
42+
return this.getResponseCache().url
43+
},
44+
arrayBuffer() {
45+
return this.getResponseCache().arrayBuffer()
46+
},
47+
blob() {
48+
return this.getResponseCache().blob()
49+
},
50+
clone() {
51+
return this.getResponseCache().clone()
52+
},
53+
error() {
54+
return this.getResponseCache().error()
55+
},
56+
formData() {
57+
return this.getResponseCache().formData()
58+
},
59+
json() {
60+
return this.getResponseCache().json()
61+
},
62+
redirect() {
63+
return this.getResponseCache().redirect()
64+
},
65+
text() {
66+
return this.getResponseCache().text()
67+
},
68+
}
69+
70+
function newResponse(body: BodyInit | null, init?: ResponseInit): Response {
71+
const res = {
72+
body,
73+
init,
74+
status: init?.status || 200,
75+
__cache:
76+
typeof body === 'string'
77+
? [body, (init?.headers || {}) as Record<string, string>]
78+
: undefined,
79+
} as unknown as Response
80+
Object.setPrototypeOf(res, responsePrototype)
81+
return res
2482
}
2583
Object.defineProperty(global, 'Response', {
26-
value: CustomResponse,
84+
value: newResponse,
2785
})
2886

2987
function newRequestFromIncoming(
@@ -53,62 +111,62 @@ function newRequestFromIncoming(
53111
}
54112

55113
const requestPrototype: Record<string, any> = {
56-
request() {
114+
getRequestCache() {
57115
return (this.requestCache ||= newRequestFromIncoming(this.method, this.url, this.incoming))
58116
},
59117
get body() {
60-
return this.request().body
118+
return this.getRequestCache().body
61119
},
62120
get bodyUsed() {
63-
return this.request().bodyUsed
121+
return this.getRequestCache().bodyUsed
64122
},
65123
get cache() {
66-
return this.request().cache
124+
return this.getRequestCache().cache
67125
},
68126
get credentials() {
69-
return this.request().credentials
127+
return this.getRequestCache().credentials
70128
},
71129
get destination() {
72-
return this.request().destination
130+
return this.getRequestCache().destination
73131
},
74132
get headers() {
75-
return this.request().headers
133+
return this.getRequestCache().headers
76134
},
77135
get integrity() {
78-
return this.request().integrity
136+
return this.getRequestCache().integrity
79137
},
80138
get mode() {
81-
return this.request().mode
139+
return this.getRequestCache().mode
82140
},
83141
get redirect() {
84-
return this.request().redirect
142+
return this.getRequestCache().redirect
85143
},
86144
get referrer() {
87-
return this.request().referrer
145+
return this.getRequestCache().referrer
88146
},
89147
get referrerPolicy() {
90-
return this.request().referrerPolicy
148+
return this.getRequestCache().referrerPolicy
91149
},
92150
get signal() {
93-
return this.request().signal
151+
return this.getRequestCache().signal
94152
},
95153
arrayBuffer() {
96-
return this.request().arrayBuffer()
154+
return this.getRequestCache().arrayBuffer()
97155
},
98156
blob() {
99-
return this.request().blob()
157+
return this.getRequestCache().blob()
100158
},
101159
clone() {
102-
return this.request().clone()
160+
return this.getRequestCache().clone()
103161
},
104162
formData() {
105-
return this.request().formData()
163+
return this.getRequestCache().formData()
106164
},
107165
json() {
108-
return this.request().json()
166+
return this.getRequestCache().json()
109167
},
110168
text() {
111-
return this.request().text()
169+
return this.getRequestCache().text()
112170
},
113171
}
114172

@@ -117,27 +175,27 @@ export const getRequestListener = (fetchCallback: FetchCallback) => {
117175
incoming: IncomingMessage | Http2ServerRequest,
118176
outgoing: ServerResponse | Http2ServerResponse
119177
) => {
120-
let res: CustomResponse
178+
let res
121179
const req = {
122180
method: incoming.method || 'GET',
123181
url: `http://${incoming.headers.host}${incoming.url}`,
124182
incoming,
125183
} as unknown as Request
126184
Object.setPrototypeOf(req, requestPrototype)
127185
try {
128-
res = (await fetchCallback(req)) as CustomResponse
186+
res = (await fetchCallback(req)) as Response
129187
} catch (e: unknown) {
130-
res = new CustomResponse(null, { status: 500 })
188+
res = new Response(null, { status: 500 })
131189
if (e instanceof Error) {
132190
// timeout error emits 504 timeout
133191
if (e.name === 'TimeoutError' || e.constructor.name === 'TimeoutError') {
134-
res = new CustomResponse(null, { status: 504 })
192+
res = new Response(null, { status: 504 })
135193
}
136194
}
137195
}
138196

139-
if (res.__cache) {
140-
const [body, header] = res.__cache
197+
if ((res as any).__cache) {
198+
const [body, header] = (res as any).__cache
141199
header['content-length'] ||= '' + Buffer.byteLength(body)
142200
outgoing.writeHead(res.status, header)
143201
outgoing.end(body)

0 commit comments

Comments
 (0)