@velox0/cerver 0.4.0 → 0.4.2
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/.github/workflows/ci.yml +35 -0
- package/.github/workflows/publish.yml +6 -4
- package/Makefile +26 -0
- package/bin/cerver.js +11 -0
- package/lib/commands/dev.js +23 -9
- package/lib/commands/new.js +273 -79
- package/lib/ir/transform.js +14 -20
- package/package.json +2 -2
- package/runtime/cerver.h +139 -129
- package/runtime/http_parser.c +153 -152
- package/runtime/http_writer.c +136 -126
- package/runtime/mime.c +49 -49
- package/runtime/router.c +99 -98
- package/runtime/server.c +594 -436
- package/runtime/static.c +174 -183
- package/runtime/tests/minunit.c +76 -0
- package/runtime/tests/minunit.h +64 -0
- package/runtime/tests/runtime_tests.c +414 -0
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
#include "cerver.h"
|
|
2
|
+
#include "minunit.h"
|
|
3
|
+
|
|
4
|
+
#include <errno.h>
|
|
5
|
+
#include <fcntl.h>
|
|
6
|
+
#include <limits.h>
|
|
7
|
+
#include <stddef.h>
|
|
8
|
+
#include <stdio.h>
|
|
9
|
+
#include <stdlib.h>
|
|
10
|
+
#include <string.h>
|
|
11
|
+
#include <sys/mman.h>
|
|
12
|
+
#include <sys/stat.h>
|
|
13
|
+
#include <time.h>
|
|
14
|
+
#include <unistd.h>
|
|
15
|
+
|
|
16
|
+
static const char* res_header(const cerver_response_t* res, const char* key) {
|
|
17
|
+
for (int i = 0; i < res->header_count; i++) {
|
|
18
|
+
if (strcmp(res->headers[i].key, key) == 0) {
|
|
19
|
+
return res->headers[i].value;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return NULL;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static void req_add_header(cerver_request_t* req, const char* key, const char* value) {
|
|
26
|
+
req->headers[req->header_count].key = key;
|
|
27
|
+
req->headers[req->header_count].value = value;
|
|
28
|
+
req->header_count++;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
static int write_file(const char* path, const void* data, size_t len) {
|
|
32
|
+
int fd = open(path, O_CREAT | O_WRONLY | O_TRUNC, 0600);
|
|
33
|
+
if (fd < 0) {
|
|
34
|
+
return -1;
|
|
35
|
+
}
|
|
36
|
+
const unsigned char* p = (const unsigned char*)data;
|
|
37
|
+
size_t off = 0;
|
|
38
|
+
while (off < len) {
|
|
39
|
+
ssize_t n = write(fd, p + off, len - off);
|
|
40
|
+
if (n <= 0) {
|
|
41
|
+
close(fd);
|
|
42
|
+
return -1;
|
|
43
|
+
}
|
|
44
|
+
off += (size_t)n;
|
|
45
|
+
}
|
|
46
|
+
close(fd);
|
|
47
|
+
return 0;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
static ssize_t read_all(int fd, char* buf, size_t cap) {
|
|
51
|
+
size_t off = 0;
|
|
52
|
+
while (off + 1 < cap) {
|
|
53
|
+
ssize_t n = read(fd, buf + off, cap - off - 1);
|
|
54
|
+
if (n < 0) {
|
|
55
|
+
return -1;
|
|
56
|
+
}
|
|
57
|
+
if (n == 0) {
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
off += (size_t)n;
|
|
61
|
+
}
|
|
62
|
+
buf[off] = '\0';
|
|
63
|
+
return (ssize_t)off;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
static void test_parse_request_basic(void) {
|
|
67
|
+
const char* raw =
|
|
68
|
+
"POST /files/hello%20world?foo=bar&name=Bob+Smith HTTP/1.1\r\n"
|
|
69
|
+
"Host: example.com\r\n"
|
|
70
|
+
"Content-Length: 5\r\n"
|
|
71
|
+
"Connection: keep-alive\r\n"
|
|
72
|
+
"\r\n"
|
|
73
|
+
"hello";
|
|
74
|
+
const size_t len = strlen(raw);
|
|
75
|
+
char* buf = (char*)malloc(len + 1);
|
|
76
|
+
MU_ASSERT(buf != NULL);
|
|
77
|
+
memcpy(buf, raw, len);
|
|
78
|
+
|
|
79
|
+
cerver_request_t req;
|
|
80
|
+
memset(&req, 0, sizeof(req));
|
|
81
|
+
|
|
82
|
+
MU_ASSERT_EQ_INT(0, cerver_parse_request(buf, len, &req));
|
|
83
|
+
MU_ASSERT_STREQ("POST", req.method);
|
|
84
|
+
MU_ASSERT_STREQ("/files/hello world", req.path);
|
|
85
|
+
MU_ASSERT_EQ_INT(2, req.query_count);
|
|
86
|
+
MU_ASSERT_STREQ("foo", req.query[0].key);
|
|
87
|
+
MU_ASSERT_STREQ("bar", req.query[0].value);
|
|
88
|
+
MU_ASSERT_STREQ("name", req.query[1].key);
|
|
89
|
+
MU_ASSERT_STREQ("Bob Smith", req.query[1].value);
|
|
90
|
+
MU_ASSERT_STREQ("example.com", cerver_req_header(&req, "host"));
|
|
91
|
+
MU_ASSERT_EQ_SIZE(5, req.body_len);
|
|
92
|
+
MU_ASSERT(memcmp(req.body, "hello", 5) == 0);
|
|
93
|
+
|
|
94
|
+
free(buf);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
static void test_parse_request_trailing_slash(void) {
|
|
98
|
+
const char* raw = "GET /about/ HTTP/1.1\r\n\r\n";
|
|
99
|
+
const size_t len = strlen(raw);
|
|
100
|
+
char* buf = (char*)malloc(len + 1);
|
|
101
|
+
MU_ASSERT(buf != NULL);
|
|
102
|
+
memcpy(buf, raw, len);
|
|
103
|
+
|
|
104
|
+
cerver_request_t req;
|
|
105
|
+
memset(&req, 0, sizeof(req));
|
|
106
|
+
|
|
107
|
+
MU_ASSERT_EQ_INT(0, cerver_parse_request(buf, len, &req));
|
|
108
|
+
MU_ASSERT_STREQ("GET", req.method);
|
|
109
|
+
MU_ASSERT_STREQ("/about", req.path);
|
|
110
|
+
MU_ASSERT_EQ_INT(0, req.query_count);
|
|
111
|
+
|
|
112
|
+
free(buf);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
static void test_write_response_keepalive(void) {
|
|
116
|
+
int fds[2];
|
|
117
|
+
MU_ASSERT(pipe(fds) == 0);
|
|
118
|
+
|
|
119
|
+
cerver_response_t res;
|
|
120
|
+
memset(&res, 0, sizeof(res));
|
|
121
|
+
cerver_res_text(&res, 200, "ok");
|
|
122
|
+
cerver_res_header(&res, "X-Test", "1");
|
|
123
|
+
|
|
124
|
+
MU_ASSERT_EQ_INT(0, cerver_write_response(fds[1], &res, 1));
|
|
125
|
+
close(fds[1]);
|
|
126
|
+
|
|
127
|
+
char out[1024];
|
|
128
|
+
MU_ASSERT(read_all(fds[0], out, sizeof(out)) > 0);
|
|
129
|
+
close(fds[0]);
|
|
130
|
+
|
|
131
|
+
MU_ASSERT(strstr(out, "HTTP/1.1 200 OK\r\n") != NULL);
|
|
132
|
+
MU_ASSERT(strstr(out, "Content-Type: text/plain; charset=utf-8\r\n") != NULL);
|
|
133
|
+
MU_ASSERT(strstr(out, "Content-Length: 2\r\n") != NULL);
|
|
134
|
+
MU_ASSERT(strstr(out, "X-Test: 1\r\n") != NULL);
|
|
135
|
+
MU_ASSERT(strstr(out, "Connection: keep-alive\r\n") != NULL);
|
|
136
|
+
MU_ASSERT(strstr(out, "Server: cerver\r\n") != NULL);
|
|
137
|
+
MU_ASSERT(strstr(out, "\r\nok") != NULL);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
static void test_write_response_force_close(void) {
|
|
141
|
+
int fds[2];
|
|
142
|
+
MU_ASSERT(pipe(fds) == 0);
|
|
143
|
+
|
|
144
|
+
cerver_response_t res;
|
|
145
|
+
memset(&res, 0, sizeof(res));
|
|
146
|
+
cerver_res_text(&res, 200, "ok");
|
|
147
|
+
res._force_close = 1;
|
|
148
|
+
|
|
149
|
+
MU_ASSERT_EQ_INT(0, cerver_write_response(fds[1], &res, 1));
|
|
150
|
+
close(fds[1]);
|
|
151
|
+
|
|
152
|
+
char out[512];
|
|
153
|
+
MU_ASSERT(read_all(fds[0], out, sizeof(out)) > 0);
|
|
154
|
+
close(fds[0]);
|
|
155
|
+
|
|
156
|
+
MU_ASSERT(strstr(out, "Connection: close\r\n") != NULL);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
static void handler_a(cerver_request_t* req, cerver_response_t* res) {
|
|
160
|
+
(void)req;
|
|
161
|
+
(void)res;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
static void handler_b(cerver_request_t* req, cerver_response_t* res) {
|
|
165
|
+
(void)req;
|
|
166
|
+
(void)res;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
static cerver_handler_fn dispatch_override(cerver_request_t* req) {
|
|
170
|
+
if (strcmp(req->path, "/override") == 0) {
|
|
171
|
+
return handler_a;
|
|
172
|
+
}
|
|
173
|
+
return NULL;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
static void test_route_match_and_dispatch(void) {
|
|
177
|
+
cerver_server_t srv;
|
|
178
|
+
cerver_init(&srv, 8080, 1);
|
|
179
|
+
|
|
180
|
+
cerver_route_t routes[2];
|
|
181
|
+
routes[0].method = "GET";
|
|
182
|
+
routes[0].pattern = "/users/:id";
|
|
183
|
+
routes[0].handler = handler_b;
|
|
184
|
+
routes[1].method = "GET";
|
|
185
|
+
routes[1].pattern = "/about";
|
|
186
|
+
routes[1].handler = handler_a;
|
|
187
|
+
cerver_add_routes(&srv, routes, 2);
|
|
188
|
+
cerver_set_dispatch(&srv, dispatch_override);
|
|
189
|
+
|
|
190
|
+
cerver_request_t req;
|
|
191
|
+
memset(&req, 0, sizeof(req));
|
|
192
|
+
strcpy(req.method, "GET");
|
|
193
|
+
strcpy(req.path, "/users/123");
|
|
194
|
+
|
|
195
|
+
MU_ASSERT(cerver_route_match(&routes[0], &req) == 1);
|
|
196
|
+
MU_ASSERT_EQ_INT(1, req.params_count);
|
|
197
|
+
MU_ASSERT_STREQ("123", cerver_req_param(&req, "id"));
|
|
198
|
+
|
|
199
|
+
memset(&req, 0, sizeof(req));
|
|
200
|
+
strcpy(req.method, "GET");
|
|
201
|
+
strcpy(req.path, "/override");
|
|
202
|
+
|
|
203
|
+
MU_ASSERT(cerver_dispatch(&srv, &req) == handler_a);
|
|
204
|
+
|
|
205
|
+
memset(&req, 0, sizeof(req));
|
|
206
|
+
strcpy(req.method, "GET");
|
|
207
|
+
strcpy(req.path, "/about");
|
|
208
|
+
|
|
209
|
+
MU_ASSERT(cerver_dispatch(&srv, &req) == handler_a);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
static void test_route_match_mismatch_resets_params(void) {
|
|
213
|
+
cerver_route_t route;
|
|
214
|
+
route.method = "GET";
|
|
215
|
+
route.pattern = "/users/:id/profile";
|
|
216
|
+
route.handler = handler_a;
|
|
217
|
+
|
|
218
|
+
cerver_request_t req;
|
|
219
|
+
memset(&req, 0, sizeof(req));
|
|
220
|
+
strcpy(req.method, "GET");
|
|
221
|
+
strcpy(req.path, "/users/123/settings");
|
|
222
|
+
|
|
223
|
+
MU_ASSERT(cerver_route_match(&route, &req) == 0);
|
|
224
|
+
MU_ASSERT_EQ_INT(0, req.params_count);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
static void test_request_header_helpers(void) {
|
|
228
|
+
cerver_request_t req;
|
|
229
|
+
memset(&req, 0, sizeof(req));
|
|
230
|
+
req_add_header(&req, "Connection", "close");
|
|
231
|
+
req_add_header(&req, "X-Test", "value");
|
|
232
|
+
|
|
233
|
+
MU_ASSERT_STREQ("value", cerver_req_header(&req, "x-test"));
|
|
234
|
+
MU_ASSERT_EQ_INT(1, cerver_req_wants_close(&req));
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
static void test_static_embedded_prefers_br(void) {
|
|
238
|
+
cerver_server_t srv;
|
|
239
|
+
cerver_init(&srv, 8080, 1);
|
|
240
|
+
|
|
241
|
+
static const unsigned char data[] = "hello";
|
|
242
|
+
static const unsigned char data_br[] = "brdata";
|
|
243
|
+
static const unsigned char data_gz[] = "gzdata";
|
|
244
|
+
|
|
245
|
+
cerver_asset_t assets[1];
|
|
246
|
+
assets[0].path = "/index.html";
|
|
247
|
+
assets[0].mime_type = "text/html";
|
|
248
|
+
assets[0].data = data;
|
|
249
|
+
assets[0].data_len = sizeof(data) - 1;
|
|
250
|
+
assets[0].data_br = data_br;
|
|
251
|
+
assets[0].data_br_len = sizeof(data_br) - 1;
|
|
252
|
+
assets[0].data_gz = data_gz;
|
|
253
|
+
assets[0].data_gz_len = sizeof(data_gz) - 1;
|
|
254
|
+
cerver_set_assets(&srv, assets, 1);
|
|
255
|
+
|
|
256
|
+
cerver_request_t req;
|
|
257
|
+
cerver_response_t res;
|
|
258
|
+
memset(&req, 0, sizeof(req));
|
|
259
|
+
memset(&res, 0, sizeof(res));
|
|
260
|
+
strcpy(req.method, "GET");
|
|
261
|
+
strcpy(req.path, "/index.html");
|
|
262
|
+
req_add_header(&req, "Accept-Encoding", "br, gzip");
|
|
263
|
+
|
|
264
|
+
MU_ASSERT_EQ_INT(0, cerver_serve_static(&srv, &req, &res));
|
|
265
|
+
MU_ASSERT(res.body == (const char*)data_br);
|
|
266
|
+
MU_ASSERT_STREQ("br", res_header(&res, "Content-Encoding"));
|
|
267
|
+
MU_ASSERT_STREQ("Accept-Encoding", res_header(&res, "Vary"));
|
|
268
|
+
MU_ASSERT(res_header(&res, "Cache-Control") != NULL);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
static void test_static_embedded_index_fallback(void) {
|
|
272
|
+
cerver_server_t srv;
|
|
273
|
+
cerver_init(&srv, 8080, 1);
|
|
274
|
+
|
|
275
|
+
static const unsigned char data[] = "docs";
|
|
276
|
+
cerver_asset_t assets[1];
|
|
277
|
+
assets[0].path = "/docs/index.html";
|
|
278
|
+
assets[0].mime_type = "text/html";
|
|
279
|
+
assets[0].data = data;
|
|
280
|
+
assets[0].data_len = sizeof(data) - 1;
|
|
281
|
+
assets[0].data_br = NULL;
|
|
282
|
+
assets[0].data_br_len = 0;
|
|
283
|
+
assets[0].data_gz = NULL;
|
|
284
|
+
assets[0].data_gz_len = 0;
|
|
285
|
+
cerver_set_assets(&srv, assets, 1);
|
|
286
|
+
|
|
287
|
+
cerver_request_t req;
|
|
288
|
+
cerver_response_t res;
|
|
289
|
+
memset(&req, 0, sizeof(req));
|
|
290
|
+
memset(&res, 0, sizeof(res));
|
|
291
|
+
strcpy(req.method, "GET");
|
|
292
|
+
strcpy(req.path, "/docs/");
|
|
293
|
+
|
|
294
|
+
MU_ASSERT_EQ_INT(0, cerver_serve_static(&srv, &req, &res));
|
|
295
|
+
MU_ASSERT(res.body == (const char*)data);
|
|
296
|
+
MU_ASSERT_STREQ("text/html", res.content_type);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
static void test_static_filesystem_small(void) {
|
|
300
|
+
char dir_template[] = "/tmp/cerver-test-XXXXXX";
|
|
301
|
+
char* dir = mkdtemp(dir_template);
|
|
302
|
+
MU_ASSERT(dir != NULL);
|
|
303
|
+
|
|
304
|
+
char file_path[PATH_MAX];
|
|
305
|
+
snprintf(file_path, sizeof(file_path), "%s/index.html", dir);
|
|
306
|
+
MU_ASSERT_EQ_INT(0, write_file(file_path, "small", 5));
|
|
307
|
+
|
|
308
|
+
cerver_server_t srv;
|
|
309
|
+
cerver_init(&srv, 8080, 1);
|
|
310
|
+
cerver_set_public_dir(&srv, dir);
|
|
311
|
+
|
|
312
|
+
cerver_request_t req;
|
|
313
|
+
cerver_response_t res;
|
|
314
|
+
memset(&req, 0, sizeof(req));
|
|
315
|
+
memset(&res, 0, sizeof(res));
|
|
316
|
+
strcpy(req.method, "GET");
|
|
317
|
+
strcpy(req.path, "/index.html");
|
|
318
|
+
|
|
319
|
+
MU_ASSERT_EQ_INT(0, cerver_serve_static(&srv, &req, &res));
|
|
320
|
+
MU_ASSERT_EQ_SIZE(5, res.body_len);
|
|
321
|
+
MU_ASSERT(memcmp(res.body, "small", 5) == 0);
|
|
322
|
+
MU_ASSERT_EQ_INT(1, res._body_owned);
|
|
323
|
+
|
|
324
|
+
free((void*)res.body);
|
|
325
|
+
unlink(file_path);
|
|
326
|
+
rmdir(dir);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
static void test_static_filesystem_large(void) {
|
|
330
|
+
char dir_template[] = "/tmp/cerver-test-XXXXXX";
|
|
331
|
+
char* dir = mkdtemp(dir_template);
|
|
332
|
+
MU_ASSERT(dir != NULL);
|
|
333
|
+
|
|
334
|
+
char file_path[PATH_MAX];
|
|
335
|
+
snprintf(file_path, sizeof(file_path), "%s/large.bin", dir);
|
|
336
|
+
|
|
337
|
+
char* payload = (char*)malloc(70000);
|
|
338
|
+
MU_ASSERT(payload != NULL);
|
|
339
|
+
memset(payload, 'a', 70000);
|
|
340
|
+
MU_ASSERT_EQ_INT(0, write_file(file_path, payload, 70000));
|
|
341
|
+
free(payload);
|
|
342
|
+
|
|
343
|
+
cerver_server_t srv;
|
|
344
|
+
cerver_init(&srv, 8080, 1);
|
|
345
|
+
cerver_set_public_dir(&srv, dir);
|
|
346
|
+
|
|
347
|
+
cerver_request_t req;
|
|
348
|
+
cerver_response_t res;
|
|
349
|
+
memset(&req, 0, sizeof(req));
|
|
350
|
+
memset(&res, 0, sizeof(res));
|
|
351
|
+
strcpy(req.method, "GET");
|
|
352
|
+
strcpy(req.path, "/large.bin");
|
|
353
|
+
|
|
354
|
+
MU_ASSERT_EQ_INT(0, cerver_serve_static(&srv, &req, &res));
|
|
355
|
+
MU_ASSERT_EQ_SIZE(70000, res.body_len);
|
|
356
|
+
MU_ASSERT_EQ_INT(2, res._body_owned);
|
|
357
|
+
MU_ASSERT(((const char*)res.body)[0] == 'a');
|
|
358
|
+
|
|
359
|
+
munmap((void*)res.body, res.body_len);
|
|
360
|
+
unlink(file_path);
|
|
361
|
+
rmdir(dir);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
static void test_static_rejects_unsafe_path(void) {
|
|
365
|
+
cerver_server_t srv;
|
|
366
|
+
cerver_init(&srv, 8080, 1);
|
|
367
|
+
|
|
368
|
+
cerver_request_t req;
|
|
369
|
+
cerver_response_t res;
|
|
370
|
+
memset(&req, 0, sizeof(req));
|
|
371
|
+
memset(&res, 0, sizeof(res));
|
|
372
|
+
strcpy(req.method, "GET");
|
|
373
|
+
strcpy(req.path, "/../secret");
|
|
374
|
+
|
|
375
|
+
MU_ASSERT_EQ_INT(-1, cerver_serve_static(&srv, &req, &res));
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
static void test_stat_cache_store_lookup(void) {
|
|
379
|
+
cerver_stat_cache_t cache;
|
|
380
|
+
cerver_stat_cache_init(&cache);
|
|
381
|
+
|
|
382
|
+
size_t out_size = 0;
|
|
383
|
+
MU_ASSERT_EQ_INT(-1, cerver_stat_cache_lookup(&cache, "/tmp/none", &out_size));
|
|
384
|
+
cerver_stat_cache_store(&cache, "/tmp/file", 123, time(NULL));
|
|
385
|
+
MU_ASSERT_EQ_INT(0, cerver_stat_cache_lookup(&cache, "/tmp/file", &out_size));
|
|
386
|
+
MU_ASSERT_EQ_SIZE(123, out_size);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
static void test_cerver_init_fields(void) {
|
|
390
|
+
cerver_server_t srv;
|
|
391
|
+
cerver_init(&srv, 9090, 3);
|
|
392
|
+
MU_ASSERT_EQ_INT(9090, srv.port);
|
|
393
|
+
MU_ASSERT_EQ_INT(3, srv.worker_count);
|
|
394
|
+
MU_ASSERT_EQ_INT(-1, srv.sock_fd);
|
|
395
|
+
MU_ASSERT_EQ_INT(0, srv.running);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
int main(void) {
|
|
399
|
+
mu_run("parse_request_basic", test_parse_request_basic);
|
|
400
|
+
mu_run("parse_request_trailing_slash", test_parse_request_trailing_slash);
|
|
401
|
+
mu_run("write_response_keepalive", test_write_response_keepalive);
|
|
402
|
+
mu_run("write_response_force_close", test_write_response_force_close);
|
|
403
|
+
mu_run("route_match_and_dispatch", test_route_match_and_dispatch);
|
|
404
|
+
mu_run("route_match_mismatch_resets_params", test_route_match_mismatch_resets_params);
|
|
405
|
+
mu_run("request_header_helpers", test_request_header_helpers);
|
|
406
|
+
mu_run("static_embedded_prefers_br", test_static_embedded_prefers_br);
|
|
407
|
+
mu_run("static_embedded_index_fallback", test_static_embedded_index_fallback);
|
|
408
|
+
mu_run("static_filesystem_small", test_static_filesystem_small);
|
|
409
|
+
mu_run("static_filesystem_large", test_static_filesystem_large);
|
|
410
|
+
mu_run("static_rejects_unsafe_path", test_static_rejects_unsafe_path);
|
|
411
|
+
mu_run("stat_cache_store_lookup", test_stat_cache_store_lookup);
|
|
412
|
+
mu_run("cerver_init_fields", test_cerver_init_fields);
|
|
413
|
+
return mu_report();
|
|
414
|
+
}
|