├── .gitignore ├── README.md ├── demo └── test.js ├── imgs ├── screenshoot1.png └── screenshoot2.png ├── index.js ├── lib └── MiniProxy.js ├── package-lock.json └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_STORE 2 | node_modules 3 | *~ 4 | *.pyc 5 | static 6 | .grunt 7 | _SpecRunner.html 8 | __benchmarks__ 9 | build/ 10 | coverage/ 11 | .module-cache 12 | *.gem 13 | docs/.bundle 14 | docs/code 15 | docs/_site 16 | docs/.sass-cache 17 | docs/js/* 18 | docs/downloads/*.zip 19 | docs/vendor/bundle 20 | fixtures/dom/public/react-dom.js 21 | fixtures/dom/public/react.js 22 | test/the-files-to-test.generated.js 23 | *.log* 24 | chrome-user-data 25 | *.sublime-project 26 | *.sublime-workspace 27 | .idea 28 | *.iml 29 | .vscode 30 | *.swp 31 | *.swo 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mini-proxy 2 | 3 | A very mini transparent proxy for http/https by NodeJS.Just like squid. 4 | 5 | 可能是最小最轻量的透明web代理,完美支持http&https。 6 | 7 | ## Installation 8 | 9 | ```bash 10 | $ npm install mini-proxy 11 | ``` 12 | 13 | ## Features 14 | 15 | * mini. 16 | * easy to learn and use. 17 | * support http & https(don't need certificate) 18 | * support modify request(http&https) and response(http only) 19 | 20 | 21 | 22 | ## Usage 23 | 24 |
25 | var MiniProxy = require("mini-proxy");
26 | 
27 | var myProxy = new MiniProxy({
28 | 	"port": 9393,
29 | 	"onBeforeRequest": function(requestOptions) {
30 | 		console.log("proxy request :" + requestOptions.host + 
31 | 			    (requestOptions.path || ''));
32 | 	}
33 | });
34 | 
35 | myProxy.start();
36 | console.log("proxy start at 9393");
37 | 
38 | 
39 | 40 | change system proxy to 127.0.0.1:9393. 41 | 42 | 43 | ![](https://raw.githubusercontent.com/liyangready/mini-proxy/master/imgs/screenshoot1.png) 44 | 45 | 46 | ![](https://raw.githubusercontent.com/liyangready/mini-proxy/master/imgs/screenshoot2.png) 47 | it wroks well! 48 | console log: 49 |
50 | $ DEBUG=mproxy node demo/test.js
51 | proxy start at 9393
52 | proxy request :www.microsoft.com/pkiops/crl/MicSecSerCA2011_2011-10-18.crl
53 | proxy request :crl.microsoft.com/pki/crl/products/tspca.crl
54 | proxy request :www.baidu.com
55 | 
56 | 57 | ### Other options 58 |
59 | var myProxy = new MiniProxy({
60 | 	"port": 9393,
61 | 	"onBeforeRequest": function(requestOptions) {
62 | 	//u can change the request param here
63 | 		console.log("proxy request :" + requestOptions.host + 
64 | 			    (requestOptions.path || ''));
65 | 	},
66 | 	"onBeforeResponse": function(remoteResponse) {
67 | 	// u can change the response here
68 | 	},
69 | 	"onRequestError": function(e, req, res) {}
70 | });
71 | 
72 | 73 | Use ```DEBUG=mproxy``` to open error log. 74 | -------------------------------------------------------------------------------- /demo/test.js: -------------------------------------------------------------------------------- 1 | var MiniProxy = require("../index.js"); 2 | var myProxy = new MiniProxy({ 3 | "port": 9393, 4 | "onBeforeRequest": function(requestOptions) { 5 | console.log("proxy request :" + requestOptions.host + (requestOptions.path || '')); 6 | } 7 | }); 8 | 9 | myProxy.start(); 10 | console.log("proxy start at 9393"); -------------------------------------------------------------------------------- /imgs/screenshoot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liyangready/mini-proxy/49c241c6c3ee687d4606e78e33cfcaaa28ea791c/imgs/screenshoot1.png -------------------------------------------------------------------------------- /imgs/screenshoot2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liyangready/mini-proxy/49c241c6c3ee687d4606e78e33cfcaaa28ea791c/imgs/screenshoot2.png -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var miniProxy = require("./lib/MiniProxy.js"); 2 | 3 | module.exports = miniProxy; -------------------------------------------------------------------------------- /lib/MiniProxy.js: -------------------------------------------------------------------------------- 1 | var http = require("http"); 2 | var net = require("net"); 3 | var url = require("url"); 4 | var port; 5 | var mpConsole = require("debug")("mproxy"); 6 | 7 | function MiniProxy(options) { 8 | this.port = options.port || 9393; 9 | this.onServerError = options.onServerError || function() {}; 10 | this.onBeforeRequest = options.onBeforeRequest || function() {}; 11 | this.onBeforeResponse = options.onBeforeResponse || function() {}; 12 | this.onRequestError = options.onRequestError || function() {}; 13 | } 14 | MiniProxy.prototype.start = function() { 15 | var server = http.createServer(); 16 | 17 | server.on("request", this.requestHandler); 18 | server.on("connect", this.connectHandler); 19 | 20 | server.on("error", this.onServerError); 21 | server.on("beforeRequest", this.onBeforeRequest); 22 | server.on("beforeResponse", this.onBeforeResponse); 23 | server.on("requestError", this.onRequestError); 24 | 25 | server.listen(this.port); 26 | port = this.port; 27 | } 28 | 29 | MiniProxy.prototype.requestHandler = function(req, res) { 30 | try { 31 | 32 | var self = this; // this -> server 33 | var path = req.headers.path || url.parse(req.url).path; 34 | var requestOptions = { 35 | host: req.headers.host.split(':')[0], 36 | port: req.headers.host.split(':')[1] || 80, 37 | path: path, 38 | method: req.method, 39 | headers: req.headers 40 | }; 41 | 42 | //check url 43 | if (requestOptions.host == "127.0.0.1" && requestOptions.port == port) { 44 | res.writeHead(200, { 45 | 'Content-Type': 'text/plain' 46 | }); 47 | res.write("ok"); 48 | res.end(); 49 | return; 50 | } 51 | 52 | //u can change request param here 53 | self.emit("beforeRequest", requestOptions); 54 | requestRemote(requestOptions, req, res, self); 55 | 56 | } catch (e) { 57 | mpConsole("requestHandlerError" + e.message); 58 | } 59 | 60 | function requestRemote(requestOptions, req, res, proxy) { 61 | var remoteRequest = http.request(requestOptions, function(remoteResponse) { 62 | remoteResponse.headers['proxy-agent'] = 'Easy Proxy 1.0'; 63 | 64 | // write out headers to handle redirects 65 | res.writeHead(remoteResponse.statusCode, '', remoteResponse.headers); 66 | 67 | // u can change resonse here 68 | proxy.emit("beforeResponse", remoteResponse); 69 | remoteResponse.pipe(res); 70 | // Res could not write, but it could close connection 71 | // https://github.com/liyangready/mini-proxy/issues/2 72 | // res.pipe(remoteResponse); 73 | }); 74 | 75 | remoteRequest.on('error', function(e) { 76 | proxy.emit("requestError", e, req, res); 77 | 78 | res.writeHead(502, 'Proxy fetch failed'); 79 | // res.end(); 80 | // remoteRequest.end(); 81 | }); 82 | 83 | req.pipe(remoteRequest); 84 | 85 | // Just in case if socket will be shutdown before http.request will connect 86 | // to the server. 87 | res.on('close', function() { 88 | remoteRequest.abort(); 89 | }); 90 | } 91 | 92 | } 93 | 94 | MiniProxy.prototype.connectHandler = function(req, socket, head) { 95 | try { 96 | var self = this; 97 | 98 | var requestOptions = { 99 | host: req.url.split(':')[0], 100 | port: req.url.split(':')[1] || 443 101 | }; 102 | 103 | self.emit("beforeRequest", requestOptions); 104 | connectRemote(requestOptions, socket); 105 | 106 | function ontargeterror(e) { 107 | mpConsole(req.url + " Tunnel error: " + e); 108 | _synReply(socket, 502, "Tunnel Error", {}, function() { 109 | try { 110 | socket.end(); 111 | } 112 | catch(e) { 113 | mpConsole('end error' + e.message); 114 | } 115 | 116 | }); 117 | } 118 | 119 | function connectRemote(requestOptions, socket) { 120 | var tunnel = net.createConnection(requestOptions, function() { 121 | //format http protocol 122 | _synReply(socket, 200, 'Connection established', { 123 | 'Connection': 'keep-alive', 124 | 'Proxy-Agent': 'Easy Proxy 1.0' 125 | }, 126 | function(error) { 127 | if (error) { 128 | mpConsole("syn error", error.message); 129 | tunnel.end(); 130 | socket.end(); 131 | return; 132 | } 133 | tunnel.pipe(socket); 134 | socket.pipe(tunnel); 135 | } 136 | ); 137 | }); 138 | socket.on('error', function(e) { 139 | mpConsole('socket error:', e); 140 | }); 141 | tunnel.setNoDelay(true); 142 | 143 | tunnel.on('error', ontargeterror); 144 | } 145 | } catch (e) { 146 | mpConsole("connectHandler error: " + e.message); 147 | } 148 | 149 | } 150 | 151 | function _synReply(socket, code, reason, headers, cb) { 152 | try { 153 | var statusLine = 'HTTP/1.1 ' + code + ' ' + reason + '\r\n'; 154 | var headerLines = ''; 155 | for (var key in headers) { 156 | headerLines += key + ': ' + headers[key] + '\r\n'; 157 | } 158 | socket.write(statusLine + headerLines + '\r\n', 'UTF-8', cb); 159 | } catch (error) { 160 | cb(error); 161 | } 162 | } 163 | 164 | module.exports = MiniProxy; -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mini-proxy", 3 | "version": "1.0.2", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "debug": { 8 | "version": "4.1.1", 9 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", 10 | "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", 11 | "requires": { 12 | "ms": "^2.1.1" 13 | } 14 | }, 15 | "ms": { 16 | "version": "2.1.1", 17 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", 18 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mini-proxy", 3 | "version": "1.0.3", 4 | "description": "very easy to do transparent proxy", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/liyangready/mini-proxy.git" 12 | }, 13 | "keywords": [ 14 | "proxy" 15 | ], 16 | "author": "leon.li", 17 | "license": "ISC", 18 | "bugs": { 19 | "url": "https://github.com/liyangready/mini-proxy/issues" 20 | }, 21 | "homepage": "https://github.com/liyangready/mini-proxy#readme", 22 | "dependencies": { 23 | "debug": "^4.1.1" 24 | } 25 | } 26 | --------------------------------------------------------------------------------