http-proxy-middleware 3.0.3 → 3.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -38,9 +38,9 @@ import type { Filter, Options, RequestHandler } from 'http-proxy-middleware';
|
|
|
38
38
|
const app = express();
|
|
39
39
|
|
|
40
40
|
const proxyMiddleware = createProxyMiddleware<Request, Response>({
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
target: 'http://www.example.org/api',
|
|
42
|
+
changeOrigin: true,
|
|
43
|
+
});
|
|
44
44
|
|
|
45
45
|
app.use('/api', proxyMiddleware);
|
|
46
46
|
|
|
@@ -48,7 +48,6 @@ app.listen(3000);
|
|
|
48
48
|
|
|
49
49
|
// proxy and keep the same base path "/api"
|
|
50
50
|
// http://127.0.0.1:3000/api/foo/bar -> http://www.example.org/api/foo/bar
|
|
51
|
-
|
|
52
51
|
```
|
|
53
52
|
|
|
54
53
|
_All_ `http-proxy` [options](https://github.com/nodejitsu/node-http-proxy#options) can be used, along with some extra `http-proxy-middleware` [options](#options).
|
|
@@ -645,4 +644,4 @@ $ yarn spellcheck
|
|
|
645
644
|
|
|
646
645
|
The MIT License (MIT)
|
|
647
646
|
|
|
648
|
-
Copyright (c) 2015-
|
|
647
|
+
Copyright (c) 2015-2025 Steven Chim
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type * as http from 'http';
|
|
2
|
+
import type { Options } from '../types';
|
|
2
3
|
export type BodyParserLikeRequest = http.IncomingMessage & {
|
|
3
|
-
body
|
|
4
|
+
body?: any;
|
|
4
5
|
};
|
|
5
6
|
/**
|
|
6
7
|
* Fix proxied body if bodyParser is involved.
|
|
7
8
|
*/
|
|
8
|
-
export declare function fixRequestBody<TReq =
|
|
9
|
+
export declare function fixRequestBody<TReq extends BodyParserLikeRequest = BodyParserLikeRequest>(proxyReq: http.ClientRequest, req: TReq, res: http.ServerResponse<http.IncomingMessage>, options: Options): void;
|
|
@@ -2,24 +2,68 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.fixRequestBody = fixRequestBody;
|
|
4
4
|
const querystring = require("querystring");
|
|
5
|
+
const logger_1 = require("../logger");
|
|
5
6
|
/**
|
|
6
7
|
* Fix proxied body if bodyParser is involved.
|
|
7
8
|
*/
|
|
8
|
-
function fixRequestBody(proxyReq, req) {
|
|
9
|
+
function fixRequestBody(proxyReq, req, res, options) {
|
|
9
10
|
const requestBody = req.body;
|
|
10
11
|
if (!requestBody) {
|
|
11
12
|
return;
|
|
12
13
|
}
|
|
13
14
|
const contentType = proxyReq.getHeader('Content-Type');
|
|
15
|
+
if (!contentType) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const logger = (0, logger_1.getLogger)(options);
|
|
19
|
+
// Handle bad request when unexpected "Connect: Upgrade" header is provided
|
|
20
|
+
if (/upgrade/gi.test(proxyReq.getHeader('Connection'))) {
|
|
21
|
+
handleBadRequest({ proxyReq, req, res });
|
|
22
|
+
logger.error(`[HPM] HPM_UNEXPECTED_CONNECTION_UPGRADE_HEADER. Aborted request: ${req.url}`);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
// Handle bad request when invalid request body is provided
|
|
26
|
+
if (hasInvalidKeys(requestBody)) {
|
|
27
|
+
handleBadRequest({ proxyReq, req, res });
|
|
28
|
+
logger.error(`[HPM] HPM_INVALID_REQUEST_DATA. Aborted request: ${req.url}`);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
14
31
|
const writeBody = (bodyData) => {
|
|
15
|
-
// deepcode ignore ContentLengthInCode: bodyParser fix
|
|
16
32
|
proxyReq.setHeader('Content-Length', Buffer.byteLength(bodyData));
|
|
17
33
|
proxyReq.write(bodyData);
|
|
18
34
|
};
|
|
19
|
-
if
|
|
35
|
+
// Use if-elseif to prevent multiple writeBody/setHeader calls:
|
|
36
|
+
// Error: "Cannot set headers after they are sent to the client"
|
|
37
|
+
if (contentType.includes('application/json') || contentType.includes('+json')) {
|
|
20
38
|
writeBody(JSON.stringify(requestBody));
|
|
21
39
|
}
|
|
22
|
-
if (contentType
|
|
40
|
+
else if (contentType.includes('application/x-www-form-urlencoded')) {
|
|
23
41
|
writeBody(querystring.stringify(requestBody));
|
|
24
42
|
}
|
|
43
|
+
else if (contentType.includes('multipart/form-data')) {
|
|
44
|
+
writeBody(handlerFormDataBodyData(contentType, requestBody));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* format FormData data
|
|
49
|
+
* @param contentType
|
|
50
|
+
* @param data
|
|
51
|
+
* @returns
|
|
52
|
+
*/
|
|
53
|
+
function handlerFormDataBodyData(contentType, data) {
|
|
54
|
+
const boundary = contentType.replace(/^.*boundary=(.*)$/, '$1');
|
|
55
|
+
let str = '';
|
|
56
|
+
for (const [key, value] of Object.entries(data)) {
|
|
57
|
+
str += `--${boundary}\r\nContent-Disposition: form-data; name="${key}"\r\n\r\n${value}\r\n`;
|
|
58
|
+
}
|
|
59
|
+
return str;
|
|
60
|
+
}
|
|
61
|
+
function hasInvalidKeys(obj) {
|
|
62
|
+
return Object.keys(obj).some((key) => /[\n\r]/.test(key));
|
|
63
|
+
}
|
|
64
|
+
function handleBadRequest({ proxyReq, req, res }) {
|
|
65
|
+
res.writeHead(400);
|
|
66
|
+
res.end('Bad Request');
|
|
67
|
+
proxyReq.destroy();
|
|
68
|
+
req.destroy();
|
|
25
69
|
}
|
|
@@ -60,10 +60,17 @@ class HttpProxyMiddleware {
|
|
|
60
60
|
}
|
|
61
61
|
};
|
|
62
62
|
this.handleUpgrade = async (req, socket, head) => {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
63
|
+
try {
|
|
64
|
+
if (this.shouldProxy(this.proxyOptions.pathFilter, req)) {
|
|
65
|
+
const activeProxyOptions = await this.prepareProxyRequest(req);
|
|
66
|
+
this.proxy.ws(req, socket, head, activeProxyOptions);
|
|
67
|
+
(0, debug_1.Debug)('server upgrade event received. Proxying WebSocket');
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
// This error does not include the URL as the fourth argument as we won't
|
|
72
|
+
// have the URL if `this.prepareProxyRequest` throws an error.
|
|
73
|
+
this.proxy.emit('error', err, req, socket);
|
|
67
74
|
}
|
|
68
75
|
};
|
|
69
76
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -2,18 +2,29 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.errorResponsePlugin = void 0;
|
|
4
4
|
const status_code_1 = require("../../status-code");
|
|
5
|
+
function isResponseLike(obj) {
|
|
6
|
+
return obj && typeof obj.writeHead === 'function';
|
|
7
|
+
}
|
|
8
|
+
function isSocketLike(obj) {
|
|
9
|
+
return obj && typeof obj.write === 'function' && !('writeHead' in obj);
|
|
10
|
+
}
|
|
5
11
|
const errorResponsePlugin = (proxyServer, options) => {
|
|
6
12
|
proxyServer.on('error', (err, req, res, target) => {
|
|
7
13
|
// Re-throw error. Not recoverable since req & res are empty.
|
|
8
14
|
if (!req && !res) {
|
|
9
15
|
throw err; // "Error: Must provide a proper URL as target"
|
|
10
16
|
}
|
|
11
|
-
if (
|
|
12
|
-
|
|
13
|
-
|
|
17
|
+
if (isResponseLike(res)) {
|
|
18
|
+
if (!res.headersSent) {
|
|
19
|
+
const statusCode = (0, status_code_1.getStatusCode)(err.code);
|
|
20
|
+
res.writeHead(statusCode);
|
|
21
|
+
}
|
|
22
|
+
const host = req.headers && req.headers.host;
|
|
23
|
+
res.end(`Error occurred while trying to proxy: ${host}${req.url}`);
|
|
24
|
+
}
|
|
25
|
+
else if (isSocketLike(res)) {
|
|
26
|
+
res.destroy();
|
|
14
27
|
}
|
|
15
|
-
const host = req.headers && req.headers.host;
|
|
16
|
-
res.end(`Error occurred while trying to proxy: ${host}${req.url}`);
|
|
17
28
|
});
|
|
18
29
|
};
|
|
19
30
|
exports.errorResponsePlugin = errorResponsePlugin;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "http-proxy-middleware",
|
|
3
3
|
"type": "commonjs",
|
|
4
|
-
"version": "3.0.
|
|
4
|
+
"version": "3.0.4",
|
|
5
5
|
"description": "The one-liner node.js proxy middleware for connect, express, next.js and more",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"build": "tsc --build",
|
|
21
21
|
"test": "jest",
|
|
22
22
|
"coverage": "jest --coverage",
|
|
23
|
-
"prepare": "husky",
|
|
23
|
+
"prepare": "husky && patch-package",
|
|
24
24
|
"prepack": "yarn clean && yarn test && yarn build",
|
|
25
25
|
"spellcheck": "npx --yes cspell --show-context --show-suggestions '**/*.*'"
|
|
26
26
|
},
|
|
@@ -56,37 +56,38 @@
|
|
|
56
56
|
},
|
|
57
57
|
"homepage": "https://github.com/chimurai/http-proxy-middleware#readme",
|
|
58
58
|
"devDependencies": {
|
|
59
|
-
"@commitlint/cli": "19.
|
|
60
|
-
"@commitlint/config-conventional": "19.
|
|
61
|
-
"@eslint/js": "9.
|
|
59
|
+
"@commitlint/cli": "19.8.0",
|
|
60
|
+
"@commitlint/config-conventional": "19.8.0",
|
|
61
|
+
"@eslint/js": "9.23.0",
|
|
62
62
|
"@types/debug": "4.1.12",
|
|
63
63
|
"@types/eslint": "9.6.1",
|
|
64
|
-
"@types/eslint__js": "8.42.3",
|
|
65
64
|
"@types/express": "4.17.21",
|
|
66
65
|
"@types/is-glob": "4.0.4",
|
|
67
|
-
"@types/jest": "29.5.
|
|
66
|
+
"@types/jest": "29.5.14",
|
|
68
67
|
"@types/micromatch": "4.0.9",
|
|
69
|
-
"@types/node": "22.
|
|
68
|
+
"@types/node": "22.10.2",
|
|
70
69
|
"@types/supertest": "6.0.2",
|
|
71
|
-
"@types/ws": "8.
|
|
72
|
-
"body-parser": "1.20.
|
|
73
|
-
"eslint": "9.
|
|
74
|
-
"eslint-config-prettier": "
|
|
75
|
-
"eslint-plugin-prettier": "5.2.
|
|
76
|
-
"express": "4.
|
|
70
|
+
"@types/ws": "8.18.0",
|
|
71
|
+
"body-parser": "1.20.3",
|
|
72
|
+
"eslint": "9.23.0",
|
|
73
|
+
"eslint-config-prettier": "10.1.1",
|
|
74
|
+
"eslint-plugin-prettier": "5.2.3",
|
|
75
|
+
"express": "4.21.2",
|
|
77
76
|
"get-port": "5.1.1",
|
|
78
|
-
"globals": "
|
|
79
|
-
"husky": "9.1.
|
|
77
|
+
"globals": "16.0.0",
|
|
78
|
+
"husky": "9.1.7",
|
|
80
79
|
"jest": "29.7.0",
|
|
81
|
-
"lint-staged": "15.
|
|
82
|
-
"mockttp": "3.
|
|
80
|
+
"lint-staged": "15.5.0",
|
|
81
|
+
"mockttp": "3.17.0",
|
|
83
82
|
"open": "8.4.2",
|
|
84
|
-
"
|
|
85
|
-
"
|
|
86
|
-
"
|
|
87
|
-
"
|
|
88
|
-
"
|
|
89
|
-
"
|
|
83
|
+
"patch-package": "8.0.0",
|
|
84
|
+
"pkg-pr-new": "0.0.41",
|
|
85
|
+
"prettier": "3.5.3",
|
|
86
|
+
"supertest": "7.1.0",
|
|
87
|
+
"ts-jest": "29.2.6",
|
|
88
|
+
"typescript": "5.8.2",
|
|
89
|
+
"typescript-eslint": "8.27.0",
|
|
90
|
+
"ws": "8.18.1"
|
|
90
91
|
},
|
|
91
92
|
"dependencies": {
|
|
92
93
|
"@types/http-proxy": "^1.17.15",
|