diff --git a/lib/recorder.js b/lib/recorder.js
index cc8cf22..29fe21e 100644
--- a/lib/recorder.js
+++ b/lib/recorder.js
@@ -2,15 +2,18 @@
var zlib = require('zlib'),
Datastore = require('nedb'),
util = require("util"),
+ path = require("path"),
fs = require("fs"),
events = require('events'),
iconv = require('iconv-lite'),
+ proxyUtil = require("./util"),
logUtil = require("./log");
//option.filename
function Recorder(option){
var self = this,
- id = 1,
+ id = 1,
+ cachePath = proxyUtil.generateCacheDir(),
db;
option = option || {};
@@ -87,31 +90,40 @@ function Recorder(option){
};
//update recordBody if exits
+
+ //TODO : trigger update callback
+ var BODY_FILE_PRFIX = "res_body_";
self.updateRecordBody =function(id,info){
if(id == -1) return;
if(!id || !info.resBody) return;
//add to body map
//ignore image data
- if(/image/.test(info.resHeader['content-type'])){
- self.recordBodyMap[id] = "(image)";
- }else{
- self.recordBodyMap[id] = info.resBody;
- }
+ var bodyFile = path.join(cachePath,BODY_FILE_PRFIX + id);
+ fs.writeFile(bodyFile, info.resBody);
};
- self.getBody = function(id){
+ self.getBody = function(id,cb){
if(id < 0){
- return "";
+ cb && cb("");
}
- return self.recordBodyMap[id] || "";
+ var bodyFile = path.join(cachePath,BODY_FILE_PRFIX + id);
+ fs.access(bodyFile, fs.F_OK | fs.R_OK ,function(err){
+ if(err){
+ cb && cb(err);
+ }else{
+ fs.readFile(bodyFile,cb);
+ }
+ });
};
- self.getBodyUTF8 = function(id,cb){
- var bodyContent = self.getBody(id),
- result = "";
-
+ self.getDecodedBody = function(id,cb){
+ var result = {
+ type : "unknown",
+ mime : "",
+ content : ""
+ };
GLOBAL.recorder.getSingleRecord(id,function(err,doc){
//check whether this record exists
if(!doc || !doc[0]){
@@ -119,24 +131,39 @@ function Recorder(option){
return;
}
- if(!bodyContent){
- cb(null,result);
- }else{
- var record = doc[0],
- resHeader = record['resHeader'] || {};
- try{
- var charsetMatch = JSON.stringify(resHeader).match(/charset="?([a-zA-Z0-9\-]+)"?/);
- if(charsetMatch && charsetMatch.length > 1){
- var currentCharset = charsetMatch[1].toLowerCase();
- if(currentCharset != "utf-8" && iconv.encodingExists(currentCharset)){
- bodyContent = iconv.decode(bodyContent, currentCharset);
+ self.getBody(id,function(err,bodyContent){
+ if(err){
+ cb(err);
+ }else if(!bodyContent){
+ cb(null,result);
+ }else{
+ var record = doc[0],
+ resHeader = record['resHeader'] || {};
+ try{
+ var headerStr = JSON.stringify(resHeader),
+ charsetMatch = headerStr.match(/charset="?([a-zA-Z0-9\-]+)"?/),
+ imageMatch = resHeader && resHeader["content-type"];
+
+ if(charsetMatch && charsetMatch.length){
+
+ var currentCharset = charsetMatch[1].toLowerCase();
+ if(currentCharset != "utf-8" && iconv.encodingExists(currentCharset)){
+ bodyContent = iconv.decode(bodyContent, currentCharset);
+ }
+ result.type = "text";
+ result.content = bodyContent.toString();
+ }else if(imageMatch){
+
+ result.type = "image";
+ result.mime = imageMatch;
+ result.content = bodyContent;
}
- }
- }catch(e){}
+ }catch(e){}
- cb(null,bodyContent.toString());
- }
+ cb(null,result);
+ }
+ });
});
};
diff --git a/lib/requestHandler.js b/lib/requestHandler.js
index 4c5340a..074ea82 100644
--- a/lib/requestHandler.js
+++ b/lib/requestHandler.js
@@ -24,6 +24,7 @@ function userRequestHandler(req,userRes){
in http server : http://www.example.com/a/b/c
in https server : /a/b/c
*/
+
var host = req.headers.host,
protocol = (!!req.connection.encrypted && !/^http:/.test(req.url)) ? "https" : "http",
fullUrl = protocol === "http" ? req.url : (protocol + '://' + host + req.url),
@@ -33,6 +34,9 @@ function userRequestHandler(req,userRes){
resourceInfoId = -1,
reqData;
+ // console.log(req.url);
+ // console.log(path);
+
//record
resourceInfo = {
host : host,
diff --git a/lib/util.js b/lib/util.js
index 28f1912..80a890b 100644
--- a/lib/util.js
+++ b/lib/util.js
@@ -1,5 +1,7 @@
var fs = require("fs"),
- path = require("path");
+ path = require("path"),
+ exec = require('child_process').exec;
+
// {"Content-Encoding":"gzip"} --> {"content-encoding":"gzip"}
module.exports.lower_keys = function(obj){
@@ -41,6 +43,27 @@ module.exports.getAnyProxyHome = function(){
return home;
}
+var CACHE_DIR_PREFIX = "cache_r";
+module.exports.generateCacheDir = function(){
+ var rand = Math.floor(Math.random() * 1000000),
+ cachePath = path.join(util.getAnyProxyHome(),"./" + CACHE_DIR_PREFIX + rand);
+
+ fs.mkdirSync(cachePath,0777);
+ return cachePath;
+}
+
+module.exports.clearCacheDir = function(cb){
+ var home = util.getAnyProxyHome(),
+ isWin = /^win/.test(process.platform);
+
+ var dirNameWildCard = CACHE_DIR_PREFIX + "*";
+ if(isWin){
+ exec("for /D %f in (" + dirNameWildCard + ") do rmdir %f /s /q",{cwd : home},cb);
+ }else{
+ exec("rm -rf " + dirNameWildCard + "",{cwd : home},cb);
+ }
+}
+
module.exports.simpleRender = function(str, object, regexp){
return String(str).replace(regexp || (/\{\{([^{}]+)\}\}/g), function(match, name){
if (match.charAt(0) == '\\') return match.slice(1);
diff --git a/lib/webInterface.js b/lib/webInterface.js
index b2b1fab..3e74597 100644
--- a/lib/webInterface.js
+++ b/lib/webInterface.js
@@ -48,6 +48,36 @@ function webInterface(config){
});
});
+ app.get("/fetchBody",function(req,res){
+ var query = req.query;
+ if(query && query.id){
+ GLOBAL.recorder.getDecodedBody(query.id, function(err, result){
+ if(err || !result || !result.content){
+ res.json({});
+ }else if(result.type && result.type == "image" && result.mime){
+ if(query.raw){
+ //TODO : cache query result
+ res.type(result.mime).end(result.content);
+ }else{
+ res.json({
+ id : query.id,
+ type : result.type,
+ ref : "/fetchBody?id=" + query.id + "&raw=true"
+ });
+ }
+ }else{
+ res.json({
+ id : query.id,
+ type : result.type,
+ content : result.content
+ });
+ }
+ });
+ }else{
+ res.end({});
+ }
+ });
+
app.get("/fetchCrtFile",function(req,res){
if(crtFilePath){
res.setHeader("Content-Type","application/x-x509-ca-cert");
diff --git a/lib/wsServer.js b/lib/wsServer.js
index 3a34578..d56fb4a 100644
--- a/lib/wsServer.js
+++ b/lib/wsServer.js
@@ -23,8 +23,8 @@ function resToMsg(msg,cb){
}
if(jsonData.type == "reqBody" && jsonData.id){
- result.type ="body";
- GLOBAL.recorder.getBodyUTF8(jsonData.id, function(err, data){
+ result.type = "body";
+ GLOBAL.recorder.getBody(jsonData.id, function(err, data){
if(err){
result.content = {
id : null,
@@ -34,7 +34,7 @@ function resToMsg(msg,cb){
}else{
result.content = {
id : jsonData.id,
- body : data
+ body : data.toString()
};
}
cb && cb(result);
diff --git a/package.json b/package.json
index 3596d97..b6ee7f3 100644
--- a/package.json
+++ b/package.json
@@ -25,7 +25,7 @@
"ws": "^0.4.32"
},
"devDependencies": {
- "proxy-eval": ">=1.1.1"
+ "proxy-eval": ">=1.1.2"
},
"scripts": {
"test": "sh test.sh"
diff --git a/proxy.js b/proxy.js
index 861d735..bfcdace 100644
--- a/proxy.js
+++ b/proxy.js
@@ -69,11 +69,7 @@ function proxyServer(option){
logUtil.setPrintStatus(false);
}
- if(option.dbFile){
- GLOBAL.recorder = new Recorder({filename: option.dbFile});
- }else{
- GLOBAL.recorder = new Recorder();
- }
+
if(!!option.interceptHttps){
default_rule.setInterceptFlag(true);
@@ -95,6 +91,18 @@ function proxyServer(option){
async.series(
[
+ //clear cache dir, prepare recorder
+ function(callback){
+ util.clearCacheDir(function(){
+ if(option.dbFile){
+ GLOBAL.recorder = new Recorder({filename: option.dbFile});
+ }else{
+ GLOBAL.recorder = new Recorder();
+ }
+ callback();
+ });
+ },
+
//creat proxy server
function(callback){
if(proxyType == T_TYPE_HTTPS){
diff --git a/test/large_post.js b/test/large_post.js
new file mode 100644
index 0000000..b92e968
--- /dev/null
+++ b/test/large_post.js
@@ -0,0 +1,37 @@
+var proxy = require("../proxy.js"),
+ proxyTester = require("proxy-eval"),
+ WebSocket = require("ws"),
+ Buffer = require("buffer").Buffer,
+ express = require("express");
+
+var app = express()
+
+app.post('/', function (req, res) {
+ var bigBody = new Buffer(1024 * 1024 * 10);
+ res.send( bigBody ); //10 mb
+});
+app.listen(3000);
+
+function test(){
+ //test the basic availibility of proxy server
+ setTimeout(function(){
+ var testParam = {
+ proxy : 'http://127.0.0.1:8001/',
+ reqTimeout : 4500,
+ httpGetUrl : "",
+ httpPostUrl : "http://127.0.0.1:3000/",
+ httpPostBody : "123",
+ httpsGetUrl : "",
+ httpsPostUrl : "",
+ httpsPostBody : ""
+ };
+ proxyTester.test(testParam ,function(results){
+ process.exit();
+ });
+ },1000);
+};
+
+setTimeout(function(){
+ test();
+},3000);
+
diff --git a/test/test.js b/test/test.js
index 5205cfe..7edb5b7 100644
--- a/test/test.js
+++ b/test/test.js
@@ -44,7 +44,13 @@ exports.avalibility = function(test){
//test the basic availibility of proxy server
setTimeout(function(){
- proxyTester.test({proxy : 'http://127.0.0.1:8995',reqTimeout:4500} ,function(results){
+ var testParam = {
+ proxy : 'http://127.0.0.1:8995',
+ reqTimeout : 4500,
+ httpsPostUrl : "http://www.sample.com/"
+ httpsPostBody : "123"
+ };
+ proxyTester.test(testParam ,function(results){
var successCount = 0;
results.map(function(item){
item.success && ++successCount;
diff --git a/web/build/detailPanel.js b/web/build/detailPanel.js
index 628678e..1f4c4f5 100644
--- a/web/build/detailPanel.js
+++ b/web/build/detailPanel.js
@@ -12,11 +12,23 @@ function init(React){
id = self.props.data.id;
if(!id) return;
- ws.reqBody(id,function(content){
- if(content.id == self.props.data.id){
- self.setState({
- body : content
- });
+ jQuery.get("/fetchBody?id=" + id ,function(resObj){
+ if(resObj && resObj.id){
+ if(resObj.type && resObj.type == "image" && resObj.ref){
+ self.setState({
+ body : {
+ img : resObj.ref,
+ id : resObj.id
+ }
+ });
+ }else if(resObj.content){
+ self.setState({
+ body : {
+ body : resObj.content,
+ id : resObj.id
+ }
+ });
+ }
}
});
},
@@ -55,9 +67,13 @@ function init(React){
);
if(this.props.data.statusCode){
-
if(this.state.body.id == this.props.data.id){
- bodyContent = (React.createElement("pre", {className: "resBodyContent"}, this.state.body.body));
+ if(this.state.body.img){
+ var imgEl = { __html : ''};
+ bodyContent = (React.createElement("div", {dangerouslySetInnerHTML: imgEl}));
+ }else{
+ bodyContent = (React.createElement("pre", {className: "resBodyContent"}, this.state.body.body));
+ }
}else{
bodyContent = null;
this.loadBody();
diff --git a/web/css/page.css b/web/css/page.css
index f9488cd..370d8b5 100644
--- a/web/css/page.css
+++ b/web/css/page.css
@@ -186,6 +186,11 @@ body, html {
word-wrap:break-word;
}
+.resBody .resBodyContent img{
+ max-width: 500px;
+ max-height: 500px;
+}
+
.subTitle{
padding-left: 6px;
border-left: 3px solid #1FA2D6;
diff --git a/web/page.js b/web/page.js
index ae0dd04..507b46d 100644
--- a/web/page.js
+++ b/web/page.js
@@ -20342,11 +20342,23 @@
id = self.props.data.id;
if(!id) return;
- ws.reqBody(id,function(content){
- if(content.id == self.props.data.id){
- self.setState({
- body : content
- });
+ jQuery.get("/fetchBody?id=" + id ,function(resObj){
+ if(resObj && resObj.id){
+ if(resObj.type && resObj.type == "image" && resObj.ref){
+ self.setState({
+ body : {
+ img : resObj.ref,
+ id : resObj.id
+ }
+ });
+ }else if(resObj.content){
+ self.setState({
+ body : {
+ body : resObj.content,
+ id : resObj.id
+ }
+ });
+ }
}
});
},
@@ -20385,9 +20397,13 @@
);
if(this.props.data.statusCode){
-
if(this.state.body.id == this.props.data.id){
- bodyContent = (React.createElement("pre", {className: "resBodyContent"}, this.state.body.body));
+ if(this.state.body.img){
+ var imgEl = { __html : '
'};
+ bodyContent = (React.createElement("div", {dangerouslySetInnerHTML: imgEl}));
+ }else{
+ bodyContent = (React.createElement("pre", {className: "resBodyContent"}, this.state.body.body));
+ }
}else{
bodyContent = null;
this.loadBody();
diff --git a/web/src/detailPanel.js b/web/src/detailPanel.js
index fb539d3..41f8ef2 100644
--- a/web/src/detailPanel.js
+++ b/web/src/detailPanel.js
@@ -12,11 +12,23 @@ function init(React){
id = self.props.data.id;
if(!id) return;
- ws.reqBody(id,function(content){
- if(content.id == self.props.data.id){
- self.setState({
- body : content
- });
+ jQuery.get("/fetchBody?id=" + id ,function(resObj){
+ if(resObj && resObj.id){
+ if(resObj.type && resObj.type == "image" && resObj.ref){
+ self.setState({
+ body : {
+ img : resObj.ref,
+ id : resObj.id
+ }
+ });
+ }else if(resObj.content){
+ self.setState({
+ body : {
+ body : resObj.content,
+ id : resObj.id
+ }
+ });
+ }
}
});
},
@@ -55,9 +67,13 @@ function init(React){
);
if(this.props.data.statusCode){
-
if(this.state.body.id == this.props.data.id){
- bodyContent = (
{this.state.body.body}); + if(this.state.body.img){ + var imgEl = { __html : '
{this.state.body.body}); + } }else{ bodyContent = null; this.loadBody();