-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathserver.js
154 lines (127 loc) · 4.69 KB
/
server.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
var net = require('net')
,port = 8894
,tool = require('./tool')//自定义的工具
;
net.createServer({ allowHalfOpen: true},function(client){
client.setKeepAlive(true, 15 * 1000);
client.on("end", function () {
client.end();
});
client.on("error", function (err) {
client.destroy();
});
client.on("timeout", function () {
client.destroy();
});
var buffer = new Buffer(0);
client.on('data',function(data){
buffer = tool.buffer_add(buffer, data);
if (tool.buffer_find_body(buffer) < 0) {
return;
}
var req = tool.parse_request(buffer);
client.removeAllListeners('data');
client.removeAllListeners('end');
client.removeAllListeners('error');
client.removeAllListeners('timeout');
relay_connection(req);
});
//从http请求头部取得请求信息后,继续监听浏览器发送数据,同时连接目标服务器,并把目标服务器的数据传给浏览器
function relay_connection(req) {
console.log(req.method + ' ' + req.host + ':' + req.port);
//如果请求不是CONNECT方法(GET, POST),那么替换掉头部的一些东西
if (req.method != 'CONNECT') {
//先从buffer中取出头部
var _body_pos = tool.buffer_find_body(buffer);
if (_body_pos < 0) _body_pos = buffer.length;
var header = buffer.slice(0, _body_pos).toString('utf8');
//替换connection头 设置 connection:close 保证每个文件执行一次请求
header = header.replace(/(proxy-)?connection\:.+\r\n/ig, '')
.replace(/Keep-Alive\:.+\r\n/i, '')
.replace("\r\n", '\r\nConnection: close\r\n');
//替换网址格式(去掉域名部分)
if (req.httpVersion == '1.1') {
var url = req.path.replace(/http\:\/\/[^\/]+/, '');
if (url.path != url) header = header.replace(req.path, url);
}
buffer = tool.buffer_add(new Buffer(header, 'utf8'), buffer.slice(_body_pos));
}
//启动双向请求,连接目标服务器
startService(
client,
{ allowHalfOpen: true, port: req.port, host: req.host},
{ 'encrypt': tool.decrypt, 'decrypt': tool.encrypt },//跟客户端的方法刚好反过来
{ 'connectfunc': proxyConnectAction, 'req': req, 'buffer': buffer }
);
}
}).listen(port,function(){
console.log('listen '+port);
});
function proxyConnectAction(client, server, req, buffer) {
if (req.method == 'CONNECT') {
/*
告诉客户端 连接确认(Connection established)
HTTP Connection的 close设置允许客户端或服务器中任何一方关闭底层的连接,双方都会要求在处理请求后关闭它们的TCP连接
这样可以减少代理服务器的消耗
其实没有保持原样(使用Keep-Alive) 是还没有找到具体的实现方法和实现起来比较麻烦,所以设置了close 保证每个文件执行一次请求
*/
client.write(tool.encrypt(new Buffer("HTTP/1.1 200 Connection established\r\nConnection: close\r\n\r\n")));
} else {
server.write(buffer);
}
}
function startService(client, options, cryptfuncs, connopts){
//建立到目标服务器的连接
var server = net.createConnection(options)
,client_closeflag = 0
,server_closeflag = 0
;
server.setKeepAlive(true, 15 * 1000);
//暂停
client.pause();
server.pause();
//连接服务端
server.on("connect", function (socket) {
client.resume();
server.resume();
connopts.connectfunc(client, server, connopts.req, connopts.buffer);
});
//接收数据
client.on("data", function (data) {
if (!server_closeflag) {
server.write(cryptfuncs.encrypt(data));
}
});
server.on("data", function (data) {
if (!client_closeflag) {
client.write(cryptfuncs.decrypt(data));
}
});
//结束事件
client.on("end", function () {
client_closeflag = 1;
server.end();
});
server.on("end", function () {
server_closeflag = 1;
client.end();
});
//错误事件
client.on("error", function () {
client_closeflag = 1;
server.destroy();
});
server.on("error", function () {
server_closeflag = 1;
client.destroy();
});
//超时事件
client.on("timeout", function () {
server.destroy();
client.destroy();
});
server.on("timeout", function () {
server.destroy();
client.destroy();
});
}