@nxtedition/nxt-undici 2.0.8 → 2.0.9
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/interceptor/redirect.js +25 -40
- package/package.json +1 -1
|
@@ -4,34 +4,16 @@ 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 }) {
|
|
7
|
+
constructor(opts, { dispatch, handler, count = 0 }) {
|
|
8
8
|
this.dispatch = dispatch
|
|
9
9
|
this.handler = handler
|
|
10
10
|
this.opts = opts
|
|
11
|
-
this.
|
|
12
|
-
this.
|
|
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
|
-
})
|
|
11
|
+
this.redirectOpts = null
|
|
12
|
+
this.count = count
|
|
27
13
|
}
|
|
28
14
|
|
|
29
15
|
onConnect(abort) {
|
|
30
|
-
|
|
31
|
-
abort(this.reason)
|
|
32
|
-
} else {
|
|
33
|
-
this.abort = abort
|
|
34
|
-
}
|
|
16
|
+
return this.handler.onConnect(abort)
|
|
35
17
|
}
|
|
36
18
|
|
|
37
19
|
onUpgrade(statusCode, headers, socket) {
|
|
@@ -55,56 +37,55 @@ class Handler {
|
|
|
55
37
|
throw new Error(`Disturbed request cannot be redirected.`)
|
|
56
38
|
}
|
|
57
39
|
|
|
58
|
-
|
|
40
|
+
const location = findHeader(headers, 'location')
|
|
59
41
|
|
|
60
|
-
if (!
|
|
42
|
+
if (!location) {
|
|
61
43
|
throw new Error(`Missing redirection location .`)
|
|
62
44
|
}
|
|
63
45
|
|
|
64
46
|
this.count += 1
|
|
65
47
|
|
|
66
48
|
if (typeof this.opts.follow === 'function') {
|
|
67
|
-
if (!this.opts.follow(
|
|
49
|
+
if (!this.opts.follow(location, this.count)) {
|
|
68
50
|
return this.handler.onHeaders(statusCode, headers, resume, statusText)
|
|
69
51
|
}
|
|
70
52
|
} else {
|
|
71
|
-
|
|
72
|
-
|
|
53
|
+
const maxCount = Number.isFinite(this.opts.follow)
|
|
54
|
+
? this.opts.follow
|
|
55
|
+
: this.opts.follow?.count ?? 0
|
|
56
|
+
if (this.count >= maxCount) {
|
|
57
|
+
throw new Error(`Max redirections reached: ${maxCount}.`)
|
|
73
58
|
}
|
|
74
59
|
}
|
|
75
60
|
|
|
76
61
|
const { origin, pathname, search } = parseURL(
|
|
77
|
-
new URL(
|
|
62
|
+
new URL(location, this.opts.origin && new URL(this.opts.path, this.opts.origin)),
|
|
78
63
|
)
|
|
79
64
|
const path = search ? `${pathname}${search}` : pathname
|
|
80
65
|
|
|
81
66
|
// Remove headers referring to the original URL.
|
|
82
67
|
// By default it is Host only, unless it's a 303 (see below), which removes also all Content-* headers.
|
|
83
68
|
// https://tools.ietf.org/html/rfc7231#section-6.4
|
|
84
|
-
this.
|
|
69
|
+
this.redirectOpts = {
|
|
85
70
|
...this.opts,
|
|
86
71
|
headers: cleanRequestHeaders(
|
|
87
72
|
this.opts.headers,
|
|
88
73
|
statusCode === 303,
|
|
89
74
|
this.opts.origin !== origin,
|
|
90
75
|
),
|
|
91
|
-
follow: {
|
|
92
|
-
...this.opts.follow,
|
|
93
|
-
count: this.maxCount - 1,
|
|
94
|
-
},
|
|
95
76
|
path,
|
|
96
77
|
origin,
|
|
97
78
|
}
|
|
98
79
|
|
|
99
80
|
// https://tools.ietf.org/html/rfc7231#section-6.4.4
|
|
100
81
|
// In case of HTTP 303, always replace method to be either HEAD or GET
|
|
101
|
-
if (statusCode === 303 && this.
|
|
102
|
-
this.
|
|
82
|
+
if (statusCode === 303 && this.redirectOpts.method !== 'HEAD') {
|
|
83
|
+
this.redirectOpts = { ...this.redirectOpts, method: 'GET', body: null }
|
|
103
84
|
}
|
|
104
85
|
}
|
|
105
86
|
|
|
106
87
|
onData(chunk) {
|
|
107
|
-
if (this.
|
|
88
|
+
if (this.redirectOpts) {
|
|
108
89
|
/*
|
|
109
90
|
https://tools.ietf.org/html/rfc7231#section-6.4
|
|
110
91
|
|
|
@@ -128,7 +109,7 @@ class Handler {
|
|
|
128
109
|
}
|
|
129
110
|
|
|
130
111
|
onComplete(trailers) {
|
|
131
|
-
if (this.
|
|
112
|
+
if (this.redirectOpts) {
|
|
132
113
|
/*
|
|
133
114
|
https://tools.ietf.org/html/rfc7231#section-6.4
|
|
134
115
|
|
|
@@ -138,8 +119,12 @@ class Handler {
|
|
|
138
119
|
See comment on onData method above for more detailed informations.
|
|
139
120
|
*/
|
|
140
121
|
this.dispatch(
|
|
141
|
-
this.
|
|
142
|
-
new Handler(this.
|
|
122
|
+
this.redirectOpts,
|
|
123
|
+
new Handler(this.redirectOpts, {
|
|
124
|
+
handler: this.handler,
|
|
125
|
+
dispatch: this.dispatch,
|
|
126
|
+
count: this.count,
|
|
127
|
+
}),
|
|
143
128
|
)
|
|
144
129
|
} else {
|
|
145
130
|
return this.handler.onComplete(trailers)
|
|
@@ -181,5 +166,5 @@ function cleanRequestHeaders(headers, removeContent, unknownOrigin) {
|
|
|
181
166
|
|
|
182
167
|
export default (dispatch) => (opts, handler) =>
|
|
183
168
|
opts.follow != null
|
|
184
|
-
? dispatch(opts, new Handler(opts, { handler, dispatch }))
|
|
169
|
+
? dispatch(opts, new Handler(opts, { handler, dispatch, count: 0 }))
|
|
185
170
|
: dispatch(opts, handler)
|