@johntalton/http-util 5.1.6 → 6.1.0

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.
Files changed (84) hide show
  1. package/README.md +54 -7
  2. package/package.json +26 -6
  3. package/src/body.js +8 -8
  4. package/src/{response/defs.js → defs.js} +35 -1
  5. package/src/{accept-encoding.js → headers/accept-encoding.js} +11 -14
  6. package/src/{accept-language.js → headers/accept-language.js} +14 -9
  7. package/src/headers/accept.js +86 -0
  8. package/src/{cache-control.js → headers/cache-control.js} +0 -6
  9. package/src/{clear-site-data.js → headers/clear-site-data.js} +4 -10
  10. package/src/headers/client-hints.js +88 -0
  11. package/src/{conditional.js → headers/conditional.js} +190 -117
  12. package/src/headers/content-disposition.js +44 -0
  13. package/src/{content-range.js → headers/content-range.js} +1 -18
  14. package/src/headers/content-type.js +101 -0
  15. package/src/{forwarded.js → headers/forwarded.js} +8 -56
  16. package/src/{index.js → headers/index.js} +4 -2
  17. package/src/headers/link.js +34 -0
  18. package/src/{multipart.js → headers/multipart.js} +22 -13
  19. package/src/{preference.js → headers/preference.js} +3 -58
  20. package/src/{range.js → headers/range.js} +4 -32
  21. package/src/{rate-limit.js → headers/rate-limit.js} +6 -1
  22. package/src/{server-timing.js → headers/server-timing.js} +3 -16
  23. package/src/headers/strict-transport-security.js +39 -0
  24. package/src/{accept-util.js → headers/util/accept-util.js} +8 -14
  25. package/src/headers/util/index.js +7 -0
  26. package/src/headers/util/kvp.js +79 -0
  27. package/src/headers/util/mime.js +77 -0
  28. package/src/headers/util/whitespace.js +8 -0
  29. package/src/{www-authenticate.js → headers/www-authenticate.js} +1 -1
  30. package/src/response/{accepted.js → 2xx/accepted.js} +2 -2
  31. package/src/response/2xx/bytes.js +62 -0
  32. package/src/response/2xx/created.js +49 -0
  33. package/src/response/2xx/json.js +60 -0
  34. package/src/response/2xx/no-content.js +45 -0
  35. package/src/response/2xx/partial-content.js +101 -0
  36. package/src/response/{preflight.js → 2xx/preflight.js} +29 -10
  37. package/src/response/{sse.js → 2xx/sse.js} +2 -2
  38. package/src/response/{trace.js → 2xx/trace.js} +3 -3
  39. package/src/response/3xx/found.js +23 -0
  40. package/src/response/{moved-permanently.js → 3xx/moved-permanently.js} +2 -2
  41. package/src/response/{multiple-choices.js → 3xx/multiple-choices.js} +2 -3
  42. package/src/response/3xx/not-modified.js +59 -0
  43. package/src/response/{permanent-redirect.js → 3xx/permanent-redirect.js} +2 -2
  44. package/src/response/{see-other.js → 3xx/see-other.js} +2 -2
  45. package/src/response/{temporary-redirect.js → 3xx/temporary-redirect.js} +2 -2
  46. package/src/response/4xx/bad-request.js +19 -0
  47. package/src/response/{conflict.js → 4xx/conflict.js} +2 -2
  48. package/src/response/{content-too-large.js → 4xx/content-too-large.js} +2 -2
  49. package/src/response/{forbidden.js → 4xx/forbidden.js} +3 -2
  50. package/src/response/{gone.js → 4xx/gone.js} +2 -2
  51. package/src/response/{im-a-teapot.js → 4xx/im-a-teapot.js} +2 -2
  52. package/src/response/{not-acceptable.js → 4xx/not-acceptable.js} +14 -3
  53. package/src/response/4xx/not-allowed.js +34 -0
  54. package/src/response/{not-found.js → 4xx/not-found.js} +3 -3
  55. package/src/response/4xx/payment-required.js +17 -0
  56. package/src/response/4xx/precondition-failed.js +45 -0
  57. package/src/response/{range-not-satisfiable.js → 4xx/range-not-satisfiable.js} +15 -4
  58. package/src/response/{timeout.js → 4xx/timeout.js} +2 -2
  59. package/src/response/{too-many-requests.js → 4xx/too-many-requests.js} +22 -5
  60. package/src/response/{unauthorized.js → 4xx/unauthorized.js} +5 -5
  61. package/src/response/{unprocessable.js → 4xx/unprocessable.js} +2 -2
  62. package/src/response/{unsupported-media.js → 4xx/unsupported-media.js} +21 -4
  63. package/src/response/{error.js → 5xx/error.js} +3 -3
  64. package/src/response/{insufficient-storage.js → 5xx/insufficient-storage.js} +2 -2
  65. package/src/response/{not-implemented.js → 5xx/not-implemented.js} +4 -4
  66. package/src/response/{unavailable.js → 5xx/unavailable.js} +16 -4
  67. package/src/response/header-util.js +2 -2
  68. package/src/response/index.js +39 -35
  69. package/src/response/response.js +40 -34
  70. package/src/response/send-util.js +32 -21
  71. package/src/accept.js +0 -122
  72. package/src/content-disposition.js +0 -57
  73. package/src/content-type.js +0 -148
  74. package/src/link.js +0 -35
  75. package/src/response/bytes.js +0 -27
  76. package/src/response/created.js +0 -28
  77. package/src/response/json.js +0 -28
  78. package/src/response/no-content.js +0 -25
  79. package/src/response/not-allowed.js +0 -23
  80. package/src/response/not-modified.js +0 -35
  81. package/src/response/partial-content.js +0 -71
  82. package/src/response/precondition-failed.js +0 -16
  83. /package/src/{fetch-metadata.js → headers/fetch-metadata.js} +0 -0
  84. /package/src/{quote.js → headers/util/quote.js} +0 -0
