1 var url
= require('url'),
3 node_static
= require('node-static'),
5 config
= require('./configuration.js'),
6 SettingsGenerator
= require('./settingsgenerator.js');
11 var HttpHandler = function (config
) {
12 var public_http
= config
.public_http
|| 'client/';
13 this.file_server
= new node_static
.Server(public_http
);
16 module
.exports
.HttpHandler
= HttpHandler
;
20 HttpHandler
.prototype.serve = function (request
, response
) {
21 // The incoming requests base path (ie. /kiwiclient)
22 var base_path
= global
.config
.http_base_path
|| '/kiwi',
25 // Trim of any trailing slashes
26 if (base_path
.substr(base_path
.length
- 1) === '/') {
27 base_path
= base_path
.substr(0, base_path
.length
- 1);
30 // Build the regex to match the base_path
31 base_path_regex
= base_path
.replace(/[-/\\^$*+?.()|[\]{}]/g
, '\\$&');
33 // Any asset request to head into the asset dir
34 request
.url
= request
.url
.replace(base_path
+ '/assets/', '/assets/');
36 // Any src request to head into the src dir
37 request
.url
= request
.url
.replace(base_path
+ '/src/', '/src/');
39 // Any requests for /client to load the index file
40 if (request
.url
.match(new RegExp('^' + base_path_regex
+ '([/$]|$)', 'i'))) {
41 request
.url
= '/index.html';
44 // If the 'magic' translation is requested, figure out the best language to use from
45 // the Accept-Language HTTP header. If nothing is suitible, fallback to our en-gb default translation
46 if (request
.url
.substr(0, 16) === '/assets/locales/') {
47 if (request
.url
=== '/assets/locales/magic.json') {
48 return serveMagicLocale
.call(this, request
, response
);
50 response
.setHeader('Content-Language', request
.url
.substr(16, request
.url
.indexOf('.') - 16));
52 } else if (request
.url
.substr(0, 21) === '/assets/settings.json') {
53 return serveSettings
.call(this, request
, response
);
56 this.file_server
.serve(request
, response
, function (err
) {
58 response
.writeHead(err
.status
, err
.headers
);
66 * Handle the /assets/locales/magic.json request
67 * Find the closest translation we have for the language
70 var serveMagicLocale = function (request
, response
) {
72 default_locale_id
= 'en-gb';
74 if (!request
.headers
['accept-language']) {
75 // No accept-language specified in the request so send the default
76 return serveLocale
.call(this, request
, response
, default_locale_id
);
79 fs
.readdir('client/assets/locales', function (err
, files
) {
82 langs
= request
.headers
['accept-language'].split(','), // Example: en-gb,en;q=0.5
83 found_locale
= default_locale_id
;
85 // Get a list of the available translations we have
86 files
.forEach(function (file
) {
87 if (file
.substr(-5) === '.json') {
88 available
.push(file
.slice(0, -5));
92 // Sanitise the browsers accepted languages and the qualities
93 for (i
= 0; i
< langs
.length
; i
++) {
94 langs
[i
]= langs
[i
].split(';q=');
95 langs
[i
][0] = langs
[i
][0].toLowerCase();
96 langs
[i
][1] = (typeof langs
[i
][1] === 'string') ? parseFloat(langs
[i
][1]) : 1.0;
99 // Sort the accepted languages by quality
100 langs
.sort(function (a
, b
) {
104 // Serve the first language we have a translation for
105 for (i
= 0; i
< langs
.length
; i
++) {
106 if (langs
[i
][0] === '*') {
108 } else if (_
.contains(available
, langs
[i
][0])) {
109 found_locale
= langs
[i
][0];
114 return serveLocale
.call(that
, request
, response
, found_locale
);
120 * Send a locale to the browser
122 var serveLocale = function (request
, response
, locale_id
) {
123 this.file_server
.serveFile('/assets/locales/' + locale_id
+ '.json', 200, {
124 Vary
: 'Accept-Language',
125 'Content-Language': locale_id
126 }, request
, response
);
131 * Handle the settings.json request
133 var serveSettings = function(request
, response
) {
138 // Check the referrer for a debug option
139 if (request
.headers
['referer']) {
140 referrer_url
= url
.parse(request
.headers
['referer'], true);
141 if (referrer_url
.query
&& referrer_url
.query
.debug
) {
146 SettingsGenerator
.get(debug
, function(settings
) {
147 if (request
.headers
['if-none-match'] && request
.headers
['if-none-match'] === settings
.hash
) {
148 response
.writeHead(304, 'Not Modified');
149 return response
.end();
152 response
.writeHead(200, {
153 'ETag': settings
.hash
,
154 'Content-Type': 'application/json'
156 response
.end(settings
.settings
);