rtjscomp 0.8.7 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +68 -13
- package/package.json +1 -1
- package/public/index.html +16 -4
- package/rtjscomp.js +391 -189
- package/changes_before_git.txt +0 -58
- package/config/file_type_dyns.txt +0 -7
- package/config/file_type_mimes.txt +0 -21
- package/config/file_type_nocompress.txt +0 -8
- package/config/path_aliases.txt +0 -5
- package/config/port_http.txt +0 -1
- package/config/port_https.txt +0 -0
- package/config/services.txt +0 -2
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ easy to use http server that allows for using javascript just as php was used ba
|
|
|
6
6
|
> as the issues indicate, a lot of breaking changes are ahead.
|
|
7
7
|
> make sure to check for these in future until version 1.0.0 is relessed.
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## usage
|
|
10
10
|
|
|
11
11
|
go into the directory where you want to have your project and run
|
|
12
12
|
|
|
@@ -29,23 +29,78 @@ $ npm install
|
|
|
29
29
|
$ npm start
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
##
|
|
32
|
+
## rtjscomp.json (optional)
|
|
33
|
+
|
|
34
|
+
it is only needed if you want to change default settings. it has the following properties:
|
|
35
|
+
|
|
36
|
+
- `path_aliases`: object where the key is the url path and the value is the file path
|
|
37
|
+
- `path_ghosts`: array of paths that are simply ignored, no response is sent
|
|
38
|
+
- `path_hiddens`: array of paths that give 404
|
|
39
|
+
- `path_statics`: array of paths in which nothing is transpiled, but the file is sent as is
|
|
40
|
+
- `port_http`: port for http server, default is 8080
|
|
41
|
+
- `port_https`: port for https server
|
|
42
|
+
- `services`: paths to (enabled) service files, prepend an entry with # to disable it
|
|
43
|
+
- `type_dynamics`: dynamic file types, see [api](#api)
|
|
44
|
+
- `type_mimes`: file type to mime type map (most common are already set, only overrides)
|
|
45
|
+
- `type_raws`: array of file types that are sent uncompressed
|
|
46
|
+
|
|
47
|
+
here is an example for a customized setup:
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"path_aliases": {
|
|
52
|
+
"": "index.html",
|
|
53
|
+
"blog": "modules/blog/index.html",
|
|
54
|
+
"blog/*id": "modules/blog/article.html"
|
|
55
|
+
},
|
|
56
|
+
"path_ghosts": [ "admin", "wp-admin" ],
|
|
57
|
+
"path_hiddens": [ "secrets.html" ],
|
|
58
|
+
"path_statics": [ "rawtruth.html" ],
|
|
59
|
+
"port_http": 8080,
|
|
60
|
+
"services": [
|
|
61
|
+
"modules/blog/blog",
|
|
62
|
+
"#modules/not/needed"
|
|
63
|
+
],
|
|
64
|
+
"type_dynamics": [ "html", "js" ],
|
|
65
|
+
"type_mimes": {
|
|
66
|
+
"html": "text/html; charset=UTF-8",
|
|
67
|
+
"js": "application/javascript; charset=UTF-8",
|
|
68
|
+
"custom": "application/custom"
|
|
69
|
+
},
|
|
70
|
+
"type_raws": [ "png", "jpg", "pdf" ]
|
|
71
|
+
}
|
|
72
|
+
```
|
|
33
73
|
|
|
34
|
-
|
|
74
|
+
## directories
|
|
35
75
|
|
|
36
|
-
|
|
76
|
+
on first run, they will be created with some defaults.
|
|
37
77
|
|
|
38
|
-
-
|
|
39
|
-
- data dir, services store their data here
|
|
78
|
+
- data dir, services store their data or read custom config files here
|
|
40
79
|
- public dir, containing dynamic and static offerings and also services
|
|
41
80
|
|
|
42
|
-
|
|
81
|
+
## files in public dir
|
|
43
82
|
|
|
44
|
-
- static files like .png in public dir are sent to requests 1:1
|
|
45
|
-
- dynamic files like .html are transpiled
|
|
83
|
+
- static files like .png in public dir are sent to requests 1:1, maybe compressed
|
|
84
|
+
- dynamic files like .html are internally transpiled/compiled and executed -> "rtjscomp"
|
|
46
85
|
- .service.js files are executed and their `this` can be accessed by other files, they are not accessible to outside
|
|
47
86
|
|
|
48
|
-
|
|
87
|
+
example:
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
public
|
|
91
|
+
├── index.html
|
|
92
|
+
├── modules
|
|
93
|
+
│ ├── blog
|
|
94
|
+
│ │ ├── article.html
|
|
95
|
+
│ │ ├── blog.service.js
|
|
96
|
+
│ │ └── index.html
|
|
97
|
+
│ └── not
|
|
98
|
+
│ └── needed.service.js
|
|
99
|
+
├── rawtruth.html
|
|
100
|
+
└── secrets.html
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## api
|
|
49
104
|
|
|
50
105
|
in every served dynamic file (like .html), you can insert `<?` and `?>` tags to insert javascript code that is executed server-side. `<?= ... ?>` can be used to insert the result of an expression.
|
|
51
106
|
request-independent services can be created using .service.js files referenced in services.txt.
|
|
@@ -54,14 +109,14 @@ in both file types (dynamic served and services), you can use all node/bun metho
|
|
|
54
109
|
- `service_require(service path)`: returns the matching service object
|
|
55
110
|
- `service_require_try(service path)`: returns the matching service object or null if not found or if disabled
|
|
56
111
|
- `rtjscomp`: has these properties/methods:
|
|
57
|
-
- `actions`: an object with methods for server control (http[s]_[start|stop|
|
|
112
|
+
- `actions`: an object with methods for server control (http[s]_[start|stop|kill], log_clear, halt, exit)
|
|
58
113
|
- `async data_load(path)`: reads the file in data directory and returns its content or null
|
|
59
114
|
- `async data_load_watch(path, callback(content))`: executes callback first and on every change
|
|
60
115
|
- `async data_save(path, content)`: writes the content to the file in data directory
|
|
61
116
|
|
|
62
|
-
##
|
|
117
|
+
## supported environments
|
|
63
118
|
|
|
64
|
-
- node
|
|
119
|
+
- node 8.0.0 or higher
|
|
65
120
|
- bun
|
|
66
121
|
|
|
67
122
|
any os
|
package/package.json
CHANGED
package/public/index.html
CHANGED
|
@@ -1,4 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
<!DOCTYPE html><?
|
|
2
|
+
|
|
3
|
+
const code = Number(input.code || 42);
|
|
4
|
+
// this is not php but javascript!!!!!!!!!!!!!
|
|
5
|
+
// but for better syntax highlighting, set ide language to php.
|
|
6
|
+
// open your local website and look into its source code. this script will be gone.
|
|
7
|
+
|
|
8
|
+
?>
|
|
9
|
+
<html>
|
|
10
|
+
<body>
|
|
11
|
+
<h1>Hello, World!</h1>
|
|
12
|
+
<p>Current reason: <?= code ?></p>
|
|
13
|
+
<p><a href="/?code=<?= code + 1 ?>">One more</a></p>
|
|
14
|
+
<p>See <a href="https://github.com/L3P3/rtjscomp">the readme</a>!</p>
|
|
15
|
+
</body>
|
|
16
|
+
</html>
|
package/rtjscomp.js
CHANGED
|
@@ -7,52 +7,102 @@
|
|
|
7
7
|
|
|
8
8
|
(async () => {
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
const url = require('url');
|
|
10
|
+
// node libs
|
|
12
11
|
const fs = require('fs');
|
|
13
12
|
const fsp = require('fs/promises');
|
|
14
|
-
const
|
|
13
|
+
const http = require('http');
|
|
14
|
+
const url = require('url');
|
|
15
15
|
const zlib = require('zlib');
|
|
16
|
-
|
|
16
|
+
|
|
17
|
+
// external libs
|
|
18
|
+
const multipart_parse = require('parse-multipart-data').parse;
|
|
17
19
|
const querystring_parse = require('querystring').decode;
|
|
18
|
-
const
|
|
20
|
+
const request_ip_get = require('ipware')().get_ip;
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
const PATH_PUBLIC = 'public/';
|
|
22
|
-
const PATH_CONFIG = 'config/';
|
|
23
|
-
const PATH_DATA = 'data/';
|
|
24
|
-
const GZIP_OPTIONS = {level: 9};
|
|
25
|
-
const WATCH_OPTIONS = {persistent: true, interval: 1000};
|
|
22
|
+
// constants
|
|
26
23
|
const AGENT_CHECK_BOT = /bot|googlebot|crawler|spider|robot|crawling|favicon/i;
|
|
27
24
|
const AGENT_CHECK_MOBIL = /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i;
|
|
25
|
+
const GZIP_OPTIONS = {level: 9};
|
|
28
26
|
const HTTP_LIST_REG = /,\s*/;
|
|
29
27
|
const IMPORT_REG = /import\(/g;
|
|
28
|
+
const IS_BUN = typeof Bun !== 'undefined';
|
|
29
|
+
const PATH_CONFIG = 'config/';
|
|
30
|
+
const PATH_DATA = 'data/';
|
|
31
|
+
const PATH_PUBLIC = 'public/';
|
|
32
|
+
const RESOLVE_OPTIONS = {paths: [require('path').resolve()]};
|
|
33
|
+
const VERSION = require('./package.json').version;
|
|
34
|
+
const WATCH_OPTIONS = {persistent: true, interval: 1000};
|
|
30
35
|
|
|
36
|
+
// config
|
|
31
37
|
let log_verbose = process.argv.includes('-v');
|
|
32
38
|
let port_http = 0;
|
|
33
39
|
let port_https = 0;
|
|
34
|
-
const file_type_mimes = new Map;
|
|
35
|
-
const file_type_dyns = new Set;
|
|
36
|
-
const file_type_nocompress = new Set;
|
|
37
|
-
/// forced static files
|
|
38
|
-
const file_raws = new Set;
|
|
39
|
-
/// hidden files
|
|
40
|
-
const file_privates = new Set;
|
|
41
|
-
/// files where requests should be totally ignored
|
|
42
|
-
const file_blocks = new Set;
|
|
43
40
|
/// any path -> file
|
|
44
|
-
const path_aliases = new Map
|
|
45
|
-
|
|
41
|
+
const path_aliases = new Map([
|
|
42
|
+
['', 'index.html'],
|
|
43
|
+
]);
|
|
44
|
+
const path_aliases_reverse = new Map([
|
|
45
|
+
['index.html', '/'],
|
|
46
|
+
]);
|
|
46
47
|
const path_aliases_templates = new Map;
|
|
47
|
-
|
|
48
|
+
/// files where requests should be totally ignored
|
|
49
|
+
const path_ghosts = new Set;
|
|
50
|
+
/// hidden files
|
|
51
|
+
const path_hiddens = new Set;
|
|
52
|
+
/// forced static files
|
|
53
|
+
const path_statics = new Set;
|
|
54
|
+
const type_dynamics = new Set([
|
|
55
|
+
'events',
|
|
56
|
+
'html',
|
|
57
|
+
'json',
|
|
58
|
+
'txt',
|
|
59
|
+
]);
|
|
60
|
+
const type_mimes = new Map([
|
|
61
|
+
['apk', 'application/zip'],
|
|
62
|
+
['bpg', 'image/bpg'],
|
|
63
|
+
['css', 'text/css; charset=utf-8'],
|
|
64
|
+
['events', 'text/event-stream'],
|
|
65
|
+
['flac', 'audio/flac'],
|
|
66
|
+
['gz', 'application/gzip'],
|
|
67
|
+
['hta', 'application/hta'],
|
|
68
|
+
['html', 'text/html; charset=utf-8'],
|
|
69
|
+
['ico', 'image/x-icon'],
|
|
70
|
+
['jpg', 'image/jpeg'],
|
|
71
|
+
['js', 'text/javascript; charset=utf-8'],
|
|
72
|
+
['json', 'application/json; charset=utf-8'],
|
|
73
|
+
['mid', 'audio/midi'],
|
|
74
|
+
['mp3', 'audio/mpeg3'],
|
|
75
|
+
['pdf', 'application/pdf'],
|
|
76
|
+
['png', 'image/png'],
|
|
77
|
+
['rss', 'application/rss+xml; charset=utf-8'],
|
|
78
|
+
['txt', 'text/plain; charset=utf-8'],
|
|
79
|
+
['xml', 'application/xml; charset=utf-8'],
|
|
80
|
+
['xz', 'application/x-xz'],
|
|
81
|
+
['zip', 'application/zip'],
|
|
82
|
+
]);
|
|
83
|
+
const type_raws = new Set([
|
|
84
|
+
'apk',
|
|
85
|
+
'bpg',
|
|
86
|
+
'flac',
|
|
87
|
+
'gz',
|
|
88
|
+
'jpg',
|
|
89
|
+
'mp3',
|
|
90
|
+
'pdf',
|
|
91
|
+
'png',
|
|
92
|
+
'xz',
|
|
93
|
+
'zip',
|
|
94
|
+
]);
|
|
95
|
+
|
|
48
96
|
/// compiled file handlers
|
|
49
97
|
const file_cache_functions = new Map;
|
|
98
|
+
|
|
50
99
|
const actions = {};
|
|
51
100
|
const rtjscomp = global.rtjscomp = {
|
|
52
101
|
actions,
|
|
53
102
|
version: VERSION,
|
|
54
103
|
};
|
|
55
104
|
|
|
105
|
+
// polyfills
|
|
56
106
|
if (!Object.fromEntries) {
|
|
57
107
|
Object.fromEntries = entries => {
|
|
58
108
|
const object = {};
|
|
@@ -63,7 +113,7 @@ if (!Object.fromEntries) {
|
|
|
63
113
|
|
|
64
114
|
// workaround for bun: https://github.com/oven-sh/bun/issues/18919
|
|
65
115
|
let fs_watch = fs.watch;
|
|
66
|
-
if (
|
|
116
|
+
if (IS_BUN) {
|
|
67
117
|
const fs_watch_original = fs_watch;
|
|
68
118
|
const watch_callbacks = new Map;
|
|
69
119
|
fs_watch = (path, options, callback) => {
|
|
@@ -88,7 +138,7 @@ if (typeof Bun !== 'undefined') {
|
|
|
88
138
|
global.globals = rtjscomp;
|
|
89
139
|
global.actions = rtjscomp.actions;
|
|
90
140
|
global.data_load = name => {
|
|
91
|
-
log('[deprecated] synchronous load: ' + PATH_DATA + name);
|
|
141
|
+
log('[deprecated] synchronous load file: ' + PATH_DATA + name);
|
|
92
142
|
try {
|
|
93
143
|
return fs.readFileSync(PATH_DATA + name, 'utf8');
|
|
94
144
|
}
|
|
@@ -97,7 +147,7 @@ global.data_load = name => {
|
|
|
97
147
|
}
|
|
98
148
|
}
|
|
99
149
|
global.data_save = (name, data) => (
|
|
100
|
-
log('[deprecated] synchronous save: ' + PATH_DATA + name),
|
|
150
|
+
log('[deprecated] synchronous save file: ' + PATH_DATA + name),
|
|
101
151
|
fs.writeFileSync(PATH_DATA + name, data, 'utf8')
|
|
102
152
|
)
|
|
103
153
|
global.number_check_int = number => (
|
|
@@ -108,7 +158,7 @@ global.number_check_uint = number => (
|
|
|
108
158
|
)
|
|
109
159
|
|
|
110
160
|
rtjscomp.data_load = async name => {
|
|
111
|
-
if (log_verbose) log('load: ' + PATH_DATA + name);
|
|
161
|
+
if (log_verbose) log('load file: ' + PATH_DATA + name);
|
|
112
162
|
const data = await fsp.readFile(PATH_DATA + name, 'utf8').catch(() => null);
|
|
113
163
|
return name.endsWith('.json') ? JSON.parse(data || null) : data;
|
|
114
164
|
}
|
|
@@ -122,7 +172,7 @@ rtjscomp.data_load_watch = (name, callback) => (
|
|
|
122
172
|
))
|
|
123
173
|
)
|
|
124
174
|
rtjscomp.data_save = (name, data) => (
|
|
125
|
-
log_verbose && log('save: ' + PATH_DATA + name),
|
|
175
|
+
log_verbose && log('save file: ' + PATH_DATA + name),
|
|
126
176
|
fsp.writeFile(
|
|
127
177
|
PATH_DATA + name,
|
|
128
178
|
name.endsWith('.json') ? JSON.stringify(data) : data,
|
|
@@ -137,8 +187,8 @@ const custom_require = path => {
|
|
|
137
187
|
let result = custom_require_cache.get(path);
|
|
138
188
|
if (result != null) return result;
|
|
139
189
|
|
|
140
|
-
log_verbose && log('require: ' + path);
|
|
141
|
-
const path_real = require.resolve(path,
|
|
190
|
+
log_verbose && log('require module: ' + path);
|
|
191
|
+
const path_real = require.resolve(path, RESOLVE_OPTIONS);
|
|
142
192
|
custom_require_paths.add(path_real);
|
|
143
193
|
custom_require_cache.set(
|
|
144
194
|
path,
|
|
@@ -150,11 +200,11 @@ const custom_import = async path => {
|
|
|
150
200
|
let result = custom_import_cache.get(path);
|
|
151
201
|
if (result != null) return result;
|
|
152
202
|
|
|
153
|
-
log_verbose && log('import: ' + path);
|
|
203
|
+
log_verbose && log('import module: ' + path);
|
|
154
204
|
custom_import_cache.set(
|
|
155
205
|
path,
|
|
156
206
|
result = await import(
|
|
157
|
-
'file://' + require.resolve(path,
|
|
207
|
+
'file://' + require.resolve(path, RESOLVE_OPTIONS)
|
|
158
208
|
)
|
|
159
209
|
);
|
|
160
210
|
return result;
|
|
@@ -170,14 +220,17 @@ const AsyncFunction = custom_import.constructor;
|
|
|
170
220
|
|
|
171
221
|
const services_active = new Map;
|
|
172
222
|
const services_loading = new Set;
|
|
173
|
-
const services_list_react = async
|
|
223
|
+
const services_list_react = async list => {
|
|
174
224
|
await Promise.all(
|
|
175
225
|
Array.from(services_active.entries())
|
|
176
|
-
.filter(([path, _]) => !
|
|
226
|
+
.filter(([path, _]) => !list.includes(path))
|
|
177
227
|
.map(([_, service_object]) => service_stop(service_object, true))
|
|
178
228
|
);
|
|
179
|
-
for (const path of
|
|
180
|
-
if (
|
|
229
|
+
for (const path of list)
|
|
230
|
+
if (
|
|
231
|
+
path.charCodeAt(0) !== 35 &&
|
|
232
|
+
!services_active.has(path)
|
|
233
|
+
) {
|
|
181
234
|
await service_start(path);
|
|
182
235
|
}
|
|
183
236
|
}
|
|
@@ -272,7 +325,6 @@ const service_start_inner = async (path, service_object, file_content) => {
|
|
|
272
325
|
if (log_verbose) log('started service: ' + path);
|
|
273
326
|
}
|
|
274
327
|
const services_shutdown = () => (
|
|
275
|
-
log_verbose && log('shutdown services...'),
|
|
276
328
|
Promise.all(
|
|
277
329
|
Array.from(services_active.values())
|
|
278
330
|
.map(service_object => service_stop(service_object, true))
|
|
@@ -317,28 +369,6 @@ global.service_require_try = path => {
|
|
|
317
369
|
);
|
|
318
370
|
}
|
|
319
371
|
|
|
320
|
-
const map_generate_bol = (set, data) => {
|
|
321
|
-
set.clear();
|
|
322
|
-
for (const key of data.split('\n'))
|
|
323
|
-
if (
|
|
324
|
-
key.length > 0 &&
|
|
325
|
-
key.charCodeAt(0) !== 35
|
|
326
|
-
) {
|
|
327
|
-
set.add(key);
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
const map_generate_equ = (map, data) => {
|
|
331
|
-
map.clear();
|
|
332
|
-
for (const entry of data.split('\n'))
|
|
333
|
-
if (
|
|
334
|
-
entry.length > 0 &&
|
|
335
|
-
entry.charCodeAt(0) !== 35
|
|
336
|
-
) {
|
|
337
|
-
const equ = entry.split(':');
|
|
338
|
-
map.set(equ[0], equ[1] || '');
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
|
|
342
372
|
const file_watch_once = (path, callback) => {
|
|
343
373
|
const watcher = fs_watch(path, WATCH_OPTIONS, () => (
|
|
344
374
|
watcher.close(),
|
|
@@ -369,6 +399,75 @@ const file_keep_new = async (path, callback) => {
|
|
|
369
399
|
));
|
|
370
400
|
}
|
|
371
401
|
|
|
402
|
+
const get_prop_uint = (obj, prop, fallback) => {
|
|
403
|
+
if (
|
|
404
|
+
obj === null ||
|
|
405
|
+
!(prop in obj)
|
|
406
|
+
) return fallback;
|
|
407
|
+
const value = obj[prop];
|
|
408
|
+
if (
|
|
409
|
+
typeof value !== 'number' ||
|
|
410
|
+
value < 0 ||
|
|
411
|
+
value % 1 > 0
|
|
412
|
+
) {
|
|
413
|
+
throw prop + ' must be positive integer';
|
|
414
|
+
}
|
|
415
|
+
delete obj[prop];
|
|
416
|
+
return value;
|
|
417
|
+
}
|
|
418
|
+
const get_prop_list = (obj, prop) => {
|
|
419
|
+
if (
|
|
420
|
+
obj === null ||
|
|
421
|
+
!(prop in obj)
|
|
422
|
+
) return null;
|
|
423
|
+
const value = obj[prop];
|
|
424
|
+
if (
|
|
425
|
+
typeof value !== 'object' ||
|
|
426
|
+
value.length == null ||
|
|
427
|
+
value.some(item => typeof item !== 'string')
|
|
428
|
+
) {
|
|
429
|
+
throw prop + ' must be array of strings';
|
|
430
|
+
}
|
|
431
|
+
delete obj[prop];
|
|
432
|
+
return value;
|
|
433
|
+
}
|
|
434
|
+
const get_prop_map = (obj, prop) => {
|
|
435
|
+
if (
|
|
436
|
+
obj === null ||
|
|
437
|
+
!(prop in obj)
|
|
438
|
+
) return null;
|
|
439
|
+
let value = obj[prop];
|
|
440
|
+
if (
|
|
441
|
+
typeof value !== 'object' ||
|
|
442
|
+
(
|
|
443
|
+
value = Object.entries(value)
|
|
444
|
+
).some(([_, item]) => typeof item !== 'string')
|
|
445
|
+
) {
|
|
446
|
+
throw prop + ' must be object of strings';
|
|
447
|
+
}
|
|
448
|
+
delete obj[prop];
|
|
449
|
+
return value;
|
|
450
|
+
}
|
|
451
|
+
const parse_old_list = data => (
|
|
452
|
+
data
|
|
453
|
+
.split('\n')
|
|
454
|
+
.filter(entry =>
|
|
455
|
+
entry.length > 0 &&
|
|
456
|
+
entry.charCodeAt(0) !== 35
|
|
457
|
+
)
|
|
458
|
+
)
|
|
459
|
+
const parse_old_map = data => (
|
|
460
|
+
Object.fromEntries(
|
|
461
|
+
data
|
|
462
|
+
.split('\n')
|
|
463
|
+
.filter(entry =>
|
|
464
|
+
entry.length > 0 &&
|
|
465
|
+
entry.charCodeAt(0) !== 35
|
|
466
|
+
)
|
|
467
|
+
.map(entry => entry.split(':'))
|
|
468
|
+
)
|
|
469
|
+
)
|
|
470
|
+
|
|
372
471
|
let log_history = rtjscomp.log_history = [];
|
|
373
472
|
actions.log_clear = () => {
|
|
374
473
|
log_history = rtjscomp.log_history = [];
|
|
@@ -438,7 +537,7 @@ const request_handle = async (request, response, https) => {
|
|
|
438
537
|
if (
|
|
439
538
|
path.includes('php') ||
|
|
440
539
|
path.includes('sql') ||
|
|
441
|
-
|
|
540
|
+
path_ghosts.has(path)
|
|
442
541
|
) return;
|
|
443
542
|
|
|
444
543
|
response.setHeader('Server', 'l3p3 rtjscomp v' + VERSION);
|
|
@@ -496,13 +595,13 @@ const request_handle = async (request, response, https) => {
|
|
|
496
595
|
|
|
497
596
|
let file_gz_enabled = (
|
|
498
597
|
'accept-encoding' in request_headers &&
|
|
499
|
-
!
|
|
598
|
+
!type_raws.has(file_type) &&
|
|
500
599
|
request_headers['accept-encoding'].split(HTTP_LIST_REG).includes('gzip')
|
|
501
600
|
);
|
|
502
601
|
|
|
503
602
|
const file_dyn_enabled = (
|
|
504
|
-
|
|
505
|
-
!
|
|
603
|
+
type_dynamics.has(file_type) &&
|
|
604
|
+
!path_statics.has(path)
|
|
506
605
|
);
|
|
507
606
|
|
|
508
607
|
if (request_method !== 'GET') {
|
|
@@ -539,7 +638,7 @@ const request_handle = async (request, response, https) => {
|
|
|
539
638
|
}ic file: ${path_real}`);
|
|
540
639
|
|
|
541
640
|
if (
|
|
542
|
-
|
|
641
|
+
path_hiddens.has(path) ||
|
|
543
642
|
path.endsWith('.service.js')
|
|
544
643
|
) throw 403;
|
|
545
644
|
if (!fs.existsSync(path_real)) throw 404;
|
|
@@ -662,7 +761,7 @@ const request_handle = async (request, response, https) => {
|
|
|
662
761
|
response.statusCode = 200;
|
|
663
762
|
response.setHeader(
|
|
664
763
|
'Content-Type',
|
|
665
|
-
|
|
764
|
+
type_mimes.get(file_type) || type_mimes.get('txt')
|
|
666
765
|
);
|
|
667
766
|
|
|
668
767
|
if (file_dyn_enabled) { // dynamic file
|
|
@@ -848,7 +947,10 @@ const request_handle = async (request, response, https) => {
|
|
|
848
947
|
err = 500;
|
|
849
948
|
}
|
|
850
949
|
|
|
851
|
-
if (
|
|
950
|
+
if (
|
|
951
|
+
err >= 500 ||
|
|
952
|
+
log_verbose && err >= 400
|
|
953
|
+
) {
|
|
852
954
|
log(`[error] request failed: ${err}; ${request_ip}; ${request.url}`);
|
|
853
955
|
}
|
|
854
956
|
|
|
@@ -862,20 +964,21 @@ const request_handle = async (request, response, https) => {
|
|
|
862
964
|
|
|
863
965
|
let exiting = false;
|
|
864
966
|
actions.halt = async () => {
|
|
967
|
+
if (log_verbose) log('stop all');
|
|
865
968
|
await Promise.all([
|
|
866
969
|
actions.http_stop && actions.http_stop(),
|
|
867
970
|
actions.https_stop && actions.https_stop(),
|
|
868
971
|
services_shutdown(),
|
|
869
972
|
]);
|
|
870
973
|
await actions.spam_save();
|
|
871
|
-
log('stopped
|
|
974
|
+
log('stopped all');
|
|
872
975
|
}
|
|
873
976
|
actions.exit = async status => {
|
|
874
977
|
if (exiting) return;
|
|
875
978
|
exiting = true;
|
|
876
979
|
if (typeof status !== 'number') status = 0;
|
|
877
980
|
await actions.halt();
|
|
878
|
-
log('
|
|
981
|
+
if (log_verbose) log('exit');
|
|
879
982
|
process.exit(status);
|
|
880
983
|
}
|
|
881
984
|
|
|
@@ -898,25 +1001,43 @@ process.on('SIGINT', actions.exit);
|
|
|
898
1001
|
process.on('SIGUSR2', actions.exit);
|
|
899
1002
|
process.on('SIGTERM', actions.exit);
|
|
900
1003
|
|
|
901
|
-
log(`rtjscomp v${
|
|
1004
|
+
log(`rtjscomp v${
|
|
1005
|
+
VERSION
|
|
1006
|
+
} in ${
|
|
1007
|
+
IS_BUN ? 'bun' : 'node'
|
|
1008
|
+
} on ${
|
|
1009
|
+
process.platform
|
|
1010
|
+
}`);
|
|
1011
|
+
|
|
1012
|
+
await file_keep_new(PATH_CONFIG + 'init.js', async data => {
|
|
1013
|
+
if (!data) return;
|
|
1014
|
+
log('[deprecated] run global init script');
|
|
1015
|
+
try {
|
|
1016
|
+
await (
|
|
1017
|
+
new AsyncFunction('require', data)
|
|
1018
|
+
)(custom_require);
|
|
1019
|
+
}
|
|
1020
|
+
catch (err) {
|
|
1021
|
+
log('[error] init.js: ' + err.message);
|
|
1022
|
+
}
|
|
1023
|
+
});
|
|
902
1024
|
|
|
903
1025
|
// initial
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
}
|
|
1026
|
+
{
|
|
1027
|
+
const [
|
|
1028
|
+
stat_data,
|
|
1029
|
+
stat_public,
|
|
1030
|
+
...files_config
|
|
1031
|
+
] = await Promise.all([
|
|
1032
|
+
fsp.stat(PATH_DATA).catch(_ => null),
|
|
1033
|
+
fsp.stat(PATH_PUBLIC).catch(_ => null),
|
|
1034
|
+
...(
|
|
1035
|
+
'file_blocks,file_privates,file_raws,file_type_dyns,file_type_mimes,file_type_nocompress,path_aliases,port_http,port_https,services'
|
|
1036
|
+
.split(',')
|
|
1037
|
+
.map(name => fsp.readFile(PATH_CONFIG + name + '.txt', 'utf8').catch(_ => null))
|
|
1038
|
+
),
|
|
1039
|
+
]);
|
|
1040
|
+
|
|
920
1041
|
if (!stat_data) {
|
|
921
1042
|
fs.mkdirSync(PATH_DATA);
|
|
922
1043
|
}
|
|
@@ -927,79 +1048,74 @@ await Promise.all([
|
|
|
927
1048
|
{recursive: true}
|
|
928
1049
|
);
|
|
929
1050
|
}
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
)
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
1051
|
+
if (
|
|
1052
|
+
files_config.some(file => file !== null)
|
|
1053
|
+
) {
|
|
1054
|
+
const json = JSON.parse(
|
|
1055
|
+
await fsp.readFile('rtjscomp.json', 'utf8').catch(_ => null)
|
|
1056
|
+
) || {};
|
|
1057
|
+
|
|
1058
|
+
const [
|
|
1059
|
+
old_file_blocks,
|
|
1060
|
+
old_file_privates,
|
|
1061
|
+
old_file_raws,
|
|
1062
|
+
old_file_type_dyns,
|
|
1063
|
+
old_file_type_mimes,
|
|
1064
|
+
old_file_type_nocompress,
|
|
1065
|
+
old_path_aliases,
|
|
1066
|
+
old_port_http,
|
|
1067
|
+
old_port_https,
|
|
1068
|
+
old_services,
|
|
1069
|
+
] = files_config;
|
|
1070
|
+
|
|
1071
|
+
if (old_file_blocks) {
|
|
1072
|
+
json['path_ghosts'] = parse_old_list(old_file_blocks);
|
|
945
1073
|
}
|
|
946
|
-
|
|
947
|
-
|
|
1074
|
+
if (old_file_privates) {
|
|
1075
|
+
json['path_hiddens'] = parse_old_list(old_file_privates);
|
|
948
1076
|
}
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
map_generate_equ(file_type_mimes, data);
|
|
952
|
-
if (!file_type_mimes.has('txt')) {
|
|
953
|
-
file_type_mimes.set('txt', 'text/plain; charset=utf-8');
|
|
1077
|
+
if (old_file_raws) {
|
|
1078
|
+
json['path_statics'] = parse_old_list(old_file_raws);
|
|
954
1079
|
}
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
path_aliases_templates.set(first, [
|
|
972
|
-
{path_split, value},
|
|
973
|
-
]);
|
|
974
|
-
}
|
|
1080
|
+
if (old_file_type_dyns) {
|
|
1081
|
+
json['type_dynamics'] = parse_old_list(old_file_type_dyns);
|
|
1082
|
+
}
|
|
1083
|
+
if (old_file_type_mimes) {
|
|
1084
|
+
json['type_mimes'] = parse_old_map(old_file_type_mimes);
|
|
1085
|
+
}
|
|
1086
|
+
if (old_file_type_nocompress) {
|
|
1087
|
+
json['type_raws'] = parse_old_list(old_file_type_nocompress);
|
|
1088
|
+
}
|
|
1089
|
+
if (old_path_aliases) {
|
|
1090
|
+
json['path_aliases'] = parse_old_map(old_path_aliases);
|
|
1091
|
+
}
|
|
1092
|
+
if (old_port_http) {
|
|
1093
|
+
const number = parseInt(old_port_http);
|
|
1094
|
+
if (!isNaN(number)) {
|
|
1095
|
+
json['port_http'] = number;
|
|
975
1096
|
}
|
|
976
|
-
|
|
977
|
-
|
|
1097
|
+
}
|
|
1098
|
+
if (old_port_https) {
|
|
1099
|
+
const number = parseInt(old_port_https);
|
|
1100
|
+
if (!isNaN(number)) {
|
|
1101
|
+
json['port_https'] = number;
|
|
978
1102
|
}
|
|
979
1103
|
}
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
}),
|
|
984
|
-
file_keep_new(PATH_CONFIG + 'file_type_nocompress.txt', data => {
|
|
985
|
-
map_generate_bol(file_type_nocompress, data);
|
|
986
|
-
}),
|
|
987
|
-
file_keep_new(PATH_CONFIG + 'file_raws.txt', data => {
|
|
988
|
-
if (!data) return;
|
|
989
|
-
map_generate_bol(file_raws, data);
|
|
990
|
-
}),
|
|
991
|
-
file_keep_new(PATH_CONFIG + 'file_privates.txt', data => {
|
|
992
|
-
if (!data) return;
|
|
993
|
-
map_generate_bol(file_privates, data);
|
|
994
|
-
}),
|
|
995
|
-
file_keep_new(PATH_CONFIG + 'file_blocks.txt', data => {
|
|
996
|
-
if (!data) return;
|
|
997
|
-
map_generate_bol(file_blocks, data);
|
|
998
|
-
}),
|
|
999
|
-
]);
|
|
1104
|
+
if (old_services) {
|
|
1105
|
+
json['services'] = old_services.split('\n').filter(path => path.length > 0);
|
|
1106
|
+
}
|
|
1000
1107
|
|
|
1108
|
+
await fsp.writeFile(
|
|
1109
|
+
'rtjscomp.json',
|
|
1110
|
+
JSON.stringify(json, null, 2),
|
|
1111
|
+
'utf8'
|
|
1112
|
+
);
|
|
1113
|
+
log('[deprecated] config files found, rtjscomp.json written, please delete config files');
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
// http(s)
|
|
1001
1118
|
let connections_count = 0;
|
|
1002
|
-
let http_status = false;
|
|
1003
1119
|
let http_status_target = false;
|
|
1004
1120
|
let http_listened_resolve = null;
|
|
1005
1121
|
const http_connections = new Map;
|
|
@@ -1020,14 +1136,12 @@ server_http.on('connection', connection => {
|
|
|
1020
1136
|
|
|
1021
1137
|
actions.http_start = async () => {
|
|
1022
1138
|
await actions.http_stop();
|
|
1139
|
+
if (!port_http) return;
|
|
1023
1140
|
http_status_target = true;
|
|
1024
1141
|
log('start http: http://localhost:' + port_http);
|
|
1025
1142
|
await new Promise(resolve => server_http.listen(port_http, http_listened_resolve = resolve));
|
|
1026
1143
|
if (http_listened_resolve) http_listened_resolve = null;
|
|
1027
|
-
else
|
|
1028
|
-
http_status = true;
|
|
1029
|
-
if (log_verbose) log('started http');
|
|
1030
|
-
}
|
|
1144
|
+
else if (log_verbose) log('started http');
|
|
1031
1145
|
}
|
|
1032
1146
|
actions.http_stop = async () => {
|
|
1033
1147
|
if (!http_status_target) return;
|
|
@@ -1036,7 +1150,6 @@ actions.http_stop = async () => {
|
|
|
1036
1150
|
const kill_timeout = setTimeout(actions.http_kill, 5e3);
|
|
1037
1151
|
await new Promise(resolve => server_http.close(resolve));
|
|
1038
1152
|
clearTimeout(kill_timeout);
|
|
1039
|
-
http_status = false;
|
|
1040
1153
|
if (log_verbose) log('stopped http');
|
|
1041
1154
|
}
|
|
1042
1155
|
actions.http_kill = async () => {
|
|
@@ -1050,24 +1163,9 @@ actions.http_kill = async () => {
|
|
|
1050
1163
|
http_connections.clear();
|
|
1051
1164
|
}
|
|
1052
1165
|
|
|
1053
|
-
file_keep_new(PATH_CONFIG + 'port_http.txt', data => {
|
|
1054
|
-
if (
|
|
1055
|
-
!data ||
|
|
1056
|
-
isNaN(data = Number(data)) ||
|
|
1057
|
-
!number_check_uint(data)
|
|
1058
|
-
) {
|
|
1059
|
-
log('[error] http: invalid port number');
|
|
1060
|
-
}
|
|
1061
|
-
else if (data !== port_http) {
|
|
1062
|
-
port_http = data;
|
|
1063
|
-
actions.http_start();
|
|
1064
|
-
}
|
|
1065
|
-
});
|
|
1066
|
-
|
|
1067
1166
|
try {
|
|
1068
1167
|
const https_key = fs.readFileSync(PATH_CONFIG + 'ssl/domain.key');
|
|
1069
1168
|
const https_cert = fs.readFileSync(PATH_CONFIG + 'ssl/chained.pem');
|
|
1070
|
-
let https_status = false;
|
|
1071
1169
|
let https_status_target = false;
|
|
1072
1170
|
let https_listened_resolve = null;
|
|
1073
1171
|
const https_connections = new Map;
|
|
@@ -1089,14 +1187,12 @@ try {
|
|
|
1089
1187
|
|
|
1090
1188
|
actions.https_start = async () => {
|
|
1091
1189
|
await actions.https_stop();
|
|
1190
|
+
if (!port_https) return;
|
|
1092
1191
|
https_status_target = true;
|
|
1093
1192
|
log('start https: https://localhost:' + port_https);
|
|
1094
1193
|
await new Promise(resolve => server_https.listen(port_https, https_listened_resolve = resolve));
|
|
1095
1194
|
if (https_listened_resolve) https_listened_resolve = null;
|
|
1096
|
-
else
|
|
1097
|
-
https_status = true;
|
|
1098
|
-
if (log_verbose) log('started https');
|
|
1099
|
-
}
|
|
1195
|
+
else if (log_verbose) log('started https');
|
|
1100
1196
|
}
|
|
1101
1197
|
actions.https_stop = async () => {
|
|
1102
1198
|
if (!https_status_target) return;
|
|
@@ -1105,7 +1201,6 @@ try {
|
|
|
1105
1201
|
const kill_timeout = setTimeout(actions.https_kill, 5000);
|
|
1106
1202
|
await new Promise(resolve => server_https.close(resolve));
|
|
1107
1203
|
clearTimeout(kill_timeout);
|
|
1108
|
-
https_status = false;
|
|
1109
1204
|
if (log_verbose) log('stopped https');
|
|
1110
1205
|
}
|
|
1111
1206
|
actions.https_kill = async () => {
|
|
@@ -1117,23 +1212,130 @@ try {
|
|
|
1117
1212
|
if (log_verbose) log('killed https');
|
|
1118
1213
|
https_connections.clear();
|
|
1119
1214
|
}
|
|
1120
|
-
|
|
1121
|
-
file_keep_new(PATH_CONFIG + 'port_https.txt', data => {
|
|
1122
|
-
if (
|
|
1123
|
-
!data ||
|
|
1124
|
-
isNaN(data = Number(data)) ||
|
|
1125
|
-
!number_check_uint(data)
|
|
1126
|
-
) {
|
|
1127
|
-
log('[error] https: invalid port number');
|
|
1128
|
-
}
|
|
1129
|
-
else if (data !== port_https) {
|
|
1130
|
-
port_https = data;
|
|
1131
|
-
actions.https_start();
|
|
1132
|
-
}
|
|
1133
|
-
});
|
|
1134
1215
|
}
|
|
1135
1216
|
catch (err) {
|
|
1136
1217
|
if (log_verbose) log('https: no cert, disabled');
|
|
1137
1218
|
}
|
|
1138
1219
|
|
|
1220
|
+
// config
|
|
1221
|
+
await file_keep_new('rtjscomp.json', data => {
|
|
1222
|
+
try {
|
|
1223
|
+
data = JSON.parse(data);
|
|
1224
|
+
if (typeof data !== 'object') {
|
|
1225
|
+
throw 'must contain {}';
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
const path_aliases_new = get_prop_map(data, 'path_aliases');
|
|
1229
|
+
const path_ghosts_new = get_prop_list(data, 'path_ghosts');
|
|
1230
|
+
const path_hiddens_new = get_prop_list(data, 'path_hiddens');
|
|
1231
|
+
const path_statics_new = get_prop_list(data, 'path_statics');
|
|
1232
|
+
const port_http_new = get_prop_uint(data, 'port_http', 8080);
|
|
1233
|
+
const port_https_new = get_prop_uint(data, 'port_https', 0);
|
|
1234
|
+
const services_new = get_prop_list(data, 'services') || [];
|
|
1235
|
+
const type_dynamics_new = get_prop_list(data, 'type_dynamics');
|
|
1236
|
+
const type_mimes_new = get_prop_map(data, 'type_mimes');
|
|
1237
|
+
const type_raws_new = get_prop_list(data, 'type_raws');
|
|
1238
|
+
|
|
1239
|
+
if (data) {
|
|
1240
|
+
const keys_left = Object.keys(data);
|
|
1241
|
+
if (keys_left.length > 0) {
|
|
1242
|
+
throw 'unknown: ' + keys_left.join(', ');
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
if (path_ghosts_new) {
|
|
1247
|
+
path_ghosts.clear();
|
|
1248
|
+
for (const key of path_ghosts_new) {
|
|
1249
|
+
path_ghosts.add(key);
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
if (path_hiddens_new) {
|
|
1253
|
+
path_hiddens.clear();
|
|
1254
|
+
for (const key of path_hiddens_new) {
|
|
1255
|
+
path_hiddens.add(key);
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
if (path_statics_new) {
|
|
1259
|
+
path_statics.clear();
|
|
1260
|
+
for (const key of path_statics_new) {
|
|
1261
|
+
path_statics.add(key);
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
if (path_aliases_new) {
|
|
1265
|
+
path_aliases.clear();
|
|
1266
|
+
path_aliases_reverse.clear();
|
|
1267
|
+
path_aliases_templates.clear();
|
|
1268
|
+
for (const [key, value] of path_aliases_new) {
|
|
1269
|
+
if (key.includes('*')) {
|
|
1270
|
+
const path_split = key.split('/');
|
|
1271
|
+
const first = path_split.shift();
|
|
1272
|
+
if (path_aliases_templates.has(first)) {
|
|
1273
|
+
path_aliases_templates.get(first).push(
|
|
1274
|
+
{path_split, value}
|
|
1275
|
+
);
|
|
1276
|
+
}
|
|
1277
|
+
else {
|
|
1278
|
+
path_aliases_templates.set(first, [
|
|
1279
|
+
{path_split, value},
|
|
1280
|
+
]);
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
else {
|
|
1284
|
+
path_aliases.set(key, value);
|
|
1285
|
+
path_aliases_reverse.set(value, '/' + key);
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
if (type_dynamics_new) {
|
|
1290
|
+
type_dynamics.clear();
|
|
1291
|
+
for (const key of type_dynamics_new) {
|
|
1292
|
+
type_dynamics.add(key);
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
if (type_mimes_new) {
|
|
1296
|
+
for (const [key, value] of type_mimes_new) {
|
|
1297
|
+
type_mimes.set(key, value);
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
if (type_raws_new) {
|
|
1301
|
+
type_raws.clear();
|
|
1302
|
+
for (const key of type_raws_new) {
|
|
1303
|
+
type_raws.add(key);
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
const promises = [
|
|
1308
|
+
services_list_react(services_new),
|
|
1309
|
+
];
|
|
1310
|
+
|
|
1311
|
+
if (port_http_new !== port_http) {
|
|
1312
|
+
port_http = port_http_new;
|
|
1313
|
+
promises.push(
|
|
1314
|
+
port_http_new > 0
|
|
1315
|
+
? actions.http_start()
|
|
1316
|
+
: actions.http_stop()
|
|
1317
|
+
);
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
if (
|
|
1321
|
+
actions.https_stop != null &&
|
|
1322
|
+
port_https_new !== port_https
|
|
1323
|
+
) {
|
|
1324
|
+
port_https = port_https_new;
|
|
1325
|
+
promises.push(
|
|
1326
|
+
port_https_new > 0
|
|
1327
|
+
? actions.https_start()
|
|
1328
|
+
: actions.https_stop()
|
|
1329
|
+
);
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
return Promise.all(promises);
|
|
1333
|
+
}
|
|
1334
|
+
catch (err) {
|
|
1335
|
+
log('[error] rtjscomp.json: ' + (err.message || err));
|
|
1336
|
+
}
|
|
1337
|
+
});
|
|
1338
|
+
|
|
1339
|
+
if (log_verbose) log('started all');
|
|
1340
|
+
|
|
1139
1341
|
})();
|
package/changes_before_git.txt
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
add compression of dynamic data
|
|
2
|
-
add https
|
|
3
|
-
add actions
|
|
4
|
-
0.5
|
|
5
|
-
add shutdown action
|
|
6
|
-
prefer gzip over lzma
|
|
7
|
-
move public files into separate dir
|
|
8
|
-
0.51
|
|
9
|
-
add list of raw files
|
|
10
|
-
0.52
|
|
11
|
-
ignore empty areas (<??> or ?><?)
|
|
12
|
-
0.53
|
|
13
|
-
move configuration data to separate files
|
|
14
|
-
0.54
|
|
15
|
-
add path aliases
|
|
16
|
-
block accessing directories
|
|
17
|
-
0.55
|
|
18
|
-
add http-header Content-Location
|
|
19
|
-
0.56
|
|
20
|
-
add list of file types not to compress
|
|
21
|
-
keep raw files in ram
|
|
22
|
-
remove lzma
|
|
23
|
-
add compression of raw files
|
|
24
|
-
load already compressed files
|
|
25
|
-
just compress when at least 100 bytes of data
|
|
26
|
-
0.57
|
|
27
|
-
cleanup code
|
|
28
|
-
execute and send file in parallel
|
|
29
|
-
add services
|
|
30
|
-
0.58
|
|
31
|
-
add analytic logger
|
|
32
|
-
use compressed file even if file type is not intended as being compressed
|
|
33
|
-
0.59
|
|
34
|
-
remove static files from cache when precompressed files got changed
|
|
35
|
-
0.591
|
|
36
|
-
set gzip level to 9
|
|
37
|
-
save automatically compressed files
|
|
38
|
-
0.592
|
|
39
|
-
block requests with invalid hostname
|
|
40
|
-
0.593
|
|
41
|
-
add user data storage
|
|
42
|
-
0.594
|
|
43
|
-
remove custom file init
|
|
44
|
-
asynchronize request handling
|
|
45
|
-
temporarily disable chaching of static files
|
|
46
|
-
0.595
|
|
47
|
-
send partial files
|
|
48
|
-
load and interpret file in parallel
|
|
49
|
-
optimize source codes of sent files
|
|
50
|
-
0.596
|
|
51
|
-
stop services before replacing them
|
|
52
|
-
service_require return service object
|
|
53
|
-
0.597
|
|
54
|
-
stop services on exit
|
|
55
|
-
0.598
|
|
56
|
-
read request body
|
|
57
|
-
0.599
|
|
58
|
-
???
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
html:text/html; charset=utf-8
|
|
2
|
-
txt:text/plain; charset=utf-8
|
|
3
|
-
xml:application/xml; charset=utf-8
|
|
4
|
-
rss:application/rss+xml; charset=utf-8
|
|
5
|
-
js:text/javascript; charset=utf-8
|
|
6
|
-
json:application/json; charset=utf-8
|
|
7
|
-
hta:application/hta
|
|
8
|
-
css:text/css; charset=utf-8
|
|
9
|
-
ico:image/x-icon
|
|
10
|
-
jpg:image/jpeg
|
|
11
|
-
png:image/png
|
|
12
|
-
bpg:image/bpg
|
|
13
|
-
zip:application/zip
|
|
14
|
-
apk:application/zip
|
|
15
|
-
gz:application/gzip
|
|
16
|
-
xz:application/x-xz
|
|
17
|
-
mp3:audio/mpeg3
|
|
18
|
-
mid:audio/midi
|
|
19
|
-
flac:audio/flac
|
|
20
|
-
pdf:application/pdf
|
|
21
|
-
events:text/event-stream
|
package/config/path_aliases.txt
DELETED
package/config/port_http.txt
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
8080
|
package/config/port_https.txt
DELETED
|
File without changes
|
package/config/services.txt
DELETED