agoo 2.14.0 → 2.14.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f70842cac2f630e74251967ca0accfcb2dacef7b143bb3707ae74d88a0f1da36
4
- data.tar.gz: 75996d57b98c1d164fa44009f1c6037deb28f22d7179b7bd3ede0296f3d9a605
3
+ metadata.gz: 843f3aa4a15a6ab57c7ff231930405c9ca55d3a6e33da3169a0677c420195fbe
4
+ data.tar.gz: 03f6b8760c6f08c0a3f9b5f75c747b77d1d4666b00af20d7db231418dfeb3c69
5
5
  SHA512:
6
- metadata.gz: 39f02fdb5ab101d1414a57a7d712b6b4910b583e2509d0911d2cf5c398badfdb556c6847eaa7e108d280b590792bf3cb007514e4f6cd7c8f57ddb233299e3a0f
7
- data.tar.gz: 10b2f2cc9d56d34e27dd597c5c2d0fa61bcf3921198efcbffcbfece23841656af9dc9eb6909b592e63ff30dd79aed315a55bacf97a471ac5c1c3e7acff4782f2
6
+ metadata.gz: '0684900cea98fbe812e5ae973ccd15dfaa054218340238dedfde382c535340945aea9857b98366fe52b2ff865129b299af541e940112200f2191b3b2247dfd58'
7
+ data.tar.gz: 95e68a0a7bc5a3eb8cd34b9853e8d89285ef9a1c78765bf970e80cdeb51f7f41f53db4948ca2885e29eef3fa7a6b738e015d01c4cbb25e41b2f50bac1fcb50a9
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.14.3] - 2022-05-05
6
+
7
+ ### Fixed
8
+ - Agoo now reports an error if the developer make the mistake of
9
+ building a schema that loops back on itself too many times using
10
+ fragments.
11
+
12
+ ## [2.14.2] - 2022-02-22
13
+
14
+ ### Fixed
15
+ - Invalid SDL now raises and exception instead of crashing.
16
+
17
+ ## [2.14.1] - 2021-06-09
18
+
19
+ ### Fixed
20
+ - Evaluating an empty GraphQL request with comments only no longer crashes.
21
+ - JSON parser bug fixed.
22
+
5
23
  ## [2.14.0] - 2020-11-07
6
24
 
7
25
  ### Added
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
- # agoo
1
+ # [![{}j](misc/agoo_128.svg)](http://www.ohler.com/agoo) Agoo
2
2
 
