@superhero/http-server 4.0.0 → 4.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +101 -91
- package/config.json +4 -1
- package/index.test.js +21 -1
- package/middleware/upstream/header/accept.js +2 -2
- package/middleware/upstream/header/content-type.js +2 -2
- package/middleware/upstream/method.js +5 -5
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
# HTTP-
|
|
2
|
+
# HTTP-Server
|
|
3
3
|
|
|
4
4
|
An HTTP server module for Node.js that supports both HTTP/1.1 and HTTP/2 protocols, with built-in routing, HTTPS support, and stream support that defaults to server-sent events (SSE). Designed to be robust, flexible and extendible, while easy to work with.
|
|
5
5
|
|
|
@@ -314,132 +314,142 @@ npm test
|
|
|
314
314
|
```
|
|
315
315
|
▶ @superhero/http-server
|
|
316
316
|
▶ Lifecycle
|
|
317
|
-
✔ Can instantiate HttpServer (8.
|
|
318
|
-
✔ Can bootstrap server with non-secure settings (2.
|
|
319
|
-
✔
|
|
320
|
-
✔
|
|
321
|
-
✔ Rejects if server is not available to
|
|
322
|
-
|
|
323
|
-
|
|
317
|
+
✔ Can instantiate HttpServer (8.609311ms)
|
|
318
|
+
✔ Can bootstrap server with non-secure settings (2.813603ms)
|
|
319
|
+
✔ Can be configured by the configuration file (37.159723ms)
|
|
320
|
+
✔ Listens and closes the server as expected (5.81708ms)
|
|
321
|
+
✔ Rejects if server is not available to listen error (2.290967ms)
|
|
322
|
+
✔ Rejects if server is not available to close error (1.058432ms)
|
|
323
|
+
✔ Lifecycle (59.459503ms)
|
|
324
|
+
|
|
324
325
|
▶ Routing and Requests
|
|
325
326
|
▶ HTTP/1
|
|
326
|
-
✔ Can dispatch a request aligned to the route map (
|
|
327
|
-
✔ Can alter the output body (5.
|
|
328
|
-
✔ Can stream HTML5 standard Server-Sent Events (SSE) (
|
|
329
|
-
✔ Can alter the output headers (
|
|
330
|
-
✔ Can alter the output status (
|
|
331
|
-
✔ Can abort the dispatcher (
|
|
332
|
-
✔ Can describe an abortion in detail (
|
|
333
|
-
✔ Can manage thrown errors in the dispatcher (
|
|
334
|
-
✔ Can not mistakenly access the wrong view property (
|
|
335
|
-
✔ Can not mistakenly assign a value to the wrong view property (
|
|
336
|
-
✔ Support connection keep-alive header (
|
|
337
|
-
✔ HTTP/1 (
|
|
327
|
+
✔ Can dispatch a request aligned to the route map (42.67787ms)
|
|
328
|
+
✔ Can alter the output body (5.709405ms)
|
|
329
|
+
✔ Can stream HTML5 standard Server-Sent Events (SSE) (9.72838ms)
|
|
330
|
+
✔ Can alter the output headers (9.330729ms)
|
|
331
|
+
✔ Can alter the output status (7.159825ms)
|
|
332
|
+
✔ Can abort the dispatcher (5.969359ms)
|
|
333
|
+
✔ Can describe an abortion in detail (7.225311ms)
|
|
334
|
+
✔ Can manage thrown errors in the dispatcher (10.332202ms)
|
|
335
|
+
✔ Can not mistakenly access the wrong view property (7.490531ms)
|
|
336
|
+
✔ Can not mistakenly assign a value to the wrong view property (5.522195ms)
|
|
337
|
+
✔ Support connection keep-alive header (10.362687ms)
|
|
338
|
+
✔ HTTP/1 (122.952777ms)
|
|
338
339
|
|
|
339
340
|
▶ HTTP/2
|
|
340
|
-
✔ Can dispatch a request aligned to the route map (
|
|
341
|
-
✔ Can alter the output body (
|
|
342
|
-
✔ Can stream HTML5 standard Server-Sent Events (SSE) (
|
|
343
|
-
✔ Can alter the output headers (
|
|
344
|
-
✔ Can alter the output status (
|
|
345
|
-
✔ Can abort the dispatcher (
|
|
346
|
-
✔ Can describe an abortion in detail (
|
|
347
|
-
✔ Can manage thrown errors in the dispatcher (
|
|
348
|
-
✔ Can not mistakenly access the wrong view property (
|
|
349
|
-
✔ Can not mistakenly assign a value to the wrong view property (
|
|
350
|
-
✔ HTTP/2 (
|
|
351
|
-
✔ Routing and Requests (
|
|
341
|
+
✔ Can dispatch a request aligned to the route map (24.833859ms)
|
|
342
|
+
✔ Can alter the output body (8.516916ms)
|
|
343
|
+
✔ Can stream HTML5 standard Server-Sent Events (SSE) (10.336142ms)
|
|
344
|
+
✔ Can alter the output headers (8.209538ms)
|
|
345
|
+
✔ Can alter the output status (7.35682ms)
|
|
346
|
+
✔ Can abort the dispatcher (8.554265ms)
|
|
347
|
+
✔ Can describe an abortion in detail (5.330231ms)
|
|
348
|
+
✔ Can manage thrown errors in the dispatcher (9.391412ms)
|
|
349
|
+
✔ Can not mistakenly access the wrong view property (7.222525ms)
|
|
350
|
+
✔ Can not mistakenly assign a value to the wrong view property (8.57349ms)
|
|
351
|
+
✔ HTTP/2 (99.758519ms)
|
|
352
|
+
✔ Routing and Requests (222.916463ms)
|
|
352
353
|
|
|
353
354
|
▶ HTTPS server with self-signed certificate
|
|
354
355
|
▶ TLSv1.2
|
|
355
356
|
▶ RSA:2048
|
|
356
|
-
✔ HTTP1 (
|
|
357
|
-
✔ HTTP2 (
|
|
358
|
-
✔ RSA:2048 (
|
|
357
|
+
✔ HTTP1 (10.68221ms)
|
|
358
|
+
✔ HTTP2 (14.607846ms)
|
|
359
|
+
✔ RSA:2048 (184.393685ms)
|
|
359
360
|
|
|
360
361
|
▶ RSA:4096
|
|
361
|
-
✔ HTTP1 (11.
|
|
362
|
-
✔ HTTP2 (
|
|
363
|
-
✔ RSA:4096 (
|
|
362
|
+
✔ HTTP1 (11.166249ms)
|
|
363
|
+
✔ HTTP2 (14.376707ms)
|
|
364
|
+
✔ RSA:4096 (239.998059ms)
|
|
364
365
|
|
|
365
366
|
▶ ECDSA:P-256
|
|
366
|
-
✔ HTTP1 (
|
|
367
|
-
✔ HTTP2 (
|
|
368
|
-
✔ ECDSA:P-256 (
|
|
367
|
+
✔ HTTP1 (6.998372ms)
|
|
368
|
+
✔ HTTP2 (9.255564ms)
|
|
369
|
+
✔ ECDSA:P-256 (52.737888ms)
|
|
369
370
|
|
|
370
371
|
▶ ECDSA:P-384
|
|
371
|
-
✔ HTTP1 (
|
|
372
|
-
✔ HTTP2 (9.
|
|
373
|
-
✔ ECDSA:P-384 (52.
|
|
372
|
+
✔ HTTP1 (8.610887ms)
|
|
373
|
+
✔ HTTP2 (9.7637ms)
|
|
374
|
+
✔ ECDSA:P-384 (52.826908ms)
|
|
374
375
|
|
|
375
376
|
▶ ECDSA:P-521
|
|
376
|
-
✔ HTTP1 (
|
|
377
|
-
✔ HTTP2 (13.
|
|
378
|
-
✔ ECDSA:P-521 (
|
|
377
|
+
✔ HTTP1 (9.391868ms)
|
|
378
|
+
✔ HTTP2 (13.179682ms)
|
|
379
|
+
✔ ECDSA:P-521 (62.741409ms)
|
|
379
380
|
|
|
380
381
|
▶ EdDSA:Ed25519
|
|
381
|
-
✔ HTTP1 (
|
|
382
|
-
✔ HTTP2 (
|
|
383
|
-
✔ EdDSA:Ed25519 (
|
|
382
|
+
✔ HTTP1 (10.110816ms)
|
|
383
|
+
✔ HTTP2 (9.99596ms)
|
|
384
|
+
✔ EdDSA:Ed25519 (58.01589ms)
|
|
384
385
|
|
|
385
386
|
▶ EdDSA:Ed448
|
|
386
|
-
✔ HTTP1 (
|
|
387
|
-
✔ HTTP2 (
|
|
388
|
-
✔ EdDSA:Ed448 (
|
|
389
|
-
✔ TLSv1.2 (
|
|
387
|
+
✔ HTTP1 (4.651357ms)
|
|
388
|
+
✔ HTTP2 (10.031462ms)
|
|
389
|
+
✔ EdDSA:Ed448 (51.550013ms)
|
|
390
|
+
✔ TLSv1.2 (703.01496ms)
|
|
390
391
|
|
|
391
392
|
▶ TLSv1.3
|
|
392
393
|
▶ RSA:2048
|
|
393
|
-
✔ HTTP1 (6.
|
|
394
|
-
✔ HTTP2 (
|
|
395
|
-
✔ RSA:2048 (
|
|
394
|
+
✔ HTTP1 (6.43647ms)
|
|
395
|
+
✔ HTTP2 (9.551209ms)
|
|
396
|
+
✔ RSA:2048 (113.791235ms)
|
|
396
397
|
|
|
397
398
|
▶ RSA:4096
|
|
398
|
-
✔ HTTP1 (
|
|
399
|
-
✔ HTTP2 (
|
|
400
|
-
✔ RSA:4096 (
|
|
399
|
+
✔ HTTP1 (18.396852ms)
|
|
400
|
+
✔ HTTP2 (22.414178ms)
|
|
401
|
+
✔ RSA:4096 (819.288505ms)
|
|
401
402
|
|
|
402
403
|
▶ ECDSA:P-256
|
|
403
|
-
✔ HTTP1 (
|
|
404
|
-
✔ HTTP2 (
|
|
405
|
-
✔ ECDSA:P-256 (
|
|
404
|
+
✔ HTTP1 (7.036644ms)
|
|
405
|
+
✔ HTTP2 (11.842337ms)
|
|
406
|
+
✔ ECDSA:P-256 (100.196088ms)
|
|
406
407
|
|
|
407
408
|
▶ ECDSA:P-384
|
|
408
|
-
✔ HTTP1 (8.
|
|
409
|
-
✔ HTTP2 (
|
|
410
|
-
✔ ECDSA:P-384 (
|
|
409
|
+
✔ HTTP1 (8.183114ms)
|
|
410
|
+
✔ HTTP2 (12.428711ms)
|
|
411
|
+
✔ ECDSA:P-384 (61.367513ms)
|
|
411
412
|
|
|
412
413
|
▶ ECDSA:P-521
|
|
413
|
-
✔ HTTP1 (
|
|
414
|
-
✔ HTTP2 (
|
|
415
|
-
✔ ECDSA:P-521 (
|
|
414
|
+
✔ HTTP1 (12.446168ms)
|
|
415
|
+
✔ HTTP2 (15.564381ms)
|
|
416
|
+
✔ ECDSA:P-521 (68.39823ms)
|
|
416
417
|
|
|
417
418
|
▶ EdDSA:Ed25519
|
|
418
|
-
✔ HTTP1 (
|
|
419
|
-
✔ HTTP2 (
|
|
420
|
-
✔ EdDSA:Ed25519 (
|
|
419
|
+
✔ HTTP1 (4.44369ms)
|
|
420
|
+
✔ HTTP2 (11.703458ms)
|
|
421
|
+
✔ EdDSA:Ed25519 (54.613453ms)
|
|
421
422
|
|
|
422
423
|
▶ EdDSA:Ed448
|
|
423
|
-
✔ HTTP1 (
|
|
424
|
-
✔ HTTP2 (
|
|
425
|
-
✔ EdDSA:Ed448 (
|
|
426
|
-
✔ TLSv1.3 (
|
|
427
|
-
✔ HTTPS server with self-signed certificate (
|
|
428
|
-
✔ @superhero/http-server (
|
|
429
|
-
|
|
430
|
-
tests
|
|
424
|
+
✔ HTTP1 (13.499592ms)
|
|
425
|
+
✔ HTTP2 (11.474115ms)
|
|
426
|
+
✔ EdDSA:Ed448 (68.423656ms)
|
|
427
|
+
✔ TLSv1.3 (1287.220809ms)
|
|
428
|
+
✔ HTTPS server with self-signed certificate (1990.42993ms)
|
|
429
|
+
✔ @superhero/http-server (2273.646154ms)
|
|
430
|
+
|
|
431
|
+
tests 69
|
|
431
432
|
suites 8
|
|
432
|
-
pass
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
file
|
|
436
|
-
|
|
437
|
-
index.js
|
|
438
|
-
index.test.js
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
433
|
+
pass 69
|
|
434
|
+
|
|
435
|
+
---------------------------------------------------------------------------------------------------------------------
|
|
436
|
+
file | line % | branch % | funcs % | uncovered lines
|
|
437
|
+
---------------------------------------------------------------------------------------------------------------------
|
|
438
|
+
index.js | 91.75 | 91.18 | 74.07 | 92-94 128-129 135-137 266-269 369-373 389-394 397-402 405-410
|
|
439
|
+
index.test.js | 100.00 | 100.00 | 100.00 |
|
|
440
|
+
middleware | | | |
|
|
441
|
+
upstream | | | |
|
|
442
|
+
header | | | |
|
|
443
|
+
accept.js | 19.23 | 100.00 | 33.33 | 10-51
|
|
444
|
+
content-type.js | 20.00 | 100.00 | 50.00 | 9-44
|
|
445
|
+
content-type | | | |
|
|
446
|
+
application | | | |
|
|
447
|
+
json.js | 31.03 | 100.00 | 0.00 | 9-28
|
|
448
|
+
method.js | 23.68 | 100.00 | 50.00 | 9-37
|
|
449
|
+
view.js | 92.98 | 88.89 | 84.21 | 133-138 196-200 238-239 247-253
|
|
450
|
+
---------------------------------------------------------------------------------------------------------------------
|
|
451
|
+
all files | 86.57 | 93.96 | 83.82 |
|
|
452
|
+
---------------------------------------------------------------------------------------------------------------------
|
|
443
453
|
```
|
|
444
454
|
|
|
445
455
|
## License
|
package/config.json
CHANGED
|
@@ -5,7 +5,10 @@
|
|
|
5
5
|
},
|
|
6
6
|
"locator":
|
|
7
7
|
{
|
|
8
|
-
"@superhero/http-server": true
|
|
8
|
+
"@superhero/http-server": true,
|
|
9
|
+
"@superhero/http-server/middleware/*/*": "./middleware/*/*.js",
|
|
10
|
+
"@superhero/http-server/middleware/*/*/*": "./middleware/*/*/*.js",
|
|
11
|
+
"@superhero/http-server/middleware/*/*/*/*/*": "./middleware/*/*/*/*/*.js"
|
|
9
12
|
},
|
|
10
13
|
"http-server":
|
|
11
14
|
{
|
package/index.test.js
CHANGED
|
@@ -4,6 +4,7 @@ import util from 'node:util'
|
|
|
4
4
|
import fs from 'node:fs'
|
|
5
5
|
import https from 'node:https'
|
|
6
6
|
import tls from 'node:tls'
|
|
7
|
+
import Config from '@superhero/config'
|
|
7
8
|
import Request from '@superhero/http-request'
|
|
8
9
|
import Router from '@superhero/router'
|
|
9
10
|
import Locator from '@superhero/locator'
|
|
@@ -11,7 +12,7 @@ import HttpServer from '@superhero/http-server'
|
|
|
11
12
|
import { execSync } from 'node:child_process'
|
|
12
13
|
import { afterEach, beforeEach, suite, test } from 'node:test'
|
|
13
14
|
|
|
14
|
-
util.inspect.defaultOptions.depth =
|
|
15
|
+
util.inspect.defaultOptions.depth = 5
|
|
15
16
|
|
|
16
17
|
suite('@superhero/http-server', () =>
|
|
17
18
|
{
|
|
@@ -63,6 +64,25 @@ suite('@superhero/http-server', () =>
|
|
|
63
64
|
assert.ok(server.http2Server.constructor.name === 'Http2Server')
|
|
64
65
|
})
|
|
65
66
|
|
|
67
|
+
test('Can be configured by the configuration file', async () =>
|
|
68
|
+
{
|
|
69
|
+
const config = new Config()
|
|
70
|
+
await config.add('./config.json')
|
|
71
|
+
|
|
72
|
+
assert.ok(config.find('bootstrap'))
|
|
73
|
+
assert.ok(config.find('locator'))
|
|
74
|
+
assert.ok(config.find('http-server/server'))
|
|
75
|
+
assert.ok(config.find('http-server/router/routes'))
|
|
76
|
+
|
|
77
|
+
await locator.eagerload(config.find('locator'))
|
|
78
|
+
|
|
79
|
+
assert.ok(locator.has('@superhero/http-server'))
|
|
80
|
+
assert.ok(locator.has('@superhero/http-server/middleware/upstream/method'))
|
|
81
|
+
assert.ok(locator.has('@superhero/http-server/middleware/upstream/header/accept'))
|
|
82
|
+
assert.ok(locator.has('@superhero/http-server/middleware/upstream/header/content-type'))
|
|
83
|
+
assert.ok(locator.has('@superhero/http-server/middleware/upstream/header/content-type/application/json'))
|
|
84
|
+
})
|
|
85
|
+
|
|
66
86
|
test('Listens and closes the server as expected', async () =>
|
|
67
87
|
{
|
|
68
88
|
await server.bootstrap()
|
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
export default new class AcceptHeaderUpstreamMiddleware
|
|
5
5
|
{
|
|
6
6
|
#listFormat = new Intl.ListFormat('en', { style:'long', type:'disjunction' })
|
|
7
|
-
#normalize = (route) => route.replace('accept
|
|
7
|
+
#normalize = (route) => route.replace('accept.', '').trim()
|
|
8
8
|
|
|
9
9
|
dispatch(request, session)
|
|
10
10
|
{
|
|
11
11
|
const
|
|
12
12
|
splitHeader = request.headers['accept']?.toLowerCase().split(',') || [],
|
|
13
13
|
accepts = splitHeader.map(this.#normalize),
|
|
14
|
-
routes = Object.keys(session.route).filter((key) => key.startsWith('accept
|
|
14
|
+
routes = Object.keys(session.route).filter((key) => key.startsWith('accept.') && session.route[key]),
|
|
15
15
|
supports = routes.map((route) => [this.#normalize(route), route])
|
|
16
16
|
|
|
17
17
|
for(let accepted of accepts)
|
|
@@ -9,8 +9,8 @@ export default new class ContentTypeHeaderUpstreamMiddleware
|
|
|
9
9
|
{
|
|
10
10
|
const
|
|
11
11
|
contentType = request.headers['content-type']?.toLowerCase().split(';')[0].split('*')[0].trim(),
|
|
12
|
-
routes = Object.keys(session.route).filter((key) => key.startsWith('content-type
|
|
13
|
-
supports = routes.map((route) => [route.replace('content-type
|
|
12
|
+
routes = Object.keys(session.route).filter((key) => key.startsWith('content-type.') && session.route[key]),
|
|
13
|
+
supports = routes.map((route) => [route.replace('content-type.', '').trim(), route])
|
|
14
14
|
|
|
15
15
|
for(let [supported, route] in supports)
|
|
16
16
|
{
|
|
@@ -9,23 +9,23 @@ export default new class MethodUpstreamMiddleware
|
|
|
9
9
|
{
|
|
10
10
|
const
|
|
11
11
|
method = request.method.toLowerCase(),
|
|
12
|
-
dispatcher = session.route['method
|
|
12
|
+
dispatcher = session.route['method.' + method] || session.route['method.*']
|
|
13
13
|
|
|
14
14
|
if(dispatcher)
|
|
15
15
|
{
|
|
16
|
-
const
|
|
16
|
+
const
|
|
17
17
|
dispatchers = Array.isArray(dispatcher) ? dispatcher : [dispatcher],
|
|
18
18
|
uniqueList = dispatchers.filter((item) => false === session.chain.dispatchers.includes(item))
|
|
19
19
|
|
|
20
|
-
// insert the forward routed dispatcher(s) after the current dispatcher in the chain
|
|
20
|
+
// insert the forward routed dispatcher(s) after the current dispatcher in the chain
|
|
21
21
|
// for the dispatcher chain iterator to dispatch it/them next
|
|
22
22
|
session.chain.dispatchers.splice(session.chain.index, 0, ...uniqueList)
|
|
23
23
|
return
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
const
|
|
27
|
-
supports = Object.keys(session.route).filter((key) => key.startsWith('method
|
|
28
|
-
allowed = supports.map((supported) => supported.replace('method
|
|
27
|
+
supports = Object.keys(session.route).filter((key) => key.startsWith('method.')),
|
|
28
|
+
allowed = supports.map((supported) => supported.replace('method.', '').toUpperCase()).sort(),
|
|
29
29
|
error = new Error(`The requested resource "${request.url}" does not support method "${request.method}"`)
|
|
30
30
|
|
|
31
31
|
error.code = 'E_HTTP_SERVER_MIDDLEWARE_METHOD_NO_MATCHING_DISPATCHER'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@superhero/http-server",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.2",
|
|
4
4
|
"description": "HTTP(S) server component supporting both HTTP 1.1 and HTTP 2.0",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"http server",
|
|
@@ -25,7 +25,8 @@
|
|
|
25
25
|
"@superhero/router": "^4.0.5"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"@superhero/
|
|
28
|
+
"@superhero/config": "^4.1.2",
|
|
29
|
+
"@superhero/locator": "^4.1.2",
|
|
29
30
|
"@superhero/http-request": "^4.0.9"
|
|
30
31
|
},
|
|
31
32
|
"scripts": {
|
|
@@ -37,6 +38,6 @@
|
|
|
37
38
|
},
|
|
38
39
|
"repository": {
|
|
39
40
|
"type": "git",
|
|
40
|
-
"url": "https://github.com/superhero/http-server"
|
|
41
|
+
"url": "git+https://github.com/superhero/http-server.git"
|
|
41
42
|
}
|
|
42
43
|
}
|