agoo 2.14.1 → 2.15.0

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: 0fbaa8a1e2f42cda657178256643bcf0161f93d9be09e90512084eb877b12aa9
4
- data.tar.gz: e33135684316f9e0244f0cc2e781561f99374888c7756866e0d2ed33db1c0446
3
+ metadata.gz: 1774bcd29b45056263ad986722015b99efa5c2bc8b0607b3a08afb79cd40cd70
4
+ data.tar.gz: dddc4062987102c87f1e2556ad425b33f3e0dd0a380c2a2416348ba2e07869d2
5
5
  SHA512:
6
- metadata.gz: 630cf6226a74119dbb5417a8a33df2893e08e61acd6037f61d6d6a1d424c22a7bb61bfa59c65420b3e4026a421764b128b36ca9ae5dc2087722f338228f2e732
7
- data.tar.gz: 6798931eaa91d29ccc0e6abe701cc62cc44b129b22e34f0f0dc53e26f409ca27c7a001424197f9c4c2f02820a8a670e38609e408ca4b6e5069957c9981a6b49f
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
  # [![{}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,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
- #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) {
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/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
@@ -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, rb_intern("each"))) {
527
- rb_iterate(rb_each, body, body_len_cb, (VALUE)&bsize);
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
- rb_iterate(rb_each, bv, body_len_cb, (VALUE)&bsize);
531
+ rb_block_call(bv, each_id, 0, 0, body_len_cb, (VALUE)&bsize);
531
532
  }
532
533
  } else {
533
- rb_iterate(rb_each, bv, body_len_cb, (VALUE)&bsize);
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
- rb_iterate(rb_each, hv, header_each_cb, (VALUE)&t);
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
- rb_iterate(rb_each, bv, body_append_cb, (VALUE)&t);
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
@@ -1,5 +1,5 @@
1
1
 
2
2
  module Agoo
3
3
  # Agoo version.
4
- VERSION = '2.14.1'
4
+ VERSION = '2.15.0'
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
@@ -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
@@ -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.14.1
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: 2021-06-09 00:00:00.000000000 Z
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.2.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