Skip to content

Commit

Permalink
feat: use options.hostname as default hostname for request
Browse files Browse the repository at this point in the history
  • Loading branch information
usualoma committed Apr 19, 2024
1 parent feca411 commit aed16dc
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 17 deletions.
3 changes: 2 additions & 1 deletion src/listener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ const responseViaResponseObject = async (
export const getRequestListener = (
fetchCallback: FetchCallback,
options: {
hostname?: string
errorHandler?: CustomErrorHandler
overrideGlobalObjects?: boolean
} = {}
Expand All @@ -173,7 +174,7 @@ export const getRequestListener = (
try {
// `fetchCallback()` requests a Request object, but global.Request is expensive to generate,
// so generate a pseudo Request object with only the minimum required information.
req = newRequest(incoming)
req = newRequest(incoming, options.hostname)

// Detect if request was aborted.
outgoing.on('close', () => {
Expand Down
9 changes: 7 additions & 2 deletions src/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,11 +130,16 @@ const requestPrototype: Record<string | symbol, any> = {
})
Object.setPrototypeOf(requestPrototype, Request.prototype)

export const newRequest = (incoming: IncomingMessage | Http2ServerRequest) => {
export const newRequest = (
incoming: IncomingMessage | Http2ServerRequest,
defaultHostname?: string
) => {
const req = Object.create(requestPrototype)
req[incomingKey] = incoming

const host = incoming instanceof Http2ServerRequest ? incoming.authority : incoming.headers.host
const host =
(incoming instanceof Http2ServerRequest ? incoming.authority : incoming.headers.host) ||
defaultHostname
if (!host) {
throw new RequestError('Missing host header')
}
Expand Down
1 change: 1 addition & 0 deletions src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type { Options, ServerType } from './types'
export const createAdaptorServer = (options: Options): ServerType => {
const fetchCallback = options.fetch
const requestListener = getRequestListener(fetchCallback, {
hostname: options.hostname,
overrideGlobalObjects: options.overrideGlobalObjects,
})
// ts will complain about createServerHTTP and createServerHTTP2 not being callable, which works just fine
Expand Down
69 changes: 55 additions & 14 deletions test/listener.test.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,69 @@
import { createServer } from 'node:http'
import request from 'supertest'
import { getRequestListener } from '../src/listener'
import { GlobalRequest, Request as LightweightRequest } from '../src/request'
import { GlobalRequest, Request as LightweightRequest, RequestError } from '../src/request'
import { GlobalResponse, Response as LightweightResponse } from '../src/response'

describe('Invalid request', () => {
const requestListener = getRequestListener(jest.fn())
const server = createServer(async (req, res) => {
await requestListener(req, res)
describe('default error handler', () => {
const requestListener = getRequestListener(jest.fn())
const server = createServer(requestListener)

if (!res.writableEnded) {
res.writeHead(500, { 'Content-Type': 'text/plain' })
res.end('error handler did not return a response')
}
it('Should return server error for a request w/o host header', async () => {
const res = await request(server).get('/').set('Host', '').send()
expect(res.status).toBe(400)
})

it('Should return server error for a request invalid host header', async () => {
const res = await request(server).get('/').set('Host', 'a b').send()
expect(res.status).toBe(400)
})
})

it('Should return server error for a request w/o host header', async () => {
const res = await request(server).get('/').set('Host', '').send()
expect(res.status).toBe(400)
describe('custom error handler', () => {
const requestListener = getRequestListener(jest.fn(), {
errorHandler: (e) => {
if (e instanceof RequestError) {
return new Response(e.message, { status: 400 })
}
else {
return new Response('unknown error', { status: 500 })
}
},
})
const server = createServer(requestListener)

it('Should return server error for a request w/o host header', async () => {
const res = await request(server).get('/').set('Host', '').send()
expect(res.status).toBe(400)
})

it('Should return server error for a request invalid host header', async () => {
const res = await request(server).get('/').set('Host', 'a b').send()
expect(res.status).toBe(400)
})

it('Should return server error for host header with path', async () => {
const res = await request(server).get('/').set('Host', 'a/b').send()
expect(res.status).toBe(400)
})
})

it('Should return server error for a request invalid host header', async () => {
const res = await request(server).get('/').set('Host', 'a b').send()
expect(res.status).toBe(400)
describe('default hostname', () => {
const requestListener = getRequestListener(() => new Response('ok'), {
hostname: 'example.com',
})
const server = createServer(requestListener)

it('Should return 200 for a request w/o host header', async () => {
const res = await request(server).get('/').set('Host', '').send()
expect(res.status).toBe(200)
})

it('Should return server error for a request invalid host header', async () => {
const res = await request(server).get('/').set('Host', 'a b').send()
expect(res.status).toBe(400)
})
})
})

Expand Down

0 comments on commit aed16dc

Please sign in to comment.