Emoticons erroneous quote
[KiwiIRC.git] / server / httphandler.js
CommitLineData
bd299b17 1var url = require('url'),
0fa2ca42
JA
2 fs = require('fs'),
3 node_static = require('node-static'),
88a9b153 4 Negotiator = require('negotiator'),
cbcd1a23 5 _ = require('lodash'),
132ba3df 6 config = require('./configuration.js'),
840d6a6e 7 winston = require('winston'),
0ca6adac
D
8 SettingsGenerator = require('./settingsgenerator.js'),
9 Stats = require('./stats.js');
3eb6b5fd
D
10
11
12
a8bf3ea4 13
186531ed 14var HttpHandler = function (config) {
ceb43091
D
15 var public_http = config.public_http || 'client/';
16 this.file_server = new node_static.Server(public_http);
a8bf3ea4
JA
17};
18
186531ed
D
19module.exports.HttpHandler = HttpHandler;
20
21
22
23HttpHandler.prototype.serve = function (request, response) {
b65ad8f1 24 // The incoming requests base path (ie. /kiwiclient)
ba317e87
D
25 var base_path, base_check,
26 whitelisted_folders = ['/assets', '/src'],
27 is_whitelisted_folder = false;
b65ad8f1 28
ba317e87
D
29 // Trim off any trailing slashes from the base_path
30 base_path = global.config.http_base_path || '';
b65ad8f1
D
31 if (base_path.substr(base_path.length - 1) === '/') {
32 base_path = base_path.substr(0, base_path.length - 1);
33 }
0fa2ca42 34
f5114ea7
D
35 // Normalise the URL + remove query strings to compare against the base_path
36 base_check = request.url.split('?')[0];
ba317e87
D
37 if (base_check.substr(base_check.length - 1) !== '/') {
38 base_check += '/';
39 }
40
41 // Normalise the URL we use by removing the base path
42 if (base_check.indexOf(base_path + '/') === 0) {
43 request.url = request.url.replace(base_path, '');
44
45 } else if (base_check !== '/') {
46 // We don't handle requests outside of the base path and not /, so just 404
47 response.writeHead(404);
48 response.write('Not Found');
49 response.end();
50 return;
51 }
52
903f9288
D
53 // Map any whitelisted folders to the local directories
54 whitelisted_folders.forEach(function(folder) {
ba317e87
D
55 if (request.url.indexOf(folder) === 0) {
56 is_whitelisted_folder = true;
57 }
903f9288 58 });
c3511215 59
ba317e87
D
60 // Any requests not for whitelisted assets returns the index page
61 if (!is_whitelisted_folder) {
92f1ff73 62 request.url = '/index.html';
b075a0d6
D
63 }
64
0ca6adac
D
65 if (request.url === '/index.html') {
66 Stats.incr('http.homepage');
67 }
68
0fa2ca42 69 // If the 'magic' translation is requested, figure out the best language to use from
b722f3c6 70 // the Accept-Language HTTP header. If nothing is suitible, fallback to our en-gb default translation
28cde487
JA
71 if (request.url.substr(0, 16) === '/assets/locales/') {
72 if (request.url === '/assets/locales/magic.json') {
73 return serveMagicLocale.call(this, request, response);
74 } else {
75 response.setHeader('Content-Language', request.url.substr(16, request.url.indexOf('.') - 16));
76 }
cbcd1a23
JA
77 } else if (request.url.substr(0, 21) === '/assets/settings.json') {
78 return serveSettings.call(this, request, response);
0fa2ca42 79 }
0ae87edb 80
186531ed 81 this.file_server.serve(request, response, function (err) {
a8bf3ea4 82 if (err) {
bd299b17
JA
83 response.writeHead(err.status, err.headers);
84 response.end();
a8bf3ea4
JA
85 }
86 });
0fa2ca42
JA
87};
88
3eb6b5fd 89
88a9b153
D
90// Cached list of available translations
91var cached_available_locales = [];
92
93// Get a list of the available translations we have
94fs.readdir('client/assets/locales', function (err, files) {
840d6a6e
D
95 if (err) {
96 if (err.code === 'ENOENT') {
97 winston.error('No locale files could be found at ' + err.path);
98 } else {
99 winston.error('Error reading locales.', err);
100 }
101 }
102
103 (files || []).forEach(function (file) {
88a9b153
D
104 if (file.substr(-5) === '.json') {
105 cached_available_locales.push(file.slice(0, -5));
106 }
107 });
108});
109
110
111
3eb6b5fd
D
112/**
113 * Handle the /assets/locales/magic.json request
114 * Find the closest translation we have for the language
115 * set in the browser.
116 **/
0fa2ca42 117var serveMagicLocale = function (request, response) {
88a9b153
D
118 var default_locale_id = 'en-gb',
119 found_locale, negotiator;
8e1ab29d 120
132ba3df
D
121 if (!request.headers['accept-language']) {
122 // No accept-language specified in the request so send the default
88a9b153 123 found_locale = default_locale_id;
cbc8feae 124
88a9b153
D
125 } else {
126 negotiator = new Negotiator(request);
127 found_locale = negotiator.language(cached_available_locales);
e539b24c
D
128
129 // If a locale couldn't be negotiated, use the default
130 found_locale = found_locale || default_locale_id;
88a9b153 131 }
3eb6b5fd 132
88a9b153
D
133 // Send a locale to the browser
134 this.file_server.serveFile('/assets/locales/' + found_locale + '.json', 200, {
3eb6b5fd 135 Vary: 'Accept-Language',
88a9b153 136 'Content-Language': found_locale
3eb6b5fd 137 }, request, response);
0fa2ca42 138};
cbcd1a23 139
3eb6b5fd 140
88a9b153 141
3eb6b5fd
D
142/**
143 * Handle the settings.json request
144 */
132ba3df 145var serveSettings = function(request, response) {
3eb6b5fd
D
146 var referrer_url,
147 debug = false,
148 settings;
149
150 // Check the referrer for a debug option
151 if (request.headers['referer']) {
152 referrer_url = url.parse(request.headers['referer'], true);
153 if (referrer_url.query && referrer_url.query.debug) {
154 debug = true;
155 }
498afd32 156 }
cbe80532 157
132ba3df
D
158 SettingsGenerator.get(debug, function(settings) {
159 if (request.headers['if-none-match'] && request.headers['if-none-match'] === settings.hash) {
160 response.writeHead(304, 'Not Modified');
161 return response.end();
cbcd1a23
JA
162 }
163
132ba3df
D
164 response.writeHead(200, {
165 'ETag': settings.hash,
166 'Content-Type': 'application/json'
cbe80532 167 });
132ba3df 168 response.end(settings.settings);
cbe80532 169 });
132ba3df 170};