diff --git a/src/core/server/http/http_server.test.ts b/src/core/server/http/http_server.test.ts index acae9d8ff0e70..f61371c5437e6 100644 --- a/src/core/server/http/http_server.test.ts +++ b/src/core/server/http/http_server.test.ts @@ -577,6 +577,45 @@ test('exposes route details of incoming request to a route handler', async () => }); }); +describe('conditional compression', () => { + test('disables compression when there is a referer', async () => { + const { registerRouter, server: innerServer } = await server.setup(config); + + const router = new Router('', logger, enhanceWithContext); + router.get({ path: '/', validate: false }, (context, req, res) => + // we need the large body here so that compression would normally be used + res.ok({ body: 'hello'.repeat(500), headers: { 'Content-Type': 'text/html; charset=UTF-8' } }) + ); + registerRouter(router); + + await server.start(); + const response = await supertest(innerServer.listener) + .get('/') + .set('accept-encoding', 'gzip') + .set('referer', 'http://some-other-site/'); + + expect(response.header).not.toHaveProperty('content-encoding'); + }); + + test(`enables compression when there isn't a referer`, async () => { + const { registerRouter, server: innerServer } = await server.setup(config); + + const router = new Router('', logger, enhanceWithContext); + router.get({ path: '/', validate: false }, (context, req, res) => + // we need the large body here so that compression will be used + res.ok({ body: 'hello'.repeat(500), headers: { 'Content-Type': 'text/html; charset=UTF-8' } }) + ); + registerRouter(router); + + await server.start(); + const response = await supertest(innerServer.listener) + .get('/') + .set('accept-encoding', 'gzip'); + + expect(response.header).toHaveProperty('content-encoding', 'gzip'); + }); +}); + describe('setup contract', () => { describe('#createSessionStorage', () => { it('creates session storage factory', async () => { diff --git a/src/core/server/http/http_server.ts b/src/core/server/http/http_server.ts index 3354324c12407..d6077200d3c75 100644 --- a/src/core/server/http/http_server.ts +++ b/src/core/server/http/http_server.ts @@ -96,6 +96,7 @@ export class HttpServer { const basePathService = new BasePath(config.basePath); this.setupBasePathRewrite(config, basePathService); + this.setupConditionalCompression(); return { registerRouter: this.registerRouter.bind(this), @@ -175,6 +176,23 @@ export class HttpServer { }); } + private setupConditionalCompression() { + if (this.server === undefined) { + throw new Error('Server is not created yet'); + } + + this.server.ext('onRequest', (request, h) => { + // whenever there is a referrer, don't use compression even if the client supports it + if (request.info.referrer !== '') { + this.log.debug( + `Not using compression because there is a referer: ${request.info.referrer}` + ); + request.info.acceptEncoding = ''; + } + return h.continue; + }); + } + private registerOnPostAuth(fn: OnPostAuthHandler) { if (this.server === undefined) { throw new Error('Server is not created yet'); diff --git a/test/api_integration/apis/core/index.js b/test/api_integration/apis/core/index.js index d617b2ad07351..e5da4e4730662 100644 --- a/test/api_integration/apis/core/index.js +++ b/test/api_integration/apis/core/index.js @@ -16,21 +16,45 @@ * specific language governing permissions and limitations * under the License. */ +import expect from '@kbn/expect'; export default function ({ getService }) { const supertest = getService('supertest'); - describe('core request context', () => { - it('provides access to elasticsearch', async () => ( - await supertest - .get('/requestcontext/elasticsearch') - .expect(200, 'Elasticsearch: true') - )); + describe('core', () => { + describe('request context', () => { + it('provides access to elasticsearch', async () => ( + await supertest + .get('/requestcontext/elasticsearch') + .expect(200, 'Elasticsearch: true') + )); - it('provides access to SavedObjects client', async () => ( - await supertest - .get('/requestcontext/savedobjectsclient') - .expect(200, 'SavedObjects client: {"page":1,"per_page":20,"total":0,"saved_objects":[]}') - )); + it('provides access to SavedObjects client', async () => ( + await supertest + .get('/requestcontext/savedobjectsclient') + .expect(200, 'SavedObjects client: {"page":1,"per_page":20,"total":0,"saved_objects":[]}') + )); + }); + + describe('compression', () => { + it(`uses compression when there isn't a referer`, async () => { + await supertest + .get('/app/kibana') + .set('accept-encoding', 'gzip') + .then(response => { + expect(response.headers).to.have.property('content-encoding', 'gzip'); + }); + }); + + it(`doesn't use compression when there is a referer`, async () => { + await supertest + .get('/app/kibana') + .set('accept-encoding', 'gzip') + .set('referer', 'https://www.google.com') + .then(response => { + expect(response.headers).not.to.have.property('content-encoding'); + }); + }); + }); }); } diff --git a/test/api_integration/apis/index.js b/test/api_integration/apis/index.js index 9f2672959390c..de36ee678b10e 100644 --- a/test/api_integration/apis/index.js +++ b/test/api_integration/apis/index.js @@ -34,5 +34,6 @@ export default function ({ loadTestFile }) { loadTestFile(require.resolve('./status')); loadTestFile(require.resolve('./stats')); loadTestFile(require.resolve('./ui_metric')); + loadTestFile(require.resolve('./core')); }); }