Replaced 'underscore' with 'lodash'.
[KiwiIRC.git] / server / weblistener.js
1 var ws = require('socket.io'),
2 events = require('events'),
3 http = require('http'),
4 https = require('https'),
5 util = require('util'),
6 fs = require('fs'),
7 dns = require('dns'),
8 url = require('url'),
9 _ = require('lodash'),
10 Client = require('./client.js').Client,
11 HttpHandler = require('./httphandler.js').HttpHandler,
12 rehash = require('./rehash.js');
13
14
15
16 rehash.on('rehashed', function (files) {
17 Client = require('./client.js').Client;
18 HttpHandler = require('./httphandler.js').HttpHandler;
19 });
20
21
22 // Instance of HttpHandler
23 var http_handler;
24
25
26 var WebListener = function (web_config, transports) {
27 var hs, opts, ws_opts,
28 that = this;
29
30
31 events.EventEmitter.call(this);
32
33 http_handler = new HttpHandler(web_config);
34
35 // Standard options for the socket.io connections
36 ws_opts = {
37 'log level': 0,
38 'log colors': 0
39 };
40
41
42 if (web_config.ssl) {
43 opts = {
44 key: fs.readFileSync(__dirname + '/' + web_config.ssl_key),
45 cert: fs.readFileSync(__dirname + '/' + web_config.ssl_cert)
46 };
47
48 // Do we have an intermediate certificate?
49 if (typeof web_config.ssl_ca !== 'undefined') {
50 opts.ca = fs.readFileSync(__dirname + '/' + web_config.ssl_ca);
51 }
52
53
54 hs = https.createServer(opts, handleHttpRequest);
55
56 // Start socket.io listening on this weblistener
57 this.ws = ws.listen(hs, _.extend({ssl: true}, ws_opts));
58 hs.listen(web_config.port, web_config.address);
59
60 console.log('Listening on ' + web_config.address + ':' + web_config.port.toString() + ' with SSL');
61 } else {
62
63 // Start some plain-text server up
64 hs = http.createServer(handleHttpRequest);
65
66 // Start socket.io listening on this weblistener
67 this.ws = ws.listen(hs, _.extend({ssl: false}, ws_opts));
68 hs.listen(web_config.port, web_config.address);
69
70 console.log('Listening on ' + web_config.address + ':' + web_config.port.toString() + ' without SSL');
71 }
72
73 this.ws.enable('browser client minification');
74 this.ws.enable('browser client etag');
75 this.ws.set('transports', transports);
76 this.ws.set('resource', (global.config.http_base_path || '') + '/transport');
77
78 this.ws.of('/kiwi').authorization(authoriseConnection)
79 .on('connection', function () {
80 newConnection.apply(that, arguments);
81 }
82 );
83 this.ws.of('/kiwi').on('error', console.log);
84 };
85 util.inherits(WebListener, events.EventEmitter);
86
87
88
89 function handleHttpRequest(request, response) {
90 var uri = url.parse(request.url, true);
91
92 // If this isn't a socket.io request, pass it onto the http handler
93 if (uri.pathname.substr(0, 10) !== '/socket.io') {
94 http_handler.serve(request, response);
95 }
96 }
97
98
99 /**
100 * Get the reverse DNS entry for this connection.
101 * Used later on for webirc, etc functionality
102 */
103 function authoriseConnection(handshakeData, callback) {
104 var address = handshakeData.address.address;
105
106 // If a forwarded-for header is found, switch the source address
107 if (handshakeData.headers['x-forwarded-for']) {
108 // Check we're connecting from a whitelisted proxy
109 if (!global.config.http_proxies || global.config.http_proxies.indexOf(address) < 0) {
110 console.log('Unlisted proxy:', address);
111 callback(null, false);
112 return;
113 }
114
115 // We're sent from a whitelisted proxy, replace the hosts
116 address = handshakeData.headers['x-forwarded-for'];
117 }
118
119 handshakeData.real_address = address;
120
121 // If enabled, don't go over the connection limit
122 if (global.config.max_client_conns && global.config.max_client_conns > 0) {
123 if (global.clients.numOnAddress(address) + 1 > global.config.max_client_conns) {
124 return callback(null, false);
125 }
126 }
127
128 dns.reverse(address, function (err, domains) {
129 if (err || domains.length === 0) {
130 handshakeData.revdns = address;
131 } else {
132 handshakeData.revdns = _.first(domains) || address;
133 }
134
135 // All is well, authorise the connection
136 callback(null, true);
137 });
138 }
139
140 function newConnection(websocket) {
141 var client, that = this;
142 client = new Client(websocket);
143 client.on('destroy', function () {
144 that.emit('destroy', this);
145 });
146 this.emit('connection', client);
147 }
148
149
150
151
152
153 module.exports = WebListener;