diff --git a/src/request.ts b/src/request.ts index 4f2284f..74565af 100644 --- a/src/request.ts +++ b/src/request.ts @@ -2,7 +2,7 @@ // Define prototype for lightweight pseudo Request object import type { IncomingMessage } from 'node:http' -import type { Http2ServerRequest } from 'node:http2' +import { Http2ServerRequest } from 'node:http2' import { Readable } from 'node:stream' const newRequestFromIncoming = ( @@ -11,9 +11,12 @@ const newRequestFromIncoming = ( incoming: IncomingMessage | Http2ServerRequest ): Request => { const headerRecord: [string, string][] = [] - const len = incoming.rawHeaders.length - for (let i = 0; i < len; i += 2) { - headerRecord.push([incoming.rawHeaders[i], incoming.rawHeaders[i + 1]]) + const rawHeaders = incoming.rawHeaders + for (let i = 0; i < rawHeaders.length; i += 2) { + const { [i]: key, [i + 1]: value } = rawHeaders + if (key.charCodeAt(0) !== /*:*/ 0x3a) { + headerRecord.push([key, value]) + } } const init = { @@ -34,6 +37,7 @@ const newRequestFromIncoming = ( const getRequestCache = Symbol('getRequestCache') const requestCache = Symbol('requestCache') const incomingKey = Symbol('incomingKey') +const urlKey = Symbol('urlKey') const requestPrototype: Record = { get method() { @@ -41,12 +45,15 @@ const requestPrototype: Record = { }, get url() { - const url = `http://${this[incomingKey].headers.host}${this[incomingKey].url}` - return /\.\./.test(url) ? new URL(url).href : url + return this[urlKey] }, [getRequestCache]() { - return (this[requestCache] ||= newRequestFromIncoming(this.method, this.url, this[incomingKey])) + return (this[requestCache] ||= newRequestFromIncoming( + this.method, + this[urlKey], + this[incomingKey] + )) }, } ;[ @@ -81,5 +88,10 @@ Object.setPrototypeOf(requestPrototype, global.Request.prototype) export const newRequest = (incoming: IncomingMessage | Http2ServerRequest) => { const req = Object.create(requestPrototype) req[incomingKey] = incoming + req[urlKey] = new URL( + `http://${incoming instanceof Http2ServerRequest ? incoming.authority : incoming.headers.host}${ + incoming.url + }` + ).href return req } diff --git a/test/server.test.ts b/test/server.test.ts index dcfd4ef..a7a111c 100644 --- a/test/server.test.ts +++ b/test/server.test.ts @@ -462,6 +462,12 @@ describe('SSL', () => { describe('HTTP2', () => { const app = new Hono() app.get('/', (c) => c.text('Hello! Node!')) + app.get('/headers', (c) => { + // call newRequestFromIncoming + c.req.header('Accept') + return c.text('Hello! Node!') + }) + app.get('/url', (c) => c.text(c.req.url)) const server = createAdaptorServer({ fetch: app.fetch, @@ -475,6 +481,23 @@ describe('HTTP2', () => { expect(res.headers['content-type']).toMatch(/text\/plain/) expect(res.text).toBe('Hello! Node!') }) + + it('Should return 200 response - GET /headers', async () => { + // @ts-expect-error: @types/supertest is not updated yet + const res = await request(server, { http2: true }).get('/headers').trustLocalhost() + expect(res.status).toBe(200) + expect(res.headers['content-type']).toMatch(/text\/plain/) + expect(res.text).toBe('Hello! Node!') + }) + + // Use :authority as the host for the url. + it('Should return 200 response - GET /url', async () => { + // @ts-expect-error: @types/supertest is not updated yet + const res = await request(server, { http2: true }).get('/url').trustLocalhost() + expect(res.status).toBe(200) + expect(res.headers['content-type']).toMatch(/text\/plain/) + expect(new URL(res.text).hostname).toBe('127.0.0.1') + }) }) describe('Hono compression', () => {