aboutsummaryrefslogtreecommitdiffstats
path: root/src/server/HttpServer.hx
blob: b49301b3d8e85456a73d50f772da34f035dbfc95 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
package server;

import js.node.Buffer;
import haxe.io.Path;
import js.node.Fs;
import sys.io.File;
import js.node.http.IncomingMessage;
import js.node.http.ServerResponse;
import js.Node.__dirname;
import js.node.Path as JsPath;
using StringTools;

class HttpServer {

	static final mimeTypes = [
		"html" => "text/html",
		"js" => "text/javascript",
		"css" => "text/css",
		"json" => "application/json",
		"png" => "image/png",
		"jpg" => "image/jpg",
		"gif" => "image/gif",
		"svg" => "image/svg+xml",
		"ico" => "image/x-icon",
		"wav" => "audio/wav",
		"mp3" => "audio/mpeg",
		"mp4" => "video/mp4",
		"woff" => "application/font-woff",
		"ttf" => "application/font-ttf",
		"eot" => "application/vnd.ms-fontobject",
		"otf" => "application/font-otf",
		"wasm" => "application/wasm"
	];

	static var dir:String;

	public static function init(directory:String):Void {
		dir = directory;
	}

	public static function serveFiles(req:IncomingMessage, res:ServerResponse):Void {
		var filePath = dir + req.url;
		if (req.url == "/") filePath = '$dir/index.html';

		final extension = Path.extension(filePath).toLowerCase();
		final contentType = getMimeType(extension);

		if (!isChildOf(dir, filePath)) {
			res.statusCode = 500;
			var rel = JsPath.relative(dir, filePath);
			res.end('Error getting the file: No access to $rel.');
			return;
		}

		// load client code from build folder
		if (filePath == '$dir/client.js') {
			filePath = '$__dirname/client.js';
		}

		Fs.readFile(filePath, function(err:Dynamic, data:Buffer) {
			if (err != null) {
				if (err.code == "ENOENT") {
					res.statusCode = 404;
					var rel = JsPath.relative(dir, filePath);
					res.end('File $rel not found.');
				} else {
					res.statusCode = 500;
					res.end('Error getting the file: $err.');
				}
				return;
			}
			res.setHeader("Content-Type", contentType);
			if (extension == "html") {
				// replace ${textId} to localized strings
				data = cast localizeHtml(data.toString(), req.headers["accept-language"]);
			}
			res.end(data);
		});
	}

	static final matchLang = ~/^[A-z]+/;

	static function localizeHtml(data:String, lang:String):String {
		if (lang != null && matchLang.match(lang)) {
			lang = matchLang.matched(0);
		} else lang = "en";
		data = ~/\${([A-z_]+)}/g.map(data, (regExp) -> {
			final key = regExp.matched(1);
			return Lang.get(lang, key);
		});
		return data;
	}

	static function isChildOf(parent:String, child:String):Bool {
		final path = JsPath;
		final relative = path.relative(parent, child);
		return relative.length > 0 && !relative.startsWith('..') && !path.isAbsolute(relative);
	}

	static function getMimeType(ext:String):String {
		var contentType = mimeTypes[ext];
		if (contentType == null) contentType = "application/octet-stream";
		return contentType;
	}

}
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage