├── .gitignore ├── LICENSE ├── README.md ├── index.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | 10 | pids 11 | logs 12 | results 13 | 14 | npm-debug.log 15 | node_modules 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 unbug 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | logproxy 2 | ======== 3 | Set up a proxy server to log http archives of your mobile devices. 4 | 5 | 6 | 7 | Install 8 | ======== 9 | ```shell 10 | npm install -g logproxy 11 | ```` 12 | 13 | Commands 14 | ========= 15 | ```shell 16 | logproxy [listen port] [only log host,..] 17 | ``` 18 | 19 | eg. 20 | ===== 21 | 1.start logproxy with default setting 22 | ```shell 23 | logproxy 24 | ``` 25 | 2.listen on port 8088 and only log hosts -- 'c.163.com' and every host matchs '126.com' 26 | ```shell 27 | logproxy 8088 c.163.com,*126.com 28 | ``` 29 | 30 | Guide 31 | ========= 32 | After run `logproxy`,you will see a log ` PROXY IS READY ON 192.168.1.102 PORT 1630`,set your device's http proxy to the IP address and port. 33 | 34 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * set up a proxy to log http archives 5 | * run: 6 | * node logproxy [listen port] [only log host,..] 7 | * eg. 8 | * 1.start logproxy with default setting 9 | * node logproxy 10 | * 2.listen on port 8088 and only log hosts -- 'c.163.com' and every host matchs '126.com' 11 | * node logproxy 8088 c.163.com,*126.com 12 | * 13 | * @auth http://www.iunbug.com 14 | */ 15 | var http = require('http'), 16 | net = require('net'), 17 | fs = require('fs'), 18 | StringDecoder = require('string_decoder').StringDecoder, 19 | Buffer = require('buffer').Buffer, 20 | Iconv = require('iconv-lite'),//https://github.com/bnoordhuis/node-iconv,https://github.com/ashtuchkin/iconv-lite 21 | chardet = require('chardet'),//https://github.com/unbug/node-chardet 22 | colors = require('colors'), 23 | util = require('util'); 24 | 25 | //prevent node.js from crashing 26 | process.on('uncaughtException', function (err) { 27 | console.log("process uncaughtException error"); 28 | console.error(err); 29 | }); 30 | 31 | var excuteArgvs = (function(){ 32 | var p = process.argv[2] || 1630, 33 | f = process.argv[3]?process.argv[3].split(','):[]; 34 | return { 35 | port: p, 36 | filterHosts: f 37 | } 38 | })();//end excuteArgvs 39 | 40 | function printLog(logs){ 41 | logs = logs || 'NULL'; 42 | if(typeof logs == 'string'){ 43 | console.log(logs); 44 | }else{ 45 | // console.log(util.inspect(logs, { showHidden: false, depth: null,colors: true})); 46 | console.dir(logs); 47 | } 48 | }//end printLog 49 | function getIPAddress() { 50 | var interfaces = require('os').networkInterfaces(); 51 | for (var devName in interfaces) { 52 | var iface = interfaces[devName]; 53 | for (var i = 0; i < iface.length; i++) { 54 | var alias = iface[i]; 55 | if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) 56 | return alias.address; 57 | } 58 | } 59 | return '0.0.0.0'; 60 | }//end getIPAddress 61 | 62 | var formatHost = (function() { 63 | var reg = /^([^:]+)(:([0-9]+))?$/i; 64 | return function(host){ 65 | var tmp = host.match(reg); 66 | return tmp?{host: tmp[1],port: tmp[3]}:{host: host} 67 | } 68 | })();//end formatHost 69 | var formatPath = (function() { 70 | var reg = /^[a-zA-Z]+:\/\/[^\/]+(\/.*)?$/i; 71 | return function(url){ 72 | var tmp = url.match(reg); 73 | return tmp?(tmp[1].length>0&&tmp[1]):'/'; 74 | } 75 | })();//end formatHost 76 | function decodeResponseBody(headers,body){ 77 | var cs; 78 | cs = headers['content-type'].match(/.*charset=(.*)[;]?/i); 79 | cs = cs && cs[1]; 80 | if(cs){ 81 | console.log(('Body charset is '+cs ).magenta.bold); 82 | if(Iconv.encodingExists(cs)){ 83 | return Iconv.decode(new Buffer(body),cs); 84 | } 85 | } 86 | return autoDecodeCharset(body); 87 | }//end decodeResponseBody 88 | function autoDecodeCharset(data){ 89 | if(data){ 90 | var buffer = new Buffer(data), 91 | charset = chardet.detect(buffer); 92 | console.log(('Data charset is '+charset ).magenta.bold); 93 | try { 94 | data = buffer.toString(charset); 95 | } catch (e) { 96 | if(Iconv.encodingExists(charset)){ 97 | data = Iconv.decode(buffer,charset); 98 | } 99 | } 100 | return data; 101 | } 102 | }//end autoDecodeCharset 103 | /** 104 | * 105 | * @param {Object} log {reqMethod,reqUrl,reqHeaders,reqData,resCode,resHeaders,resBody} 106 | */ 107 | var printClientLog = (function(){ 108 | var requestCount = 0; 109 | return function(logs){ 110 | if(!isFilterHost(logs.reqHeaders['host'])){return;} 111 | 112 | util.log(('--'+requestCount+'--------------------------- LOG REQUEST STARTED ---------------------------'+requestCount+'--').yellow); 113 | 114 | console.log('HTTP VERSION: '.magenta.bold+logs.httpVersion.red); 115 | console.log(('METHOD '+logs.reqMethod+': ').magenta.bold+logs.reqUrl.red); 116 | if( logs.resHeaders && (/image|audio|video|upload/ig).test(logs.resHeaders['content-type']) ){ 117 | printLog('CONTENT TYPE: '.magenta.bold+logs.resHeaders['content-type'].red); 118 | }else{ 119 | printLog('REQUEST HEADERS: '.magenta.bold); 120 | printLog(logs.reqHeaders); 121 | if( !(/connect/ig).test(logs.reqMethod) ){ 122 | printLog('REQUEST DATA: '.magenta.bold); 123 | printLog(autoDecodeCharset(logs.reqData)); 124 | printLog('RESPONSE STATUS CODE: '.magenta.bold+(logs.resCode+'').red); 125 | printLog('RESPONSE HEADERS: '.magenta.bold); 126 | printLog(logs.resHeaders); 127 | printLog('RESPONSE BODY: '.magenta.bold); 128 | printLog( autoDecodeCharset(logs.resBody) ); 129 | } 130 | } 131 | 132 | util.log(('--'+requestCount+'----------------------------- LOG REQUEST END ---------------------------'+requestCount+'--').yellow); 133 | 134 | requestCount++; 135 | } 136 | })();//end printClientLog 137 | function isFilterHost(host){ 138 | if(excuteArgvs.filterHosts.length<1 || host.length<1){ 139 | return true; 140 | } 141 | for(var i=0;i