Cors http(s) proxy for dev any purposes
# npm
npm i qorsproxy --save-dev
# yarn
yarn add -D qorsproxyor just run via npx / npm exec:
npx qorsproxy [options]qorsproxy -p 8080 -c /Users/a.golub/repo/qorsproxy/config/qorsproxy.dev.qiwi.tools.jsonor 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,-hDNS name or IP address. Defaults tolocalhost.--port,-pdefines 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,-csets path to the custom config.--watch,-wif defined setsfs.watchFileinterval for config update. Ifportorhosthas 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
});
}