@johntalton/http-core 1.0.3 → 1.0.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@johntalton/http-core",
3
3
  "type": "module",
4
- "version": "1.0.3",
4
+ "version": "1.0.5",
5
5
  "license": "MIT",
6
6
  "exports": {
7
7
  ".": "./src/index.js"
@@ -15,7 +15,7 @@
15
15
  "scripts": {
16
16
  },
17
17
  "dependencies": {
18
- "@johntalton/http-util": "^5.1.2",
18
+ "@johntalton/http-util": "^6.0.0",
19
19
  "@johntalton/sse-util": "^1.0.0"
20
20
  }
21
21
  }
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,7 +47,7 @@ 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.push([ 'X-Request-Id', streamId ])
50
+ meta.customHeaders?.push([ 'X-Request-Id', streamId ])
51
51
 
52
52
  switch(type) {
53
53
  //
package/src/index.js CHANGED
@@ -44,6 +44,8 @@ export const KNOWN_METHODS = [
44
44
  /** @import { BodyFuture } from '@johntalton/http-util/body' */
45
45
  /** @import { EtagItem, IMFFixDate, ContentRangeDirective, RateLimitPolicyInfo, RateLimitInfo, ChallengeItem } from '@johntalton/http-util/headers' */
46
46
  /** @import { SendBody } from '@johntalton/http-util/response' */
47
+ /** @import { SecFetchSite, SecFetchMode, SecFetchDest } from '@johntalton/http-util/headers' */
48
+
47
49
 
48
50
  /** @typedef {(state: RouteRequest|RouteAction) => Promise<RouteAction>} Router */
49
51
 
@@ -110,6 +112,7 @@ export const KNOWN_METHODS = [
110
112
  * @property {RouteRequestAccept} accept
111
113
  * @property {RouteRemoteClient} client
112
114
  * @property {RouteConditions} conditions
115
+ * @property {SecFetchMetadata} secFetchMetadata
113
116
  * @property {string} SNI
114
117
  */
115
118
  /** @typedef {RouteBase & RouteRequestBase} RouteRequest */
@@ -165,6 +168,14 @@ export const KNOWN_METHODS = [
165
168
  * @property {IMFFixDate|EtagItem|undefined} [range]
166
169
  */
167
170
 
171
+ /**
172
+ * @typedef {Object} SecFetchMetadata
173
+ * @property {SecFetchSite|undefined} site
174
+ * @property {SecFetchMode|undefined} mode
175
+ * @property {SecFetchDest|undefined} dest
176
+ */
177
+
178
+
168
179
  /**
169
180
  * @typedef {Object} RoutePreflightBase
170
181
  * @property {'preflight'} type
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
- parseContentType
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
 
@@ -142,9 +147,9 @@ export function preamble(config, streamId, stream, headers, servername, shutdown
142
147
  // const secUA = header[HTTP_HEADER_SEC_CH_UA]
143
148
  // const secPlatform = header[HTTP_HEADER_SEC_CH_PLATFORM]
144
149
  // const secMobile = header[HTTP_HEADER_SEC_CH_MOBILE]
145
- // const secFetchSite = header[HTTP_HEADER_SEC_FETCH_SITE]
146
- // const secFetchMode = header[HTTP_HEADER_SEC_FETCH_MODE]
147
- // const secFetchDest = header[HTTP_HEADER_SEC_FETCH_DEST]
150
+ const secFetchSite = headers[HTTP_HEADER_SEC_FETCH_SITE]
151
+ const secFetchMode = headers[HTTP_HEADER_SEC_FETCH_MODE]
152
+ const secFetchDest = headers[HTTP_HEADER_SEC_FETCH_DEST]
148
153
 
149
154
  //
150
155
  const allowedOrigin = (ALLOWED_ORIGINS.includes('*') || ((origin !== undefined) && URL.canParse(origin) && ALLOWED_ORIGINS.includes(origin))) ? origin : undefined
@@ -200,6 +205,15 @@ export function preamble(config, streamId, stream, headers, servername, shutdown
200
205
  //
201
206
  const requestUrl = new URL(fullPathAndQuery, `${scheme}://${authority}`)
202
207
 
208
+ // Sec Fetch Metadata
209
+ /** @type {SecFetchMetadata} */
210
+ const secFetchMetadata = {
211
+ site: SecFetch.parseSite(secFetchSite),
212
+ mode: SecFetch.parseMode(secFetchMode),
213
+ dest: SecFetch.parseDestination(secFetchDest)
214
+ }
215
+
216
+
203
217
  //
204
218
  /** @type {RouteConditions} */
205
219
  const conditions = {
@@ -240,7 +254,7 @@ export function preamble(config, streamId, stream, headers, servername, shutdown
240
254
  //
241
255
  // content negotiation
242
256
  //
243
- const contentType = parseContentType(fullContentType)
257
+ const contentType = ContentType.parse(fullContentType)
244
258
  const acceptedEncoding = AcceptEncoding.select(fullAcceptEncoding, DEFAULT_SUPPORTED_ENCODINGS)
245
259
  const accept = Accept.select(fullAccept, DEFAULT_SUPPORTED_MIME_TYPES)
246
260
  const acceptedLanguage = AcceptLanguage.select(fullAcceptLanguage, DEFAULT_SUPPORTED_LANGUAGES)
@@ -255,7 +269,7 @@ export function preamble(config, streamId, stream, headers, servername, shutdown
255
269
  //
256
270
  if(method === HTTP2_METHOD_TRACE) {
257
271
  if(!ALLOW_TRACE) { return { ...state, type: 'not-allowed', method, methods: [], url: requestUrl }}
258
- const maxForwardsValue = maxForwards !== undefined ? Number.parseInt(maxForwards) : 0
272
+ const maxForwardsValue = maxForwards === undefined ? 0 : Number.parseInt(maxForwards)
259
273
  const preambleEnd = performance.now()
260
274
  state.meta.performance.push({ name: 'preamble-trace', duration: preambleEnd - preambleStart })
261
275
  if(acceptObject.type !== MIME_TYPE_MESSAGE_HTTP) { return { ...state, type: 'not-acceptable', acceptableMediaTypes: [ MIME_TYPE_MESSAGE_HTTP ] } }
@@ -294,6 +308,7 @@ export function preamble(config, streamId, stream, headers, servername, shutdown
294
308
  body,
295
309
  // tokens,
296
310
  conditions,
311
+ secFetchMetadata,
297
312
  accept: acceptObject,
298
313
  client: { family, ip, port },
299
314
  SNI