Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions docs/docs/api/Errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,19 @@ The maximum number of allowed origins has been reached.
* `name` {string} Always `'MaxOriginsReachedError'`.
* `code` {string} Always `'UND_ERR_MAX_ORIGINS_REACHED'`.

## Class: `MaxRedirectsError`

<!-- YAML
added: v8.12.0
-->

* Extends: {UndiciError}

The maximum number of redirects has been reached.

* `name` {string} Always `'MaxRedirectsError'`.
* `code` {string} Always `'UND_ERR_REDIRECT_MAX'`.

## Class: `Socks5ProxyError`

<!-- YAML
Expand Down
19 changes: 19 additions & 0 deletions lib/core/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,24 @@ class ProxyConnectionError extends UndiciError {
}
}

const kMaxRedirectsError = Symbol.for('undici.error.UND_ERR_REDIRECT_MAX')
class MaxRedirectsError extends UndiciError {
constructor (message) {
super(message)
this.name = 'MaxRedirectsError'
this.message = message || 'max redirects'
this.code = 'UND_ERR_REDIRECT_MAX'
}

static [Symbol.hasInstance] (instance) {
return instance && instance[kMaxRedirectsError] === true
}

get [kMaxRedirectsError] () {
return true
}
}

const kMaxOriginsReachedError = Symbol.for('undici.error.UND_ERR_MAX_ORIGINS_REACHED')
class MaxOriginsReachedError extends UndiciError {
constructor (message) {
Expand Down Expand Up @@ -492,6 +510,7 @@ module.exports = {
SecureProxyConnectionError,
ProxyConnectionError,
MaxOriginsReachedError,
MaxRedirectsError,
Socks5ProxyError,
MessageSizeExceededError
}
4 changes: 2 additions & 2 deletions lib/handler/redirect-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

const util = require('../core/util')
const assert = require('node:assert')
const { InvalidArgumentError } = require('../core/errors')
const { InvalidArgumentError, MaxRedirectsError } = require('../core/errors')
const { kRequestOrigin } = require('../core/symbols')

const redirectableStatusCodes = [300, 301, 302, 303, 307, 308]
Expand Down Expand Up @@ -96,7 +96,7 @@ class RedirectHandler {
// 3xx without a Location header, is delivered as usual.
if (this.location && this.history.length >= this.maxRedirections) {
if (this.opts.throwOnMaxRedirect) {
throw new Error('max redirects')
throw new MaxRedirectsError()
}
this.location = null
}
Expand Down
5 changes: 3 additions & 2 deletions test/interceptors/redirect.js
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ for (const factory of [
})

test('should throw when max redirections is reached and throwOnMaxRedirect is set as interceptor default', async t => {
t = tspl(t, { plan: 1 })
t = tspl(t, { plan: 2 })

const server = await startRedirectingServer()

Expand All @@ -481,6 +481,7 @@ for (const factory of [
t.fail('Did not throw')
} catch (error) {
t.strictEqual(error.message, 'max redirects')
t.strictEqual(error.code, 'UND_ERR_REDIRECT_MAX')
}

await t.completed
Expand Down Expand Up @@ -521,7 +522,7 @@ for (const factory of [

await t.assert.rejects(
undici.request(`${origin}/3`, { dispatcher }),
{ message: 'max redirects' }
{ message: 'max redirects', code: 'UND_ERR_REDIRECT_MAX' }
)
})
}
Expand Down
3 changes: 2 additions & 1 deletion test/redirect-request.js
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,7 @@ for (const factory of [
})

test('should throw when max redirections is reached and throwOnMaxRedirect is enabled', async t => {
t = tspl(t, { plan: 1 })
t = tspl(t, { plan: 2 })

const server = await startRedirectingServer()

Expand All @@ -444,6 +444,7 @@ for (const factory of [
} else {
t.fail(`Unexpected error: ${error.message}`)
}
t.strictEqual(error.code, 'UND_ERR_REDIRECT_MAX')
}

await t.completed
Expand Down
5 changes: 5 additions & 0 deletions test/types/errors.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@ expectAssignable<errors.MaxOriginsReachedError>(new errors.MaxOriginsReachedErro
expectAssignable<'MaxOriginsReachedError'>(new errors.MaxOriginsReachedError().name)
expectAssignable<'UND_ERR_MAX_ORIGINS_REACHED'>(new errors.MaxOriginsReachedError().code)

expectAssignable<errors.UndiciError>(new errors.MaxRedirectsError())
expectAssignable<errors.MaxRedirectsError>(new errors.MaxRedirectsError())
expectAssignable<'MaxRedirectsError'>(new errors.MaxRedirectsError().name)
expectAssignable<'UND_ERR_REDIRECT_MAX'>(new errors.MaxRedirectsError().code)

{
// @ts-ignore
function f (): errors.HeadersTimeoutError | errors.ConnectTimeoutError { }
Expand Down
6 changes: 6 additions & 0 deletions types/errors.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,12 @@ declare namespace Errors {
code: 'UND_ERR_MAX_ORIGINS_REACHED'
}

/** The maximum number of redirects has been reached. */
export class MaxRedirectsError extends UndiciError {
name: 'MaxRedirectsError'
code: 'UND_ERR_REDIRECT_MAX'
}

/** SOCKS5 proxy related error. */
export class Socks5ProxyError extends UndiciError {
constructor (
Expand Down
Loading