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'),
10 _
= require('lodash'),
11 spdy
= require('spdy'),
12 ipaddr
= require('ipaddr.js'),
13 winston
= require('winston'),
14 Client
= require('./client.js').Client
,
15 HttpHandler
= require('./httphandler.js').HttpHandler
,
16 rehash
= require('./rehash.js'),
17 Stats
= require('./stats.js');
21 rehash
.on('rehashed', function (files
) {
22 Client
= require('./client.js').Client
;
23 HttpHandler
= require('./httphandler.js').HttpHandler
;
27 // Instance of HttpHandler
31 var WebListener
= module
.exports = function (web_config
) {
36 events
.EventEmitter
.call(this);
38 http_handler
= new HttpHandler(web_config
);
42 key
: fs
.readFileSync(web_config
.ssl_key
),
43 cert
: fs
.readFileSync(web_config
.ssl_cert
)
46 // Do we have an intermediate certificate?
47 if (typeof web_config
.ssl_ca
!== 'undefined') {
49 if (typeof web_config
.ssl_ca
.map
!== 'undefined') {
50 opts
.ca
= web_config
.ssl_ca
.map(function (f
) { return fs
.readFileSync(f
); });
53 opts
.ca
= fs
.readFileSync(web_config
.ssl_ca
);
57 hs
= spdy
.createServer(opts
);
59 hs
.listen(web_config
.port
, web_config
.address
, function () {
60 that
.emit('listening');
64 // Start some plain-text server up
65 hs
= http
.createServer();
67 hs
.listen(web_config
.port
, web_config
.address
, function () {
68 that
.emit('listening');
72 hs
.on('error', function (err
) {
73 that
.emit('error', err
);
76 this.ws
= new engine
.Server();
78 hs
.on('upgrade', function(req
, socket
, head
){
79 // engine.io can sometimes "loose" the clients remote address. Keep note of it
81 remote_address
: req
.connection
.remoteAddress
84 that
.ws
.handleUpgrade(req
, socket
, head
);
87 hs
.on('request', function(req
, res
){
88 var base_path
= (global
.config
.http_base_path
|| ''),
91 // Trim off any trailing slashes
92 if (base_path
.substr(base_path
.length
- 1) === '/') {
93 base_path
= base_path
.substr(0, base_path
.length
- 1);
95 transport_url
= base_path
+ '/transport';
97 Stats
.incr('http.request');
99 // engine.io can sometimes "loose" the clients remote address. Keep note of it
101 remote_address
: req
.connection
.remoteAddress
104 // If the request is for our transport, pass it onto engine.io
105 if (req
.url
.toLowerCase().indexOf(transport_url
.toLowerCase()) === 0) {
106 that
.ws
.handleRequest(req
, res
);
108 http_handler
.serve(req
, res
);
114 this.ws
.on('connection', function(socket
) {
115 Stats
.incr('http.websocket');
117 initialiseSocket(socket
, function(err
, authorised
) {
125 client
= new Client(socket
, {server_config
: web_config
});
126 client
.on('dispose', function () {
127 that
.emit('client_dispose', this);
130 that
.emit('connection', client
);
132 // Call any modules listening for new clients
133 global
.modules
.emit('client created', {client
: client
});
137 util
.inherits(WebListener
, events
.EventEmitter
);
141 function rangeCheck(addr
, range
) {
142 var i
, ranges
, parts
;
143 ranges
= (!_
.isArray(range
)) ? [range
] : range
;
144 for (i
= 0; i
< ranges
.length
; i
++) {
145 parts
= ranges
[i
].split('/');
146 if (ipaddr
.process(addr
).match(ipaddr
.process(parts
[0]), parts
[1])) {
155 * Get the reverse DNS entry for this connection.
156 * Used later on for webirc, etc functionality
158 function initialiseSocket(socket
, callback
) {
159 var request
= socket
.request
,
160 address
= request
.meta
.remote_address
,
163 // Key/val data stored to the socket to be read later on
164 // May also be synced to a redis DB to lookup clients
165 socket
.meta
= socket
.request
.meta
;
167 // If a forwarded-for header is found, switch the source address
168 if (request
.headers
[global
.config
.http_proxy_ip_header
|| 'x-forwarded-for']) {
169 // Check we're connecting from a whitelisted proxy
170 if (!global
.config
.http_proxies
|| !rangeCheck(address
, global
.config
.http_proxies
)) {
171 winston
.info('Unlisted proxy: %s', address
);
172 callback(null, false);
176 // We're sent from a whitelisted proxy, replace the hosts
177 address
= request
.headers
[global
.config
.http_proxy_ip_header
|| 'x-forwarded-for'];
180 socket
.meta
.real_address
= address
;
182 // If enabled, don't go over the connection limit
183 if (global
.config
.max_client_conns
&& global
.config
.max_client_conns
> 0) {
184 if (global
.clients
.numOnAddress(address
) + 1 > global
.config
.max_client_conns
) {
185 return callback(null, false);
191 dns
.reverse(address
, function (err
, domains
) {
192 if (!err
&& domains
.length
> 0) {
193 revdns
= _
.first(domains
);
197 // No reverse DNS found, use the IP
198 socket
.meta
.revdns
= address
;
199 callback(null, true);
202 // Make sure the reverse DNS matches the A record to use the hostname..
203 dns
.lookup(revdns
, function (err
, ip_address
, family
) {
204 if (!err
&& ip_address
== address
) {
205 // A record matches PTR, perfectly valid hostname
206 socket
.meta
.revdns
= revdns
;
208 // A record does not match the PTR, invalid hostname
209 socket
.meta
.revdns
= address
;
212 // We have all the info we need, proceed with the connection
213 callback(null, true);
219 socket
.meta
.revdns
= address
;
220 callback(null, true);