@nxtedition/nxt-undici 2.0.14 → 2.0.15

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.
@@ -4,16 +4,34 @@ import { findHeader, isDisturbed, parseURL } from '../utils.js'
4
4
  const redirectableStatusCodes = [300, 301, 302, 303, 307, 308]
5
5
 
6
6
  class Handler {
7
- constructor(opts, { dispatch, handler, count = 0 }) {
7
+ constructor(opts, { dispatch, handler }) {
8
8
  this.dispatch = dispatch
9
9
  this.handler = handler
10
10
  this.opts = opts
11
- this.redirectOpts = null
12
- this.count = count
11
+ this.abort = null
12
+ this.aborted = false
13
+ this.reason = null
14
+ this.maxCount = Number.isFinite(opts.follow) ? opts.follow : opts.follow?.count ?? 0
15
+
16
+ this.count = 0
17
+ this.location = null
18
+
19
+ this.handler.onConnect((reason) => {
20
+ this.aborted = true
21
+ if (this.abort) {
22
+ this.abort(reason)
23
+ } else {
24
+ this.reason = reason
25
+ }
26
+ })
13
27
  }
14
28
 
15
29
  onConnect(abort) {
16
- return this.handler.onConnect(abort)
30
+ if (this.aborted) {
31
+ abort(this.reason)
32
+ } else {
33
+ this.abort = abort
34
+ }
17
35
  }
18
36
 
19
37
  onUpgrade(statusCode, headers, socket) {
@@ -33,42 +51,37 @@ class Handler {
33
51
  return this.handler.onHeaders(statusCode, headers, resume, statusText)
34
52
  }
35
53
 
36
- const location = findHeader(headers, 'location')
54
+ if (isDisturbed(this.opts.body)) {
55
+ throw new Error(`Disturbed request cannot be redirected.`)
56
+ }
57
+
58
+ this.location = findHeader(headers, 'location')
37
59
 
38
- if (!location) {
39
- // TODO (perf): Consume body?
60
+ if (!this.location) {
40
61
  throw new Error(`Missing redirection location .`)
41
62
  }
42
63
 
43
64
  this.count += 1
44
65
 
45
- // TODO (feat): follow as function...
46
-
47
- const maxCount = Number.isFinite(this.opts.follow)
48
- ? this.opts.follow
49
- : Number.isFinite(this.opts.follow?.count)
50
- ? this.opts.follow?.count
51
- : 0
52
-
53
- if (this.count >= maxCount) {
54
- // TODO (perf): Consume body?
55
- throw new Error(`Max redirections reached: ${maxCount}.`)
56
- }
57
-
58
- if (isDisturbed(this.opts.body)) {
59
- // TODO (perf): Consume body?
60
- throw new Error(`Disturbed request cannot be redirected.`)
66
+ if (typeof this.opts.follow === 'function') {
67
+ if (!this.opts.follow(this.location, this.count)) {
68
+ return this.handler.onHeaders(statusCode, headers, resume, statusText)
69
+ }
70
+ } else {
71
+ if (this.count >= this.maxCount) {
72
+ throw new Error(`Max redirections reached: ${this.maxCount}.`)
73
+ }
61
74
  }
62
75
 
63
76
  const { origin, pathname, search } = parseURL(
64
- new URL(location, this.opts.origin && new URL(this.opts.path, this.opts.origin)),
77
+ new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin)),
65
78
  )
66
79
  const path = search ? `${pathname}${search}` : pathname
67
80
 
68
81
  // Remove headers referring to the original URL.
69
82
  // By default it is Host only, unless it's a 303 (see below), which removes also all Content-* headers.
70
83
  // https://tools.ietf.org/html/rfc7231#section-6.4
71
- this.redirectOpts = {
84
+ this.opts = {
72
85
  ...this.opts,
73
86
  headers: cleanRequestHeaders(
74
87
  this.opts.headers,
@@ -77,17 +90,18 @@ class Handler {
77
90
  ),
78
91
  path,
79
92
  origin,
93
+ query: null,
80
94
  }
81
95
 
82
96
  // https://tools.ietf.org/html/rfc7231#section-6.4.4
83
97
  // In case of HTTP 303, always replace method to be either HEAD or GET
84
- if (statusCode === 303 && this.redirectOpts.method !== 'HEAD') {
85
- this.redirectOpts = { ...this.redirectOpts, method: 'GET', body: null }
98
+ if (statusCode === 303 && this.opts.method !== 'HEAD') {
99
+ this.opts = { ...this.opts, method: 'GET', body: null }
86
100
  }
87
101
  }
88
102
 
89
103
  onData(chunk) {
90
- if (this.redirectOpts) {
104
+ if (this.location) {
91
105
  /*
92
106
  https://tools.ietf.org/html/rfc7231#section-6.4
93
107
 
@@ -111,7 +125,7 @@ class Handler {
111
125
  }
112
126
 
113
127
  onComplete(trailers) {
114
- if (this.redirectOpts) {
128
+ if (this.location) {
115
129
  /*
116
130
  https://tools.ietf.org/html/rfc7231#section-6.4
117
131
 
@@ -120,15 +134,10 @@ class Handler {
120
134
 
121
135
  See comment on onData method above for more detailed informations.
122
136
  */
123
- this.dispatch(
124
- this.redirectOpts,
125
- new Handler(this.redirectOpts, {
126
- handler: this.handler,
127
- dispatch: this.dispatch,
128
- count: this.count,
129
- }),
130
- )
131
- this.handler = null
137
+
138
+ this.location = null
139
+
140
+ this.dispatch(this.opts, this)
132
141
  } else {
133
142
  return this.handler.onComplete(trailers)
134
143
  }
@@ -169,5 +178,5 @@ function cleanRequestHeaders(headers, removeContent, unknownOrigin) {
169
178
 
170
179
  export default (dispatch) => (opts, handler) =>
171
180
  opts.follow != null
172
- ? dispatch(opts, new Handler(opts, { handler, dispatch, count: 0 }))
181
+ ? dispatch(opts, new Handler(opts, { handler, dispatch }))
173
182
  : dispatch(opts, handler)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxtedition/nxt-undici",
3
- "version": "2.0.14",
3
+ "version": "2.0.15",
4
4
  "license": "MIT",
5
5
  "author": "Robert Nagy <robert.nagy@boffins.se>",
6
6
  "main": "lib/index.js",