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.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +61 -0
- data/ext/agoo/agoo.c +19 -0
- data/ext/agoo/con.c +515 -0
- data/ext/agoo/con.h +46 -0
- data/ext/agoo/dtime.c +52 -0
- data/ext/agoo/dtime.h +10 -0
- data/ext/agoo/err.c +78 -0
- data/ext/agoo/err.h +48 -0
- data/ext/agoo/error_stream.c +92 -0
- data/ext/agoo/error_stream.h +13 -0
- data/ext/agoo/extconf.rb +13 -0
- data/ext/agoo/hook.c +74 -0
- data/ext/agoo/hook.h +33 -0
- data/ext/agoo/http.c +617 -0
- data/ext/agoo/http.h +13 -0
- data/ext/agoo/log.c +497 -0
- data/ext/agoo/log.h +106 -0
- data/ext/agoo/log_queue.h +30 -0
- data/ext/agoo/page.c +342 -0
- data/ext/agoo/page.h +39 -0
- data/ext/agoo/queue.c +191 -0
- data/ext/agoo/queue.h +39 -0
- data/ext/agoo/request.c +563 -0
- data/ext/agoo/request.h +36 -0
- data/ext/agoo/res.c +38 -0
- data/ext/agoo/res.h +28 -0
- data/ext/agoo/response.c +271 -0
- data/ext/agoo/response.h +33 -0
- data/ext/agoo/server.c +891 -0
- data/ext/agoo/server.h +47 -0
- data/ext/agoo/text.c +66 -0
- data/ext/agoo/text.h +24 -0
- data/ext/agoo/types.h +18 -0
- data/lib/agoo.rb +9 -0
- data/lib/agoo/version.rb +5 -0
- data/test/base_handler_test.rb +170 -0
- data/test/log_test.rb +269 -0
- data/test/rack_handler_test.rb +147 -0
- data/test/static_test.rb +81 -0
- data/test/tests.rb +8 -0
- metadata +159 -0
data/ext/agoo/con.h
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
// Copyright (c) 2018, Peter Ohler, All rights reserved.
|
2
|
+
|
3
|
+
#ifndef __AGOO_CON_H__
|
4
|
+
#define __AGOO_CON_H__
|
5
|
+
|
6
|
+
#include <poll.h>
|
7
|
+
#include <stdbool.h>
|
8
|
+
#include <stdint.h>
|
9
|
+
|
10
|
+
#include "err.h"
|
11
|
+
#include "request.h"
|
12
|
+
#include "response.h"
|
13
|
+
#include "server.h"
|
14
|
+
|
15
|
+
#define MAX_HEADER_SIZE 8192
|
16
|
+
|
17
|
+
typedef struct _Con {
|
18
|
+
int sock;
|
19
|
+
struct pollfd *pp;
|
20
|
+
char id[32];
|
21
|
+
uint64_t iid;
|
22
|
+
char buf[MAX_HEADER_SIZE];
|
23
|
+
size_t bcnt;
|
24
|
+
|
25
|
+
ssize_t msize; // size of complete message
|
26
|
+
ssize_t mcnt; // how much has been read so far
|
27
|
+
|
28
|
+
ssize_t wcnt; // how much has been written
|
29
|
+
|
30
|
+
Server server;
|
31
|
+
double timeout;
|
32
|
+
bool closing;
|
33
|
+
Req req;
|
34
|
+
Res res_head;
|
35
|
+
Res res_tail;
|
36
|
+
|
37
|
+
//FEval eval;
|
38
|
+
} *Con;
|
39
|
+
|
40
|
+
extern Con con_create(Err err, Server server, int sock, uint64_t id);
|
41
|
+
extern void con_destroy(Con c);
|
42
|
+
extern const char* con_header_value(const char *header, int hlen, const char *key, int *vlen);
|
43
|
+
|
44
|
+
extern void* con_loop(void *ctx);
|
45
|
+
|
46
|
+
#endif /* __AGOO_CON_H__ */
|
data/ext/agoo/dtime.c
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
// Copyright 2009, 2015, 2016, 2018 by Peter Ohler, All Rights Reserved
|
2
|
+
|
3
|
+
#include <time.h>
|
4
|
+
#include <sys/time.h>
|
5
|
+
#include <errno.h>
|
6
|
+
|
7
|
+
#include "dtime.h"
|
8
|
+
|
9
|
+
#define MIN_SLEEP (1.0 / (double)CLOCKS_PER_SEC)
|
10
|
+
|
11
|
+
double
|
12
|
+
dtime() {
|
13
|
+
struct timeval tv;
|
14
|
+
struct timezone tz;
|
15
|
+
|
16
|
+
gettimeofday(&tv, &tz);
|
17
|
+
|
18
|
+
return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
|
19
|
+
}
|
20
|
+
|
21
|
+
double
|
22
|
+
dsleep(double t) {
|
23
|
+
struct timespec req, rem;
|
24
|
+
|
25
|
+
if (MIN_SLEEP > t) {
|
26
|
+
t = MIN_SLEEP;
|
27
|
+
}
|
28
|
+
req.tv_sec = (time_t)t;
|
29
|
+
req.tv_nsec = (long)(1000000000.0 * (t - (double)req.tv_sec));
|
30
|
+
if (nanosleep(&req, &rem) == -1 && EINTR == errno) {
|
31
|
+
return (double)rem.tv_sec + (double)rem.tv_nsec / 1000000000.0;
|
32
|
+
}
|
33
|
+
return 0.0;
|
34
|
+
}
|
35
|
+
|
36
|
+
double
|
37
|
+
dwait(double t) {
|
38
|
+
double end = dtime() + t;
|
39
|
+
|
40
|
+
if (MIN_SLEEP < t) {
|
41
|
+
struct timespec req, rem;
|
42
|
+
|
43
|
+
t -= MIN_SLEEP;
|
44
|
+
req.tv_sec = (time_t)t;
|
45
|
+
req.tv_nsec = (long)(1000000000.0 * (t - (double)req.tv_sec));
|
46
|
+
nanosleep(&req, &rem);
|
47
|
+
}
|
48
|
+
while (dtime() < end) {
|
49
|
+
continue;
|
50
|
+
}
|
51
|
+
return 0.0;
|
52
|
+
}
|
data/ext/agoo/dtime.h
ADDED
data/ext/agoo/err.c
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
// Copyright (c) 2018, Peter Ohler, All rights reserved.
|
2
|
+
|
3
|
+
#include <stdarg.h>
|
4
|
+
#include <stdio.h>
|
5
|
+
#include <string.h>
|
6
|
+
|
7
|
+
#include "err.h"
|
8
|
+
|
9
|
+
#ifdef PLATFORM_LINUX
|
10
|
+
#pragma GCC diagnostic ignored "-Wsuggest-attribute=format"
|
11
|
+
#endif
|
12
|
+
|
13
|
+
int
|
14
|
+
err_set(Err err, int code, const char *fmt, ...) {
|
15
|
+
va_list ap;
|
16
|
+
|
17
|
+
va_start(ap, fmt);
|
18
|
+
vsnprintf(err->msg, sizeof(err->msg), fmt, ap);
|
19
|
+
va_end(ap);
|
20
|
+
err->code = code;
|
21
|
+
|
22
|
+
return err->code;
|
23
|
+
}
|
24
|
+
|
25
|
+
int
|
26
|
+
err_no(Err err, const char *fmt, ...) {
|
27
|
+
int cnt = 0;
|
28
|
+
|
29
|
+
if (NULL != fmt) {
|
30
|
+
va_list ap;
|
31
|
+
|
32
|
+
va_start(ap, fmt);
|
33
|
+
cnt = vsnprintf(err->msg, sizeof(err->msg), fmt, ap);
|
34
|
+
va_end(ap);
|
35
|
+
}
|
36
|
+
if (cnt < (int)sizeof(err->msg) + 2 && 0 <= cnt) {
|
37
|
+
err->msg[cnt] = ' ';
|
38
|
+
cnt++;
|
39
|
+
strncpy(err->msg + cnt, strerror(errno), sizeof(err->msg) - cnt);
|
40
|
+
err->msg[sizeof(err->msg) - 1] = '\0';
|
41
|
+
}
|
42
|
+
err->code = errno;
|
43
|
+
|
44
|
+
return err->code;
|
45
|
+
}
|
46
|
+
|
47
|
+
void
|
48
|
+
err_clear(Err err) {
|
49
|
+
err->code = ERR_OK;
|
50
|
+
*err->msg = '\0';
|
51
|
+
}
|
52
|
+
|
53
|
+
const char*
|
54
|
+
err_str(ErrCode code) {
|
55
|
+
const char *str = NULL;
|
56
|
+
|
57
|
+
if (code <= ELAST) {
|
58
|
+
str = strerror(code);
|
59
|
+
}
|
60
|
+
if (NULL == str) {
|
61
|
+
switch (code) {
|
62
|
+
case ERR_PARSE: str = "parse error"; break;
|
63
|
+
case ERR_READ: str = "read failed"; break;
|
64
|
+
case ERR_WRITE: str = "write failed"; break;
|
65
|
+
case ERR_ARG: str = "invalid argument"; break;
|
66
|
+
case ERR_NOT_FOUND: str = "not found"; break;
|
67
|
+
case ERR_THREAD: str = "thread error"; break;
|
68
|
+
case ERR_NETWORK: str = "network error"; break;
|
69
|
+
case ERR_LOCK: str = "lock error"; break;
|
70
|
+
case ERR_FREE: str = "already freed"; break;
|
71
|
+
case ERR_IN_USE: str = "in use"; break;
|
72
|
+
case ERR_TOO_MANY: str = "too many"; break;
|
73
|
+
case ERR_TYPE: str = "type error"; break;
|
74
|
+
default: str = "unknown error"; break;
|
75
|
+
}
|
76
|
+
}
|
77
|
+
return str;
|
78
|
+
}
|
data/ext/agoo/err.h
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
// Copyright (c) 2018, Peter Ohler, All rights reserved.
|
2
|
+
|
3
|
+
#ifndef __AGOO_ERR_H__
|
4
|
+
#define __AGOO_ERR_H__
|
5
|
+
|
6
|
+
#include <errno.h>
|
7
|
+
|
8
|
+
#ifndef ELAST
|
9
|
+
#define ELAST 300
|
10
|
+
#endif
|
11
|
+
|
12
|
+
#define ERR_INIT { 0, { 0 } }
|
13
|
+
|
14
|
+
typedef enum {
|
15
|
+
ERR_OK = 0,
|
16
|
+
ERR_MEMORY = ENOMEM,
|
17
|
+
ERR_DENIED = EACCES,
|
18
|
+
ERR_IMPL = ENOSYS,
|
19
|
+
ERR_PARSE = ELAST + 1,
|
20
|
+
ERR_READ,
|
21
|
+
ERR_WRITE,
|
22
|
+
ERR_OVERFLOW,
|
23
|
+
ERR_ARG,
|
24
|
+
ERR_NOT_FOUND,
|
25
|
+
ERR_THREAD,
|
26
|
+
ERR_NETWORK,
|
27
|
+
ERR_LOCK,
|
28
|
+
ERR_FREE,
|
29
|
+
ERR_IN_USE,
|
30
|
+
ERR_TOO_MANY,
|
31
|
+
ERR_TYPE,
|
32
|
+
ERR_LAST
|
33
|
+
} ErrCode;
|
34
|
+
|
35
|
+
// The struct used to report errors or status after a function returns. The
|
36
|
+
// struct must be initialized before use as most calls that take an err
|
37
|
+
// argument will return immediately if an error has already occurred.
|
38
|
+
typedef struct _Err {
|
39
|
+
int code;
|
40
|
+
char msg[256];
|
41
|
+
} *Err;
|
42
|
+
|
43
|
+
extern int err_set(Err err, int code, const char *fmt, ...);
|
44
|
+
extern int err_no(Err err, const char *fmt, ...);
|
45
|
+
extern const char* err_str(ErrCode code);
|
46
|
+
extern void err_clear(Err err);
|
47
|
+
|
48
|
+
#endif /* __AGOO_ERR_H__ */
|
@@ -0,0 +1,92 @@
|
|
1
|
+
// Copyright (c) 2018, Peter Ohler, All rights reserved.
|
2
|
+
|
3
|
+
#include "error_stream.h"
|
4
|
+
#include "text.h"
|
5
|
+
|
6
|
+
static VALUE es_class = Qundef;
|
7
|
+
|
8
|
+
typedef struct _ErrorStream {
|
9
|
+
Server server;
|
10
|
+
Text text;
|
11
|
+
} *ErrorStream;
|
12
|
+
|
13
|
+
static void
|
14
|
+
es_free(void *ptr) {
|
15
|
+
ErrorStream es = (ErrorStream)ptr;
|
16
|
+
|
17
|
+
free(es->text); // allocated with malloc
|
18
|
+
xfree(ptr);
|
19
|
+
}
|
20
|
+
|
21
|
+
VALUE
|
22
|
+
error_stream_new(Server server) {
|
23
|
+
ErrorStream es = ALLOC(struct _ErrorStream);
|
24
|
+
|
25
|
+
es->text = text_allocate(1024);
|
26
|
+
es->server = server;
|
27
|
+
|
28
|
+
return Data_Wrap_Struct(es_class, NULL, es_free, es);
|
29
|
+
}
|
30
|
+
|
31
|
+
/* Document-method: puts
|
32
|
+
|
33
|
+
* call-seq: puts(str)
|
34
|
+
*
|
35
|
+
* Write the _str_ to the stream along with a newline character, accumulating
|
36
|
+
* it until _flush_ is called.
|
37
|
+
*/
|
38
|
+
static VALUE
|
39
|
+
es_puts(VALUE self, VALUE str) {
|
40
|
+
ErrorStream es = (ErrorStream)DATA_PTR(self);
|
41
|
+
|
42
|
+
es->text = text_append(es->text, StringValuePtr(str), RSTRING_LEN(str));
|
43
|
+
es->text = text_append(es->text, "\n", 1);
|
44
|
+
|
45
|
+
return Qnil;
|
46
|
+
}
|
47
|
+
|
48
|
+
/* Document-method: write
|
49
|
+
|
50
|
+
* call-seq: write(str)
|
51
|
+
*
|
52
|
+
* Write the _str_ to the stream, accumulating it until _flush_ is called.
|
53
|
+
*/
|
54
|
+
static VALUE
|
55
|
+
es_write(VALUE self, VALUE str) {
|
56
|
+
ErrorStream es = (ErrorStream)DATA_PTR(self);
|
57
|
+
int cnt = RSTRING_LEN(str);
|
58
|
+
|
59
|
+
es->text = text_append(es->text, StringValuePtr(str), cnt);
|
60
|
+
|
61
|
+
return INT2NUM(cnt);
|
62
|
+
}
|
63
|
+
|
64
|
+
/* Document-method: flush
|
65
|
+
|
66
|
+
* call-seq: flush()
|
67
|
+
*
|
68
|
+
* Flushs the accumulated text in the stream as an error log entry.
|
69
|
+
*/
|
70
|
+
static VALUE
|
71
|
+
es_flush(VALUE self) {
|
72
|
+
ErrorStream es = (ErrorStream)DATA_PTR(self);
|
73
|
+
|
74
|
+
log_cat(&es->server->error_cat, "%s", es->text->text);
|
75
|
+
es->text->len = 0;
|
76
|
+
|
77
|
+
return self;
|
78
|
+
}
|
79
|
+
|
80
|
+
/* Document-class: Agoo::ErrorStream
|
81
|
+
*
|
82
|
+
* Used in a reqquest as the _rack.errors_ attribute. Writing to the stream
|
83
|
+
* and flushing will make an error log entry.
|
84
|
+
*/
|
85
|
+
void
|
86
|
+
error_stream_init(VALUE mod) {
|
87
|
+
es_class = rb_define_class_under(mod, "ErrorStream", rb_cObject);
|
88
|
+
|
89
|
+
rb_define_method(es_class, "puts", es_puts, 1);
|
90
|
+
rb_define_method(es_class, "write", es_write, 1);
|
91
|
+
rb_define_method(es_class, "flush", es_flush, 0);
|
92
|
+
}
|
@@ -0,0 +1,13 @@
|
|
1
|
+
// Copyright (c) 2018, Peter Ohler, All rights reserved.
|
2
|
+
|
3
|
+
#ifndef __AGOO_ERROR_STREAM_H__
|
4
|
+
#define __AGOO_ERROR_STREAM_H__
|
5
|
+
|
6
|
+
#include <ruby.h>
|
7
|
+
|
8
|
+
#include "server.h"
|
9
|
+
|
10
|
+
extern void error_stream_init(VALUE mod);
|
11
|
+
extern VALUE error_stream_new(Server server);
|
12
|
+
|
13
|
+
#endif // __AGOO_ERROR_STREAM_H__
|
data/ext/agoo/extconf.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
require 'rbconfig'
|
3
|
+
|
4
|
+
extension_name = 'agoo'
|
5
|
+
dir_config(extension_name)
|
6
|
+
|
7
|
+
$CPPFLAGS += " -DPLATFORM_LINUX" if 'x86_64-linux' == RUBY_PLATFORM
|
8
|
+
|
9
|
+
create_makefile(File.join(extension_name, extension_name))
|
10
|
+
|
11
|
+
puts ">>>>> Created Makefile for #{RUBY_DESCRIPTION.split(' ')[0]} version #{RUBY_VERSION} on #{RUBY_PLATFORM} <<<<<"
|
12
|
+
|
13
|
+
%x{make clean}
|
data/ext/agoo/hook.c
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
// Copyright (c) 2018, Peter Ohler, All rights reserved.
|
2
|
+
|
3
|
+
#include <stdlib.h>
|
4
|
+
#include <string.h>
|
5
|
+
|
6
|
+
#include "hook.h"
|
7
|
+
|
8
|
+
Hook
|
9
|
+
hook_create(Method method, const char *pattern, VALUE handler) {
|
10
|
+
Hook hook = (Hook)malloc(sizeof(struct _Hook));
|
11
|
+
|
12
|
+
if (NULL != hook) {
|
13
|
+
if (NULL == pattern) {
|
14
|
+
pattern = "";
|
15
|
+
}
|
16
|
+
hook->next = NULL;
|
17
|
+
hook->handler = handler;
|
18
|
+
rb_gc_register_address(&handler);
|
19
|
+
hook->pattern = strdup(pattern);
|
20
|
+
hook->method = method;
|
21
|
+
if (rb_respond_to(handler, rb_intern("on_request"))) {
|
22
|
+
hook->type = BASE_HOOK;
|
23
|
+
} else if (rb_respond_to(handler, rb_intern("call"))) {
|
24
|
+
hook->type = RACK_HOOK;
|
25
|
+
} else if (rb_respond_to(handler, rb_intern("create")) &&
|
26
|
+
rb_respond_to(handler, rb_intern("read")) &&
|
27
|
+
rb_respond_to(handler, rb_intern("update")) &&
|
28
|
+
rb_respond_to(handler, rb_intern("delete"))) {
|
29
|
+
hook->type = WAB_HOOK;
|
30
|
+
} else {
|
31
|
+
rb_raise(rb_eArgError, "handler does not have a on_request, or call method nor is it a WAB::Controller");
|
32
|
+
}
|
33
|
+
}
|
34
|
+
return hook;
|
35
|
+
}
|
36
|
+
|
37
|
+
void
|
38
|
+
hook_destroy(Hook hook) {
|
39
|
+
free(hook->pattern);
|
40
|
+
free(hook);
|
41
|
+
}
|
42
|
+
|
43
|
+
bool
|
44
|
+
hook_match(Hook hook, Method method, const char *path, const char *pend) {
|
45
|
+
const char *pat = hook->pattern;
|
46
|
+
|
47
|
+
if (method != hook->method && ALL != hook->method) {
|
48
|
+
return false;
|
49
|
+
}
|
50
|
+
for (; '\0' != *pat && path < pend; pat++) {
|
51
|
+
if (*path == *pat) {
|
52
|
+
path++;
|
53
|
+
} else if ('*' == *pat) {
|
54
|
+
if ('*' == *(pat + 1)) {
|
55
|
+
return true;
|
56
|
+
}
|
57
|
+
for (; path < pend && '/' != *path; path++) {
|
58
|
+
}
|
59
|
+
} else {
|
60
|
+
break;
|
61
|
+
}
|
62
|
+
}
|
63
|
+
return '\0' == *pat && path == pend;
|
64
|
+
}
|
65
|
+
|
66
|
+
Hook
|
67
|
+
hook_find(Hook hook, Method method, const char *path, const char *pend) {
|
68
|
+
for (; NULL != hook; hook = hook->next) {
|
69
|
+
if (hook_match(hook, method, path, pend)) {
|
70
|
+
return hook;
|
71
|
+
}
|
72
|
+
}
|
73
|
+
return NULL;
|
74
|
+
}
|
data/ext/agoo/hook.h
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
// Copyright (c) 2018, Peter Ohler, All rights reserved.
|
2
|
+
|
3
|
+
#ifndef __AGOO_HOOK_H__
|
4
|
+
#define __AGOO_HOOK_H__
|
5
|
+
|
6
|
+
#include <stdbool.h>
|
7
|
+
|
8
|
+
#include <ruby.h>
|
9
|
+
|
10
|
+
#include "types.h"
|
11
|
+
|
12
|
+
typedef enum {
|
13
|
+
NO_HOOK = '\0',
|
14
|
+
RACK_HOOK = 'R',
|
15
|
+
BASE_HOOK = 'B',
|
16
|
+
WAB_HOOK = 'W',
|
17
|
+
} HookType;
|
18
|
+
|
19
|
+
typedef struct _Hook {
|
20
|
+
struct _Hook *next;
|
21
|
+
Method method;
|
22
|
+
VALUE handler;
|
23
|
+
char *pattern;
|
24
|
+
HookType type;
|
25
|
+
} *Hook;
|
26
|
+
|
27
|
+
extern Hook hook_create(Method method, const char *pattern, VALUE handler);
|
28
|
+
extern void hook_destroy(Hook hook);
|
29
|
+
|
30
|
+
extern bool hook_match(Hook hook, Method method, const char *path, const char *pend);
|
31
|
+
extern Hook hook_find(Hook hook, Method method, const char *path, const char *pend);
|
32
|
+
|
33
|
+
#endif // __AGOO_HOOK_H__
|