1 var ws
= require('socket.io'),
2 events
= require('events'),
3 http
= require('http'),
4 https
= require('https'),
5 util
= require('util'),
10 spdy
= require('spdy'),
11 ipaddr
= require('ipaddr.js'),
12 Client
= require('./client.js').Client
,
13 HttpHandler
= require('./httphandler.js').HttpHandler
,
14 rehash
= require('./rehash.js');
18 rehash
.on('rehashed', function (files
) {
19 Client
= require('./client.js').Client
;
20 HttpHandler
= require('./httphandler.js').HttpHandler
;
24 // Instance of HttpHandler
28 var WebListener = function (web_config
, transports
) {
29 var hs
, opts
, ws_opts
,
33 events
.EventEmitter
.call(this);
35 http_handler
= new HttpHandler(web_config
);
37 // Standard options for the socket.io connections
46 key
: fs
.readFileSync(web_config
.ssl_key
),
47 cert
: fs
.readFileSync(web_config
.ssl_cert
)
50 // Do we have an intermediate certificate?
51 if (typeof web_config
.ssl_ca
!== 'undefined') {
53 if (typeof web_config
.ssl_ca
.map
!== 'undefined') {
54 opts
.ca
= web_config
.ssl_ca
.map(function (f
) { return fs
.readFileSync(f
); });
57 opts
.ca
= fs
.readFileSync(web_config
.ssl_ca
);
61 hs
= spdy
.createServer(opts
, handleHttpRequest
);
63 // Start socket.io listening on this weblistener
64 this.ws
= ws
.listen(hs
, _
.extend({ssl
: true}, ws_opts
));
65 hs
.listen(web_config
.port
, web_config
.address
, function () {
66 that
.emit('listening');
70 // Start some plain-text server up
71 hs
= http
.createServer(handleHttpRequest
);
73 // Start socket.io listening on this weblistener
74 this.ws
= ws
.listen(hs
, _
.extend({ssl
: false}, ws_opts
));
75 hs
.listen(web_config
.port
, web_config
.address
, function () {
76 that
.emit('listening');
80 hs
.on('error', function (err
) {
81 that
.emit('error', err
);
84 this.ws
.enable('browser client minification');
85 this.ws
.enable('browser client etag');
86 this.ws
.set('transports', transports
);
87 this.ws
.set('resource', (global
.config
.http_base_path
|| '') + '/transport');
89 this.ws
.of('/kiwi').authorization(authoriseConnection
)
90 .on('connection', function () {
91 newConnection
.apply(that
, arguments
);
94 this.ws
.of('/kiwi').on('error', console
.log
);
96 util
.inherits(WebListener
, events
.EventEmitter
);
100 function handleHttpRequest(request
, response
) {
101 var uri
= url
.parse(request
.url
, true);
103 // If this isn't a socket.io request, pass it onto the http handler
104 if (uri
.pathname
.substr(0, 10) !== '/socket.io') {
105 http_handler
.serve(request
, response
);
109 function rangeCheck(addr
, range
) {
110 var i
, ranges
, parts
;
111 ranges
= (!_
.isArray(range
)) ? [range
] : range
;
112 for (i
= 0; i
< ranges
.length
; i
++) {
113 parts
= ranges
[i
].split('/');
114 if (ipaddr
.process(addr
).match(ipaddr
.process(parts
[0]), parts
[1])) {
123 * Get the reverse DNS entry for this connection.
124 * Used later on for webirc, etc functionality
126 function authoriseConnection(handshakeData
, callback
) {
127 var address
= handshakeData
.address
.address
;
129 // If a forwarded-for header is found, switch the source address
130 if (handshakeData
.headers
[global
.config
.http_proxy_ip_header
|| 'x-forwarded-for']) {
131 // Check we're connecting from a whitelisted proxy
132 if (!global
.config
.http_proxies
|| !rangeCheck(address
, global
.config
.http_proxies
)) {
133 console
.log('Unlisted proxy:', address
);
134 callback(null, false);
138 // We're sent from a whitelisted proxy, replace the hosts
139 address
= handshakeData
.headers
['x-forwarded-for'];
142 handshakeData
.real_address
= address
;
144 // If enabled, don't go over the connection limit
145 if (global
.config
.max_client_conns
&& global
.config
.max_client_conns
> 0) {
146 if (global
.clients
.numOnAddress(address
) + 1 > global
.config
.max_client_conns
) {
147 return callback(null, false);
153 dns
.reverse(address
, function (err
, domains
) {
154 if (err
|| domains
.length
=== 0) {
155 handshakeData
.revdns
= address
;
157 handshakeData
.revdns
= _
.first(domains
) || address
;
160 // All is well, authorise the connection
161 callback(null, true);
164 handshakeData
.revdns
= address
;
165 callback(null, true);
169 function newConnection(websocket
) {
170 var client
, that
= this;
171 client
= new Client(websocket
);
172 client
.on('dispose', function () {
173 that
.emit('client_dispose', this);
175 this.emit('connection', client
);
182 module
.exports
= WebListener
;