Skip to content
Open
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
24 changes: 12 additions & 12 deletions lib/handler/retry-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -293,18 +293,6 @@ class RetryHandler {
this.statusCode = statusCode
this.headers = headers

if (statusCode >= 300) {
const err = new RequestRetryError('Request failed', statusCode, {
headers,
data: {
count: this.retryCount
}
})

this.onResponseStartWithRetry(controller, statusCode, headers, statusMessage, err)
return
}

// Checkpoint for resume from where we left it
if (this.headersSent) {
// Only Partial Content 206 supposed to provide Content-Range,
Expand Down Expand Up @@ -347,6 +335,18 @@ class RetryHandler {
return
}

if (statusCode >= 300) {
const err = new RequestRetryError('Request failed', statusCode, {
headers,
data: {
count: this.retryCount
}
})

this.onResponseStartWithRetry(controller, statusCode, headers, statusMessage, err)
return
}

if (this.end == null) {
if (statusCode === 206) {
// First time we receive 206
Expand Down
59 changes: 59 additions & 0 deletions test/retry-agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const { tspl } = require('@matteo.collina/tspl')
const { test, after } = require('node:test')
const { createServer } = require('node:http')
const { once } = require('node:events')
const { Writable } = require('node:stream')

const { RetryAgent, Client } = require('..')
test('Should retry status code', async t => {
Expand Down Expand Up @@ -65,3 +66,61 @@ test('Should retry status code', async t => {

await t.completed
})

for (const throwOnError of [true, false]) {
test(`Should reject a non-206 response when resuming a partially consumed response | throwOnError: ${throwOnError}`, async context => {
const t = tspl(context, { plan: 4 })

let requestCount = 0
const chunks = []
const server = createServer((req, res) => {
if (requestCount++ === 0) {
res.writeHead(200, { 'content-length': '12' })
res.write('AAAA')
const socket = res.socket
setTimeout(() => socket.destroy(), 50)
return
}

t.equal(req.headers.range, 'bytes=4-11')
res.writeHead(412, { 'content-length': '8' })
res.end('XXXXXXXX')
})

server.listen(0)
await once(server, 'listening')

const client = new Client(`http://localhost:${server.address().port}`)
const agent = new RetryAgent(client, {
throwOnError,
maxRetries: 3,
minTimeout: 10,
maxTimeout: 10
})

context.after(async () => {
await agent.close()
server.close()
await once(server, 'close')
})

await t.rejects(agent.stream({
method: 'GET',
path: '/'
}, ({ statusCode }) => {
t.equal(statusCode, 200)
return new Writable({
write (chunk, encoding, callback) {
chunks.push(chunk)
callback()
}
})
}), {
code: 'UND_ERR_REQ_RETRY',
message: 'server does not support the range header and the payload was partially consumed'
})

t.equal(Buffer.concat(chunks).toString(), 'AAAA')
await t.completed
})
}
Loading