diff --git a/lib/requestHandler.js b/lib/requestHandler.js index 7f664c8..9618147 100644 --- a/lib/requestHandler.js +++ b/lib/requestHandler.js @@ -550,14 +550,14 @@ function getConnectReqHandler(userRule, recorder, httpsServerMgr) { shouldIntercept = reqHandlerCtx.forceProxyHttps; } }) - .then(() => - new Promise((resolve) => { + .then(() => { + return new Promise((resolve) => { // mark socket connection as established, to detect the request protocol cltSocket.write('HTTP/' + req.httpVersion + ' 200 OK\r\n\r\n', 'UTF-8', resolve); - }) - ) - .then(() => - new Promise((resolve, reject) => { + }); + }) + .then(() => { + return new Promise((resolve, reject) => { let resolved = false; cltSocket.on('data', (chunk) => { requestStream.push(chunk); @@ -580,11 +580,19 @@ function getConnectReqHandler(userRule, recorder, httpsServerMgr) { resolve(); } }); + cltSocket.on('error', (error) => { + logUtil.printLog(util.collectErrorLog(error), logUtil.T_ERR); + co.wrap(function *() { + try { + yield userRule.onClientSocketError(requestDetail, error); + } catch (e) { } + }); + }); cltSocket.on('end', () => { requestStream.push(null); }); - }) - ) + }); + }) .then((result) => { // log and recorder if (shouldIntercept) { diff --git a/lib/rule_default.js b/lib/rule_default.js index dc74910..b3d29e9 100644 --- a/lib/rule_default.js +++ b/lib/rule_default.js @@ -66,4 +66,16 @@ module.exports = { *onConnectError(requestDetail, error) { return null; }, + + + /** + * + * + * @param {any} requestDetail + * @param {any} error + * @returns + */ + *onClientSocketError(requestDetail, error) { + return null; + }, }; diff --git a/package.json b/package.json index 30b857a..20625e4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "anyproxy", - "version": "4.0.12", + "version": "4.0.13", "description": "A fully configurable HTTP/HTTPS proxy in Node.js", "main": "proxy.js", "bin": { @@ -61,7 +61,6 @@ "eslint-plugin-react": "^7.4.0", "extract-text-webpack-plugin": "^3.0.2", "file-loader": "^0.9.0", - "https-proxy-agent": "^1.0.0", "jasmine": "^2.5.3", "koa": "^1.2.1", "koa-body": "^1.4.0", @@ -85,6 +84,7 @@ "stream-equal": "0.1.8", "style-loader": "^0.13.1", "svg-inline-loader": "^0.7.1", + "tunnel": "^0.0.6", "url-loader": "^0.5.7", "webpack": "^3.10.0", "worker-loader": "^0.7.1" diff --git a/proxy.js b/proxy.js index a80ca2b..2977acb 100644 --- a/proxy.js +++ b/proxy.js @@ -271,7 +271,7 @@ class ProxyCore extends events.EventEmitter { for (const cltSocketItem of this.requestHandler.cltSockets) { const key = cltSocketItem[0]; const cltSocket = cltSocketItem[1]; - logUtil.printLog(`endding https cltSocket : ${key}`); + logUtil.printLog(`closing https cltSocket : ${key}`); cltSocket.end(); } diff --git a/test/spec_rule/rule_deal_error_spec.js b/test/spec_rule/rule_deal_error_spec.js index d208b9f..e1794b3 100644 --- a/test/spec_rule/rule_deal_error_spec.js +++ b/test/spec_rule/rule_deal_error_spec.js @@ -4,9 +4,10 @@ */ const ProxyServerUtil = require('../util/ProxyServerUtil.js'); const { proxyGet } = require('../util/HttpUtil.js'); - const { printLog } = require('../util/CommonUtil.js'); +const domain_not_exists = 'not_exist.not_exist_anyproxy_io_domain.com'; + let errorInRule = null; const ruleNotDealError = { *onError(requestDetail, error) { @@ -62,7 +63,7 @@ function testWrapper(protocol) { }); it('Should get a request error', done => { - const url = protocol + '://not_exist_url.anyproxy.io'; + const url = protocol + `://${domain_not_exists}`; proxyGet(url) .then(proxyRes => { expect(proxyRes.statusCode).toEqual(500); @@ -99,7 +100,7 @@ function testWrapper(protocol) { }); it('Should get a request error', done => { - const url = protocol + '://not_exist_url.anyproxy.io'; + const url = protocol + `://${domain_not_exists}`; proxyGet(url) .then(proxyRes => { expect(proxyRes.statusCode).toEqual(200); @@ -140,7 +141,7 @@ function testHttpsConnect() { }); it('Should get a request error', done => { - const url = 'https://not_exist_url.anyproxy.io'; + const url = `https://${domain_not_exists}`; proxyGet(url) .then(proxyRes => { done.fail('should throw an error when requesting'); diff --git a/test/util/HttpUtil.js b/test/util/HttpUtil.js index 2c03002..5b79360 100644 --- a/test/util/HttpUtil.js +++ b/test/util/HttpUtil.js @@ -6,19 +6,21 @@ const request = require('request'); const fs = require('fs'); const WebSocket = require('ws'); -const HttpsProxyAgent = require('https-proxy-agent'); +const tunnel = require('tunnel'); const stream = require('stream'); +const nodeUrl = require('url'); 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_CHUNK_COLLECT_THRESHOLD = 20 * 1024 * 1024; // about 20 mb +const SOCKE_PROXY_URL_OBJ = nodeUrl.parse(SOCKET_PROXY_HOST); + class commonStream extends stream.Readable { constructor(config) { super({ @@ -191,7 +193,23 @@ function doWebSocket(url, headers = {}, isProxy) { let ws; if (isProxy) { headers['via-proxy'] = 'true'; - const agent = new HttpsProxyAgent(SOCKET_PROXY_HOST); + let agent = new tunnel.httpOverHttp({ + proxy: { + hostname: SOCKE_PROXY_URL_OBJ.hostname, + port: SOCKE_PROXY_URL_OBJ.port + } + }) + + if (url.indexOf('wss') === 0) { + agent = new tunnel.httpsOverHttp({ + rejectUnauthorized: false, + proxy: { + hostname: SOCKE_PROXY_URL_OBJ.hostname, + port: SOCKE_PROXY_URL_OBJ.port + } + }) + } + ws = new WebSocket(url, { agent, rejectUnauthorized: false,