@ohos-ports/http-proxy-middleware 0.0.0-stage → 4.2.0-beta.1
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/LICENSE +22 -0
- package/README.md +670 -2
- package/dist/configuration.d.ts +3 -0
- package/dist/configuration.js +6 -0
- package/dist/debug.d.ts +5 -0
- package/dist/debug.js +5 -0
- package/dist/errors.d.ts +4 -0
- package/dist/errors.js +15 -0
- package/dist/factory-hono.d.ts +28 -0
- package/dist/factory-hono.js +45 -0
- package/dist/factory.d.ts +79 -0
- package/dist/factory.js +81 -0
- package/dist/get-plugins.d.ts +3 -0
- package/dist/get-plugins.js +10 -0
- package/dist/handlers/fix-request-body-utils/stringify-form-data.d.ts +12 -0
- package/dist/handlers/fix-request-body-utils/stringify-form-data.js +46 -0
- package/dist/handlers/fix-request-body.d.ts +22 -0
- package/dist/handlers/fix-request-body.js +78 -0
- package/dist/handlers/index.d.ts +1 -0
- package/dist/handlers/index.js +1 -0
- package/dist/handlers/public.d.ts +2 -0
- package/dist/handlers/public.js +2 -0
- package/dist/handlers/response-interceptor.d.ts +27 -0
- package/dist/handlers/response-interceptor.js +145 -0
- package/dist/http-proxy-middleware.d.ts +31 -0
- package/dist/http-proxy-middleware.js +183 -0
- package/dist/index-hono.d.ts +10 -0
- package/dist/index-hono.js +10 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3 -0
- package/dist/logger.d.ts +2 -0
- package/dist/logger.js +21 -0
- package/dist/path-filter.d.ts +3 -0
- package/dist/path-filter.js +76 -0
- package/dist/path-rewriter.d.ts +6 -0
- package/dist/path-rewriter.js +59 -0
- package/dist/plugins/default/debug-proxy-errors-plugin.d.ts +6 -0
- package/dist/plugins/default/debug-proxy-errors-plugin.js +77 -0
- package/dist/plugins/default/error-response-plugin.d.ts +2 -0
- package/dist/plugins/default/error-response-plugin.js +28 -0
- package/dist/plugins/default/index.d.ts +4 -0
- package/dist/plugins/default/index.js +4 -0
- package/dist/plugins/default/logger-plugin.d.ts +2 -0
- package/dist/plugins/default/logger-plugin.js +57 -0
- package/dist/plugins/default/proxy-events.d.ts +22 -0
- package/dist/plugins/default/proxy-events.js +42 -0
- package/dist/plugins/define-plugin.d.ts +25 -0
- package/dist/plugins/define-plugin.js +25 -0
- package/dist/plugins/index.d.ts +2 -0
- package/dist/plugins/index.js +4 -0
- package/dist/router.d.ts +3 -0
- package/dist/router.js +60 -0
- package/dist/status-code.d.ts +1 -0
- package/dist/status-code.js +23 -0
- package/dist/types.d.ts +139 -0
- package/dist/types.js +1 -0
- package/dist/utils/create-url.d.ts +9 -0
- package/dist/utils/create-url.js +17 -0
- package/dist/utils/function.d.ts +1 -0
- package/dist/utils/function.js +4 -0
- package/dist/utils/ipv6.d.ts +20 -0
- package/dist/utils/ipv6.js +66 -0
- package/dist/utils/logger-plugin.d.ts +7 -0
- package/dist/utils/logger-plugin.js +7 -0
- package/dist/utils/sanitize.d.ts +1 -0
- package/dist/utils/sanitize.js +3 -0
- package/package.json +120 -4
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Debug } from '../../debug.js';
|
|
2
|
+
import { getFunctionName } from '../../utils/function.js';
|
|
3
|
+
import { definePlugin } from '../define-plugin.js';
|
|
4
|
+
const debug = Debug.extend('proxy-events-plugin');
|
|
5
|
+
/**
|
|
6
|
+
* Implements option.on object to subscribe to `httpxy` events.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```js
|
|
10
|
+
* createProxyMiddleware({
|
|
11
|
+
* on: {
|
|
12
|
+
* error: (error, req, res, target) => {},
|
|
13
|
+
* proxyReq: (proxyReq, req, res, options) => {},
|
|
14
|
+
* proxyReqWs: (proxyReq, req, socket, options) => {},
|
|
15
|
+
* proxyRes: (proxyRes, req, res) => {},
|
|
16
|
+
* open: (proxySocket) => {},
|
|
17
|
+
* close: (proxyRes, proxySocket, proxyHead) => {},
|
|
18
|
+
* start: (req, res, target) => {},
|
|
19
|
+
* end: (req, res, proxyRes) => {},
|
|
20
|
+
* econnreset: (error, req, res, target) => {},
|
|
21
|
+
* }
|
|
22
|
+
* });
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export const proxyEventsPlugin = definePlugin((proxyServer, options) => {
|
|
26
|
+
if (!options.on) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
// hoist variable here for better typing
|
|
30
|
+
let eventName;
|
|
31
|
+
// for in provide better typing than Object.entries()
|
|
32
|
+
for (eventName in options.on) {
|
|
33
|
+
if (Object.prototype.hasOwnProperty.call(options.on, eventName)) {
|
|
34
|
+
const handler = options.on[eventName];
|
|
35
|
+
if (!handler) {
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
debug(`register event handler: "${eventName}" -> "${getFunctionName(handler)}"`);
|
|
39
|
+
proxyServer.on(eventName, handler);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type * as http from 'node:http';
|
|
2
|
+
import type { Plugin } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Helper function to define a http-proxy-middleware plugin
|
|
5
|
+
* @see proxyServer {@link ProxyServer} - proxy server instance to which the plugin is being applied
|
|
6
|
+
* @see options {@link Options} - options object passed to `createProxyMiddleware`
|
|
7
|
+
*
|
|
8
|
+
* @example defining a plugin
|
|
9
|
+
* ```js
|
|
10
|
+
* export const myPlugin = definePlugin((proxyServer, options) => {
|
|
11
|
+
* // plugin implementation
|
|
12
|
+
* });
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* @example using a plugin
|
|
16
|
+
* ```js
|
|
17
|
+
* createProxyMiddleware({
|
|
18
|
+
* target: 'http://example.com',
|
|
19
|
+
* plugins: [myPlugin],
|
|
20
|
+
* });
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* @since 4.1.0
|
|
24
|
+
*/
|
|
25
|
+
export declare function definePlugin<TReq extends http.IncomingMessage = http.IncomingMessage, TRes extends http.ServerResponse = http.ServerResponse>(fn: Plugin<TReq, TRes>): Plugin<TReq, TRes>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper function to define a http-proxy-middleware plugin
|
|
3
|
+
* @see proxyServer {@link ProxyServer} - proxy server instance to which the plugin is being applied
|
|
4
|
+
* @see options {@link Options} - options object passed to `createProxyMiddleware`
|
|
5
|
+
*
|
|
6
|
+
* @example defining a plugin
|
|
7
|
+
* ```js
|
|
8
|
+
* export const myPlugin = definePlugin((proxyServer, options) => {
|
|
9
|
+
* // plugin implementation
|
|
10
|
+
* });
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* @example using a plugin
|
|
14
|
+
* ```js
|
|
15
|
+
* createProxyMiddleware({
|
|
16
|
+
* target: 'http://example.com',
|
|
17
|
+
* plugins: [myPlugin],
|
|
18
|
+
* });
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* @since 4.1.0
|
|
22
|
+
*/
|
|
23
|
+
export function definePlugin(fn) {
|
|
24
|
+
return fn;
|
|
25
|
+
}
|
package/dist/router.d.ts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type * as http from 'node:http';
|
|
2
|
+
import type { Options } from './index.js';
|
|
3
|
+
export declare function getTarget<TReq extends http.IncomingMessage = http.IncomingMessage, TRes extends http.ServerResponse = http.ServerResponse>(req: TReq, res: TRes | undefined, config: Options<TReq, TRes>): Promise<import("httpxy").ProxyTarget | undefined>;
|
package/dist/router.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import isPlainObject from 'is-plain-obj';
|
|
2
|
+
import { Debug } from './debug.js';
|
|
3
|
+
const debug = Debug.extend('router');
|
|
4
|
+
export async function getTarget(req, res, config) {
|
|
5
|
+
let newTarget;
|
|
6
|
+
const router = config.router;
|
|
7
|
+
if (isPlainObject(router)) {
|
|
8
|
+
newTarget = getTargetFromProxyTable(req, router);
|
|
9
|
+
}
|
|
10
|
+
else if (typeof router === 'function') {
|
|
11
|
+
newTarget = await router(req, res, config);
|
|
12
|
+
}
|
|
13
|
+
return newTarget;
|
|
14
|
+
}
|
|
15
|
+
function getTargetFromProxyTable(req, table) {
|
|
16
|
+
let result;
|
|
17
|
+
const host = req.headers.host ?? '';
|
|
18
|
+
const path = req.url ?? '';
|
|
19
|
+
for (const [key, value] of Object.entries(table)) {
|
|
20
|
+
if (containsPath(key)) {
|
|
21
|
+
if (isHostAndPathKey(key)) {
|
|
22
|
+
const [keyHost, keyPath] = splitHostAndPathKey(key);
|
|
23
|
+
// SECURITY: host+path keys must match exact host + path prefix.
|
|
24
|
+
if (host === keyHost && path.startsWith(keyPath)) {
|
|
25
|
+
// match 'localhost:3000/api'
|
|
26
|
+
result = value;
|
|
27
|
+
debug('match: "%s" -> "%s"', key, result);
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
if (path.startsWith(key)) {
|
|
33
|
+
// match '/api'
|
|
34
|
+
result = value;
|
|
35
|
+
debug('match: "%s" -> "%s"', key, result);
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
if (key === host) {
|
|
42
|
+
// match 'localhost:3000'
|
|
43
|
+
result = value;
|
|
44
|
+
debug('match: "%s" -> "%s"', host, result);
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
51
|
+
function containsPath(v) {
|
|
52
|
+
return v.indexOf('/') > -1;
|
|
53
|
+
}
|
|
54
|
+
function isHostAndPathKey(v) {
|
|
55
|
+
return containsPath(v) && !v.startsWith('/');
|
|
56
|
+
}
|
|
57
|
+
function splitHostAndPathKey(v) {
|
|
58
|
+
const firstSlash = v.indexOf('/');
|
|
59
|
+
return [v.slice(0, firstSlash), v.slice(firstSlash)];
|
|
60
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getStatusCode(errorCode: string): number;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export function getStatusCode(errorCode) {
|
|
2
|
+
let statusCode;
|
|
3
|
+
if (/HPE_INVALID/.test(errorCode)) {
|
|
4
|
+
statusCode = 502;
|
|
5
|
+
return statusCode;
|
|
6
|
+
}
|
|
7
|
+
if (/HPM_ERR_INVALID_MULTIPART_/.test(errorCode)) {
|
|
8
|
+
statusCode = 400;
|
|
9
|
+
return statusCode;
|
|
10
|
+
}
|
|
11
|
+
switch (errorCode) {
|
|
12
|
+
case 'ECONNRESET':
|
|
13
|
+
case 'ENOTFOUND':
|
|
14
|
+
case 'ECONNREFUSED':
|
|
15
|
+
case 'ETIMEDOUT':
|
|
16
|
+
statusCode = 504;
|
|
17
|
+
break;
|
|
18
|
+
default:
|
|
19
|
+
statusCode = 500;
|
|
20
|
+
break;
|
|
21
|
+
}
|
|
22
|
+
return statusCode;
|
|
23
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Based on definition by DefinitelyTyped:
|
|
3
|
+
* https://github.com/DefinitelyTyped/DefinitelyTyped/blob/6f529c6c67a447190f86bfbf894d1061e41e07b7/types/http-proxy-middleware/index.d.ts
|
|
4
|
+
*/
|
|
5
|
+
import type * as http from 'node:http';
|
|
6
|
+
import type * as net from 'node:net';
|
|
7
|
+
import type { ProxyServer, ProxyServerOptions } from 'httpxy';
|
|
8
|
+
export type NextFunction<T = (err?: any) => void> = T;
|
|
9
|
+
export interface RequestHandler<TReq extends http.IncomingMessage = http.IncomingMessage, TRes extends http.ServerResponse = http.ServerResponse, TNext = NextFunction> {
|
|
10
|
+
(req: TReq, res: TRes, next?: TNext): Promise<void>;
|
|
11
|
+
upgrade: (req: TReq, socket: net.Socket, head: Buffer) => void;
|
|
12
|
+
}
|
|
13
|
+
export type Filter<TReq extends http.IncomingMessage = http.IncomingMessage> = string | string[] | ((pathname: string, req: TReq) => boolean | string | RegExpMatchArray | null);
|
|
14
|
+
/**
|
|
15
|
+
* @see {@link https://github.com/chimurai/http-proxy-middleware/tree/master#defineplugin-helper `definePlugin()`} to define a http-proxy-middleware plugin.
|
|
16
|
+
*/
|
|
17
|
+
export interface Plugin<TReq extends http.IncomingMessage = http.IncomingMessage, TRes extends http.ServerResponse = http.ServerResponse> {
|
|
18
|
+
(proxyServer: ProxyServer<TReq, TRes>, options: Options<TReq, TRes>): void;
|
|
19
|
+
}
|
|
20
|
+
export interface OnProxyEvent<TReq extends http.IncomingMessage = http.IncomingMessage, TRes extends http.ServerResponse = http.ServerResponse> {
|
|
21
|
+
error?: (err: Error, req: TReq, res: TRes | net.Socket, target?: string | Partial<URL>) => void;
|
|
22
|
+
proxyReq?: (proxyReq: http.ClientRequest, req: TReq, res: TRes, options: ProxyServerOptions) => void;
|
|
23
|
+
proxyReqWs?: (proxyReq: http.ClientRequest, req: TReq, socket: net.Socket, options: ProxyServerOptions, head: any) => void;
|
|
24
|
+
proxyRes?: (proxyRes: TReq, req: TReq, res: TRes) => void | Promise<void>;
|
|
25
|
+
open?: (proxySocket: net.Socket) => void;
|
|
26
|
+
close?: (proxyRes: TReq, proxySocket: net.Socket, proxyHead: any) => void;
|
|
27
|
+
start?: (req: TReq, res: TRes, target: string | Partial<URL>) => void;
|
|
28
|
+
end?: (req: TReq, res: TRes, proxyRes: TReq) => void;
|
|
29
|
+
econnreset?: (err: Error, req: TReq, res: TRes, target: string | Partial<URL>) => void;
|
|
30
|
+
}
|
|
31
|
+
export type Logger = Pick<Console, 'info' | 'warn' | 'error'>;
|
|
32
|
+
export type PathRewriteConfig<TReq extends http.IncomingMessage = http.IncomingMessage, TRes extends http.ServerResponse = http.ServerResponse> = {
|
|
33
|
+
[regexp: string]: string;
|
|
34
|
+
} | ((path: string, req: TReq,
|
|
35
|
+
/** `res` is undefined in WebSocket upgrade flows. */
|
|
36
|
+
res?: TRes | undefined, options?: Options<TReq, TRes>) => string | undefined) | ((path: string, req: TReq,
|
|
37
|
+
/** `res` is undefined in WebSocket upgrade flows. */
|
|
38
|
+
res?: TRes | undefined, options?: Options<TReq, TRes>) => Promise<string | undefined>);
|
|
39
|
+
export interface Options<TReq extends http.IncomingMessage = http.IncomingMessage, TRes extends http.ServerResponse = http.ServerResponse> extends ProxyServerOptions {
|
|
40
|
+
/**
|
|
41
|
+
* Narrow down requests to proxy or not.
|
|
42
|
+
* Filter on {@link http.IncomingMessage.url `pathname`} which is relative to the proxy's "mounting" point in the server.
|
|
43
|
+
* Or use the {@link http.IncomingMessage `req`} object for more complex filtering.
|
|
44
|
+
* @link https://github.com/chimurai/http-proxy-middleware/blob/master/recipes/pathFilter.md
|
|
45
|
+
* @since v3.0.0
|
|
46
|
+
*/
|
|
47
|
+
pathFilter?: Filter<TReq>;
|
|
48
|
+
/**
|
|
49
|
+
* Modify request paths before requests are send to the target.
|
|
50
|
+
* @example
|
|
51
|
+
* ```js
|
|
52
|
+
* createProxyMiddleware({
|
|
53
|
+
* pathRewrite: {
|
|
54
|
+
* '^/api/old-path': '/api/new-path', // rewrite path
|
|
55
|
+
* }
|
|
56
|
+
* });
|
|
57
|
+
* ```
|
|
58
|
+
* @since v0.15.0
|
|
59
|
+
* @since v0.21.0 - support `async` function
|
|
60
|
+
* @since v4.1.0 - `res` and `options` parameters added to custom function
|
|
61
|
+
*
|
|
62
|
+
* @link https://github.com/chimurai/http-proxy-middleware/blob/master/recipes/pathRewrite.md
|
|
63
|
+
*/
|
|
64
|
+
pathRewrite?: PathRewriteConfig<TReq, TRes>;
|
|
65
|
+
/**
|
|
66
|
+
* Access the internal `httpxy` server instance to customize behavior
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```js
|
|
70
|
+
* createProxyMiddleware({
|
|
71
|
+
* plugins: [(proxyServer, options) => {
|
|
72
|
+
* proxyServer.on('error', (error, req, res) => {
|
|
73
|
+
* console.error(error);
|
|
74
|
+
* });
|
|
75
|
+
* }]
|
|
76
|
+
* });
|
|
77
|
+
* ```
|
|
78
|
+
* @link https://github.com/chimurai/http-proxy-middleware#plugins-array
|
|
79
|
+
* @since v3.0.0
|
|
80
|
+
*/
|
|
81
|
+
plugins?: Plugin<TReq, TRes>[];
|
|
82
|
+
/**
|
|
83
|
+
* Eject pre-configured plugins.
|
|
84
|
+
* NOTE: register your own error handlers to prevent server from crashing.
|
|
85
|
+
*
|
|
86
|
+
* @link https://github.com/chimurai/http-proxy-middleware#ejectplugins-boolean-default-false
|
|
87
|
+
* @since v3.0.0
|
|
88
|
+
*/
|
|
89
|
+
ejectPlugins?: boolean;
|
|
90
|
+
/**
|
|
91
|
+
* Listen to `httpxy` events
|
|
92
|
+
* @see {@link OnProxyEvent} for available events
|
|
93
|
+
* @example
|
|
94
|
+
* ```js
|
|
95
|
+
* createProxyMiddleware({
|
|
96
|
+
* on: {
|
|
97
|
+
* error: (error, req, res, target) => {
|
|
98
|
+
* console.error(error);
|
|
99
|
+
* }
|
|
100
|
+
* }
|
|
101
|
+
* });
|
|
102
|
+
* ```
|
|
103
|
+
* @link https://github.com/chimurai/http-proxy-middleware/blob/master/recipes/proxy-events.md
|
|
104
|
+
* @since v3.0.0
|
|
105
|
+
*/
|
|
106
|
+
on?: OnProxyEvent<TReq, TRes>;
|
|
107
|
+
/**
|
|
108
|
+
* Dynamically set the {@link Options.target `options.target`}.
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```js
|
|
112
|
+
* createProxyMiddleware({
|
|
113
|
+
* router: async (req, res, options) => {
|
|
114
|
+
* return 'http://127:0.0.1:3000';
|
|
115
|
+
* }
|
|
116
|
+
* });
|
|
117
|
+
* ```
|
|
118
|
+
*
|
|
119
|
+
* @since v0.16.0
|
|
120
|
+
* @since v4.1.0 - `res` and `options` parameters added to router function signature
|
|
121
|
+
*
|
|
122
|
+
* NOTE: `res` is undefined in WebSocket upgrade flows.
|
|
123
|
+
*
|
|
124
|
+
* @link https://github.com/chimurai/http-proxy-middleware/blob/master/recipes/router.md
|
|
125
|
+
*/
|
|
126
|
+
router?: Record<string, ProxyServerOptions['target']> | ((req: TReq, res: TRes | undefined, options: Options<TReq, TRes>) => ProxyServerOptions['target']) | ((req: TReq, res: TRes | undefined, options: Options<TReq, TRes>) => Promise<ProxyServerOptions['target']>);
|
|
127
|
+
/**
|
|
128
|
+
* Log information from http-proxy-middleware
|
|
129
|
+
* @example
|
|
130
|
+
* ```js
|
|
131
|
+
* createProxyMiddleware({
|
|
132
|
+
* logger: console
|
|
133
|
+
* });
|
|
134
|
+
* ```
|
|
135
|
+
* @link https://github.com/chimurai/http-proxy-middleware/blob/master/recipes/logger.md
|
|
136
|
+
* @since v3.0.0
|
|
137
|
+
*/
|
|
138
|
+
logger?: Logger;
|
|
139
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { URL } from 'url';
|
|
2
|
+
export function createUrl({ protocol, host, port, path }) {
|
|
3
|
+
// wrap IPv6 host in brackets
|
|
4
|
+
const ipv6Host = host?.includes(':') ? `[${host}]` : host;
|
|
5
|
+
// use fallback values to create a valid URL (protocol: 'undefined:', host: '[::]')
|
|
6
|
+
// nock v13 issue: protocol and host are undefined (https://github.com/chimurai/http-proxy-middleware/issues/1035)
|
|
7
|
+
// nock v14+ seems to return protocol and host correctly
|
|
8
|
+
const base = `${protocol || 'undefined:'}//${ipv6Host || '[::]'}`;
|
|
9
|
+
const url = new URL(base);
|
|
10
|
+
if (port) {
|
|
11
|
+
url.port = port;
|
|
12
|
+
}
|
|
13
|
+
if (path) {
|
|
14
|
+
url.pathname = path;
|
|
15
|
+
}
|
|
16
|
+
return url;
|
|
17
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getFunctionName(fn: Function): string;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type * as http from 'node:http';
|
|
2
|
+
import type { Options } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Normalize bracketed IPv6 URL targets into unbracketed host options.
|
|
5
|
+
*
|
|
6
|
+
* RFC 2732 defines the URL syntax for literal IPv6 addresses as bracketed
|
|
7
|
+
* host references (for example `http://[::1]:8080/path` where host is
|
|
8
|
+
* `[::1]`).
|
|
9
|
+
*
|
|
10
|
+
* `httpxy` resolves bracketed hostnames (for example `[::1]`) via DNS,
|
|
11
|
+
* which can fail for IPv6 literals. This converts string/URL `target` and
|
|
12
|
+
* `forward` values into object form with `hostname: ::1` (brackets removed)
|
|
13
|
+
* so the address can be connected directly.
|
|
14
|
+
*
|
|
15
|
+
* Reference: RFC 2732, Section 2 (Literal IPv6 Address Format in URL's)
|
|
16
|
+
* https://www.ietf.org/rfc/rfc2732.txt
|
|
17
|
+
*
|
|
18
|
+
* The provided options object is mutated in place.
|
|
19
|
+
*/
|
|
20
|
+
export declare function normalizeIPv6LiteralTargets<TReq extends http.IncomingMessage = http.IncomingMessage, TRes extends http.ServerResponse = http.ServerResponse>(options: Options<TReq, TRes>): void;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { Debug } from '../debug.js';
|
|
2
|
+
const debug = Debug.extend('ipv6');
|
|
3
|
+
/**
|
|
4
|
+
* Normalize bracketed IPv6 URL targets into unbracketed host options.
|
|
5
|
+
*
|
|
6
|
+
* RFC 2732 defines the URL syntax for literal IPv6 addresses as bracketed
|
|
7
|
+
* host references (for example `http://[::1]:8080/path` where host is
|
|
8
|
+
* `[::1]`).
|
|
9
|
+
*
|
|
10
|
+
* `httpxy` resolves bracketed hostnames (for example `[::1]`) via DNS,
|
|
11
|
+
* which can fail for IPv6 literals. This converts string/URL `target` and
|
|
12
|
+
* `forward` values into object form with `hostname: ::1` (brackets removed)
|
|
13
|
+
* so the address can be connected directly.
|
|
14
|
+
*
|
|
15
|
+
* Reference: RFC 2732, Section 2 (Literal IPv6 Address Format in URL's)
|
|
16
|
+
* https://www.ietf.org/rfc/rfc2732.txt
|
|
17
|
+
*
|
|
18
|
+
* The provided options object is mutated in place.
|
|
19
|
+
*/
|
|
20
|
+
export function normalizeIPv6LiteralTargets(options) {
|
|
21
|
+
options.target = normalizeIPv6ProxyTarget(options.target, 'target');
|
|
22
|
+
options.forward = normalizeIPv6ProxyTarget(options.forward, 'forward');
|
|
23
|
+
}
|
|
24
|
+
function normalizeIPv6ProxyTarget(target, optionName) {
|
|
25
|
+
const targetUrl = toTargetUrl(target);
|
|
26
|
+
if (targetUrl && isBracketedIPv6Hostname(targetUrl.hostname)) {
|
|
27
|
+
const normalizedHostname = normalizeIPv6DestinationHostname(stripBrackets(targetUrl.hostname));
|
|
28
|
+
debug('normalized IPv6 "%s" %s', optionName, target);
|
|
29
|
+
const auth = targetUrl.username || targetUrl.password
|
|
30
|
+
? `${targetUrl.username}:${targetUrl.password}`
|
|
31
|
+
: undefined;
|
|
32
|
+
return {
|
|
33
|
+
hostname: normalizedHostname,
|
|
34
|
+
auth,
|
|
35
|
+
pathname: targetUrl.pathname,
|
|
36
|
+
port: targetUrl.port,
|
|
37
|
+
protocol: targetUrl.protocol,
|
|
38
|
+
search: targetUrl.search,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
return target;
|
|
42
|
+
}
|
|
43
|
+
function toTargetUrl(target) {
|
|
44
|
+
if (typeof target === 'string') {
|
|
45
|
+
return new URL(target);
|
|
46
|
+
}
|
|
47
|
+
if (target instanceof URL) {
|
|
48
|
+
return target;
|
|
49
|
+
}
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
function isBracketedIPv6Hostname(hostname) {
|
|
53
|
+
return hostname.startsWith('[') && hostname.endsWith(']');
|
|
54
|
+
}
|
|
55
|
+
function stripBrackets(hostname) {
|
|
56
|
+
return hostname.replace(/^\[|\]$/g, '');
|
|
57
|
+
}
|
|
58
|
+
function normalizeIPv6DestinationHostname(hostname) {
|
|
59
|
+
// The unspecified address (::) is not a routable destination for outbound client requests.
|
|
60
|
+
// Treat it as loopback so a target like http://[::]:port reaches local IPv6 listeners.
|
|
61
|
+
if (hostname === '::') {
|
|
62
|
+
debug('normalizing hostname unspecified IPv6 address (::) to loopback (::1)');
|
|
63
|
+
return '::1';
|
|
64
|
+
}
|
|
65
|
+
return hostname;
|
|
66
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function sanitize(input: string | undefined): string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,122 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ohos-ports/http-proxy-middleware",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "4.2.0-beta.1",
|
|
4
|
+
"description": "The one-liner node.js proxy middleware for connect, express, next.js and more",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"browser-sync",
|
|
7
|
+
"connect",
|
|
8
|
+
"cors",
|
|
9
|
+
"express",
|
|
10
|
+
"fastify",
|
|
11
|
+
"grunt-contrib-connect",
|
|
12
|
+
"gulp",
|
|
13
|
+
"hono",
|
|
14
|
+
"http",
|
|
15
|
+
"https",
|
|
16
|
+
"middleware",
|
|
17
|
+
"next.js",
|
|
18
|
+
"polka",
|
|
19
|
+
"proxy",
|
|
20
|
+
"reverse",
|
|
21
|
+
"websocket",
|
|
22
|
+
"ws"
|
|
23
|
+
],
|
|
24
|
+
"homepage": "https://github.com/chimurai/http-proxy-middleware#readme",
|
|
25
|
+
"bugs": {
|
|
26
|
+
"url": "https://github.com/ohos-ports/ohos-ports/issues"
|
|
27
|
+
},
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"author": "Steven Chim",
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "https://github.com/ohos-ports/ohos-ports.git",
|
|
33
|
+
"directory": "ports/http-proxy-middleware/4.2.0"
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"dist"
|
|
37
|
+
],
|
|
38
|
+
"type": "module",
|
|
39
|
+
"main": "dist/index.js",
|
|
40
|
+
"types": "dist/index.d.ts",
|
|
41
|
+
"exports": {
|
|
42
|
+
".": {
|
|
43
|
+
"types": "./dist/index.d.ts",
|
|
44
|
+
"import": "./dist/index.js",
|
|
45
|
+
"default": "./dist/index.js"
|
|
46
|
+
},
|
|
47
|
+
"./hono": {
|
|
48
|
+
"types": "./dist/index-hono.d.ts",
|
|
49
|
+
"import": "./dist/index-hono.js",
|
|
50
|
+
"default": "./dist/index-hono.js"
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"publishConfig": {
|
|
54
|
+
"provenance": true
|
|
55
|
+
},
|
|
56
|
+
"scripts": {
|
|
57
|
+
"clean": "rm -rf dist coverage tsconfig.tsbuildinfo .eslintcache",
|
|
58
|
+
"install:all": "yarn && (cd examples && yarn)",
|
|
59
|
+
"lint": "yarn format && yarn eslint",
|
|
60
|
+
"lint:fix": "yarn format:fix && yarn eslint:fix",
|
|
61
|
+
"eslint": "eslint --cache '**/*.{js,ts,mjs,mts}'",
|
|
62
|
+
"eslint:fix": "yarn eslint --fix",
|
|
63
|
+
"format": "oxfmt --list-different \"**/*.{js,ts,mjs,mts,md,yml,json,html}\"",
|
|
64
|
+
"format:fix": "oxfmt --write \"**/*.{js,ts,mjs,mts,md,yml,json,html}\"",
|
|
65
|
+
"build": "tsc --build",
|
|
66
|
+
"test": "vitest run",
|
|
67
|
+
"test:types": "tsc --project tsconfig.test.json --noEmit",
|
|
68
|
+
"coverage": "vitest run --coverage",
|
|
69
|
+
"prepare": "husky",
|
|
70
|
+
"prepack": "yarn clean && yarn test && yarn build",
|
|
71
|
+
"spellcheck": "npx --yes cspell --show-context --show-suggestions '**/*.*'"
|
|
72
|
+
},
|
|
73
|
+
"dependencies": {
|
|
74
|
+
"debug": "^4.4.3",
|
|
75
|
+
"httpxy": "^0.5.4",
|
|
76
|
+
"is-glob": "^4.0.3",
|
|
77
|
+
"is-plain-obj": "^4.1.0",
|
|
78
|
+
"micromatch": "^4.0.8"
|
|
79
|
+
},
|
|
80
|
+
"devDependencies": {
|
|
81
|
+
"@commitlint/cli": "21.2.0",
|
|
82
|
+
"@commitlint/config-conventional": "21.2.0",
|
|
83
|
+
"@eslint/js": "10.0.1",
|
|
84
|
+
"@hono/node-server": "2.0.8",
|
|
85
|
+
"@types/debug": "4.1.13",
|
|
86
|
+
"@types/eslint": "9.6.1",
|
|
87
|
+
"@types/express": "5.0.6",
|
|
88
|
+
"@types/is-glob": "4.0.4",
|
|
89
|
+
"@types/micromatch": "4.0.10",
|
|
90
|
+
"@types/node": "26.1.0",
|
|
91
|
+
"@types/supertest": "7.2.0",
|
|
92
|
+
"@types/ws": "8.18.1",
|
|
93
|
+
"@vitest/coverage-v8": "4.1.9",
|
|
94
|
+
"body-parser": "2.3.0",
|
|
95
|
+
"eslint": "10.6.0",
|
|
96
|
+
"express": "5.2.1",
|
|
97
|
+
"get-port": "7.2.0",
|
|
98
|
+
"globals": "17.7.0",
|
|
99
|
+
"hono": "4.12.27",
|
|
100
|
+
"husky": "9.1.7",
|
|
101
|
+
"lint-staged": "17.0.8",
|
|
102
|
+
"mockttp": "4.4.2",
|
|
103
|
+
"msw": "2.14.6",
|
|
104
|
+
"nock": "14.0.16",
|
|
105
|
+
"open": "11.0.0",
|
|
106
|
+
"oxfmt": "0.57.0",
|
|
107
|
+
"pkg-pr-new": "0.0.75",
|
|
108
|
+
"supertest": "7.2.2",
|
|
109
|
+
"typescript": "6.0.3",
|
|
110
|
+
"typescript-eslint": "8.62.1",
|
|
111
|
+
"vitest": "4.1.9",
|
|
112
|
+
"ws": "8.21.0"
|
|
113
|
+
},
|
|
114
|
+
"commitlint": {
|
|
115
|
+
"extends": [
|
|
116
|
+
"@commitlint/config-conventional"
|
|
117
|
+
]
|
|
118
|
+
},
|
|
119
|
+
"engines": {
|
|
120
|
+
"node": "^22.15.0 || ^24.0.0 || >=26.0.0"
|
|
121
|
+
}
|
|
122
|
+
}
|