Sitelet https://github.com/alibaba/anyproxy/commit/b51236d67873da9a6695272696d0cff4ca84a0c7
Skip to content

Commit b51236d

Browse files
author
加里
committed
add ui config server
1 parent bc5659b commit b51236d

14 files changed

Lines changed: 604 additions & 40 deletions

File tree

‎README.md‎

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ A fully configurable proxy in NodeJS, which can handle HTTPS requests perfectly.
44

55
(Chinese in this doc is nothing but translation of some key points. Be relax if you dont understand.)
66

7+
因为一些集团开源/专利限制,我们暂时把anyproxy迁回了gitlab。如果喜欢,欢迎到[https://github.com/alipay-ct-wd/anyproxy](https://github.com/alipay-ct-wd/anyproxy)为我们点赞。
8+
79
![](https://i.alipayobjects.com/i/ecmng/png/201409/3NKRCRk2Uf.png_250x.png)
810

911
Feature
@@ -12,6 +14,7 @@ Feature
1214
* fully configurable, you can modify a request at any stage by your own javascript code
1315
* when working as https proxy, it can generate and intercept https requests for any domain without complaint by browser (after you trust its root CA)
1416
* a web interface is availabe for you to view request details
17+
* (beta)a web UI interface for you to replace some remote response with local data
1518

1619
![screenshot](http://gtms03.alicdn.com/tps/i3/TB1ddyqGXXXXXbXXpXXihxC1pXX-1000-549.jpg_640x640q90.jpg)
1720

@@ -73,34 +76,47 @@ How to write your own rule file
7376
```javascript
7477

7578
module.exports = {
76-
/*
77-
these functions will overwrite the default ones, write your own when necessary.
78-
*/
7979
summary:function(){
80-
console.log("this is a blank rule for anyproxy");
80+
return "this is a blank rule for anyproxy";
8181
},
8282

83-
//whether to intercept this request by local logic
83+
84+
//=======================
85+
//when getting a request from user
86+
//收到用户请求之后
87+
//=======================
88+
89+
//是否在本地直接发送响应(不再向服务器发出请求)
90+
//whether to intercept this request by local logic
8491
//if the return value is true, anyproxy will call dealLocalResponse to get response data and will not send request to remote server anymore
8592
shouldUseLocalResponse : function(req,reqBody){
8693
return false;
8794
},
8895

96+
//如果shouldUseLocalResponse返回true,会调用这个函数来获取本地响应内容
8997
//you may deal the response locally instead of sending it to server
90-
//this function be called when shouldUseLocalResponse returns true
98+
//this function be called when shouldUseLocalResponse returns true
9199
//callback(statusCode,resHeader,responseData)
92100
//e.g. callback(200,{"content-type":"text/html"},"hello world")
93101
dealLocalResponse : function(req,reqBody,callback){
94102
callback(statusCode,resHeader,responseData)
95103
},
96104

105+
106+
//=======================
107+
//when ready to send a request to server
108+
//向服务端发出请求之前
109+
//=======================
110+
111+
//替换向服务器发出的请求协议(http和https的替换)
97112
//replace the request protocol when sending to the real server
98113
//protocol : "http" or "https"
99114
replaceRequestProtocol:function(req,protocol){
100115
var newProtocol = protocol;
101116
return newProtocol;
102117
},
103118

119+
//替换向服务器发出的请求参数(option)
104120
//req is user's request which will be sent to the proxy server, docs : http://nodejs.org/api/http.html#http_http_request_options_callback
105121
//you may return a customized option to replace the original option
106122
//you should not write content-length header in options, since anyproxy will handle it for you
@@ -109,37 +125,52 @@ module.exports = {
109125
return newOption;
110126
},
111127

128+
//替换请求的body
112129
//replace the request body
113130
replaceRequestData: function(req,data){
114131
return data;
115132
},
116133

134+
//=======================
135+
//when ready to send the response to user after receiving response from server
136+
//向用户返回服务端的响应之前
137+
//=======================
138+
139+
//替换服务器响应的http状态码
117140
//replace the statusCode before it's sent to the user
118141
replaceResponseStatusCode: function(req,res,statusCode){
119142
var newStatusCode = statusCode;
120143
return newStatusCode;
121144
},
122145

146+
//替换服务器响应的http头
123147
//replace the httpHeader before it's sent to the user
124148
//Here header == res.headers
125149
replaceResponseHeader: function(req,res,header){
126150
var newHeader = header;
127151
return newHeader;
128152
},
129153

154+
//替换服务器响应的数据
130155
//replace the response from the server before it's sent to the user
131156
//you may return either a Buffer or a string
132157
//serverResData is a Buffer, you may get its content by calling serverResData.toString()
133158
replaceServerResData: function(req,res,serverResData){
134159
return serverResData;
135160
},
136161

162+
//在请求返回给用户前的延迟时间
137163
//add a pause before sending response to user
138164
pauseBeforeSendingResponse : function(req,res){
139165
var timeInMS = 1; //delay all requests for 1ms
140166
return timeInMS;
141167
},
142168

169+
//=======================
170+
//https config
171+
//=======================
172+
173+
//是否截获https请求
143174
//should intercept https request, or it will be forwarded to real server
144175
shouldInterceptHttpsReq :function(req){
145176
return false;

‎lib/requestHandler.js‎

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ function userRequestHandler(req,userRes){
7979
}
8080
resourceInfo.resHeader = resHeader || {};
8181
resourceInfo.resBody = resBody;
82-
resourceInfo.length = resBody.length;
82+
resourceInfo.length = resBody ? resBody.length : 0;
8383
resourceInfo.statusCode = statusCode;
8484

8585
GLOBAL.recorder && GLOBAL.recorder.updateRecord(resourceInfoId,resourceInfo);
@@ -171,12 +171,12 @@ function userRequestHandler(req,userRes){
171171

172172
//send response
173173
},function(callback){
174-
if(404 == statusCode){
175-
var html404path = pathUtil.join(__dirname, '..', 'web', '404.html');
176-
userRes.end(fs.readFileSync(html404path));
177-
}else{
174+
// if(404 == statusCode){
175+
// var html404path = pathUtil.join(__dirname, '..', 'web', '404.html');
176+
// userRes.end(fs.readFileSync(html404path));
177+
// }else{
178178
userRes.end(serverResData);
179-
}
179+
// }
180180
callback();
181181

182182
//udpate record info
@@ -304,14 +304,26 @@ function setRules(newRule){
304304
if(!newRule){
305305
return;
306306
}else{
307+
308+
if(!newRule.summary){
309+
newRule.summary = function(){
310+
return "this rule file does not have a summary";
311+
};
312+
}
313+
307314
userRule = util.merge(defaultRule,newRule);
308-
'function' == typeof(userRule.summary) && userRule.summary();
315+
'function' == typeof(userRule.summary) && console.log(userRule.summary());
309316
}
310317
}
311318

319+
function getRuleSummary(){
320+
return userRule.summary();
321+
}
322+
312323
module.exports.userRequestHandler = userRequestHandler;
313324
module.exports.connectReqHandler = connectReqHandler;
314325
module.exports.setRules = setRules;
326+
module.exports.getRuleSummary = getRuleSummary;
315327

316328
/*
317329
note

‎lib/rule_default.js‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
module.exports = {
22
summary:function(){
3-
console.log("this is the default rule for anyproxy, which supports CORS request");
3+
return "the default rule for anyproxy, which supports CORS request";
44
},
55

66
shouldUseLocalResponse : function(req,reqBody){
7+
78
//intercept all options request
89
if(req.method == "OPTIONS"){
910
return true;

‎package.json‎

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "anyproxy",
3-
"version": "2.2.1",
3+
"version": "2.3.0",
44
"description": "a charles/fiddler like proxy written in NodeJs, which can handle HTTPS requests and CROS perfectly.",
55
"main": "proxy.js",
66
"bin": {
@@ -14,18 +14,15 @@
1414
"entities": "^1.1.1",
1515
"express": "^4.8.5",
1616
"iconv-lite": "^0.4.4",
17+
"juicer": "^0.6.6-stable",
1718
"nedb": "^0.11.0",
18-
"ws": "^0.4.32",
19-
"iconv-lite": "^0.4.4"
20-
},
21-
"devDependencies": {
22-
19+
"ws": "^0.4.32"
2320
},
21+
"devDependencies": {},
2422
"scripts": {
2523
"test": "nodeunit test.js"
2624
},
27-
"repository": {
28-
},
25+
"repository": {},
2926
"author": "ottomao@gmail.com",
3027
"license": "ISC"
3128
}

‎proxy.js‎

Lines changed: 112 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,13 @@ var http = require('http'),
1717
getPort = require("./lib/getPort"),
1818
requestHandler = require("./lib/requestHandler"),
1919
Recorder = require("./lib/Recorder"),
20+
inherits = require("util").inherits,
2021
util = require("./lib/util"),
2122
entities = require("entities"),
2223
express = require("express"),
2324
path = require("path"),
25+
juicer = require('juicer'),
26+
events = require("events"),
2427
WebSocketServer= require('ws').Server;
2528

2629
GLOBAL.recorder = new Recorder();
@@ -30,6 +33,7 @@ var T_TYPE_HTTP = 0,
3033
DEFAULT_PORT = 8001,
3134
DEFAULT_WEB_PORT = 8002,
3235
DEFAULT_WEBSOCKET_PORT = 8003,
36+
DEFAULT_CONFIG_PORT = 8080,
3337
DEFAULT_HOST = "localhost",
3438
DEFAULT_TYPE = T_TYPE_HTTP;
3539

@@ -57,7 +61,7 @@ function proxyServer(option){
5761
proxyType = /https/i.test(option.type || DEFAULT_TYPE) ? T_TYPE_HTTPS : T_TYPE_HTTP ,
5862
proxyPort = option.port || DEFAULT_PORT,
5963
proxyHost = option.hostname || DEFAULT_HOST,
60-
proxyRules = option.rule || default_rule;
64+
proxyRules = option.rule || default_rule;
6165

6266
requestHandler.setRules(proxyRules); //TODO : optimize calling for set rule
6367
self.httpProxyServer = null;
@@ -95,7 +99,15 @@ function proxyServer(option){
9599

96100
//start web interface
97101
function(callback){
98-
startWebServer();
102+
var webServer = new proxyWebServer();
103+
var wss = webServer.wss;
104+
105+
var configServer = new UIConfigServer(DEFAULT_CONFIG_PORT);
106+
configServer.on("rule_changed",function() {
107+
console.log(arguments);
108+
})
109+
// var wss = proxyWebServer();
110+
99111
callback(null);
100112
}
101113
],
@@ -119,7 +131,90 @@ function proxyServer(option){
119131
}
120132
}
121133

122-
function startWebServer(port){
134+
// doing
135+
function UIConfigServer(port){
136+
var self = this;
137+
138+
var app = express(),
139+
customerRule = {
140+
summary: function(){
141+
console.log("replace some response with local response");
142+
return "replace some response with local response";
143+
}
144+
},
145+
userKey;
146+
147+
148+
customerRule.shouldUseLocalResponse = function(req,reqBody){
149+
var url = req.url;
150+
if(userKey){
151+
var ifMatch = false;
152+
userKey.map(function(item){
153+
if(ifMatch) return;
154+
155+
var matchCount = 0;
156+
if( !item.urlKey && !item.reqBodyKey){
157+
ifMatch = false;
158+
return;
159+
}else{
160+
if(!item.urlKey || (item.urlKey && url.indexOf(item.urlKey) >= 0 ) ){
161+
++matchCount;
162+
}
163+
164+
if(!item.reqBodyKey || (item.reqBodyKey && reqBody.toString().indexOf(item.reqBodyKey) >= 0) ){
165+
++matchCount;
166+
}
167+
168+
ifMatch = (matchCount==2);
169+
if(ifMatch){
170+
req.willResponse = item.localResponse;
171+
}
172+
}
173+
});
174+
175+
return ifMatch;
176+
}else{
177+
return false;
178+
}
179+
};
180+
181+
customerRule.dealLocalResponse = function(req,reqBody,callback){
182+
callback(200,{"content-type":"text/html"},req.willResponse)
183+
184+
return req.willResponse;
185+
};
186+
187+
app.post("/update",function(req,res){
188+
var data = "";
189+
req.on("data",function(chunk){
190+
data += chunk;
191+
});
192+
193+
req.on("end",function(){
194+
userKey = JSON.parse(data);
195+
196+
res.statusCode = 200;
197+
res.setHeader("Content-Type", "application/json;charset=UTF-8");
198+
res.end(JSON.stringify({success : true}));
199+
200+
requestHandler.setRules(customerRule);
201+
self.emit("rule_changed");
202+
});
203+
});
204+
205+
app.use(express.static(__dirname + "/web_uiconfig"));
206+
app.listen(port);
207+
208+
self.app = app;
209+
}
210+
211+
inherits(UIConfigServer, events.EventEmitter);
212+
213+
214+
215+
function proxyWebServer(port){
216+
var self = this;
217+
123218
port = port || DEFAULT_WEB_PORT;
124219

125220
//web interface
@@ -150,13 +245,22 @@ function startWebServer(port){
150245
res.end(entities.encodeHTML(body));
151246
});
152247

248+
app.use(function(req,res,next){
249+
var indexHTML = fs.readFileSync("./web/index.html",{encoding:"utf8"});
250+
251+
if(req.url == "/"){
252+
res.setHeader("Content-Type", "text/html");
253+
res.end(indexHTML.replace("{{rule}}",requestHandler.getRuleSummary()) );
254+
}else{
255+
next();
256+
}
257+
});
258+
153259
app.use(express.static(__dirname + '/web'));
154260

155261
app.listen(port);
156262

157263
var tipText = "web interface started at port " + port;
158-
console.log(color.green(tipText));
159-
160264

161265
//web socket interface
162266
var wss = new WebSocketServer({port: DEFAULT_WEBSOCKET_PORT});
@@ -169,6 +273,9 @@ function startWebServer(port){
169273
GLOBAL.recorder.on("update",function(data){
170274
wss.broadcast( JSON.stringify(data) );
171275
});
276+
277+
self.app = app;
278+
self.wss = wss;
172279
}
173280

174281

0 commit comments

Comments
 (0)