agoo 2.6.1 → 2.7.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.

@@ -30,17 +30,18 @@ typedef struct _agooGroup {
30
30
  agooDir dirs;
31
31
  } *agooGroup;
32
32
 
33
- extern void agoo_pages_init();
34
- extern void agoo_pages_set_root(const char *root);
33
+ extern int agoo_pages_init(agooErr err);
34
+ extern int agoo_pages_set_root(agooErr err, const char *root);
35
35
  extern void agoo_pages_cleanup();
36
36
 
37
37
  extern agooGroup group_create(const char *path);
38
- extern void group_add(agooGroup g, const char *dir);
38
+ extern agooDir group_add(agooErr err, agooGroup g, const char *dir);
39
39
  extern agooPage group_get(agooErr err, const char *path, int plen);
40
40
 
41
41
  extern agooPage agoo_page_create(const char *path);
42
42
  extern agooPage agoo_page_immutable(agooErr err, const char *path, const char *content, int clen);
43
43
  extern agooPage agoo_page_get(agooErr err, const char *path, int plen);
44
44
  extern int mime_set(agooErr err, const char *key, const char *value);
45
+ extern int agoo_header_rule(agooErr err, const char *path, const char *mime, const char *key, const char *value);
45
46
 
46
47
  #endif // AGOO_PAGE_H
@@ -26,20 +26,21 @@
26
26
  // When head == tail the queue is full. This happens when tail catches up with head.
27
27
  //
28
28
 
