UNPKG

koa-even-better-http-proxy

Version:
368 lines (315 loc) 10.3 kB
import assert from 'assert'; import Koa from 'koa'; import { agent } from 'supertest'; import proxy from '..'; function proxyTarget(port) { const other = new Koa(); other.use((ctx, next) => { if (ctx.request.url !== '/json') { return next(); } ctx.set('content-type', 'application/json'); ctx.body = JSON.stringify({ foo: 'bar' }); }); other.use((ctx) => { ctx.status = 200; ctx.set('x-wombat-alliance', 'mammels'); ctx.set('x-custom-header', 'something'); ctx.body = 'Success'; }); return other.listen(port); } function gzipProxyTarget(port) { const other = new Koa(); other.use((ctx) => { ctx.status = 200; ctx.set('content-type', 'application/octet-stream'); ctx.set('content-encoding', 'gzip'); ctx.body = ''; }); return other.listen(port); } describe('userResDecorator', () => { let other; beforeEach(() => { other = proxyTarget(8080); }); afterEach(() => { other.close(); }); it('has access to original response', (done) => { const app = new Koa(); app.use( proxy('http://localhost', { port: 8080, userResDecorator(proxyRes, proxyResData) { assert(proxyRes.connection); assert(proxyRes.socket); assert(proxyRes.headers); assert(proxyRes.headers['content-type']); return proxyResData; }, }) ); agent(app.callback()).get('/').end(done); }); it('works with promises', (done) => { const app = new Koa(); app.use( proxy('http://localhost', { port: 8080, userResDecorator(proxyRes, proxyResData) { return new Promise((resolve) => { proxyResData.funkyMessage = 'oi io oo ii'; setTimeout(() => { resolve(proxyResData); }, 200); }); }, }) ); agent(app.callback()) .get('/') .end((err, res) => { if (err) { return done(err); } assert((res.body.funkyMessage = 'oi io oo ii')); done(); }); }); it('can modify the response data', (done) => { const app = new Koa(); app.use( proxy('http://localhost', { port: 8080, userResDecorator(proxyRes, proxyResData) { proxyResData = JSON.parse(proxyResData.toString('utf8')); proxyResData.intercepted = true; return JSON.stringify(proxyResData); }, }) ); agent(app.callback()) .get('/json') .end((err, res) => { if (err) { return done(err); } assert(res.body.intercepted); done(); }); }); it('can filter response headers', (done) => { const proxiedApp = new Koa(); const app = new Koa(); let p1Done; let p2Done; const p1 = new Promise((resolve) => { p1Done = resolve; }); const p2 = new Promise((resolve) => { p2Done = resolve; }); app.use( proxy('http://localhost', { port: 8080, }) ); proxiedApp.use( proxy('http://localhost', { port: 8080, strippedHeaders: ['x-wombat-alliance', 'x-custom-header'], }) ); agent(app.callback()) .get('/') .end((err, res) => { if (err) { return done(err); } assert(typeof res.headers['x-custom-header'] === 'string'); assert(typeof res.headers['x-wombat-alliance'] === 'string'); p1Done(); }); agent(proxiedApp.callback()) .get('/') .end((err, res) => { if (err) { return done(err); } assert(typeof res.headers['x-custom-header'] !== 'string'); assert(typeof res.headers['x-wombat-alliance'] !== 'string'); p2Done(); }); Promise.all([p1, p2]).then(() => { done(); }); }); it('can modify the response headers', (done) => { const app = new Koa(); app.use( proxy('http://localhost', { port: 8080, userResHeadersDecorator(headers) { const newHeaders = Object.keys(headers).reduce( (result, key) => { result[key] = headers[key]; return result; }, {} ); newHeaders['x-transaction-id'] = '12345'; newHeaders['x-entity-id'] = 'abcdef'; return newHeaders; }, }) ); agent(app.callback()) .get('/ip') .end((err, res) => { if (err) { return done(err); } assert(res.headers['x-transaction-id'] === '12345'); assert(res.headers['x-entity-id'] === 'abcdef'); done(); }); }); it('can mutuate an html response', (done) => { const app = new Koa(); app.use( proxy('http://localhost', { port: 8080, userResDecorator(rsp, data) { data = data .toString() .replace('Success', '<strong>Hey</strong>'); assert(data !== ''); return data; }, }) ); agent(app.callback()) .get('/') .end((err, res) => { if (err) { return done(err); } assert(res.text.indexOf('<strong>Hey</strong>') > -1); done(); }); }); it('can change the location of a redirect', (done) => { function redirectingServer(port, origin) { const app = new Koa(); app.use((ctx) => { ctx.redirect(`${origin}/proxied/redirect/url`); }); return app.listen(port); } const redirectingServerPort = 8012; const redirectingServerOrigin = [ 'http://localhost', redirectingServerPort, ].join(':'); const server = redirectingServer( redirectingServerPort, redirectingServerOrigin ); const proxyApp = new Koa(); const preferredPort = 3000; proxyApp.use( proxy(redirectingServerOrigin, { userResDecorator(rsp, data, ctx) { const proxyReturnedLocation = ctx.response.headers.location; ctx.set( 'location', proxyReturnedLocation.replace( redirectingServerPort, preferredPort ) ); return data; }, }) ); agent(proxyApp.callback()) .get('/') .expect((res) => { res.headers.location.match(/localhost:3000/); }) .end(() => { server.close(); done(); }); }); }); describe('userResDecorator Gzip compression handling', () => { let other; beforeEach(() => { other = gzipProxyTarget(9090); }); afterEach(() => { other.close(); }); it('properly handles an empty gzipped HEAD response from proxy', function(done) { const app = new Koa(); app.use(proxy('localhost', { port: 9090 })); agent(app.callback()).head('/').end((err, res) => { if (err) { return done(err); } assert(res.statusCode === 200); assert(res.headers['content-encoding'] === 'gzip'); done(); }); }); it('properly handles an empty gzipped GET response from proxy', function(done) { const app = new Koa(); app.use(proxy('localhost', { port: 9090 })); agent(app.callback()).get('/').end((err, res) => { if (err) { return done(err); } assert(res.statusCode === 200); assert(res.headers['content-encoding'] === 'gzip'); done(); }); }); }); describe('test userResDecorator on html response from github', () => { /* Github provided a unique situation where the encoding was different than utf-8 when we didn't explicitly ask for utf-8. This test helped sort out the issue, and even though its a little too on the nose for a specific case, it seems worth keeping around to ensure we don't regress on this issue. */ it('is able to read and manipulate the response', function (done) { this.timeout(15000); // give it some extra time to get response const app = new Koa(); app.use( proxy('https://github.com/villadora/express-http-proxy', { userResDecorator(targetResponse, data) { data = data.toString().replace('DOCTYPE', 'WINNING'); assert(data !== ''); return data; }, }) ); agent(app.callback()) .get('/html') .end((err, res) => { if (err) { return done(err); } assert(res.text.indexOf('WINNING') > -1); done(); }); }); });