Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,8 @@
"ws": "8.19.0"
},
"dependencies": {
"@types/http-proxy": "^1.17.15",
"debug": "^4.3.6",
"http-proxy": "^1.18.1",
"http-proxy-3": "^1.23.2",
"is-glob": "^4.0.3",
"is-plain-object": "^5.0.0",
"micromatch": "^4.0.8"
Expand Down
23 changes: 0 additions & 23 deletions patches/http-proxy+1.18.1.patch

This file was deleted.

13 changes: 9 additions & 4 deletions src/http-proxy-middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type * as http from 'node:http';
import type * as https from 'node:https';
import type * as net from 'node:net';

import * as httpProxy from 'http-proxy';
import * as httpProxy from 'http-proxy-3';

import { verifyConfig } from './configuration';
import { Debug as debug } from './debug';
Expand All @@ -18,7 +18,7 @@ export class HttpProxyMiddleware<TReq, TRes> {
private wsInternalSubscribed = false;
private serverOnCloseSubscribed = false;
private proxyOptions: Options<TReq, TRes>;
private proxy: httpProxy<TReq, TRes>;
private proxy: httpProxy.ProxyServer;
private pathRewriter;
private logger: Logger;

Expand Down Expand Up @@ -81,7 +81,7 @@ export class HttpProxyMiddleware<TReq, TRes> {
}
}) as RequestHandler;

