agoo 2.5.7 → 2.6.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.

Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/README.md +38 -0
  4. data/ext/agoo/agoo.c +11 -2
  5. data/ext/agoo/bind.c +15 -20
  6. data/ext/agoo/con.c +32 -25
  7. data/ext/agoo/debug.c +225 -162
  8. data/ext/agoo/debug.h +31 -51
  9. data/ext/agoo/doc.c +278 -5
  10. data/ext/agoo/doc.h +6 -1
  11. data/ext/agoo/err.c +1 -0
  12. data/ext/agoo/err.h +1 -0
  13. data/ext/agoo/error_stream.c +3 -6
  14. data/ext/agoo/gqlcobj.c +12 -0
  15. data/ext/agoo/gqlcobj.h +25 -0
  16. data/ext/agoo/gqleval.c +520 -0
  17. data/ext/agoo/gqleval.h +49 -0
  18. data/ext/agoo/gqlintro.c +1237 -97
  19. data/ext/agoo/gqlintro.h +8 -0
  20. data/ext/agoo/gqljson.c +460 -0
  21. data/ext/agoo/gqljson.h +15 -0
  22. data/ext/agoo/gqlvalue.c +679 -136
  23. data/ext/agoo/gqlvalue.h +29 -7
  24. data/ext/agoo/graphql.c +841 -362
  25. data/ext/agoo/graphql.h +180 -90
  26. data/ext/agoo/hook.c +8 -16
  27. data/ext/agoo/http.c +3 -4
  28. data/ext/agoo/log.c +22 -25
  29. data/ext/agoo/log.h +1 -0
  30. data/ext/agoo/page.c +24 -40
  31. data/ext/agoo/pub.c +23 -21
  32. data/ext/agoo/queue.c +2 -4
  33. data/ext/agoo/ready.c +9 -9
  34. data/ext/agoo/req.c +80 -5
  35. data/ext/agoo/req.h +2 -0
  36. data/ext/agoo/res.c +1 -3
  37. data/ext/agoo/rgraphql.c +753 -0
  38. data/ext/agoo/rresponse.c +9 -15
  39. data/ext/agoo/rserver.c +18 -17
  40. data/ext/agoo/sdl.c +1264 -120
  41. data/ext/agoo/sdl.h +8 -1
  42. data/ext/agoo/sectime.c +136 -0
  43. data/ext/agoo/sectime.h +19 -0
  44. data/ext/agoo/server.c +1 -3
  45. data/ext/agoo/subject.c +2 -4
  46. data/ext/agoo/text.c +124 -18
  47. data/ext/agoo/text.h +5 -1
  48. data/ext/agoo/upgraded.c +2 -4
  49. data/lib/agoo/version.rb +1 -1
  50. data/test/base_handler_test.rb +43 -40
  51. data/test/bind_test.rb +49 -48
  52. data/test/graphql_test.rb +1019 -0
  53. data/test/hijack_test.rb +1 -1
  54. data/test/rack_handler_test.rb +40 -34
  55. data/test/static_test.rb +33 -32
  56. metadata +17 -6
@@ -4,7 +4,15 @@
4
4
  #define AGOO_GQLINTRO_H
5
5
 
6
6
  #include "err.h"
7
+ #include "gqlcobj.h"
8
+
9
+ struct _gqlField;
10
+ struct _gqlSel;
11
+ struct _gqlType;
12
+ struct _gqlValue;
7
13
 
8
14
  extern int gql_intro_init(agooErr err);
9
15
 
16
+ extern int gql_intro_eval(agooErr err, struct _gqlDoc *doc, struct _gqlSel *sel, struct _gqlValue *result, int depth);
17
+
10
18
  #endif // AGOO_GQLINTRO_H
