/
proxyv2.js
136 lines (106 loc) · 3.41 KB
/
proxyv2.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
/**
* @author: guileen@gmail.com
*/
//TODO: More test
//TODO: User controll
//TODO: compress support
//TODO: redis cache for static file like webDav
//TODO: compress output only
var https = require('https'),
http = require('http'),
querystring = require('querystring'),
util = require('util'),
utils = require('./utils'),
encoder = require('./encodev2');
/**
* options : server, port, useHttps
* TODO
* baseHTTP: string
* baseHTTPS: string
* timeout: int
* allowCookie: boolean
* allowImage: boolean
* allowBin: boolean
* maxLength: int
* whiteList: Array // won't encrypt link
* blackList: Array // won't proxy
*
*/
var proxy = module.exports = function(options) {
options.port = options.port || 443;
options.useHttps = options.useHttps || this.port == 443;
if (options.port === 443 || options.port === 80) {
options.serverAndPort = options.server;
}else {
options.serverAndPort = options.server + ':' + options.port;
}
if(options.compress === undefined) options.compress = true;
var log4js = options.logger || require('log4js'),
logger = log4js.getLogger('proxy<' + options.serverAndPort + '>');
return function(req, res, next) {
var logger = log4js.getLogger(req.method + ' ' + req.headers.host + req.url);
logger.debug('handle request of ' + util.inspect(req.headers));
req.encoder = encoder(options);
req.options = options;
req.plugins = options.plugins;
makeRequest(req, res, next, logger);
};
function makeRequest(req, res, next, logger) {
var url = req.url = utils.fixurlv2(req.url);
// -------- decode req and do request -----------
var req_option = req.encoder.decodeRequest(req);
if(!req_option) return next();
var scheme;
if(req_option.isSecure) {
scheme = https;
} else {
scheme = http;
}
var clientRequest = scheme.request(req_option, function(clientResponse) {
logger.debug('clientResponse callback');
req_option.encoder = req.encoder;
req.plugins.handle(req_option, clientResponse, req, res, next, logger);
});
// setTimeout, config it, long pull
if(options.timeout) {
var timeoutTimer = setTimeout(function() {
clientRequest.abort()
var e = new Error("ETIMEDOUT")
e.code = "ETIMEDOUT"
clientRequest.emit("error", e)
}, options.timeout)
clientRequest.on('end', function() {
clearTimeout(timeoutTimer);
});
}
clientRequest.on('error', function(err) {
next(err);
});
decodeRequestBodyTo(req, clientRequest);
}
function decodeRequestBodyTo(req, clientRequest) {
// TODO 是否要做成plugin形式, 可对不同网站自定义 post
var postIsText = req.headers['content-type'] === 'application/x-www-form-urlencoded';
var body;
if (postIsText) {
logger.debug('post is text, content-type: ' + req.headers['content-type']);
body = '';
}
req.on('data', function(data) {
if (postIsText && typeof data === 'string') {
body += data;
}else {
clientRequest.write(data);
}
});
req.on('end', function() {
if (postIsText && body.length > 0) {
logger.debug('post data is <' + body + '>');
body = decodeQuery(body);
logger.debug('decoded body is <' + body + '>');
clientRequest.write(body);
}
clientRequest.end();
});
}
};