11import { spawn } from 'node:child_process'
2+ import { once } from 'node:events'
23import { setTimeout } from 'node:timers/promises'
34
45const PORT = 3000
@@ -16,6 +17,7 @@ interface ServerResult {
1617 ping : number
1718 query : number
1819 body : number
20+ headers : number
1921}
2022
2123async function waitForServer ( ) : Promise < void > {
@@ -44,6 +46,15 @@ async function retryFetch(url: string, options?: RequestInit, retries = 0): Prom
4446 }
4547}
4648
49+ async function stopServer ( server : ReturnType < typeof spawn > ) : Promise < void > {
50+ if ( server . exitCode !== null || server . signalCode !== null ) {
51+ return
52+ }
53+ const exited = once ( server , 'exit' )
54+ server . kill ( 'SIGKILL' )
55+ await exited
56+ }
57+
4758async function testEndpoints ( ) : Promise < void > {
4859 // Test GET /
4960 const res1 = await retryFetch ( 'http://127.0.0.1:3000/' )
@@ -75,6 +86,17 @@ async function testEndpoints(): Promise<void> {
7586 `Body: Result not match - expected ${ JSON . stringify ( body ) } , got ${ JSON . stringify ( json3 ) } `
7687 )
7788 }
89+
90+ // Test an isolated incoming request-header read.
91+ const res4 = await retryFetch ( 'http://127.0.0.1:3000/headers' , {
92+ headers : {
93+ 'x-test' : '123' ,
94+ } ,
95+ } )
96+ const text4 = await res4 . text ( )
97+ if ( res4 . status !== 200 || text4 !== '123' ) {
98+ throw new Error ( `Headers: Result not match - expected "123", got "${ text4 } "` )
99+ }
78100}
79101
80102async function runBenchmarkForServer (
@@ -102,6 +124,7 @@ async function runBenchmarkForServer(
102124 { name : 'GET /' , url : 'http://127.0.0.1:3000/' } ,
103125 { name : 'GET /id/:id' , url : 'http://127.0.0.1:3000/id/1?name=bun' } ,
104126 { name : 'POST /json' , url : 'http://127.0.0.1:3000/json' , method : 'POST' } ,
127+ { name : 'GET /headers' , url : 'http://127.0.0.1:3000/headers' } ,
105128 ]
106129
107130 const results : BenchmarkResult [ ] = [ ]
@@ -111,6 +134,9 @@ async function runBenchmarkForServer(
111134 if ( bench . method === 'POST' ) {
112135 args . push ( '-m' , 'POST' , '-H' , 'Content-Type:application/json' , '-f' , './scripts/body.json' )
113136 }
137+ if ( bench . name === 'GET /headers' ) {
138+ args . push ( '-H' , 'x-test:123' )
139+ }
114140 args . push ( bench . url )
115141
116142 const output = await new Promise < string > ( ( resolve , reject ) => {
@@ -147,7 +173,8 @@ async function runBenchmarkForServer(
147173 const ping = results [ 0 ] ?. reqsPerSec || 0
148174 const query = results [ 1 ] ?. reqsPerSec || 0
149175 const body = results [ 2 ] ?. reqsPerSec || 0
150- const average = ( ping + query + body ) / 3
176+ const headers = results [ 3 ] ?. reqsPerSec || 0
177+ const average = ( ping + query + body + headers ) / 4
151178
152179 return {
153180 server : serverName ,
@@ -156,14 +183,14 @@ async function runBenchmarkForServer(
156183 ping,
157184 query,
158185 body,
186+ headers,
159187 }
160188 } catch ( error ) {
161189 console . error ( 'Error:' , ( error as Error ) . message )
162190 throw error
163191 } finally {
164192 console . log ( 'Stopping server...' )
165- server . kill ( )
166- await setTimeout ( 1000 )
193+ await stopServer ( server )
167194 }
168195}
169196
@@ -185,14 +212,14 @@ async function testServer(serverFile: string, serverName: string): Promise<boole
185212 console . log ( ' ' , ( error as Error ) ?. message || error )
186213 return false
187214 } finally {
188- server . kill ( )
189- await setTimeout ( 1000 )
215+ await stopServer ( server )
190216 }
191217}
192218
193219async function main ( ) : Promise < void > {
194220 const servers = [
195- { file : 'src/server-npm.js' , name : '@hono/node-server (npm)' } ,
221+ { file : 'src/server-npm.js' , name : '@hono/node-server (2.1.0)' } ,
222+ { file : 'src/server-srvx.js' , name : 'srvx (0.12.5, fast)' } ,
196223 { file : 'src/server-dev.js' , name : '@hono/node-server (dev)' } ,
197224 ]
198225
@@ -238,47 +265,53 @@ async function main(): Promise<void> {
238265 } )
239266 }
240267
241- const formatDiff = ( npm : number , dev : number ) : string => {
242- const diff = ( ( dev - npm ) / npm ) * 100
243- const sign = diff > 0 ? '+' : ''
244- return `${ sign } ${ diff . toFixed ( 2 ) } %`
268+ const formatDiff = ( baseline : number , dev : number ) : string => {
269+ const diff = ( ( dev - baseline ) / baseline ) * 100
270+ return `${ diff > 0 ? '+' : '' } ${ diff . toFixed ( 2 ) } %`
245271 }
246272
247- if ( allResults . length === 2 ) {
248- // Comparison mode: npm vs dev
249- const npmResult = allResults . find ( ( r ) => r . server . includes ( 'npm' ) )
273+ if ( allResults . length === 3 ) {
274+ const npmResult = allResults . find ( ( r ) => r . server === '@hono/node-server (2.1.0)' )
275+ const srvxResult = allResults . find ( ( r ) => r . server === 'srvx (0.12.5, fast)' )
250276 const devResult = allResults . find ( ( r ) => r . server . includes ( 'dev' ) )
251277
252- if ( npmResult && devResult ) {
253- console . log ( '| Benchmark | npm | dev | Difference |' )
254- console . log ( '| ----------------- | -------------- | -------------- | ----------- |' )
278+ if ( npmResult && srvxResult && devResult ) {
279+ console . log (
280+ '| Benchmark | @hono/node-server (2.1.0) | srvx (0.12.5, fast) | @hono/node-server (dev) | dev vs npm | dev vs srvx |'
281+ )
282+ console . log (
283+ '| ----------------- | ------------------------- | ------------------- | ----------------------- | ---------- | ----------- |'
284+ )
285+ console . log (
286+ `| Average | ${ formatNumber ( npmResult . average ) . padEnd ( 25 ) } | ${ formatNumber ( srvxResult . average ) . padEnd ( 19 ) } | ${ formatNumber ( devResult . average ) . padEnd ( 23 ) } | ${ formatDiff ( npmResult . average , devResult . average ) . padEnd ( 10 ) } | ${ formatDiff ( srvxResult . average , devResult . average ) . padEnd ( 11 ) } |`
287+ )
255288 console . log (
256- `| Average | ${ formatNumber ( npmResult . average ) . padEnd ( 14 ) } | ${ formatNumber ( devResult . average ) . padEnd ( 14 ) } | ${ formatDiff ( npmResult . average , devResult . average ) . padEnd ( 11 ) } |`
289+ `| Ping (GET /) | ${ formatNumber ( npmResult . ping ) . padEnd ( 25 ) } | ${ formatNumber ( srvxResult . ping ) . padEnd ( 19 ) } | ${ formatNumber ( devResult . ping ) . padEnd ( 23 ) } | ${ formatDiff ( npmResult . ping , devResult . ping ) . padEnd ( 10 ) } | ${ formatDiff ( srvxResult . ping , devResult . ping ) . padEnd ( 11 ) } |`
257290 )
258291 console . log (
259- `| Ping (GET /) | ${ formatNumber ( npmResult . ping ) . padEnd ( 14 ) } | ${ formatNumber ( devResult . ping ) . padEnd ( 14 ) } | ${ formatDiff ( npmResult . ping , devResult . ping ) . padEnd ( 11 ) } |`
292+ `| Query (GET /id ) | ${ formatNumber ( npmResult . query ) . padEnd ( 25 ) } | ${ formatNumber ( srvxResult . query ) . padEnd ( 19 ) } | ${ formatNumber ( devResult . query ) . padEnd ( 23 ) } | ${ formatDiff ( npmResult . query , devResult . query ) . padEnd ( 10 ) } | ${ formatDiff ( srvxResult . query , devResult . query ) . padEnd ( 11 ) } |`
260293 )
261294 console . log (
262- `| Query (GET /id) | ${ formatNumber ( npmResult . query ) . padEnd ( 14 ) } | ${ formatNumber ( devResult . query ) . padEnd ( 14 ) } | ${ formatDiff ( npmResult . query , devResult . query ) . padEnd ( 11 ) } |`
295+ `| Body (POST /json) | ${ formatNumber ( npmResult . body ) . padEnd ( 25 ) } | ${ formatNumber ( srvxResult . body ) . padEnd ( 19 ) } | ${ formatNumber ( devResult . body ) . padEnd ( 23 ) } | ${ formatDiff ( npmResult . body , devResult . body ) . padEnd ( 10 ) } | ${ formatDiff ( srvxResult . body , devResult . body ) . padEnd ( 11 ) } |`
263296 )
264297 console . log (
265- `| Body (POST /json) | ${ formatNumber ( npmResult . body ) . padEnd ( 14 ) } | ${ formatNumber ( devResult . body ) . padEnd ( 14 ) } | ${ formatDiff ( npmResult . body , devResult . body ) . padEnd ( 11 ) } |`
298+ `| Headers (GET) | ${ formatNumber ( npmResult . headers ) . padEnd ( 25 ) } | ${ formatNumber ( srvxResult . headers ) . padEnd ( 19 ) } | ${ formatNumber ( devResult . headers ) . padEnd ( 23 ) } | ${ formatDiff ( npmResult . headers , devResult . headers ) . padEnd ( 10 ) } | ${ formatDiff ( srvxResult . headers , devResult . headers ) . padEnd ( 11 ) } |`
266299 )
267300 }
268301 } else {
269302 // Fallback: original table format
270303 console . log (
271- '| Server | Runtime | Average | Ping | Query | Body |'
304+ '| Server | Runtime | Average | Ping | Query | Body | Headers | '
272305 )
273306 console . log (
274- '| -------------------------- | ------- | ------------ | ------------ | ------------ | ------------ |'
307+ '| -------------------------- | ------- | ------------ | ------------ | ------------ | ------------ | ------------ | '
275308 )
276309
277310 const sortedResults = allResults . sort ( ( a , b ) => b . average - a . average )
278311
279312 for ( const result of sortedResults ) {
280313 console . log (
281- `| ${ result . server . padEnd ( 26 ) } | ${ result . runtime . padEnd ( 7 ) } | ${ formatNumber ( result . average ) . padEnd ( 12 ) } | ${ formatNumber ( result . ping ) . padEnd ( 12 ) } | ${ formatNumber ( result . query ) . padEnd ( 12 ) } | ${ formatNumber ( result . body ) . padEnd ( 12 ) } |`
314+ `| ${ result . server . padEnd ( 26 ) } | ${ result . runtime . padEnd ( 7 ) } | ${ formatNumber ( result . average ) . padEnd ( 12 ) } | ${ formatNumber ( result . ping ) . padEnd ( 12 ) } | ${ formatNumber ( result . query ) . padEnd ( 12 ) } | ${ formatNumber ( result . body ) . padEnd ( 12 ) } | ${ formatNumber ( result . headers ) . padEnd ( 12 ) } | `
282315 )
283316 }
284317 }
0 commit comments