@johntalton/http-core 1.0.3 → 1.0.7
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/package.json +6 -2
- package/src/epilogue.js +10 -10
- package/src/index.js +54 -22
- package/src/preamble.js +39 -19
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@johntalton/http-core",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.7",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": "./src/index.js"
|
|
@@ -13,9 +13,13 @@
|
|
|
13
13
|
"url": "https://github.com/johntalton/http-core"
|
|
14
14
|
},
|
|
15
15
|
"scripts": {
|
|
16
|
+
"lint": "biome check"
|
|
16
17
|
},
|
|
17
18
|
"dependencies": {
|
|
18
|
-
"@johntalton/http-util": "^
|
|
19
|
+
"@johntalton/http-util": "^6.1.0",
|
|
19
20
|
"@johntalton/sse-util": "^1.0.0"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@biomejs/biome": "^2.4.15"
|
|
20
24
|
}
|
|
21
25
|
}
|
package/src/epilogue.js
CHANGED
|
@@ -24,7 +24,7 @@ function addSSEPortHandler(stream, port, streamId, shutdownSignal) {
|
|
|
24
24
|
port.close()
|
|
25
25
|
}))
|
|
26
26
|
|
|
27
|
-
shutdownSignal.addEventListener('abort', signalHandler)
|
|
27
|
+
shutdownSignal.addEventListener('abort', signalHandler, { once: true })
|
|
28
28
|
|
|
29
29
|
// ServerSentEvents.messageToEventStreamLines({
|
|
30
30
|
// comment: 'Welcome',
|
|
@@ -47,17 +47,17 @@ function addSSEPortHandler(stream, port, streamId, shutdownSignal) {
|
|
|
47
47
|
export function epilogue(state) {
|
|
48
48
|
const { type, stream, meta, streamId } = state
|
|
49
49
|
|
|
50
|
-
meta.customHeaders
|
|
50
|
+
meta.customHeaders?.push([ 'X-Request-Id', streamId ])
|
|
51
51
|
|
|
52
52
|
switch(type) {
|
|
53
53
|
//
|
|
54
54
|
case 'trace': { Response.trace(stream, state.method, state.url, state.headers, meta) } break
|
|
55
55
|
//
|
|
56
56
|
case 'preflight': { Response.preflight(stream, state.methods, state.supportedQueryTypes, undefined, meta) } break
|
|
57
|
-
case 'no-content': { Response.noContent(stream, state.etag, meta)} break
|
|
57
|
+
case 'no-content': { Response.noContent(stream, state.etag, state.lastModified, meta)} break
|
|
58
58
|
// case 'accepted': { Response.accepted(stream, meta) } break
|
|
59
|
-
case 'created': { Response.created(stream, new URL(state.location, meta.origin), state.etag, meta) } break
|
|
60
|
-
case 'not-modified': { Response.notModified(stream, state.etag, state.
|
|
59
|
+
case 'created': { Response.created(stream, new URL(state.location, meta.origin), state.etag, state.lastModified, meta) } break
|
|
60
|
+
case 'not-modified': { Response.notModified(stream, state.etag, state.lastModified, state.age, state.cacheControl ?? {}, meta) } break
|
|
61
61
|
|
|
62
62
|
//
|
|
63
63
|
// case 'multiple-choices': { Response.multipleChoices(stream, meta) } break
|
|
@@ -74,7 +74,7 @@ export function epilogue(state) {
|
|
|
74
74
|
case 'not-acceptable': { Response.notAcceptable(stream, state.acceptableMediaTypes ?? [], meta)} break
|
|
75
75
|
case 'unsupported-media': { Response.unsupportedMediaType(stream, state.acceptableMediaTypes, state.supportedQueryTypes, meta) } break
|
|
76
76
|
case 'unprocessable': { Response.unprocessable(stream, meta) } break
|
|
77
|
-
case 'precondition-failed': { Response.preconditionFailed(stream, meta) } break
|
|
77
|
+
case 'precondition-failed': { Response.preconditionFailed(stream, state.etag, state.lastModified, meta) } break
|
|
78
78
|
case 'not-satisfiable': { Response.rangeNotSatisfiable(stream, { size: state.contentLength }, meta) } break
|
|
79
79
|
case 'content-too-large': { Response.contentTooLarge(stream, meta) } break
|
|
80
80
|
case 'insufficient-storage': { Response.insufficientStorage(stream, meta) } break
|
|
@@ -94,10 +94,10 @@ export function epilogue(state) {
|
|
|
94
94
|
}
|
|
95
95
|
break
|
|
96
96
|
case 'json': {
|
|
97
|
-
const { obj, accept, etag } = state
|
|
97
|
+
const { obj, accept, etag, lastModified } = state
|
|
98
98
|
|
|
99
99
|
if(accept.type === MIME_TYPE_JSON) {
|
|
100
|
-
Response.json(stream, obj, accept.encoding, etag, state.age,
|
|
100
|
+
Response.json(stream, obj, accept.encoding, etag, lastModified, state.age, state.cacheControl ?? {}, state.supportedQueryTypes, meta)
|
|
101
101
|
}
|
|
102
102
|
else {
|
|
103
103
|
// todo: but we did process the request - is that ok?
|
|
@@ -105,8 +105,8 @@ export function epilogue(state) {
|
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
107
|
break
|
|
108
|
-
case 'partial-bytes': { Response.partialContent(stream, state.contentType, state.objs, state.contentLength, undefined, state.etag, state.age,
|
|
109
|
-
case 'bytes': { Response.bytes(stream, state.contentType, state.obj, state.contentLength, 'identity', state.etag, state.age,
|
|
108
|
+
case 'partial-bytes': { Response.partialContent(stream, state.contentType, state.objs, state.contentLength, undefined, state.etag, state.lastModified, state.age, state.cacheControl ?? {}, meta) } break
|
|
109
|
+
case 'bytes': { Response.bytes(stream, state.contentType, state.obj, state.contentLength, 'identity', state.etag, state.lastModified, state.age, state.cacheControl ?? {}, state.acceptRanges, meta) } break
|
|
110
110
|
|
|
111
111
|
//
|
|
112
112
|
case 'error': {
|
package/src/index.js
CHANGED
|
@@ -42,8 +42,19 @@ export const KNOWN_METHODS = [
|
|
|
42
42
|
|
|
43
43
|
/** @import { Metadata } from '@johntalton/http-util/response' */
|
|
44
44
|
/** @import { BodyFuture } from '@johntalton/http-util/body' */
|
|
45
|
-
/** @import {
|
|
45
|
+
/** @import {
|
|
46
|
+
EtagItem,
|
|
47
|
+
IMFFixDate,
|
|
48
|
+
IMFFixDateInput,
|
|
49
|
+
ContentRangeDirective,
|
|
50
|
+
RateLimitPolicyInfo,
|
|
51
|
+
RateLimitInfo,
|
|
52
|
+
ChallengeItem,
|
|
53
|
+
CacheControlOptions
|
|
54
|
+
} from '@johntalton/http-util/headers' */
|
|
46
55
|
/** @import { SendBody } from '@johntalton/http-util/response' */
|
|
56
|
+
/** @import { SecFetchSite, SecFetchMode, SecFetchDest } from '@johntalton/http-util/headers' */
|
|
57
|
+
|
|
47
58
|
|
|
48
59
|
/** @typedef {(state: RouteRequest|RouteAction) => Promise<RouteAction>} Router */
|
|
49
60
|
|
|
@@ -100,6 +111,20 @@ export const KNOWN_METHODS = [
|
|
|
100
111
|
* @property {AbortSignal} shutdownSignal
|
|
101
112
|
*/
|
|
102
113
|
|
|
114
|
+
/**
|
|
115
|
+
* @typedef {Object} RouteRequestAccept
|
|
116
|
+
* @property {string|undefined} type
|
|
117
|
+
* @property {string|undefined} encoding
|
|
118
|
+
* @property {string|undefined} language
|
|
119
|
+
*/
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* @typedef {Object} RouteRemoteClient
|
|
123
|
+
* @property {string|undefined} family
|
|
124
|
+
* @property {string|undefined} ip
|
|
125
|
+
* @property {number|undefined} port
|
|
126
|
+
*/
|
|
127
|
+
|
|
103
128
|
/**
|
|
104
129
|
* @typedef {Object} RouteRequestBase
|
|
105
130
|
* @property {'request'} type
|
|
@@ -110,6 +135,7 @@ export const KNOWN_METHODS = [
|
|
|
110
135
|
* @property {RouteRequestAccept} accept
|
|
111
136
|
* @property {RouteRemoteClient} client
|
|
112
137
|
* @property {RouteConditions} conditions
|
|
138
|
+
* @property {SecFetchMetadata} secFetchMetadata
|
|
113
139
|
* @property {string} SNI
|
|
114
140
|
*/
|
|
115
141
|
/** @typedef {RouteBase & RouteRequestBase} RouteRequest */
|
|
@@ -138,24 +164,9 @@ export const KNOWN_METHODS = [
|
|
|
138
164
|
* @property {URL} url
|
|
139
165
|
* @property {IncomingHttpHeaders} headers
|
|
140
166
|
* @property {number} maxForwards
|
|
141
|
-
* @property {RouteRequestAccept} accept
|
|
142
167
|
*/
|
|
143
168
|
/** @typedef {RouteBase & RouteTraceBase} RouteTrace */
|
|
144
169
|
|
|
145
|
-
/**
|
|
146
|
-
* @typedef {Object} RouteRequestAccept
|
|
147
|
-
* @property {string|undefined} type
|
|
148
|
-
* @property {string|undefined} encoding
|
|
149
|
-
* @property {string|undefined} language
|
|
150
|
-
*/
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* @typedef {Object} RouteRemoteClient
|
|
154
|
-
* @property {string|undefined} family
|
|
155
|
-
* @property {string|undefined} ip
|
|
156
|
-
* @property {number|undefined} port
|
|
157
|
-
*/
|
|
158
|
-
|
|
159
170
|
/**
|
|
160
171
|
* @typedef {Object} RouteConditions
|
|
161
172
|
* @property {Array<EtagItem>} match
|
|
@@ -165,6 +176,14 @@ export const KNOWN_METHODS = [
|
|
|
165
176
|
* @property {IMFFixDate|EtagItem|undefined} [range]
|
|
166
177
|
*/
|
|
167
178
|
|
|
179
|
+
/**
|
|
180
|
+
* @typedef {Object} SecFetchMetadata
|
|
181
|
+
* @property {SecFetchSite|undefined} site
|
|
182
|
+
* @property {SecFetchMode|undefined} mode
|
|
183
|
+
* @property {SecFetchDest|undefined} dest
|
|
184
|
+
*/
|
|
185
|
+
|
|
186
|
+
|
|
168
187
|
/**
|
|
169
188
|
* @typedef {Object} RoutePreflightBase
|
|
170
189
|
* @property {'preflight'} type
|
|
@@ -180,9 +199,10 @@ export const KNOWN_METHODS = [
|
|
|
180
199
|
* @property {'json'} type
|
|
181
200
|
* @property {RouteRequestAccept} accept
|
|
182
201
|
* @property {Record<any, any>} obj
|
|
183
|
-
* @property {
|
|
202
|
+
* @property {IMFFixDateInput|string|undefined} [lastModified]
|
|
184
203
|
* @property {EtagItem|undefined} [etag]
|
|
185
204
|
* @property {number|undefined} [age]
|
|
205
|
+
* @property {CacheControlOptions|undefined} [cacheControl]
|
|
186
206
|
* @property {Array<string>|undefined} [supportedQueryTypes]
|
|
187
207
|
*/
|
|
188
208
|
/** @typedef {RouteBase & RouteJSONBase} RouteJSON */
|
|
@@ -201,6 +221,7 @@ export const KNOWN_METHODS = [
|
|
|
201
221
|
* @property {'created'} type
|
|
202
222
|
* @property {URL|string} location
|
|
203
223
|
* @property {EtagItem|undefined} [etag]
|
|
224
|
+
* @property {IMFFixDateInput|string|undefined} [lastModified]
|
|
204
225
|
*/
|
|
205
226
|
/** @typedef {RouteBase & RouteCreatedBase} RouteCreated */
|
|
206
227
|
|
|
@@ -217,7 +238,9 @@ export const KNOWN_METHODS = [
|
|
|
217
238
|
* @property {'not-modified'} type
|
|
218
239
|
* @property {number} age
|
|
219
240
|
* @property {EtagItem|undefined} [etag]
|
|
241
|
+
* @property {IMFFixDateInput|string|undefined} [lastModified]
|
|
220
242
|
* @property {number|undefined} [age]
|
|
243
|
+
* @property {CacheControlOptions|undefined} [cacheControl]
|
|
221
244
|
*/
|
|
222
245
|
/** @typedef {RouteBase & RouteNotModifiedBase} RouteNotModified */
|
|
223
246
|
|
|
@@ -225,6 +248,7 @@ export const KNOWN_METHODS = [
|
|
|
225
248
|
* @typedef {Object} RoutePreconditionFailedBase
|
|
226
249
|
* @property {'precondition-failed'} type
|
|
227
250
|
* @property {EtagItem|undefined} [etag]
|
|
251
|
+
* @property {IMFFixDateInput|string|undefined} [lastModified]
|
|
228
252
|
*/
|
|
229
253
|
/** @typedef {RouteBase & RoutePreconditionFailedBase} RoutePreconditionFailed */
|
|
230
254
|
|
|
@@ -272,10 +296,10 @@ export const KNOWN_METHODS = [
|
|
|
272
296
|
* @property {string} contentType
|
|
273
297
|
* @property {number|undefined} [contentLength]
|
|
274
298
|
* @property {SendBody|undefined} obj
|
|
275
|
-
* @property {
|
|
299
|
+
* @property {IMFFixDateInput|string|undefined} [lastModified]
|
|
276
300
|
* @property {EtagItem|undefined} [etag]
|
|
277
301
|
* @property {number|undefined} [age]
|
|
278
|
-
* @property {
|
|
302
|
+
* @property {CacheControlOptions|undefined} [cacheControl]
|
|
279
303
|
* @property {'bytes'|'none'|undefined} [acceptRanges]
|
|
280
304
|
*/
|
|
281
305
|
/** @typedef {RouteBase & RouteBytesBase} RouteBytes */
|
|
@@ -298,8 +322,9 @@ export const KNOWN_METHODS = [
|
|
|
298
322
|
* @property {string} contentType
|
|
299
323
|
* @property {number|undefined} [contentLength]
|
|
300
324
|
* @property {EtagItem|undefined} [etag]
|
|
325
|
+
* @property {IMFFixDateInput|string|undefined} [lastModified]
|
|
301
326
|
* @property {number|undefined} [age]
|
|
302
|
-
* @property {
|
|
327
|
+
* @property {CacheControlOptions|undefined} [cacheControl]
|
|
303
328
|
*/
|
|
304
329
|
/** @typedef {RouteBase & RoutePartialBytesBase} RoutePartialBytes */
|
|
305
330
|
|
|
@@ -342,6 +367,7 @@ export const KNOWN_METHODS = [
|
|
|
342
367
|
* @typedef {Object} RouteNoContentBase
|
|
343
368
|
* @property {'no-content'} type
|
|
344
369
|
* @property {EtagItem|undefined} [etag]
|
|
370
|
+
* @property {IMFFixDateInput|string|undefined} [lastModified]
|
|
345
371
|
*/
|
|
346
372
|
/** @typedef {RouteBase & RouteNoContentBase} RouteNoContent */
|
|
347
373
|
|
|
@@ -396,7 +422,6 @@ export const KNOWN_METHODS = [
|
|
|
396
422
|
* @property {boolean} active
|
|
397
423
|
* @property {boolean} bom
|
|
398
424
|
* @property {MessagePort} port
|
|
399
|
-
* @property {RouteRequestAccept} accept
|
|
400
425
|
*/
|
|
401
426
|
/** @typedef {RouteBase & RouteSSEBase} RouteSSE */
|
|
402
427
|
|
|
@@ -604,7 +629,14 @@ export class H2CoreServer {
|
|
|
604
629
|
if(!isServerStream(stream)) { return }
|
|
605
630
|
|
|
606
631
|
// const start = performance.now()
|
|
607
|
-
const state = preamble(
|
|
632
|
+
const state = preamble({
|
|
633
|
+
config: this.#h2Options.config,
|
|
634
|
+
streamId,
|
|
635
|
+
stream,
|
|
636
|
+
shutdownSignal: this.#controller.signal
|
|
637
|
+
},
|
|
638
|
+
headers,
|
|
639
|
+
this.#h2Options.serverName)
|
|
608
640
|
router(state)
|
|
609
641
|
.then(epilogue)
|
|
610
642
|
.catch(e => epilogue({ ...state, type: 'error', cause: e.message, error: e }))
|
package/src/preamble.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/** biome-ignore-all lint/nursery/noExcessiveLinesPerFile: does all the work */
|
|
1
2
|
import http2 from 'node:http2'
|
|
2
3
|
import { TLSSocket } from 'node:tls'
|
|
3
4
|
|
|
@@ -8,6 +9,7 @@ import {
|
|
|
8
9
|
AcceptLanguage,
|
|
9
10
|
|
|
10
11
|
Conditional,
|
|
12
|
+
ContentType,
|
|
11
13
|
ETag,
|
|
12
14
|
|
|
13
15
|
FORWARDED_KEY_FOR,
|
|
@@ -19,18 +21,21 @@ import {
|
|
|
19
21
|
MIME_TYPE_MESSAGE_HTTP,
|
|
20
22
|
MIME_TYPE_TEXT,
|
|
21
23
|
MIME_TYPE_XML,
|
|
22
|
-
|
|
24
|
+
SecFetch
|
|
23
25
|
} from '@johntalton/http-util/headers'
|
|
24
26
|
import {
|
|
25
27
|
ENCODER_MAP,
|
|
26
28
|
HTTP_HEADER_FORWARDED,
|
|
27
|
-
HTTP_HEADER_ORIGIN
|
|
29
|
+
HTTP_HEADER_ORIGIN,
|
|
30
|
+
HTTP_HEADER_SEC_FETCH_DEST,
|
|
31
|
+
HTTP_HEADER_SEC_FETCH_MODE,
|
|
32
|
+
HTTP_HEADER_SEC_FETCH_SITE
|
|
28
33
|
} from '@johntalton/http-util/response'
|
|
29
34
|
|
|
30
35
|
import { isValidHeader, isValidLikeHeader, isValidMethod } from './index.js'
|
|
31
36
|
|
|
32
37
|
/** @import { ServerHttp2Stream, IncomingHttpHeaders } from 'node:http2' */
|
|
33
|
-
/** @import { Config, RouteRequest, RouteAction, StreamID, RouteConditions } from './index.js' */
|
|
38
|
+
/** @import { Config, RouteRequest, RouteAction, StreamID, RouteConditions, SecFetchMetadata } from './index.js' */
|
|
34
39
|
|
|
35
40
|
const { HTTP2_METHOD_OPTIONS, HTTP2_METHOD_TRACE } = http2.constants
|
|
36
41
|
|
|
@@ -94,16 +99,24 @@ const BODY_BYTE_LENGTH = BYTE_PER_K * BYTE_PER_K
|
|
|
94
99
|
// }
|
|
95
100
|
|
|
96
101
|
/**
|
|
97
|
-
* @
|
|
98
|
-
* @
|
|
99
|
-
* @
|
|
102
|
+
* @typedef {Object} PreState
|
|
103
|
+
* @property {Config} config
|
|
104
|
+
* @property {StreamID} streamId
|
|
105
|
+
* @property {ServerHttp2Stream} stream
|
|
106
|
+
* @property {AbortSignal} shutdownSignal
|
|
107
|
+
*/
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* @param {PreState} preState
|
|
100
111
|
* @param {IncomingHttpHeaders} headers
|
|
101
112
|
* @param {string|undefined} servername
|
|
102
|
-
* @param {AbortSignal} shutdownSignal
|
|
103
113
|
* @returns {RouteRequest|RouteAction}
|
|
104
114
|
*/
|
|
105
|
-
|
|
115
|
+
|
|
116
|
+
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: work horse
|
|
117
|
+
export function preamble(preState, headers, servername) {
|
|
106
118
|
const preambleStart = performance.now()
|
|
119
|
+
const { stream, shutdownSignal } = preState
|
|
107
120
|
|
|
108
121
|
//
|
|
109
122
|
const method = headers[HTTP2_HEADER_METHOD]
|
|
@@ -142,9 +155,9 @@ export function preamble(config, streamId, stream, headers, servername, shutdown
|
|
|
142
155
|
// const secUA = header[HTTP_HEADER_SEC_CH_UA]
|
|
143
156
|
// const secPlatform = header[HTTP_HEADER_SEC_CH_PLATFORM]
|
|
144
157
|
// const secMobile = header[HTTP_HEADER_SEC_CH_MOBILE]
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
158
|
+
const secFetchSite = headers[HTTP_HEADER_SEC_FETCH_SITE]
|
|
159
|
+
const secFetchMode = headers[HTTP_HEADER_SEC_FETCH_MODE]
|
|
160
|
+
const secFetchDest = headers[HTTP_HEADER_SEC_FETCH_DEST]
|
|
148
161
|
|
|
149
162
|
//
|
|
150
163
|
const allowedOrigin = (ALLOWED_ORIGINS.includes('*') || ((origin !== undefined) && URL.canParse(origin) && ALLOWED_ORIGINS.includes(origin))) ? origin : undefined
|
|
@@ -154,16 +167,13 @@ export function preamble(config, streamId, stream, headers, servername, shutdown
|
|
|
154
167
|
const state = {
|
|
155
168
|
type: 'error',
|
|
156
169
|
cause: 'initialize',
|
|
157
|
-
|
|
158
|
-
streamId,
|
|
159
|
-
stream,
|
|
170
|
+
...preState,
|
|
160
171
|
meta: {
|
|
161
172
|
servername,
|
|
162
173
|
performance: [],
|
|
163
174
|
origin: allowedOrigin,
|
|
164
175
|
customHeaders: []
|
|
165
|
-
}
|
|
166
|
-
shutdownSignal
|
|
176
|
+
}
|
|
167
177
|
}
|
|
168
178
|
|
|
169
179
|
if(shutdownSignal.aborted) {
|
|
@@ -200,6 +210,15 @@ export function preamble(config, streamId, stream, headers, servername, shutdown
|
|
|
200
210
|
//
|
|
201
211
|
const requestUrl = new URL(fullPathAndQuery, `${scheme}://${authority}`)
|
|
202
212
|
|
|
213
|
+
// Sec Fetch Metadata
|
|
214
|
+
/** @type {SecFetchMetadata} */
|
|
215
|
+
const secFetchMetadata = {
|
|
216
|
+
site: SecFetch.parseSite(secFetchSite),
|
|
217
|
+
mode: SecFetch.parseMode(secFetchMode),
|
|
218
|
+
dest: SecFetch.parseDestination(secFetchDest)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
|
|
203
222
|
//
|
|
204
223
|
/** @type {RouteConditions} */
|
|
205
224
|
const conditions = {
|
|
@@ -240,7 +259,7 @@ export function preamble(config, streamId, stream, headers, servername, shutdown
|
|
|
240
259
|
//
|
|
241
260
|
// content negotiation
|
|
242
261
|
//
|
|
243
|
-
const contentType =
|
|
262
|
+
const contentType = ContentType.parse(fullContentType)
|
|
244
263
|
const acceptedEncoding = AcceptEncoding.select(fullAcceptEncoding, DEFAULT_SUPPORTED_ENCODINGS)
|
|
245
264
|
const accept = Accept.select(fullAccept, DEFAULT_SUPPORTED_MIME_TYPES)
|
|
246
265
|
const acceptedLanguage = AcceptLanguage.select(fullAcceptLanguage, DEFAULT_SUPPORTED_LANGUAGES)
|
|
@@ -255,11 +274,11 @@ export function preamble(config, streamId, stream, headers, servername, shutdown
|
|
|
255
274
|
//
|
|
256
275
|
if(method === HTTP2_METHOD_TRACE) {
|
|
257
276
|
if(!ALLOW_TRACE) { return { ...state, type: 'not-allowed', method, methods: [], url: requestUrl }}
|
|
258
|
-
const maxForwardsValue = maxForwards
|
|
277
|
+
const maxForwardsValue = maxForwards === undefined ? 0 : Number.parseInt(maxForwards)
|
|
259
278
|
const preambleEnd = performance.now()
|
|
260
279
|
state.meta.performance.push({ name: 'preamble-trace', duration: preambleEnd - preambleStart })
|
|
261
280
|
if(acceptObject.type !== MIME_TYPE_MESSAGE_HTTP) { return { ...state, type: 'not-acceptable', acceptableMediaTypes: [ MIME_TYPE_MESSAGE_HTTP ] } }
|
|
262
|
-
return { ...state, type: 'trace', method, headers, url: requestUrl, maxForwards: maxForwardsValue
|
|
281
|
+
return { ...state, type: 'trace', method, headers, url: requestUrl, maxForwards: maxForwardsValue }
|
|
263
282
|
}
|
|
264
283
|
|
|
265
284
|
//
|
|
@@ -294,6 +313,7 @@ export function preamble(config, streamId, stream, headers, servername, shutdown
|
|
|
294
313
|
body,
|
|
295
314
|
// tokens,
|
|
296
315
|
conditions,
|
|
316
|
+
secFetchMetadata,
|
|
297
317
|
accept: acceptObject,
|
|
298
318
|
client: { family, ip, port },
|
|
299
319
|
SNI
|