agoo 2.15.10 → 2.15.11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +19 -3
- data/ext/agoo/page.c +505 -505
- data/ext/agoo/rserver.c +24 -15
- data/lib/agoo/version.rb +1 -1
- data/misc/flymd.md +581 -0
- data/misc/glue-diagram.svg +3 -0
- data/misc/glue.md +25 -0
- data/misc/optimize.md +100 -0
- data/misc/push.md +581 -0
- data/misc/rails.md +174 -0
- data/misc/song.md +268 -0
- metadata +19 -3
data/ext/agoo/page.c
CHANGED
@@ -10,58 +10,58 @@
|
|
10
10
|
#include "dtime.h"
|
11
11
|
#include "page.h"
|
12
12
|
|
13
|
-
#define PAGE_RECHECK_TIME
|
13
|
+
#define PAGE_RECHECK_TIME 5.0
|
14
14
|
|
15
|
-
#define MAX_KEY_UNIQ
|
16
|
-
#define MAX_KEY_LEN
|
17
|
-
#define PAGE_BUCKET_SIZE
|
18
|
-
#define PAGE_BUCKET_MASK
|
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
19
|
|
20
|
-
#define MAX_MIME_KEY_LEN
|
21
|
-
#define MIME_BUCKET_SIZE
|
22
|
-
#define MIME_BUCKET_MASK
|
20
|
+
#define MAX_MIME_KEY_LEN 15
|
21
|
+
#define MIME_BUCKET_SIZE 64
|
22
|
+
#define MIME_BUCKET_MASK 63
|
23
23
|
|
24
24
|
typedef struct _slot {
|
25
|
-
struct _slot
|
26
|
-
char
|
27
|
-
agooPage
|
28
|
-
uint64_t
|
29
|
-
int
|
25
|
+
struct _slot *next;
|
26
|
+
char key[MAX_KEY_LEN + 1];
|
27
|
+
agooPage value;
|
28
|
+
uint64_t hash;
|
29
|
+
int klen;
|
30
30
|
} *Slot;
|
31
31
|
|
32
32
|
typedef struct _headRule {
|
33
|
-
struct _headRule
|
34
|
-
char
|
35
|
-
char
|
36
|
-
char
|
37
|
-
char
|
38
|
-
int
|
33
|
+
struct _headRule *next;
|
34
|
+
char *path;
|
35
|
+
char *mime;
|
36
|
+
char *key;
|
37
|
+
char *value;
|
38
|
+
int len; // length of key + value + ': ' + '\r\n'
|
39
39
|
} *HeadRule;
|
40
40
|
|
41
41
|
typedef struct _mimeSlot {
|
42
|
-
struct _mimeSlot
|
43
|
-
char
|
44
|
-
char
|
45
|
-
uint64_t
|
46
|
-
int
|
42
|
+
struct _mimeSlot *next;
|
43
|
+
char key[MAX_MIME_KEY_LEN + 1];
|
44
|
+
char *value;
|
45
|
+
uint64_t hash;
|
46
|
+
int klen;
|
47
47
|
} *MimeSlot;
|
48
48
|
|
49
49
|
typedef struct _cache {
|
50
|
-
Slot
|
51
|
-
Slot
|
52
|
-
MimeSlot
|
53
|
-
char
|
54
|
-
agooGroup
|
55
|
-
HeadRule
|
50
|
+
Slot buckets[PAGE_BUCKET_SIZE];
|
51
|
+
Slot ruckets[PAGE_BUCKET_SIZE];
|
52
|
+
MimeSlot muckets[MIME_BUCKET_SIZE];
|
53
|
+
char *root;
|
54
|
+
agooGroup groups;
|
55
|
+
HeadRule head_rules;
|
56
56
|
} *Cache;
|
57
57
|
|
58
58
|
typedef struct _mime {
|
59
|
-
const char
|
60
|
-
const char
|
59
|
+
const char *suffix;
|
60
|
+
const char *type;
|
61
61
|
} *Mime;
|
62
62
|
|
63
63
|
// These are used for the initial load.
|
64
|
-
static struct _mime
|
64
|
+
static struct _mime mime_map[] = {
|
65
65
|
{ "asc", "text/plain" },
|
66
66
|
{ "avi", "video/x-msvideo" },
|
67
67
|
{ "bin", "application/octet-stream" },
|
@@ -108,8 +108,8 @@ static struct _mime mime_map[] = {
|
|
108
108
|
{ NULL, NULL }
|
109
109
|
};
|
110
110
|
|
111
|
-
static const char
|
112
|
-
static const char
|
111
|
+
static const char page_fmt[] = "HTTP/1.1 200 OK\r\nContent-Type: %s\r\nContent-Length: %ld\r\n\r\n";
|
112
|
+
static const char page_min_fmt[] = "HTTP/1.1 200 OK\r\nContent-Length: %ld\r\n";
|
113
113
|
// 0123456789abcdef0123456789abcdef
|
114
114
|
static const char hex_map[] = "\
|
115
115
|
................................\
|
@@ -121,7 +121,7 @@ static const char hex_map[] = "\
|
|
121
121
|
................................\
|
122
122
|
................................";
|
123
123
|
|
124
|
-
static struct _cache
|
124
|
+
static struct _cache cache = {
|
125
125
|
.buckets = {0},
|
126
126
|
.ruckets = {0},
|
127
127
|
.muckets = {0},
|
@@ -147,15 +147,15 @@ parse_percent_seq(const char *seq) {
|
|
147
147
|
|
148
148
|
static uint64_t
|
149
149
|
calc_hash(const char *key, int *lenp) {
|
150
|
-
int
|
151
|
-
int
|
152
|
-
uint64_t
|
153
|
-
const uint8_t
|
150
|
+
int len = 0;
|
151
|
+
int klen = *lenp;
|
152
|
+
uint64_t h = 0;
|
153
|
+
const uint8_t *k = (const uint8_t*)key;
|
154
154
|
|
155
155
|
for (; len < klen; k++) {
|
156
|
-
|
157
|
-
|
158
|
-
|
156
|
+
// fast, just spread it out
|
157
|
+
h = 77 * h + (*k - 0x2D);
|
158
|
+
len++;
|
159
159
|
}
|
160
160
|
*lenp = len;
|
161
161
|
|
@@ -180,94 +180,94 @@ get_mime_bucketp(uint64_t h) {
|
|
180
180
|
|
181
181
|
const char*
|
182
182
|
mime_get(const char *key) {
|
183
|
-
int
|
184
|
-
int
|
185
|
-
int64_t
|
186
|
-
MimeSlot
|
187
|
-
MimeSlot
|
188
|
-
const char
|
183
|
+
int klen = (int)strlen(key);
|
184
|
+
int len = klen;
|
185
|
+
int64_t h = calc_hash(key, &len);
|
186
|
+
MimeSlot *bucket = get_mime_bucketp(h);
|
187
|
+
MimeSlot s;
|
188
|
+
const char *v = NULL;
|
189
189
|
|
190
190
|
for (s = *bucket; NULL != s; s = s->next) {
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
191
|
+
if (h == (int64_t)s->hash && len == (int)s->klen &&
|
192
|
+
((0 <= len && len <= MAX_KEY_UNIQ) || 0 == strncmp(s->key, key, klen))) {
|
193
|
+
v = s->value;
|
194
|
+
break;
|
195
|
+
}
|
196
196
|
}
|
197
197
|
return v;
|
198
198
|
}
|
199
199
|
|
200
200
|
agooPage
|
201
201
|
cache_get(const char *key, int klen) {
|
202
|
-
int
|
203
|
-
int64_t
|
204
|
-
Slot
|
205
|
-
Slot
|
206
|
-
agooPage
|
202
|
+
int len = klen;
|
203
|
+
int64_t h = calc_hash(key, &len);
|
204
|
+
Slot *bucket = get_bucketp(h);
|
205
|
+
Slot s;
|
206
|
+
agooPage v = NULL;
|
207
207
|
|
208
208
|
for (s = *bucket; NULL != s; s = s->next) {
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
209
|
+
if (h == (int64_t)s->hash && len == (int)s->klen &&
|
210
|
+
((0 <= len && len <= MAX_KEY_UNIQ) || 0 == strncmp(s->key, key, klen))) {
|
211
|
+
v = s->value;
|
212
|
+
break;
|
213
|
+
}
|
214
214
|
}
|
215
215
|
return v;
|
216
216
|
}
|
217
217
|
|
218
218
|
agooPage
|
219
219
|
cache_root_get(const char *key, int klen) {
|
220
|
-
int
|
221
|
-
int64_t
|
222
|
-
Slot
|
223
|
-
Slot
|
224
|
-
agooPage
|
220
|
+
int len = klen;
|
221
|
+
int64_t h = calc_hash(key, &len);
|
222
|
+
Slot *bucket = get_rucketp(h);
|
223
|
+
Slot s;
|
224
|
+
agooPage v = NULL;
|
225
225
|
|
226
226
|
for (s = *bucket; NULL != s; s = s->next) {
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
227
|
+
if (h == (int64_t)s->hash && len == (int)s->klen &&
|
228
|
+
((0 <= len && len <= MAX_KEY_UNIQ) || 0 == strncmp(s->key, key, klen))) {
|
229
|
+
v = s->value;
|
230
|
+
break;
|
231
|
+
}
|
232
232
|
}
|
233
233
|
return v;
|
234
234
|
}
|
235
235
|
|
236
236
|
int
|
237
237
|
mime_set(agooErr err, const char *key, const char *value) {
|
238
|
-
int
|
239
|
-
int
|
240
|
-
int64_t
|
241
|
-
MimeSlot
|
242
|
-
MimeSlot
|
238
|
+
int klen = (int)strlen(key);
|
239
|
+
int len = klen;
|
240
|
+
int64_t h = calc_hash(key, &len);
|
241
|
+
MimeSlot *bucket = get_mime_bucketp(h);
|
242
|
+
MimeSlot s;
|
243
243
|
|
244
244
|
if (MAX_MIME_KEY_LEN < len) {
|
245
|
-
|
245
|
+
return agoo_err_set(err, AGOO_ERR_ARG, "%s is too long for a file extension. Maximum is %d", key, MAX_MIME_KEY_LEN);
|
246
246
|
}
|
247
247
|
for (s = *bucket; NULL != s; s = s->next) {
|
248
|
-
|
249
|
-
|
248
|
+
if (h == (int64_t)s->hash && len == s->klen &&
|
249
|
+
((0 <= len && len <= MAX_KEY_UNIQ) || 0 == strncmp(s->key, key, len))) {
|
250
250
|
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
251
|
+
AGOO_FREE(s->value);
|
252
|
+
if (NULL == (s->value = AGOO_STRDUP(value))) {
|
253
|
+
return agoo_err_set(err, AGOO_ERR_ARG, "out of memory adding %s", key);
|
254
|
+
}
|
255
|
+
return AGOO_ERR_OK;
|
256
|
+
}
|
257
257
|
}
|
258
258
|
if (NULL == (s = (MimeSlot)AGOO_MALLOC(sizeof(struct _mimeSlot)))) {
|
259
|
-
|
259
|
+
return AGOO_ERR_MEM(err, "mime key and value");
|
260
260
|
}
|
261
261
|
s->hash = h;
|
262
262
|
s->klen = len;
|
263
263
|
if (NULL == key) {
|
264
|
-
|
264
|
+
*s->key = '\0';
|
265
265
|
} else {
|
266
|
-
|
266
|
+
strcpy(s->key, key);
|
267
267
|
}
|
268
268
|
if (NULL == (s->value = AGOO_STRDUP(value))) {
|
269
|
-
|
270
|
-
|
269
|
+
AGOO_FREE(s);
|
270
|
+
return AGOO_ERR_MEM(err, "mime key and value");
|
271
271
|
}
|
272
272
|
s->next = *bucket;
|
273
273
|
*bucket = s;
|
@@ -277,33 +277,33 @@ mime_set(agooErr err, const char *key, const char *value) {
|
|
277
277
|
|
278
278
|
static agooPage
|
279
279
|
bucket_set(Slot *bucket, int64_t h, const char *key, int klen, agooPage value) {
|
280
|
-
Slot
|
281
|
-
agooPage
|
280
|
+
Slot s;
|
281
|
+
agooPage old = NULL;
|
282
282
|
|
283
283
|
if (MAX_KEY_LEN < klen) {
|
284
|
-
|
284
|
+
return value;
|
285
285
|
}
|
286
286
|
for (s = *bucket; NULL != s; s = s->next) {
|
287
|
-
|
288
|
-
|
287
|
+
if (h == (int64_t)s->hash && klen == s->klen &&
|
288
|
+
((0 <= klen && klen <= MAX_KEY_UNIQ) || 0 == strncmp(s->key, key, klen))) {
|
289
289
|
|
290
|
-
|
291
|
-
|
292
|
-
|
290
|
+
old = s->value;
|
291
|
+
// replace
|
292
|
+
s->value = value;
|
293
293
|
|
294
|
-
|
295
|
-
|
294
|
+
return old;
|
295
|
+
}
|
296
296
|
}
|
297
297
|
if (NULL == (s = (Slot)AGOO_MALLOC(sizeof(struct _slot)))) {
|
298
|
-
|
298
|
+
return value;
|
299
299
|
}
|
300
300
|
s->hash = h;
|
301
301
|
s->klen = klen;
|
302
302
|
if (NULL == key) {
|
303
|
-
|
303
|
+
*s->key = '\0';
|
304
304
|
} else {
|
305
|
-
|
306
|
-
|
305
|
+
strncpy(s->key, key, klen);
|
306
|
+
s->key[klen] = '\0';
|
307
307
|
}
|
308
308
|
s->value = value;
|
309
309
|
s->next = *bucket;
|
@@ -314,32 +314,32 @@ bucket_set(Slot *bucket, int64_t h, const char *key, int klen, agooPage value) {
|
|
314
314
|
|
315
315
|
static agooPage
|
316
316
|
cache_set(const char *key, int klen, agooPage value) {
|
317
|
-
int
|
318
|
-
int64_t
|
319
|
-
Slot
|
317
|
+
int len = klen;
|
318
|
+
int64_t h = calc_hash(key, &len);
|
319
|
+
Slot *bucket = get_bucketp(h);
|
320
320
|
|
321
321
|
return bucket_set(bucket, h, key, len, value);
|
322
322
|
}
|
323
323
|
|
324
324
|
static agooPage
|
325
325
|
cache_root_set(const char *key, int klen, agooPage value) {
|
326
|
-
int
|
327
|
-
int64_t
|
328
|
-
Slot
|
326
|
+
int len = klen;
|
327
|
+
int64_t h = calc_hash(key, &len);
|
328
|
+
Slot *bucket = get_rucketp(h);
|
329
329
|
|
330
330
|
return bucket_set(bucket, h, key, len, value);
|
331
331
|
}
|
332
332
|
|
333
333
|
int
|
334
334
|
agoo_pages_init(agooErr err) {
|
335
|
-
Mime
|
335
|
+
Mime m;
|
336
336
|
|
337
337
|
memset(&cache, 0, sizeof(struct _cache));
|
338
338
|
if (NULL == (cache.root = AGOO_STRDUP("."))) {
|
339
|
-
|
339
|
+
return agoo_err_set(err, AGOO_ERR_ARG, "out of memory allocating root path");
|
340
340
|
}
|
341
341
|
for (m = mime_map; NULL != m->suffix; m++) {
|
342
|
-
|
342
|
+
mime_set(err, m->suffix, m->type);
|
343
343
|
}
|
344
344
|
return err->code;
|
345
345
|
}
|
@@ -348,11 +348,11 @@ int
|
|
348
348
|
agoo_pages_set_root(agooErr err, const char *root) {
|
349
349
|
AGOO_FREE(cache.root);
|
350
350
|
if (NULL == root) {
|
351
|
-
|
351
|
+
cache.root = NULL;
|
352
352
|
} else {
|
353
|
-
|
354
|
-
|
355
|
-
|
353
|
+
if (NULL == (cache.root = AGOO_STRDUP(root))) {
|
354
|
+
return agoo_err_set(err, AGOO_ERR_ARG, "out of memory allocating root path");
|
355
|
+
}
|
356
356
|
}
|
357
357
|
return AGOO_ERR_OK;
|
358
358
|
}
|
@@ -360,8 +360,8 @@ agoo_pages_set_root(agooErr err, const char *root) {
|
|
360
360
|
static void
|
361
361
|
agoo_page_destroy(agooPage p) {
|
362
362
|
if (NULL != p->resp) {
|
363
|
-
|
364
|
-
|
363
|
+
agoo_text_release(p->resp);
|
364
|
+
p->resp = NULL;
|
365
365
|
}
|
366
366
|
AGOO_FREE(p->path);
|
367
367
|
AGOO_FREE(p);
|
@@ -369,86 +369,86 @@ agoo_page_destroy(agooPage p) {
|
|
369
369
|
|
370
370
|
void
|
371
371
|
agoo_pages_cleanup() {
|
372
|
-
Slot
|
373
|
-
Slot
|
374
|
-
Slot
|
375
|
-
MimeSlot
|
376
|
-
MimeSlot
|
377
|
-
MimeSlot
|
378
|
-
HeadRule
|
379
|
-
int
|
372
|
+
Slot *sp = cache.buckets;
|
373
|
+
Slot s;
|
374
|
+
Slot n;
|
375
|
+
MimeSlot *mp = cache.muckets;
|
376
|
+
MimeSlot sm;
|
377
|
+
MimeSlot m;
|
378
|
+
HeadRule hr;
|
379
|
+
int i;
|
380
380
|
|
381
381
|
for (i = PAGE_BUCKET_SIZE; 0 < i; i--, sp++) {
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
382
|
+
for (s = *sp; NULL != s; s = n) {
|
383
|
+
n = s->next;
|
384
|
+
agoo_page_destroy(s->value);
|
385
|
+
AGOO_FREE(s);
|
386
|
+
}
|
387
|
+
*sp = NULL;
|
388
388
|
}
|
389
389
|
for (sp = cache.ruckets, i = PAGE_BUCKET_SIZE; 0 < i; i--, sp++) {
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
390
|
+
for (s = *sp; NULL != s; s = n) {
|
391
|
+
n = s->next;
|
392
|
+
agoo_page_destroy(s->value);
|
393
|
+
AGOO_FREE(s);
|
394
|
+
}
|
395
|
+
*sp = NULL;
|
396
396
|
}
|
397
397
|
for (i = MIME_BUCKET_SIZE; 0 < i; i--, mp++) {
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
398
|
+
for (sm = *mp; NULL != sm; sm = m) {
|
399
|
+
m = sm->next;
|
400
|
+
AGOO_FREE(sm->value);
|
401
|
+
AGOO_FREE(sm);
|
402
|
+
}
|
403
|
+
*mp = NULL;
|
404
404
|
}
|
405
405
|
while (NULL != (hr = cache.head_rules)) {
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
406
|
+
cache.head_rules = hr->next;
|
407
|
+
AGOO_FREE(hr->path);
|
408
|
+
AGOO_FREE(hr->mime);
|
409
|
+
AGOO_FREE(hr->key);
|
410
|
+
AGOO_FREE(hr->value);
|
411
|
+
AGOO_FREE(hr);
|
412
412
|
}
|
413
413
|
AGOO_FREE(cache.root);
|
414
414
|
}
|
415
415
|
|
416
416
|
static const char*
|
417
417
|
path_mime(const char *path) {
|
418
|
-
const char
|
419
|
-
const char
|
418
|
+
const char *suffix = path + strlen(path) - 1;
|
419
|
+
const char *mime = NULL;
|
420
420
|
|
421
421
|
for (; '.' != *suffix; suffix--) {
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
422
|
+
if (suffix <= path) {
|
423
|
+
suffix = NULL;
|
424
|
+
break;
|
425
|
+
}
|
426
426
|
}
|
427
427
|
if (suffix <= path) {
|
428
|
-
|
428
|
+
suffix = NULL;
|
429
429
|
}
|
430
430
|
if (NULL != suffix) {
|
431
|
-
|
432
|
-
|
431
|
+
suffix++;
|
432
|
+
mime = mime_get(suffix);
|
433
433
|
}
|
434
434
|
return mime;
|
435
435
|
}
|
436
436
|
|
437
437
|
static const char*
|
438
438
|
path_suffix(const char *path) {
|
439
|
-
const char
|
439
|
+
const char *suffix = path + strlen(path) - 1;
|
440
440
|
|
441
441
|
for (; '.' != *suffix; suffix--) {
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
442
|
+
if (suffix <= path) {
|
443
|
+
suffix = NULL;
|
444
|
+
break;
|
445
|
+
}
|
446
446
|
}
|
447
447
|
if (suffix <= path) {
|
448
|
-
|
448
|
+
suffix = NULL;
|
449
449
|
}
|
450
450
|
if (NULL != suffix) {
|
451
|
-
|
451
|
+
suffix++;
|
452
452
|
}
|
453
453
|
return suffix;
|
454
454
|
}
|
@@ -456,141 +456,141 @@ path_suffix(const char *path) {
|
|
456
456
|
static bool
|
457
457
|
path_match(const char *pat, const char *path) {
|
458
458
|
if (NULL == pat) {
|
459
|
-
|
459
|
+
return true;
|
460
460
|
}
|
461
461
|
if (NULL == path) {
|
462
|
-
|
462
|
+
return '*' == *pat && '*' == pat[1] && '\0' == pat[2];
|
463
463
|
}
|
464
464
|
if ('/' == *path) {
|
465
|
-
|
465
|
+
path++;
|
466
466
|
}
|
467
467
|
for (; '\0' != *pat && '\0' != *path; pat++) {
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
468
|
+
if (*path == *pat) {
|
469
|
+
path++;
|
470
|
+
} else if ('*' == *pat) {
|
471
|
+
if ('*' == *(pat + 1)) {
|
472
|
+
return true;
|
473
|
+
}
|
474
|
+
for (; '\0' != *path && '/' != *path; path++) {
|
475
|
+
}
|
476
|
+
} else {
|
477
|
+
break;
|
478
|
+
}
|
479
479
|
}
|
480
480
|
return '\0' == *pat && '\0' == *path;
|
481
481
|
}
|
482
482
|
|
483
483
|
static bool
|
484
484
|
head_rule_match(HeadRule rule, const char *path, const char *mime) {
|
485
|
-
const char
|
485
|
+
const char *suffix = NULL;
|
486
486
|
|
487
487
|
if (NULL != path) {
|
488
|
-
|
488
|
+
suffix = path_suffix(path);
|
489
489
|
}
|
490
490
|
return path_match(rule->path, path) &&
|
491
|
-
|
492
|
-
|
491
|
+
(NULL == rule->mime || 0 == strcmp(rule->mime, mime) ||
|
492
|
+
(NULL != suffix && 0 == strcmp(rule->mime, suffix)));
|
493
493
|
}
|
494
494
|
|
495
495
|
// The page resp points to the page resp msg to save memory and reduce
|
496
496
|
// allocations.
|
497
497
|
agooPage
|
498
498
|
agoo_page_create(const char *path) {
|
499
|
-
agooPage
|
499
|
+
agooPage p = (agooPage)AGOO_MALLOC(sizeof(struct _agooPage));
|
500
500
|
|
501
501
|
if (NULL != p) {
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
502
|
+
p->resp = NULL;
|
503
|
+
if (NULL == path) {
|
504
|
+
p->path = NULL;
|
505
|
+
} else {
|
506
|
+
if (NULL == (p->path = AGOO_STRDUP(path))) {
|
507
|
+
AGOO_FREE(p);
|
508
|
+
return NULL;
|
509
|
+
}
|
510
|
+
}
|
511
|
+
p->mtime = 0;
|
512
|
+
p->last_check = 0.0;
|
513
|
+
p->immutable = false;
|
514
514
|
}
|
515
515
|
return p;
|
516
516
|
}
|
517
517
|
|
518
518
|
agooPage
|
519
519
|
agoo_page_immutable(agooErr err, const char *path, const char *content, int clen) {
|
520
|
-
agooPage
|
521
|
-
const char
|
522
|
-
char
|
523
|
-
long
|
524
|
-
int
|
525
|
-
int
|
526
|
-
long
|
527
|
-
HeadRule
|
520
|
+
agooPage p = (agooPage)AGOO_MALLOC(sizeof(struct _agooPage));
|
521
|
+
const char *mime = path_mime(path);
|
522
|
+
char *rel_path = NULL;
|
523
|
+
long msize;
|
524
|
+
int cnt;
|
525
|
+
int plen = 0;
|
526
|
+
long hlen = 0;
|
527
|
+
HeadRule hr;
|
528
528
|
|
529
529
|
if (NULL == p) {
|
530
|
-
|
531
|
-
|
530
|
+
AGOO_ERR_MEM(err, "Page");
|
531
|
+
return NULL;
|
532
532
|
}
|
533
533
|
if (NULL == path) {
|
534
|
-
|
534
|
+
p->path = NULL;
|
535
535
|
} else {
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
536
|
+
if (NULL == (p->path = AGOO_STRDUP(path))) {
|
537
|
+
AGOO_FREE(p);
|
538
|
+
return NULL;
|
539
|
+
}
|
540
|
+
plen = (int)strlen(path);
|
541
|
+
if (NULL != cache.root) {
|
542
|
+
int rlen = (int)strlen(cache.root);
|
543
|
+
|
544
|
+
if (0 == strncmp(cache.root, p->path, rlen) && '/' == p->path[rlen]) {
|
545
|
+
rel_path = p->path + rlen + 1;
|
546
|
+
} else {
|
547
|
+
rel_path = NULL;
|
548
|
+
}
|
549
|
+
}
|
550
550
|
}
|
551
551
|
p->mtime = 0;
|
552
552
|
p->last_check = 0.0;
|
553
553
|
p->immutable = true;
|
554
554
|
|
555
555
|
if (NULL == mime) {
|
556
|
-
|
556
|
+
mime = "text/html";
|
557
557
|
}
|
558
558
|
if (0 == clen) {
|
559
|
-
|
559
|
+
clen = (int)strlen(content);
|
560
560
|
}
|
561
561
|
for (hr = cache.head_rules; NULL != hr; hr = hr->next) {
|
562
|
-
|
563
|
-
|
564
|
-
|
562
|
+
if (head_rule_match(hr, rel_path, mime)) {
|
563
|
+
hlen += hr->len;
|
564
|
+
}
|
565
565
|
}
|
566
566
|
// Format size plus space for the length, the mime type, and some
|
567
567
|
// padding. Then add the content length.
|
568
568
|
msize = sizeof(page_fmt) + 60 + clen;
|
569
569
|
if (NULL == (p->resp = agoo_text_allocate((int)msize))) {
|
570
|
-
|
571
|
-
|
572
|
-
|
570
|
+
AGOO_ERR_MEM(err, "Page content");
|
571
|
+
AGOO_FREE(p);
|
572
|
+
return NULL;
|
573
573
|
}
|
574
574
|
if (0 < hlen) {
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
575
|
+
bool has_ct;
|
576
|
+
|
577
|
+
cnt = sprintf(p->resp->text, page_min_fmt, (long)clen); // HTTP/1.1 200 OK\r\nContent-Length: %ld\r\n
|
578
|
+
for (hr = cache.head_rules; NULL != hr; hr = hr->next) {
|
579
|
+
if (head_rule_match(hr, rel_path, mime)) {
|
580
|
+
cnt += sprintf(p->resp->text + cnt, "%s: %s\r\n", hr->key, hr->value);
|
581
|
+
if (0 == strcasecmp("Content-Type", hr->key)) {
|
582
|
+
has_ct = true;
|
583
|
+
}
|
584
|
+
}
|
585
|
+
}
|
586
|
+
if (!has_ct) {
|
587
|
+
cnt += sprintf(p->resp->text + cnt, "Content-Type: %s\r\n\r\n", mime);
|
588
|
+
} else {
|
589
|
+
strcpy(p->resp->text + cnt, "\r\n");
|
590
|
+
cnt += 2;
|
591
|
+
}
|
592
592
|
} else {
|
593
|
-
|
593
|
+
cnt = sprintf(p->resp->text, page_fmt, mime, (long)clen);
|
594
594
|
}
|
595
595
|
msize = cnt + clen;
|
596
596
|
memcpy(p->resp->text + cnt, content, clen);
|
@@ -611,19 +611,19 @@ close_return_false(FILE *f) {
|
|
611
611
|
|
612
612
|
static bool
|
613
613
|
update_contents(agooPage p) {
|
614
|
-
const char
|
615
|
-
char
|
616
|
-
char
|
617
|
-
int
|
618
|
-
long
|
619
|
-
struct stat
|
620
|
-
long
|
621
|
-
long
|
622
|
-
int
|
623
|
-
struct stat
|
624
|
-
agooText
|
625
|
-
FILE
|
626
|
-
HeadRule
|
614
|
+
const char *mime = path_mime(p->path);
|
615
|
+
char path[1024];
|
616
|
+
char *rel_path = NULL;
|
617
|
+
int plen = (int)strlen(p->path);
|
618
|
+
long size;
|
619
|
+
struct stat fattr;
|
620
|
+
long msize;
|
621
|
+
long hlen = 0;
|
622
|
+
int cnt;
|
623
|
+
struct stat fs;
|
624
|
+
agooText t;
|
625
|
+
FILE *f = fopen(p->path, "rb");
|
626
|
+
HeadRule hr;
|
627
627
|
|
628
628
|
strncpy(path, p->path, sizeof(path));
|
629
629
|
path[sizeof(path) - 1] = '\0';
|
@@ -631,104 +631,104 @@ update_contents(agooPage p) {
|
|
631
631
|
// fstat is called to get the file mode and verify it is a regular file or
|
632
632
|
// a symlink.
|
633
633
|
if (NULL != f) {
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
634
|
+
if (0 == fstat(fileno(f), &fs)) {
|
635
|
+
if (!S_ISREG(fs.st_mode) && !S_ISLNK(fs.st_mode)) {
|
636
|
+
fclose(f);
|
637
|
+
f = NULL;
|
638
|
+
}
|
639
|
+
} else {
|
640
|
+
return close_return_false(f);
|
641
|
+
}
|
642
642
|
}
|
643
643
|
if (NULL == f) {
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
644
|
+
// If not found how about with a /index.html added?
|
645
|
+
if (NULL == mime) {
|
646
|
+
int cnt;
|
647
|
+
|
648
|
+
if ('/' == p->path[plen - 1]) {
|
649
|
+
cnt = snprintf(path, sizeof(path), "%sindex.html", p->path);
|
650
|
+
} else {
|
651
|
+
cnt = snprintf(path, sizeof(path), "%s/index.html", p->path);
|
652
|
+
}
|
653
|
+
if ((int)sizeof(path) < cnt) {
|
654
|
+
return false;
|
655
|
+
}
|
656
|
+
if (NULL == (f = fopen(path, "rb"))) {
|
657
|
+
return false;
|
658
|
+
}
|
659
|
+
mime = "text/html";
|
660
|
+
} else {
|
661
|
+
return false;
|
662
|
+
}
|
663
663
|
}
|
664
664
|
if (NULL == mime) {
|
665
|
-
|
665
|
+
mime = "text/html";
|
666
666
|
}
|
667
667
|
if (0 != fseek(f, 0, SEEK_END)) {
|
668
|
-
|
668
|
+
return close_return_false(f);
|
669
669
|
}
|
670
670
|
if (0 > (size = ftell(f))) {
|
671
|
-
|
671
|
+
return close_return_false(f);
|
672
672
|
}
|
673
673
|
rewind(f);
|
674
674
|
|
675
675
|
if (NULL != cache.root) {
|
676
|
-
|
676
|
+
int rlen = (int)strlen(cache.root);
|
677
677
|
|
678
|
-
|
679
|
-
|
680
|
-
|
678
|
+
if (0 == strncmp(cache.root, path, rlen) && '/' == path[rlen]) {
|
679
|
+
rel_path = path + rlen + 1;
|
680
|
+
}
|
681
681
|
}
|
682
682
|
for (hr = cache.head_rules; NULL != hr; hr = hr->next) {
|
683
|
-
|
684
|
-
|
685
|
-
|
683
|
+
if (head_rule_match(hr, rel_path, mime)) {
|
684
|
+
hlen += hr->len;
|
685
|
+
}
|
686
686
|
}
|
687
687
|
// Format size plus space for the length, the mime type, and some
|
688
688
|
// padding. Then add the header rule and content length.
|
689
689
|
msize = sizeof(page_fmt) + 60 + size + hlen;
|
690
690
|
if (NULL == (t = agoo_text_allocate((int)msize))) {
|
691
|
-
|
691
|
+
return close_return_false(f);
|
692
692
|
}
|
693
693
|
if (0 < hlen) {
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
694
|
+
bool has_ct = false;
|
695
|
+
|
696
|
+
cnt = sprintf(t->text, page_min_fmt, size); // HTTP/1.1 200 OK\r\nContent-Length: %ld\r\n
|
697
|
+
for (hr = cache.head_rules; NULL != hr; hr = hr->next) {
|
698
|
+
if (head_rule_match(hr, rel_path, mime)) {
|
699
|
+
cnt += sprintf(t->text + cnt, "%s: %s\r\n", hr->key, hr->value);
|
700
|
+
if (0 == strcasecmp("Content-Type", hr->key)) {
|
701
|
+
has_ct = true;
|
702
|
+
}
|
703
|
+
}
|
704
|
+
}
|
705
|
+
if (!has_ct) {
|
706
|
+
cnt += sprintf(t->text + cnt, "Content-Type: %s\r\n\r\n", mime);
|
707
|
+
} else {
|
708
|
+
strcpy(t->text + cnt, "\r\n");
|
709
|
+
cnt += 2;
|
710
|
+
}
|
711
711
|
} else {
|
712
|
-
|
712
|
+
cnt = sprintf(t->text, page_fmt, mime, size);
|
713
713
|
}
|
714
714
|
msize = cnt + size;
|
715
715
|
if (0 < size) {
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
716
|
+
if (size != (long)fread(t->text + cnt, 1, size, f)) {
|
717
|
+
agoo_text_release(t);
|
718
|
+
return close_return_false(f);
|
719
|
+
}
|
720
720
|
}
|
721
721
|
fclose(f);
|
722
722
|
t->text[msize] = '\0';
|
723
723
|
t->len = msize;
|
724
724
|
if (0 == stat(p->path, &fattr)) {
|
725
|
-
|
725
|
+
p->mtime = fattr.st_mtime;
|
726
726
|
} else {
|
727
|
-
|
727
|
+
p->mtime = 0;
|
728
728
|
}
|
729
729
|
if (NULL != p->resp) {
|
730
|
-
|
731
|
-
|
730
|
+
agoo_text_release(p->resp);
|
731
|
+
p->resp = NULL;
|
732
732
|
}
|
733
733
|
p->resp = t;
|
734
734
|
agoo_text_ref(p->resp);
|
@@ -739,73 +739,73 @@ update_contents(agooPage p) {
|
|
739
739
|
|
740
740
|
static void
|
741
741
|
agoo_page_remove(agooPage p) {
|
742
|
-
int
|
743
|
-
int64_t
|
744
|
-
Slot
|
745
|
-
Slot
|
746
|
-
Slot
|
742
|
+
int len = (int)strlen(p->path);
|
743
|
+
int64_t h = calc_hash(p->path, &len);
|
744
|
+
Slot *bucket = get_bucketp(h);
|
745
|
+
Slot s;
|
746
|
+
Slot prev = NULL;
|
747
747
|
|
748
748
|
for (s = *bucket; NULL != s; s = s->next) {
|
749
|
-
|
750
|
-
|
749
|
+
if (h == (int64_t)s->hash && len == (int)s->klen &&
|
750
|
+
((0 <= len && len <= MAX_KEY_UNIQ) || 0 == strncmp(s->key, p->path, len))) {
|
751
751
|
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
752
|
+
if (NULL == prev) {
|
753
|
+
*bucket = s->next;
|
754
|
+
} else {
|
755
|
+
prev->next = s->next;
|
756
|
+
}
|
757
|
+
agoo_page_destroy(s->value);
|
758
|
+
AGOO_FREE(s);
|
759
759
|
|
760
|
-
|
761
|
-
|
762
|
-
|
760
|
+
break;
|
761
|
+
}
|
762
|
+
prev = s;
|
763
763
|
}
|
764
764
|
}
|
765
765
|
|
766
766
|
static agooPage
|
767
767
|
page_check(agooErr err, agooPage page) {
|
768
768
|
if (!page->immutable) {
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
769
|
+
double now = dtime();
|
770
|
+
|
771
|
+
if (page->last_check + PAGE_RECHECK_TIME < now) {
|
772
|
+
struct stat fattr;
|
773
|
+
|
774
|
+
if (0 == stat(page->path, &fattr) && page->mtime != fattr.st_mtime) {
|
775
|
+
update_contents(page);
|
776
|
+
if (NULL == page->resp) {
|
777
|
+
agoo_page_remove(page);
|
778
|
+
agoo_err_set(err, AGOO_ERR_NOT_FOUND, "not found.");
|
779
|
+
return NULL;
|
780
|
+
}
|
781
|
+
}
|
782
|
+
page->last_check = now;
|
783
|
+
}
|
784
784
|
}
|
785
785
|
return page;
|
786
786
|
}
|
787
787
|
|
788
788
|
agooPage
|
789
789
|
agoo_page_get(agooErr err, const char *path, int plen, const char *root) {
|
790
|
-
agooPage
|
790
|
+
agooPage page = NULL;
|
791
791
|
|
792
792
|
if (NULL != strstr(path, "../")) {
|
793
|
-
|
793
|
+
return NULL;
|
794
794
|
}
|
795
795
|
if (NULL != root) {
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
796
|
+
char full_path[2048];
|
797
|
+
char *s = stpcpy(full_path, root);
|
798
|
+
|
799
|
+
if (NULL != strstr(path, "../")) {
|
800
|
+
return NULL;
|
801
|
+
}
|
802
|
+
if ((int)sizeof(full_path) <= plen + (s - full_path)) {
|
803
|
+
AGOO_ERR_MEM(err, "Page path");
|
804
|
+
return NULL;
|
805
|
+
}
|
806
|
+
if ('/' != *(s - 1) && '/' != *path) {
|
807
|
+
*s++ = '/';
|
808
|
+
}
|
809
809
|
// TBD if path has % then ...
|
810
810
|
if (NULL != memchr(path, '%', plen)) {
|
811
811
|
const char *pend = path + plen;
|
@@ -823,44 +823,44 @@ agoo_page_get(agooErr err, const char *path, int plen, const char *root) {
|
|
823
823
|
strncpy(s, path, plen);
|
824
824
|
s += plen;
|
825
825
|
}
|
826
|
-
|
826
|
+
*s = '\0';
|
827
827
|
plen = (int)(s - full_path);
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
828
|
+
if (NULL == (page = cache_root_get(full_path, plen))) {
|
829
|
+
if (NULL != cache.root) {
|
830
|
+
agooPage old;
|
831
|
+
|
832
|
+
if (NULL == (page = agoo_page_create(full_path))) {
|
833
|
+
AGOO_ERR_MEM(err, "Page");
|
834
|
+
return NULL;
|
835
|
+
}
|
836
|
+
if (!update_contents(page) || NULL == page->resp) {
|
837
|
+
agoo_page_destroy(page);
|
838
|
+
agoo_err_set(err, AGOO_ERR_NOT_FOUND, "not found.");
|
839
|
+
return NULL;
|
840
|
+
}
|
841
|
+
if (NULL != (old = cache_root_set(full_path, plen, page))) {
|
842
|
+
agoo_page_destroy(old);
|
843
|
+
}
|
844
|
+
}
|
845
|
+
} else {
|
846
|
+
page = page_check(err, page);
|
847
|
+
}
|
848
848
|
} else {
|
849
|
-
|
849
|
+
if (NULL == (page = cache_get(path, plen))) {
|
850
850
|
bool has_percent = NULL != memchr(path, '%', plen);
|
851
851
|
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
852
|
+
if (NULL != cache.root || has_percent) {
|
853
|
+
agooPage old;
|
854
|
+
char full_path[2048];
|
855
|
+
char *s = stpcpy(full_path, cache.root);
|
856
|
+
|
857
|
+
if ('/' != *(s - 1) && '/' != *path) {
|
858
|
+
*s++ = '/';
|
859
|
+
}
|
860
|
+
if ((int)sizeof(full_path) <= plen + (s - full_path)) {
|
861
|
+
AGOO_ERR_MEM(err, "Page path");
|
862
|
+
return NULL;
|
863
|
+
}
|
864
864
|
if (has_percent) {
|
865
865
|
const char *pend = path + plen;
|
866
866
|
const char *pp = path;
|
@@ -878,150 +878,150 @@ agoo_page_get(agooErr err, const char *path, int plen, const char *root) {
|
|
878
878
|
strncpy(s, path, plen);
|
879
879
|
s[plen] = '\0';
|
880
880
|
}
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
881
|
+
if (NULL == (page = agoo_page_create(full_path))) { // TBD full_path or original path?
|
882
|
+
AGOO_ERR_MEM(err, "Page");
|
883
|
+
return NULL;
|
884
|
+
}
|
885
885
|
plen = (int)strlen(full_path);
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
886
|
+
if (!update_contents(page) || NULL == page->resp) {
|
887
|
+
agoo_page_destroy(page);
|
888
|
+
agoo_err_set(err, AGOO_ERR_NOT_FOUND, "not found.");
|
889
|
+
return NULL;
|
890
|
+
}
|
891
891
|
// Cache key is the original path/plen.
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
892
|
+
if (NULL != (old = cache_set(path, plen, page))) {
|
893
|
+
agoo_page_destroy(old);
|
894
|
+
}
|
895
|
+
}
|
896
|
+
} else {
|
897
|
+
page = page_check(err, page);
|
898
|
+
}
|
899
899
|
}
|
900
900
|
return page;
|
901
901
|
}
|
902
902
|
|
903
903
|
agooPage
|
904
904
|
agoo_group_get(agooErr err, const char *path, int plen) {
|
905
|
-
agooPage
|
906
|
-
agooGroup
|
907
|
-
char
|
908
|
-
char
|
909
|
-
agooDir
|
905
|
+
agooPage page = NULL;
|
906
|
+
agooGroup g = NULL;
|
907
|
+
char full_path[2048];
|
908
|
+
char *s = NULL;
|
909
|
+
agooDir d;
|
910
910
|
|
911
911
|
if (NULL != strstr(path, "../")) {
|
912
|
-
|
912
|
+
return NULL;
|
913
913
|
}
|
914
914
|
for (g = cache.groups; NULL != g; g = g->next) {
|
915
|
-
|
916
|
-
|
917
|
-
|
915
|
+
if (g->plen < plen && 0 == strncmp(path, g->path, g->plen) && '/' == path[g->plen]) {
|
916
|
+
break;
|
917
|
+
}
|
918
918
|
}
|
919
919
|
if (NULL == g) {
|
920
|
-
|
920
|
+
return NULL;
|
921
921
|
}
|
922
922
|
for (d = g->dirs; NULL != d; d = d->next) {
|
923
|
-
|
924
|
-
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
|
931
|
-
|
932
|
-
|
923
|
+
if ((int)sizeof(full_path) <= d->plen + plen) {
|
924
|
+
continue;
|
925
|
+
}
|
926
|
+
s = stpcpy(full_path, d->path);
|
927
|
+
strncpy(s, path + g->plen, plen - g->plen);
|
928
|
+
s += plen - g->plen;
|
929
|
+
*s = '\0';
|
930
|
+
if (NULL != (page = cache_get(full_path, (int)(s - full_path)))) {
|
931
|
+
break;
|
932
|
+
}
|
933
933
|
}
|
934
934
|
if (NULL == page) {
|
935
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
|
943
|
-
|
944
|
-
|
945
|
-
|
946
|
-
|
947
|
-
|
948
|
-
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
|
968
|
-
|
935
|
+
for (d = g->dirs; NULL != d; d = d->next) {
|
936
|
+
if ((int)sizeof(full_path) <= d->plen + plen) {
|
937
|
+
continue;
|
938
|
+
}
|
939
|
+
s = stpcpy(full_path, d->path);
|
940
|
+
strncpy(s, path + g->plen, plen - g->plen);
|
941
|
+
s += plen - g->plen;
|
942
|
+
*s = '\0';
|
943
|
+
if (0 == access(full_path, R_OK)) {
|
944
|
+
break;
|
945
|
+
}
|
946
|
+
}
|
947
|
+
if (NULL == d) {
|
948
|
+
return NULL;
|
949
|
+
}
|
950
|
+
plen = (int)(s - full_path);
|
951
|
+
path = full_path;
|
952
|
+
if (NULL == (page = cache_get(path, plen))) {
|
953
|
+
agooPage old;
|
954
|
+
|
955
|
+
if (NULL == (page = agoo_page_create(path))) {
|
956
|
+
AGOO_ERR_MEM(err, "Page");
|
957
|
+
return NULL;
|
958
|
+
}
|
959
|
+
if (!update_contents(page) || NULL == page->resp) {
|
960
|
+
agoo_page_destroy(page);
|
961
|
+
agoo_err_set(err, AGOO_ERR_NOT_FOUND, "not found.");
|
962
|
+
return NULL;
|
963
|
+
}
|
964
|
+
if (NULL != (old = cache_set(path, plen, page))) {
|
965
|
+
agoo_page_destroy(old);
|
966
|
+
}
|
967
|
+
}
|
968
|
+
return page;
|
969
969
|
}
|
970
970
|
return page_check(err, page);
|
971
971
|
}
|
972
972
|
|
973
973
|
agooGroup
|
974
974
|
agoo_group_create(const char *path) {
|
975
|
-
agooGroup
|
975
|
+
agooGroup g = (agooGroup)AGOO_MALLOC(sizeof(struct _agooGroup));
|
976
976
|
|
977
977
|
if (NULL != g) {
|
978
|
-
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
983
|
-
|
984
|
-
|
985
|
-
|
978
|
+
if (NULL == (g->path = AGOO_STRDUP(path))) {
|
979
|
+
AGOO_FREE(g);
|
980
|
+
return NULL;
|
981
|
+
}
|
982
|
+
g->plen = (int)strlen(path);
|
983
|
+
g->dirs = NULL;
|
984
|
+
g->next = cache.groups;
|
985
|
+
cache.groups = g;
|
986
986
|
}
|
987
987
|
return g;
|
988
988
|
}
|
989
989
|
|
990
990
|
agooDir
|
991
991
|
agoo_group_add(agooErr err, agooGroup g, const char *dir) {
|
992
|
-
agooDir
|
992
|
+
agooDir d = (agooDir)AGOO_MALLOC(sizeof(struct _agooDir));
|
993
993
|
|
994
994
|
if (NULL != d) {
|
995
|
-
|
996
|
-
|
997
|
-
|
998
|
-
|
999
|
-
|
1000
|
-
|
1001
|
-
|
995
|
+
if (NULL == (d->path = AGOO_STRDUP(dir))) {
|
996
|
+
AGOO_ERR_MEM(err, "Group");
|
997
|
+
return NULL;
|
998
|
+
}
|
999
|
+
d->plen = (int)strlen(dir);
|
1000
|
+
d->next = g->dirs;
|
1001
|
+
g->dirs = d;
|
1002
1002
|
}
|
1003
1003
|
return d;
|
1004
1004
|
}
|
1005
1005
|
|
1006
1006
|
int
|
1007
1007
|
agoo_header_rule(agooErr err, const char *path, const char *mime, const char *key, const char *value) {
|
1008
|
-
HeadRule
|
1008
|
+
HeadRule hr;
|
1009
1009
|
|
1010
1010
|
if (0 == strcasecmp("Content-Length", key)) {
|
1011
|
-
|
1011
|
+
return agoo_err_set(err, AGOO_ERR_ARG, "Can not mask Content-Length with a header rule.");
|
1012
1012
|
}
|
1013
1013
|
if (NULL == (hr = (HeadRule)AGOO_CALLOC(1, sizeof(struct _headRule)))) {
|
1014
|
-
|
1014
|
+
return AGOO_ERR_MEM(err, "Header Rule");
|
1015
1015
|
}
|
1016
1016
|
if (NULL == (hr->path = AGOO_STRDUP(path)) ||
|
1017
|
-
|
1018
|
-
|
1019
|
-
|
1017
|
+
NULL == (hr->key = AGOO_STRDUP(key)) ||
|
1018
|
+
NULL == (hr->value = AGOO_STRDUP(value))) {
|
1019
|
+
goto ERROR;
|
1020
1020
|
}
|
1021
1021
|
if ('*' == *mime && '\0' == mime[1]) {
|
1022
|
-
|
1022
|
+
hr->mime = NULL;
|
1023
1023
|
} else if (NULL == (hr->mime = AGOO_STRDUP(mime))) {
|
1024
|
-
|
1024
|
+
goto ERROR;
|
1025
1025
|
}
|
1026
1026
|
hr->len = (int)strlen(hr->key) + (int)strlen(hr->value) + 4;
|
1027
1027
|
hr->next = cache.head_rules;
|