agoo 2.14.1 → 2.15.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -0
- data/README.md +1 -2
- data/ext/agoo/con.c +2 -0
- data/ext/agoo/extconf.rb +1 -1
- data/ext/agoo/gqleval.c +5 -1
- data/ext/agoo/gqlintro.c +2 -2
- data/ext/agoo/graphql.c +1 -1
- data/ext/agoo/ready.c +9 -9
- data/ext/agoo/rserver.c +10 -6
- data/lib/agoo/version.rb +1 -1
- data/test/graphql_error_test.rb +35 -0
- data/test/graphql_test.rb +32 -1
- data/test/rack_handler_test.rb +18 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1774bcd29b45056263ad986722015b99efa5c2bc8b0607b3a08afb79cd40cd70
|
4
|
+
data.tar.gz: dddc4062987102c87f1e2556ad425b33f3e0dd0a380c2a2416348ba2e07869d2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5b4dbbe0b330c4456d46354019940e962a79229486b323940e20d3b8213416fd025d6279772b35f441bbbdd8e1fa5cfebe812ecba7f5d7e3a5ad16d46b41ef25
|
7
|
+
data.tar.gz: aad80f64bc75f27663c1372d02ced4a205ea5e89a5deba77619951cc09d0a083810f57520375a9fc8fe658e591f453367e1b4638f362ccfc95a2bbba3a183c7a
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,24 @@
|
|
2
2
|
|
3
3
|
All changes to the Agoo gem are documented here. Releases follow semantic versioning.
|
4
4
|
|
5
|
+
## [2.15.0] - 2022-05-20
|
6
|
+
|
7
|
+
### Added
|
8
|
+
|
9
|
+
- Support added for PATCH.
|
10
|
+
|
11
|
+
## [2.14.3] - 2022-05-05
|
12
|
+
|
13
|
+
### Fixed
|
14
|
+
- Agoo now reports an error if the developer make the mistake of
|
15
|
+
building a schema that loops back on itself too many times using
|
16
|
+
fragments.
|
17
|
+
|
18
|
+
## [2.14.2] - 2022-02-22
|
19
|
+
|
20
|
+
### Fixed
|
21
|
+
- Invalid SDL now raises and exception instead of crashing.
|
22
|
+
|
5
23
|
## [2.14.1] - 2021-06-09
|
6
24
|
|
7
25
|
### Fixed
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# [](http://www.ohler.com/agoo) Agoo
|
2
2
|
|
3
|
-
[](https://github.com/ohler55/agoo/actions/workflows/CI.yml)
|
4
4
|
[](https://badge.fury.io/rb/agoo)
|
5
5
|
 [](https://tidelift.com/subscription/pkg/rubygems-agoo?utm_source=rubygems-agoo&utm_medium=referral&utm_campaign=readme)
|
6
6
|
|
@@ -163,4 +163,3 @@ the develop branch. Pull requests should be made against the develop branch.
|
|
163
163
|
- *WABuR* *repo*: https://github.com/ohler55/wabur has an option to use Agoo
|
164
164
|
|
165
165
|
- *Perfer* *repo*: https://github.com/ohler55/perfer
|
166
|
-
|
data/ext/agoo/con.c
CHANGED
@@ -327,6 +327,8 @@ con_header_read(agooCon c, size_t *mlenp) {
|
|
327
327
|
method = AGOO_PUT;
|
328
328
|
} else if (4 == b - c->buf && 0 == strncmp("POST", c->buf, 4)) {
|
329
329
|
method = AGOO_POST;
|
330
|
+
} else if (5 == b - c->buf && 0 == strncmp("PATCH", c->buf, 5)) {
|
331
|
+
method = AGOO_PATCH;
|
330
332
|
} else {
|
331
333
|
return bad_request(c, 400, __LINE__);
|
332
334
|
}
|
data/ext/agoo/extconf.rb
CHANGED
@@ -20,7 +20,7 @@ CONFIG['warnflags'].slice!(/ -Wdeclaration-after-statement/)
|
|
20
20
|
CONFIG['warnflags'].slice!(/ -Wmissing-noreturn/)
|
21
21
|
|
22
22
|
have_header('stdatomic.h')
|
23
|
-
|
23
|
+
have_header('sys/epoll.h')
|
24
24
|
have_header('openssl/ssl.h')
|
25
25
|
have_library('ssl')
|
26
26
|
|
data/ext/agoo/gqleval.c
CHANGED
@@ -21,6 +21,7 @@
|
|
21
21
|
#include "websocket.h"
|
22
22
|
|
23
23
|
#define MAX_RESOLVE_ARGS 16
|
24
|
+
#define MAX_DEPTH 100
|
24
25
|
|
25
26
|
gqlRef gql_root = NULL;
|
26
27
|
gqlType _gql_root_type = NULL;
|
@@ -273,7 +274,10 @@ gql_eval_sels(agooErr err, gqlDoc doc, gqlRef ref, gqlField field, gqlSel sels,
|
|
273
274
|
gqlSel sel;
|
274
275
|
gqlField sf = NULL;
|
275
276
|
|
276
|
-
|
277
|
+
if (MAX_DEPTH < depth) {
|
278
|
+
return agoo_err_set(err, AGOO_ERR_EVAL, "Maximum resolve depth of %d exceeded.", MAX_DEPTH);
|
279
|
+
}
|
280
|
+
depth++;
|
277
281
|
|
278
282
|
for (sel = sels; NULL != sel; sel = sel->next) {
|
279
283
|
if (NULL != field) {
|
data/ext/agoo/gqlintro.c
CHANGED
@@ -1497,13 +1497,13 @@ gql_intro_eval(agooErr err, gqlDoc doc, gqlSel sel, gqlValue result, int depth)
|
|
1497
1497
|
struct _gqlCobj obj;
|
1498
1498
|
|
1499
1499
|
if (0 == strcmp("__type", sel->name)) {
|
1500
|
-
if (
|
1500
|
+
if (2 < depth) {
|
1501
1501
|
return agoo_err_set(err, AGOO_ERR_EVAL, "__type can only be called from a query root.");
|
1502
1502
|
}
|
1503
1503
|
obj.clas = &root_class;
|
1504
1504
|
obj.ptr = NULL;
|
1505
1505
|
} else if (0 == strcmp("__schema", sel->name)) {
|
1506
|
-
if (
|
1506
|
+
if (2 < depth) {
|
1507
1507
|
return agoo_err_set(err, AGOO_ERR_EVAL, "__scheme can only be called from a query root.");
|
1508
1508
|
}
|
1509
1509
|
obj.clas = &root_class;
|
data/ext/agoo/graphql.c
CHANGED
data/ext/agoo/ready.c
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
#include <string.h>
|
6
6
|
#include <unistd.h>
|
7
7
|
|
8
|
-
#
|
8
|
+
#ifdef HAVE_SYS_EPOLL_H
|
9
9
|
#include <sys/epoll.h>
|
10
10
|
#else
|
11
11
|
#include <ctype.h>
|
@@ -22,7 +22,7 @@
|
|
22
22
|
// milliseconds
|
23
23
|
#define MAX_WAIT 10
|
24
24
|
|
25
|
-
#
|
25
|
+
#ifdef HAVE_SYS_EPOLL_H
|
26
26
|
#define EPOLL_SIZE 100
|
27
27
|
#else
|
28
28
|
#define INITIAL_POLL_SIZE 1024
|
@@ -34,7 +34,7 @@ typedef struct _link {
|
|
34
34
|
int fd;
|
35
35
|
void *ctx;
|
36
36
|
agooHandler handler;
|
37
|
-
#
|
37
|
+
#ifdef HAVE_SYS_EPOLL_H
|
38
38
|
uint32_t events; // last events set
|
39
39
|
#else
|
40
40
|
struct pollfd *pp;
|
@@ -45,7 +45,7 @@ struct _agooReady {
|
|
45
45
|
Link links;
|
46
46
|
int lcnt;
|
47
47
|
double next_check;
|
48
|
-
#
|
48
|
+
#ifdef HAVE_SYS_EPOLL_H
|
49
49
|
int epoll_fd;
|
50
50
|
#else
|
51
51
|
struct pollfd *pa;
|
@@ -82,7 +82,7 @@ agoo_ready_create(agooErr err) {
|
|
82
82
|
ready->links = NULL;
|
83
83
|
ready->lcnt = 0;
|
84
84
|
ready->next_check = dtime() + CHECK_FREQ;
|
85
|
-
#
|
85
|
+
#ifdef HAVE_SYS_EPOLL_H
|
86
86
|
if (0 > (ready->epoll_fd = epoll_create(1))) {
|
87
87
|
agoo_err_no(err, "epoll create failed");
|
88
88
|
return NULL;
|
@@ -111,7 +111,7 @@ agoo_ready_destroy(agooReady ready) {
|
|
111
111
|
}
|
112
112
|
AGOO_FREE(link);
|
113
113
|
}
|
114
|
-
#
|
114
|
+
#ifdef HAVE_SYS_EPOLL_H
|
115
115
|
close(ready->epoll_fd);
|
116
116
|
#else
|
117
117
|
AGOO_FREE(ready->pa);
|
@@ -137,7 +137,7 @@ agoo_ready_add(agooErr err,
|
|
137
137
|
ready->links = link;
|
138
138
|
ready->lcnt++;
|
139
139
|
|
140
|
-
#
|
140
|
+
#ifdef HAVE_SYS_EPOLL_H
|
141
141
|
link->events = EPOLLIN;
|
142
142
|
{
|
143
143
|
struct epoll_event event = {
|
@@ -181,7 +181,7 @@ ready_remove(agooReady ready, Link link) {
|
|
181
181
|
if (NULL != link->next) {
|
182
182
|
link->next->prev = link->prev;
|
183
183
|
}
|
184
|
-
#
|
184
|
+
#ifdef HAVE_SYS_EPOLL_H
|
185
185
|
{
|
186
186
|
struct epoll_event event = {
|
187
187
|
.events = 0,
|
@@ -214,7 +214,7 @@ agoo_ready_go(agooErr err, agooReady ready) {
|
|
214
214
|
Link link;
|
215
215
|
Link next;
|
216
216
|
|
217
|
-
#
|
217
|
+
#ifdef HAVE_SYS_EPOLL_H
|
218
218
|
struct epoll_event events[EPOLL_SIZE];
|
219
219
|
struct epoll_event *ep;
|
220
220
|
int cnt;
|
data/ext/agoo/rserver.c
CHANGED
@@ -48,6 +48,7 @@ static VALUE options_sym;
|
|
48
48
|
static VALUE post_sym;
|
49
49
|
static VALUE push_env_key;
|
50
50
|
static VALUE put_sym;
|
51
|
+
static VALUE patch_sym;
|
51
52
|
|
52
53
|
static VALUE rserver;
|
53
54
|
|
@@ -523,14 +524,14 @@ handle_rack_inner(VALUE x) {
|
|
523
524
|
if (Qnil != body) {
|
524
525
|
body = rb_ivar_get(body, rb_intern("@body"));
|
525
526
|
}
|
526
|
-
if (rb_respond_to(body,
|
527
|
-
|
527
|
+
if (rb_respond_to(body, each_id)) {
|
528
|
+
rb_block_call(body, each_id, 0, 0, body_len_cb, (VALUE)&bsize);
|
528
529
|
}
|
529
530
|
} else {
|
530
|
-
|
531
|
+
rb_block_call(bv, each_id, 0, 0, body_len_cb, (VALUE)&bsize);
|
531
532
|
}
|
532
533
|
} else {
|
533
|
-
|
534
|
+
rb_block_call(bv, each_id, 0, 0, body_len_cb, (VALUE)&bsize);
|
534
535
|
}
|
535
536
|
}
|
536
537
|
switch (code) {
|
@@ -587,7 +588,7 @@ handle_rack_inner(VALUE x) {
|
|
587
588
|
if (T_HASH == rb_type(hv)) {
|
588
589
|
rb_hash_foreach(hv, header_cb, (VALUE)&t);
|
589
590
|
} else {
|
590
|
-
|
591
|
+
rb_block_call(hv, each_id, 0, 0, header_each_cb, (VALUE)&t);
|
591
592
|
}
|
592
593
|
}
|
593
594
|
t = agoo_text_append(t, "\r\n", 2);
|
@@ -602,7 +603,7 @@ handle_rack_inner(VALUE x) {
|
|
602
603
|
t = agoo_text_append(t, StringValuePtr(v), (int)RSTRING_LEN(v));
|
603
604
|
}
|
604
605
|
} else {
|
605
|
-
|
606
|
+
rb_block_call(bv, each_id, 0, 0, body_append_cb, (VALUE)&t);
|
606
607
|
}
|
607
608
|
}
|
608
609
|
agoo_res_message_push(req->res, t);
|
@@ -971,6 +972,8 @@ handle(VALUE self, VALUE method, VALUE pattern, VALUE handler) {
|
|
971
972
|
meth = AGOO_POST;
|
972
973
|
} else if (put_sym == method) {
|
973
974
|
meth = AGOO_PUT;
|
975
|
+
} else if (patch_sym == method) {
|
976
|
+
meth = AGOO_PATCH;
|
974
977
|
} else if (Qnil == method) {
|
975
978
|
meth = AGOO_ALL;
|
976
979
|
} else {
|
@@ -1277,6 +1280,7 @@ server_init(VALUE mod) {
|
|
1277
1280
|
options_sym = ID2SYM(rb_intern("OPTIONS")); rb_gc_register_address(&options_sym);
|
1278
1281
|
post_sym = ID2SYM(rb_intern("POST")); rb_gc_register_address(&post_sym);
|
1279
1282
|
put_sym = ID2SYM(rb_intern("PUT")); rb_gc_register_address(&put_sym);
|
1283
|
+
patch_sym = ID2SYM(rb_intern("PATCH")); rb_gc_register_address(&patch_sym);
|
1280
1284
|
|
1281
1285
|
push_env_key = rb_str_new_cstr("rack.upgrade"); rb_gc_register_address(&push_env_key);
|
1282
1286
|
|
data/lib/agoo/version.rb
CHANGED
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$: << File.dirname(__FILE__)
|
4
|
+
$root_dir = File.dirname(File.expand_path(File.dirname(__FILE__)))
|
5
|
+
%w(lib ext).each do |dir|
|
6
|
+
$: << File.join($root_dir, dir)
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'minitest'
|
10
|
+
require 'minitest/autorun'
|
11
|
+
|
12
|
+
require 'agoo'
|
13
|
+
|
14
|
+
class Schema
|
15
|
+
attr_reader :query
|
16
|
+
|
17
|
+
def initialize()
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class GraphQLErrTest < Minitest::Test
|
22
|
+
|
23
|
+
def test_bad_sdl
|
24
|
+
bad_sdl = %^
|
25
|
+
type Query @ruby(class: "Query" {
|
26
|
+
}
|
27
|
+
^
|
28
|
+
Agoo::GraphQL.schema(Schema.new) {
|
29
|
+
assert_raises(StandardError) {
|
30
|
+
Agoo::GraphQL.load(bad_sdl)
|
31
|
+
}
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
data/test/graphql_test.rb
CHANGED
@@ -458,6 +458,32 @@ fragment basic on Artist {
|
|
458
458
|
post_test(uri, body, 'application/graphql', expect)
|
459
459
|
end
|
460
460
|
|
461
|
+
def test_post_fragment_loop
|
462
|
+
uri = URI('http://localhost:6472/graphql?indent=2')
|
463
|
+
body = %^
|
464
|
+
{
|
465
|
+
artist(name:"Fazerdaze") {
|
466
|
+
...loop
|
467
|
+
}
|
468
|
+
}
|
469
|
+
|
470
|
+
fragment loop on Artist {
|
471
|
+
name
|
472
|
+
...loop
|
473
|
+
}
|
474
|
+
^
|
475
|
+
expect = %^{
|
476
|
+
"errors":[
|
477
|
+
{
|
478
|
+
"message":"Maximum resolve depth of 100 exceeded.",
|
479
|
+
"code":"eval error"
|
480
|
+
}
|
481
|
+
]
|
482
|
+
}
|
483
|
+
^
|
484
|
+
post_test(uri, body, 'application/graphql', expect, 'errors.0.timestamp')
|
485
|
+
end
|
486
|
+
|
461
487
|
def test_post_json_fragment
|
462
488
|
uri = URI('http://localhost:6472/graphql?indent=2')
|
463
489
|
body = %^{
|
@@ -1044,7 +1070,7 @@ mutation {
|
|
1044
1070
|
assert_equal(expect, content)
|
1045
1071
|
end
|
1046
1072
|
|
1047
|
-
def post_test(uri, body, content_type, expect)
|
1073
|
+
def post_test(uri, body, content_type, expect, ignore=nil)
|
1048
1074
|
uri = URI(uri)
|
1049
1075
|
req = Net::HTTP::Post.new(uri)
|
1050
1076
|
req['Accept-Encoding'] = '*'
|
@@ -1055,6 +1081,11 @@ mutation {
|
|
1055
1081
|
}
|
1056
1082
|
content = res.body
|
1057
1083
|
assert_equal('application/json', res['Content-Type'])
|
1084
|
+
unless ignore.nil?
|
1085
|
+
result = Oj.load(content, mode: :strict)
|
1086
|
+
deep_delete(result, ignore.split('.'))
|
1087
|
+
content = Oj.dump(result, indent: 2)
|
1088
|
+
end
|
1058
1089
|
assert_equal(expect, content)
|
1059
1090
|
end
|
1060
1091
|
end
|
data/test/rack_handler_test.rb
CHANGED
@@ -33,7 +33,7 @@ size=big
|
|
33
33
|
]
|
34
34
|
elsif 'POST' == req['REQUEST_METHOD']
|
35
35
|
[ 204, { }, [] ]
|
36
|
-
elsif 'PUT' == req['REQUEST_METHOD']
|
36
|
+
elsif 'PUT' == req['REQUEST_METHOD'] || 'PATCH' == req['REQUEST_METHOD']
|
37
37
|
[ 201,
|
38
38
|
{ },
|
39
39
|
[ req['rack.input'].read ]
|
@@ -65,6 +65,7 @@ size=big
|
|
65
65
|
Agoo::Server.handle(:GET, "/tellme", handler)
|
66
66
|
Agoo::Server.handle(:POST, "/makeme", handler)
|
67
67
|
Agoo::Server.handle(:PUT, "/makeme", handler)
|
68
|
+
Agoo::Server.handle(:PATCH, "/makeme", handler)
|
68
69
|
|
69
70
|
Agoo::Server.start()
|
70
71
|
|
@@ -156,4 +157,20 @@ size=big
|
|
156
157
|
assert_equal('hello', res.body)
|
157
158
|
end
|
158
159
|
|
160
|
+
def test_patch
|
161
|
+
uri = URI('http://localhost:6467/makeme')
|
162
|
+
req = Net::HTTP::Patch.new(uri)
|
163
|
+
# Set the headers the way we want them.
|
164
|
+
req['Accept-Encoding'] = '*'
|
165
|
+
req['Accept'] = 'application/json'
|
166
|
+
req['User-Agent'] = 'Ruby'
|
167
|
+
req.body = 'hello'
|
168
|
+
|
169
|
+
res = Net::HTTP.start(uri.hostname, uri.port) { |h|
|
170
|
+
h.request(req)
|
171
|
+
}
|
172
|
+
assert_equal(Net::HTTPCreated, res.class)
|
173
|
+
assert_equal('hello', res.body)
|
174
|
+
end
|
175
|
+
|
159
176
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: agoo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.15.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Ohler
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-05-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: oj
|
@@ -154,6 +154,7 @@ files:
|
|
154
154
|
- test/bind_test.rb
|
155
155
|
- test/domain_test.rb
|
156
156
|
- test/early_hints_test.rb
|
157
|
+
- test/graphql_error_test.rb
|
157
158
|
- test/graphql_test.rb
|
158
159
|
- test/hijack_test.rb
|
159
160
|
- test/log_test.rb
|
@@ -189,7 +190,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
189
190
|
version: '0'
|
190
191
|
requirements:
|
191
192
|
- Linux or macOS
|
192
|
-
rubygems_version: 3.
|
193
|
+
rubygems_version: 3.3.3
|
193
194
|
signing_key:
|
194
195
|
specification_version: 4
|
195
196
|
summary: An HTTP server
|
@@ -198,6 +199,7 @@ test_files:
|
|
198
199
|
- test/bind_test.rb
|
199
200
|
- test/domain_test.rb
|
200
201
|
- test/early_hints_test.rb
|
202
|
+
- test/graphql_error_test.rb
|
201
203
|
- test/graphql_test.rb
|
202
204
|
- test/hijack_test.rb
|
203
205
|
- test/log_test.rb
|