agoo 0.9.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of agoo might be problematic. Click here for more details.

data/ext/agoo/log.h ADDED
@@ -0,0 +1,106 @@
1
+ // Copyright 2018 by Peter Ohler, All Rights Reserved
2
+
3
+ #ifndef __AGOO_LOG_H__
4
+ #define __AGOO_LOG_H__
5
+
6
+ #include <netdb.h>
7
+ #include <pthread.h>
8
+ #include <stdarg.h>
9
+ #include <stdatomic.h>
10
+ #include <stdbool.h>
11
+ #include <stdint.h>
12
+ #include <stdio.h>
13
+
14
+ #include <ruby.h>
15
+
16
+ #include "err.h"
17
+
18
+ typedef enum {
19
+ FATAL = 0,
20
+ ERROR = 1,
21
+ WARN = 2,
22
+ INFO = 3,
23
+ DEBUG = 4,
24
+ UNKNOWN = 5,
25
+ } LogLevel;
26
+
27
+ typedef struct _Color {
28
+ const char *name;
29
+ const char *ansi;
30
+ } *Color;
31
+
32
+ #define BLACK "black"
33
+ #define RED "red"
34
+ #define GREEN "green"
35
+ #define YELLOW "yellow"
36
+ #define BLUE "blue"
37
+ #define MAGENTA "magenta"
38
+ #define CYAN "cyan"
39
+ #define WHITE "white"
40
+ #define GRAY "gray"
41
+ #define DARK_RED "dark_red"
42
+ #define DARK_GREEN "dark_green"
43
+ #define BROWN "brown"
44
+ #define DARK_BLUE "dark_blue"
45
+ #define PURPLE "purple"
46
+ #define DARK_CYAN "dark_cyan"
47
+
48
+ typedef struct _Log *Log;
49
+
50
+ typedef struct _LogCat {
51
+ struct _LogCat *next;
52
+ Log log;
53
+ char label[32];
54
+ Color color;
55
+ int level;
56
+ bool on;
57
+ } *LogCat;
58
+
59
+ typedef struct _LogEntry {
60
+ LogCat cat;
61
+ int64_t when; // nano UTC
62
+ char *whatp;
63
+ char what[104];
64
+ volatile bool ready;
65
+ } *LogEntry;
66
+
67
+ struct _Log {
68
+ LogCat cats;
69
+ char dir[1024];
70
+ FILE *file; // current output file
71
+ int max_files;
72
+ int max_size;
73
+ long size; // current file size
74
+ pthread_t thread;
75
+ volatile bool done;
76
+ bool console; // if true print log message to stdout
77
+ bool classic; // classic in stdout
78
+ bool colorize; // color in stdout
79
+ int zone; // timezone offset from GMT in seconds
80
+ int64_t day_start;
81
+ int64_t day_end;
82
+ char day_buf[16];
83
+
84
+ LogEntry q;
85
+ LogEntry end;
86
+ _Atomic(LogEntry) head;
87
+ _Atomic(LogEntry) tail;
88
+ atomic_flag push_lock;
89
+ atomic_int wait_state;
90
+ int rsock;
91
+ int wsock;
92
+ };
93
+
94
+ extern int log_init(Err err, Log log, VALUE cfg);
95
+ extern void log_close(Log log);
96
+ extern bool log_flush(Log log, double timeout);
97
+
98
+ extern void log_cat_reg(Log log, LogCat cat, const char *label, LogLevel level, const char *color, bool on);
99
+ extern void log_cat_on(Log log, const char *label, bool on);
100
+ extern LogCat log_cat_find(Log log, const char *label);
101
+
102
+ // Function to call to make a log entry.
103
+ extern void log_cat(LogCat cat, const char *fmt, ...);
104
+ extern void log_catv(LogCat cat, const char *fmt, va_list ap);
105
+
106
+ #endif /* __AGOO_LOG_H__ */
@@ -0,0 +1,30 @@
1
+ // Copyright 2018 by Peter Ohler, All Rights Reserved
2
+
3
+ #ifndef __AGOO_LOG_QUEUE_H__
4
+ #define __AGOO_LOG_QUEUE_H__
5
+
6
+ #include <stdatomic.h>
7
+ #include <stdbool.h>
8
+
9
+ #include "val.h"
10
+
11
+ typedef struct _LogQueue {
12
+ opoMsg *q;
13
+ opoMsg *end;
14
+ _Atomic(opoMsg*) head;
15
+ _Atomic(opoMsg*) tail;
16
+ atomic_flag pop_lock; // set to true when ppo in progress
17
+ atomic_int wait_state;
18
+ int rsock;
19
+ int wsock;
20
+ } *LogQueue;
21
+
22
+ extern void queue_init(Queue q, size_t qsize);
23
+
24
+ extern void queue_cleanup(Queue q);
25
+ extern void queue_push(Queue q, opoMsg item);
26
+ extern opoMsg queue_pop(Queue q, double timeout);
27
+ extern bool queue_empty(Queue q);
28
+ extern int queue_count(Queue q);
29
+
30
+ #endif /* __AGOO_LOG_QUEUE_H__ */
data/ext/agoo/page.c ADDED
@@ -0,0 +1,342 @@
1
+ // Copyright 2016, 2018 by Peter Ohler, All Rights Reserved
2
+
3
+ #include <string.h>
4
+ #include <stdio.h>
5
+ #include <stdlib.h>
6
+ #include <sys/stat.h>
7
+
8
+ #include "dtime.h"
9
+ #include "page.h"
10
+
11
+ #define PAGE_RECHECK_TIME 5.0
12
+ #define MAX_KEY_UNIQ 9
13
+
14
+ typedef struct _Mime {
15
+ const char *suffix;
16
+ const char *type;
17
+ } *Mime;
18
+
19
+ static struct _Mime mime_map[] = {
20
+ { "css", "text/css" },
21
+ { "eot", "application/vnd.ms-fontobject" },
22
+ { "es5", "application/javascript" },
23
+ { "es6", "application/javascript" },
24
+ { "gif", "image/gif" },
25
+ { "html", "text/html" },
26
+ { "ico", "image/x-icon" },
27
+ { "jpeg", "image/jpeg" },
28
+ { "jpg", "image/jpeg" },
29
+ { "js", "application/javascript" },
30
+ { "json", "application/json" },
31
+ { "png", "image/png" },
32
+ { "sse", "text/plain" },
33
+ { "svg", "image/svg+xml" },
34
+ { "ttf", "application/font-sfnt" },
35
+ { "txt", "text/plain" },
36
+ { "woff", "application/font-woff" },
37
+ { "woff2", "font/woff2" },
38
+ { NULL, NULL }
39
+ };
40
+
41
+ static const char page_fmt[] = "HTTP/1.1 200 OK\r\nContent-Type: %s\r\nContent-Length: %ld\r\n\r\n";
42
+
43
+ static uint64_t
44
+ calc_hash(const char *key, int *lenp) {
45
+ int len = 0;
46
+ int klen = *lenp;
47
+ uint64_t h = 0;
48
+ bool special = false;
49
+ const uint8_t *k = (const uint8_t*)key;
50
+
51
+ for (; len < klen; k++) {
52
+ // narrow to most used range of 0x4D (77) in size
53
+ if (*k < 0x2D || 0x7A < *k) {
54
+ special = true;
55
+ }
56
+ // fast, just spread it out
57
+ h = 77 * h + (*k - 0x2D);
58
+ len++;
59
+ }
60
+
61
+ if (special) {
62
+ *lenp = -len;
63
+ } else {
64
+ *lenp = len;
65
+ }
66
+ return h;
67
+ }
68
+
69
+ // Buckets are a twist on the hash to mix it up a bit. Odd shifts and XORs.
70
+ static Slot*
71
+ get_bucketp(Cache cache, uint64_t h) {
72
+ return cache->buckets + (PAGE_BUCKET_MASK & (h ^ (h << 5) ^ (h >> 7)));
73
+ }
74
+
75
+ void
76
+ cache_init(Cache cache) {
77
+ memset(cache, 0, sizeof(struct _Cache));
78
+ }
79
+
80
+ void
81
+ cache_destroy(Cache cache) {
82
+ Slot *sp = cache->buckets;
83
+ Slot s;
84
+ Slot n;
85
+
86
+ for (int i = PAGE_BUCKET_SIZE; 0 < i; i--, sp++) {
87
+ for (s = *sp; NULL != s; s = n) {
88
+ n = s->next;
89
+ free(s);
90
+ }
91
+ *sp = NULL;
92
+ }
93
+ free(cache);
94
+ }
95
+
96
+ Page
97
+ cache_get(Cache cache, const char *key, int klen) {
98
+ int len = klen;
99
+ int64_t h = calc_hash(key, &len);
100
+ Slot *bucket = get_bucketp(cache, h);
101
+ Slot s;
102
+ Page v = NULL;
103
+
104
+ for (s = *bucket; NULL != s; s = s->next) {
105
+ if (h == (int64_t)s->hash && len == (int)s->klen &&
106
+ ((0 <= len && len <= MAX_KEY_UNIQ) || 0 == strncmp(s->key, key, klen))) {
107
+ v = s->value;
108
+ break;
109
+ }
110
+ }
111
+ return v;
112
+ }
113
+
114
+ Page
115
+ cache_set(Cache cache, const char *key, int klen, Page value) {
116
+ int len = klen;
117
+ int64_t h = calc_hash(key, &len);
118
+ Slot *bucket = get_bucketp(cache, h);
119
+ Slot s;
120
+ Page old = NULL;
121
+
122
+ if (MAX_KEY_LEN < len) {
123
+ return value;
124
+ }
125
+ for (s = *bucket; NULL != s; s = s->next) {
126
+ if (h == (int64_t)s->hash && len == s->klen &&
127
+ ((0 <= len && len <= MAX_KEY_UNIQ) || 0 == strcmp(s->key, key))) {
128
+ if (h == (int64_t)s->hash && len == s->klen &&
129
+ ((0 <= len && len <= MAX_KEY_UNIQ) || 0 == strcmp(s->key, key))) {
130
+ old = s->value;
131
+ // replace
132
+ s->value = value;
133
+
134
+ return old;
135
+ }
136
+ }
137
+ }
138
+ if (NULL == (s = (Slot)malloc(sizeof(struct _Slot)))) {
139
+ return value;
140
+ }
141
+ s->hash = h;
142
+ s->klen = len;
143
+ if (NULL == key) {
144
+ *s->key = '\0';
145
+ } else {
146
+ strcpy(s->key, key);
147
+ }
148
+ s->value = value;
149
+ s->next = *bucket;
150
+ *bucket = s;
151
+
152
+ return old;
153
+ }
154
+
155
+ // The page resp contents point to the page resp msg to save memory and reduce
156
+ // allocations.
157
+ Page
158
+ page_create(const char *path) {
159
+ Page p = (Page)malloc(sizeof(struct _Page));
160
+
161
+ if (NULL != p) {
162
+ p->resp = NULL;
163
+ if (NULL == path) {
164
+ p->path = NULL;
165
+ } else {
166
+ p->path = strdup(path);
167
+ }
168
+ p->mtime = 0;
169
+ p->last_check = 0.0;
170
+ }
171
+ return p;
172
+ }
173
+
174
+ void
175
+ page_destroy(Page p) {
176
+ if (NULL != p->resp) {
177
+ text_release(p->resp);
178
+ p->resp = NULL;
179
+ }
180
+ free(p->path);
181
+ free(p);
182
+ }
183
+
184
+ static bool
185
+ update_contents(Page p) {
186
+ const char *mime = NULL;
187
+ int plen = strlen(p->path);
188
+ const char *suffix = p->path + plen - 1;
189
+ FILE *f;
190
+ long size;
191
+ struct stat fattr;
192
+ long msize;
193
+ char *msg;
194
+ int cnt;
195
+ struct stat fs;
196
+
197
+ for (; '.' != *suffix; suffix--) {
198
+ if (suffix <= p->path) {
199
+ suffix = NULL;
200
+ break;
201
+ }
202
+ }
203
+ if (NULL != suffix) {
204
+ Mime m;
205
+
206
+ suffix++;
207
+ for (m = mime_map; NULL != m->suffix; m++) {
208
+ if (0 == strcasecmp(m->suffix, suffix)) {
209
+ break;
210
+ }
211
+ }
212
+ if (NULL == m) {
213
+ mime = "text/plain";
214
+ } else {
215
+ mime = m->type;
216
+ }
217
+ } else {
218
+ mime = "text/plain";
219
+ }
220
+
221
+ f = fopen(p->path, "rb");
222
+ // On linux a directory is opened by fopen (sometimes? all the time?) so
223
+ // fstat is called to get the file mode and verify it is a regular file or
224
+ // a symlink.
225
+ if (NULL != f) {
226
+ fstat(fileno(f), &fs);
227
+ if (!S_ISREG(fs.st_mode) && !S_ISLNK(fs.st_mode)) {
228
+ fclose(f);
229
+ f = NULL;
230
+ }
231
+ }
232
+ if (NULL == f) {
233
+ // If not found how about with a /index.html added?
234
+ if (NULL == suffix) {
235
+ char path[1024];
236
+ int cnt;
237
+
238
+ if ('/' == p->path[plen - 1]) {
239
+ cnt = snprintf(path, sizeof(path), "%sindex.html", p->path);
240
+ } else {
241
+ cnt = snprintf(path, sizeof(path), "%s/index.html", p->path);
242
+ }
243
+ if ((int)sizeof(path) < cnt) {
244
+ return false;
245
+ }
246
+ if (NULL == (f = fopen(path, "rb"))) {
247
+ return false;
248
+ }
249
+ } else {
250
+ return false;
251
+ }
252
+ }
253
+ if (0 != fseek(f, 0, SEEK_END)) {
254
+ fclose(f);
255
+ return false;
256
+ }
257
+ if (0 >= (size = ftell(f))) {
258
+ fclose(f);
259
+ return false;
260
+ }
261
+ rewind(f);
262
+ // Format size plus space for the length, the mime type, and some
263
+ // padding. Then add the content length.
264
+ msize = sizeof(page_fmt) + 60 + size;
265
+ if (NULL == (msg = (char*)malloc(msize))) {
266
+ return false;
267
+ }
268
+ cnt = sprintf(msg, page_fmt, mime, size);
269
+
270
+ msize = cnt + size;
271
+ if (size != (long)fread(msg + cnt, 1, size, f)) {
272
+ fclose(f);
273
+ free(msg);
274
+ return false;
275
+ }
276
+ fclose(f);
277
+ msg[msize] = '\0';
278
+ if (0 == stat(p->path, &fattr)) {
279
+ p->mtime = fattr.st_mtime;
280
+ } else {
281
+ p->mtime = 0;
282
+ }
283
+ if (NULL != p->resp) {
284
+ text_release(p->resp);
285
+ p->resp = NULL;
286
+ }
287
+ p->resp = text_create(msg, msize);
288
+ text_ref(p->resp);
289
+ p->last_check = dtime();
290
+
291
+ return true;
292
+ }
293
+
294
+ Page
295
+ page_get(Err err, Cache cache, const char *dir, const char *path, int plen) {
296
+ Page page;
297
+
298
+ if (NULL == (page = cache_get(cache, path, plen))) {
299
+ Page old;
300
+ char full_path[2048];
301
+ char *s = stpcpy(full_path, dir);
302
+
303
+ if ('/' != *dir && '/' != *path) {
304
+ *s++ = '/';
305
+ }
306
+ if ((int)sizeof(full_path) <= plen + (s - full_path)) {
307
+ err_set(err, ERR_MEMORY, "Failed to allocate memory for page path.");
308
+ return NULL;
309
+ }
310
+ strncpy(s, path, plen);
311
+ s[plen] = '\0';
312
+ if (NULL == (page = page_create(full_path))) {
313
+ err_set(err, ERR_MEMORY, "Failed to allocate memory for Page.");
314
+ return NULL;
315
+ }
316
+ if (!update_contents(page) || NULL == page->resp) {
317
+ page_destroy(page);
318
+ err_set(err, ERR_NOT_FOUND, "not found.");
319
+ return NULL;
320
+ }
321
+ if (NULL != (old = cache_set(cache, path, plen, page))) {
322
+ page_destroy(old);
323
+ }
324
+ } else {
325
+ double now = dtime();
326
+
327
+ if (page->last_check + PAGE_RECHECK_TIME < now) {
328
+ struct stat fattr;
329
+
330
+ if (0 == stat(page->path, &fattr) && page->mtime != fattr.st_mtime) {
331
+ update_contents(page);
332
+ if (NULL == page->resp) {
333
+ page_destroy(page);
334
+ err_set(err, ERR_NOT_FOUND, "not found.");
335
+ return NULL;
336
+ }
337
+ }
338
+ page->last_check = now;
339
+ }
340
+ }
341
+ return page;
342
+ }