1 | var joinbuffers = require("joinbuffers");
|
2 | var isUtf8 = require('is-utf8');
|
3 | var iconv = require('iconv-lite');
|
4 | var config = require('./config.js');
|
5 |
|
6 | var prjInfo = config.get('project');
|
7 |
|
8 | var http = require('http');
|
9 | var https = require('https');
|
10 | var net = require('net');
|
11 | var debug = require('debug')('Clam:requestHandle');
|
12 | var _ = require('underscore');
|
13 |
|
14 | var path = require('path');
|
15 | var uri = require('url');
|
16 | var fs = require('fs');
|
17 |
|
18 | exports = module.exports = function () {
|
19 | return function (req, res, next) {
|
20 | var remotes = exports.remotes;
|
21 |
|
22 | if (!remotes || !remotes.length) {
|
23 | next();
|
24 | return;
|
25 | }
|
26 | var url = uri.parse(req.url);
|
27 | _.some(remotes, function (options) {
|
28 |
|
29 | if (options.pathname === url.pathname || url.pathname.match(options.pathname)) {
|
30 | exports.proxy(req, res, next, options);
|
31 | return true;
|
32 | }
|
33 | }) || next();
|
34 | };
|
35 | };
|
36 | exports.remotes = [];
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 |
|
43 | exports._reFullURI = /^(?:(http(?:s*)|socket):\/\/)*([^\:\/]+)*(?:\:(\d+))*(\/[^?]*)(?:\?(.*))*$/;
|
44 |
|
45 | if (prjInfo && prjInfo.dataApi) {
|
46 | _.each(prjInfo.dataApi, function (options) {
|
47 |
|
48 | var local = path.join(config.root(), '/.clam/dataApi/', options.local || '');
|
49 | var remote = (options.remote || '').match(exports._reFullURI);
|
50 | var type = options.type || 'auto';
|
51 | var pathname = options.url;
|
52 | if (!pathname || !remote) {
|
53 | debug('Failed to build remote %s from %s !', remote, local);
|
54 | }
|
55 | exports.remotes.push({
|
56 | pathname: pathname,
|
57 | type: type,
|
58 | local: local,
|
59 | remote: {
|
60 |
|
61 | agreement: remote[1] || 'http',
|
62 | domain: remote[2] || 'localhost',
|
63 | port: remote[3] || 80,
|
64 | pathname: remote[4] || '',
|
65 | querystring: remote[5] || ''
|
66 | }
|
67 | });
|
68 | });
|
69 | }
|
70 |
|
71 | exports.handle = exports;
|
72 | exports.proxy = function (req, res, next, options) {
|
73 | if (options.type === 'auto' || options.type === 'local') {
|
74 | exports._local(req, res, next, options);
|
75 | }
|
76 | if (options.type === 'remote') {
|
77 | exports._remote(req, res, next, options);
|
78 | }
|
79 | };
|
80 | exports._local = function (req, res, next, options) {
|
81 | fs.stat(options.local, function (err, stats) {
|
82 | if (!err && stats.isFile()) {
|
83 | var action = require(options.local);
|
84 | if ('function' === typeof action.handle) {
|
85 | action.handle(req, res, next, options);
|
86 | return;
|
87 | }
|
88 | try {
|
89 |
|
90 |
|
91 | res.setHeader('Content-Type', 'application/json;text/json; charset=' + exports.charset);
|
92 | res.write(JSON.stringify(action));
|
93 | res.end();
|
94 | } catch ( e ) {
|
95 | debug('Stringify failed! Data: %o \n\r File: %s', action, options.local);
|
96 | res.end(JSON.stringify({
|
97 | "errno": 500,
|
98 | "errmsg": "Stringify failed ! Please check your action file : "+options.local+"! "
|
99 | }));
|
100 | }
|
101 | return;
|
102 | }
|
103 | if (options.type === 'auto') {
|
104 | return exports._remote(req, res, next, options);
|
105 | }
|
106 | return next();
|
107 | });
|
108 | };
|
109 | exports._remote = function (req, res, next, options) {
|
110 | if (options.remote.agreement === 'http') {
|
111 | return exports.httpProxy(req, res, next, options);
|
112 | }
|
113 | if (options.remote.agreement === 'https') {
|
114 | return exports.httpsProxy(req, res, next, options);
|
115 | }
|
116 | if (options.remote.agreement === 'socket') {
|
117 | return exports.socketProxy(req, res, next, options);
|
118 | }
|
119 | debug('Remote failed; Unknown agreement <%s> ', options.agreement);
|
120 | next();
|
121 | };
|
122 | exports.charset = prjInfo ? prjInfo.charset[0] : "utf-8";
|
123 | exports.httpProxy = function (req, res, next, options) {
|
124 | var remote = options.remote;
|
125 | var url = uri.parse(req.url);
|
126 | var pathname = remote.pathname || url.pathname;
|
127 | var querystring = remote.querystring;
|
128 | querystring += (url.query ? '&' : '') + (url.query || '');
|
129 |
|
130 | var nsreq = http.request({
|
131 | host: remote.domain,
|
132 | port: remote.port,
|
133 | path: pathname + '?' + querystring,
|
134 | method: req.method,
|
135 | headers: req.headers
|
136 | }, function (nsres) {
|
137 | res.statusCode = nsres.statusCode;
|
138 |
|
139 | var headers = nsres.headers;
|
140 | var headerItem;
|
141 | var header;
|
142 | for (header in headers) {
|
143 | headerItem = headers[header];
|
144 | res.setHeader(header, headerItem);
|
145 | }
|
146 | var buffs = [];
|
147 |
|
148 | nsres.on('data', function (chunk) {
|
149 | buffs.push(chunk);
|
150 | });
|
151 |
|
152 | nsres.on('end', function () {
|
153 | buff = joinbuffers(buffs);
|
154 |
|
155 | if(buff[0] === 239 && buff[1] === 187 && buff[2] === 191) {
|
156 | buff = buff.slice(3, buff.length);
|
157 | }
|
158 | var buffChatset = isUtf8(buff) ? 'utf8' : 'gbk';
|
159 | if (buffChatset !== exports.charset) {
|
160 | buff = iconv.encode(iconv.decode(buff, buffChatset), exports.charset);
|
161 | }
|
162 | res.write(buff);
|
163 | res.end();
|
164 | });
|
165 | });
|
166 | req.on('data', function (chunk) {
|
167 | nsreq.write(chunk);
|
168 | });
|
169 | req.on('end', function () {
|
170 | nsreq.end();
|
171 | });
|
172 | nsreq.on('error', function (e) {
|
173 | debug(e);
|
174 | });
|
175 | };
|
176 | exports.httpsProxy = function (req, res, next, info) {
|
177 |
|
178 | };
|
179 | exports.socketProxy = function (req, res, next, info) {
|
180 |
|
181 | }; |
\ | No newline at end of file |