Improve handling of 413 HTTP responses
This commit is contained in:
parent
8b98035cbf
commit
9791fa43ef
7 changed files with 188 additions and 78 deletions
44
ts/test-node/jobs/helpers/getHttpErrorCode_test.ts
Normal file
44
ts/test-node/jobs/helpers/getHttpErrorCode_test.ts
Normal file
|
@ -0,0 +1,44 @@
|
|||
// Copyright 2021 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import { assert } from 'chai';
|
||||
|
||||
import { getHttpErrorCode } from '../../../jobs/helpers/getHttpErrorCode';
|
||||
|
||||
describe('getHttpErrorCode', () => {
|
||||
it('returns -1 if not passed an object', () => {
|
||||
assert.strictEqual(getHttpErrorCode(undefined), -1);
|
||||
assert.strictEqual(getHttpErrorCode(null), -1);
|
||||
assert.strictEqual(getHttpErrorCode(404), -1);
|
||||
});
|
||||
|
||||
it('returns -1 if passed an object lacking a valid code', () => {
|
||||
assert.strictEqual(getHttpErrorCode({}), -1);
|
||||
assert.strictEqual(getHttpErrorCode({ code: 'garbage' }), -1);
|
||||
assert.strictEqual(
|
||||
getHttpErrorCode({ httpError: { code: 'garbage' } }),
|
||||
-1
|
||||
);
|
||||
});
|
||||
|
||||
it('returns the top-level error code if it exists', () => {
|
||||
assert.strictEqual(getHttpErrorCode({ code: 404 }), 404);
|
||||
assert.strictEqual(getHttpErrorCode({ code: '404' }), 404);
|
||||
});
|
||||
|
||||
it('returns a nested error code if available', () => {
|
||||
assert.strictEqual(getHttpErrorCode({ httpError: { code: 404 } }), 404);
|
||||
assert.strictEqual(getHttpErrorCode({ httpError: { code: '404' } }), 404);
|
||||
});
|
||||
|
||||
it('"prefers" the first valid error code it finds if there is ambiguity', () => {
|
||||
assert.strictEqual(
|
||||
getHttpErrorCode({ code: '404', httpError: { code: 999 } }),
|
||||
404
|
||||
);
|
||||
assert.strictEqual(
|
||||
getHttpErrorCode({ code: 'garbage', httpError: { code: 404 } }),
|
||||
404
|
||||
);
|
||||
});
|
||||
});
|
|
@ -6,7 +6,7 @@ import * as sinon from 'sinon';
|
|||
import { HTTPError } from '../../../textsecure/Errors';
|
||||
import * as durations from '../../../util/durations';
|
||||
|
||||
import { sleepFor413RetryAfterTimeIfApplicable } from '../../../jobs/helpers/sleepFor413RetryAfterTimeIfApplicable';
|
||||
import { sleepFor413RetryAfterTime } from '../../../jobs/helpers/sleepFor413RetryAfterTime';
|
||||
|
||||
describe('sleepFor413RetryAfterTimeIfApplicable', () => {
|
||||
const createLogger = () => ({ info: sinon.spy() });
|
||||
|
@ -23,39 +23,28 @@ describe('sleepFor413RetryAfterTimeIfApplicable', () => {
|
|||
sandbox.restore();
|
||||
});
|
||||
|
||||
it('does nothing if not passed a 413 HTTP error', async () => {
|
||||
it('does nothing if no time remains', async () => {
|
||||
const log = createLogger();
|
||||
|
||||
const errors = [
|
||||
undefined,
|
||||
new Error('Normal error'),
|
||||
new HTTPError('Uh oh', { code: 422, headers: {}, response: {} }),
|
||||
];
|
||||
await Promise.all(
|
||||
errors.map(async err => {
|
||||
await sleepFor413RetryAfterTimeIfApplicable({
|
||||
err,
|
||||
[-1, 0].map(timeRemaining =>
|
||||
sleepFor413RetryAfterTime({
|
||||
err: {},
|
||||
log,
|
||||
timeRemaining: 1234,
|
||||
});
|
||||
})
|
||||
timeRemaining,
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
sinon.assert.notCalled(log.info);
|
||||
});
|
||||
|
||||
it('waits for 1 second if receiving a 413 HTTP error without a Retry-After header', async () => {
|
||||
const err = new HTTPError('Slow down', {
|
||||
code: 413,
|
||||
headers: {},
|
||||
response: {},
|
||||
});
|
||||
|
||||
it('waits for 1 second if the error lacks Retry-After info', async () => {
|
||||
let done = false;
|
||||
|
||||
(async () => {
|
||||
await sleepFor413RetryAfterTimeIfApplicable({
|
||||
err,
|
||||
await sleepFor413RetryAfterTime({
|
||||
err: {},
|
||||
log: createLogger(),
|
||||
timeRemaining: 1234,
|
||||
});
|
||||
|
@ -69,7 +58,7 @@ describe('sleepFor413RetryAfterTimeIfApplicable', () => {
|
|||
assert.isTrue(done);
|
||||
});
|
||||
|
||||
it('waits for Retry-After seconds if receiving a 413', async () => {
|
||||
it('finds the Retry-After header on an HTTPError', async () => {
|
||||
const err = new HTTPError('Slow down', {
|
||||
code: 413,
|
||||
headers: { 'retry-after': '200' },
|
||||
|
@ -79,7 +68,7 @@ describe('sleepFor413RetryAfterTimeIfApplicable', () => {
|
|||
let done = false;
|
||||
|
||||
(async () => {
|
||||
await sleepFor413RetryAfterTimeIfApplicable({
|
||||
await sleepFor413RetryAfterTime({
|
||||
err,
|
||||
log: createLogger(),
|
||||
timeRemaining: 123456789,
|
||||
|
@ -94,6 +83,31 @@ describe('sleepFor413RetryAfterTimeIfApplicable', () => {
|
|||
assert.isTrue(done);
|
||||
});
|
||||
|
||||
it('finds the Retry-After on an HTTPError nested under a wrapper error', async () => {
|
||||
const httpError = new HTTPError('Slow down', {
|
||||
code: 413,
|
||||
headers: { 'retry-after': '200' },
|
||||
response: {},
|
||||
});
|
||||
|
||||
let done = false;
|
||||
|
||||
(async () => {
|
||||
await sleepFor413RetryAfterTime({
|
||||
err: { httpError },
|
||||
log: createLogger(),
|
||||
timeRemaining: 123456789,
|
||||
});
|
||||
done = true;
|
||||
})();
|
||||
|
||||
await clock.tickAsync(199 * durations.SECOND);
|
||||
assert.isFalse(done);
|
||||
|
||||
await clock.tickAsync(2 * durations.SECOND);
|
||||
assert.isTrue(done);
|
||||
});
|
||||
|
||||
it("won't wait longer than the remaining time", async () => {
|
||||
const err = new HTTPError('Slow down', {
|
||||
code: 413,
|
||||
|
@ -104,7 +118,7 @@ describe('sleepFor413RetryAfterTimeIfApplicable', () => {
|
|||
let done = false;
|
||||
|
||||
(async () => {
|
||||
await sleepFor413RetryAfterTimeIfApplicable({
|
||||
await sleepFor413RetryAfterTime({
|
||||
err,
|
||||
log: createLogger(),
|
||||
timeRemaining: 3 * durations.SECOND,
|
||||
|
@ -124,7 +138,7 @@ describe('sleepFor413RetryAfterTimeIfApplicable', () => {
|
|||
response: {},
|
||||
});
|
||||
|
||||
sleepFor413RetryAfterTimeIfApplicable({ err, log, timeRemaining: 9999999 });
|
||||
sleepFor413RetryAfterTime({ err, log, timeRemaining: 9999999 });
|
||||
await clock.nextAsync();
|
||||
|
||||
sinon.assert.calledOnce(log.info);
|
Loading…
Add table
Add a link
Reference in a new issue