3
- [![Build Status](https://img.shields.io/travis/ohler55/agoo/master.svg)](http://travis-ci.org/ohler55/agoo?branch=master)
3
+ [![Build Status](https://img.shields.io/github/workflow/status/ohler55/agoo/CI?logo=github)](https://github.com/ohler55/agoo/actions/workflows/CI.yml)
4
4
  [![Gem Version](https://badge.fury.io/rb/agoo.svg)](https://badge.fury.io/rb/agoo)
5
5
  ![Gem](https://img.shields.io/gem/dt/agoo.svg) [![TideLift](https://tidelift.com/badges/github/ohler55/agoo)](https://tidelift.com/subscription/pkg/rubygems-agoo?utm_source=rubygems-agoo&utm_medium=referral&utm_campaign=readme)
6
6
 
@@ -163,5 +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
-
167
- Follow [@peterohler on Twitter](http://twitter.com/#!/peterohler) for announcements and news about the Agoo gem.
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
- #have_header('sys/epoll.h')
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
- // TBD if depth over max then return an error
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) {
@@ -620,7 +624,7 @@ eval_post(agooErr err, agooReq req) {
620
624
  } else {
621
625
  result = gql_doc_eval_func(err, doc);
622
626
  }
623
- if (GQL_SUBSCRIPTION == doc->op->kind) {
627
+ if (NULL != doc->op && GQL_SUBSCRIPTION == doc->op->kind) {
624
628
  result = NULL;
625
629
  }
626
630
  DONE:
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 (1 < depth) {
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 (1 < depth) {
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/gqljson.c CHANGED
@@ -307,6 +307,7 @@ parse_object(agooErr err, agooDoc doc) {
307
307
  agoo_doc_skip_jwhite(doc);
308
308
  if ('}' != *doc->cur) {
309
309
  for (; doc->cur < doc->end; doc->cur++) {
310
+ agoo_doc_skip_jwhite(doc);
310
311
  if ('"' != *doc->cur) {
311
312
  return return_parse_err(err, doc, "expected an object key as a string", value);
312
313
  }
data/ext/agoo/graphql.c CHANGED
@@ -892,8 +892,8 @@ gql_assure_nonnull(agooErr err, gqlType base) {
892
892
 
893
893
  void
894
894
  gql_type_destroy(gqlType type) {
895
- type_destroy(type);
896
895
  type_remove(type);
896
+ type_destroy(type);
897
897
  }
898
898
 
899
899
  // If negative then there are non-simple-string characters.
data/ext/agoo/ready.c CHANGED
@@ -5,7 +5,7 @@
5
5
  #include <string.h>
6
6
  #include <unistd.h>
7
7
 
8
- #if HAVE_SYS_EPOLL_H
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
- #if HAVE_SYS_EPOLL_H
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
- #if HAVE_SYS_EPOLL_H
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
- #if HAVE_SYS_EPOLL_H
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
- #if HAVE_SYS_EPOLL_H
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
- #if HAVE_SYS_EPOLL_H
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
- #if HAVE_SYS_EPOLL_H
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
- #if HAVE_SYS_EPOLL_H
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
- #if HAVE_SYS_EPOLL_H
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
@@ -523,14 +523,14 @@ handle_rack_inner(VALUE x) {
523
523
  if (Qnil != body) {
524
524
  body = rb_ivar_get(body, rb_intern("@body"));
525
525
  }
526
- if (rb_respond_to(body, rb_intern("each"))) {
527
- rb_iterate(rb_each, body, body_len_cb, (VALUE)&bsize);
526
+ if (rb_respond_to(body, each_id)) {
527
+ rb_block_call(body, each_id, 0, 0, body_len_cb, (VALUE)&bsize);
528
528
  }
529
529
  } else {
530
- rb_iterate(rb_each, bv, body_len_cb, (VALUE)&bsize);
530
+ rb_block_call(bv, each_id, 0, 0, body_len_cb, (VALUE)&bsize);
531
531
  }
532
532
  } else {
533
- rb_iterate(rb_each, bv, body_len_cb, (VALUE)&bsize);
533
+ rb_block_call(bv, each_id, 0, 0, body_len_cb, (VALUE)&bsize);
534
534
  }
535
535
  }
536
536
  switch (code) {
@@ -587,7 +587,7 @@ handle_rack_inner(VALUE x) {
587
587
  if (T_HASH == rb_type(hv)) {
588
588
  rb_hash_foreach(hv, header_cb, (VALUE)&t);
589
589
  } else {
590
- rb_iterate(rb_each, hv, header_each_cb, (VALUE)&t);
590
+ rb_block_call(hv, each_id, 0, 0, header_each_cb, (VALUE)&t);
591
591
  }
592
592
  }
593
593
  t = agoo_text_append(t, "\r\n", 2);
@@ -602,7 +602,7 @@ handle_rack_inner(VALUE x) {
602
602
  t = agoo_text_append(t, StringValuePtr(v), (int)RSTRING_LEN(v));
603
603
  }
604
604
  } else {
605
- rb_iterate(rb_each, bv, body_append_cb, (VALUE)&t);
605
+ rb_block_call(bv, each_id, 0, 0, body_append_cb, (VALUE)&t);
606
606
  }
607
607
  }
608
608
  agoo_res_message_push(req->res, t);
data/lib/agoo/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
2
  module Agoo
3
3
  # Agoo version.
4
- VERSION = '2.14.0'
4
+ VERSION = '2.14.3'
5
5
  end
@@ -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
@@ -79,6 +79,7 @@ end
79
79
  $songs_sdl = %^
80
80
  type Query @ruby(class: "Query") {
81
81
  artist(name: String!): Artist
82
+ artists: [Artist!]
82
83
  }
83
84
 
84
85
  type Mutation {
@@ -120,26 +121,30 @@ type Song {
120
121
  ^
121
122
 
122
123
  class Query
123
- attr_reader :artists
124
+ attr_reader :artistHash
124
125
 
125
126
  def initialize(artists)
126
- @artists = artists
127
+ @artistHash = artists
127
128
  end
128
129
 
129
130
  def artist(args)
130
- @artists[args['name']]
131
+ @artistHash[args['name']]
132
+ end
133
+
134
+ def artists(args)
135
+ @artistHash.values
131
136
  end
132
137
  end
133
138
 
134
139
  class Mutation
135
- attr_reader :artists
140
+ attr_reader :artistHash
136
141
 
137
142
  def initialize(artists)
138
- @artists = artists
143
+ @artistHash = artists
139
144
  end
140
145
 
141
146
  def like(args)
142
- artist = @artists[args['artist']]
147
+ artist = @artistHash[args['artist']]
143
148
  artist.like
144
149
  artist
145
150
  end
@@ -187,6 +192,7 @@ type Mutation @ruby(class: "Mutation") {
187
192
 
188
193
  type Query @ruby(class: "Query") {
189
194
  artist(name: String!): Artist
195
+ artists: [Artist!]
190
196
  }
191
197
 
192
198
  type Song @ruby(class: "Song") {
@@ -452,6 +458,56 @@ fragment basic on Artist {
452
458
  post_test(uri, body, 'application/graphql', expect)
453
459
  end
454
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
+
487
+ def test_post_json_fragment
488
+ uri = URI('http://localhost:6472/graphql?indent=2')
489
+ body = %^{
490
+ "query": "fragment basic on Artist {name origin} query list($filter: String) {artists {...basic}}",
491
+ "operationName": "list",
492
+ "variables": {"filters": {}}
493
+ }^
494
+ expect = %^{
495
+ "data":{
496
+ "artists":[
497
+ {
498
+ "name":"Fazerdaze",
499
+ "origin":[
500
+ "Morningside",
501
+ "Auckland",
502
+ "New Zealand"
503
+ ]
504
+ }
505
+ ]
506
+ }
507
+ }^
508
+ post_test(uri, body, 'application/json', expect)
509
+ end
510
+
455
511
  def test_post_inline
456
512
  uri = URI('http://localhost:6472/graphql?indent=2')
457
513
  body = %^
@@ -1014,7 +1070,7 @@ mutation {
1014
1070
  assert_equal(expect, content)
1015
1071
  end
1016
1072
 
1017
- def post_test(uri, body, content_type, expect)
1073
+ def post_test(uri, body, content_type, expect, ignore=nil)
1018
1074
  uri = URI(uri)
1019
1075
  req = Net::HTTP::Post.new(uri)
1020
1076
  req['Accept-Encoding'] = '*'
@@ -1025,6 +1081,11 @@ mutation {
1025
1081
  }
1026
1082
  content = res.body
1027
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
1028
1089
  assert_equal(expect, content)
1029
1090
  end
1030
1091
  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.14.0
4
+ version: 2.14.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Ohler
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-11-07 00:00:00.000000000 Z
11
+ date: 2022-05-05 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
@@ -163,7 +164,7 @@ homepage: https://github.com/ohler55/agoo
163
164
  licenses:
164
165
  - MIT
165
166
  metadata: {}
166
- post_install_message:
167
+ post_install_message:
167
168
  rdoc_options:
168
169
  - "-t"
169
170
  - Agoo
@@ -189,17 +190,18 @@ required_rubygems_version: !ruby/object:Gem::Requirement
189
190
  version: '0'
190
191
  requirements:
191
192
  - Linux or macOS
192
- rubygems_version: 3.1.2
193
- signing_key:
193
+ rubygems_version: 3.3.3
194
+ signing_key:
194
195
  specification_version: 4
195
196
  summary: An HTTP server
196
197
  test_files:
197
- - test/graphql_test.rb
198
- - test/hijack_test.rb
199
- - test/rack_handler_test.rb
200
198
  - test/base_handler_test.rb
201
- - test/log_test.rb
199
+ - test/bind_test.rb
202
200
  - test/domain_test.rb
203
201
  - test/early_hints_test.rb
204
- - test/bind_test.rb
202
+ - test/graphql_error_test.rb
203
+ - test/graphql_test.rb
204
+ - test/hijack_test.rb
205
+ - test/log_test.rb
206
+ - test/rack_handler_test.rb
205
207
  - test/static_test.rb