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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 5 additions & 2 deletions README.md
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
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
@@ -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