Cors http(s) proxy for dev any purposes
# npm
npm i qorsproxy --save-dev
# yarn
yarn add -D qorsproxy
or just run via npx
/ npm exec
:
npx qorsproxy [options]
qorsproxy -p 8080 -c /Users/a.golub/repo/qorsproxy/config/qorsproxy.dev.qiwi.tools.json
or via runners:
npm start -- --config=path
pm2 start npm --name qorsproxy -- start -- --port=8080 --config=/Users/a.golub/repo/qorsproxy/config/qorsproxy.dev.qiwi.tools.json
npm run start:pm2 -- -- --port=8080
{"message":"[email protected] is loading...","level":"info"}
{"message":"argv={}","level":"info"}
{"message":"Config path=<empty>","level":"info"}
{"message":"Config ready.","level":"info"}
{"message":"Container configured.","level":"info"}
{"message":"Container is online: http://localhost:9292, https://localhost:9293","level":"info"}
curl 'http://127.0.0.1:9292/http://example.com' -H 'origin:http://localhost' → <!doctype html> ...
import {App} from 'qorsproxy'
const options = {
config: 'path/to/config.json', // or plain object
watch: true, // if true, config would be reloaded on change
port: 9292, // http port. Optional
host: 'localhost', // http host. Optional
}
const orchestrator = App.main(options)
// later
orchestrator.config.update({server: {port: 8080}, ...rest})
// ...
await orchestrator.container.stop()
--host
,-h
DNS name or IP address. Defaults tolocalhost
.--port
,-p
defines exposed port. Defaults to9292
.--secure.port
, defines exposed secure port. Defaults to9293
.--secure.cert
, path to SSL certificate. Defaults to certificate inssl/cert.pem
.--secure.key
, path to SSL private key. Defaults to key inssl/cert.pem
.--config
,-c
sets path to the custom config.--watch
,-w
if defined setsfs.watchFile
interval for config update. Ifport
orhost
has been changed, the server would be restarted. If config becomes invalid, the prev working version remains applied.
At the top level config describes server
, log
and proxy rules
sections.
It declares allowed connections and their side-effects like mutations
, interceptions
, customAuthorization
and etc.
Qorsproxy applies the first matched rule to the request, therefore declaration order matters.
rules
may be declared as a map:
{
"rules": {
"localhost": {
"from": [
"*"
],
"to": [
"example.com"
],
"paths": [
"/"
],
"mutations": [
{
"direction": "to",
"headers": [
{
"name": "origin",
"value": "localhost"
}
]
},
{
"direction": "from",
"headers": [
{
"name": "set-cookie",
"value": {
"from": "/;Domain.+;/",
"to": ";Domain: foobar.com;"
}
}
]
}
]
}
}
}
array syntax is suitable too:
{
"rules": [
{
"from": [
"*"
],
"to": [
"example.com"
]
}
]
}
Winston is under the hood and you're able to set some parameters:
{
"log": {
"dir": "./logs/",
"filename": "qors-%DATE%.log",
"datePattern": "YYYY-MM-DD",
"size": 52428800,
"level": "info"
}
}
{
"server": {
"host": "127.0.0.1",
"port": 8080,
"cert": "/path/to/cert.pem", // Defaults to ./ssl/cert.pem
"key": "/path/to/key.pem" // and ./ssl/key.pem
}
}
If you need support for OPTIONS request, extend target rule:
"interceptions": [
{
"req": {
"method": "OPTIONS"
},
"res": {
"status": 200
}
}
],
If intermediate authorization is required (change auth for JWT) add customAuthorization
to the target rule. See details at schema and impl.
"customAuthorization": {
"targetUrl": "example.com",
"authorizationUrl": "example-authorization.com",
"headers": ["authorization", "cookie"],
"authPath": "Edge.Headers.Authorization[0]"
}
Cypress has a trouble with Transfer-Encoding: chunked
header, so in this case you may use a workaround:
{
"mutations": [
{
"direction": "from",
"headers": [
{
"name": "transfer-encoding",
"value": null
}
]
}
]
}
There are several features to clarify what's going on with proxy.
Exposes liveness probe.
{
"status":"UP",
"critical":true,
"deps":{
"corsproxy":{
"status":"UP",
"critical":true
}
}
}
Uptime, CPU and memory usage, request counter:
{
"process": {
"uptime": "00:10:29",
"memory": {"rss": 96956416, "heapTotal": 56356864, "heapUsed": 47617368, "external": 10413906},
"cpu": {"user": 2229086, "system": 585411}
},
"servlets": {
"corsproxy": {
"count": 3,
"traffic": 1270
}
}
}
Common app info: version, name, etc.
{
"name": "qorsproxy",
"version": "1.5.4",
"description": "Cors proxy for dev purposes",
"repository": "[email protected]:qiwi/qorsproxy.git"
}
- Get any from google
- Write your own.
const http = require('http');
http.createServer(handler).listen(3000);
function handler(req, res) {
console.log('serve: ' + req.url);
const options = {
hostname: 'example.com',
port: 80,
path: req.url,
method: req.method
};
const proxy = http.request(options, _res => {
_res.pipe(res, {
end: true
});
});
req.pipe(proxy, {
end: true
});
}