@nxtedition/nxt-undici 2.0.31 → 2.0.33

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/lib/index.js CHANGED
@@ -185,12 +185,10 @@ export async function request(url, opts) {
185
185
  if (statusCode !== 101) {
186
186
  this.abort(createError(statusCode, { headers }))
187
187
  } else {
188
- this.resolve?.({ headers, socket })
188
+ this.resolve({ headers, socket })
189
189
  this.resolve = null
190
190
  }
191
191
  },
192
- onBodySent(chunk) {},
193
- onRequestSent() {},
194
192
  onHeaders(
195
193
  statusCode,
196
194
  rawHeaders,
@@ -214,7 +212,7 @@ export async function request(url, opts) {
214
212
  size: Number.isFinite(contentLength) ? contentLength : null,
215
213
  })
216
214
 
217
- this.resolve?.(this.body)
215
+ this.resolve(this.body)
218
216
  this.resolve = null
219
217
  this.reject = null
220
218
 
@@ -18,14 +18,6 @@ class CacheHandler {
18
18
  return this.handler.onUpgrade(statusCode, rawHeaders, socket, headers)
19
19
  }
20
20
 
21
- onBodySent(chunk) {
22
- return this.handler.onBodySent(chunk)
23
- }
24
-
25
- onRequestSent() {
26
- return this.handler.onRequestSent()
27
- }
28
-
29
21
  onHeaders(statusCode, rawHeaders, resume, statusMessage, headers) {
30
22
  // NOTE: Only cache 307 respones for now...
31
23
  if (statusCode !== 307) {
@@ -13,8 +13,6 @@ class Handler {
13
13
  start: -1,
14
14
  end: -1,
15
15
  headers: -1,
16
- firstBodySent: -1,
17
- lastBodySent: -1,
18
16
  firstBodyReceived: -1,
19
17
  lastBodyReceived: -1,
20
18
  }
@@ -40,20 +38,6 @@ class Handler {
40
38
  return this.handler.onUpgrade(statusCode, rawHeaders, socket, headers)
41
39
  }
42
40
 
43
- onBodySent(chunk) {
44
- if (this.stats.firstBodySent === -1) {
45
- this.stats.firstBodySent = performance.now() - this.stats.start
46
- }
47
-
48
- return this.handler.onBodySent(chunk)
49
- }
50
-
51
- onRequestSent() {
52
- this.stats.lastBodySent = performance.now() - this.stats.start
53
-
54
- return this.handler.onRequestSent()
55
- }
56
-
57
41
  onHeaders(statusCode, rawHeaders, resume, statusMessage, headers = parseHeaders(rawHeaders)) {
58
42
  this.stats.headers = performance.now() - this.stats.start
59
43
 
@@ -31,14 +31,6 @@ class Handler {
31
31
  )
32
32
  }
33
33
 
34
- onBodySent(chunk) {
35
- return this.handler.onBodySent(chunk)
36
- }
37
-
38
- onRequestSent() {
39
- return this.handler.onRequestSent()
40
- }
41
-
42
34
  onHeaders(statusCode, rawHeaders, resume, statusMessage) {
43
35
  return this.handler.onHeaders(
44
36
  statusCode,
@@ -13,6 +13,8 @@ class Handler {
13
13
  this.reason = null
14
14
  this.maxCount = Number.isFinite(opts.follow) ? opts.follow : opts.follow?.count ?? 0
15
15
 
16
+ this.headersSent = false
17
+
16
18
  this.count = 0
17
19
  this.location = null
18
20
 
@@ -38,16 +40,10 @@ class Handler {
38
40
  return this.handler.onUpgrade(statusCode, rawHeaders, socket, headers)
39
41
  }
40
42
 
41
- onBodySent(chunk) {
42
- return this.handler.onBodySent(chunk)
43
- }
44
-
45
- onRequestSent() {
46
- return this.handler.onRequestSent()
47
- }
48
-
49
43
  onHeaders(statusCode, rawHeaders, resume, statusText, headers) {
50
44
  if (redirectableStatusCodes.indexOf(statusCode) === -1) {
45
+ assert(!this.headersSent)
46
+ this.headersSent = true
51
47
  return this.handler.onHeaders(statusCode, rawHeaders, resume, statusText, headers)
52
48
  }
53
49
 
@@ -65,6 +61,8 @@ class Handler {
65
61
 
66
62
  if (typeof this.opts.follow === 'function') {
67
63
  if (!this.opts.follow(this.location, this.count)) {
64
+ assert(!this.headersSent)
65
+ this.headersSent = true
68
66
  return this.handler.onHeaders(statusCode, rawHeaders, resume, statusText, headers)
69
67
  }
70
68
  } else {
@@ -1,71 +1,53 @@
1
1
  import crypto from 'node:crypto'
2
- import { findHeader } from '../utils.js'
3
-
4
- class Handler {
5
- constructor(opts, { handler, md5, length }) {
6
- this.handler = handler
7
- this.md5 = opts.md5 ? md5 : null
8
- this.length = length
9
- this.hasher = this.md5 ? crypto.createHash('md5') : null
10
- this.pos = 0
11
- this.abort = null
12
- }
13
-
14
- onConnect(abort) {
15
- this.abort = abort
16
-
17
- return this.handler.onConnect(abort)
18
- }
19
-
20
- onUpgrade(statusCode, rawHeaders, socket, headers) {
21
- return this.handler.onUpgrade(statusCode, rawHeaders, socket, headers)
22
- }
23
-
24
- onBodySent(chunk) {
25
- this.pos += chunk.length
26
- this.hasher?.update(chunk)
27
-
28
- return this.handler.onBodySent(chunk)
29
- }
30
-
31
- onRequestSent() {
32
- const hash = this.hasher?.digest('base64') ?? null
33
-
34
- if (this.length != null && this.pos !== Number(this.length)) {
35
- this.abort(
36
- Object.assign(new Error('Request Content-Length mismatch'), {
37
- expected: Number(this.length),
38
- actual: this.pos,
39
- }),
40
- )
41
- }
42
-
43
- if (this.md5 != null && hash !== this.md5) {
44
- this.abort(
45
- Object.assign(new Error('Request Content-MD5 mismatch'), {
46
- expected: this.md5,
47
- actual: hash,
48
- }),
49
- )
50
- }
51
-
52
- return this.handler.onRequestSent()
53
- }
54
-
55
- onHeaders(statusCode, rawHeaders, resume, statusMessage, headers) {
56
- return this.handler.onHeaders(statusCode, rawHeaders, resume, statusMessage, headers)
57
- }
58
-
59
- onData(chunk) {
60
- return this.handler.onData(chunk)
61
- }
62
-
63
- onComplete(rawTrailers) {
64
- return this.handler.onComplete(rawTrailers)
65
- }
66
-
67
- onError(err) {
68
- return this.handler.onError(err)
2
+ import { Transform, pipeline, Readable } from 'node:stream'
3
+ import { findHeader, isBuffer, isStream } from '../utils.js'
4
+
5
+ function getBody(body, opts) {
6
+ if (body == null) {
7
+ return getBody(Readable.from([]), opts)
8
+ } else if (typeof body === 'string') {
9
+ return getBody(Readable.from([Buffer.from(body)]), opts)
10
+ } else if (isBuffer(body)) {
11
+ return getBody(Readable.from([body]), opts)
12
+ } else if (typeof body === 'function') {
13
+ return async (...args) => getBody(await body(...args), opts)
14
+ } else if (isStream(body)) {
15
+ const hasher = opts.md5 ? crypto.createHash('md5') : null
16
+ let pos = 0
17
+ body = pipeline(
18
+ body,
19
+ new Transform({
20
+ transform(chunk, encoding, callback) {
21
+ pos += chunk.length
22
+ this.push(chunk)
23
+ hasher?.update(chunk, encoding)
24
+ callback()
25
+ },
26
+ flush(callback) {
27
+ const hash = hasher?.digest('base64') ?? null
28
+
29
+ if (opts.length != null && pos !== Number(opts.length)) {
30
+ callback(
31
+ Object.assign(new Error('Request Content-Length mismatch'), {
32
+ expected: Number(opts.length),
33
+ actual: pos,
34
+ }),
35
+ )
36
+ } else if (opts.md5 != null && hash !== opts.md5) {
37
+ callback(
38
+ Object.assign(new Error('Request Content-MD5 mismatch'), {
39
+ expected: opts.md5,
40
+ actual: hash,
41
+ }),
42
+ )
43
+ } else {
44
+ callback(null)
45
+ }
46
+ },
47
+ }),
48
+ )
49
+ } else {
50
+ return body
69
51
  }
70
52
  }
71
53
 
@@ -74,11 +56,10 @@ export default (dispatch) => (opts, handler) => {
74
56
  return dispatch(opts, handler)
75
57
  }
76
58
 
77
- // TODO (fix): case-insensitive check?
78
- const md5 = findHeader(opts.headers, 'content-md5')
59
+ const md5 = opts.md5 ? findHeader(opts.headers, 'content-md5') : null
79
60
  const length = findHeader(opts.headers, 'content-length')
80
61
 
81
- return md5 != null || length != null
82
- ? dispatch(opts, new Handler(opts, { handler, md5, length }))
62
+ return md5 || length
63
+ ? dispatch({ ...opts, body: getBody(opts.body, { md5, length }) }, handler)
83
64
  : dispatch(opts, handler)
84
65
  }
@@ -19,14 +19,6 @@ class Handler {
19
19
  return this.handler.onUpgrade(statusCode, rawHeaders, socket, headers)
20
20
  }
21
21
 
22
- onBodySent(chunk) {
23
- return this.handler.onBodySent(chunk)
24
- }
25
-
26
- onRequestSent() {
27
- return this.handler.onRequestSent()
28
- }
29
-
30
22
  onHeaders(statusCode, rawHeaders, resume, statusMessage, headers) {
31
23
  this.md5 = this.opts.md5 ? findHeader(rawHeaders, 'content-md5') : null
32
24
  this.length = findHeader(rawHeaders, 'content-length')
@@ -19,14 +19,6 @@ class Handler {
19
19
  return this.handler.onUpgrade(statusCode, rawHeaders, socket, headers)
20
20
  }
21
21
 
22
- onBodySent(chunk) {
23
- return this.handler.onBodySent(chunk)
24
- }
25
-
26
- onRequestSent() {
27
- return this.handler.onRequestSent()
28
- }
29
-
30
22
  onHeaders(statusCode, rawHeaders, resume, statusMessage, headers = parseHeaders(rawHeaders)) {
31
23
  if (statusCode >= 400) {
32
24
  this.statusCode = statusCode
@@ -13,6 +13,8 @@ class Handler {
13
13
  this.error = null
14
14
  this.etag = null
15
15
 
16
+ this.headersSent = false
17
+
16
18
  this.reason = null
17
19
  this.aborted = false
18
20
 
@@ -38,14 +40,6 @@ class Handler {
38
40
  return this.handler.onUpgrade(statusCode, rawHeaders, socket, headers)
39
41
  }
40
42
 
41
- onBodySent(chunk) {
42
- return this.handler.onBodySent(chunk)
43
- }
44
-
45
- onRequestSent() {
46
- return this.handler.onRequestSent()
47
- }
48
-
49
43
  onHeaders(statusCode, rawHeaders, resume, statusMessage, headers) {
50
44
  const etag = findHeader(rawHeaders, 'etag')
51
45
 
@@ -80,6 +74,8 @@ class Handler {
80
74
  if (statusCode === 206) {
81
75
  const contentRange = parseContentRange(findHeader(rawHeaders, 'content-range'))
82
76
  if (!contentRange) {
77
+ assert(!this.headersSent)
78
+ this.headersSent = true
83
79
  return this.handler.onHeaders(
84
80
  statusCode,
85
81
  rawHeaders,
@@ -107,6 +103,8 @@ class Handler {
107
103
  this.etag = etag
108
104
  this.resume = resume
109
105
 
106
+ assert(!this.headersSent)
107
+ this.headersSent = true
110
108
  return this.handler.onHeaders(
111
109
  statusCode,
112
110
  rawHeaders,
@@ -1,3 +1,4 @@
1
+ import assert from 'node:assert'
1
2
  import { isDisturbed, retry as retryFn } from '../utils.js'
2
3
 
3
4
  class Handler {
@@ -6,12 +7,18 @@ class Handler {
6
7
  this.handler = handler
7
8
  this.opts = opts
8
9
 
9
- this.hasBody = false
10
+ this.headersSent = false
10
11
  this.count = 0
11
12
 
12
13
  this.reason = null
13
14
  this.aborted = false
14
15
 
16
+ this.statusCode = null
17
+ this.rawHeaders = null
18
+ this.resume = null
19
+ this.statusMessage = null
20
+ this.headers = null
21
+
15
22
  this.handler.onConnect((reason) => {
16
23
  this.aborted = true
17
24
  if (this.abort) {
@@ -34,29 +41,34 @@ class Handler {
34
41
  return this.handler.onUpgrade(statusCode, rawHeaders, socket, headers)
35
42
  }
36
43
 
37
- onBodySent(chunk) {
38
- return this.handler.onBodySent(chunk)
39
- }
40
-
41
- onRequestSent() {
42
- return this.handler.onRequestSent()
43
- }
44
-
45
44
  onHeaders(statusCode, rawHeaders, resume, statusMessage, headers) {
46
- return this.handler.onHeaders(statusCode, rawHeaders, resume, statusMessage, headers)
45
+ this.statusCode = statusCode
46
+ this.rawHeaders = rawHeaders
47
+ this.resume = resume
48
+ this.statusMessage = statusMessage
49
+ this.headers = headers
50
+
51
+ return true
47
52
  }
48
53
 
49
54
  onData(chunk) {
50
- this.hasBody = true
55
+ if (!this.headersSent) {
56
+ this.sendHeaders()
57
+ }
58
+
51
59
  return this.handler.onData(chunk)
52
60
  }
53
61
 
54
62
  onComplete(rawTrailers) {
63
+ if (!this.headersSent) {
64
+ this.sendHeaders()
65
+ }
66
+
55
67
  return this.handler.onComplete(rawTrailers)
56
68
  }
57
69
 
58
70
  onError(err) {
59
- if (this.aborted || this.hasBody || isDisturbed(this.opts.body)) {
71
+ if (this.aborted || this.headersSent || isDisturbed(this.opts.body)) {
60
72
  return this.handler.onError(err)
61
73
  }
62
74
 
@@ -79,6 +91,25 @@ class Handler {
79
91
  }
80
92
  })
81
93
  }
94
+
95
+ sendHeaders() {
96
+ assert(!this.headersSent)
97
+
98
+ this.headersSent = true
99
+ this.handler.onHeaders(
100
+ this.statusCode,
101
+ this.rawHeaders,
102
+ this.resume,
103
+ this.statusMessage,
104
+ this.headers,
105
+ )
106
+
107
+ this.statusCode = null
108
+ this.rawHeaders = null
109
+ this.resume = null
110
+ this.statusMessage = null
111
+ this.headers = null
112
+ }
82
113
  }
83
114
 
84
115
  export default (dispatch) => (opts, handler) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxtedition/nxt-undici",
3
- "version": "2.0.31",
3
+ "version": "2.0.33",
4
4
  "license": "MIT",
5
5
  "author": "Robert Nagy <robert.nagy@boffins.se>",
6
6
  "main": "lib/index.js",