mirror of
https://github.com/alibaba/anyproxy.git
synced 2025-08-04 21:39:04 +00:00
Add test cases for the proxy, and do some tiny fixes.
the fixes are: 1. add "content-type" in headers for when dealing with localresponse 2. make a more accurate tip for throttle rate when lower than 1 3. make the crtMgr funcionality a more independent one 4. uppercase the request header before sending it out update the tip
This commit is contained in:
28
test/data/headers.js
Normal file
28
test/data/headers.js
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 用于放置所有header信息的测试数据
|
||||
*
|
||||
*/
|
||||
|
||||
// Get 和 Post共有的header信息
|
||||
/*eslint max-len: ["off"]*/
|
||||
const CommonRequestHeader = {
|
||||
Accept: 'application/json;charset=utf-8,text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
|
||||
'Accept-Charset': 'utf-8',
|
||||
'Accept-Encoding': 'gzip, deflate',
|
||||
'Accept-Language': 'zh-CN',
|
||||
'Accept-Datetime': 'Thu, 31 May 2007 20:35:00 GMT',
|
||||
'Authorization': 'Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==',
|
||||
'Cache-Control': 'no-cache',
|
||||
'Connection': 'keep-alive',
|
||||
'Cookie': 'testCookie1=cookie1; testCookie2=cookie2',
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'Date': 'Tue, 15 Nov 1994 08:12:31 GMT',
|
||||
'Origin': 'http://localhost',
|
||||
'Pragma': 'no-cache',
|
||||
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36'
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
CommonRequestHeader
|
||||
};
|
||||
|
||||
3
test/data/test.css
Normal file
3
test/data/test.css
Normal file
@@ -0,0 +1,3 @@
|
||||
.test {
|
||||
display: block;
|
||||
}
|
||||
BIN
test/data/test.eot
Executable file
BIN
test/data/test.eot
Executable file
Binary file not shown.
3
test/data/test.js
Normal file
3
test/data/test.js
Normal file
@@ -0,0 +1,3 @@
|
||||
function test () {
|
||||
console.info('This is nothing but a js file, to test the js download');
|
||||
}
|
||||
3
test/data/test.json
Normal file
3
test/data/test.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
'testkey': 'this is just a normal json file'
|
||||
}
|
||||
BIN
test/data/test.png
Executable file
BIN
test/data/test.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 103 KiB |
14
test/data/test.svg
Executable file
14
test/data/test.svg
Executable file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<metadata>Copyright (C) 2016 by original authors @ fontello.com</metadata>
|
||||
<defs>
|
||||
<font id="fontello" horiz-adv-x="1000" >
|
||||
<font-face font-family="fontello" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
|
||||
<missing-glyph horiz-adv-x="1000" />
|
||||
<glyph glyph-name="glass" unicode="" d="M948 746q0-19-24-43l-353-353v-429h179q15 0 25-10t11-25-11-25-25-11h-500q-14 0-25 11t-11 25 11 25 25 10h179v429l-353 353q-24 24-24 43 0 13 10 21t21 9 24 3h786q13 0 24-3t21-9 10-21z" horiz-adv-x="1000" />
|
||||
|
||||
<glyph glyph-name="music" unicode="" d="M857 725v-625q0-28-19-50t-48-33-58-18-53-6-54 6-58 18-48 33-19 50 19 50 48 33 58 18 54 6q58 0 107-22v300l-429-132v-396q0-28-19-50t-48-33-58-18-53-6-54 6-58 18-48 33-19 50 19 50 48 34 58 17 54 6q58 0 107-21v539q0 17 10 32t28 20l464 142q7 3 16 3 22 0 38-16t15-38z" horiz-adv-x="857.1" />
|
||||
</font>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
BIN
test/data/test.ttf
Executable file
BIN
test/data/test.ttf
Executable file
Binary file not shown.
BIN
test/data/test.webp
Normal file
BIN
test/data/test.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 45 KiB |
BIN
test/data/test.woff
Executable file
BIN
test/data/test.woff
Executable file
Binary file not shown.
BIN
test/data/test.woff2
Executable file
BIN
test/data/test.woff2
Executable file
Binary file not shown.
459
test/no_rule_spec.js
Normal file
459
test/no_rule_spec.js
Normal file
@@ -0,0 +1,459 @@
|
||||
const http = require('http');
|
||||
const querystring = require('querystring');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const Buffer = require('buffer').Buffer;
|
||||
const Server = require('./server/server.js');
|
||||
const
|
||||
{
|
||||
proxyGet,
|
||||
proxyPost,
|
||||
directGet,
|
||||
directPost,
|
||||
directUpload,
|
||||
proxyUpload,
|
||||
generateUrl,
|
||||
proxyPut,
|
||||
directPut,
|
||||
proxyDelete,
|
||||
directDelete,
|
||||
directHead,
|
||||
proxyHead,
|
||||
directOptions,
|
||||
proxyOptions,
|
||||
proxyPutUpload,
|
||||
directPutUpload
|
||||
} = require('./util/HttpUtil.js');
|
||||
const { CommonRequestHeader } = require('./data/headers.js');
|
||||
const { isCommonResHeaderEqual, isCommonReqEqual, printLog } = require('./util/CommonUtil.js');
|
||||
const color = require('colorful');
|
||||
const streamEqual = require('stream-equal');
|
||||
const WebSocket = require('ws');
|
||||
|
||||
const ProxyServerUtil = require('./util/ProxyServerUtil.js');
|
||||
|
||||
const wsHost = 'ws://localhost:3000/test/socket';
|
||||
|
||||
testRequest('http');
|
||||
testRequest('https');
|
||||
|
||||
// Test suites for http and https request
|
||||
function testRequest(protocol = 'http') {
|
||||
|
||||
function constructUrl(urlPath) {
|
||||
return generateUrl(protocol, urlPath);
|
||||
}
|
||||
|
||||
describe('Test request without proxy rules in protocol ' + protocol, () => {
|
||||
let proxyServer ;
|
||||
let serverInstance;
|
||||
|
||||
beforeAll((done) => {
|
||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 200000;
|
||||
printLog('Start server for no_rule_spec');
|
||||
|
||||
serverInstance = new Server();
|
||||
proxyServer = ProxyServerUtil.defaultProxyServer();
|
||||
setTimeout(function() {
|
||||
done();
|
||||
}, 2000);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
serverInstance && serverInstance.close();
|
||||
proxyServer && proxyServer.close();
|
||||
printLog('Closed server for no_rule_spec');
|
||||
});
|
||||
|
||||
|
||||
it('Get should work as direct without proxy rules', (done) => {
|
||||
const url = constructUrl('/test');
|
||||
const getParam = {
|
||||
param: 'nothing'
|
||||
};
|
||||
|
||||
proxyGet(url, getParam, CommonRequestHeader).then((proxyRes) => {
|
||||
directGet(url, getParam, CommonRequestHeader).then(directRes => {
|
||||
|
||||
expect(proxyRes.statusCode).toEqual(200);
|
||||
|
||||
expect(isCommonResHeaderEqual(directRes.headers, proxyRes.headers, url)).toBe(true);
|
||||
expect(isCommonReqEqual(url, serverInstance)).toBe(true);
|
||||
expect(proxyRes.statusCode).toEqual(directRes.statusCode);
|
||||
expect(directRes.body).toEqual(proxyRes.body);
|
||||
|
||||
done();
|
||||
}, error => {
|
||||
console.error('error happend in direct get:', error);
|
||||
done.fail('error happend in direct get');
|
||||
});
|
||||
|
||||
}, error => {
|
||||
console.log('error happened in proxy get:', error);
|
||||
done.fail('error happend in proxy get');
|
||||
});
|
||||
});
|
||||
|
||||
it('Post should work as direct without proxy rules', (done) => {
|
||||
const url = constructUrl('/test/getuser');
|
||||
const param = {
|
||||
param: 'postnothing'
|
||||
};
|
||||
|
||||
proxyPost(url, param, CommonRequestHeader).then(proxyRes => {
|
||||
directPost(url, param, CommonRequestHeader).then(directRes => {
|
||||
|
||||
expect(proxyRes.statusCode).toEqual(200);
|
||||
|
||||
expect(isCommonResHeaderEqual(directRes.headers, proxyRes.headers, url)).toBe(true);
|
||||
expect(proxyRes.statusCode).toEqual(directRes.statusCode);
|
||||
expect(directRes.body).toEqual(proxyRes.body);
|
||||
|
||||
expect(isCommonReqEqual(url, serverInstance)).toBe(true);
|
||||
|
||||
done();
|
||||
}, error => {
|
||||
console.error('error in direct post:', error);
|
||||
done.fail('error happend in direct post');
|
||||
});
|
||||
|
||||
}, error => {
|
||||
console.log('error happened in proxy post,', error);
|
||||
done.fail('error happend in proxy post');
|
||||
});
|
||||
});
|
||||
|
||||
it('PUT should work as direct without proxy rules', done => {
|
||||
const url = constructUrl('/test/put');
|
||||
const param = {
|
||||
param: 'putsomething'
|
||||
};
|
||||
proxyPut(url, param, CommonRequestHeader).then(proxyRes => {
|
||||
directPut(url, param, CommonRequestHeader).then(directRes => {
|
||||
expect(directRes.statusCode).toEqual(200);
|
||||
|
||||
expect(isCommonResHeaderEqual(directRes.headers, proxyRes.headers, url)).toBe(true);
|
||||
expect(directRes.statusCode).toEqual(proxyRes.statusCode);
|
||||
expect(directRes.body).toEqual(proxyRes.body);
|
||||
expect(isCommonReqEqual(url, serverInstance)).toBe(true);
|
||||
|
||||
done();
|
||||
}, error => {
|
||||
console.error('error happened in direct put', error);
|
||||
done.fail('error happened in direct put');
|
||||
});
|
||||
}, error => {
|
||||
console.error('error happened in proxy put', error);
|
||||
done.fail('error happened in proxy put');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('DELETE rquest should work as direct without proxy rules', (done) => {
|
||||
const url = constructUrl('/test/delete/123456');
|
||||
|
||||
proxyDelete(url, {}, CommonRequestHeader).then(proxyRes => {
|
||||
directDelete(url, {}, CommonRequestHeader).then(directRes => {
|
||||
expect(directRes.statusCode).toEqual(200);
|
||||
|
||||
expect(directRes.statusCode).toEqual(proxyRes.statusCode);
|
||||
expect(isCommonResHeaderEqual(directRes.headers, proxyRes.headers, url)).toBe(true);
|
||||
expect(directRes.body).toEqual(proxyRes.body);
|
||||
expect(isCommonReqEqual(url, serverInstance)).toBe(true);
|
||||
|
||||
done();
|
||||
}, error => {
|
||||
console.error('error happened in direct delete :', error);
|
||||
done.fail('error happened in direct delete');
|
||||
});
|
||||
}, error => {
|
||||
console.error('error happened in proxy delete :', error);
|
||||
done.fail('error happened in proxy delete');
|
||||
});
|
||||
});
|
||||
|
||||
it('HEAD request should work as direct without proxy rules', (done) => {
|
||||
const url = constructUrl('/test/head');
|
||||
|
||||
proxyHead(url, CommonRequestHeader)
|
||||
.then(proxyRes => {
|
||||
directHead(url, CommonRequestHeader)
|
||||
.then(directRes => {
|
||||
expect(directRes.statusCode).toEqual(200);
|
||||
expect(directRes.body).toEqual('');
|
||||
|
||||
expect(directRes.statusCode).toEqual(proxyRes.statusCode);
|
||||
expect(isCommonResHeaderEqual(directRes.headers, proxyRes.headers, url)).toBe(true);
|
||||
expect(directRes.body).toEqual(proxyRes.body);
|
||||
expect(isCommonReqEqual(url, serverInstance)).toBe(true);
|
||||
|
||||
done();
|
||||
}, error => {
|
||||
console.error('error happened in direct head request:', error);
|
||||
done.fail('error happened in direct head request');
|
||||
});
|
||||
}, error => {
|
||||
console.error('error happened in proxy head request:', error);
|
||||
done.fail('error happened in proxy head request');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('OPTIONS request should work as direct without proxy rules', (done) => {
|
||||
const url = constructUrl('/test/options');
|
||||
|
||||
proxyOptions(url, CommonRequestHeader)
|
||||
.then(proxyRes => {
|
||||
directOptions(url, CommonRequestHeader)
|
||||
.then(directRes => {
|
||||
expect(directRes.statusCode).toEqual(200);
|
||||
expect(directRes.body).toEqual('could_be_empty');
|
||||
|
||||
expect(directRes.statusCode).toEqual(proxyRes.statusCode);
|
||||
expect(isCommonResHeaderEqual(directRes.headers, proxyRes.headers, url)).toBe(true);
|
||||
expect(directRes.body).toEqual(proxyRes.body);
|
||||
expect(isCommonReqEqual(url, serverInstance)).toBe(true);
|
||||
|
||||
done();
|
||||
}, error => {
|
||||
console.error('error happened in direct options request:', error);
|
||||
done.fail('error happened in direct options request');
|
||||
});
|
||||
}, error => {
|
||||
console.error('error happened in proxy options request:', error);
|
||||
done.fail('error happened in proxy options request');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('Response code should be honored as direct without proxy rules', () => {
|
||||
[301, 302, 303].forEach(code => {
|
||||
testRedirect(code);
|
||||
});
|
||||
|
||||
function testRedirect (redirectCode) {
|
||||
it(`${redirectCode} response should work as direct without proxy rules`, (done) => {
|
||||
const url = constructUrl(`/test/response/${redirectCode}`);
|
||||
|
||||
proxyGet(url)
|
||||
.then(proxyRes => {
|
||||
directGet(url)
|
||||
.then(directRes => {
|
||||
const redirects = directRes.request._redirect.redirects || [];
|
||||
const proxyRedirects = proxyRes.request._redirect.redirects || [];
|
||||
expect(redirects.length).toEqual(1);
|
||||
expect(proxyRedirects.length).toEqual(1);
|
||||
|
||||
expect(redirects[0].statusCode).toEqual(redirectCode);
|
||||
expect(redirects[0].redirectUri).toEqual(proxyRedirects[0].redirectUri);
|
||||
expect(redirects[0].statusCode).toEqual(proxyRedirects[0].statusCode);
|
||||
if (protocol === 'https') {
|
||||
expect(redirects[0].redirectUri).toEqual('https://localhost:3001/test');
|
||||
} else {
|
||||
expect(redirects[0].redirectUri).toEqual('http://localhost:3000/test');
|
||||
}
|
||||
done();
|
||||
}, error => {
|
||||
console.log(`error happened in direct ${redirectCode}:`, error);
|
||||
done.fail(`error happened in direct ${redirectCode}`);
|
||||
});
|
||||
|
||||
}, error => {
|
||||
console.log(`error happened in proxy ${redirectCode}:`, error);
|
||||
done.fail(`error happened in proxy ${redirectCode}`);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
describe('Test file download ', () => {
|
||||
const testArray = [
|
||||
{
|
||||
url: constructUrl('/test/download/png'),
|
||||
type: 'png',
|
||||
contentType: 'image/png'
|
||||
},
|
||||
{
|
||||
url: constructUrl('/test/download/webp'),
|
||||
type: 'WEBP',
|
||||
contentType: 'image/webp'
|
||||
},
|
||||
{
|
||||
url: constructUrl('/test/download/json'),
|
||||
type: 'JSON',
|
||||
contentType: 'application/json; charset=utf-8'
|
||||
},
|
||||
{
|
||||
url: constructUrl('/test/download/css'),
|
||||
type: 'CSS',
|
||||
contentType: 'text/css; charset=utf-8'
|
||||
},
|
||||
{
|
||||
url: constructUrl('/test/download/ttf'),
|
||||
type: 'TTF',
|
||||
contentType: 'application/x-font-ttf'
|
||||
},
|
||||
{
|
||||
url: constructUrl('/test/download/eot'),
|
||||
type: 'EOT',
|
||||
contentType: 'application/vnd.ms-fontobject'
|
||||
},
|
||||
{
|
||||
url: constructUrl('/test/download/svg'),
|
||||
type: 'SVG',
|
||||
contentType: 'image/svg+xml'
|
||||
},
|
||||
{
|
||||
url: constructUrl('/test/download/woff'),
|
||||
type: 'WOFF',
|
||||
contentType: 'application/font-woff'
|
||||
},
|
||||
{
|
||||
url: constructUrl('/test/download/woff2'),
|
||||
type: 'WOFF2',
|
||||
contentType: 'application/font-woff2'
|
||||
}
|
||||
];
|
||||
|
||||
testArray.forEach(item => {
|
||||
testFileDownload(item.url, item.type, item.contentType);
|
||||
});
|
||||
|
||||
// 封装测试文件下载的测试工具类
|
||||
function testFileDownload (url, filetype, contentType) {
|
||||
const describe = `${filetype} file download without rules should be work as direct download`;
|
||||
const param = {};
|
||||
|
||||
it(describe, (done) => {
|
||||
|
||||
proxyGet(url, param).then(proxyRes => {
|
||||
directGet(url, param).then(directRes => {
|
||||
expect(proxyRes.statusCode).toEqual(200);
|
||||
|
||||
expect(isCommonResHeaderEqual(directRes.headers, proxyRes.headers, url)).toBe(true);
|
||||
expect(proxyRes.statusCode).toEqual(directRes.statusCode);
|
||||
expect(proxyRes.body).toEqual(directRes.body);
|
||||
expect(isCommonReqEqual(url, serverInstance)).toBe(true);
|
||||
|
||||
done();
|
||||
}, error => {
|
||||
console.error('error in direct get :', filetype, error);
|
||||
done.fail(`error happend in direct get ${filetype}`);
|
||||
});
|
||||
}, error => {
|
||||
console.error('error in proxy get :', filetype, error);
|
||||
done.fail(`error happend in proxy get ${filetype}`);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
describe('Test file upload', () => {
|
||||
const formParams = {
|
||||
param1: 'param_1',
|
||||
param2: 'param2'
|
||||
};
|
||||
it('POST upload should be working', (done) => {
|
||||
const url = constructUrl('/test/upload/png');
|
||||
const filePath = path.resolve('./test/data/test.png');
|
||||
|
||||
proxyUpload(url, filePath, formParams)
|
||||
.then(proxyRes => {
|
||||
directUpload(url, filePath, formParams)
|
||||
.then((directRes) => {
|
||||
expect(isCommonResHeaderEqual(directRes.headers, proxyRes.headers, url)).toBe(true);
|
||||
expect(isCommonReqEqual(url, serverInstance)).toBe(true);
|
||||
assertReponse(proxyRes, directRes, filePath, done);
|
||||
}, error => {
|
||||
console.error('error in direct upload:', error);
|
||||
done.fail('error in direct upload');
|
||||
});
|
||||
}, error => {
|
||||
console.error('error in proxy upload:', error);
|
||||
done.fail('error in proxy upload:');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('PUT upload should be working', (done) => {
|
||||
const url = constructUrl('/test/upload/putpng');
|
||||
const filePath = path.resolve('./test/data/test.png');
|
||||
proxyPutUpload(url, filePath, formParams)
|
||||
.then(proxyRes => {
|
||||
directPutUpload(url, filePath, formParams)
|
||||
.then((directRes) => {
|
||||
expect(isCommonResHeaderEqual(directRes.headers, proxyRes.headers, url)).toBe(true);
|
||||
|
||||
assertReponse(proxyRes, directRes, filePath, done);
|
||||
}, error => {
|
||||
console.error('error in direct upload:', error);
|
||||
done.fail('error in direct upload');
|
||||
});
|
||||
}, error => {
|
||||
console.error('error in proxy upload:', error);
|
||||
done.fail('error in proxy upload:');
|
||||
});
|
||||
});
|
||||
|
||||
function assertReponse (proxyRes, directRes, originFilePath, done) {
|
||||
expect(proxyRes.statusCode).toEqual(200);
|
||||
|
||||
expect(proxyRes.statusCode).toEqual(directRes.statusCode);
|
||||
// expect(proxyRes.headers.reqbody).toEqual(directRes.headers.reqbody);
|
||||
|
||||
// the body will be the file path
|
||||
const directUploadedStream = fs.createReadStream(directRes.body);
|
||||
const proxyUploadedStream = fs.createReadStream(proxyRes.body);
|
||||
const localFileStream = fs.createReadStream(originFilePath);
|
||||
streamEqual(directUploadedStream, localFileStream)
|
||||
.then(isLocalEqual => {
|
||||
expect(isLocalEqual).toBe(true);
|
||||
streamEqual(directUploadedStream, proxyUploadedStream)
|
||||
.then(isUploadedEqual => {
|
||||
expect(isUploadedEqual).toBe(true);
|
||||
done();
|
||||
}, error => {
|
||||
console.error('error in comparing directUpload with proxy:\n',error);
|
||||
done.fail('error in comparing directUpload with proxy');
|
||||
});
|
||||
done();
|
||||
}, error => {
|
||||
console.error('error in comparing directUpload with local:\n',error);
|
||||
done.fail('error in comparing directUpload with local');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// describe('Test Big file download', () => {
|
||||
// // const url = '/test/download/bigfile';
|
||||
// const url = 'http://yunpan.alibaba-inc.com/downloadService.do?token=pZWiXMXUguIUQDvR098qnUVqVAWhNVY6';
|
||||
// const contentType = 'application/octet-stream';
|
||||
// const param = {};
|
||||
// it('BIG file downlaod should be working', (done) => {
|
||||
// directGet(url, param, CommonRequestHeader).then(proxyRes => {
|
||||
// console.info('proxyRes body:', proxyRes.body);
|
||||
|
||||
// directGet(url, param, CommonRequestHeader).then(directRes => {
|
||||
// expect(proxyRes.statusCode).toEqual(200);
|
||||
// expect(proxyRes.headers['content-type']).toEqual(contentType);
|
||||
|
||||
// expect(proxyRes.statusCode).toEqual(directRes.statusCode);
|
||||
// expect(proxyRes.headers['content-type']).toEqual(directRes.headers['content-type']);
|
||||
// expect(proxyRes.body).toEqual(directRes.body);
|
||||
// done();
|
||||
// }, error => {
|
||||
// console.error('error in direct get bigfile :', error);
|
||||
// done.fail(`error happend in direct get bigfile`);
|
||||
// });
|
||||
// }, error => {
|
||||
// console.error('error in proxy get bigfile :', error);
|
||||
// done.fail(`error happend in proxy get bigfile`);
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
});
|
||||
}
|
||||
144
test/no_rule_websocket_spec.js
Normal file
144
test/no_rule_websocket_spec.js
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Test suites for WebSocket.
|
||||
* ONLY TO ENSURE THE REQUEST WILL BE BYPASSED SUCCESSFULLY, WE HAVEN'T SUPPORTTED WEBSOCKET YET.
|
||||
*
|
||||
*/
|
||||
const ProxyServerUtil = require('./util/ProxyServerUtil.js');
|
||||
const { generateWsUrl, directWs, proxyWs } = require('./util/HttpUtil.js');
|
||||
const Server = require('./server/server.js');
|
||||
const { printLog } = require('./util/CommonUtil.js');
|
||||
|
||||
const wsHost = 'ws://localhost:3000/test/socket';
|
||||
|
||||
testWebsocket('ws');
|
||||
testWebsocket('wss');
|
||||
|
||||
function testWebsocket(protocol) {
|
||||
describe('Test WebSocket in protocol : ' + protocol , () =>{
|
||||
const url = generateWsUrl(protocol, '/test/socket');
|
||||
let serverInstance ;
|
||||
let proxyServer ;
|
||||
|
||||
beforeAll((done) => {
|
||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 200000;
|
||||
printLog('Start server for no_rule_websocket_spec');
|
||||
serverInstance = new Server();
|
||||
|
||||
proxyServer = ProxyServerUtil.proxyServerWithoutHttpsIntercept();
|
||||
|
||||
setTimeout(function() {
|
||||
done();
|
||||
}, 2000);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
serverInstance && serverInstance.close();
|
||||
proxyServer && proxyServer.close();
|
||||
printLog('Closed server for no_rule_websocket_spec');
|
||||
});
|
||||
|
||||
it('Default websocket option', done => {
|
||||
const sendMessage = 'Send the message with default option';
|
||||
let directMessage ; // set the flag for direct message, compare when both direct and proxy got message
|
||||
let proxyMessage;
|
||||
|
||||
const ws = directWs(url);
|
||||
const porxyWsRef = proxyWs(url);
|
||||
ws.on('open', () => {
|
||||
ws.send(sendMessage);
|
||||
});
|
||||
|
||||
porxyWsRef.on('open', () => {
|
||||
porxyWsRef.send(sendMessage);
|
||||
});
|
||||
|
||||
ws.on('message', (data, flag) => {
|
||||
const message = JSON.parse(data);
|
||||
if (message.type === 'onMessage') {
|
||||
directMessage = message.content;
|
||||
compareMessageIfReady();
|
||||
}
|
||||
});
|
||||
|
||||
porxyWsRef.on('message', (data, flag) => {
|
||||
const message = JSON.parse(data);
|
||||
if (message.type === 'onMessage') {
|
||||
proxyMessage = message.content;
|
||||
compareMessageIfReady();
|
||||
}
|
||||
});
|
||||
|
||||
ws.on('error', error => {
|
||||
console.error('error happened in direct websocket:', error);
|
||||
done.fail('Error happened in direct websocket');
|
||||
});
|
||||
|
||||
porxyWsRef.on('error', error => {
|
||||
console.error('error happened in proxy websocket:', error);
|
||||
done.fail('Error happened in proxy websocket');
|
||||
});
|
||||
|
||||
function compareMessageIfReady () {
|
||||
if (directMessage && proxyMessage) {
|
||||
expect(directMessage).toEqual(proxyMessage);
|
||||
expect(directMessage).toEqual(sendMessage);
|
||||
done();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('masked:true', done => {
|
||||
const sendMessage = 'Send the message with option masked:true';
|
||||
let directMessage ; // set the flag for direct message, compare when both direct and proxy got message
|
||||
let proxyMessage;
|
||||
|
||||
const ws = directWs(url);
|
||||
const porxyWsRef = proxyWs(url);
|
||||
ws.on('open', () => {
|
||||
ws.send(sendMessage, { masked: true });
|
||||
});
|
||||
|
||||
porxyWsRef.on('open', () => {
|
||||
porxyWsRef.send(sendMessage, { masked: true });
|
||||
});
|
||||
|
||||
ws.on('message', (data, flag) => {
|
||||
const message = JSON.parse(data);
|
||||
if (message.type === 'onMessage') {
|
||||
directMessage = message.content;
|
||||
compareMessageIfReady();
|
||||
}
|
||||
});
|
||||
|
||||
porxyWsRef.on('message', (data, flag) => {
|
||||
const message = JSON.parse(data);
|
||||
if (message.type === 'onMessage') {
|
||||
proxyMessage = message.content;
|
||||
compareMessageIfReady();
|
||||
}
|
||||
});
|
||||
|
||||
ws.on('error', error => {
|
||||
console.error('error happened in direct websocket:', error);
|
||||
done.fail('Error happened in direct websocket');
|
||||
});
|
||||
|
||||
porxyWsRef.on('error', error => {
|
||||
console.error('error happened in proxy websocket:', error);
|
||||
|
||||
done.fail('Error happened in proxy websocket');
|
||||
});
|
||||
|
||||
function compareMessageIfReady () {
|
||||
if (directMessage && proxyMessage) {
|
||||
expect(directMessage).toEqual(proxyMessage);
|
||||
expect(directMessage).toEqual(sendMessage);
|
||||
done();
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
57
test/rule_shouldUseLocalResponse_spec.js
Normal file
57
test/rule_shouldUseLocalResponse_spec.js
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* test for rule shouldUseLocal
|
||||
*
|
||||
*/
|
||||
|
||||
const ProxyServerUtil = require('./util/ProxyServerUtil.js');
|
||||
const { proxyGet, generateUrl } = require('./util/HttpUtil.js');
|
||||
const Server = require('./server/server.js');
|
||||
const { printLog } = require('./util/CommonUtil.js');
|
||||
|
||||
const rule = require('./test_rules/shouldUseLocalResponseRule.js');
|
||||
const expectedLocalBody = 'handled_in_local_response';
|
||||
|
||||
|
||||
testWrapper('http');
|
||||
testWrapper('https');
|
||||
|
||||
function testWrapper(protocol, ) {
|
||||
describe('Rule shouldUseLocalResponse should be working in :' + protocol, () => {
|
||||
let proxyServer ;
|
||||
let serverInstance ;
|
||||
|
||||
beforeAll((done) => {
|
||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 2000000;
|
||||
printLog('Start server for rule_shouldUseLocalResponse_spec');
|
||||
|
||||
serverInstance = new Server();
|
||||
|
||||
proxyServer = ProxyServerUtil.proxyServerWithRule(rule);
|
||||
|
||||
setTimeout(function() {
|
||||
done();
|
||||
}, 2000);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
serverInstance && serverInstance.close();
|
||||
proxyServer && proxyServer.close();
|
||||
printLog('Close server for rule_shouldUseLocalResponse_spec');
|
||||
|
||||
});
|
||||
|
||||
it('Should use local response if the assertion is true', done => {
|
||||
const url = generateUrl(protocol, '/test/uselocal');
|
||||
proxyGet(url, {})
|
||||
.then(res => {
|
||||
expect(res.body).toEqual(expectedLocalBody);
|
||||
expect(res.headers['via-proxy-local']).toEqual('true');
|
||||
done();
|
||||
}, error => {
|
||||
console.log('error happened in proxy get for shouldUseLocal: ',error);
|
||||
done.fail('error happened when test shouldUseLocal rule');
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
274
test/server/server.js
Normal file
274
test/server/server.js
Normal file
@@ -0,0 +1,274 @@
|
||||
const Koa = require('koa');
|
||||
const KoaRouter = require('koa-router');
|
||||
const koaBody = require('koa-body');
|
||||
const send = require('koa-send');
|
||||
const path = require('path');
|
||||
const https = require('https');
|
||||
const certMgr = require("../../lib/certMgr");
|
||||
const fs = require('fs');
|
||||
const websocket = require('koa-websocket');
|
||||
const wsRouter = require('koa-router')();
|
||||
const color = require('colorful');
|
||||
const WebSocketServer = require('ws').Server;
|
||||
|
||||
const DEFAULT_PORT = 3000;
|
||||
const HTTPS_PORT = 3001;
|
||||
const UPLOAD_DIR = './test/temp';
|
||||
const PROXY_KEY_PREFIX = 'proxy-';
|
||||
|
||||
function KoaServer() {
|
||||
this.httpServer = null;
|
||||
this.httpsServer = null;
|
||||
this.requestRecordMap = {}; // store all request data to the map
|
||||
const self = this;
|
||||
|
||||
/**
|
||||
* log the request info, write as
|
||||
*/
|
||||
this.logRequest = function* (next) {
|
||||
const headers = this.request.headers;
|
||||
let key = this.request.host + this.request.url;
|
||||
|
||||
// take proxy data with 'proxy-' + url
|
||||
if (headers['via-proxy'] === 'true') {
|
||||
key = PROXY_KEY_PREFIX + key;
|
||||
}
|
||||
|
||||
let body = this.request.body;
|
||||
body = typeof body === 'object' ? JSON.stringify(body) : body;
|
||||
self.requestRecordMap[key] = {
|
||||
headers: headers,
|
||||
body: body
|
||||
};
|
||||
yield next;
|
||||
};
|
||||
|
||||
this.start();
|
||||
}
|
||||
|
||||
KoaServer.prototype.constructRouter = function() {
|
||||
const router = KoaRouter();
|
||||
router.post('/test/getuser', this.logRequest, koaBody(), function*(next) {
|
||||
printLog('requesting post /test/getuser');
|
||||
this.response.set('reqbody', JSON.stringify(this.request.body));
|
||||
this.response.body = 'something in post';
|
||||
});
|
||||
|
||||
router.get('/test', this.logRequest, function*(next) {
|
||||
printLog('request in get: ' + JSON.stringify(this.request));
|
||||
this.response.body = 'something';
|
||||
this.response.__req = this.request;
|
||||
printLog('response in get:' + JSON.stringify(this.response));
|
||||
});
|
||||
|
||||
router.get('/test/uselocal', this.logRequest, function*(next) {
|
||||
printLog('request in get local:' + JSON.stringify(this.request));
|
||||
this.response.body = 'something should be in local';
|
||||
this.response.__req = this.request;
|
||||
printLog('response in get:' + JSON.stringify(this.response));
|
||||
});
|
||||
|
||||
['png', 'webp', 'json', 'js', 'css', 'ttf', 'eot', 'svg', 'woff', 'woff2'].forEach(item => {
|
||||
router.get(`/test/download/${item}`, this.logRequest, function* (next) {
|
||||
printLog(`now downloading the ${item}`);
|
||||
yield send(this, `test/data/test.${item}`);
|
||||
});
|
||||
});
|
||||
|
||||
router.get('/test/response/303', function*(next) {
|
||||
printLog('now to redirect 303');
|
||||
this.redirect('/test');
|
||||
this.status = 303;
|
||||
});
|
||||
|
||||
router.get('/test/response/302', function*(next) {
|
||||
printLog('now to redirect 302');
|
||||
this.redirect('/test');
|
||||
});
|
||||
|
||||
router.get('/test/response/301', function*(next) {
|
||||
printLog('now to redirect permanently');
|
||||
this.redirect('/test');
|
||||
this.status = 301;
|
||||
});
|
||||
|
||||
const onFileBegin = function(name, file) {
|
||||
if (!fs.existsSync('./test/temp')) {
|
||||
try {
|
||||
fs.mkdirSync('./test/temp', '0777');
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
file.name = 'test_upload_' + Date.now() + '.png';
|
||||
var folder = path.dirname(file.path);
|
||||
file.path = path.join(folder, file.name);
|
||||
|
||||
};
|
||||
|
||||
router.post('/test/upload/png',
|
||||
this.logRequest,
|
||||
koaBody({
|
||||
multipart: true,
|
||||
formidable: {
|
||||
uploadDir: UPLOAD_DIR,
|
||||
onFileBegin: onFileBegin
|
||||
}
|
||||
}),
|
||||
function*(next) {
|
||||
const file = this.request.body.files.file;
|
||||
this.response.set('reqbody', JSON.stringify(this.request.body.fields));
|
||||
this.response.body = file.path;
|
||||
}
|
||||
);
|
||||
|
||||
router.put('/test/upload/putpng',
|
||||
this.logRequest,
|
||||
koaBody({
|
||||
multipart: true,
|
||||
formidable: {
|
||||
uploadDir: UPLOAD_DIR,
|
||||
onFileBegin: onFileBegin
|
||||
}
|
||||
}),
|
||||
function*(next) {
|
||||
const file = this.request.body.files.file;
|
||||
this.response.body = file.path;
|
||||
}
|
||||
);
|
||||
|
||||
router.put('/test/put', koaBody(), this.logRequest, function*(next) {
|
||||
printLog('requesting put /test/put' + JSON.stringify(this.request));
|
||||
this.response.body = 'something in put';
|
||||
});
|
||||
|
||||
router.delete('/test/delete/:id', this.logRequest, function*(next) {
|
||||
printLog('requesting delete /test/delete/:id'+ JSON.stringify(this.params));
|
||||
this.response.body = 'something in delete';
|
||||
});
|
||||
|
||||
router.head('/test/head', this.logRequest, function*(next) {
|
||||
printLog('requesting head /test/head');
|
||||
this.response.body = ''; // the body will not be passed to response, in HEAD request
|
||||
this.response.set('reqBody', 'head_request_contains_no_resbody');
|
||||
});
|
||||
|
||||
router.options('/test/options', this.logRequest, function*(next) {
|
||||
printLog('requesting options /test/options');
|
||||
this.response.body = 'could_be_empty';
|
||||
this.response.set('Allow', 'GET, HEAD, POST, OPTIONS');
|
||||
});
|
||||
|
||||
// router.connect('/test/connect', function *(next) {
|
||||
// printLog('requesting connect /test/connect');
|
||||
// this.response.body = 'connect_established_body';
|
||||
// });
|
||||
|
||||
return router;
|
||||
};
|
||||
|
||||
KoaServer.prototype.constructWsRouter = function() {
|
||||
const wsRouter = KoaRouter();
|
||||
const self = this;
|
||||
wsRouter.get('/test/socket', function*(next) {
|
||||
const ws = this.websocket;
|
||||
const messageObj = {
|
||||
type: 'initial',
|
||||
content: 'default message'
|
||||
};
|
||||
|
||||
ws.send(JSON.stringify(messageObj));
|
||||
ws.on('message', message => {
|
||||
printLog('message from request socket: ' + message);
|
||||
self.handleRecievedMessage(ws, message);
|
||||
});
|
||||
yield next;
|
||||
});
|
||||
|
||||
return wsRouter;
|
||||
};
|
||||
|
||||
KoaServer.prototype.getRequestRecord = function (key) {
|
||||
return this.requestRecordMap[key] || {};
|
||||
};
|
||||
|
||||
KoaServer.prototype.getProxyRequestRecord = function (key) {
|
||||
key = PROXY_KEY_PREFIX + key;
|
||||
return this.requestRecordMap[key] || {};
|
||||
};
|
||||
|
||||
KoaServer.prototype.handleRecievedMessage = function(ws, message) {
|
||||
const newMessage = {
|
||||
type: 'onMessage',
|
||||
content: message
|
||||
};
|
||||
ws.send(JSON.stringify(newMessage));
|
||||
};
|
||||
|
||||
KoaServer.prototype.start = function() {
|
||||
printLog('Starting the server...');
|
||||
const router = this.constructRouter();
|
||||
const wsRouter = this.constructWsRouter();
|
||||
const self = this;
|
||||
const app = Koa();
|
||||
websocket(app);
|
||||
|
||||
app.use(router.routes());
|
||||
app.ws.use(wsRouter.routes());
|
||||
this.httpServer = app.listen(DEFAULT_PORT);
|
||||
|
||||
printLog('HTTP is now listening on port :' + DEFAULT_PORT);
|
||||
|
||||
certMgr.getCertificate('localhost', function(error, keyContent, crtContent) {
|
||||
if (error) {
|
||||
console.error('failed to create https server:', error);
|
||||
} else {
|
||||
self.httpsServer = https.createServer({
|
||||
key: keyContent,
|
||||
cert: crtContent
|
||||
}, app.callback());
|
||||
|
||||
// create wss server
|
||||
const wss = new WebSocketServer({
|
||||
server: self.httpsServer
|
||||
});
|
||||
|
||||
wss.on('connection', function connection(ws) {
|
||||
ws.on('message', function incoming(message) {
|
||||
printLog('received in wss: ' + message);
|
||||
self.handleRecievedMessage(ws, message);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
wss.on('error', error => {
|
||||
console.error('erro happened in wss:%s', error);
|
||||
});
|
||||
|
||||
self.httpsServer.listen(HTTPS_PORT);
|
||||
|
||||
printLog('HTTPS is now listening on port :' + HTTPS_PORT);
|
||||
|
||||
printLog('Server started successfully');
|
||||
}
|
||||
});
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
KoaServer.prototype.close = function() {
|
||||
printLog('Closing server now...');
|
||||
this.httpServer && this.httpServer.close();
|
||||
this.httpsServer && this.httpsServer.close();
|
||||
this.requestRecordMap = {};
|
||||
printLog('Server closed successfully');
|
||||
};
|
||||
|
||||
|
||||
function printLog(content) {
|
||||
console.log(color.cyan('===SERVER LOG===' + content));
|
||||
}
|
||||
|
||||
|
||||
module.exports = KoaServer;
|
||||
3
test/server/startServer.js
Normal file
3
test/server/startServer.js
Normal file
@@ -0,0 +1,3 @@
|
||||
const Server = require('./server.js');
|
||||
|
||||
new Server();
|
||||
@@ -1,5 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "nodeunit is required to run these test cases"
|
||||
echo "Begin to run the test suites, JASMINE is required.\n"
|
||||
echo "Removing test temp directory before running"
|
||||
rm -rf ./test/temp/*
|
||||
echo "Removing done, test cases now running"
|
||||
node -v
|
||||
nodeunit test.js
|
||||
jasmine JASMINE_CONFIG_PATH=./jasmine.json
|
||||
|
||||
22
test/test_rules/shouldUseLocalResponseRule.js
Normal file
22
test/test_rules/shouldUseLocalResponseRule.js
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Rule defination for shouldUseLocalResponse
|
||||
*
|
||||
*/
|
||||
|
||||
const dealLocalBody = 'handled_in_local_response';
|
||||
|
||||
module.exports = {
|
||||
shouldUseLocalResponse: function (req, reqBody) {
|
||||
return req.url.indexOf('uselocal') > -1;
|
||||
},
|
||||
shouldInterceptHttpsReq: function () {
|
||||
return true;
|
||||
},
|
||||
dealLocalResponse: function (req, reqBody, callback) {
|
||||
const header = {
|
||||
'Via-Proxy-Local': 'true'
|
||||
};
|
||||
|
||||
callback(200, header, dealLocalBody);
|
||||
}
|
||||
};
|
||||
153
test/util/CommonUtil.js
Normal file
153
test/util/CommonUtil.js
Normal file
@@ -0,0 +1,153 @@
|
||||
/**
|
||||
*
|
||||
* The utility class for test
|
||||
*/
|
||||
const zlib = require('zlib');
|
||||
const color = require('colorful');
|
||||
|
||||
/*
|
||||
* Compare whether tow object are equal
|
||||
*/
|
||||
function isObjectEqual (source = {} , target = {}, url = '') {
|
||||
source = Object.assign({}, source);
|
||||
target = Object.assign({}, target);
|
||||
let isEqual = true;
|
||||
|
||||
for(const key in source) {
|
||||
isEqual = isEqual && source[key] === target[key];
|
||||
|
||||
if (!isEqual) {
|
||||
console.info('source object :', source);
|
||||
console.info('target object :', target);
|
||||
printError(`different key in isObjectEqual is: "${key}", source is "${source[key]}",
|
||||
target is "${target[key]}" the url is ${url}`);
|
||||
break;
|
||||
}
|
||||
|
||||
delete source[key];
|
||||
delete target[key];
|
||||
}
|
||||
|
||||
for(const key in target) {
|
||||
isEqual = isEqual && source[key] === target[key];
|
||||
|
||||
if (!isEqual) {
|
||||
console.info('source object :', source);
|
||||
console.info('target object :', target);
|
||||
printError(`different key in isObjectEqual is: "${key}", source is "${source[key]}",
|
||||
target is "${target[key]}" the url is ${url}`);
|
||||
break;
|
||||
}
|
||||
|
||||
delete source[key];
|
||||
delete target[key];
|
||||
}
|
||||
|
||||
return isEqual;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare the header between direct with proxy
|
||||
* Will exclude the header(s) which modified by proxy
|
||||
*/
|
||||
function isCommonResHeaderEqual (directHeaders, proxyHeaders, requestUrl) {
|
||||
directHeaders = Object.assign({}, directHeaders);
|
||||
proxyHeaders = Object.assign({}, proxyHeaders);
|
||||
let isEqual = true;
|
||||
const mustEqualFileds = []; // the fileds that have to be equal, or the assert will be failed
|
||||
|
||||
if (!/gzip/i.test(directHeaders['content-encoding'])) {
|
||||
// if the content is gzipped, proxy will unzip and remove the header
|
||||
mustEqualFileds.push('content-encoding');
|
||||
mustEqualFileds.push('content-length');
|
||||
}
|
||||
mustEqualFileds.push('content-type');
|
||||
mustEqualFileds.push('cache-control');
|
||||
mustEqualFileds.push('allow');
|
||||
|
||||
// ensure the required fileds are same
|
||||
mustEqualFileds.forEach(filedName => {
|
||||
isEqual = directHeaders[filedName] === proxyHeaders[filedName];
|
||||
delete directHeaders[filedName];
|
||||
delete proxyHeaders[filedName];
|
||||
});
|
||||
|
||||
// remained filed are good to be same, but are allowed to be different
|
||||
// will warn out those different fileds
|
||||
for (const key in directHeaders) {
|
||||
if (directHeaders[key] !== proxyHeaders[key]) {
|
||||
printWarn(`key "${key}" of two response headers are different in request "${requestUrl}" :
|
||||
direct is: "${directHeaders[key]}", proxy is: "${proxyHeaders[key]}"`);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
return isEqual;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare the request between direct with proxy
|
||||
*
|
||||
*/
|
||||
function isCommonReqEqual(url, serverInstance) {
|
||||
try{
|
||||
url = url.replace('https://', '').replace('http://', ''); // only the remained path is required
|
||||
let isEqual = true;
|
||||
|
||||
const directReqObj = serverInstance.getRequestRecord(url);
|
||||
const proxyReqObj = serverInstance.getProxyRequestRecord(url);
|
||||
|
||||
// ensure the proxy header is correct
|
||||
isEqual = isEqual && proxyReqObj.headers['via-proxy'] === 'true';
|
||||
delete proxyReqObj.headers['via-proxy'];
|
||||
|
||||
// exclued accept-encoding from comparing, since the proxy will remove it before sending it out
|
||||
delete directReqObj.headers['accept-encoding'];
|
||||
|
||||
// per undefined header, proxy will set it with 0, and an empty request body
|
||||
if (typeof directReqObj.headers['content-length'] === 'undefined') {
|
||||
|
||||
directReqObj.headers['content-length'] = "0";
|
||||
}
|
||||
|
||||
directReqObj.headers['content-type'] = trimFormContentType(directReqObj.headers['content-type']);
|
||||
proxyReqObj.headers['content-type'] = trimFormContentType(proxyReqObj.headers['content-type']);
|
||||
|
||||
isEqual = isEqual && directReqObj.url === proxyReqObj.url;
|
||||
isEqual = isEqual && isObjectEqual(directReqObj.headers, proxyReqObj.headers, url);
|
||||
isEqual = isEqual && directReqObj.body === proxyReqObj.body;
|
||||
return isEqual;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* for multipart-form, the boundary will be different with each update, we trim it here
|
||||
*/
|
||||
function trimFormContentType (contentType = '') {
|
||||
return contentType.replace(/boundary.*/, '');
|
||||
}
|
||||
|
||||
|
||||
function printLog (content) {
|
||||
console.log(color.blue('==LOG==: ' + content));
|
||||
}
|
||||
|
||||
function printWarn(content) {
|
||||
console.log(color.magenta('==WARN==: ' + content));
|
||||
}
|
||||
|
||||
function printError(content) {
|
||||
console.log(color.red('==ERROR==: ' + content));
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
isObjectEqual,
|
||||
isCommonResHeaderEqual,
|
||||
printLog,
|
||||
printWarn,
|
||||
printError,
|
||||
isCommonReqEqual
|
||||
};
|
||||
262
test/util/HttpUtil.js
Normal file
262
test/util/HttpUtil.js
Normal file
@@ -0,0 +1,262 @@
|
||||
/**
|
||||
* An util to make the request out
|
||||
*
|
||||
*/
|
||||
const querystring = require('querystring');
|
||||
const http = require('http');
|
||||
const zlib = require('zlib');
|
||||
const Buffer = require('buffer').Buffer;
|
||||
const request = require('request');
|
||||
const fs = require('fs');
|
||||
const WebSocket = require('ws');
|
||||
const HttpsProxyAgent = require('https-proxy-agent');
|
||||
|
||||
const DEFAULT_HOST = 'localhost';
|
||||
const PROXY_HOST = 'http://localhost:8001';
|
||||
const SOCKET_PROXY_HOST = 'http://localhost:8001';
|
||||
|
||||
|
||||
const HTTP_SERVER_BASE = 'http://localhost:3000';
|
||||
const HTTPS_SERVER_BASE = 'https://localhost:3001';
|
||||
const WS_SERVER_BASE = 'ws://localhost:3000';
|
||||
const WSS_SERVER_BASE = 'wss://localhost:3001';
|
||||
|
||||
const DEFAULT_PROXY_OPTIONS = {
|
||||
port: 8001, // proxy的端口
|
||||
method: 'GET',
|
||||
host: 'localhost'
|
||||
};
|
||||
|
||||
const DEFAULT_OPTIONS = {
|
||||
|
||||
};
|
||||
|
||||
function getHostFromUrl (url = '') {
|
||||
const hostReg = /^(https{0,1}:\/\/)(\w+)/;
|
||||
const match = url.match(hostReg);
|
||||
|
||||
return match && match[2] ? match[2] : '';
|
||||
}
|
||||
|
||||
function getPortFromUrl (url = '') {
|
||||
const portReg = /^https{0,1}:\/\/\w+(:(\d+)){0,1}/;
|
||||
const match = url.match(portReg);
|
||||
let port = match && match[2] ? match[2] : '';
|
||||
|
||||
if (!port) {
|
||||
port = url.indexOf('https://') === 0 ? 443 : 80;
|
||||
}
|
||||
return port;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取url中的path
|
||||
*/
|
||||
function getPathFromUrl (url = '') {
|
||||
const pathReg = /^https{0,1}:\/\/\w+(:\d+){0,1}(.+)/;
|
||||
const match = url.match(pathReg);
|
||||
const path = match && match[3] ? match[2] : url;
|
||||
return path;
|
||||
}
|
||||
|
||||
function proxyRequest (method = 'GET', url, params, headers = {}) {
|
||||
return doRequest(method, url, params, headers, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* 直接请求到真实服务器,不经过代理服务器
|
||||
*
|
||||
*/
|
||||
function directRequest (method = 'GET', url, params, headers = {}) {
|
||||
return doRequest(method, url, params, headers);
|
||||
}
|
||||
|
||||
function directUpload (url, filepath, formParams = {}, headers = {}) {
|
||||
return doUpload(url, 'POST', filepath, formParams, headers);
|
||||
}
|
||||
|
||||
function proxyUpload (url, filepath, formParams = {}, headers = {}) {
|
||||
return doUpload(url, 'POST', filepath, formParams, headers, true);
|
||||
}
|
||||
|
||||
function directPutUpload (url, filepath, formParams = {}, headers = {}) {
|
||||
return doUpload(url, 'PUT', filepath, formParams, headers);
|
||||
}
|
||||
|
||||
function proxyPutUpload (url, filepath, headers = {}) {
|
||||
return doUpload(url, 'PUT', filepath, headers, true);
|
||||
}
|
||||
|
||||
function doRequest (method = 'GET', url, params, headers = {}, isProxy) {
|
||||
headers = Object.assign({}, headers);
|
||||
const requestData = {
|
||||
method: method,
|
||||
form: params,
|
||||
url: url,
|
||||
headers: headers,
|
||||
rejectUnauthorized: false
|
||||
};
|
||||
|
||||
if (isProxy) {
|
||||
requestData.proxy = PROXY_HOST;
|
||||
requestData.headers['via-proxy'] = 'true';
|
||||
}
|
||||
|
||||
const requestTask = new Promise((resolve, reject) => {
|
||||
request(
|
||||
requestData,
|
||||
function (error, response, body) {
|
||||
if (error) {
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
resolve(response);
|
||||
}
|
||||
);
|
||||
});
|
||||
return requestTask;
|
||||
}
|
||||
|
||||
function doUpload (url, method, filepath, formParams, headers = {}, isProxy) {
|
||||
let formData = {
|
||||
file: fs.createReadStream(filepath)
|
||||
};
|
||||
|
||||
formData = Object.assign({}, formData, formParams);
|
||||
headers = Object.assign({}, headers);
|
||||
|
||||
const requestData = {
|
||||
formData: formData,
|
||||
url: url,
|
||||
method: method,
|
||||
headers: headers,
|
||||
json: true,
|
||||
rejectUnauthorized: false
|
||||
};
|
||||
|
||||
if (isProxy) {
|
||||
requestData.proxy = PROXY_HOST;
|
||||
requestData.headers['via-proxy'] = 'true';
|
||||
}
|
||||
const requestTask = new Promise((resolve, reject) => {
|
||||
request(
|
||||
requestData,
|
||||
function (error, response, body) {
|
||||
if (error) {
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
resolve(response);
|
||||
}
|
||||
);
|
||||
});
|
||||
return requestTask;
|
||||
}
|
||||
|
||||
function doWebSocket(url, isProxy) {
|
||||
let ws;
|
||||
if (isProxy) {
|
||||
const agent = new HttpsProxyAgent(SOCKET_PROXY_HOST);
|
||||
ws = new WebSocket(url, {
|
||||
agent: agent,
|
||||
rejectUnauthorized: false
|
||||
});
|
||||
} else {
|
||||
ws = new WebSocket(url, {
|
||||
rejectUnauthorized: false
|
||||
});
|
||||
}
|
||||
|
||||
return ws;
|
||||
}
|
||||
|
||||
function proxyGet (url, params, headers = {}) {
|
||||
return proxyRequest('GET', url, params, headers);
|
||||
}
|
||||
|
||||
function proxyPost (url, params, headers = {}) {
|
||||
return proxyRequest('POST', url, params, headers);
|
||||
}
|
||||
|
||||
function proxyPut (url, params, headers = {}) {
|
||||
return proxyRequest('PUT', url, params, headers);
|
||||
}
|
||||
|
||||
function proxyDelete (url, params, headers = {}) {
|
||||
return proxyRequest('DELETE', url, params, headers);
|
||||
}
|
||||
|
||||
function proxyHead(url, headers = {}) {
|
||||
return proxyRequest('HEAD', url, {}, headers);
|
||||
}
|
||||
|
||||
function proxyOptions(url, headers = {}) {
|
||||
return proxyRequest('OPTIONS', url, {}, headers);
|
||||
}
|
||||
|
||||
function directGet (url, params, headers = {}) {
|
||||
return directRequest('GET', url, params, headers);
|
||||
}
|
||||
|
||||
function directPost (url, params, headers = {}) {
|
||||
return directRequest('POST', url, params, headers);
|
||||
}
|
||||
|
||||
function directPut (url, params, headers = {}) {
|
||||
return directRequest('PUT', url, params, headers);
|
||||
}
|
||||
|
||||
function directDelete (url, params, headers = {}) {
|
||||
return directRequest('DELETE', url, params, headers);
|
||||
}
|
||||
|
||||
function directHead (url, headers = {}) {
|
||||
return directRequest('HEAD', url, {} , headers);
|
||||
}
|
||||
|
||||
function directOptions (url, headers ={}) {
|
||||
return directRequest('OPTIONS', url, {}, headers);
|
||||
}
|
||||
|
||||
function proxyWs (url) {
|
||||
return doWebSocket(url, true);
|
||||
}
|
||||
|
||||
function directWs (url) {
|
||||
return doWebSocket(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* generate the final url based on protocol and path
|
||||
*
|
||||
*/
|
||||
function generateUrl (protocol, urlPath) {
|
||||
return protocol === 'http' ? HTTP_SERVER_BASE + urlPath : HTTPS_SERVER_BASE + urlPath;
|
||||
}
|
||||
|
||||
function generateWsUrl (protocol, urlPath) {
|
||||
return protocol === 'wss' ? WSS_SERVER_BASE + urlPath : WS_SERVER_BASE + urlPath;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
proxyGet,
|
||||
proxyPost,
|
||||
directGet,
|
||||
directPost,
|
||||
directUpload,
|
||||
proxyUpload,
|
||||
generateUrl,
|
||||
proxyWs,
|
||||
directWs,
|
||||
generateWsUrl,
|
||||
directPut,
|
||||
proxyPut,
|
||||
directDelete,
|
||||
proxyDelete,
|
||||
directHead,
|
||||
proxyHead,
|
||||
directOptions,
|
||||
proxyOptions,
|
||||
directPutUpload,
|
||||
proxyPutUpload
|
||||
};
|
||||
65
test/util/ProxyServerUtil.js
Normal file
65
test/util/ProxyServerUtil.js
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Utility class for creating proxy server, used to create specfied proxy server
|
||||
*
|
||||
*/
|
||||
|
||||
let proxy = require('../../proxy.js');
|
||||
const util = require('../../lib/util.js');
|
||||
|
||||
const DEFAULT_OPTIONS = {
|
||||
type: "http",
|
||||
port: 8001,
|
||||
hostname: "localhost",
|
||||
dbFile: null, // optional, save request data to a specified file, will use in-memory db if not specified
|
||||
webPort: 8002, // optional, port for web interface
|
||||
socketPort: 8003, // optional, internal port for web socket, replace this when it is conflict with your own service
|
||||
throttle: 10000, // optional, speed limit in kb/s
|
||||
disableWebInterface: false, //optional, set it when you don't want to use the web interface
|
||||
setAsGlobalProxy: false, //set anyproxy as your system proxy
|
||||
interceptHttps: true, // intercept https as well
|
||||
silent: false //optional, do not print anything into terminal. do not set it when you are still debugging.
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @return An instance of proxy, could be closed by calling `instance.close()`
|
||||
*/
|
||||
function defaultProxyServer () {
|
||||
proxy = util.freshRequire('../proxy.js');
|
||||
|
||||
const options = util.merge({}, DEFAULT_OPTIONS);
|
||||
options.rule = util.freshRequire('./rule_default.js');
|
||||
return new proxy.proxyServer(options);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create proxy server with rule
|
||||
* @param rules
|
||||
Object, the rule object which contains required intercept method
|
||||
@return An instance of proxy, could be closed by calling `instance.close()`
|
||||
*/
|
||||
function proxyServerWithRule (rule) {
|
||||
proxy = util.freshRequire('../proxy.js');
|
||||
|
||||
const options = util.merge({}, DEFAULT_OPTIONS);
|
||||
options.rule = rule;
|
||||
|
||||
return new proxy.proxyServer(options);
|
||||
}
|
||||
|
||||
function proxyServerWithoutHttpsIntercept (rule) {
|
||||
proxy = util.freshRequire('../proxy.js');
|
||||
|
||||
const options = util.merge({}, DEFAULT_OPTIONS);
|
||||
if (rule) {
|
||||
options.rule = rule;
|
||||
}
|
||||
options.interceptHttps = false;
|
||||
return new proxy.proxyServer(options);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
defaultProxyServer,
|
||||
proxyServerWithoutHttpsIntercept,
|
||||
proxyServerWithRule
|
||||
};
|
||||
Reference in New Issue
Block a user