@nxtedition/nxt-undici 2.0.30 → 2.0.32

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)
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,
@@ -6,7 +6,7 @@ class Handler {
6
6
  this.handler = handler
7
7
  this.opts = opts
8
8
 
9
- this.hasBody = false
9
+ this.headersSent = false
10
10
  this.count = 0
11
11
 
12
12
  this.reason = null
@@ -34,20 +34,12 @@ class Handler {
34
34
  return this.handler.onUpgrade(statusCode, rawHeaders, socket, headers)
35
35
  }
36
36
 
37
- onBodySent(chunk) {
38
- return this.handler.onBodySent(chunk)
39
- }
40
-
41
- onRequestSent() {
42
- return this.handler.onRequestSent()
43
- }
44
-
45
37
  onHeaders(statusCode, rawHeaders, resume, statusMessage, headers) {
38
+ this.headersSent = true
46
39
  return this.handler.onHeaders(statusCode, rawHeaders, resume, statusMessage, headers)
47
40
  }
48
41
 
49
42
  onData(chunk) {
50
- this.hasBody = true
51
43
  return this.handler.onData(chunk)
52
44
  }
53
45
 
@@ -56,7 +48,7 @@ class Handler {
56
48
  }
57
49
 
58
50
  onError(err) {
59
- if (this.aborted || this.hasBody || isDisturbed(this.opts.body)) {
51
+ if (this.aborted || this.headersSent || isDisturbed(this.opts.body)) {
60
52
  return this.handler.onError(err)
61
53
  }
62
54
 
package/lib/readable.js CHANGED
@@ -88,15 +88,17 @@ export class BodyReadable extends Readable {
88
88
  this[kHandler].signal = null
89
89
  }
90
90
 
91
- // Workaround for Node "bug". If the stream is destroyed in same
92
- // tick as it is created, then a user who is waiting for a
93
- // promise (i.e micro tick) for installing a 'error' listener will
94
- // never get a chance and will always encounter an unhandled exception.
95
- // - tick => process.nextTick(fn)
96
- // - micro tick => queueMicrotask(fn)
97
- queueMicrotask(() => {
91
+ if (err) {
92
+ // Workaround for Node "bug". If the stream is destroyed in same
93
+ // tick as it is created, then a user who is waiting for a
94
+ // promise (i.e micro tick) for installing a 'error' listener will
95
+ // never get a chance and will always encounter an unhandled exception.
96
+ // - tick => process.nextTick(fn)
97
+ // - micro tick => queueMicrotask(fn)
98
+ setImmediate(() => callback(err))
99
+ } else {
98
100
  callback(err)
99
- })
101
+ }
100
102
  }
101
103
 
102
104
  on(ev, ...args) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxtedition/nxt-undici",
3
- "version": "2.0.30",
3
+ "version": "2.0.32",
4
4
  "license": "MIT",
5
5
  "author": "Robert Nagy <robert.nagy@boffins.se>",
6
6
  "main": "lib/index.js",