Commit | Line | Data |
---|---|---|
d99e7823 D |
1 | var engine = require('engine.io'), |
2 | WebsocketRpc = require('./websocketrpc.js'); | |
3 | events = require('events'), | |
4 | http = require('http'), | |
5 | https = require('https'), | |
6 | util = require('util'), | |
7 | fs = require('fs'), | |
8 | dns = require('dns'), | |
9 | url = require('url'), | |
10 | _ = require('lodash'), | |
11 | spdy = require('spdy'), | |
12 | ipaddr = require('ipaddr.js'), | |
13 | Client = require('./client.js').Client, | |
14 | HttpHandler = require('./httphandler.js').HttpHandler, | |
15 | rehash = require('./rehash.js'); | |
1286229a D |
16 | |
17 | ||
18 | ||
19 | rehash.on('rehashed', function (files) { | |
20 | Client = require('./client.js').Client; | |
2f1e8a71 | 21 | HttpHandler = require('./httphandler.js').HttpHandler; |
1286229a D |
22 | }); |
23 | ||
186531ed D |
24 | |
25 | // Instance of HttpHandler | |
26 | var http_handler; | |
27 | ||
a8bf3ea4 | 28 | |
0fe7c000 | 29 | var WebListener = module.exports = function (web_config, transports) { |
a0bf87be | 30 | var hs, opts, |
a8bf3ea4 JA |
31 | that = this; |
32 | ||
71c81a3b | 33 | |
a8bf3ea4 | 34 | events.EventEmitter.call(this); |
b156e01a | 35 | |
8b0eb787 | 36 | http_handler = new HttpHandler(web_config); |
b156e01a | 37 | |
8b0eb787 | 38 | if (web_config.ssl) { |
a8bf3ea4 | 39 | opts = { |
562ecbe0 PV |
40 | key: fs.readFileSync(web_config.ssl_key), |
41 | cert: fs.readFileSync(web_config.ssl_cert) | |
a8bf3ea4 | 42 | }; |
186531ed | 43 | |
a8bf3ea4 | 44 | // Do we have an intermediate certificate? |
480552a2 D |
45 | if (typeof web_config.ssl_ca !== 'undefined') { |
46 | // An array of them? | |
47 | if (typeof web_config.ssl_ca.map !== 'undefined') { | |
48 | opts.ca = web_config.ssl_ca.map(function (f) { return fs.readFileSync(f); }); | |
186531ed | 49 | |
480552a2 D |
50 | } else { |
51 | opts.ca = fs.readFileSync(web_config.ssl_ca); | |
52 | } | |
53 | } | |
186531ed | 54 | |
8f2efe03 JA |
55 | hs = spdy.createServer(opts, handleHttpRequest); |
56 | ||
e380bc9e D |
57 | hs.listen(web_config.port, web_config.address, function () { |
58 | that.emit('listening'); | |
59 | }); | |
a8bf3ea4 | 60 | } else { |
186531ed | 61 | |
a8bf3ea4 | 62 | // Start some plain-text server up |
186531ed D |
63 | hs = http.createServer(handleHttpRequest); |
64 | ||
e380bc9e D |
65 | hs.listen(web_config.port, web_config.address, function () { |
66 | that.emit('listening'); | |
67 | }); | |
a8bf3ea4 | 68 | } |
d558508c JA |
69 | |
70 | hs.on('error', function (err) { | |
71 | that.emit('error', err); | |
b156e01a JA |
72 | }); |
73 | ||
d99e7823 D |
74 | this.ws = engine.attach(hs, { |
75 | transports: ['websocket', 'polling', 'flashsocket'], | |
76 | path: (global.config.http_base_path || '') + '/transport' | |
77 | }); | |
d99e7823 D |
78 | |
79 | this.ws.on('connection', function(socket) { | |
d99e7823 D |
80 | initialiseSocket(socket, function(err, authorised) { |
81 | var client; | |
82 | ||
83 | if (!authorised) { | |
84 | socket.close(); | |
85 | return; | |
86 | } | |
87 | ||
88 | client = new Client(socket); | |
89 | client.on('dispose', function () { | |
90 | that.emit('client_dispose', this); | |
91 | }); | |
92 | ||
93 | that.emit('connection', client); | |
94 | }); | |
95 | }); | |
a8bf3ea4 JA |
96 | }; |
97 | util.inherits(WebListener, events.EventEmitter); | |
98 | ||
186531ed D |
99 | |
100 | ||
101 | function handleHttpRequest(request, response) { | |
0fe7c000 | 102 | http_handler.serve(request, response); |
186531ed D |
103 | } |
104 | ||
e7af0cbb JA |
105 | function rangeCheck(addr, range) { |
106 | var i, ranges, parts; | |
107 | ranges = (!_.isArray(range)) ? [range] : range; | |
108 | for (i = 0; i < ranges.length; i++) { | |
109 | parts = ranges[i].split('/'); | |
110 | if (ipaddr.process(addr).match(ipaddr.process(parts[0]), parts[1])) { | |
111 | return true; | |
112 | } | |
113 | } | |
114 | return false; | |
115 | } | |
116 | ||
a8bf3ea4 | 117 | |
15fefff7 D |
118 | /** |
119 | * Get the reverse DNS entry for this connection. | |
120 | * Used later on for webirc, etc functionality | |
121 | */ | |
d99e7823 D |
122 | function initialiseSocket(socket, callback) { |
123 | var request = socket.request, | |
124 | address = request.connection.remoteAddress; | |
125 | ||
126 | // Key/val data stored to the socket to be read later on | |
127 | // May also be synced to a redis DB to lookup clients | |
a0bf87be | 128 | socket.meta = {}; |
c6e3ed44 D |
129 | |
130 | // If a forwarded-for header is found, switch the source address | |
d99e7823 | 131 | if (request.headers[global.config.http_proxy_ip_header || 'x-forwarded-for']) { |
c6e3ed44 | 132 | // Check we're connecting from a whitelisted proxy |
e7af0cbb | 133 | if (!global.config.http_proxies || !rangeCheck(address, global.config.http_proxies)) { |
c6e3ed44 D |
134 | console.log('Unlisted proxy:', address); |
135 | callback(null, false); | |
136 | return; | |
137 | } | |
138 | ||
139 | // We're sent from a whitelisted proxy, replace the hosts | |
d99e7823 | 140 | address = request.headers[global.config.http_proxy_ip_header || 'x-forwarded-for']; |
c6e3ed44 D |
141 | } |
142 | ||
a0bf87be | 143 | socket.meta.real_address = address; |
b156e01a | 144 | |
13d7faa3 | 145 | // If enabled, don't go over the connection limit |
b737610b JA |
146 | if (global.config.max_client_conns && global.config.max_client_conns > 0) { |
147 | if (global.clients.numOnAddress(address) + 1 > global.config.max_client_conns) { | |
13d7faa3 D |
148 | return callback(null, false); |
149 | } | |
c36ed4eb | 150 | } |
be481108 D |
151 | |
152 | ||
153 | try { | |
154 | dns.reverse(address, function (err, domains) { | |
155 | if (err || domains.length === 0) { | |
a0bf87be | 156 | socket.meta.revdns = address; |
be481108 | 157 | } else { |
a0bf87be | 158 | socket.meta.revdns = _.first(domains) || address; |
be481108 | 159 | } |
b156e01a | 160 | |
be481108 D |
161 | // All is well, authorise the connection |
162 | callback(null, true); | |
163 | }); | |
164 | } catch (err) { | |
a0bf87be | 165 | socket.meta.revdns = address; |
a8bf3ea4 | 166 | callback(null, true); |
be481108 | 167 | } |
15fefff7 | 168 | } |