@@ -0,0 +1,49 @@
1
+ import http2 from 'node:http2'
2
+
3
+ import { Conditional } from '../../headers/conditional.js'
4
+ import { send } from '../send-util.js'
5
+
6
+ /** @import { ServerHttp2Stream } from 'node:http2' */
7
+ /** @import { SendContent, Metadata } from '../../defs.js' */
8
+ /** @import { EtagItem, IMFFixDateInput } from '../../headers/conditional.js' */
9
+
10
+ const {
11
+ HTTP2_HEADER_LOCATION,
12
+ HTTP2_HEADER_ETAG,
13
+ HTTP2_HEADER_LAST_MODIFIED
14
+ } = http2.constants
15
+
16
+ const { HTTP_STATUS_CREATED } = http2.constants
17
+
18
+ /**
19
+ * @param {ServerHttp2Stream} stream
20
+ * @param {URL} location
21
+ * @param {EtagItem|undefined} etag
22
+ * @param {IMFFixDateInput|string|undefined} lastModified
23
+ * @param {Metadata} meta
24
+ */
25
+ export function sendCreated(stream, location, etag, lastModified, meta) {
26
+ _sendCreated(stream, location, {
27
+ etag,
28
+ lastModified
29
+ }, meta)
30
+ }
31
+
32
+ /**
33
+ * @param {ServerHttp2Stream} stream
34
+ * @param {URL} location
35
+ * @param {Pick<SendContent, 'etag' | 'lastModified'>} content
36
+ * @param {Metadata} meta
37
+ */
38
+ export function _sendCreated(stream, location, content, meta) {
39
+ const {
40
+ etag,
41
+ lastModified
42
+ } = content
43
+
44
+ send(stream, HTTP_STATUS_CREATED, {
45
+ [HTTP2_HEADER_LOCATION]: location.href,
46
+ [HTTP2_HEADER_ETAG]: Conditional.encodeEtag(etag),
47
+ [HTTP2_HEADER_LAST_MODIFIED]: Conditional.encodeFixDate(lastModified)
48
+ }, [ HTTP2_HEADER_LOCATION ], undefined, undefined, meta)
49
+ }
@@ -0,0 +1,60 @@
1
+ import http2 from 'node:http2'
2
+
3
+ import { CONTENT_TYPE_JSON } from '../../headers/content-type.js'
4
+ import { send_encoded } from '../send-util.js'
5
+
6
+ /** @import { ServerHttp2Stream } from 'node:http2' */
7
+ /** @import { SendContent, SendInfo, Metadata } from '../../defs.js' */
8
+ /** @import { EtagItem, IMFFixDateInput } from '../../headers/conditional.js' */
9
+ /** @import { CacheControlOptions } from '../../headers/cache-control.js' */
10
+
11
+ const { HTTP_STATUS_OK } = http2.constants
12
+
13
+ /**
14
+ * @param {ServerHttp2Stream} stream
15
+ * @param {Object} obj
16
+ * @param {string|undefined} encoding
17
+ * @param {EtagItem|undefined} etag
18
+ * @param {IMFFixDateInput|string|undefined} lastModified
19
+ * @param {number|undefined} age
20
+ * @param {CacheControlOptions} cacheControl
21
+ * @param {Array<string>|undefined} supportedQueryTypes
22
+ * @param {Metadata} meta
23
+ */
24
+ export function sendJSON_Encoded(stream, obj, encoding, etag, lastModified, age, cacheControl, supportedQueryTypes, meta) {
25
+ _sendJSON_Encoded(stream, obj, {
26
+ encoding,
27
+ etag,
28
+ lastModified,
29
+ age,
30
+ cacheControl
31
+ }, {
32
+ supportedQueryTypes
33
+ }, meta)
34
+ }
35
+
36
+ /**
37
+ * @param {ServerHttp2Stream} stream
38
+ * @param {Object} obj
39
+ * @param {Omit<SendContent, 'contentType' | 'contentLength' | 'rangeDirective'>} content
40
+ * @param {Pick<SendInfo, 'supportedQueryTypes'>} info
41
+ * @param {Metadata} meta
42
+ */
43
+ export function _sendJSON_Encoded(stream, obj, content, info, meta) {
44
+ const {
45
+ encoding,
46
+ etag,
47
+ lastModified,
48
+ age,
49
+ cacheControl
50
+ } = content
51
+
52
+ const {
53
+ supportedQueryTypes
54
+ } = info
55
+
56
+ if(stream.closed) { return }
57
+
58
+ const json = JSON.stringify(obj)
59
+ send_encoded(stream, HTTP_STATUS_OK, CONTENT_TYPE_JSON, json, encoding, etag, lastModified, age, cacheControl, undefined, supportedQueryTypes, meta)
60
+ }
@@ -0,0 +1,45 @@
1
+ import http2 from 'node:http2'
2
+
3
+ import { Conditional } from '../../headers/conditional.js'
4
+ import { send } from '../send-util.js'
5
+
6
+ /** @import { ServerHttp2Stream } from 'node:http2' */
7
+ /** @import { SendContent, Metadata } from '../../defs.js' */
8
+ /** @import { EtagItem, IMFFixDateInput } from '../../headers/conditional.js' */
9
+
10
+ const {
11
+ HTTP2_HEADER_ETAG,
12
+ HTTP2_HEADER_LAST_MODIFIED
13
+ } = http2.constants
14
+
15
+ const { HTTP_STATUS_NO_CONTENT } = http2.constants
16
+
17
+ /**
18
+ * @param {ServerHttp2Stream} stream
19
+ * @param {EtagItem|undefined} etag
20
+ * @param {IMFFixDateInput|string|undefined} lastModified
21
+ * @param {Metadata} meta
22
+ */
23
+ export function sendNoContent(stream, etag, lastModified, meta) {
24
+ _sendNoContent(stream, {
25
+ etag,
26
+ lastModified
27
+ }, meta)
28
+ }
29
+
30
+ /**
31
+ * @param {ServerHttp2Stream} stream
32
+ * @param {Pick<SendContent, 'etag' | 'lastModified'>} content
33
+ * @param {Metadata} meta
34
+ */
35
+ export function _sendNoContent(stream, content, meta) {
36
+ const {
37
+ etag,
38
+ lastModified
39
+ } = content
40
+
41
+ send(stream, HTTP_STATUS_NO_CONTENT, {
42
+ [HTTP2_HEADER_ETAG]: Conditional.encodeEtag(etag),
43
+ [HTTP2_HEADER_LAST_MODIFIED]: Conditional.encodeFixDate(lastModified)
44
+ }, [], undefined, undefined, meta)
45
+ }
@@ -0,0 +1,101 @@
1
+ import http2 from 'node:http2'
2
+
3
+ import { RANGE_UNITS_BYTES } from '../../defs.js'
4
+ import { MIME_TYPE_MULTIPART_RANGE, MIME_TYPE_OCTET_STREAM } from '../../headers/content-type.js'
5
+ import { Multipart } from '../../headers/multipart.js'
6
+ import { send_bytes } from '../send-util.js'
7
+
8
+ /** @import { ServerHttp2Stream } from 'node:http2' */
9
+ /** @import { SendContent, Metadata, SendBody } from '../../defs.js' */
10
+ /** @import { EtagItem, IMFFixDateInput } from '../../headers/conditional.js' */
11
+ /** @import { CacheControlOptions } from '../../headers/cache-control.js' */
12
+ /** @import { ContentRangeDirective } from '../../headers/content-range.js' */
13
+
14
+
15
+ const { HTTP_STATUS_PARTIAL_CONTENT } = http2.constants
16
+
17
+ /**
18
+ * @template T
19
+ * @typedef {[ T, ...T[] ]} NonEmptyArray
20
+ */
21
+
22
+ /**
23
+ * @typedef {Object} PartialBytes
24
+ * @property {SendBody} obj
25
+ * @property {ContentRangeDirective} range
26
+ */
27
+
28
+ /**
29
+ * @param {ServerHttp2Stream} stream
30
+ * @param {string|undefined} contentType
31
+ * @param {NonEmptyArray<PartialBytes>|PartialBytes} objs
32
+ * @param {number|undefined} contentLength
33
+ * @param {string|undefined} encoding
34
+ * @param {EtagItem|undefined} etag
35
+ * @param {IMFFixDateInput|string|undefined} lastModified
36
+ * @param {number|undefined} age
37
+ * @param {CacheControlOptions} cacheControl
38
+ * @param {Metadata} meta
39
+ */
40
+ export function sendPartialContent(stream, contentType, objs, contentLength, encoding, etag, lastModified, age, cacheControl, meta) {
41
+ return _sendPartialContent(stream, objs, {
42
+ contentType,
43
+ contentLength,
44
+ encoding,
45
+ etag,
46
+ lastModified,
47
+ age,
48
+ cacheControl
49
+ }, meta)
50
+ }
51
+
52
+ /**
53
+ * @param {ServerHttp2Stream} stream
54
+ * @param {NonEmptyArray<PartialBytes>|PartialBytes} objs
55
+ * @param {Omit<SendContent, 'rangeDirective'>} content
56
+ * @param {Metadata} meta
57
+ */
58
+ export function _sendPartialContent(stream, objs, content, meta) {
59
+ const {
60
+ contentType,
61
+ contentLength,
62
+ encoding,
63
+ etag,
64
+ lastModified,
65
+ age,
66
+ cacheControl
67
+ } = content
68
+
69
+ const acceptRanges = RANGE_UNITS_BYTES
70
+ const supportedQueryTypes = undefined
71
+
72
+ if(Array.isArray(objs) && objs.length > 1) {
73
+ // send using multipart bytes
74
+ const boundary = 'PARTIAL_CONTENT_BOUNDARY' // todo make unique for content
75
+ const obj = Multipart.encode_Bytes(contentType ?? MIME_TYPE_OCTET_STREAM, objs, contentLength, boundary)
76
+
77
+ const multipartContentType = `${MIME_TYPE_MULTIPART_RANGE}; boundary=${boundary}`
78
+
79
+ send_bytes(
80
+ stream,
81
+ HTTP_STATUS_PARTIAL_CONTENT,
82
+ multipartContentType,
83
+ obj,
84
+ undefined,
85
+ undefined,
86
+ encoding,
87
+ etag,
88
+ lastModified,
89
+ age,
90
+ cacheControl,
91
+ acceptRanges,
92
+ supportedQueryTypes,
93
+ meta)
94
+
95
+ return
96
+ }
97
+
98
+ // single range, send as regular object
99
+ const obj = Array.isArray(objs) ? objs[0] : objs
100
+ send_bytes(stream, HTTP_STATUS_PARTIAL_CONTENT, contentType, obj.obj, obj.range, undefined, encoding, etag, lastModified, age, cacheControl, acceptRanges, supportedQueryTypes, meta)
101
+ }
@@ -5,11 +5,11 @@ import {
5
5
  HTTP_METHOD_QUERY,
6
6
  HTTP2_HEADER_ACCESS_CONTROL_MAX_AGE,
7
7
  PREFLIGHT_AGE_SECONDS
8
- } from './defs.js'
9
- import { send } from './send-util.js'
8
+ } from '../../defs.js'
9
+ import { send } from '../send-util.js'
10
10
 
