UNPKG

4.44 kBJavaScriptView Raw
1const Domain = require('./domain.js');
2const BlazeError = require('./error.js');
3
4const urlPattern = require('url-pattern');
5const url = require('url');
6const fs = require('fs-extra');
7const path = require('path');
8const mime = require('mime-types');
9const protocols = {
10 "https": require('https'),
11 "http": require('http')
12}
13
14const Plugin = require('./plugins.js');
15const form = require('./form.js');
16const context = require('./context.js');
17
18module.exports = class server {
19 constructor(config) {
20 this.Instances = [];
21 this.Log = new require('./logger.js')(config.logger);
22
23 let instances = [];
24 config.http.ports.forEach(port => {
25 instances.push({ protocol: 'http', port: port });
26 });
27
28 config.https.ports.forEach(port => {
29 instances.push({ protocol: 'https', port: port });
30 });
31 instances.forEach(instanceConfig => {
32 let serverInstance = protocols[instanceConfig.protocol].createServer({ SNICallback: Domain.handleSSL });
33 serverInstance.on('request', async (request, response) => { await this.handleRequest(request, response, instanceConfig.protocol) });
34 serverInstance.on('timeout', async (socket) => { await this.handleTimeout(socket.$_CONTEXT, new BlazeError('Request Timed Out', 408)); })
35 serverInstance.on('error', async (error) => { await this.handleError({}, new BlazeError(error, 500)); });
36 this.Instances.push({
37 port: instanceConfig.port, server: serverInstance
38 });
39 });
40 }
41
42 async handleRequest(request, response, protocol) {
43 let $_SOCKET = request.socket;
44 let $_CONTEXT = $_SOCKET.$_CONTEXT = new context(request, response, this.Log);
45
46 $_CONTEXT.$_REQUEST.uri = new URL(protocol + '://' + request.headers.host + request.url);
47 $_CONTEXT.$_DOMAIN = await Domain.find(request.uri.host, protocol === 'https');
48
49 try {
50 if ($_CONTEXT.$_DOMAIN) {
51 let filename = $_CONTEXT.$_REQUEST.uri.pathname;
52 for (let pattern in $_CONTEXT.$_DOMAIN.redirects) {
53 let match = new urlPattern(pattern)
54 .match($_CONTEXT.$_REQUEST.uri.hostname + $_CONTEXT.$_REQUEST.uri.pathname);
55
56 if (match) {
57 let redirect = $_CONTEXT.$_DOMAIN.redirects[pattern];
58 response.writeHead(redirect.code, { 'Location': $_CONTEXT.$_REQUEST.uri.protocol + '//' + eval('`' + redirect.rewrite.replace(/\$\{/g, '${match.') + '`') });
59 break;
60 }
61 }
62 for (let pattern in $_CONTEXT.$_DOMAIN.rewrites) {
63 let match = new urlPattern(pattern)
64 .match($_CONTEXT.$_REQUEST.uri.pathname);
65
66 if (match) {
67 let evaled = eval('`' + $_CONTEXT.$_DOMAIN.rewrites[pattern].replace(/\$\{/g, '${match.') + '`');
68 let fileObject = new URL(evaled, $_CONTEXT.$_REQUEST.uri.origin + '/');
69 filename = evaled.replace(fileObject.search, '')
70 $_CONTEXT.$_REQUEST.uri.template = fileObject.searchParams;
71 break;
72 }
73 }
74
75 request.method = request.method.toLowerCase();
76
77 $_CONTEXT.setFilePath(path.join($_CONTEXT.$_DOMAIN.root, decodeURIComponent(filename) || "/"));
78
79 await Plugin.fire($_CONTEXT, Plugin.BEFORE_REQUEST);
80
81 if (
82 !fs.existsSync($_CONTEXT.$_SERVER.$_FILEPATH) ||
83 !fs.statSync($_CONTEXT.$_SERVER.$_FILEPATH).isFile()
84 ) {
85 throw (new BlazeError(request.uri.href + " not found", 404));
86 }
87
88 if (!$_CONTEXT.$_RESPONSE.finished) {
89 let contentType = mime.contentType($_CONTEXT.$_FILENAME);
90 $_CONTEXT.$_RESPONSE.setHeader("Content-Type", contentType);
91
92 await $_CONTEXT.$_DOMAIN.parse($_CONTEXT, fs.readFileSync($_CONTEXT.$_SERVER.$_FILEPATH, mime.charset(contentType) || null))
93
94 this.end($_CONTEXT);
95 }
96 }
97 } catch (error) {
98 this.handleError($_CONTEXT, error);
99 }
100 }
101
102 async end($_CONTEXT) {
103 if (!$_CONTEXT.$_RESPONSE.finished) {
104 $_CONTEXT.$_RESPONSE.end($_CONTEXT.$_SERVER.Response);
105 await Plugin.fire($_CONTEXT, Plugin.AFTER_REQUEST);
106 }
107 }
108
109 async handleTimeout($_CONTEXT, error) {
110 await Plugin.fire($_CONTEXT, Plugin.BEFORE_TIMEOUT);
111 await this.handleError($_CONTEXT, error);
112 await Plugin.fire($_CONTEXT, Plugin.AFTER_TIMEOUT);
113 }
114
115 async handleError($_CONTEXT, error) {
116 await Plugin.fire($_CONTEXT, Plugin.BEFORE_ERROR);
117 if (!(error instanceof BlazeError)) {
118 error = new BlazeError(error, 500);
119 }
120
121 $_CONTEXT.$_LOG(error)
122 $_CONTEXT.$_SERVER.Response = error.format();
123 this.end($_CONTEXT);
124 await Plugin.fire($_CONTEXT, Plugin.AFTER_ERROR);
125 }
126
127 async listen() {
128 this.Instances.forEach(instance => {
129 instance.server.listen(instance.port);
130 });
131 }
132}
\No newline at end of file