diff --git a/plugins/caches.js b/plugins/caches.js index d8d5500..6581883 100644 --- a/plugins/caches.js +++ b/plugins/caches.js @@ -291,6 +291,28 @@ exports.plugin = { id: SCHEMA_SCOPE_ID, cacheName: SCHEMA_CACHE_NAME }) + }, + ext: { + onPreAuth: { + method: (request, h) => { + const contentLength = request.headers['content-length']; + const expectHeader = request.headers.expect; + + if (expectHeader && expectHeader.toLowerCase() === '100-continue') { + if (contentLength && parseInt(contentLength, 10) > options.maxByteSize) { + request.log( + 'Payload content length greater than maximum allowed', + options.maxByteSize + ); + throw boom.entityTooLarge(); + } + + request.raw.res.writeContinue(); + } + + return h.continue; + } + } } } }, diff --git a/test/plugins/caches.test.js b/test/plugins/caches.test.js index 9f249bd..9cf631b 100644 --- a/test/plugins/caches.test.js +++ b/test/plugins/caches.test.js @@ -847,7 +847,7 @@ describe('caches plugin test using s3', () => { plugin, options: { expiresInSec: '100', - maxByteSize: '5368709120' + maxByteSize: 10 * 1024 * 1024 } }) .then(() => server.start()); @@ -931,6 +931,7 @@ describe('caches plugin test using s3', () => { headers: { 'x-foo': 'bar', 'content-type': 'text/plain', + expect: '100-continue', ignore: 'true' }, auth: { @@ -978,6 +979,23 @@ describe('caches plugin test using s3', () => { assert.equal(putResponse.statusCode, 503); }); + + it('returns 100 Continue if Expect header is set and payload size is within limit', async () => { + options.url = `/caches/events/${mockEventID}/foo`; + + const putResponse = await server.inject(options); + + assert.equal(putResponse.statusCode, 202); + }); + + it('returns 413 if Expect header is set and payload size exceeds limit', async () => { + options.url = `/caches/events/${mockEventID}/foo`; + options.payload = 'A'.repeat(1024 * 1024 * 11); + + const putResponse = await server.inject(options); + + assert.equal(putResponse.statusCode, 413); + }); }); describe('DELETE /caches/:scope/:id', () => {