Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(typescript): fix proxyRes and router types #410

Merged
merged 4 commits into from
Feb 29, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,6 @@ Providing an alternative way to decide which requests should be proxied; In case
if (should_add_something) path += "something";
return path;
}

```

- **option.router**: object/function, re-target `option.target` for specific requests.
Expand All @@ -245,7 +244,11 @@ Providing an alternative way to decide which requests should be proxied; In case

// Custom router function
router: function(req) {
return 'http://localhost:8004';
return {
chimurai marked this conversation as resolved.
Show resolved Hide resolved
protocol: 'https:', // The : is required
host: 'localhost',
port: 8004
};
}

// Asynchronous router function which returns promise
Expand Down
8 changes: 4 additions & 4 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ export interface Options extends httpProxy.ServerOptions {
| ((path: string, req: Request) => string)
| ((path: string, req: Request) => Promise<string>);
router?:
| { [hostOrPath: string]: string }
| ((req: Request) => string)
| ((req: Request) => Promise<string>);
| { [hostOrPath: string]: httpProxy.ServerOptions['target'] }
| ((req: Request) => httpProxy.ServerOptions['target'])
| ((req: Request) => Promise<httpProxy.ServerOptions['target']>);
logLevel?: 'debug' | 'info' | 'warn' | 'error' | 'silent';
logProvider?(provider: LogProvider): LogProvider;

onError?(err: Error, req: Request, res: Response): void;
onProxyRes?(proxyRes: http.ServerResponse, req: Request, res: Response): void;
onProxyRes?(proxyRes: http.IncomingMessage, req: Request, res: Response): void;
onProxyReq?(proxyReq: http.ClientRequest, req: Request, res: Response): void;
onProxyReqWs?(
proxyReq: http.ClientRequest,
Expand Down
110 changes: 94 additions & 16 deletions test/e2e/router.spec.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,44 @@
import { createProxyMiddleware, createApp, createAppWithPath } from './_utils';
import * as request from 'supertest';
import { getLocal, Mockttp } from 'mockttp';
import { getLocal, generateCACertificate, Mockttp } from 'mockttp';

const untrustedCACert = generateCACertificate({ bits: 1024 });

process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';

describe('E2E router', () => {
let targetServerA: Mockttp;
let targetServerB: Mockttp;
let targetServerC: Mockttp;

beforeEach(async () => {
targetServerA = getLocal();
targetServerB = getLocal();
targetServerC = getLocal();
targetServerA = getLocal({ https: await untrustedCACert });
targetServerB = getLocal({ https: await untrustedCACert });
targetServerC = getLocal({ https: await untrustedCACert });

await targetServerA
.anyRequest()
.thenPassThrough({ ignoreHostCertificateErrors: ['localhost'] });
await targetServerB
.anyRequest()
.thenPassThrough({ ignoreHostCertificateErrors: ['localhost'] });
await targetServerC
.anyRequest()
.thenPassThrough({ ignoreHostCertificateErrors: ['localhost'] });

await targetServerA
.anyRequest()
.thenCallback(({ protocol }) => ({ body: protocol === 'https' ? 'A' : 'NOT HTTPS A' }));
await targetServerB
.anyRequest()
.thenCallback(({ protocol }) => ({ body: protocol === 'https' ? 'B' : 'NOT HTTPS B' }));
await targetServerC
.anyRequest()
.thenCallback(({ protocol }) => ({ body: protocol === 'https' ? 'C' : 'NOT HTTPS C' }));

await targetServerA.start(6001);
await targetServerB.start(6002);
await targetServerC.start(6003);

targetServerA.get().thenReply(200, 'A');
targetServerB.get().thenReply(200, 'B');
targetServerC.get().thenReply(200, 'C');
});

afterEach(async () => {
Expand All @@ -27,13 +47,50 @@ describe('E2E router', () => {
await targetServerC.stop();
});

describe('router with proxyTable', () => {
it('should proxy to: "localhost:6003/api"', async () => {
describe('router with req', () => {
it('should work with a string', async () => {
const app = createApp(
createProxyMiddleware({
target: 'https://localhost:6001',
secure: false,
changeOrigin: true,
router(req) {
return 'https://localhost:6003';
}
})
);

const agent = request(app);
const response = await agent.get('/api').expect(200);
expect(response.text).toBe('C');
});

it('should work with an object', async () => {
const app = createApp(
createProxyMiddleware({
target: `http://localhost:6001`,
target: 'https://localhost:6001',
secure: false,
changeOrigin: true,
router(req) {
return 'http://localhost:6003';
return { host: 'localhost', port: 6003, protocol: 'https:' };
}
})
);
const agent = request(app);
const response = await agent.get('/api').expect(200);
expect(response.text).toBe('C');
});

it('should work with an async callback', async () => {
const app = createApp(
createProxyMiddleware({
target: 'https://localhost:6001',
secure: false,
changeOrigin: true,
router: async req => {
return new Promise(resolve =>
resolve({ host: 'localhost', port: 6003, protocol: 'https:' })
);
}
})
);
Expand All @@ -42,6 +99,25 @@ describe('E2E router', () => {
const response = await agent.get('/api').expect(200);
expect(response.text).toBe('C');
});

it('missing a : will cause it to use http', async () => {
const app = createApp(
createProxyMiddleware({
target: 'https://localhost:6001',
secure: false,
changeOrigin: true,
router: async req => {
return new Promise(resolve =>
resolve({ host: 'localhost', port: 6003, protocol: 'https' })
);
}
})
);

const agent = request(app);
const response = await agent.get('/api').expect(200);
expect(response.text).toBe('NOT HTTPS C');
});
});

describe('router with proxyTable', () => {
Expand All @@ -51,11 +127,13 @@ describe('E2E router', () => {
const app = createAppWithPath(
'/',
createProxyMiddleware({
target: 'http://localhost:6001',
target: 'https://localhost:6001',
secure: false,
changeOrigin: true,
router: {
'alpha.localhost:6000': 'http://localhost:6001',
'beta.localhost:6000': 'http://localhost:6002',
'localhost:6000/api': 'http://localhost:6003'
'alpha.localhost:6000': 'https://localhost:6001',
'beta.localhost:6000': 'https://localhost:6002',
'localhost:6000/api': 'https://localhost:6003'
}
})
);
Expand Down