Skip to content

Commit 5946392

Browse files
committed
refactor: port redirect handler to new hooks
1 parent 67f3c96 commit 5946392

File tree

5 files changed

+75
-65
lines changed

5 files changed

+75
-65
lines changed

lib/core/util.js

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,46 @@ function parseHeaders (headers, obj) {
436436
return obj
437437
}
438438

439+
function normalizeHeaders (headers) {
440+
const ret = {}
441+
if (headers == null) {
442+
// Do nothing...
443+
} else if (Array.isArray(headers)) {
444+
for (let i = 0; i < headers.length; i += 2) {
445+
if (Array.isArray(headers[i]) && headers[i].length === 2) {
446+
const key = headerNameToString(headers[i][0])
447+
const val = ret[key]
448+
if (val == null) {
449+
ret[key] = String(headers[i][1])
450+
} else if (typeof val === 'string') {
451+
ret[key] = [val, String(headers[i][1])]
452+
} else {
453+
val.push(String(headers[i][1]))
454+
}
455+
} else {
456+
const key = headerNameToString(headers[i])
457+
const val = ret[key]
458+
if (val == null) {
459+
ret[key] = String(headers[i][1])
460+
} else if (typeof val === 'string') {
461+
ret[key] = [val, String(headers[i + 1])]
462+
} else {
463+
val.push(String(headers[i + 1]))
464+
}
465+
}
466+
}
467+
} else if (typeof headers[Symbol.iterator] === 'function') {
468+
for (const [key, val] of headers) {
469+
ret[headerNameToString(key)] = Array.isArray(val) ? val.map(x => String(x)) : String(val)
470+
}
471+
} else {
472+
for (const [key, val] of Object.entries(headers)) {
473+
ret[headerNameToString(key)] = Array.isArray(val) ? val.map(x => String(x)) : String(val)
474+
}
475+
}
476+
return ret
477+
}
478+
439479
/**
440480
* @param {Buffer[]} headers
441481
* @returns {string[]}
@@ -903,5 +943,6 @@ module.exports = {
903943
nodeMajor,
904944
nodeMinor,
905945
safeHTTPMethods: Object.freeze(['GET', 'HEAD', 'OPTIONS', 'TRACE']),
906-
wrapRequestBody
946+
wrapRequestBody,
947+
normalizeHeaders
907948
}

lib/handler/cache-handler.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,7 @@ class CacheHandler {
3838
* @param {import('../../types/cache-interceptor.d.ts').default.CacheKey} cacheKey
3939
* @param {import('../../types/dispatcher.d.ts').default.DispatchHandler} handler
4040
*/
41-
constructor (opts, cacheKey, handler) {
42-
const { store } = opts
43-
41+
constructor ({ store }, cacheKey, handler) {
4442
this.#store = store
4543
this.#cacheKey = cacheKey
4644
this.#handler = handler

lib/handler/decorator-handler.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
const assert = require('node:assert')
44

5+
/**
6+
* @deprecated
7+
*/
58
module.exports = class DecoratorHandler {
69
#handler
710
#onCompleteCalled = false

lib/handler/redirect-handler.js

Lines changed: 28 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ class RedirectHandler {
4242

4343
this.dispatch = dispatch
4444
this.location = null
45-
this.abort = null
4645
this.opts = { ...opts, maxRedirections: 0 } // opts must be a copy
4746
this.maxRedirections = maxRedirections
4847
this.handler = handler
@@ -83,20 +82,16 @@ class RedirectHandler {
8382
}
8483
}
8584

86-
onConnect (abort) {
87-
this.abort = abort
88-
this.handler.onConnect(abort, { history: this.history })
89-
}
90-
91-
onUpgrade (statusCode, headers, socket) {
92-
this.handler.onUpgrade(statusCode, headers, socket)
85+
onRequestStart (controller, context) {
86+
this.location = null
87+
this.handler.onRequestStart?.(controller, { ...context, history: this.history })
9388
}
9489

95-
onError (error) {
96-
this.handler.onError(error)
90+
onRequestUpgrade (controller, statusCode, headers, socket) {
91+
this.handler.onRequestUpgrade?.(controller, statusCode, headers, socket)
9792
}
9893

99-
onHeaders (statusCode, rawHeaders, resume, statusText) {
94+
onResponseStart (controller, statusCode, statusMessage, headers) {
10095
if (this.opts.throwOnMaxRedirect && this.history.length >= this.maxRedirections) {
10196
throw new Error('max redirects')
10297
}
@@ -122,16 +117,17 @@ class RedirectHandler {
122117
this.opts.body = null
123118
}
124119

125-
this.location = this.history.length >= this.maxRedirections || util.isDisturbed(this.opts.body)
120+
this.location = this.history.length >= this.maxRedirections || util.isDisturbed(this.opts.body) || redirectableStatusCodes.indexOf(statusCode) === -1
126121
? null
127-
: parseLocation(statusCode, rawHeaders)
122+
: headers.location
128123

129124
if (this.opts.origin) {
130125
this.history.push(new URL(this.opts.path, this.opts.origin))
131126
}
132127

133128
if (!this.location) {
134-
return this.handler.onHeaders(statusCode, rawHeaders, resume, statusText)
129+
this.handler.onResponseStart?.(controller, statusCode, statusMessage, headers)
130+
return
135131
}
136132

137133
const { origin, pathname, search } = util.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin)))
@@ -140,14 +136,16 @@ class RedirectHandler {
140136
// Remove headers referring to the original URL.
141137
// By default it is Host only, unless it's a 303 (see below), which removes also all Content-* headers.
142138
// https://tools.ietf.org/html/rfc7231#section-6.4
143-
this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin)
139+
this.opts.headers = this.opts.headers
140+
? cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin)
141+
: this.opts.headers
144142
this.opts.path = path
145143
this.opts.origin = origin
146144
this.opts.maxRedirections = 0
147145
this.opts.query = null
148146
}
149147

150-
onData (chunk) {
148+
onResponseData (controller, chunk) {
151149
if (this.location) {
152150
/*
153151
https://tools.ietf.org/html/rfc7231#section-6.4
@@ -167,11 +165,11 @@ class RedirectHandler {
167165
servers and browsers implementors, we ignore the body as there is no specified way to eventually parse it.
168166
*/
169167
} else {
170-
return this.handler.onData(chunk)
168+
this.handler.onResponseData?.(controller, chunk)
171169
}
172170
}
173171

174-
onComplete (trailers) {
172+
onResponseEnd (controller, trailers) {
175173
if (this.location) {
176174
/*
177175
https://tools.ietf.org/html/rfc7231#section-6.4
@@ -181,68 +179,38 @@ class RedirectHandler {
181179
182180
See comment on onData method above for more detailed information.
183181
*/
184-
185-
this.location = null
186-
this.abort = null
187-
188182
this.dispatch(this.opts, this)
189183
} else {
190-
this.handler.onComplete(trailers)
184+
this.handler.onResponseEnd(controller, trailers)
191185
}
192186
}
193187

194-
onBodySent (chunk) {
195-
if (this.handler.onBodySent) {
196-
this.handler.onBodySent(chunk)
197-
}
198-
}
199-
}
200-
201-
function parseLocation (statusCode, rawHeaders) {
202-
if (redirectableStatusCodes.indexOf(statusCode) === -1) {
203-
return null
204-
}
205-
206-
for (let i = 0; i < rawHeaders.length; i += 2) {
207-
if (rawHeaders[i].length === 8 && util.headerNameToString(rawHeaders[i]) === 'location') {
208-
return rawHeaders[i + 1]
209-
}
188+
onResponseError (controller, error) {
189+
this.handler.onResponseError?.(controller, error)
210190
}
211191
}
212192

213193
// https://tools.ietf.org/html/rfc7231#section-6.4.4
214-
function shouldRemoveHeader (header, removeContent, unknownOrigin) {
215-
if (header.length === 4) {
216-
return util.headerNameToString(header) === 'host'
194+
function shouldRemoveHeader (name, removeContent, unknownOrigin) {
195+
if (name.length === 4) {
196+
return name === 'host'
217197
}
218-
if (removeContent && util.headerNameToString(header).startsWith('content-')) {
198+
if (removeContent && name.startsWith('content-')) {
219199
return true
220200
}
221-
if (unknownOrigin && (header.length === 13 || header.length === 6 || header.length === 19)) {
222-
const name = util.headerNameToString(header)
201+
if (unknownOrigin && (name.length === 13 || name.length === 6 || name.length === 19)) {
223202
return name === 'authorization' || name === 'cookie' || name === 'proxy-authorization'
224203
}
225204
return false
226205
}
227206

228207
// https://tools.ietf.org/html/rfc7231#section-6.4
229208
function cleanRequestHeaders (headers, removeContent, unknownOrigin) {
230-
const ret = []
231-
if (Array.isArray(headers)) {
232-
for (let i = 0; i < headers.length; i += 2) {
233-
if (!shouldRemoveHeader(headers[i], removeContent, unknownOrigin)) {
234-
ret.push(headers[i], headers[i + 1])
235-
}
236-
}
237-
} else if (headers && typeof headers === 'object') {
238-
const entries = typeof headers[Symbol.iterator] === 'function' ? headers : Object.entries(headers)
239-
for (const [key, value] of entries) {
240-
if (!shouldRemoveHeader(key, removeContent, unknownOrigin)) {
241-
ret.push(key, value)
242-
}
209+
const ret = util.normalizeHeaders(headers)
210+
for (const name of Object.keys(ret)) {
211+
if (shouldRemoveHeader(name, removeContent, unknownOrigin)) {
212+
delete ret[name]
243213
}
244-
} else {
245-
assert(headers == null, 'headers must be an object or an array')
246214
}
247215
return ret
248216
}

lib/handler/unwrap-handler.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ module.exports = class UnwrapHandler {
8787
}
8888

8989
onError (err) {
90-
if (!this.#handler.onError) {
90+
if (!this.#handler.onResponseError) {
9191
throw new InvalidArgumentError('invalid onError method')
9292
}
9393

0 commit comments

Comments
 (0)