From b1fc4925928c061234e9492f3794c0797467e123 Mon Sep 17 00:00:00 2001 From: chris48s Date: Mon, 5 Apr 2021 18:56:32 +0100 Subject: [PATCH] add setting which allows us to set a timeout on HTTP requests (#6364) Co-authored-by: repo-ranger[bot] <39074581+repo-ranger[bot]@users.noreply.github.com> --- config/custom-environment-variables.yml | 2 + config/default.yml | 2 + core/server/server.js | 7 ++-- core/server/server.spec.js | 49 +++++++++++++++++++++++++ 4 files changed, 57 insertions(+), 3 deletions(-) diff --git a/config/custom-environment-variables.yml b/config/custom-environment-variables.yml index f77bee2c13701..90efe20e7ecd0 100644 --- a/config/custom-environment-variables.yml +++ b/config/custom-environment-variables.yml @@ -61,6 +61,8 @@ public: fetchLimit: 'FETCH_LIMIT' + requestTimeoutSeconds: 'REQUEST_TIMEOUT_SECONDS' + requireCloudflare: 'REQUIRE_CLOUDFLARE' private: diff --git a/config/default.yml b/config/default.yml index bef32342581f7..b0f5f9c9472c7 100644 --- a/config/default.yml +++ b/config/default.yml @@ -33,6 +33,8 @@ public: fetchLimit: '10MB' + requestTimeoutSeconds: 120 + requireCloudflare: false private: {} diff --git a/core/server/server.js b/core/server/server.js index 9737e16ed3993..d97e6b6d2c6db 100644 --- a/core/server/server.js +++ b/core/server/server.js @@ -18,6 +18,7 @@ const { makeSend } = require('../base-service/legacy-result-sender') const { handleRequest } = require('../base-service/legacy-request-handler') const { clearRegularUpdateCache } = require('../legacy/regular-update') const { rasterRedirectUrl } = require('../badge-urls/make-badge-url') +const { nonNegativeInteger } = require('../../services/validators') const log = require('./log') const sysMonitor = require('./monitor') const PrometheusMetrics = require('./prometheus-metrics') @@ -137,12 +138,11 @@ const publicConfigSchema = Joi.object({ teamcity: defaultService, trace: Joi.boolean().required(), }).required(), - cacheHeaders: { - defaultCacheLengthSeconds: Joi.number().integer().required(), - }, + cacheHeaders: { defaultCacheLengthSeconds: nonNegativeInteger }, rateLimit: Joi.boolean().required(), handleInternalErrors: Joi.boolean().required(), fetchLimit: Joi.string().regex(/^[0-9]+(b|kb|mb|gb|tb)$/i), + requestTimeoutSeconds: nonNegativeInteger, documentRoot: Joi.string().default( path.resolve(__dirname, '..', '..', 'public') ), @@ -476,6 +476,7 @@ class Server { this.registerRedirects() this.registerServices() + camp.timeout = this.config.public.requestTimeoutSeconds * 1000 camp.listenAsConfigured() await new Promise(resolve => camp.on('listening', () => resolve())) diff --git a/core/server/server.spec.js b/core/server/server.spec.js index 644eb5ea34df3..c577911f07653 100644 --- a/core/server/server.spec.js +++ b/core/server/server.spec.js @@ -207,6 +207,55 @@ describe('The server', function () { }) }) + describe('`requestTimeoutSeconds` setting', function () { + let server + + beforeEach(async function () { + this.timeout(10000) + + // configure server to time out requests that take >2 seconds + server = await createTestServer({ public: { requestTimeoutSeconds: 2 } }) + await server.start() + + // /fast returns a 200 OK after a 1 second delay + server.camp.route(/^\/fast$/, (data, match, end, ask) => { + setTimeout(() => { + ask.res.statusCode = 200 + ask.res.end() + }, 1000) + }) + + // /slow returns a 200 OK after a 3 second delay + server.camp.route(/^\/slow$/, (data, match, end, ask) => { + setTimeout(() => { + ask.res.statusCode = 200 + ask.res.end() + }, 3000) + }) + }) + + afterEach(async function () { + if (server) { + server.stop() + } + server = undefined + }) + + it('should time out slow requests', async function () { + this.timeout(10000) + return expect(got(`${server.baseUrl}slow`)).to.be.rejectedWith( + got.RequestError + ) + }) + + it('should not time out fast requests', async function () { + this.timeout(10000) + const { statusCode, body } = await got(`${server.baseUrl}fast`) + expect(statusCode).to.be.equal(200) + expect(body).to.equal('') + }) + }) + describe('configuration', function () { let server afterEach(async function () {