29
- void
30
- agoo_queue_init(agooQueue q, size_t qsize) {
31
- agoo_queue_multi_init(q, qsize, false, false);
29
+ int
30
+ agoo_queue_init(agooErr err, agooQueue q, size_t qsize) {
31
+ return agoo_queue_multi_init(err, q, qsize, false, false);
32
32
  }
33
33
 
34
- void
35
- agoo_queue_multi_init(agooQueue q, size_t qsize, bool multi_push, bool multi_pop) {
34
+ int
35
+ agoo_queue_multi_init(agooErr err, agooQueue q, size_t qsize, bool multi_push, bool multi_pop) {
36
36
  if (qsize < 4) {
37
37
  qsize = 4;
38
38
  }
39
- q->q = (agooQItem*)AGOO_MALLOC(sizeof(agooQItem) * qsize);
39
+ if (NULL == (q->q = (agooQItem*)AGOO_CALLOC(qsize, sizeof(agooQItem)))) {
40
+ return AGOO_ERR_MEM(err, "Queue");
41
+ }
40
42
  q->end = q->q + qsize;
41
43
 
42
- memset(q->q, 0, sizeof(agooQItem) * qsize);
43
44
  atomic_init(&q->head, q->q);
44
45
  atomic_init(&q->tail, q->q + 1);
45
46
  agoo_atomic_flag_init(&q->push_lock);
@@ -50,6 +51,8 @@ agoo_queue_multi_init(agooQueue q, size_t qsize, bool multi_push, bool multi_pop
50
51
  // Create when/if needed.
51
52
  q->rsock = 0;
52
53
  q->wsock = 0;
54
+
55
+ return AGOO_ERR_OK;
53
56
  }
54
57
 
55
58
  void
@@ -7,6 +7,7 @@
7
7
  #include <stdlib.h>
8
8
 
9
9
  #include "atomic.h"
10
+ #include "err.h"
10
11
 
11
12
  typedef void *agooQItem;
12
13
 
@@ -24,9 +25,9 @@ typedef struct _agooQueue {
24
25
  int wsock;
25
26
  } *agooQueue;
26
27
 
27
- extern void agoo_queue_init(agooQueue q, size_t qsize);
28
+ extern int agoo_queue_init(agooErr err, agooQueue q, size_t qsize);
28
29
 
29
- extern void agoo_queue_multi_init(agooQueue q, size_t qsize, bool multi_push, bool multi_pop);
30
+ extern int agoo_queue_multi_init(agooErr err, agooQueue q, size_t qsize, bool multi_push, bool multi_pop);
30
31
 
31
32
  extern void agoo_queue_cleanup(agooQueue q);
32
33
  extern void agoo_queue_push(agooQueue q, agooQItem item);
@@ -59,7 +59,7 @@ link_create(agooErr err, int fd, void *ctx, agooHandler handler) {
59
59
  Link link = (Link)AGOO_MALLOC(sizeof(struct _link));
60
60
 
61
61
  if (NULL == link) {
62
- agoo_err_set(err, AGOO_ERR_MEMORY, "Failed to allocate memory for a connection link.");
62
+ AGOO_ERR_MEM(err, "Connection Link");
63
63
  } else {
64
64
  //DEBUG_ALLOC(mem_???, c);
65
65
  link->next = NULL;
@@ -76,7 +76,7 @@ agoo_ready_create(agooErr err) {
76
76
  agooReady ready = (agooReady)AGOO_MALLOC(sizeof(struct _agooReady));
77
77
 
78
78
  if (NULL == ready) {
79
- agoo_err_set(err, AGOO_ERR_MEMORY, "Failed to allocate memory for a connection manager.");
79
+ AGOO_ERR_MEM(err, "Connection Manager");
80
80
  } else {
81
81
  //DEBUG_ALLOC(mem_???, c);
82
82
  ready->links = NULL;
@@ -126,7 +126,7 @@ agoo_ready_add(agooErr err,
126
126
  agooHandler handler,
127
127
  void *ctx) {
128
128
  Link link;
129
-
129
+
130
130
  if (NULL == (link = link_create(err, fd, ctx, handler))) {
131
131
  return err->code;
132
132
  }
@@ -155,9 +155,9 @@ agoo_ready_add(agooErr err,
155
155
  if (ready->pend - ready->pa <= ready->lcnt) {
156
156
  size_t cnt = (ready->pend - ready->pa) * 2;
157
157
  size_t size = cnt * sizeof(struct pollfd);
158
-
158
+
159
159
  if (NULL == (ready->pa = (struct pollfd*)AGOO_REALLOC(ready->pa, size))) {
160
- agoo_err_set(err, AGOO_ERR_MEMORY, "Failed to allocate memory for a connection pool.");
160
+ AGOO_ERR_MEM(err, "Connection Pool");
161
161
  agoo_log_cat(&agoo_error_cat, "Out of memory.");
162
162
  agoo_log_close();
163
163
  exit(EXIT_FAILURE);
@@ -206,7 +206,7 @@ agoo_ready_go(agooErr err, agooReady ready) {
206
206
  double now;
207
207
  Link link;
208
208
  Link next;
209
-
209
+
210
210
  #if HAVE_SYS_EPOLL_H
211
211
  struct epoll_event events[EPOLL_SIZE];
212
212
  struct epoll_event *ep;
@@ -271,7 +271,7 @@ agoo_ready_go(agooErr err, agooReady ready) {
271
271
  #else
272
272
  struct pollfd *pp;
273
273
  int i;
274
-
274
+
275
275
  // Setup the poll events.
276
276
  for (link = ready->links, pp = ready->pa; NULL != link; link = link->next, pp++) {
277
277
  pp->fd = link->fd;
@@ -290,6 +290,7 @@ agoo_ready_go(agooErr err, agooReady ready) {
290
290
  case AGOO_READY_NONE:
291
291
  default:
292
292
  // ignore, either dead or closing
293
+ link->pp = NULL;
293
294
  pp--;
294
295
  break;
295
296
  }
@@ -6,6 +6,7 @@
6
6
  #include <ruby.h>
7
7
  #include <ruby/thread.h>
8
8
 
9
+ #include "debug.h"
9
10
  #include "err.h"
10
11
  #include "gqleval.h"
11
12
  #include "gqlintro.h"
@@ -90,7 +91,7 @@ eval_wrap(agooErr err, gqlDoc doc) {
90
91
  .err = err,
91
92
  .value = NULL,
92
93
  };
93
-
94
+
94
95
  rb_thread_call_with_gvl(protect_eval, &eval);
95
96
 
96
97
  return eval.value;
@@ -123,7 +124,7 @@ gval_to_ruby(gqlValue value) {
123
124
  break;
124
125
  case GQL_SCALAR_TIME: {
125
126
  time_t secs = (time_t)(value->time / 1000000000LL);
126
-
127
+
127
128
  rval = rb_time_nano_new(secs, (long)(value->time - secs * 1000000000LL));
128
129
  break;
129
130
  }
@@ -141,7 +142,7 @@ gval_to_ruby(gqlValue value) {
141
142
  }
142
143
  case GQL_SCALAR_LIST: {
143
144
  gqlLink link;
144
-
145
+
145
146
  rval = rb_ary_new();
146
147
  for (link = value->members; NULL != link; link = link->next) {
147
148
  rb_ary_push(rval, gval_to_ruby(link->value));
@@ -150,11 +151,11 @@ gval_to_ruby(gqlValue value) {
150
151
  }
151
152
  case GQL_SCALAR_OBJECT: {
152
153
  gqlLink link;
153
-
154
+
154
155
  rval = rb_hash_new();
155
156
  for (link = value->members; NULL != link; link = link->next) {
156
157
  rb_hash_aset(rval, rb_str_new_cstr(link->key), gval_to_ruby(link->value));
157
-
158
+
158
159
  }
159
160
  break;
160
161
  }
@@ -170,7 +171,7 @@ gval_to_ruby(gqlValue value) {
170
171
  static VALUE
171
172
  ref_to_string(gqlRef ref) {
172
173
  volatile VALUE value;
173
-
174
+
174
175
  if (T_STRING == rb_type((VALUE)ref)) {
175
176
  value = (VALUE)ref;
176
177
  } else {
@@ -344,7 +345,7 @@ ref_type(gqlRef ref) {
344
345
  if (NULL != type_class_map) {
345
346
  TypeClass tc;
346
347
  const char *classname = rb_obj_classname((VALUE)ref);
347
-
348
+
348
349
  for (tc = type_class_map; NULL != tc->type; tc++) {
349
350
  if (0 == strcmp(classname, tc->classname)) {
350
351
  type = tc->type;
@@ -383,10 +384,10 @@ resolve(agooErr err, gqlDoc doc, gqlRef target, gqlField field, gqlSel sel, gqlV
383
384
  if (NULL == sel->args) {
384
385
  child = rb_funcall(obj, rb_intern(sel->name), 0);
385
386
  } else {
386
- volatile VALUE rargs = rb_hash_new();
387
+ volatile VALUE rargs = rb_hash_new();
387
388
  gqlSelArg sa;
388
389
  gqlValue v;
389
-
390
+
390
391
  for (sa = sel->args; NULL != sa; sa = sa->next) {
391
392
  if (NULL != sa->var) {
392
393
  v = sa->var->value;
@@ -395,7 +396,7 @@ resolve(agooErr err, gqlDoc doc, gqlRef target, gqlField field, gqlSel sel, gqlV
395
396
  }
396
397
  if (NULL != field) {
397
398
  gqlArg fa;
398
-
399
+
399
400
  for (fa = field->args; NULL != fa; fa = fa->next) {
400
401
  if (0 == strcmp(sa->name, fa->name)) {
401
402
  if (v->type != fa->type && GQL_SCALAR_VAR != v->type->scalar_kind) {
@@ -418,7 +419,7 @@ resolve(agooErr err, gqlDoc doc, gqlRef target, gqlField field, gqlSel sel, gqlV
418
419
  gqlValue list;
419
420
  int cnt;
420
421
  int i;
421
-
422
+
422
423
  rb_check_type(child, RUBY_T_ARRAY);
423
424
  if (NULL == (list = gql_list_create(err, NULL))) {
424
425
  return err->code;
@@ -452,7 +453,7 @@ resolve(agooErr err, gqlDoc doc, gqlRef target, gqlField field, gqlSel sel, gqlV
452
453
  }
453
454
  } else if (NULL == sel->sels) {
454
455
  gqlValue cv;
455
-
456
+
456
457
  if (NULL == (cv = coerce(err, (gqlRef)child, sel->type)) ||
457
458
  AGOO_ERR_OK != gql_object_set(err, result, key, cv)) {
458
459
  return err->code;
@@ -482,7 +483,7 @@ ruby_types_cb(gqlType type, void *ctx) {
482
483
  if (NULL != type_class_map) {
483
484
  TypeClass tc = &type_class_map[*(int*)ctx];
484
485
  gqlLink arg;
485
-
486
+
486
487
  tc->type = type;
487
488
  for (arg = dir->args; NULL != arg; arg = arg->next) {
488
489
  if (0 == strcmp("class", arg->key)) {
@@ -498,16 +499,15 @@ ruby_types_cb(gqlType type, void *ctx) {
498
499
  static int
499
500
  build_type_class_map(agooErr err) {
500
501
  int cnt = 0;
501
-
502
- free(type_class_map);
502
+
503
+ AGOO_FREE(type_class_map);
503
504
  type_class_map = NULL;
504
505
 
505
506
  gql_type_iterate(ruby_types_cb, &cnt);
506
507
 
507
- if (NULL == (type_class_map = (TypeClass)malloc(sizeof(struct _typeClass) * (cnt + 1)))) {
508
- return agoo_err_set(err, AGOO_ERR_MEMORY, "out of memory");
508
+ if (NULL == (type_class_map = (TypeClass)AGOO_CALLOC(cnt + 1, sizeof(struct _typeClass)))) {
509
+ return AGOO_ERR_MEM(err, "GraphQL Class map");
509
510
  }
510
- memset(type_class_map, 0, sizeof(struct _typeClass) * (cnt + 1));
511
511
  cnt = 0;
512
512
  gql_type_iterate(ruby_types_cb, &cnt);
513
513
 
@@ -657,9 +657,9 @@ static VALUE
657
657
  graphql_load_file(VALUE self, VALUE path) {
658
658
  struct _agooErr err = AGOO_ERR_INIT;
659
659
  FILE *f;
660
- size_t len;
660
+ long len;
661
661
  char *sdl;
662
-
662
+
663
663
  if (NULL == gql_root) {
664
664
  rb_raise(rb_eStandardError, "GraphQL root not set. Use Agoo::GraphQL.schema.");
665
665
  }
@@ -670,10 +670,14 @@ graphql_load_file(VALUE self, VALUE path) {
670
670
  if (0 != fseek(f, 0, SEEK_END)) {
671
671
  rb_raise(rb_eIOError, "%s", strerror(errno));
672
672
  }
673
- len = ftell(f);
673
+ if (0 > (len = ftell(f))) {
674
+ rb_raise(rb_eIOError, "%s", strerror(errno));
675
+ }
674
676
  sdl = ALLOC_N(char, len + 1);
675
- fseek(f, 0, SEEK_SET);
676
- if (len != fread(sdl, 1, len, f)) {
677
+ if (0 != fseek(f, 0, SEEK_SET)) {
678
+ rb_raise(rb_eIOError, "%s", strerror(errno));
679
+ }
680
+ if (len != (long)fread(sdl, 1, len, f)) {
677
681
  rb_raise(rb_eIOError, "%s", strerror(errno));
678
682
  } else {
679
683
  sdl[len] = '\0';
@@ -711,7 +715,7 @@ graphql_sdl_dump(VALUE self, VALUE options) {
711
715
  VALUE v;
712
716
  bool with_desc = true;
713
717
  bool all = false;
714
-
718
+
715
719
  Check_Type(options, T_HASH);
716
720
 
717
721
  v = rb_hash_aref(options, ID2SYM(rb_intern("with_descriptions")));
@@ -726,7 +730,7 @@ graphql_sdl_dump(VALUE self, VALUE options) {
726
730
 
727
731
  dump = rb_str_new(t->text, t->len);
728
732
  agoo_text_release(t);
729
-
733
+
730
734
  return dump;
731
735
  }
732
736
 
@@ -468,8 +468,8 @@ rlog_init(VALUE mod) {
468
468
 
469
469
  agoo_log.on_error = on_error;
470
470
 
471
- agoo_log_init("agoo");
472
- if (AGOO_ERR_OK != agoo_log_start(&err, false)) {
471
+ if (AGOO_ERR_OK != agoo_log_init(&err, "agoo") ||
472
+ AGOO_ERR_OK != agoo_log_start(&err, false)) {
473
473
  rb_raise(rb_eStandardError, "%s", err.msg);
474
474
  }
475
475
  }
@@ -28,6 +28,9 @@ VALUE
28
28
  response_new() {
29
29
  agooResponse res = (agooResponse)AGOO_MALLOC(sizeof(struct _agooResponse));
30
30
 
31
+ if (NULL == res) {
32
+ return Qnil;
33
+ }
31
34
  memset(res, 0, sizeof(struct _agooResponse));
32
35
  res->code = 200;
33
36
 
@@ -46,6 +49,9 @@ to_s(VALUE self) {
46
49
  int len = agoo_response_len(res);
47
50
  char *s = (char*)AGOO_MALLOC(len + 1);
48
51
 
52
+ if (NULL == s) {
53
+ rb_raise(rb_eNoMemError, "out of memory");
54
+ }
49
55
  agoo_response_fill(res, s);
50
56
 
51
57
  return rb_str_new(s, len);
@@ -4,6 +4,7 @@
4
4
  #include <netinet/tcp.h>
5
5
  #include <signal.h>
6
6
  #include <stdio.h>
7
+ #include <string.h>
7
8
  #include <sys/wait.h>
8
9
 
9
10
  #include <ruby.h>
@@ -93,7 +94,9 @@ url_bind(VALUE rurl) {
93
94
 
94
95
  static int
95
96
  configure(agooErr err, int port, const char *root, VALUE options) {
96
- agoo_pages_set_root(root);
97
+ if (AGOO_ERR_OK != agoo_pages_set_root(err, root)) {
98
+ return err->code;
99
+ }
97
100
  agoo_server.thread_cnt = 0;
98
101
  the_rserver.worker_cnt = 1;
99
102
  atomic_init(&agoo_server.running, 0);
@@ -236,9 +239,10 @@ configure(agooErr err, int port, const char *root, VALUE options) {
236
239
  * call-seq: init(port, root, options)
237
240
  *
238
241
  * Configures the server that will listen on the designated _port_ and using
239
- * the _root_ as the root of the static resources. Logging is feature based
240
- * and not level based and the options reflect that approach. If bind option
241
- * is to be used instead of the port then set the port to zero.
242
+ * the _root_ as the root of the static resources. This must be called before
243
+ * using other server methods. Logging is feature based and not level based
244
+ * and the options reflect that approach. If bind option is to be used instead
245
+ * of the port then set the port to zero.
242
246
  *
243
247
  * - *options* [_Hash_] server options
244
248
  *
@@ -268,7 +272,9 @@ rserver_init(int argc, VALUE *argv, VALUE self) {
268
272
  if (3 <= argc) {
269
273
  options = argv[2];
270
274
  }
271
- agoo_server_setup();
275
+ if (AGOO_ERR_OK != agoo_server_setup(&err)) {
276
+ rb_raise(rb_eStandardError, "%s", err.msg);
277
+ }
272
278
  agoo_server.ctx_nil_value = (void*)Qnil;
273
279
  agoo_server.env_nil_value = (void*)Qnil;
274
280
 
@@ -762,7 +768,7 @@ rserver_start(VALUE self) {
762
768
  agooReq req;
763
769
 
764
770
  while (agoo_server.active) {
765
- if (NULL != (req = (agooReq)agoo_queue_pop(&agoo_server.eval_queue, 0.01))) { // TBD 0.1
771
+ if (NULL != (req = (agooReq)agoo_queue_pop(&agoo_server.eval_queue, 0.1))) {
766
772
  handle_protected(req, false);
767
773
  agoo_req_destroy(req);
768
774
  } else {
@@ -998,7 +1004,8 @@ add_mime(VALUE self, VALUE suffix, VALUE type) {
998
1004
  */
999
1005
  static VALUE
1000
1006
  path_group(VALUE self, VALUE path, VALUE dirs) {
1001
- agooGroup g;
1007
+ struct _agooErr err = AGOO_ERR_INIT;
1008
+ agooGroup g;
1002
1009
 
1003
1010
  rb_check_type(path, T_STRING);
1004
1011
  rb_check_type(dirs, T_ARRAY);
@@ -1013,12 +1020,45 @@ path_group(VALUE self, VALUE path, VALUE dirs) {
1013
1020
  if (T_STRING != rb_type(entry)) {
1014
1021
  entry = rb_funcall(entry, rb_intern("to_s"), 0);
1015
1022
  }
1016
- group_add(g, StringValuePtr(entry));
1023
+ if (NULL == group_add(&err, g, StringValuePtr(entry))) {
1024
+ rb_raise(rb_eStandardError, "%s", err.msg);
1025
+ }
1017
1026
  }
1018
1027
  }
1019
1028
  return Qnil;
1020
1029
  }
1021
1030
 
1031
+ /* Document-method: header_rule
1032
+ *
1033
+ * call-seq: header_rule(path, mime, key, value)
1034
+ *
1035
+ * Add a header rule. A header rule will add the key and value to the headers
1036
+ * of any static asset that matches the path and mime type specified. The path
1037
+ * pattern follows glob like rules in that a single * matches a single token
1038
+ * bounded by the `/` character and a double ** matches all remaining. The
1039
+ * mime can also be a * which matches all types. The mime argument will be
1040
+ * compared to the mine type as well as the file extension so
1041
+ * 'applicaiton/json', a mime type can be used as can 'json' as a file
1042
+ * extension. All rules that match add the header key and value to the header
1043
+ * of a static asset.
1044
+ *
1045
+ * Note that the server must be initialized before calling this method.
1046
+ */
1047
+ static VALUE
1048
+ header_rule(VALUE self, VALUE path, VALUE mime, VALUE key, VALUE value) {
1049
+ struct _agooErr err = AGOO_ERR_INIT;
1050
+
1051
+ rb_check_type(path, T_STRING);
1052
+ rb_check_type(mime, T_STRING);
1053
+ rb_check_type(key, T_STRING);
1054
+ rb_check_type(value, T_STRING);
1055
+
1056
+ if (AGOO_ERR_OK != agoo_header_rule(&err, StringValuePtr(path), StringValuePtr(mime), StringValuePtr(key), StringValuePtr(value))) {
1057
+ rb_raise(rb_eArgError, "%s", err.msg);
1058
+ }
1059
+ return Qnil;
1060
+ }
1061
+
1022
1062
  /* Document-class: Agoo::Server
1023
1063
  *
1024
1064
  * An HTTP server that support the rack API as well as some other optimized
@@ -1036,6 +1076,7 @@ server_init(VALUE mod) {
1036
1076
  rb_define_module_function(server_mod, "handle_not_found", handle_not_found, 1);
1037
1077
  rb_define_module_function(server_mod, "add_mime", add_mime, 2);
1038
1078
  rb_define_module_function(server_mod, "path_group", path_group, 2);
1079
+ rb_define_module_function(server_mod, "header_rule", header_rule, 4);
1039
1080
 
1040
1081
  call_id = rb_intern("call");
1041
1082
  each_id = rb_intern("each");