mirror of
https://github.com/avwo/whistle.git
synced 2026-10-18 14:41:12 +08:00
274 lines
7.3 KiB
JavaScript
274 lines
7.3 KiB
JavaScript
var http = require('http');
|
|
var https = require('https');
|
|
var parseUrl = require('url').parse;
|
|
var net = require('net');
|
|
var path = require('path');
|
|
var StringDecoder = require('string_decoder').StringDecoder;
|
|
require('should');
|
|
require('should-http');
|
|
var fs = require('fs');
|
|
var fse = require('fs-extra2');
|
|
var startWhistle = require('../index');
|
|
var socks = require('sockx');
|
|
var util = require('./util.test');
|
|
var config = require('./config.test');
|
|
var events = require('./events');
|
|
var values = util.getValues();
|
|
var testList = fs.readdirSync(path.join(__dirname, './units'));
|
|
var defaultRules = fs.readFileSync(path.join(__dirname, 'rules.txt'), {encoding: 'utf8'});
|
|
var options = {
|
|
key: fs.readFileSync(path.join(__dirname, 'assets/certs/root.key')),
|
|
cert: fs.readFileSync(path.join(__dirname, 'assets/certs/_root.crt'))
|
|
};
|
|
var count = 6;
|
|
|
|
var WebSocketServer = require('ws').Server;
|
|
var wss = new WebSocketServer({ port: config.wsPort });
|
|
var WHISTLE_PATH = process.env.WHISTLE_PATH = __dirname;
|
|
var PLUGINS_PATH = path.join(WHISTLE_PATH, '.whistle/node_modules');
|
|
//Node7及以下使用非SNI Server
|
|
if (process.versions.modules <= 51) {
|
|
require('hagent').serverAgent.existsServer = function() {
|
|
return true;
|
|
};
|
|
}
|
|
|
|
fse.removeSync(path.join(WHISTLE_PATH, '.whistle'));
|
|
fse.copySync(path.join(__dirname, 'plugins'), PLUGINS_PATH);
|
|
|
|
wss.on('connection', function connection(ws) {
|
|
var req = ws.upgradeReq;
|
|
ws.on('message', function(msg) {
|
|
ws.send(JSON.stringify({
|
|
type: 'server',
|
|
method: req.method,
|
|
headers: req.headers,
|
|
body: msg
|
|
}, null, '\t'));
|
|
});
|
|
});
|
|
|
|
http.createServer(function(req, res) {
|
|
req.on('error', util.noop);
|
|
res.on('error', util.noop);
|
|
|
|
var body = '';
|
|
var decoder = new StringDecoder('utf8');
|
|
req.on('data', function(data) {
|
|
body += decoder.write(data);
|
|
});
|
|
req.on('end', function() {
|
|
body += decoder.end();
|
|
res.end(JSON.stringify({
|
|
type: 'server',
|
|
url: req.url,
|
|
method: req.method,
|
|
headers: req.headers,
|
|
body: body
|
|
}, null, '\t'));
|
|
});
|
|
}).listen(config.serverPort, startTest);
|
|
|
|
https.createServer(options, function(req, res) {
|
|
if (req.url.indexOf('test-remote.rules') !== -1) {
|
|
return res.end('str2.w2.org/index.html file://`(${search.replace(a,b)})`\nstr2.w2.org/index2.html file://`(${query.replace(/a/g,b)})`');
|
|
}
|
|
res.end(JSON.stringify({
|
|
headers: req.headers,
|
|
body: 'test'
|
|
}));
|
|
}).listen(config.httpsPort, startTest);
|
|
values['options.html'] = {
|
|
method: 'options'
|
|
};
|
|
var proxy = startWhistle({
|
|
port: config.port,
|
|
storage: 'test_',
|
|
mode: 'strict',
|
|
httpPort: config.httpServerPort,
|
|
httpsPort: config.httpsServerPort,
|
|
certDir: path.join(__dirname, 'assets/certs'),
|
|
debugMode: true,
|
|
localUIHost: 'local.whistle.com|local2.whistle.com&localn.whistle.com',
|
|
pluginHost: 'test=test.local.whistle.com|b.test.local.whistle.com&test3.local.whistle.com,',
|
|
rules: {
|
|
Default: defaultRules,
|
|
test: {
|
|
rules: 'test.options.com file://{options.html}\n@'
|
|
+ path.join(__dirname, 'assets/files/rules.txt')
|
|
+ '\n@https://127.0.0.1:' + config.httpsPort + '/test-remote.rules',
|
|
enable: true
|
|
},
|
|
abc: '123'
|
|
},
|
|
values: values,
|
|
copy: true
|
|
}, startTest);
|
|
|
|
proxy.on('tunnelRequest', util.noop);
|
|
proxy.on('wsRequest', util.noop);
|
|
proxy.on('_request', util.noop);
|
|
proxy.setUIHost('_');
|
|
proxy.setUIHost();
|
|
proxy.setPluginUIHost('test', '_');
|
|
proxy.setPluginUIHost('whistle.test', '');
|
|
var socksServer = socks.createServer(function(info, accept, deny) {
|
|
var socket, client;
|
|
if (info.dstPort === 443) {
|
|
if (socket = accept(true)) {
|
|
client = net.connect({
|
|
host: '127.0.0.1',
|
|
port: 5566
|
|
}, function() {
|
|
socket.pipe(client).pipe(socket);
|
|
});
|
|
}
|
|
return;
|
|
}
|
|
if (info.dstPort === 8081) {
|
|
if (socket = accept(true)) {
|
|
client = net.connect({
|
|
host: '127.0.0.1',
|
|
port: 8081
|
|
}, function() {
|
|
socket.pipe(client).pipe(socket);
|
|
});
|
|
}
|
|
return;
|
|
}
|
|
if (socket = accept(true)) {
|
|
var body = JSON.stringify({
|
|
port: config.socksPort
|
|
});
|
|
socket.end([
|
|
'HTTP/1.1 200 OK',
|
|
'Connection: close',
|
|
'Content-Type: text/plain;charset=utf8',
|
|
'Content-Length: ' + Buffer.byteLength(body),
|
|
'',
|
|
body
|
|
].join('\r\n'));
|
|
}
|
|
});
|
|
|
|
var authSocksServer = socks.createServer(function(info, accept, deny) {
|
|
var socket;
|
|
if (info.dstPort === 443) {
|
|
if (socket = accept(true)) {
|
|
var client = net.connect({
|
|
host: '127.0.0.1',
|
|
port: 5566
|
|
}, function() {
|
|
socket.pipe(client).pipe(socket);
|
|
});
|
|
}
|
|
return;
|
|
}
|
|
if (socket = accept(true)) {
|
|
var body = JSON.stringify({
|
|
port: config.authSocksPort
|
|
});
|
|
socket.end([
|
|
'HTTP/1.1 200 OK',
|
|
'Connection: close',
|
|
'Content-Type: text/plain;charset=utf8',
|
|
'Content-Length: ' + Buffer.byteLength(body),
|
|
'',
|
|
body
|
|
].join('\r\n'));
|
|
}
|
|
});
|
|
|
|
socksServer.useAuth(socks.auth.None());
|
|
authSocksServer.useAuth(socks.auth.UserPassword(function(user, password, cb) {
|
|
cb(user == 'test' && password == 'hello1234');
|
|
}));
|
|
|
|
socksServer.listen(config.socksPort, startTest);
|
|
authSocksServer.listen(config.authSocksPort, startTest);
|
|
|
|
/**
|
|
* 不用处理异常
|
|
*/
|
|
var server = http.createServer(function(req, res) {
|
|
var fullUrl = /^http:/.test(req.url) ? req.url : 'http://' + req.headers.host + req.url;
|
|
var options = parseUrl(fullUrl);
|
|
delete options.hostname;
|
|
options.host = '127.0.0.1';
|
|
options.method = req.method;
|
|
options.headers = req.headers;
|
|
var client = http.request(options, function(_res) {
|
|
_res.pipe(res);
|
|
});
|
|
req.pipe(client);
|
|
});
|
|
|
|
server.on('connect', function(req, socket) {
|
|
var tunnelUrl = 'tunnel://' + (/^[^:\/]+:\d+$/.test(req.url) ? req.url : req.headers.host);
|
|
var options = parseUrl(tunnelUrl);
|
|
var client = net.connect({
|
|
host: '127.0.0.1',
|
|
port: options.port || 443
|
|
}, function() {
|
|
socket.pipe(client).pipe(socket);
|
|
socket.write('HTTP/1.1 200 Connection Established\r\nProxy-Agent: whistle/test\r\n\r\n');
|
|
});
|
|
});
|
|
|
|
server.listen(config.proxyPort, startTest);
|
|
|
|
function startTest() {
|
|
if (--count > 0) {
|
|
return;
|
|
}
|
|
|
|
var done;
|
|
function testAll() {
|
|
if (done) {
|
|
return;
|
|
}
|
|
done = true;
|
|
var lastUnit = 'ui.test.js';
|
|
testList.splice(testList.indexOf(lastUnit), 1);
|
|
testList.splice(testList.indexOf('tplStr.test.js'), 1);
|
|
testList.push('tplStr.test.js');
|
|
testList = testList.map(function(name) {
|
|
return require('./units/' + name);
|
|
});
|
|
lastUnit = require('./units/' + lastUnit);
|
|
var stride = 30;
|
|
var execUnit = function() {
|
|
var list = testList.slice(0, stride);
|
|
if (!list.length) {
|
|
util.setEnd();
|
|
lastUnit();
|
|
return true;
|
|
}
|
|
testList = testList.slice(stride);
|
|
list.forEach(function(fn) {
|
|
fn();
|
|
});
|
|
};
|
|
execUnit();
|
|
events.on('next', execUnit);
|
|
}
|
|
var index = 0;
|
|
(function getData() {
|
|
var query = '?name=host&value=com&url=com';
|
|
var dataUrl = 'http://local.whistlejs.com/cgi-bin/get-data';
|
|
if (++index > 2) {
|
|
index = 0;
|
|
dataUrl += query + 'ip=self,1.1.1.1';
|
|
} else if (index === 1) {
|
|
dataUrl += query + 'ip=self';
|
|
}
|
|
util.request(dataUrl, function() {
|
|
testAll();
|
|
setTimeout(getData, 10000);
|
|
});
|
|
})();
|
|
}
|
|
|
|
|
|
|