11
11
  /** @import { ServerHttp2Stream } from 'node:http2' */
12
- /** @import { Metadata } from './defs.js' */
12
+ /** @import { AcceptRangeUnits, SendInfo, Metadata } from '../../defs.js' */
13
13
 
14
14
  const {
15
15
  HTTP2_HEADER_CONTENT_TYPE,
@@ -27,18 +27,37 @@ const { HTTP_STATUS_OK } = http2.constants
27
27
 
28
28
  /**
29
29
  * @param {ServerHttp2Stream} stream
30
- * @param {Array<string>} methods
30
+ * @param {Array<string>} supportedMethods
31
31
  * @param {Array<string>|undefined} supportedQueryTypes
32
- * @param {'byte'|'none'|undefined} acceptRanges
32
+ * @param {AcceptRangeUnits|undefined} acceptRanges
33
33
  * @param {Metadata} meta
34
34
  */
35
- export function sendPreflight(stream, methods, supportedQueryTypes, acceptRanges, meta) {
36
- const supportsQuery = methods.includes(HTTP_METHOD_QUERY) && supportedQueryTypes !== undefined && supportedQueryTypes.length > 0
35
+ export function sendPreflight(stream, supportedMethods, supportedQueryTypes, acceptRanges, meta) {
36
+ _sendPreflight(stream, {
37
+ supportedMethods,
38
+ supportedQueryTypes,
39
+ acceptRanges
40
+ }, meta)
41
+ }
42
+
43
+ /**
44
+ * @param {ServerHttp2Stream} stream
45
+ * @param {Pick<SendInfo, 'supportedMethods' | 'supportedQueryTypes' | 'acceptRanges'>} info
46
+ * @param {Metadata} meta
47
+ */
48
+ export function _sendPreflight(stream, info, meta) {
49
+ const {
50
+ supportedMethods,
51
+ supportedQueryTypes,
52
+ acceptRanges
53
+ } = info
54
+
55
+ const supportsQuery = supportedMethods.includes(HTTP_METHOD_QUERY) && supportedQueryTypes !== undefined && supportedQueryTypes.length > 0
37
56
  const exposedHeadersAcceptQuery = supportsQuery ? [ HTTP_HEADER_ACCEPT_QUERY ] : []
38
- const exposedHeaders = acceptRanges !== undefined ? [ HTTP2_HEADER_ACCEPT_RANGES, ...exposedHeadersAcceptQuery ] : exposedHeadersAcceptQuery
57
+ const exposedHeaders = acceptRanges === undefined ? exposedHeadersAcceptQuery : [ HTTP2_HEADER_ACCEPT_RANGES, ...exposedHeadersAcceptQuery ]
39
58
 
40
59
  send(stream, HTTP_STATUS_OK, {
41
- [HTTP2_HEADER_ACCESS_CONTROL_ALLOW_METHODS]: methods.join(','),
60
+ [HTTP2_HEADER_ACCESS_CONTROL_ALLOW_METHODS]: supportedMethods.join(','),
42
61
  [HTTP2_HEADER_ACCESS_CONTROL_ALLOW_HEADERS]: [
43
62
  HTTP2_HEADER_IF_MATCH,
44
63
  HTTP2_HEADER_IF_NONE_MATCH,
@@ -49,7 +68,7 @@ export function sendPreflight(stream, methods, supportedQueryTypes, acceptRanges
49
68
  ].join(','),
50
69
  [HTTP2_HEADER_ACCESS_CONTROL_MAX_AGE]: PREFLIGHT_AGE_SECONDS,
51
70
  [HTTP2_HEADER_ACCEPT_RANGES]: acceptRanges,
52
- [HTTP_HEADER_ACCEPT_QUERY]: supportedQueryTypes?.join(',')
71
+ [HTTP_HEADER_ACCEPT_QUERY]: supportedQueryTypes?.join(',') // todo should empty array return undef
53
72
  // Access-Control-Allow-Credentials
54
73
  }, exposedHeaders, undefined, undefined, meta)
55
74
  }
@@ -6,10 +6,10 @@ import {
6
6
  SSE_INACTIVE_STATUS_CODE,
7
7
  SSE_MIME,
8
8
  } from '@johntalton/sse-util'
9
- import { coreHeaders, performanceHeaders } from './header-util.js'
9
+ import { coreHeaders, performanceHeaders } from '../header-util.js'
10
10
 
11
11
  /** @import { ServerHttp2Stream } from 'node:http2' */
12
- /** @import { Metadata, SSEOptions } from './defs.js' */
12
+ /** @import { Metadata, SSEOptions } from '../../defs.js' */
13
13
 
14
14
  const { HTTP_STATUS_OK } = http2.constants
15
15
 
@@ -1,11 +1,11 @@
1
1
  import http2 from 'node:http2'
2
2
 
3
- import { CONTENT_TYPE_MESSAGE_HTTP } from '../content-type.js'
4
- import { send } from './send-util.js'
3
+ import { CONTENT_TYPE_MESSAGE_HTTP } from '../../headers/content-type.js'
4
+ import { send } from '../send-util.js'
5
5
 
6
6
  /** @import { ServerHttp2Stream } from 'node:http2' */
7
7
  /** @import { IncomingHttpHeaders } from 'node:http2' */
8
- /** @import { Metadata } from './defs.js' */
8
+ /** @import { Metadata } from '../../defs.js' */
9
9
 
10
10
  const { HTTP_STATUS_OK } = http2.constants
11
11
 
@@ -0,0 +1,23 @@
1
+ import http2 from 'node:http2'
2
+
3
+ import { send } from '../send-util.js'
4
+
5
+ /** @import { ServerHttp2Stream } from 'node:http2' */
6
+ /** @import { Metadata } from '../../defs.js' */
7
+
8
+ const {
9
+ HTTP2_HEADER_LOCATION
10
+ } = http2.constants
11
+
12
+ const { HTTP_STATUS_FOUND } = http2.constants
13
+
14
+ /**
15
+ * @param {ServerHttp2Stream} stream
16
+ * @param {URL} location
17
+ * @param {Metadata} meta
18
+ */
19
+ export function sendFound(stream, location, meta) {
20
+ send(stream, HTTP_STATUS_FOUND, {
21
+ [HTTP2_HEADER_LOCATION]: location.href
22
+ }, [ HTTP2_HEADER_LOCATION ], undefined, undefined, meta)
23
+ }
@@ -1,9 +1,9 @@
1
1
  import http2 from 'node:http2'
2
2
 
3
- import { send } from './send-util.js'
3
+ import { send } from '../send-util.js'
4
4
 
5
5
  /** @import { ServerHttp2Stream } from 'node:http2' */
6
- /** @import { Metadata } from './defs.js' */
6
+ /** @import { Metadata } from '../../defs.js' */
7
7
 
8
8
  const {
9
9
  HTTP2_HEADER_LOCATION
@@ -1,9 +1,9 @@
1
1
  import http2 from 'node:http2'
2
2
 
3
- import { send } from './send-util.js'
3
+ import { send } from '../send-util.js'
4
4
 
5
5
  /** @import { ServerHttp2Stream } from 'node:http2' */
6
- /** @import { Metadata } from './defs.js' */
6
+ /** @import { Metadata } from '../../defs.js' */
7
7
 
8
8
  const { HTTP_STATUS_MULTIPLE_CHOICES } = http2.constants
9
9
 
@@ -12,7 +12,6 @@ const { HTTP_STATUS_MULTIPLE_CHOICES } = http2.constants
12
12
  * @param {Metadata} meta
13
13
  */
14
14
  export function sendMultipleChoices(stream, meta) {
15
- throw new Error('unsupported')
16
15
  send(stream, HTTP_STATUS_MULTIPLE_CHOICES, {
17
16
  // Alternates:
18
17
  // TCN: list
@@ -0,0 +1,59 @@
1
+ import http2 from 'node:http2'
2
+
3
+ import { CacheControl } from '../../headers/cache-control.js'
4
+ import { Conditional } from '../../headers/conditional.js'
5
+ import { send } from '../send-util.js'
6
+
7
+ /** @import { ServerHttp2Stream } from 'node:http2' */
8
+ /** @import { SendContent, Metadata } from '../../defs.js' */
9
+ /** @import { EtagItem, IMFFixDateInput } from '../../headers/conditional.js' */
10
+ /** @import { CacheControlOptions } from '../../headers/cache-control.js' */
11
+
12
+ const {
13
+ HTTP2_HEADER_AGE,
14
+ HTTP2_HEADER_ETAG,
15
+ HTTP2_HEADER_LAST_MODIFIED,
16
+ HTTP2_HEADER_VARY,
17
+ HTTP2_HEADER_CACHE_CONTROL
18
+ } = http2.constants
19
+
20
+ const { HTTP_STATUS_NOT_MODIFIED } = http2.constants
21
+
22
+ /**
23
+ * @param {ServerHttp2Stream} stream
24
+ * @param {EtagItem|undefined} etag
25
+ * @param {IMFFixDateInput|string|undefined} lastModified
26
+ * @param {number|undefined} age
27
+ * @param {CacheControlOptions} cacheControl
28
+ * @param {Metadata} meta
29
+ */
30
+ export function sendNotModified(stream, etag, lastModified, age, cacheControl, meta) {
31
+ _sendNotModified(stream, {
32
+ etag,
33
+ lastModified,
34
+ age,
35
+ cacheControl
36
+ }, meta)
37
+ }
38
+
39
+ /**
40
+ * @param {ServerHttp2Stream} stream
41
+ * @param {Pick<SendContent, 'etag' | 'lastModified' | 'age' | 'cacheControl'>} content
42
+ * @param {Metadata} meta
43
+ */
44
+ export function _sendNotModified(stream, content, meta) {
45
+ const {
46
+ etag,
47
+ lastModified,
48
+ age,
49
+ cacheControl
50
+ } = content
51
+
52
+ send(stream, HTTP_STATUS_NOT_MODIFIED, {
53
+ [HTTP2_HEADER_VARY]: 'Accept, Accept-Encoding',
54
+ [HTTP2_HEADER_CACHE_CONTROL]: CacheControl.encode(cacheControl),
55
+ [HTTP2_HEADER_ETAG]: Conditional.encodeEtag(etag),
56
+ [HTTP2_HEADER_LAST_MODIFIED]: Conditional.encodeFixDate(lastModified),
57
+ [HTTP2_HEADER_AGE]: age === undefined ? undefined : `${age}`
58
+ }, [ HTTP2_HEADER_AGE ], undefined, undefined, meta)
59
+ }
@@ -1,9 +1,9 @@
1
1
  import http2 from 'node:http2'
2
2
 
3
- import { send } from './send-util.js'
3
+ import { send } from '../send-util.js'
4
4
 
5
5
  /** @import { ServerHttp2Stream } from 'node:http2' */
6
- /** @import { Metadata } from './defs.js' */
6
+ /** @import { Metadata } from '../../defs.js' */
7
7
 
8
8
  const {
9
9
  HTTP2_HEADER_LOCATION
@@ -1,9 +1,9 @@
1
1
  import http2 from 'node:http2'
2
2
 
3
- import { send } from './send-util.js'
3
+ import { send } from '../send-util.js'
4
4
 
5
5
  /** @import { ServerHttp2Stream } from 'node:http2' */
6
- /** @import { Metadata } from './defs.js' */
6
+ /** @import { Metadata } from '../../defs.js' */
7
7
 
8
8
  const {
9
9
  HTTP2_HEADER_LOCATION
@@ -1,9 +1,9 @@
1
1
  import http2 from 'node:http2'
2
2
 
3
- import { send } from './send-util.js'
3
+ import { send } from '../send-util.js'
4
4
 
5
5
  /** @import { ServerHttp2Stream } from 'node:http2' */
6
- /** @import { Metadata } from './defs.js' */
6
+ /** @import { Metadata } from '../../defs.js' */
7
7
 
8
8
  const {
9
9
  HTTP2_HEADER_LOCATION
@@ -0,0 +1,19 @@
1
+ import http2 from 'node:http2'
2
+
3
+ import { CONTENT_TYPE_TEXT } from '../../headers/content-type.js'
4
+ import { send } from '../send-util.js'
5
+
6
+ /** @import { ServerHttp2Stream } from 'node:http2' */
7
+ /** @import { Metadata } from '../../defs.js' */
8
+
9
+ const { HTTP_STATUS_BAD_REQUEST } = http2.constants
10
+
11
+ /**
12
+ * @param {ServerHttp2Stream} stream
13
+ * @param {string} message
14
+ * @param {Metadata} meta
15
+ */
16
+ export function sendBadRequest(stream, message, meta) {
17
+ send(stream, HTTP_STATUS_BAD_REQUEST, {
18
+ }, [ ], CONTENT_TYPE_TEXT, message, meta)
19
+ }
@@ -1,9 +1,9 @@
1
1
  import http2 from 'node:http2'
2
2
 
3
- import { send } from './send-util.js'
3
+ import { send } from '../send-util.js'
4
4
 
5
5
  /** @import { ServerHttp2Stream } from 'node:http2' */
6
- /** @import { Metadata } from './defs.js' */
6
+ /** @import { Metadata } from '../../defs.js' */
7
7
 
8
8
  const { HTTP_STATUS_CONFLICT } = http2.constants
9
9
 
@@ -1,9 +1,9 @@
1
1
  import http2 from 'node:http2'
2
2
 
3
- import { send } from './send-util.js'
3
+ import { send } from '../send-util.js'
4
4
 
5
5
  /** @import { ServerHttp2Stream } from 'node:http2' */
6
- /** @import { Metadata } from './defs.js' */
6
+ /** @import { Metadata } from '../../defs.js' */
7
7
 
8
8
  const { HTTP_STATUS_PAYLOAD_TOO_LARGE } = http2.constants
9
9
 
@@ -1,8 +1,9 @@
1
1
  import http2 from 'node:http2'
2
- import { send } from './send-util.js'
2
+
3
+ import { send } from '../send-util.js'
3
4
 
4
5
  /** @import { ServerHttp2Stream } from 'node:http2' */
5
- /** @import { Metadata } from './defs.js' */
6
+ /** @import { Metadata } from '../../defs.js' */
6
7
 
7
8
  const { HTTP_STATUS_FORBIDDEN} = http2.constants
8
9
 
@@ -1,9 +1,9 @@
1
1
  import http2 from 'node:http2'
2
2
 
3
- import { send } from './send-util.js'
3
+ import { send } from '../send-util.js'
4
4
 
5
5
  /** @import { ServerHttp2Stream } from 'node:http2' */
6
- /** @import { Metadata } from './defs.js' */
6
+ /** @import { Metadata } from '../../defs.js' */
7
7
 
8
8
  const { HTTP_STATUS_GONE } = http2.constants
9
9
 
@@ -1,9 +1,9 @@
1
1
  import http2 from 'node:http2'
2
2
 
3
- import { send } from './send-util.js'
3
+ import { send } from '../send-util.js'
4
4
 
5
5
  /** @import { ServerHttp2Stream } from 'node:http2' */
6
- /** @import { Metadata } from './defs.js' */
6
+ /** @import { Metadata } from '../../defs.js' */
7
7
 
8
8
  const { HTTP_STATUS_TEAPOT } = http2.constants
9
9
 
@@ -1,10 +1,10 @@
1
1
  import http2 from 'node:http2'
2
2
 
3
- import { CONTENT_TYPE_JSON } from '../content-type.js'
4
- import { send } from './send-util.js'
3
+ import { CONTENT_TYPE_JSON } from '../../headers/content-type.js'
4
+ import { send } from '../send-util.js'
5
5
 
6
6
  /** @import { ServerHttp2Stream } from 'node:http2' */
7
- /** @import { Metadata } from './defs.js' */
7
+ /** @import { SendInfo, Metadata } from '../../defs.js' */
8
8
 
9
9
  const { HTTP_STATUS_NOT_ACCEPTABLE } = http2.constants
10
10
 
@@ -14,6 +14,17 @@ const { HTTP_STATUS_NOT_ACCEPTABLE } = http2.constants
14
14
  * @param {Metadata} meta
15
15
  */
16
16
  export function sendNotAcceptable(stream, supportedTypes, meta) {
17
+ _sendNotAcceptable(stream, { supportedTypes }, meta)
18
+ }
19
+
20
+ /**
21
+ * @param {ServerHttp2Stream} stream
22
+ * @param {Pick<SendInfo, 'supportedTypes'>} info
23
+ * @param {Metadata} meta
24
+ */
25
+ export function _sendNotAcceptable(stream, info, meta) {
26
+ const { supportedTypes } = info
27
+
17
28
  const supportedTypesList = Array.isArray(supportedTypes) ? supportedTypes : [ supportedTypes ]
18
29
  const has = supportedTypesList.length > 0
19
30
 
@@ -0,0 +1,34 @@
1
+ import http2 from 'node:http2'
2
+
3
+ import { send } from '../send-util.js'
4
+
5
+ /** @import { ServerHttp2Stream } from 'node:http2' */
6
+ /** @import { SendInfo, Metadata } from '../../defs.js' */
7
+
8
+ const {
9
+ HTTP_STATUS_METHOD_NOT_ALLOWED
10
+ } = http2.constants
11
+
12
+ const { HTTP2_HEADER_ALLOW } = http2.constants
13
+
14
+ /**
15
+ * @param {ServerHttp2Stream} stream
16
+ * @param {Array<string>} supportedMethods
17
+ * @param {Metadata} meta
18
+ */
19
+ export function sendNotAllowed(stream, supportedMethods, meta) {
20
+ _sendNotAllowed(stream, { supportedMethods }, meta)
21
+ }
22
+
23
+ /**
24
+ * @param {ServerHttp2Stream} stream
25
+ * @param {Pick<SendInfo, 'supportedMethods'>} info
26
+ * @param {Metadata} meta
27
+ */
28
+ export function _sendNotAllowed(stream, info, meta) {
29
+ const { supportedMethods } = info
30
+
31
+ send(stream, HTTP_STATUS_METHOD_NOT_ALLOWED, {
32
+ [HTTP2_HEADER_ALLOW]: supportedMethods.join(',')
33
+ }, [ HTTP2_HEADER_ALLOW ], undefined, undefined, meta)
34
+ }