@@ -0,0 +1,460 @@
1
+ // Copyright (c) 2018, Peter Ohler, All rights reserved.
2
+
3
+ #include <math.h>
4
+ #include <stdint.h>
5
+ #include <stdio.h>
6
+ #include <stdlib.h>
7
+ #include <string.h>
8
+
9
+ #include "doc.h"
10
+ #include "err.h"
11
+ #include "gqljson.h"
12
+ #include "gqlvalue.h"
13
+ #include "graphql.h"
14
+
15
+ #define EXP_MAX 1023
16
+ #define DEC_MAX 14
17
+ #define DIV_MAX 100000000000000000LL
18
+ #define BIGGISH 922337203685477580LL
19
+ #ifndef INT32_MAX
20
+ #define INT32_MAX 2147483647LL
21
+ #endif
22
+ #ifndef INT64_MAX
23
+ #define INT64_MAX 9223372036854775807LL
24
+ #endif
25
+
26
+ static gqlValue parse_value(agooErr err, agooDoc doc);
27
+
28
+ static gqlValue
29
+ parse_num(agooErr err, agooDoc doc) {
30
+ gqlValue value = NULL;
31
+ int zero_cnt = 0;
32
+ int64_t i = 0;
33
+ int64_t num = 0;
34
+ int64_t div = 1;
35
+ long exp = 0;
36
+ int dec_cnt = 0;
37
+ bool big = false;
38
+ bool neg = false;
39
+ char c;
40
+ const char *start = doc->cur;
41
+
42
+ c = *doc->cur;
43
+ if ('-' == c) {
44
+ doc->cur++;
45
+ c = *doc->cur;
46
+ neg = true;
47
+ } else if ('+' == c) {
48
+ doc->cur++;
49
+ c = *doc->cur;
50
+ }
51
+ for (; doc->cur < doc->end && '0' <= c && c <= '9'; c = *++doc->cur) {
52
+ dec_cnt++;
53
+ if (!big) {
54
+ int d = (c - '0');
55
+
56
+ if (0 == d) {
57
+ zero_cnt++;
58
+ } else {
59
+ zero_cnt = 0;
60
+ }
61
+ if (BIGGISH <= i && (INT64_MAX - i * 10LL) < (int64_t)d) {
62
+ big = true;
63
+ } else {
64
+ i = i * 10 + d;
65
+ }
66
+ }
67
+ }
68
+ if ('.' == c) {
69
+ c = *++doc->cur;
70
+ for (; doc->cur < doc->end && '0' <= c && c <= '9'; c = *++doc->cur) {
71
+ int d = (c - '0');
72
+
73
+ if (0 == d) {
74
+ zero_cnt++;
75
+ } else {
76
+ zero_cnt = 0;
77
+ }
78
+ dec_cnt++;
79
+ if ((BIGGISH < num && (INT64_MAX - (int64_t)d) / 10LL <= num) ||
80
+ DIV_MAX <= div || DEC_MAX < dec_cnt - zero_cnt) {
81
+ big = true;
82
+ } else {
83
+ num = num * 10 + d;
84
+ div *= 10;
85
+ }
86
+ }
87
+ }
88
+ if ('e' == c || 'E' == c) {
89
+ int eneg = 0;
90
+
91
+ c = *++doc->cur;
92
+ if ('-' == c) {
93
+ c = *++doc->cur;
94
+ eneg = 1;
95
+ } else if ('+' == c) {
96
+ c = *++doc->cur;
97
+ }
98
+ for (; doc->cur < doc->end && '0' <= c && c <= '9'; c = *++doc->cur) {
99
+ exp = exp * 10 + (c - '0');
100
+ if (EXP_MAX <= exp) {
101
+ big = true;
102
+ }
103
+ }
104
+ if (eneg) {
105
+ exp = -exp;
106
+ }
107
+ }
108
+ dec_cnt -= zero_cnt;
109
+ if (big) {
110
+ value = gql_string_create(err, start, (int)(doc->cur - start));
111
+ } else if (1 == div && 0 == exp) {
112
+ int64_t si = i;
113
+ if (neg) {
114
+ si = -si;
115
+ }
116
+ if (INT32_MAX < i) {
117
+ value = gql_i64_create(err, si);
118
+ } else {
119
+ value = gql_int_create(err, si);
120
+ }
121
+ } else { // decimal
122
+ double d = (double)i + (double)num / (double)div;
123
+
124
+ if (neg) {
125
+ d = -d;
126
+ }
127
+ if (0 != exp) {
128
+ d *= pow(10.0, exp);
129
+ }
130
+ value = gql_float_create(err, d);
131
+ }
132
+ return value;
133
+ }
134
+
135
+ static uint32_t
136
+ read_hex(agooErr err, agooDoc doc) {
137
+ uint32_t hex = 0;
138
+ const char *end = doc->cur + 4;
139
+ char c;
140
+
141
+ if (doc->end < end) {
142
+ agoo_doc_err(doc, err, "invalid escaped character");
143
+ return 0;
144
+ }
145
+ for (; doc->cur < end; doc->cur++) {
146
+ c = *doc->cur;
147
+ hex = hex << 4;
148
+ if ('0' <= c && c <= '9') {
149
+ hex += c - '0';
150
+ } else if ('A' <= c && c <= 'F') {
151
+ hex += c - 'A' + 10;
152
+ } else if ('a' <= c && c <= 'f') {
153
+ hex += c - 'a' + 10;
154
+ } else {
155
+ agoo_doc_err(doc, err, "invalid unicode character");
156
+ return 0;
157
+ }
158
+ }
159
+ return hex;
160
+ }
161
+
162
+ static agooText
163
+ unicode_to_chars(agooErr err, agooText t, uint32_t code, agooDoc doc) {
164
+ if (0x0000007F >= code) {
165
+ agoo_text_append_char(t, (char)code);
166
+ } else if (0x000007FF >= code) {
167
+ agoo_text_append_char(t, 0xC0 | (code >> 6));
168
+ agoo_text_append_char(t, 0x80 | (0x3F & code));
169
+ } else if (0x0000FFFF >= code) {
170
+ agoo_text_append_char(t, 0xE0 | (code >> 12));
171
+ agoo_text_append_char(t, 0x80 | ((code >> 6) & 0x3F));
172
+ agoo_text_append_char(t, 0x80 | (0x3F & code));
173
+ } else if (0x001FFFFF >= code) {
174
+ agoo_text_append_char(t, 0xF0 | (code >> 18));
175
+ agoo_text_append_char(t, 0x80 | ((code >> 12) & 0x3F));
176
+ agoo_text_append_char(t, 0x80 | ((code >> 6) & 0x3F));
177
+ agoo_text_append_char(t, 0x80 | (0x3F & code));
178
+ } else if (0x03FFFFFF >= code) {
179
+ agoo_text_append_char(t, 0xF8 | (code >> 24));
180
+ agoo_text_append_char(t, 0x80 | ((code >> 18) & 0x3F));
181
+ agoo_text_append_char(t, 0x80 | ((code >> 12) & 0x3F));
182
+ agoo_text_append_char(t, 0x80 | ((code >> 6) & 0x3F));
183
+ agoo_text_append_char(t, 0x80 | (0x3F & code));
184
+ } else if (0x7FFFFFFF >= code) {
185
+ agoo_text_append_char(t, 0xFC | (code >> 30));
186
+ agoo_text_append_char(t, 0x80 | ((code >> 24) & 0x3F));
187
+ agoo_text_append_char(t, 0x80 | ((code >> 18) & 0x3F));
188
+ agoo_text_append_char(t, 0x80 | ((code >> 12) & 0x3F));
189
+ agoo_text_append_char(t, 0x80 | ((code >> 6) & 0x3F));
190
+ agoo_text_append_char(t, 0x80 | (0x3F & code));
191
+ } else {
192
+ agoo_doc_err(doc, err, "invalid unicode character");
193
+ }
194
+ return t;
195
+ }
196
+
197
+ static gqlValue
198
+ parse_escaped(agooErr err, agooDoc doc) {
199
+ agooText t = agoo_text_allocate(4096);
200
+ gqlValue value = NULL;
201
+
202
+ if (NULL == t) {
203
+ return NULL;
204
+ }
205
+ for (; doc->cur < doc->end && '"' != *doc->cur; doc->cur++) {
206
+ if ('\\' == *doc->cur) {
207
+ doc->cur++;
208
+ switch (*doc->cur) {
209
+ case 'n': t = agoo_text_append_char(t, '\n'); break;
210
+ case 'r': t = agoo_text_append_char(t, '\r'); break;
211
+ case 't': t = agoo_text_append_char(t, '\t'); break;
212
+ case 'f': t = agoo_text_append_char(t, '\f'); break;
213
+ case 'b': t = agoo_text_append_char(t, '\b'); break;
214
+ case '"': t = agoo_text_append_char(t, '\"'); break;
215
+ case '/': t = agoo_text_append_char(t, '/'); break;
216
+ case '\\': t = agoo_text_append_char(t, '\\'); break;
217
+ case 'u': {
218
+ uint32_t code;
219
+
220
+ doc->cur++;
221
+ if (0 == (code = read_hex(err, doc)) && AGOO_ERR_OK != err->code) {
222
+ goto DONE;
223
+ }
224
+ if (0x0000D800 <= code && code <= 0x0000DFFF) {
225
+ uint32_t c1 = (code - 0x0000D800) & 0x000003FF;
226
+ uint32_t c2;
227
+
228
+ if ('\\' != *doc->cur || 'u' != doc->cur[1]) {
229
+ agoo_doc_err(doc, err, "invalid unicode character");
230
+ goto DONE;
231
+ }
232
+ doc->cur += 2;
233
+ if (0 == (c2 = read_hex(err, doc)) && AGOO_ERR_OK != err->code) {
234
+ goto DONE;
235
+ }
236
+ c2 = (c2 - 0x0000DC00) & 0x000003FF;
237
+ code = ((c1 << 10) | c2) + 0x00010000;
238
+ }
239
+ unicode_to_chars(err, t, code, doc);
240
+ if (AGOO_ERR_OK != err->code) {
241
+ goto DONE;
242
+ }
243
+ doc->cur--;
244
+ break;
245
+ }
246
+ default:
247
+ agoo_doc_err(doc, err, "invalid escaped character");
248
+ agoo_text_release(t);
249
+ return NULL;
250
+ }
251
+ } else {
252
+ t = agoo_text_append(t, doc->cur, 1);
253
+ }
254
+ }
255
+ value = gql_string_create(err, t->text, t->len);
256
+ doc->cur++; // past trailing "
257
+ DONE:
258
+ agoo_text_release(t);
259
+
260
+ return value;
261
+ }
262
+
263
+ static gqlValue
264
+ parse_string(agooErr err, agooDoc doc) {
265
+ const char *start;
266
+
267
+ if ('"' != *doc->cur) {
268
+ agoo_doc_err(doc, err, "invalid string");
269
+ return NULL;
270
+ }
271
+ doc->cur++;
272
+ start = doc->cur;
273
+ for (; doc->cur < doc->end && '"' != *doc->cur; doc->cur++) {
274
+ if ('\\' == *doc->cur) {
275
+ doc->cur = start;
276
+ return parse_escaped(err, doc);
277
+ }
278
+ }
279
+ doc->cur++;
280
+
281
+ return gql_string_create(err, start, (int)(doc->cur - start - 1));
282
+ }
283
+
284
+ static gqlValue
285
+ return_parse_err(agooErr err, agooDoc doc, const char *msg, gqlValue value) {
286
+ agoo_doc_err(doc, err, msg);
287
+ gql_value_destroy(value);
288
+
289
+ return NULL;
290
+ }
291
+
292
+ static gqlValue
293
+ parse_object(agooErr err, agooDoc doc) {
294
+ char key[256];
295
+ gqlValue value = gql_object_create(err);
296
+ gqlValue member;
297
+ const char *start;
298
+
299
+ if (NULL == value) {
300
+ return NULL;
301
+ }
302
+ doc->cur++; // past the {
303
+ agoo_doc_skip_jwhite(doc);
304
+ if ('}' != *doc->cur) {
305
+ for (; doc->cur < doc->end; doc->cur++) {
306
+ if ('"' != *doc->cur) {
307
+ return return_parse_err(err, doc, "expected an object key as a string", value);
308
+ }
309
+ doc->cur++; // past "
310
+
311
+ // TBD support unicode and escaped characters in key
312
+
313
+ start = doc->cur;
314
+ for (; doc->cur < doc->end && '"' != *doc->cur; doc->cur++) {
315
+ }
316
+ if ((int)sizeof(key) <= (int)(doc->cur - start)) {
317
+ return return_parse_err(err, doc, "object key too long", value);
318
+ }
319
+ memcpy(key, start, doc->cur - start);
320
+ key[doc->cur - start] = '\0';
321
+ doc->cur++; // past "
322
+ agoo_doc_skip_jwhite(doc);
323
+ if (':' != *doc->cur) {
324
+ return return_parse_err(err, doc, "expected a colon", value);
325
+ }
326
+ doc->cur++;
327
+ agoo_doc_skip_jwhite(doc);
328
+ if (NULL == (member = parse_value(err, doc)) ||
329
+ AGOO_ERR_OK != gql_object_set(err, value, key, member)) {
330
+ gql_value_destroy(value);
331
+ return NULL;
332
+ }
333
+ agoo_doc_skip_jwhite(doc);
334
+ if ('}' == *doc->cur) {
335
+ break;
336
+ }
337
+ if (',' != *doc->cur) {
338
+ return return_parse_err(err, doc, "expected a comma", value);
339
+ }
340
+ }
341
+ }
342
+ if ('}' != *doc->cur) {
343
+ agoo_doc_err(doc, err, "object not terminated");
344
+ gql_value_destroy(value);
345
+ return NULL;
346
+ }
347
+ doc->cur++;
348
+
349
+ return value;
350
+ }
351
+
352
+ static gqlValue
353
+ parse_array(agooErr err, agooDoc doc) {
354
+ gqlValue value = gql_list_create(err, NULL);
355
+ gqlValue member;
356
+
357
+ if (NULL == value) {
358
+ return NULL;
359
+ }
360
+ doc->cur++; // past the [
361
+ agoo_doc_skip_jwhite(doc);
362
+ if (']' != *doc->cur) {
363
+ for (; doc->cur < doc->end; doc->cur++) {
364
+ if (NULL == (member = parse_value(err, doc)) ||
365
+ AGOO_ERR_OK != gql_list_append(err, value, member)) {
366
+ gql_value_destroy(value);
367
+ return NULL;
368
+ }
369
+ agoo_doc_skip_jwhite(doc);
370
+ if (']' == *doc->cur) {
371
+ break;
372
+ }
373
+ if (',' != *doc->cur) {
374
+ agoo_doc_err(doc, err, "expected a comma");
375
+ gql_value_destroy(value);
376
+ return NULL;
377
+ }
378
+ }
379
+ }
380
+ if (']' != *doc->cur) {
381
+ agoo_doc_err(doc, err, "array not terminated");
382
+ gql_value_destroy(value);
383
+ return NULL;
384
+ }
385
+ doc->cur++;
386
+
387
+ return value;
388
+ }
389
+
390
+ static gqlValue
391
+ parse_value(agooErr err, agooDoc doc) {
392
+ gqlValue value = NULL;
393
+
394
+ agoo_doc_skip_jwhite(doc);
395
+ switch (*doc->cur) {
396
+ case '{':
397
+ value = parse_object(err, doc);
398
+ break;
399
+ case '[':
400
+ value = parse_array(err, doc);
401
+ break;
402
+ case '"':
403
+ value = parse_string(err, doc);
404
+ break;
405
+ case '+':
406
+ case '-':
407
+ case '0':
408
+ case '1':
409
+ case '2':
410
+ case '3':
411
+ case '4':
412
+ case '5':
413
+ case '6':
414
+ case '7':
415
+ case '8':
416
+ case '9':
417
+ value = parse_num(err, doc);
418
+ break;
419
+ case 't':
420
+ if (4 <= doc->end - doc->cur &&
421
+ 'r' == doc->cur[1] && 'u' == doc->cur[2] && 'e' == doc->cur[3]) {
422
+ value = gql_bool_create(err, true);
423
+ } else {
424
+ agoo_doc_err(doc, err, "invalid token");
425
+ }
426
+ break;
427
+ case 'f':
428
+ if (5 <= doc->end - doc->cur &&
429
+ 'a' == doc->cur[1] && 'l' == doc->cur[2] && 's' == doc->cur[3] && 'e' == doc->cur[4]) {
430
+ value = gql_bool_create(err, false);
431
+ } else {
432
+ agoo_doc_err(doc, err, "invalid token");
433
+ }
434
+ break;
435
+ case 'n':
436
+ if (4 <= doc->end - doc->cur &&
437
+ 'u' == doc->cur[1] && 'l' == doc->cur[2] && 'l' == doc->cur[3]) {
438
+ value = gql_null_create(err);
439
+ } else {
440
+ agoo_doc_err(doc, err, "invalid token");
441
+ }
442
+ break;
443
+ case '\0':
444
+ agoo_doc_err(doc, err, "embedded null character");
445
+ break;
446
+ default:
447
+ agoo_doc_err(doc, err, "invalid token character");
448
+ break;
449
+ }
450
+ return value;
451
+ }
452
+
453
+ gqlValue
454
+ gql_json_parse(agooErr err, const char *json, size_t len) {
455
+ struct _agooDoc doc;
456
+
457
+ agoo_doc_init(&doc, json, len);
458
+
459
+ return parse_value(err, &doc);
460
+ }