private registerPlugins(proxy: httpProxy<TReq, TRes>, options: Options<TReq, TRes>) {
private registerPlugins(proxy: httpProxy.ProxyServer, options: Options<TReq, TRes>) {
const plugins = getPlugins<TReq, TRes>(options);
plugins.forEach((plugin) => {
debug(`register plugin: "${getFunctionName(plugin)}"`);
Expand Down Expand Up @@ -109,7 +109,8 @@ export class HttpProxyMiddleware<TReq, TRes> {
} catch (err) {
// This error does not include the URL as the fourth argument as we won't
// have the URL if `this.prepareProxyRequest` throws an error.
this.proxy.emit('error', err, req, socket);

this.proxy.emit('error', err as Error, req, socket);
}
};

Expand Down Expand Up @@ -155,6 +156,10 @@ export class HttpProxyMiddleware<TReq, TRes> {
await this.applyRouter(req, newProxyOptions);
await this.applyPathRewrite(req, this.pathRewriter);

if (!newProxyOptions.target) {
throw new Error('Must provide a proper URL as target');
}

return newProxyOptions;
};

Expand Down
2 changes: 1 addition & 1 deletion src/plugins/default/proxy-events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ const debug = Debug.extend('proxy-events-plugin');
export const proxyEventsPlugin: Plugin = (proxyServer, options) => {
Object.entries(options.on || {}).forEach(([eventName, handler]) => {
debug(`register event handler: "${eventName}" -> "${getFunctionName(handler)}"`);
proxyServer.on(eventName, handler as (...args: unknown[]) => void);
proxyServer.on(eventName, handler as never);
});
};
72 changes: 50 additions & 22 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,52 @@
import type * as http from 'node:http';
import type * as net from 'node:net';

import type * as httpProxy from 'http-proxy';
import type { ErrorCallback, ProxyServer, ServerOptions } from 'http-proxy-3';

export type NextFunction<T = (err?: any) => void> = T;

export interface Plugin<TReq = http.IncomingMessage, TRes = http.ServerResponse> {
(proxyServer: ProxyServer, options: Options<TReq, TRes>): void;
}

export interface OnProxyEvent<TReq = http.IncomingMessage, TRes = http.ServerResponse> {
error?: (
err: Error,
req: TReq,
res: TRes,
target: string | { port: number; host: string; protocol?: string },
) => void | ErrorCallback;
proxyReq?: (
proxyReq: http.ClientRequest,
req: TReq,
res: TRes,
options: ServerOptions,
socket: net.Socket,
) => void;
proxyReqWs?: (
proxyReq: http.ClientRequest,
req: TReq,
socket: net.Socket,
options: ServerOptions,
head: any,
) => void;
proxyRes?: (proxyRes: TReq, req: TReq, res: TRes) => void;
open?: (socket: net.Socket) => void;
close?: (proxyRes: TReq, proxySocket: net.Socket, proxyHead: any) => void;
start?: (
req: TReq,
res: TRes,
target: string | { port: number; host: string; protocol?: string },
) => void;
end?: (req: TReq, res: TRes, proxyRes: TReq) => void;
econnreset?: (
err: Error,
req: TReq,
res: TRes,
target: string | { port: number; host: string; protocol?: string },
) => void;
}

export interface RequestHandler<
TReq = http.IncomingMessage,
TRes = http.ServerResponse,
Expand All @@ -23,26 +65,12 @@ export type Filter<TReq = http.IncomingMessage> =
| string[]
| ((pathname: string, req: TReq) => boolean);

export interface Plugin<TReq = http.IncomingMessage, TRes = http.ServerResponse> {
(proxyServer: httpProxy<TReq, TRes>, options: Options<TReq, TRes>): void;
}

export interface OnProxyEvent<TReq = http.IncomingMessage, TRes = http.ServerResponse> {
error?: httpProxy.ErrorCallback<Error, TReq, TRes>;
proxyReq?: httpProxy.ProxyReqCallback<http.ClientRequest, TReq, TRes>;
proxyReqWs?: httpProxy.ProxyReqWsCallback<http.ClientRequest, TReq>;
proxyRes?: httpProxy.ProxyResCallback<TReq, TRes>;
open?: httpProxy.OpenCallback;
close?: httpProxy.CloseCallback<TReq>;
start?: httpProxy.StartCallback<TReq, TRes>;
end?: httpProxy.EndCallback<TReq, TRes>;
econnreset?: httpProxy.EconnresetCallback<Error, TReq, TRes>;
}

export type Logger = Pick<Console, 'info' | 'warn' | 'error'>;

export interface Options<TReq = http.IncomingMessage, TRes = http.ServerResponse>
extends httpProxy.ServerOptions {
export interface Options<
TReq = http.IncomingMessage,
TRes = http.ServerResponse,
> extends ServerOptions {
/**
* Narrow down requests to proxy or not.
* Filter on {@link http.IncomingMessage.url `pathname`} which is relative to the proxy's "mounting" point in the server.
Expand Down Expand Up @@ -122,9 +150,9 @@ export interface Options<TReq = http.IncomingMessage, TRes = http.ServerResponse
* @link https://github.com/chimurai/http-proxy-middleware/blob/master/recipes/router.md
*/
router?:
| { [hostOrPath: string]: httpProxy.ServerOptions['target'] }
| ((req: TReq) => httpProxy.ServerOptions['target'])
| ((req: TReq) => Promise<httpProxy.ServerOptions['target']>);
| { [hostOrPath: string]: ServerOptions['target'] }
| ((req: TReq) => ServerOptions['target'])
| ((req: TReq) => Promise<ServerOptions['target']>);
/**
* Log information from http-proxy-middleware
* @example
Expand Down
8 changes: 7 additions & 1 deletion test/e2e/express-error-middleware.spec.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as express from 'express';
import * as request from 'supertest';

import { createApp, createProxyMiddleware } from './test-kit';
Expand All @@ -11,7 +12,12 @@ describe('express error middleware', () => {
router: (req) => undefined, // Trigger "Error: Must provide a proper URL as target"
});

const errorMiddleware = (err, req, res, next) => {
const errorMiddleware = (
err: Error,
req: express.Request,
res: express.Response,
next: express.NextFunction,
) => {
httpProxyError = err;
res.status(504).send('Something broke!');
};
Expand Down
7 changes: 4 additions & 3 deletions test/e2e/express-router.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as express from 'express';
import * as http from 'http';
import * as request from 'supertest';

import { Options } from '../../src/index';
Expand All @@ -18,7 +19,7 @@ describe('Usage in Express', () => {
// sub route config
const sub = express.Router();

function filter(pathname, req) {
function filter(pathname: string, req: http.IncomingMessage) {
const urlFilter = new RegExp('^/sub/api');
const match = urlFilter.test(pathname);
return match;
Expand Down Expand Up @@ -49,8 +50,8 @@ describe('Usage in Express', () => {
});
});

function jsonMiddleware(data) {
return (req, res) => {
function jsonMiddleware(data: any) {
return (req: express.Request, res: express.Response) => {
res.json(data);
};
}
Expand Down
6 changes: 3 additions & 3 deletions test/e2e/http-proxy-middleware.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ describe('E2E http-proxy-middleware', () => {

describe('custom pathFilter matcher/filter', () => {
it('should have response body: "HELLO WEB"', async () => {
const filter = (path, req) => {
const filter = (path: string, req: http.IncomingMessage) => {
return true;
};

Expand All @@ -152,7 +152,7 @@ describe('E2E http-proxy-middleware', () => {
});

it('should not proxy when filter returns false', async () => {
const filter = (path, req) => {
const filter = (path: string, req: http.IncomingMessage) => {
return false;
};

Expand All @@ -172,7 +172,7 @@ describe('E2E http-proxy-middleware', () => {

it('should not proxy when filter throws Error', async () => {
const myError = new Error('MY_ERROR');
const filter = (path, req) => {
const filter = (path: string, req: http.IncomingMessage) => {
throw myError;
};

Expand Down
3 changes: 2 additions & 1 deletion test/e2e/router.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { ErrorRequestHandler } from 'express';
import * as getPort from 'get-port';
import { Mockttp, generateCACertificate, getLocal } from 'mockttp';
import * as request from 'supertest';
import * as TestAgent from 'supertest';

import { createApp, createAppWithPath, createProxyMiddleware } from './test-kit';

Expand Down Expand Up @@ -147,7 +148,7 @@ describe('E2E router', () => {
});

describe('router with proxyTable', () => {
let agent;
let agent: TestAgent.Agent;

beforeEach(() => {
const app = createAppWithPath(
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/test-kit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { Express, RequestHandler } from 'express';

export { createProxyMiddleware, responseInterceptor, fixRequestBody } from '../../src/index';

export function createApp(...middlewares): Express {
export function createApp(...middlewares: any[]): Express {
const app = express();
app.use(...middlewares);
return app;
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/websocket.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ describe('E2E WebSocket proxy', () => {
proxyServer = createApp(proxyMiddleware).listen(SERVER_PORT);

// quick & dirty Promise version of http.get (don't care about correctness)
const get = async (uri) => new Promise((resolve, reject) => http.get(uri, resolve));
const get = async (uri: string) => new Promise((resolve, reject) => http.get(uri, resolve));

// need to make a normal http request, so http-proxy-middleware can catch the upgrade request
await get(`http://localhost:${SERVER_PORT}/`);
Expand Down
42 changes: 12 additions & 30 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1412,13 +1412,6 @@
resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.1.tgz#20172f9578b225f6c7da63446f56d4ce108d5a65"
integrity sha512-/K3ds8TRAfBvi5vfjuz8y6+GiAYBZ0x4tXv1Av6CWBWn0IlADc+ZX9pMq7oU0fNQPnBwIZl3rmeLp6SBApbxSQ==

"@types/http-proxy@^1.17.15":
version "1.17.15"
resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.15.tgz#12118141ce9775a6499ecb4c01d02f90fc839d36"
integrity sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==
dependencies:
"@types/node" "*"

"@types/is-glob@4.0.4":
version "4.0.4"
resolved "https://registry.yarnpkg.com/@types/is-glob/-/is-glob-4.0.4.tgz#1d60fa47ff70abc97b4d9ea45328747c488b3a50"
Expand Down Expand Up @@ -2835,11 +2828,6 @@ eventemitter3@^3.1.0:
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7"
integrity sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==

eventemitter3@^4.0.0:
version "4.0.7"
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==

eventemitter3@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4"
Expand Down Expand Up @@ -3092,10 +3080,10 @@ flatted@^3.2.9:
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a"
integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==

follow-redirects@^1.0.0:
version "1.15.6"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b"
integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==
follow-redirects@^1.15.9:
version "1.15.11"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.11.tgz#777d73d72a92f8ec4d2e410eb47352a56b8e8340"
integrity sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==

foreground-child@^3.1.0:
version "3.3.1"
Expand Down Expand Up @@ -3409,6 +3397,14 @@ http-errors@~2.0.1:
statuses "~2.0.2"
toidentifier "~1.0.1"

http-proxy-3@^1.23.2:
version "1.23.2"
resolved "https://registry.yarnpkg.com/http-proxy-3/-/http-proxy-3-1.23.2.tgz#c3cceead89ce94e8feca7f75bb23e508f3924347"
integrity sha512-vZks1dLliM0w7aQDT9eFYLO8PUuQ9Cm67y7kn+kgkLtvKP0HZ6Thb3+MCGFFNCnKMCkLXY6rvIH1d7jQITryxA==
dependencies:
debug "^4.4.0"
follow-redirects "^1.15.9"

http-proxy-agent@^7.0.0:
version "7.0.2"
resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz#9a8b1f246866c028509486585f62b8f2c18c270e"
Expand All @@ -3417,15 +3413,6 @@ http-proxy-agent@^7.0.0:
agent-base "^7.1.0"
debug "^4.3.4"

http-proxy@^1.18.1:
version "1.18.1"
resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549"
integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==
dependencies:
eventemitter3 "^4.0.0"
follow-redirects "^1.0.0"
requires-port "^1.0.0"

http2-wrapper@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-2.2.1.tgz#310968153dcdedb160d8b72114363ef5fce1f64a"
Expand Down Expand Up @@ -5106,11 +5093,6 @@ require-from-string@^2.0.2:
resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909"
integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==

requires-port@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==

resolve-alpn@^1.2.0:
version "1.2.1"
resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9"
Expand Down
Loading