agoo 2.4.0 → 2.5.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.
Potentially problematic release.
This version of agoo might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/ext/agoo/agoo.c +4 -3
- data/ext/agoo/bind.c +275 -0
- data/ext/agoo/bind.h +35 -0
- data/ext/agoo/con.c +22 -25
- data/ext/agoo/debug.c +2 -0
- data/ext/agoo/debug.h +1 -0
- data/ext/agoo/error_stream.c +1 -0
- data/ext/agoo/hook.c +16 -6
- data/ext/agoo/hook.h +3 -1
- data/ext/agoo/http.c +7 -7
- data/ext/agoo/http.h +3 -1
- data/ext/agoo/log.h +1 -0
- data/ext/agoo/page.c +231 -104
- data/ext/agoo/page.h +10 -38
- data/ext/agoo/request.c +5 -1
- data/ext/agoo/request.h +1 -2
- data/ext/agoo/response.c +5 -1
- data/ext/agoo/rhook.c +2 -2
- data/ext/agoo/rhook.h +1 -1
- data/ext/agoo/rserver.c +991 -0
- data/ext/agoo/rserver.h +42 -0
- data/ext/agoo/server.c +95 -978
- data/ext/agoo/server.h +16 -27
- data/ext/agoo/upgraded.c +28 -20
- data/ext/agoo/websocket.c +4 -7
- data/lib/agoo/version.rb +1 -1
- data/test/bind_test.rb +134 -0
- data/test/named_client.rb +7 -0
- data/test/named_server.rb +13 -0
- metadata +12 -2
data/ext/agoo/debug.c
CHANGED
@@ -21,6 +21,7 @@ typedef struct _Rec {
|
|
21
21
|
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
|
22
22
|
static Rec recs = NULL;
|
23
23
|
|
24
|
+
atomic_int mem_bind = 0;
|
24
25
|
atomic_int mem_cb = 0;
|
25
26
|
atomic_int mem_con = 0;
|
26
27
|
atomic_int mem_cslot = 0;
|
@@ -89,6 +90,7 @@ print_stats() {
|
|
89
90
|
printf("********************************************************************************\n");
|
90
91
|
#if 0
|
91
92
|
printf("memory statistics\n");
|
93
|
+
printf(" mem_bind: %d\n", mem_bind);
|
92
94
|
printf(" mem_cb: %d\n", mem_cb);
|
93
95
|
printf(" mem_con: %d\n", mem_con);
|
94
96
|
printf(" mem_cslot: %d\n", mem_cslot);
|
data/ext/agoo/debug.h
CHANGED
data/ext/agoo/error_stream.c
CHANGED
data/ext/agoo/hook.c
CHANGED
@@ -7,29 +7,39 @@
|
|
7
7
|
#include "hook.h"
|
8
8
|
|
9
9
|
Hook
|
10
|
-
hook_create(Method method, const char *pattern, void *handler, HookType type) {
|
10
|
+
hook_create(Method method, const char *pattern, void *handler, HookType type, Queue q) {
|
11
11
|
Hook hook = (Hook)malloc(sizeof(struct _Hook));
|
12
12
|
|
13
13
|
if (NULL != hook) {
|
14
|
-
|
14
|
+
char *pat = NULL;
|
15
|
+
|
16
|
+
DEBUG_ALLOC(mem_hook, hook);
|
15
17
|
if (NULL == pattern) {
|
16
|
-
|
18
|
+
if (NONE != method) {
|
19
|
+
pat = strdup("");
|
20
|
+
}
|
21
|
+
} else {
|
22
|
+
pat = strdup(pattern);
|
17
23
|
}
|
24
|
+
hook->pattern = pat;
|
25
|
+
|
18
26
|
hook->next = NULL;
|
19
|
-
hook->pattern = strdup(pattern);
|
20
27
|
DEBUG_ALLOC(mem_hook_pattern, hook->pattern)
|
21
28
|
hook->method = method;
|
22
29
|
hook->handler = handler;
|
23
30
|
hook->type = type;
|
31
|
+
hook->queue = q;
|
24
32
|
}
|
25
33
|
return hook;
|
26
34
|
}
|
27
35
|
|
28
36
|
void
|
29
37
|
hook_destroy(Hook hook) {
|
30
|
-
|
38
|
+
if (NULL != hook->pattern) {
|
39
|
+
DEBUG_FREE(mem_hook_pattern, hook->pattern);
|
40
|
+
free(hook->pattern);
|
41
|
+
}
|
31
42
|
DEBUG_FREE(mem_hook, hook)
|
32
|
-
free(hook->pattern);
|
33
43
|
free(hook);
|
34
44
|
}
|
35
45
|
|
data/ext/agoo/hook.h
CHANGED
@@ -6,6 +6,7 @@
|
|
6
6
|
#include <stdbool.h>
|
7
7
|
|
8
8
|
#include "method.h"
|
9
|
+
#include "queue.h"
|
9
10
|
#include "seg.h"
|
10
11
|
|
11
12
|
typedef enum {
|
@@ -31,9 +32,10 @@ typedef struct _Hook {
|
|
31
32
|
char *pattern;
|
32
33
|
HookType type;
|
33
34
|
void* handler;
|
35
|
+
Queue queue;
|
34
36
|
} *Hook;
|
35
37
|
|
36
|
-
extern Hook hook_create(Method method, const char *pattern, void *handler, HookType type);
|
38
|
+
extern Hook hook_create(Method method, const char *pattern, void *handler, HookType type, Queue q);
|
37
39
|
extern void hook_destroy(Hook hook);
|
38
40
|
|
39
41
|
extern bool hook_match(Hook hook, Method method, const Seg seg);
|
data/ext/agoo/http.c
CHANGED
@@ -4,8 +4,6 @@
|
|
4
4
|
#include <stdlib.h>
|
5
5
|
#include <string.h>
|
6
6
|
|
7
|
-
#include <ruby.h>
|
8
|
-
|
9
7
|
#include "debug.h"
|
10
8
|
#include "http.h"
|
11
9
|
|
@@ -507,8 +505,8 @@ http_cleanup() {
|
|
507
505
|
}
|
508
506
|
}
|
509
507
|
|
510
|
-
|
511
|
-
http_header_ok(const char *key, int klen, const char *value, int vlen) {
|
508
|
+
int
|
509
|
+
http_header_ok(Err err, const char *key, int klen, const char *value, int vlen) {
|
512
510
|
int len = klen;
|
513
511
|
int64_t h = calc_hash(key, &len);
|
514
512
|
Slot *bucket = get_bucketp(h);
|
@@ -530,21 +528,23 @@ http_header_ok(const char *key, int klen, const char *value, int vlen) {
|
|
530
528
|
}
|
531
529
|
strncpy(buf, key, klen);
|
532
530
|
buf[klen] = '\0';
|
533
|
-
|
531
|
+
|
532
|
+
return err_set(err, ERR_ARG, "%s is not a valid HTTP header key.", buf);
|
534
533
|
}
|
535
534
|
// Now check the value.
|
536
535
|
found = false; // reuse as indicator for in a quoted string
|
537
536
|
for (; 0 < vlen; vlen--, value++) {
|
538
537
|
if ('o' != header_value_chars[(uint8_t)*value]) {
|
539
|
-
|
538
|
+
return err_set(err, ERR_ARG, "%02x is not a valid HTTP header value character.", *value);
|
540
539
|
}
|
541
540
|
if ('"' == *value) {
|
542
541
|
found = !found;
|
543
542
|
}
|
544
543
|
}
|
545
544
|
if (found) {
|
546
|
-
|
545
|
+
return err_set(err, ERR_ARG, "HTTP header has unmatched quote.");
|
547
546
|
}
|
547
|
+
return ERR_OK;
|
548
548
|
}
|
549
549
|
|
550
550
|
const char*
|
data/ext/agoo/http.h
CHANGED
@@ -5,10 +5,12 @@
|
|
5
5
|
|
6
6
|
#include <stdbool.h>
|
7
7
|
|
8
|
+
#include "err.h"
|
9
|
+
|
8
10
|
extern void http_init();
|
9
11
|
extern void http_cleanup();
|
10
12
|
|
11
|
-
extern
|
13
|
+
extern int http_header_ok(Err err, const char *key, int klen, const char *value, int vlen);
|
12
14
|
|
13
15
|
extern const char* http_code_message(int code);
|
14
16
|
|
data/ext/agoo/log.h
CHANGED
data/ext/agoo/page.c
CHANGED
@@ -6,14 +6,43 @@
|
|
6
6
|
#include <sys/stat.h>
|
7
7
|
#include <unistd.h>
|
8
8
|
|
9
|
-
#include <ruby.h>
|
10
|
-
|
11
9
|
#include "debug.h"
|
12
10
|
#include "dtime.h"
|
13
11
|
#include "page.h"
|
14
12
|
|
15
13
|
#define PAGE_RECHECK_TIME 5.0
|
14
|
+
|
16
15
|
#define MAX_KEY_UNIQ 9
|
16
|
+
#define MAX_KEY_LEN 1024
|
17
|
+
#define PAGE_BUCKET_SIZE 1024
|
18
|
+
#define PAGE_BUCKET_MASK 1023
|
19
|
+
|
20
|
+
#define MAX_MIME_KEY_LEN 15
|
21
|
+
#define MIME_BUCKET_SIZE 64
|
22
|
+
#define MIME_BUCKET_MASK 63
|
23
|
+
|
24
|
+
typedef struct _Slot {
|
25
|
+
struct _Slot *next;
|
26
|
+
char key[MAX_KEY_LEN + 1];
|
27
|
+
Page value;
|
28
|
+
uint64_t hash;
|
29
|
+
int klen;
|
30
|
+
} *Slot;
|
31
|
+
|
32
|
+
typedef struct _MimeSlot {
|
33
|
+
struct _MimeSlot *next;
|
34
|
+
char key[MAX_MIME_KEY_LEN + 1];
|
35
|
+
char *value;
|
36
|
+
uint64_t hash;
|
37
|
+
int klen;
|
38
|
+
} *MimeSlot;
|
39
|
+
|
40
|
+
typedef struct _Cache {
|
41
|
+
Slot buckets[PAGE_BUCKET_SIZE];
|
42
|
+
MimeSlot muckets[MIME_BUCKET_SIZE];
|
43
|
+
char *root;
|
44
|
+
Group groups;
|
45
|
+
} *Cache;
|
17
46
|
|
18
47
|
typedef struct _Mime {
|
19
48
|
const char *suffix;
|
@@ -70,6 +99,13 @@ static struct _Mime mime_map[] = {
|
|
70
99
|
|
71
100
|
static const char page_fmt[] = "HTTP/1.1 200 OK\r\nContent-Type: %s\r\nContent-Length: %ld\r\n\r\n";
|
72
101
|
|
102
|
+
static struct _Cache cache = {
|
103
|
+
.buckets = {0},
|
104
|
+
.muckets = {0},
|
105
|
+
.root = NULL,
|
106
|
+
.groups = NULL,
|
107
|
+
};
|
108
|
+
|
73
109
|
static uint64_t
|
74
110
|
calc_hash(const char *key, int *lenp) {
|
75
111
|
int len = 0;
|
@@ -98,21 +134,21 @@ calc_hash(const char *key, int *lenp) {
|
|
98
134
|
|
99
135
|
// Buckets are a twist on the hash to mix it up a bit. Odd shifts and XORs.
|
100
136
|
static Slot*
|
101
|
-
get_bucketp(
|
102
|
-
return cache
|
137
|
+
get_bucketp(uint64_t h) {
|
138
|
+
return cache.buckets + (PAGE_BUCKET_MASK & (h ^ (h << 5) ^ (h >> 7)));
|
103
139
|
}
|
104
140
|
|
105
141
|
static MimeSlot*
|
106
|
-
get_mime_bucketp(
|
107
|
-
return cache
|
142
|
+
get_mime_bucketp(uint64_t h) {
|
143
|
+
return cache.muckets + (MIME_BUCKET_MASK & (h ^ (h << 5) ^ (h >> 7)));
|
108
144
|
}
|
109
145
|
|
110
146
|
const char*
|
111
|
-
mime_get(
|
147
|
+
mime_get(const char *key) {
|
112
148
|
int klen = (int)strlen(key);
|
113
149
|
int len = klen;
|
114
150
|
int64_t h = calc_hash(key, &len);
|
115
|
-
MimeSlot *bucket = get_mime_bucketp(
|
151
|
+
MimeSlot *bucket = get_mime_bucketp(h);
|
116
152
|
MimeSlot s;
|
117
153
|
const char *v = NULL;
|
118
154
|
|
@@ -127,10 +163,10 @@ mime_get(Cache cache, const char *key) {
|
|
127
163
|
}
|
128
164
|
|
129
165
|
Page
|
130
|
-
cache_get(
|
166
|
+
cache_get(const char *key, int klen) {
|
131
167
|
int len = klen;
|
132
168
|
int64_t h = calc_hash(key, &len);
|
133
|
-
Slot *bucket = get_bucketp(
|
169
|
+
Slot *bucket = get_bucketp(h);
|
134
170
|
Slot s;
|
135
171
|
Page v = NULL;
|
136
172
|
|
@@ -144,33 +180,31 @@ cache_get(Cache cache, const char *key, int klen) {
|
|
144
180
|
return v;
|
145
181
|
}
|
146
182
|
|
147
|
-
|
148
|
-
mime_set(
|
183
|
+
int
|
184
|
+
mime_set(Err err, const char *key, const char *value) {
|
149
185
|
int klen = (int)strlen(key);
|
150
186
|
int len = klen;
|
151
187
|
int64_t h = calc_hash(key, &len);
|
152
|
-
MimeSlot *bucket = get_mime_bucketp(
|
188
|
+
MimeSlot *bucket = get_mime_bucketp(h);
|
153
189
|
MimeSlot s;
|
154
190
|
|
155
191
|
if (MAX_MIME_KEY_LEN < len) {
|
156
|
-
|
192
|
+
return err_set(err, ERR_ARG, "%s is too long for a file extension. Maximum is %d", key, MAX_MIME_KEY_LEN);
|
157
193
|
}
|
158
194
|
for (s = *bucket; NULL != s; s = s->next) {
|
159
195
|
if (h == (int64_t)s->hash && len == s->klen &&
|
160
196
|
((0 <= len && len <= MAX_KEY_UNIQ) || 0 == strncmp(s->key, key, len))) {
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
return;
|
167
|
-
}
|
197
|
+
|
198
|
+
DEBUG_FREE(mem_mime_slot, s->value);
|
199
|
+
free(s->value);
|
200
|
+
s->value = strdup(value);
|
201
|
+
return ERR_OK;
|
168
202
|
}
|
169
203
|
}
|
170
204
|
if (NULL == (s = (MimeSlot)malloc(sizeof(struct _MimeSlot)))) {
|
171
|
-
|
205
|
+
return err_set(err, ERR_ARG, "out of memory adding %s", key);
|
172
206
|
}
|
173
|
-
DEBUG_ALLOC(mem_mime_slot, s)
|
207
|
+
DEBUG_ALLOC(mem_mime_slot, s);
|
174
208
|
s->hash = h;
|
175
209
|
s->klen = len;
|
176
210
|
if (NULL == key) {
|
@@ -181,13 +215,15 @@ mime_set(Cache cache, const char *key, const char *value) {
|
|
181
215
|
s->value = strdup(value);
|
182
216
|
s->next = *bucket;
|
183
217
|
*bucket = s;
|
218
|
+
|
219
|
+
return ERR_OK;
|
184
220
|
}
|
185
221
|
|
186
222
|
static Page
|
187
|
-
cache_set(
|
223
|
+
cache_set(const char *key, int klen, Page value) {
|
188
224
|
int len = klen;
|
189
225
|
int64_t h = calc_hash(key, &len);
|
190
|
-
Slot *bucket = get_bucketp(
|
226
|
+
Slot *bucket = get_bucketp(h);
|
191
227
|
Slot s;
|
192
228
|
Page old = NULL;
|
193
229
|
|
@@ -197,14 +233,12 @@ cache_set(Cache cache, const char *key, int klen, Page value) {
|
|
197
233
|
for (s = *bucket; NULL != s; s = s->next) {
|
198
234
|
if (h == (int64_t)s->hash && len == s->klen &&
|
199
235
|
((0 <= len && len <= MAX_KEY_UNIQ) || 0 == strncmp(s->key, key, len))) {
|
200
|
-
if (h == (int64_t)s->hash && len == s->klen &&
|
201
|
-
((0 <= len && len <= MAX_KEY_UNIQ) || 0 == strncmp(s->key, key, len))) {
|
202
|
-
old = s->value;
|
203
|
-
// replace
|
204
|
-
s->value = value;
|
205
236
|
|
206
|
-
|
207
|
-
|
237
|
+
old = s->value;
|
238
|
+
// replace
|
239
|
+
s->value = value;
|
240
|
+
|
241
|
+
return old;
|
208
242
|
}
|
209
243
|
}
|
210
244
|
if (NULL == (s = (Slot)malloc(sizeof(struct _Slot)))) {
|
@@ -227,21 +261,41 @@ cache_set(Cache cache, const char *key, int klen, Page value) {
|
|
227
261
|
}
|
228
262
|
|
229
263
|
void
|
230
|
-
pages_init(
|
264
|
+
pages_init() {
|
231
265
|
Mime m;
|
232
|
-
|
233
|
-
|
266
|
+
struct _Err err = ERR_INIT;
|
267
|
+
|
268
|
+
memset(&cache, 0, sizeof(struct _Cache));
|
269
|
+
cache.root = strdup(".");
|
234
270
|
for (m = mime_map; NULL != m->suffix; m++) {
|
235
|
-
mime_set(
|
271
|
+
mime_set(&err, m->suffix, m->type);
|
272
|
+
}
|
273
|
+
}
|
274
|
+
|
275
|
+
void
|
276
|
+
pages_set_root(const char *root) {
|
277
|
+
free(cache.root);
|
278
|
+
cache.root = strdup(root);
|
279
|
+
}
|
280
|
+
|
281
|
+
static void
|
282
|
+
page_destroy(Page p) {
|
283
|
+
if (NULL != p->resp) {
|
284
|
+
text_release(p->resp);
|
285
|
+
p->resp = NULL;
|
236
286
|
}
|
287
|
+
DEBUG_FREE(mem_page_path, p->path);
|
288
|
+
DEBUG_FREE(mem_page, p);
|
289
|
+
free(p->path);
|
290
|
+
free(p);
|
237
291
|
}
|
238
292
|
|
239
293
|
void
|
240
|
-
pages_cleanup(
|
241
|
-
Slot *sp = cache
|
294
|
+
pages_cleanup() {
|
295
|
+
Slot *sp = cache.buckets;
|
242
296
|
Slot s;
|
243
297
|
Slot n;
|
244
|
-
MimeSlot *mp = cache
|
298
|
+
MimeSlot *mp = cache.muckets;
|
245
299
|
MimeSlot sm;
|
246
300
|
MimeSlot m;
|
247
301
|
int i;
|
@@ -255,7 +309,6 @@ pages_cleanup(Cache cache) {
|
|
255
309
|
}
|
256
310
|
*sp = NULL;
|
257
311
|
}
|
258
|
-
|
259
312
|
for (i = MIME_BUCKET_SIZE; 0 < i; i--, mp++) {
|
260
313
|
for (sm = *mp; NULL != sm; sm = m) {
|
261
314
|
m = sm->next;
|
@@ -264,47 +317,107 @@ pages_cleanup(Cache cache) {
|
|
264
317
|
}
|
265
318
|
*mp = NULL;
|
266
319
|
}
|
267
|
-
free(cache
|
320
|
+
free(cache.root);
|
268
321
|
}
|
269
322
|
|
270
|
-
|
323
|
+
static const char*
|
324
|
+
path_mime(const char *path) {
|
325
|
+
const char *suffix = path + strlen(path) - 1;
|
326
|
+
const char *mime = NULL;
|
327
|
+
|
328
|
+
for (; '.' != *suffix; suffix--) {
|
329
|
+
if (suffix <= path) {
|
330
|
+
suffix = NULL;
|
331
|
+
break;
|
332
|
+
}
|
333
|
+
}
|
334
|
+
if (suffix <= path) {
|
335
|
+
suffix = NULL;
|
336
|
+
}
|
337
|
+
if (NULL != suffix) {
|
338
|
+
suffix++;
|
339
|
+
mime = mime_get(suffix);
|
340
|
+
}
|
341
|
+
return mime;
|
342
|
+
}
|
343
|
+
|
344
|
+
// The page resp points to the page resp msg to save memory and reduce
|
271
345
|
// allocations.
|
272
346
|
Page
|
273
347
|
page_create(const char *path) {
|
274
348
|
Page p = (Page)malloc(sizeof(struct _Page));
|
275
349
|
|
276
350
|
if (NULL != p) {
|
277
|
-
DEBUG_ALLOC(mem_page, p)
|
351
|
+
DEBUG_ALLOC(mem_page, p);
|
278
352
|
p->resp = NULL;
|
279
353
|
if (NULL == path) {
|
280
354
|
p->path = NULL;
|
281
355
|
} else {
|
282
356
|
p->path = strdup(path);
|
283
|
-
DEBUG_ALLOC(mem_page_path, p->path)
|
357
|
+
DEBUG_ALLOC(mem_page_path, p->path);
|
284
358
|
}
|
285
359
|
p->mtime = 0;
|
286
360
|
p->last_check = 0.0;
|
361
|
+
p->immutable = false;
|
287
362
|
}
|
288
363
|
return p;
|
289
364
|
}
|
290
365
|
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
366
|
+
Page
|
367
|
+
page_immutable(Err err, const char *path, const char *content, int clen) {
|
368
|
+
Page p = (Page)malloc(sizeof(struct _Page));
|
369
|
+
const char *mime = path_mime(path);
|
370
|
+
long msize;
|
371
|
+
int cnt;
|
372
|
+
int plen = 0;
|
373
|
+
|
374
|
+
if (NULL == p) {
|
375
|
+
err_set(err, ERR_MEMORY, "Failed to allocate memory for page.");
|
376
|
+
return NULL;
|
296
377
|
}
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
378
|
+
DEBUG_ALLOC(mem_page, p);
|
379
|
+
if (NULL == path) {
|
380
|
+
p->path = NULL;
|
381
|
+
} else {
|
382
|
+
p->path = strdup(path);
|
383
|
+
plen = strlen(path);
|
384
|
+
DEBUG_ALLOC(mem_page_path, p->path);
|
385
|
+
}
|
386
|
+
p->mtime = 0;
|
387
|
+
p->last_check = 0.0;
|
388
|
+
p->immutable = true;
|
389
|
+
|
390
|
+
if (NULL == mime) {
|
391
|
+
mime = "text/html";
|
392
|
+
}
|
393
|
+
if (0 == clen) {
|
394
|
+
clen = (int)strlen(content);
|
395
|
+
}
|
396
|
+
// Format size plus space for the length, the mime type, and some
|
397
|
+
// padding. Then add the content length.
|
398
|
+
msize = sizeof(page_fmt) + 60 + clen;
|
399
|
+
if (NULL == (p->resp = text_allocate((int)msize))) {
|
400
|
+
DEBUG_FREE(mem_page, p);
|
401
|
+
free(p);
|
402
|
+
err_set(err, ERR_MEMORY, "Failed to allocate memory for page content.");
|
403
|
+
return NULL;
|
404
|
+
}
|
405
|
+
cnt = sprintf(p->resp->text, page_fmt, mime, (long)clen);
|
406
|
+
msize = cnt + clen;
|
407
|
+
memcpy(p->resp->text + cnt, content, clen);
|
408
|
+
p->resp->text[msize] = '\0';
|
409
|
+
p->resp->len = msize;
|
410
|
+
text_ref(p->resp);
|
411
|
+
|
412
|
+
cache_set(path, plen, p);
|
413
|
+
|
414
|
+
return p;
|
301
415
|
}
|
302
416
|
|
303
417
|
static bool
|
304
|
-
update_contents(
|
305
|
-
const char *mime =
|
418
|
+
update_contents(Page p) {
|
419
|
+
const char *mime = path_mime(p->path);
|
306
420
|
int plen = (int)strlen(p->path);
|
307
|
-
const char *suffix = p->path + plen - 1;
|
308
421
|
FILE *f;
|
309
422
|
long size;
|
310
423
|
struct stat fattr;
|
@@ -313,24 +426,6 @@ update_contents(Cache cache, Page p) {
|
|
313
426
|
struct stat fs;
|
314
427
|
Text t;
|
315
428
|
|
316
|
-
for (; '.' != *suffix; suffix--) {
|
317
|
-
if (suffix <= p->path) {
|
318
|
-
suffix = NULL;
|
319
|
-
break;
|
320
|
-
}
|
321
|
-
}
|
322
|
-
if (suffix <= p->path) {
|
323
|
-
suffix = NULL;
|
324
|
-
}
|
325
|
-
if (NULL != suffix) {
|
326
|
-
suffix++;
|
327
|
-
if (NULL == (mime = mime_get(cache, suffix))) {
|
328
|
-
mime = "text/plain";
|
329
|
-
}
|
330
|
-
} else {
|
331
|
-
mime = "text/plain";
|
332
|
-
}
|
333
|
-
|
334
429
|
f = fopen(p->path, "rb");
|
335
430
|
// On linux a directory is opened by fopen (sometimes? all the time?) so
|
336
431
|
// fstat is called to get the file mode and verify it is a regular file or
|
@@ -344,7 +439,7 @@ update_contents(Cache cache, Page p) {
|
|
344
439
|
}
|
345
440
|
if (NULL == f) {
|
346
441
|
// If not found how about with a /index.html added?
|
347
|
-
if (NULL ==
|
442
|
+
if (NULL == mime) {
|
348
443
|
char path[1024];
|
349
444
|
int cnt;
|
350
445
|
|
@@ -364,6 +459,9 @@ update_contents(Cache cache, Page p) {
|
|
364
459
|
return false;
|
365
460
|
}
|
366
461
|
}
|
462
|
+
if (NULL == mime) {
|
463
|
+
mime = "text/html";
|
464
|
+
}
|
367
465
|
if (0 != fseek(f, 0, SEEK_END)) {
|
368
466
|
fclose(f);
|
369
467
|
return false;
|
@@ -406,39 +504,68 @@ update_contents(Cache cache, Page p) {
|
|
406
504
|
return true;
|
407
505
|
}
|
408
506
|
|
409
|
-
static
|
410
|
-
|
411
|
-
|
507
|
+
static void
|
508
|
+
page_remove(Page p) {
|
509
|
+
int len = strlen(p->path);
|
510
|
+
int64_t h = calc_hash(p->path, &len);
|
511
|
+
Slot *bucket = get_bucketp(h);
|
512
|
+
Slot s;
|
513
|
+
Slot prev = NULL;
|
412
514
|
|
413
|
-
|
414
|
-
|
515
|
+
for (s = *bucket; NULL != s; s = s->next) {
|
516
|
+
if (h == (int64_t)s->hash && len == (int)s->klen &&
|
517
|
+
((0 <= len && len <= MAX_KEY_UNIQ) || 0 == strncmp(s->key, p->path, len))) {
|
415
518
|
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
519
|
+
if (NULL == prev) {
|
520
|
+
*bucket = s->next;
|
521
|
+
} else {
|
522
|
+
prev->next = s->next;
|
523
|
+
}
|
524
|
+
DEBUG_FREE(mem_page_slot, s);
|
525
|
+
page_destroy(s->value);
|
526
|
+
free(s);
|
527
|
+
|
528
|
+
break;
|
529
|
+
}
|
530
|
+
prev = s;
|
531
|
+
}
|
532
|
+
}
|
533
|
+
|
534
|
+
static Page
|
535
|
+
page_check(Err err, Page page) {
|
536
|
+
if (!page->immutable) {
|
537
|
+
double now = dtime();
|
538
|
+
|
539
|
+
if (page->last_check + PAGE_RECHECK_TIME < now) {
|
540
|
+
struct stat fattr;
|
541
|
+
|
542
|
+
if (0 == stat(page->path, &fattr) && page->mtime != fattr.st_mtime) {
|
543
|
+
update_contents(page);
|
544
|
+
if (NULL == page->resp) {
|
545
|
+
page_remove(page);
|
546
|
+
err_set(err, ERR_NOT_FOUND, "not found.");
|
547
|
+
return NULL;
|
548
|
+
}
|
422
549
|
}
|
550
|
+
page->last_check = now;
|
423
551
|
}
|
424
|
-
page->last_check = now;
|
425
552
|
}
|
426
553
|
return page;
|
427
554
|
}
|
428
555
|
|
429
556
|
Page
|
430
|
-
page_get(Err err,
|
557
|
+
page_get(Err err, const char *path, int plen) {
|
431
558
|
Page page;
|
432
559
|
|
433
560
|
if (NULL != strstr(path, "../")) {
|
434
561
|
return NULL;
|
435
562
|
}
|
436
|
-
if (NULL == (page = cache_get(
|
563
|
+
if (NULL == (page = cache_get(path, plen))) {
|
437
564
|
Page old;
|
438
565
|
char full_path[2048];
|
439
|
-
char *s = stpcpy(full_path, cache
|
566
|
+
char *s = stpcpy(full_path, cache.root);
|
440
567
|
|
441
|
-
if ('/' != *cache
|
568
|
+
if ('/' != *cache.root && '/' != *path) {
|
442
569
|
*s++ = '/';
|
443
570
|
}
|
444
571
|
if ((int)sizeof(full_path) <= plen + (s - full_path)) {
|
@@ -451,22 +578,22 @@ page_get(Err err, Cache cache, const char *path, int plen) {
|
|
451
578
|
err_set(err, ERR_MEMORY, "Failed to allocate memory for Page.");
|
452
579
|
return NULL;
|
453
580
|
}
|
454
|
-
if (!update_contents(
|
581
|
+
if (!update_contents(page) || NULL == page->resp) {
|
455
582
|
page_destroy(page);
|
456
583
|
err_set(err, ERR_NOT_FOUND, "not found.");
|
457
584
|
return NULL;
|
458
585
|
}
|
459
|
-
if (NULL != (old = cache_set(
|
586
|
+
if (NULL != (old = cache_set(path, plen, page))) {
|
460
587
|
page_destroy(old);
|
461
588
|
}
|
462
589
|
} else {
|
463
|
-
page = page_check(err,
|
590
|
+
page = page_check(err, page);
|
464
591
|
}
|
465
592
|
return page;
|
466
593
|
}
|
467
594
|
|
468
595
|
Page
|
469
|
-
group_get(Err err,
|
596
|
+
group_get(Err err, const char *path, int plen) {
|
470
597
|
Page page = NULL;
|
471
598
|
Group g = NULL;
|
472
599
|
char full_path[2048];
|
@@ -476,7 +603,7 @@ group_get(Err err, Cache cache, const char *path, int plen) {
|
|
476
603
|
if (NULL != strstr(path, "../")) {
|
477
604
|
return NULL;
|
478
605
|
}
|
479
|
-
for (g = cache
|
606
|
+
for (g = cache.groups; NULL != g; g = g->next) {
|
480
607
|
if (g->plen < plen && 0 == strncmp(path, g->path, g->plen) && '/' == path[g->plen]) {
|
481
608
|
break;
|
482
609
|
}
|
@@ -492,7 +619,7 @@ group_get(Err err, Cache cache, const char *path, int plen) {
|
|
492
619
|
strncpy(s, path + g->plen, plen - g->plen);
|
493
620
|
s += plen - g->plen;
|
494
621
|
*s = '\0';
|
495
|
-
if (NULL != (page = cache_get(
|
622
|
+
if (NULL != (page = cache_get(full_path, s - full_path))) {
|
496
623
|
break;
|
497
624
|
}
|
498
625
|
}
|
@@ -514,35 +641,35 @@ group_get(Err err, Cache cache, const char *path, int plen) {
|
|
514
641
|
}
|
515
642
|
plen = s - full_path;
|
516
643
|
path = full_path;
|
517
|
-
if (NULL == (page = cache_get(
|
644
|
+
if (NULL == (page = cache_get(path, plen))) {
|
518
645
|
Page old;
|
519
646
|
|
520
647
|
if (NULL == (page = page_create(path))) {
|
521
648
|
err_set(err, ERR_MEMORY, "Failed to allocate memory for Page.");
|
522
649
|
return NULL;
|
523
650
|
}
|
524
|
-
if (!update_contents(
|
651
|
+
if (!update_contents(page) || NULL == page->resp) {
|
525
652
|
page_destroy(page);
|
526
653
|
err_set(err, ERR_NOT_FOUND, "not found.");
|
527
654
|
return NULL;
|
528
655
|
}
|
529
|
-
if (NULL != (old = cache_set(
|
656
|
+
if (NULL != (old = cache_set(path, plen, page))) {
|
530
657
|
page_destroy(old);
|
531
658
|
}
|
532
659
|
}
|
533
660
|
return page;
|
534
661
|
}
|
535
|
-
return page_check(err,
|
662
|
+
return page_check(err, page);
|
536
663
|
}
|
537
664
|
|
538
665
|
Group
|
539
|
-
group_create(
|
666
|
+
group_create(const char *path) {
|
540
667
|
Group g = (Group)malloc(sizeof(struct _Group));
|
541
668
|
|
542
669
|
if (NULL != g) {
|
543
670
|
DEBUG_ALLOC(mem_group, g);
|
544
|
-
g->next = cache
|
545
|
-
cache
|
671
|
+
g->next = cache.groups;
|
672
|
+
cache.groups = g;
|
546
673
|
g->path = strdup(path);
|
547
674
|
g->plen = strlen(path);
|
548
675
|
DEBUG_ALLOC(mem_group_path, g->path);
|