First commit

This commit is contained in:
2021-03-07 05:58:59 +01:00
commit 8204c6b556
18475 changed files with 3309357 additions and 0 deletions

View File

@@ -0,0 +1,140 @@
# Changelog
## [v0.19.2](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.19.2)
- chore(deps): http-proxy 1.18.1
## [v0.19.1](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.19.1)
- fix(log): handle case when error code is missing ([#303](https://github.com/chimurai/http-proxy-middleware/pull/303))
## [v0.19.0](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.19.0)
- feat(http-proxy): bump to v1.17.0 ([#261](https://github.com/chimurai/http-proxy-middleware/pull/261))
## [v0.18.0](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.18.0)
- fix(vulnerability): update micromatch to v3.x ([npm:braces:20180219](https://snyk.io/test/npm/http-proxy-middleware?tab=issues&severity=high&severity=medium&severity=low#npm:braces:20180219))
- test(node): drop node 0.x support ([#212](https://github.com/chimurai/http-proxy-middleware/pull/212))
## [v0.17.4](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.17.4)
- fix(ntlm authentication): fixed bug preventing proxying with ntlm authentication. ([#132](https://github.com/chimurai/http-proxy-middleware/pull/149)) (Thanks: [EladBezalel](https://github.com/EladBezalel), [oshri551](https://github.com/oshri551))
## [v0.17.3](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.17.3)
- fix(onError): improve default proxy error handling. http status codes (504, 502 and 500). ([#132](https://github.com/chimurai/http-proxy-middleware/pull/132)) ([graingert](https://github.com/graingert))
## [v0.17.2](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.17.2)
- feat(logging): improve error message & add link to Node errors page. ([#106](https://github.com/chimurai/http-proxy-middleware/pull/106)) ([cloudmu](https://github.com/cloudmu))
- feat(pathRewrite): path can be empty string. ([#110](https://github.com/chimurai/http-proxy-middleware/pull/110)) ([sunnylqm](https://github.com/sunnylqm))
- bug(websocket): memory leak when option 'ws:true' is used. ([#114](https://github.com/chimurai/http-proxy-middleware/pull/114)) ([julbra](https://github.com/julbra))
- chore(package.json): reduce package size. ([#109](https://github.com/chimurai/http-proxy-middleware/pull/109))
## [v0.17.1](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.17.1)
- fix(Express sub Router): 404 on non-proxy routes ([#94](https://github.com/chimurai/http-proxy-middleware/issues/94))
## [v0.17.0](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.17.0)
- fix(context matching): Use [RFC 3986 path](https://tools.ietf.org/html/rfc3986#section-3.3) in context matching. (excludes query parameters)
## [v0.16.0](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.16.0)
- deprecated(proxyTable): renamed `proxyTable` to `router`.
- feat(router): support for custom `router` function.
## [v0.15.2](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.15.2)
- fix(websocket): fixes websocket upgrade.
## [v0.15.1](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.15.1)
- feat(pathRewrite): expose `req` object to pathRewrite function.
- fix(websocket): fixes websocket upgrade when both config.ws and external .upgrade() are used.
## [v0.15.0](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.15.0)
- feat(pathRewrite): support for custom pathRewrite function.
## [v0.14.0](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.14.0)
- feat(proxy): support proxy creation without context.
- fix(connect mounting): use connect's `path` configuration to mount proxy.
## [v0.13.0](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.13.0)
- feat(context): custom context matcher; when simple `path` matching is not sufficient.
## [v0.12.0](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.12.0)
- add option `onProxyReqWs` (subscribe to http-proxy `proxyReqWs` event)
- add option `onOpen` (subscribe to http-proxy `open` event)
- add option `onClose` (subscribe to http-proxy `close` event)
## [v0.11.0](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.11.0)
- improved logging
## [v0.10.0](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.10.0)
- feat(proxyTable) - added proxyTable support for WebSockets.
- fixed(proxyTable) - ensure original path (not rewritten path) is being used when `proxyTable` is used in conjunction with `pathRewrite`.
## [v0.9.1](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.9.1)
- fix server crash when socket error not handled correctly.
## [v0.9.0](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.9.0)
- support subscribing to http-proxy `proxyReq` event ([trbngr](https://github.com/trbngr))
- add `logLevel` and `logProvider` support
## [v0.8.2](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.8.2)
- fix proxyError handler ([mTazelaar](https://github.com/mTazelaar))
## [v0.8.1](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.8.1)
- fix pathRewrite when `agent` is configured
## [v0.8.0](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.8.0)
- support external websocket upgrade
- fix websocket shorthand
## [v0.7.0](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.7.0)
- support shorthand syntax
- fix express/connect mounting
## [v0.6.0](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.6.0)
- support proxyTable
## [v0.5.0](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.5.0)
- support subscribing to http-proxy `error` event
- support subscribing to http-proxy `proxyRes` event
## [v0.4.0](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.4.0)
- support websocket
## [v0.3.0](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.3.0)
- support wildcard / glob
## [v0.2.0](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.2.0)
- support multiple paths
## [v0.1.0](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.1.0)
- support path rewrite
- deprecate proxyHost option
## [v0.0.5](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.0.5)
- initial release

22
hGameTest/node_modules/http-proxy-middleware/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 Steven Chim
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

491
hGameTest/node_modules/http-proxy-middleware/README.md generated vendored Normal file
View File

@@ -0,0 +1,491 @@
# http-proxy-middleware
[![Build Status](https://img.shields.io/travis/chimurai/http-proxy-middleware/master.svg?style=flat-square)](https://travis-ci.org/chimurai/http-proxy-middleware)
[![Coveralls](https://img.shields.io/coveralls/chimurai/http-proxy-middleware.svg?style=flat-square)](https://coveralls.io/r/chimurai/http-proxy-middleware)
[![dependency Status](https://img.shields.io/david/chimurai/http-proxy-middleware.svg?style=flat-square)](https://david-dm.org/chimurai/http-proxy-middleware#info=dependencies)
[![dependency Status](https://snyk.io/test/npm/http-proxy-middleware/badge.svg)](https://snyk.io/test/npm/http-proxy-middleware)
[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier)
Node.js proxying made simple. Configure proxy middleware with ease for [connect](https://github.com/senchalabs/connect), [express](https://github.com/strongloop/express), [browser-sync](https://github.com/BrowserSync/browser-sync) and [many more](#compatible-servers).
Powered by the popular Nodejitsu [`http-proxy`](https://github.com/nodejitsu/node-http-proxy). [![GitHub stars](https://img.shields.io/github/stars/nodejitsu/node-http-proxy.svg?style=social&label=Star)](https://github.com/nodejitsu/node-http-proxy)
## TL;DR
Proxy `/api` requests to `http://www.example.org`
```javascript
var express = require('express')
var proxy = require('http-proxy-middleware')
var app = express()
app.use('/api', proxy({ target: 'http://www.example.org', changeOrigin: true }))
app.listen(3000)
// http://localhost:3000/api/foo/bar -> http://www.example.org/api/foo/bar
```
_All_ `http-proxy` [options](https://github.com/nodejitsu/node-http-proxy#options) can be used, along with some extra `http-proxy-middleware` [options](#options).
:bulb: **Tip:** Set the option `changeOrigin` to `true` for [name-based virtual hosted sites](http://en.wikipedia.org/wiki/Virtual_hosting#Name-based).
## Table of Contents
<!-- MarkdownTOC autolink=true bracket=round depth=2 -->
- [Install](#install)
- [Core concept](#core-concept)
- [Example](#example)
- [Context matching](#context-matching)
- [Options](#options)
- [http-proxy-middleware options](#http-proxy-middleware-options)
- [http-proxy events](#http-proxy-events)
- [http-proxy options](#http-proxy-options)
- [Shorthand](#shorthand)
- [app.use\(path, proxy\)](#appusepath-proxy)
- [WebSocket](#websocket)
- [External WebSocket upgrade](#external-websocket-upgrade)
- [Working examples](#working-examples)
- [Recipes](#recipes)
- [Compatible servers](#compatible-servers)
- [Tests](#tests)
- [Changelog](#changelog)
- [License](#license)
<!-- /MarkdownTOC -->
## Install
```javascript
$ npm install --save-dev http-proxy-middleware
```
## Core concept
Proxy middleware configuration.
#### proxy([context,] config)
```javascript
var proxy = require('http-proxy-middleware')
var apiProxy = proxy('/api', { target: 'http://www.example.org' })
// \____/ \_____________________________/
// | |
// context options
// 'apiProxy' is now ready to be used as middleware in a server.
```
- **context**: Determine which requests should be proxied to the target host.
(more on [context matching](#context-matching))
- **options.target**: target host to proxy to. _(protocol + host)_
(full list of [`http-proxy-middleware` configuration options](#options))
#### proxy(uri [, config])
```javascript
// shorthand syntax for the example above:
var apiProxy = proxy('http://www.example.org/api')
```
More about the [shorthand configuration](#shorthand).
## Example
An example with `express` server.
```javascript
// include dependencies
var express = require('express')
var proxy = require('http-proxy-middleware')
// proxy middleware options
var options = {
target: 'http://www.example.org', // target host
changeOrigin: true, // needed for virtual hosted sites
ws: true, // proxy websockets
pathRewrite: {
'^/api/old-path': '/api/new-path', // rewrite path
'^/api/remove/path': '/path' // remove base path
},
router: {
// when request.headers.host == 'dev.localhost:3000',
// override target 'http://www.example.org' to 'http://localhost:8000'
'dev.localhost:3000': 'http://localhost:8000'
}
}
// create the proxy (without context)
var exampleProxy = proxy(options)
// mount `exampleProxy` in web server
var app = express()
app.use('/api', exampleProxy)
app.listen(3000)
```
## Context matching
Providing an alternative way to decide which requests should be proxied; In case you are not able to use the server's [`path` parameter](http://expressjs.com/en/4x/api.html#app.use) to mount the proxy or when you need more flexibility.
[RFC 3986 `path`](https://tools.ietf.org/html/rfc3986#section-3.3) is used for context matching.
```
foo://example.com:8042/over/there?name=ferret#nose
\_/ \______________/\_________/ \_________/ \__/
| | | | |
scheme authority path query fragment
```
- **path matching**
- `proxy({...})` - matches any path, all requests will be proxied.
- `proxy('/', {...})` - matches any path, all requests will be proxied.
- `proxy('/api', {...})` - matches paths starting with `/api`
- **multiple path matching**
- `proxy(['/api', '/ajax', '/someotherpath'], {...})`
- **wildcard path matching**
For fine-grained control you can use wildcard matching. Glob pattern matching is done by _micromatch_. Visit [micromatch](https://www.npmjs.com/package/micromatch) or [glob](https://www.npmjs.com/package/glob) for more globbing examples.
- `proxy('**', {...})` matches any path, all requests will be proxied.
- `proxy('**/*.html', {...})` matches any path which ends with `.html`
- `proxy('/*.html', {...})` matches paths directly under path-absolute
- `proxy('/api/**/*.html', {...})` matches requests ending with `.html` in the path of `/api`
- `proxy(['/api/**', '/ajax/**'], {...})` combine multiple patterns
- `proxy(['/api/**', '!**/bad.json'], {...})` exclusion
**Note**: In multiple path matching, you cannot use string paths and wildcard paths together.
- **custom matching**
For full control you can provide a custom function to determine which requests should be proxied or not.
```javascript
/**
* @return {Boolean}
*/
var filter = function(pathname, req) {
return pathname.match('^/api') && req.method === 'GET'
}
var apiProxy = proxy(filter, { target: 'http://www.example.org' })
```
## Options
### http-proxy-middleware options
- **option.pathRewrite**: object/function, rewrite target's url path. Object-keys will be used as _RegExp_ to match paths.
```javascript
// rewrite path
pathRewrite: {'^/old/api' : '/new/api'}
// remove path
pathRewrite: {'^/remove/api' : ''}
// add base path
pathRewrite: {'^/' : '/basepath/'}
// custom rewriting
pathRewrite: function (path, req) { return path.replace('/api', '/base/api') }
```
- **option.router**: object/function, re-target `option.target` for specific requests.
```javascript
// Use `host` and/or `path` to match requests. First match will be used.
// The order of the configuration matters.
router: {
'integration.localhost:3000' : 'http://localhost:8001', // host only
'staging.localhost:3000' : 'http://localhost:8002', // host only
'localhost:3000/api' : 'http://localhost:8003', // host + path
'/rest' : 'http://localhost:8004' // path only
}
// Custom router function
router: function(req) {
return 'http://localhost:8004';
}
```
- **option.logLevel**: string, ['debug', 'info', 'warn', 'error', 'silent']. Default: `'info'`
- **option.logProvider**: function, modify or replace log provider. Default: `console`.
```javascript
// simple replace
function logProvider(provider) {
// replace the default console log provider.
return require('winston')
}
```
```javascript
// verbose replacement
function logProvider(provider) {
var logger = new (require('winston')).Logger()
var myCustomProvider = {
log: logger.log,
debug: logger.debug,
info: logger.info,
warn: logger.warn,
error: logger.error
}
return myCustomProvider
}
```
- (DEPRECATED) **option.proxyHost**: Use `option.changeOrigin = true` instead.
- (DEPRECATED) **option.proxyTable**: Use `option.router` instead.
### http-proxy events
Subscribe to [http-proxy events](https://github.com/nodejitsu/node-http-proxy#listening-for-proxy-events):
- **option.onError**: function, subscribe to http-proxy's `error` event for custom error handling.
```javascript
function onError(err, req, res) {
res.writeHead(500, {
'Content-Type': 'text/plain'
})
res.end(
'Something went wrong. And we are reporting a custom error message.'
)
}
```
- **option.onProxyRes**: function, subscribe to http-proxy's `proxyRes` event.
```javascript
function onProxyRes(proxyRes, req, res) {
proxyRes.headers['x-added'] = 'foobar' // add new header to response
delete proxyRes.headers['x-removed'] // remove header from response
}
```
- **option.onProxyReq**: function, subscribe to http-proxy's `proxyReq` event.
```javascript
function onProxyReq(proxyReq, req, res) {
// add custom header to request
proxyReq.setHeader('x-added', 'foobar')
// or log the req
}
```
- **option.onProxyReqWs**: function, subscribe to http-proxy's `proxyReqWs` event.
```javascript
function onProxyReqWs(proxyReq, req, socket, options, head) {
// add custom header
proxyReq.setHeader('X-Special-Proxy-Header', 'foobar')
}
```
- **option.onOpen**: function, subscribe to http-proxy's `open` event.
```javascript
function onOpen(proxySocket) {
// listen for messages coming FROM the target here
proxySocket.on('data', hybiParseAndLogMessage)
}
```
- **option.onClose**: function, subscribe to http-proxy's `close` event.
```javascript
function onClose(res, socket, head) {
// view disconnected websocket connections
console.log('Client disconnected')
}
```
### http-proxy options
The following options are provided by the underlying [http-proxy](https://github.com/nodejitsu/node-http-proxy#options) library.
- **option.target**: url string to be parsed with the url module
- **option.forward**: url string to be parsed with the url module
- **option.agent**: object to be passed to http(s).request (see Node's [https agent](http://nodejs.org/api/https.html#https_class_https_agent) and [http agent](http://nodejs.org/api/http.html#http_class_http_agent) objects)
- **option.ssl**: object to be passed to https.createServer()
- **option.ws**: true/false: if you want to proxy websockets
- **option.xfwd**: true/false, adds x-forward headers
- **option.secure**: true/false, if you want to verify the SSL Certs
- **option.toProxy**: true/false, passes the absolute URL as the `path` (useful for proxying to proxies)
- **option.prependPath**: true/false, Default: true - specify whether you want to prepend the target's path to the proxy path
- **option.ignorePath**: true/false, Default: false - specify whether you want to ignore the proxy path of the incoming request (note: you will have to append / manually if required).
- **option.localAddress** : Local interface string to bind for outgoing connections
- **option.changeOrigin**: true/false, Default: false - changes the origin of the host header to the target URL
- **option.preserveHeaderKeyCase**: true/false, Default: false - specify whether you want to keep letter case of response header key
- **option.auth** : Basic authentication i.e. 'user:password' to compute an Authorization header.
- **option.hostRewrite**: rewrites the location hostname on (301/302/307/308) redirects.
- **option.autoRewrite**: rewrites the location host/port on (301/302/307/308) redirects based on requested host/port. Default: false.
- **option.protocolRewrite**: rewrites the location protocol on (301/302/307/308) redirects to 'http' or 'https'. Default: null.
- **option.cookieDomainRewrite**: rewrites domain of `set-cookie` headers. Possible values:
- `false` (default): disable cookie rewriting
- String: new domain, for example `cookieDomainRewrite: "new.domain"`. To remove the domain, use `cookieDomainRewrite: ""`.
- Object: mapping of domains to new domains, use `"*"` to match all domains.
For example keep one domain unchanged, rewrite one domain and remove other domains:
```
cookieDomainRewrite: {
"unchanged.domain": "unchanged.domain",
"old.domain": "new.domain",
"*": ""
}
```
- **option.cookiePathRewrite**: rewrites path of `set-cookie` headers. Possible values:
- `false` (default): disable cookie rewriting
- String: new path, for example `cookiePathRewrite: "/newPath/"`. To remove the path, use `cookiePathRewrite: ""`. To set path to root use `cookiePathRewrite: "/"`.
- Object: mapping of paths to new paths, use `"*"` to match all paths.
For example, to keep one path unchanged, rewrite one path and remove other paths:
```
cookiePathRewrite: {
"/unchanged.path/": "/unchanged.path/",
"/old.path/": "/new.path/",
"*": ""
}
```
- **option.headers**: object, adds [request headers](https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Request_fields). (Example: `{host:'www.example.org'}`)
- **option.proxyTimeout**: timeout (in millis) when proxy receives no response from target
- **option.timeout**: timeout (in millis) for incoming requests
- **option.followRedirects**: true/false, Default: false - specify whether you want to follow redirects
- **option.selfHandleResponse** true/false, if set to true, none of the webOutgoing passes are called and it's your responsibility to appropriately return the response by listening and acting on the `proxyRes` event
- **option.buffer**: stream of data to send as the request body. Maybe you have some middleware that consumes the request stream before proxying it on e.g. If you read the body of a request into a field called 'req.rawbody' you could restream this field in the buffer option:
```
'use strict';
const streamify = require('stream-array');
const HttpProxy = require('http-proxy');
const proxy = new HttpProxy();
module.exports = (req, res, next) => {
proxy.web(req, res, {
target: 'http://localhost:4003/',
buffer: streamify(req.rawBody)
}, next);
};
```
## Shorthand
Use the shorthand syntax when verbose configuration is not needed. The `context` and `option.target` will be automatically configured when shorthand is used. Options can still be used if needed.
```javascript
proxy('http://www.example.org:8000/api')
// proxy('/api', {target: 'http://www.example.org:8000'});
proxy('http://www.example.org:8000/api/books/*/**.json')
// proxy('/api/books/*/**.json', {target: 'http://www.example.org:8000'});
proxy('http://www.example.org:8000/api', { changeOrigin: true })
// proxy('/api', {target: 'http://www.example.org:8000', changeOrigin: true});
```
### app.use(path, proxy)
If you want to use the server's `app.use` `path` parameter to match requests;
Create and mount the proxy without the http-proxy-middleware `context` parameter:
```javascript
app.use('/api', proxy({ target: 'http://www.example.org', changeOrigin: true }))
```
`app.use` documentation:
- express: http://expressjs.com/en/4x/api.html#app.use
- connect: https://github.com/senchalabs/connect#mount-middleware
## WebSocket
```javascript
// verbose api
proxy('/', { target: 'http://echo.websocket.org', ws: true })
// shorthand
proxy('http://echo.websocket.org', { ws: true })
// shorter shorthand
proxy('ws://echo.websocket.org')
```
### External WebSocket upgrade
In the previous WebSocket examples, http-proxy-middleware relies on a initial http request in order to listen to the http `upgrade` event. If you need to proxy WebSockets without the initial http request, you can subscribe to the server's http `upgrade` event manually.
```javascript
var wsProxy = proxy('ws://echo.websocket.org', { changeOrigin: true })
var app = express()
app.use(wsProxy)
var server = app.listen(3000)
server.on('upgrade', wsProxy.upgrade) // <-- subscribe to http 'upgrade'
```
## Working examples
View and play around with [working examples](https://github.com/chimurai/http-proxy-middleware/tree/master/examples).
- Browser-Sync ([example source](https://github.com/chimurai/http-proxy-middleware/tree/master/examples/browser-sync/index.js))
- express ([example source](https://github.com/chimurai/http-proxy-middleware/tree/master/examples/express/index.js))
- connect ([example source](https://github.com/chimurai/http-proxy-middleware/tree/master/examples/connect/index.js))
- WebSocket ([example source](https://github.com/chimurai/http-proxy-middleware/tree/master/examples/websocket/index.js))
## Recipes
View the [recipes](https://github.com/chimurai/http-proxy-middleware/tree/master/recipes) for common use cases.
## Compatible servers
`http-proxy-middleware` is compatible with the following servers:
- [connect](https://www.npmjs.com/package/connect)
- [express](https://www.npmjs.com/package/express)
- [browser-sync](https://www.npmjs.com/package/browser-sync)
- [lite-server](https://www.npmjs.com/package/lite-server)
- [grunt-contrib-connect](https://www.npmjs.com/package/grunt-contrib-connect)
- [grunt-browser-sync](https://www.npmjs.com/package/grunt-browser-sync)
- [gulp-connect](https://www.npmjs.com/package/gulp-connect)
- [gulp-webserver](https://www.npmjs.com/package/gulp-webserver)
Sample implementations can be found in the [server recipes](https://github.com/chimurai/http-proxy-middleware/tree/master/recipes/servers.md).
## Tests
Run the test suite:
```bash
# install dependencies
$ npm install
# linting
$ npm run lint
# unit tests
$ npm test
# code coverage
$ npm run cover
```
## Changelog
- [View changelog](https://github.com/chimurai/http-proxy-middleware/blob/master/CHANGELOG.md)
## License
The MIT License (MIT)
Copyright (c) 2015-2018 Steven Chim

View File

@@ -0,0 +1,5 @@
var HPM = require('./lib')
module.exports = function(context, opts) {
return new HPM(context, opts)
}

View File

@@ -0,0 +1,129 @@
var _ = require('lodash')
var url = require('url')
var ERRORS = require('./errors')
var logger = require('./logger').getInstance()
module.exports = {
createConfig: createConfig
}
function createConfig(context, opts) {
// structure of config object to be returned
var config = {
context: undefined,
options: {}
}
// app.use('/api', proxy({target:'http://localhost:9000'}));
if (isContextless(context, opts)) {
config.context = '/'
config.options = _.assign(config.options, context)
// app.use('/api', proxy('http://localhost:9000'));
// app.use(proxy('http://localhost:9000/api'));
} else if (isStringShortHand(context)) {
var oUrl = url.parse(context)
var target = [oUrl.protocol, '//', oUrl.host].join('')
config.context = oUrl.pathname || '/'
config.options = _.assign(config.options, { target: target }, opts)
if (oUrl.protocol === 'ws:' || oUrl.protocol === 'wss:') {
config.options.ws = true
}
// app.use('/api', proxy({target:'http://localhost:9000'}));
} else {
config.context = context
config.options = _.assign(config.options, opts)
}
configureLogger(config.options)
if (!config.options.target) {
throw new Error(ERRORS.ERR_CONFIG_FACTORY_TARGET_MISSING)
}
// Legacy option.proxyHost
config.options = mapLegacyProxyHostOption(config.options)
// Legacy option.proxyTable > option.router
config.options = mapLegacyProxyTableOption(config.options)
return config
}
/**
* Checks if a String only target/config is provided.
* This can be just the host or with the optional path.
*
* @example
* app.use('/api', proxy('http://localhost:9000'));
app.use(proxy('http://localhost:9000/api'));
*
* @param {String} context [description]
* @return {Boolean} [description]
*/
function isStringShortHand(context) {
if (_.isString(context)) {
return !!url.parse(context).host
}
}
/**
* Checks if a Object only config is provided, without a context.
* In this case the all paths will be proxied.
*
* @example
* app.use('/api', proxy({target:'http://localhost:9000'}));
*
* @param {Object} context [description]
* @param {*} opts [description]
* @return {Boolean} [description]
*/
function isContextless(context, opts) {
return _.isPlainObject(context) && _.isEmpty(opts)
}
function mapLegacyProxyHostOption(options) {
// set options.headers.host when option.proxyHost is provided
if (options.proxyHost) {
logger.warn('*************************************')
logger.warn('[HPM] Deprecated "option.proxyHost"')
logger.warn(
' Use "option.changeOrigin" or "option.headers.host" instead'
)
logger.warn(' "option.proxyHost" will be removed in future release.')
logger.warn('*************************************')
options.headers = options.headers || {}
options.headers.host = options.proxyHost
}
return options
}
// Warn deprecated proxyTable api usage
function mapLegacyProxyTableOption(options) {
if (options.proxyTable) {
logger.warn('*************************************')
logger.warn('[HPM] Deprecated "option.proxyTable"')
logger.warn(' Use "option.router" instead')
logger.warn(' "option.proxyTable" will be removed in future release.')
logger.warn('*************************************')
options.router = _.clone(options.proxyTable)
_.omit(options, 'proxyTable')
}
return options
}
function configureLogger(options) {
if (options.logLevel) {
logger.setLevel(options.logLevel)
}
if (options.logProvider) {
logger.setProvider(options.logProvider)
}
}

View File

@@ -0,0 +1,94 @@
var _ = require('lodash')
var url = require('url')
var isGlob = require('is-glob')
var micromatch = require('micromatch')
var ERRORS = require('./errors')
module.exports = {
match: matchContext
}
function matchContext(context, uri, req) {
// single path
if (isStringPath(context)) {
return matchSingleStringPath(context, uri)
}
// single glob path
if (isGlobPath(context)) {
return matchSingleGlobPath(context, uri)
}
// multi path
if (Array.isArray(context)) {
if (context.every(isStringPath)) {
return matchMultiPath(context, uri)
}
if (context.every(isGlobPath)) {
return matchMultiGlobPath(context, uri)
}
throw new Error(ERRORS.ERR_CONTEXT_MATCHER_INVALID_ARRAY)
}
// custom matching
if (_.isFunction(context)) {
var pathname = getUrlPathName(uri)
return context(pathname, req)
}
throw new Error(ERRORS.ERR_CONTEXT_MATCHER_GENERIC)
}
/**
* @param {String} context '/api'
* @param {String} uri 'http://example.org/api/b/c/d.html'
* @return {Boolean}
*/
function matchSingleStringPath(context, uri) {
var pathname = getUrlPathName(uri)
return pathname.indexOf(context) === 0
}
function matchSingleGlobPath(pattern, uri) {
var pathname = getUrlPathName(uri)
var matches = micromatch(pathname, pattern)
return matches && matches.length > 0
}
function matchMultiGlobPath(patternList, uri) {
return matchSingleGlobPath(patternList, uri)
}
/**
* @param {String} contextList ['/api', '/ajax']
* @param {String} uri 'http://example.org/api/b/c/d.html'
* @return {Boolean}
*/
function matchMultiPath(contextList, uri) {
for (var i = 0; i < contextList.length; i++) {
var context = contextList[i]
if (matchSingleStringPath(context, uri)) {
return true
}
}
return false
}
/**
* Parses URI and returns RFC 3986 path
*
* @param {String} uri from req.url
* @return {String} RFC 3986 path
*/
function getUrlPathName(uri) {
return uri && url.parse(uri).pathname
}
function isStringPath(context) {
return _.isString(context) && !isGlob(context)
}
function isGlobPath(context) {
return isGlob(context)
}

View File

@@ -0,0 +1,12 @@
/* eslint-disable max-len */
module.exports = {
ERR_CONFIG_FACTORY_TARGET_MISSING:
'[HPM] Missing "target" option. Example: {target: "http://www.example.org"}',
ERR_CONTEXT_MATCHER_GENERIC:
'[HPM] Invalid context. Expecting something like: "/api" or ["/api", "/ajax"]',
ERR_CONTEXT_MATCHER_INVALID_ARRAY:
'[HPM] Invalid context. Expecting something like: ["/api", "/ajax"] or ["/api/**", "!**.html"]',
ERR_PATH_REWRITER_CONFIG:
'[HPM] Invalid pathRewrite config. Expecting object with pathRewrite config or a rewrite function'
}

View File

@@ -0,0 +1,82 @@
var _ = require('lodash')
var logger = require('./logger').getInstance()
module.exports = {
init: init,
getHandlers: getProxyEventHandlers
}
function init(proxy, opts) {
var handlers = getProxyEventHandlers(opts)
_.forIn(handlers, function(handler, eventName) {
proxy.on(eventName, handlers[eventName])
})
logger.debug('[HPM] Subscribed to http-proxy events: ', _.keys(handlers))
}
function getProxyEventHandlers(opts) {
// https://github.com/nodejitsu/node-http-proxy#listening-for-proxy-events
var proxyEvents = [
'error',
'proxyReq',
'proxyReqWs',
'proxyRes',
'open',
'close'
]
var handlers = {}
_.forEach(proxyEvents, function(event) {
// all handlers for the http-proxy events are prefixed with 'on'.
// loop through options and try to find these handlers
// and add them to the handlers object for subscription in init().
var eventName = _.camelCase('on ' + event)
var fnHandler = _.get(opts, eventName)
if (_.isFunction(fnHandler)) {
handlers[event] = fnHandler
}
})
// add default error handler in absence of error handler
if (!_.isFunction(handlers.error)) {
handlers.error = defaultErrorHandler
}
// add default close handler in absence of close handler
if (!_.isFunction(handlers.close)) {
handlers.close = logClose
}
return handlers
}
function defaultErrorHandler(err, req, res) {
var host = req.headers && req.headers.host
var code = err.code
if (res.writeHead && !res.headersSent) {
if (/HPE_INVALID/.test(code)) {
res.writeHead(502)
} else {
switch (code) {
case 'ECONNRESET':
case 'ENOTFOUND':
case 'ECONNREFUSED':
res.writeHead(504)
break
default:
res.writeHead(500)
}
}
}
res.end('Error occured while trying to proxy to: ' + host + req.url)
}
function logClose(req, socket, head) {
// view disconnected websocket connections
logger.info('[HPM] Client disconnected')
}

View File

@@ -0,0 +1,182 @@
var _ = require('lodash')
var httpProxy = require('http-proxy')
var configFactory = require('./config-factory')
var handlers = require('./handlers')
var contextMatcher = require('./context-matcher')
var PathRewriter = require('./path-rewriter')
var Router = require('./router')
var logger = require('./logger').getInstance()
var getArrow = require('./logger').getArrow
module.exports = HttpProxyMiddleware
function HttpProxyMiddleware(context, opts) {
// https://github.com/chimurai/http-proxy-middleware/issues/57
var wsUpgradeDebounced = _.debounce(handleUpgrade)
var wsInitialized = false
var config = configFactory.createConfig(context, opts)
var proxyOptions = config.options
// create proxy
var proxy = httpProxy.createProxyServer({})
logger.info(
'[HPM] Proxy created:',
config.context,
' -> ',
proxyOptions.target
)
var pathRewriter = PathRewriter.create(proxyOptions.pathRewrite) // returns undefined when "pathRewrite" is not provided
// attach handler to http-proxy events
handlers.init(proxy, proxyOptions)
// log errors for debug purpose
proxy.on('error', logError)
// https://github.com/chimurai/http-proxy-middleware/issues/19
// expose function to upgrade externally
middleware.upgrade = wsUpgradeDebounced
return middleware
function middleware(req, res, next) {
if (shouldProxy(config.context, req)) {
var activeProxyOptions = prepareProxyRequest(req)
proxy.web(req, res, activeProxyOptions)
} else {
next()
}
if (proxyOptions.ws === true) {
// use initial request to access the server object to subscribe to http upgrade event
catchUpgradeRequest(req.connection.server)
}
}
function catchUpgradeRequest(server) {
// subscribe once; don't subscribe on every request...
// https://github.com/chimurai/http-proxy-middleware/issues/113
if (!wsInitialized) {
server.on('upgrade', wsUpgradeDebounced)
wsInitialized = true
}
}
function handleUpgrade(req, socket, head) {
// set to initialized when used externally
wsInitialized = true
if (shouldProxy(config.context, req)) {
var activeProxyOptions = prepareProxyRequest(req)
proxy.ws(req, socket, head, activeProxyOptions)
logger.info('[HPM] Upgrading to WebSocket')
}
}
/**
* Determine whether request should be proxied.
*
* @private
* @param {String} context [description]
* @param {Object} req [description]
* @return {Boolean}
*/
function shouldProxy(context, req) {
var path = req.originalUrl || req.url
return contextMatcher.match(context, path, req)
}
/**
* Apply option.router and option.pathRewrite
* Order matters:
* Router uses original path for routing;
* NOT the modified path, after it has been rewritten by pathRewrite
* @param {Object} req
* @return {Object} proxy options
*/
function prepareProxyRequest(req) {
// https://github.com/chimurai/http-proxy-middleware/issues/17
// https://github.com/chimurai/http-proxy-middleware/issues/94
req.url = req.originalUrl || req.url
// store uri before it gets rewritten for logging
var originalPath = req.url
var newProxyOptions = _.assign({}, proxyOptions)
// Apply in order:
// 1. option.router
// 2. option.pathRewrite
__applyRouter(req, newProxyOptions)
__applyPathRewrite(req, pathRewriter)
// debug logging for both http(s) and websockets
if (proxyOptions.logLevel === 'debug') {
var arrow = getArrow(
originalPath,
req.url,
proxyOptions.target,
newProxyOptions.target
)
logger.debug(
'[HPM] %s %s %s %s',
req.method,
originalPath,
arrow,
newProxyOptions.target
)
}
return newProxyOptions
}
// Modify option.target when router present.
function __applyRouter(req, options) {
var newTarget
if (options.router) {
newTarget = Router.getTarget(req, options)
if (newTarget) {
logger.debug(
'[HPM] Router new target: %s -> "%s"',
options.target,
newTarget
)
options.target = newTarget
}
}
}
// rewrite path
function __applyPathRewrite(req, pathRewriter) {
if (pathRewriter) {
var path = pathRewriter(req.url, req)
if (typeof path === 'string') {
req.url = path
} else {
logger.info('[HPM] pathRewrite: No rewritten path found. (%s)', req.url)
}
}
}
function logError(err, req, res) {
var hostname =
(req.headers && req.headers.host) || (req.hostname || req.host) // (websocket) || (node0.10 || node 4/5)
var target = proxyOptions.target.host || proxyOptions.target
var errorMessage =
'[HPM] Error occurred while trying to proxy request %s from %s to %s (%s) (%s)'
var errReference =
'https://nodejs.org/api/errors.html#errors_common_system_errors' // link to Node Common Systems Errors page
logger.error(
errorMessage,
req.url,
hostname,
target,
err.code || err,
errReference
)
}
}

View File

@@ -0,0 +1,172 @@
var util = require('util')
var _ = require('lodash')
var loggerInstance
var defaultProvider = {
log: console.log,
debug: console.log, // use .log(); since console does not have .debug()
info: console.info,
warn: console.warn,
error: console.error
}
// log level 'weight'
var LEVELS = {
debug: 10,
info: 20,
warn: 30,
error: 50,
silent: 80
}
module.exports = {
// singleton
getInstance: function() {
if (!loggerInstance) {
loggerInstance = new Logger()
}
return loggerInstance
},
getArrow: getArrow
}
function Logger() {
var logLevel
var provider
var api = {
log: log,
debug: debug,
info: info,
warn: warn,
error: error,
setLevel: function(v) {
if (isValidLevel(v)) {
logLevel = v
}
},
setProvider: function(fn) {
if (fn && isValidProvider(fn)) {
provider = fn(defaultProvider)
}
}
}
init()
return api
function init() {
api.setLevel('info')
api.setProvider(function() {
return defaultProvider
})
}
// log will log messages, regardless of logLevels
function log() {
provider.log(_interpolate.apply(null, arguments))
}
function debug() {
if (_showLevel('debug')) {
provider.debug(_interpolate.apply(null, arguments))
}
}
function info() {
if (_showLevel('info')) {
provider.info(_interpolate.apply(null, arguments))
}
}
function warn() {
if (_showLevel('warn')) {
provider.warn(_interpolate.apply(null, arguments))
}
}
function error() {
if (_showLevel('error')) {
provider.error(_interpolate.apply(null, arguments))
}
}
/**
* Decide to log or not to log, based on the log levels 'weight'
* @param {String} showLevel [debug, info, warn, error, silent]
* @return {Boolean}
*/
function _showLevel(showLevel) {
var result = false
var currentLogLevel = LEVELS[logLevel]
if (currentLogLevel && currentLogLevel <= LEVELS[showLevel]) {
result = true
}
return result
}
// make sure logged messages and its data are return interpolated
// make it possible for additional log data, such date/time or custom prefix.
function _interpolate() {
var fn = _.spread(util.format)
var result = fn(_.slice(arguments))
return result
}
function isValidProvider(fnProvider) {
var result = true
if (fnProvider && !_.isFunction(fnProvider)) {
throw new Error('[HPM] Log provider config error. Expecting a function.')
}
return result
}
function isValidLevel(levelName) {
var validLevels = _.keys(LEVELS)
var isValid = _.includes(validLevels, levelName)
if (!isValid) {
throw new Error('[HPM] Log level error. Invalid logLevel.')
}
return isValid
}
}
/**
* -> normal proxy
* => router
* ~> pathRewrite
* ≈> router + pathRewrite
*
* @param {String} originalPath
* @param {String} newPath
* @param {String} originalTarget
* @param {String} newTarget
* @return {String}
*/
function getArrow(originalPath, newPath, originalTarget, newTarget) {
var arrow = ['>']
var isNewTarget = originalTarget !== newTarget // router
var isNewPath = originalPath !== newPath // pathRewrite
if (isNewPath && !isNewTarget) {
arrow.unshift('~')
} else if (!isNewPath && isNewTarget) {
arrow.unshift('=')
} else if (isNewPath && isNewTarget) {
arrow.unshift('≈')
} else {
arrow.unshift('-')
}
return arrow.join('')
}

View File

@@ -0,0 +1,79 @@
var _ = require('lodash')
var logger = require('./logger').getInstance()
var ERRORS = require('./errors')
module.exports = {
create: createPathRewriter
}
/**
* Create rewrite function, to cache parsed rewrite rules.
*
* @param {Object} rewriteConfig
* @return {Function} Function to rewrite paths; This function should accept `path` (request.url) as parameter
*/
function createPathRewriter(rewriteConfig) {
var rulesCache
if (!isValidRewriteConfig(rewriteConfig)) {
return
}
if (_.isFunction(rewriteConfig)) {
var customRewriteFn = rewriteConfig
return customRewriteFn
} else {
rulesCache = parsePathRewriteRules(rewriteConfig)
return rewritePath
}
function rewritePath(path) {
var result = path
_.forEach(rulesCache, function(rule) {
if (rule.regex.test(path)) {
result = result.replace(rule.regex, rule.value)
logger.debug('[HPM] Rewriting path from "%s" to "%s"', path, result)
return false
}
})
return result
}
}
function isValidRewriteConfig(rewriteConfig) {
if (_.isFunction(rewriteConfig)) {
return true
} else if (!_.isEmpty(rewriteConfig) && _.isPlainObject(rewriteConfig)) {
return true
} else if (
_.isUndefined(rewriteConfig) ||
_.isNull(rewriteConfig) ||
_.isEqual(rewriteConfig, {})
) {
return false
} else {
throw new Error(ERRORS.ERR_PATH_REWRITER_CONFIG)
}
}
function parsePathRewriteRules(rewriteConfig) {
var rules = []
if (_.isPlainObject(rewriteConfig)) {
_.forIn(rewriteConfig, function(value, key) {
rules.push({
regex: new RegExp(key),
value: rewriteConfig[key]
})
logger.info(
'[HPM] Proxy rewrite rule created: "%s" ~> "%s"',
key,
rewriteConfig[key]
)
})
}
return rules
}

View File

@@ -0,0 +1,51 @@
var _ = require('lodash')
var logger = require('./logger.js').getInstance()
module.exports = {
getTarget: getTarget
}
function getTarget(req, config) {
var newTarget
var router = config.router
if (_.isPlainObject(router)) {
newTarget = getTargetFromProxyTable(req, router)
} else if (_.isFunction(router)) {
newTarget = router(req)
}
return newTarget
}
function getTargetFromProxyTable(req, table) {
var result
var host = req.headers.host
var path = req.url
var hostAndPath = host + path
_.forIn(table, function(value, key) {
if (containsPath(key)) {
if (hostAndPath.indexOf(key) > -1) {
// match 'localhost:3000/api'
result = table[key]
logger.debug('[HPM] Router table match: "%s"', key)
return false
}
} else {
if (key === host) {
// match 'localhost:3000'
result = table[key]
logger.debug('[HPM] Router table match: "%s"', host)
return false
}
}
})
return result
}
function containsPath(v) {
return v.indexOf('/') > -1
}

View File

@@ -0,0 +1,108 @@
{
"_from": "http-proxy-middleware@^0.19.1",
"_id": "http-proxy-middleware@0.19.2",
"_inBundle": false,
"_integrity": "sha512-aYk1rTKqLTus23X3L96LGNCGNgWpG4cG0XoZIT1GUPhhulEHX/QalnO6Vbo+WmKWi4AL2IidjuC0wZtbpg0yhQ==",
"_location": "/http-proxy-middleware",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "http-proxy-middleware@^0.19.1",
"name": "http-proxy-middleware",
"escapedName": "http-proxy-middleware",
"rawSpec": "^0.19.1",
"saveSpec": null,
"fetchSpec": "^0.19.1"
},
"_requiredBy": [
"/webpack-dev-server"
],
"_resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.2.tgz",
"_shasum": "ee73dcc8348165afefe8de2ff717751d181608ee",
"_spec": "http-proxy-middleware@^0.19.1",
"_where": "/home/andreas/Documents/Projects/haxe/openfl/nigger/node_modules/webpack-dev-server",
"author": {
"name": "Steven Chim"
},
"bugs": {
"url": "https://github.com/chimurai/http-proxy-middleware/issues"
},
"bundleDependencies": false,
"commitlint": {
"extends": [
"@commitlint/config-conventional"
]
},
"dependencies": {
"http-proxy": "^1.18.1",
"is-glob": "^4.0.0",
"lodash": "^4.17.11",
"micromatch": "^3.1.10"
},
"deprecated": false,
"description": "The one-liner node.js proxy middleware for connect, express and browser-sync",
"devDependencies": {
"@commitlint/cli": "^7.2.1",
"@commitlint/config-conventional": "^7.1.2",
"browser-sync": "^2.26.3",
"chai": "^4.2.0",
"connect": "^3.6.6",
"coveralls": "^3.0.2",
"express": "^4.16.4",
"husky": "^1.2.0",
"istanbul": "^0.4.5",
"istanbul-coveralls": "^1.0.3",
"mocha": "^5.2.0",
"mocha-lcov-reporter": "1.3.0",
"opn": "^5.4.0",
"precise-commits": "^1.0.2",
"prettier": "^1.15.2",
"ws": "^6.1.2"
},
"engines": {
"node": ">=4.0.0"
},
"files": [
"index.js",
"lib"
],
"homepage": "https://github.com/chimurai/http-proxy-middleware",
"husky": {
"hooks": {
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS",
"pre-commit": "precise-commits"
}
},
"keywords": [
"reverse",
"proxy",
"middleware",
"http",
"https",
"connect",
"express",
"browser-sync",
"gulp",
"grunt-contrib-connect",
"websocket",
"ws",
"cors"
],
"license": "MIT",
"main": "index.js",
"name": "http-proxy-middleware",
"repository": {
"type": "git",
"url": "git+https://github.com/chimurai/http-proxy-middleware.git"
},
"scripts": {
"clean": "rm -rf coverage",
"cover": "npm run clean && istanbul cover ./node_modules/mocha/bin/_mocha -- --recursive",
"coveralls": "istanbul cover ./node_modules/mocha/bin/_mocha --report lcovonly -- --recursive --reporter spec && istanbul-coveralls && npm run clean",
"lint": "prettier \"**/*.{js,md}\" --list-different",
"lint:fix": "prettier \"**/*.{js,md}\" --write",
"test": "mocha --recursive --colors --reporter spec"
},
"version": "0.19.2"
}