agoo 2.15.13 → 2.15.15

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1d25af07a365bf540edf65b600f250c8a6ae25b0aef09f9ad96dfe8be43a1dd8
4
- data.tar.gz: b460cc434a4b18a05d040b5771c2c4031a3c40ead1d3759e0b92d26756e76ccf
3
+ metadata.gz: 4082bd93ed8668165d61bae2e0cc68d6bb4ff4c015172e281f1f4c81193e635f
4
+ data.tar.gz: a93f805c0d630183abd684e1c995b649f42573d41dcb01e48e68949ec520a036
5
5
  SHA512:
6
- metadata.gz: 9eb4d926cca9cd7c613ce395299b3d82ad5cfedc3187956193de90b0aac4909dd89202982f4d3d3820515ccaa5f385725cdc767144eaca0e568091935336aaee
7
- data.tar.gz: e80520cd9ab1d0f7dc9535938113165735164b63942cd89e16881051d9edef3ff828a51771824ac127f078d71e3f9d3f6de17ccef5ae01092bffb0091fd6e9ba
6
+ metadata.gz: c9c668862fd616a3579ab3164ba98a04fbdf58ac4ae86ddd7d28facfbb6e665ced1298becace7ed5047fb6b9a1a0a2a6a79b87661139f1b3fc9561e499277c76
7
+ data.tar.gz: 96f3f2c3c732e0bc26438185399b1aeb0494f63564678e2c2bb6ba8340c199dd8950aec1dd347bcf75513b87bbb50240efba9a858ee9684bc8a3acec396caf10
data/CHANGELOG.md CHANGED
@@ -2,6 +2,22 @@
2
2
 
3
3
  All changes to the Agoo gem are documented here. Releases follow semantic versioning.
4
4
 
5
+ ## [2.15.15] - 2026-05-09
6
+
7
+ ### Fixed
8
+
9
+ - Moved URL decoding to before page lookup invalid denial.
10
+
11
+ - Eliminated deprecated code warnings.
12
+
13
+ - Fix issue Connection string too long error.
14
+
15
+ ## [2.15.14] - 2025-09-24
16
+
17
+ ### Fixed
18
+
19
+ - HTTP DELETE requests can now include a body.
20
+
5
21
  ## [2.15.13] - 2024-10-20
6
22
 
7
23
  ### Fixed
data/ext/agoo/con.c CHANGED
@@ -26,8 +26,6 @@
26
26
  #include "upgraded.h"
27
27
  #include "websocket.h"
28
28
 
29
- #define INITIAL_POLL_SIZE 1024
30
-
31
29
  double con_timeout = 30.0;
32
30
 
33
31
  typedef enum {
@@ -297,6 +295,10 @@ con_header_read(agooCon c, size_t *mlenp) {
297
295
  agooHook hook = NULL;
298
296
  agooPage p;
299
297
  struct _agooErr err = AGOO_ERR_INIT;
298
+ const char *v;
299
+ int vlen = 0;
300
+ char *vend;
301
+
300
302
 
301
303
  if (NULL == hend) {
302
304
  if (sizeof(c->buf) - 1 <= c->bcnt) {
@@ -321,11 +323,7 @@ con_header_read(agooCon c, size_t *mlenp) {
321
323
  }
322
324
  method = AGOO_GET;
323
325
  break;
324
- case 'P': {
325
- const char *v;
326
- int vlen = 0;
327
- char *vend;
328
-
326
+ case 'P':
329
327
  if (3 == b - c->buf && 0 == strncmp("PUT", c->buf, 3)) {
330
328
  method = AGOO_PUT;
331
329
  } else if (4 == b - c->buf && 0 == strncmp("POST", c->buf, 4)) {
@@ -343,12 +341,17 @@ con_header_read(agooCon c, size_t *mlenp) {
343
341
  return bad_request(c, 411, __LINE__);
344
342
  }
345
343
  break;
346
- }
347
344
  case 'D':
348
345
  if (6 != b - c->buf || 0 != strncmp("DELETE", c->buf, 6)) {
349
346
  return bad_request(c, 400, __LINE__);
350
347
  }
351
348
  method = AGOO_DELETE;
349
+ if (NULL != (v = agoo_con_header_value(c->buf, (int)(hend - c->buf), "Content-Length", &vlen))) {
350
+ clen = (size_t)strtoul(v, &vend, 10);
351
+ if (vend != v + vlen) {
352
+ return bad_request(c, 411, __LINE__);
353
+ }
354
+ }
352
355
  break;
353
356
  case 'H':
354
357
  if (4 != b - c->buf || 0 != strncmp("HEAD", c->buf, 4)) {
data/ext/agoo/doc.c CHANGED
@@ -13,7 +13,7 @@
13
13
  #define EXP_MAX 100000
14
14
  #define DEC_MAX 16
15
15
 
16
- static char char_map[256] = "\
16
+ static char char_map[257] = "\
17
17
  .........ww..w..................\
18
18
  wpq.....pp..w.p.ttttttttttp..p..\
19
19
  pttttttttttttttttttttttttttp.p.t\
@@ -23,7 +23,7 @@ pttttttttttttttttttttttttttp.p.t\
23
23
  ................................\
24
24
  ................................";
25
25
 
26
- static char json_map[256] = "\
26
+ static char json_map[257] = "\
27
27
  .........ww..w..................\
28
28
  wpq.....pp..c.p.ttttttttttp..p..\
29
29
  pttttttttttttttttttttttttttp.p.t\
@@ -33,7 +33,7 @@ pttttttttttttttttttttttttttp.p.t\
33
33
  ................................\
34
34
  ................................";
35
35
 
36
- static char value_map[256] = "\
36
+ static char value_map[257] = "\
37
37
  .........ww..w..................\
38
38
  wpq.....pp..ctt.ttttttttttt..p..\
39
39
  pttttttttttttttttttttttttttp.p.t\
@@ -24,6 +24,22 @@ eh_free(void *ptr) {
24
24
  }
25
25
  }
26
26
 
27
+ static size_t
28
+ eh_size(const void *ptr) {
29
+ return sizeof(struct _earlyHints);
30
+ }
31
+
32
+ static const rb_data_type_t early_hints_type = {
33
+ .wrap_struct_name = "early_hints",
34
+ .function = {
35
+ .dmark = NULL,
36
+ .dfree = eh_free,
37
+ .dsize = eh_size,
38
+ },
39
+ .data = NULL,
40
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
41
+ };
42
+
27
43
  VALUE
28
44
  agoo_early_hints_new(agooReq req) {
29
45
  EarlyHints eh = (EarlyHints)AGOO_CALLOC(1, sizeof(struct _earlyHints));
@@ -33,7 +49,7 @@ agoo_early_hints_new(agooReq req) {
33
49
  }
34
50
  eh->req = req;
35
51
 
36
- return Data_Wrap_Struct(eh_class, NULL, eh_free, eh);
52
+ return TypedData_Wrap_Struct(eh_class, &early_hints_type, eh);
37
53
  }
38
54
 
39
55
  /* Document-method: call
@@ -22,6 +22,22 @@ es_free(void *ptr) {
22
22
  }
23
23
  }
24
24
 
25
+ static size_t
26
+ es_size(const void *ptr) {
27
+ return sizeof(struct _errorStream);
28
+ }
29
+
30
+ static const rb_data_type_t error_stream_type = {
31
+ .wrap_struct_name = "error_stream",
32
+ .function = {
33
+ .dmark = NULL,
34
+ .dfree = es_free,
35
+ .dsize = es_size,
36
+ },
37
+ .data = NULL,
38
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
39
+ };
40
+
25
41
  VALUE
26
42
  error_stream_new(void) {
27
43
  ErrorStream es = (ErrorStream)AGOO_MALLOC(sizeof(struct _errorStream));
@@ -32,7 +48,7 @@ error_stream_new(void) {
32
48
  es->server = NULL;
33
49
  es->text = NULL;
34
50
 
35
- return Data_Wrap_Struct(es_class, NULL, es_free, es);
51
+ return TypedData_Wrap_Struct(es_class, &error_stream_type, es);
36
52
  }
37
53
 
38
54
  /* Document-method: puts
data/ext/agoo/gqlvalue.c CHANGED
@@ -10,7 +10,7 @@
10
10
  #include "graphql.h"
11
11
  #include "sectime.h"
12
12
 
13
- static const char spaces[256] = "\n ";
13
+ static const char spaces[257] = "\n ";
14
14
 
15
15
  // Null type
16
16
  static agooText
data/ext/agoo/graphql.c CHANGED
@@ -24,7 +24,7 @@ typedef struct _slot {
24
24
 
25
25
  static Slot buckets[BUCKET_SIZE];
26
26
 
27
- static uint8_t name_chars[256] = "\
27
+ static uint8_t name_chars[257] = "\
28
28
  \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
29
29
  \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
30
30
  \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
@@ -43,7 +43,7 @@ static uint8_t name_chars[256] = "\
43
43
  \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
44
44
  ";
45
45
 
46
- static const char spaces[16] = " ";
46
+ static const char spaces[17] = " ";
47
47
 
48
48
  gqlDir gql_directives = NULL;
49
49
 
data/ext/agoo/http.c CHANGED
@@ -27,7 +27,7 @@ struct _cache key_cache;
27
27
 
28
28
  // The rack spec indicates the characters (),/:;<=>?@[]{} are invalid which
29
29
  // clearly is not consistent with RFC7230 so stick with the RFC.
30
- static char header_value_chars[256] = "\
30
+ static char header_value_chars[257] = "\
31
31
  xxxxxxxxxxoxxxxxxxxxxxxxxxxxxxxx\
32
32
  oooooooooooooooooooooooooooooooo\
33
33
  oooooooooooooooooooooooooooooooo\
data/ext/agoo/page.c CHANGED
@@ -788,114 +788,66 @@ page_check(agooErr err, agooPage page) {
788
788
  agooPage
789
789
  agoo_page_get(agooErr err, const char *path, int plen, const char *root) {
790
790
  agooPage page = NULL;
791
+ char full_path[2048];
792
+ char *s;
791
793
 
792
- if (NULL != strstr(path, "../")) {
794
+ if (NULL != root) {
795
+ s = stpcpy(full_path, root);
796
+ } else if (NULL != cache.root) {
797
+ s = stpcpy(full_path, cache.root);
798
+ } else {
799
+ s = full_path;
800
+ }
801
+ // This catches the accidental repeated / but not the intentional URL
802
+ // encoding which is detected and denied later.
803
+ if ('/' != *(s - 1) && '/' != *path) {
804
+ *s++ = '/';
805
+ }
806
+ if ((int)sizeof(full_path) <= plen + (s - full_path)) {
807
+ AGOO_ERR_MEM(err, "Page path");
808
+ return NULL;
809
+ }
810
+ if (NULL != memchr(path, '%', plen)) {
811
+ const char *pend = path + plen;
812
+ const char *pp = path;
813
+
814
+ for (; pp < pend; pp++) {
815
+ if ('%' != *pp) {
816
+ *s++ = *pp;
817
+ continue;
818
+ }
819
+ *s++ = parse_percent_seq(pp+1);
820
+ pp += 2;
821
+ }
822
+ } else {
823
+ strncpy(s, path, plen);
824
+ s += plen;
825
+ }
826
+ *s = '\0';
827
+ // full_path is now URL decoded.
828
+ if (NULL != strstr(full_path, "../") || NULL != strstr(full_path, "//")) {
793
829
  return NULL;
794
830
  }
795
- if (NULL != root) {
796
- char full_path[2048];
797
- char *s = stpcpy(full_path, root);
798
-
799
- if (NULL != strstr(path, "../")) {
800
- return NULL;
801
- }
802
- if ((int)sizeof(full_path) <= plen + (s - full_path)) {
803
- AGOO_ERR_MEM(err, "Page path");
804
- return NULL;
805
- }
806
- if ('/' != *(s - 1) && '/' != *path) {
807
- *s++ = '/';
808
- }
809
- // TBD if path has % then ...
810
- if (NULL != memchr(path, '%', plen)) {
811
- const char *pend = path + plen;
812
- const char *pp = path;
813
-
814
- for (; pp < pend; pp++) {
815
- if ('%' != *pp) {
816
- *s++ = *pp;
817
- continue;
818
- }
819
- *s++ = parse_percent_seq(pp+1);
820
- pp += 2;
821
- }
822
- } else {
823
- strncpy(s, path, plen);
824
- s += plen;
825
- }
826
- *s = '\0';
827
- plen = (int)(s - full_path);
828
- if (NULL == (page = cache_root_get(full_path, plen))) {
829
- if (NULL != cache.root) {
830
- agooPage old;
831
-
832
- if (NULL == (page = agoo_page_create(full_path))) {
833
- AGOO_ERR_MEM(err, "Page");
834
- return NULL;
835
- }
836
- if (!update_contents(page) || NULL == page->resp) {
837
- agoo_page_destroy(page);
838
- agoo_err_set(err, AGOO_ERR_NOT_FOUND, "not found.");
839
- return NULL;
840
- }
841
- if (NULL != (old = cache_root_set(full_path, plen, page))) {
842
- agoo_page_destroy(old);
843
- }
844
- }
845
- } else {
846
- page = page_check(err, page);
847
- }
831
+ plen = (int)(s - full_path);
832
+ if (NULL == (page = cache_root_get(full_path, plen))) {
833
+ if (NULL != cache.root) {
834
+ agooPage old;
835
+
836
+ if (NULL == (page = agoo_page_create(full_path))) {
837
+ AGOO_ERR_MEM(err, "Page");
838
+ return NULL;
839
+ }
840
+ if (!update_contents(page) || NULL == page->resp) {
841
+ agoo_page_destroy(page);
842
+ agoo_err_set(err, AGOO_ERR_NOT_FOUND, "not found.");
843
+ return NULL;
844
+ }
845
+ if (NULL != (old = cache_root_set(full_path, plen, page))) {
846
+ agoo_page_destroy(old);
847
+ }
848
+ }
848
849
  } else {
849
- if (NULL == (page = cache_get(path, plen))) {
850
- bool has_percent = NULL != memchr(path, '%', plen);
851
-
852
- if (NULL != cache.root || has_percent) {
853
- agooPage old;
854
- char full_path[2048];
855
- char *s = stpcpy(full_path, cache.root);
856
-
857
- if ('/' != *(s - 1) && '/' != *path) {
858
- *s++ = '/';
859
- }
860
- if ((int)sizeof(full_path) <= plen + (s - full_path)) {
861
- AGOO_ERR_MEM(err, "Page path");
862
- return NULL;
863
- }
864
- if (has_percent) {
865
- const char *pend = path + plen;
866
- const char *pp = path;
867
-
868
- for (; pp < pend; pp++) {
869
- if ('%' != *pp) {
870
- *s++ = *pp;
871
- continue;
872
- }
873
- *s++ = parse_percent_seq(pp+1);
874
- pp += 2;
875
- }
876
- *s = '\0';
877
- } else {
878
- strncpy(s, path, plen);
879
- s[plen] = '\0';
880
- }
881
- if (NULL == (page = agoo_page_create(full_path))) { // TBD full_path or original path?
882
- AGOO_ERR_MEM(err, "Page");
883
- return NULL;
884
- }
885
- plen = (int)strlen(full_path);
886
- if (!update_contents(page) || NULL == page->resp) {
887
- agoo_page_destroy(page);
888
- agoo_err_set(err, AGOO_ERR_NOT_FOUND, "not found.");
889
- return NULL;
890
- }
891
- // Cache key is the original path/plen.
892
- if (NULL != (old = cache_set(path, plen, page))) {
893
- agoo_page_destroy(old);
894
- }
895
- }
896
- } else {
897
- page = page_check(err, page);
898
- }
850
+ page = page_check(err, page);
899
851
  }
900
852
  return page;
901
853
  }
data/ext/agoo/queue.c CHANGED
@@ -57,15 +57,20 @@ agoo_queue_multi_init(agooErr err, agooQueue q, size_t qsize, bool multi_push, b
57
57
 
58
58
  void
59
59
  agoo_queue_cleanup(agooQueue q) {
60
+ int sock = q->wsock;
61
+
62
+ q->wsock = 0;
63
+ if (0 < sock) {
64
+ close(sock);
65
+ }
66
+ sock = q->rsock;
67
+ q->rsock = 0;
68
+ if (0 < sock) {
69
+ close(sock);
70
+ }
60
71
  AGOO_FREE(q->q);
61
72
  q->q = NULL;
62
73
  q->end = NULL;
63
- if (0 < q->wsock) {
64
- close(q->wsock);
65
- }
66
- if (0 < q->rsock) {
67
- close(q->rsock);
68
- }
69
74
  }
70
75
 
71
76
  void
data/ext/agoo/request.c CHANGED
@@ -483,7 +483,6 @@ fill_headers(agooReq r, VALUE hash) {
483
483
  if (NULL == r) {
484
484
  rb_raise(rb_eArgError, "Request is no longer valid.");
485
485
  }
486
-
487
486
  for (; h < end; h++) {
488
487
  switch (*h) {
489
488
  case ':':
@@ -515,10 +514,12 @@ fill_headers(agooReq r, VALUE hash) {
515
514
  } else if (sizeof(connection_key) - 1 == klen && 0 == strncasecmp(key, connection_key, sizeof(connection_key) - 1)) {
516
515
  char buf[1024];
517
516
 
518
- strncpy(buf, val, vend - val);
519
- buf[sizeof(buf)-1] = '\0';
520
- if (NULL != strstr(buf, upgrade_key)) {
521
- upgrade = true;
517
+ if (vend - val < (long)sizeof(buf) - 1) {
518
+ strncpy(buf, val, vend - val);
519
+ buf[sizeof(buf)-1] = '\0';
520
+ if (NULL != strstr(buf, upgrade_key)) {
521
+ upgrade = true;
522
+ }
522
523
  }
523
524
  } else if (sizeof(accept_key) - 1 == klen && 0 == strncasecmp(key, accept_key, sizeof(accept_key) - 1)) {
524
525
  if (sizeof(event_stream_val) - 1 == vend - val &&
@@ -739,10 +740,28 @@ request_mark(void *ptr) {
739
740
  }
740
741
  }
741
742
 
743
+ static size_t
744
+ request_size(const void *ptr) {
745
+ agooReq r = (agooReq)ptr;
746
+
747
+ return sizeof(struct _agooReq) + r->mlen - 8;
748
+ }
749
+
750
+ static const rb_data_type_t request_type = {
751
+ .wrap_struct_name = "request",
752
+ .function = {
753
+ .dmark = request_mark,
754
+ .dfree = NULL,
755
+ .dsize = request_size,
756
+ },
757
+ .data = NULL,
758
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
759
+ };
760
+
742
761
  VALUE
743
762
  request_wrap(agooReq req) {
744
763
  // freed from the C side of things
745
- return Data_Wrap_Struct(req_class, request_mark, NULL, req);
764
+ return TypedData_Wrap_Struct(req_class, &request_type, req);
746
765
  }
747
766
 
748
767
  /* Document-class: Agoo::Request
data/ext/agoo/rresponse.c CHANGED
@@ -24,6 +24,22 @@ response_free(void *ptr) {
24
24
  AGOO_FREE(ptr);
25
25
  }
26
26
 
27
+ static size_t
28
+ response_size(const void *ptr) {
29
+ return sizeof(struct _agooResponse);
30
+ }
31
+
32
+ static const rb_data_type_t response_type = {
33
+ .wrap_struct_name = "response",
34
+ .function = {
35
+ .dmark = NULL,
36
+ .dfree = response_free,
37
+ .dsize = response_size,
38
+ },
39
+ .data = NULL,
40
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
41
+ };
42
+
27
43
  VALUE
28
44
  response_new(void) {
29
45
  agooResponse res = (agooResponse)AGOO_MALLOC(sizeof(struct _agooResponse));
@@ -34,7 +50,7 @@ response_new(void) {
34
50
  memset(res, 0, sizeof(struct _agooResponse));
35
51
  res->code = 200;
36
52
 
37
- return Data_Wrap_Struct(res_class, NULL, response_free, res);
53
+ return TypedData_Wrap_Struct(res_class, &response_type, res);
38
54
  }
39
55
 
40
56
  /* Document-method: to_s
data/ext/agoo/rserver.c CHANGED
@@ -1292,6 +1292,23 @@ use(int argc, VALUE *argv, VALUE self) {
1292
1292
  return Qnil;
1293
1293
  }
1294
1294
 
1295
+ static size_t
1296
+ server_size(const void *ptr) {
1297
+ return sizeof(struct _agooServer);
1298
+ }
1299
+
1300
+ static const rb_data_type_t server_type = {
1301
+ .wrap_struct_name = "server",
1302
+ .function = {
1303
+ .dmark = server_mark,
1304
+ .dfree = NULL,
1305
+ .dsize = server_size,
1306
+ },
1307
+ .data = NULL,
1308
+ .flags = 0,
1309
+ };
1310
+
1311
+
1295
1312
  /* Document-class: Agoo::Server
1296
1313
  *
1297
1314
  * An HTTP server that support the rack API as well as some other optimized
@@ -1335,7 +1352,8 @@ server_init(VALUE mod) {
1335
1352
 
1336
1353
  push_env_key = rb_str_new_cstr("rack.upgrade"); rb_gc_register_address(&push_env_key);
1337
1354
 
1338
- rserver = Data_Wrap_Struct(rb_cObject, server_mark, NULL, strdup("dummy"));
1355
+ rserver = TypedData_Wrap_Struct(rb_cObject, &server_type, strdup("dummy"));
1356
+
1339
1357
  rb_gc_register_address(&rserver);
1340
1358
 
1341
1359
  agoo_http_init();
data/ext/agoo/rupgraded.c CHANGED
@@ -231,6 +231,22 @@ on_destroy(agooUpgraded up) {
231
231
  }
232
232
  }
233
233
 
234
+ static size_t
235
+ upgraded_size(const void *ptr) {
236
+ return sizeof(struct _agooUpgraded);
237
+ }
238
+
239
+ static const rb_data_type_t upgraded_type = {
240
+ .wrap_struct_name = "upgraded",
241
+ .function = {
242
+ .dmark = NULL,
243
+ .dfree = NULL,
244
+ .dsize = upgraded_size,
245
+ },
246
+ .data = NULL,
247
+ .flags = 0,
248
+ };
249
+
234
250
  agooUpgraded
235
251
  rupgraded_create(agooCon c, VALUE obj, VALUE env) {
236
252
  agooUpgraded up;
@@ -246,7 +262,7 @@ rupgraded_create(agooCon c, VALUE obj, VALUE env) {
246
262
  up->on_error = rb_respond_to(obj, rb_intern("on_error"));
247
263
  up->on_destroy = on_destroy;
248
264
 
249
- up->wrap = (void*)Data_Wrap_Struct(upgraded_class, NULL, NULL, up);
265
+ up->wrap = (void*)TypedData_Wrap_Struct(upgraded_class, &upgraded_type, up);
250
266
 
251
267
  agoo_server_add_upgraded(up);
252
268
 
data/ext/agoo/server.c CHANGED
@@ -163,12 +163,12 @@ listen_loop(void *x) {
163
163
  agoo_log_cat(&agoo_con_cat, "Server with pid %d accepted connection %llu on %s [%d] from %s",
164
164
  getpid(), (unsigned long long)cnt, b->id, con->sock, con->remote);
165
165
 
166
- /* TBD
167
- con_cnt = atomic_fetch_add(&agoo_server.con_cnt, 1);
168
- if (agoo_server.loop_max > agoo_server.loop_cnt && agoo_server.loop_cnt * LOOP_UP < con_cnt) {
169
- add_con_loop();
170
- }
171
- */
166
+ /* TBD
167
+ con_cnt = atomic_fetch_add(&agoo_server.con_cnt, 1);
168
+ if (agoo_server.loop_max > agoo_server.loop_cnt && agoo_server.loop_cnt * LOOP_UP < con_cnt) {
169
+ add_con_loop();
170
+ }
171
+ */
172
172
  agoo_queue_push(&agoo_server.con_queue, (void*)con);
173
173
  }
174
174
  }
data/ext/agoo/text.c CHANGED
@@ -10,7 +10,7 @@
10
10
 
11
11
  static const char hex_chars[17] = "0123456789abcdef";
12
12
 
13
- static char json_chars[256] = "\
13
+ static char json_chars[257] = "\
14
14
  66666666222622666666666666666666\
15
15
  11211111111111111111111111111111\
16
16
  11111111111111111111111111112111\
data/lib/agoo/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
2
  module Agoo
3
3
  # Agoo version.
4
- VERSION = '2.15.13'
4
+ VERSION = '2.15.15'
5
5
  end
@@ -29,6 +29,9 @@ class BaseHandlerTest < Minitest::Test
29
29
  elsif 'PUT' == req.request_method
30
30
  res.code = 201
31
31
  res.body = req.body
32
+ elsif 'DELETE' == req.request_method
33
+ res.code = 200
34
+ res.body = req.body
32
35
  end
33
36
  end
34
37
  end
@@ -66,6 +69,7 @@ class BaseHandlerTest < Minitest::Test
66
69
  Agoo::Server.handle(:PUT, "/makeme", handler)
67
70
  Agoo::Server.handle(:GET, "/wild/*/one", WildHandler.new('one'))
68
71
  Agoo::Server.handle(:GET, "/wild/all/**", WildHandler.new('all'))
72
+ Agoo::Server.handle(:DELETE, "/notme", handler)
69
73
 
70
74
  Agoo::Server.start()
71
75
 
@@ -118,9 +122,52 @@ class BaseHandlerTest < Minitest::Test
118
122
  }
119
123
  expect.each_pair { |k,v|
120
124
  if v.nil?
121
- assert_nil(obj[k], k)
125
+ assert_nil(obj[k], k)
126
+ else
127
+ assert_equal(v, obj[k], k)
128
+ end
129
+ }
130
+ end
131
+
132
+ def test_long_connection
133
+ uri = URI('http://localhost:6470/tellme?a=1')
134
+ req = Net::HTTP::Get.new(uri)
135
+ # Set the headers the way we want them.
136
+ req['Accept-Encoding'] = '*'
137
+ req['Accept'] = 'application/json'
138
+ req['User-Agent'] = 'Ruby'
139
+ req['Connection'] = 'X'* 1024 # should not cause a failure
140
+
141
+ res = Net::HTTP.start(uri.hostname, uri.port) { |h|
142
+ h.request(req)
143
+ }
144
+ content = res.body
145
+ obj = Oj.load(content, mode: :strict)
146
+
147
+ expect = {
148
+ "HTTP_ACCEPT" => "application/json",
149
+ "HTTP_ACCEPT_ENCODING" => "*",
150
+ "HTTP_USER_AGENT" => "Ruby",
151
+ "PATH_INFO" => "/tellme",
152
+ "QUERY_STRING" => "a=1",
153
+ "REQUEST_METHOD" => "GET",
154
+ "SCRIPT_NAME" => "",
155
+ "SERVER_NAME" => "localhost",
156
+ "SERVER_PORT" => "6470",
157
+ "rack.errors" => nil,
158
+ "rack.input" => nil,
159
+ "rack.multiprocess" => false,
160
+ "rack.multithread" => false,
161
+ "rack.run_once" => false,
162
+ "rack.url_scheme" => "http",
163
+ "rack.version" => [1, 3],
164
+ "rack.logger" => nil,
165
+ }
166
+ expect.each_pair { |k,v|
167
+ if v.nil?
168
+ assert_nil(obj[k], k)
122
169
  else
123
- assert_equal(v, obj[k], k)
170
+ assert_equal(v, obj[k], k)
124
171
  end
125
172
  }
126
173
  end
@@ -155,6 +202,21 @@ class BaseHandlerTest < Minitest::Test
155
202
  assert_equal('hello', res.body)
156
203
  end
157
204
 
205
+ def test_delete
206
+ uri = URI('http://localhost:6470/notme')
207
+ req = Net::HTTP::Delete.new(uri)
208
+ # Set the headers the way we want them.
209
+ req['Accept-Encoding'] = '*'
210
+ req['Accept'] = 'application/json'
211
+ req['User-Agent'] = 'Ruby'
212
+ req.body = 'goodbye'
213
+
214
+ res = Net::HTTP.start(uri.hostname, uri.port) { |h|
215
+ h.request(req)
216
+ }
217
+ assert_equal('goodbye', res.body)
218
+ end
219
+
158
220
  def test_wild_one
159
221
  uri = URI('http://localhost:6470/wild/abc/one')
160
222
  req = Net::HTTP::Get.new(uri)
data/test/static_test.rb CHANGED
@@ -124,4 +124,16 @@ class StaticTest < Minitest::Test
124
124
  assert_equal("404", res.code)
125
125
  end
126
126
 
127
+ def test_fetch_encoded
128
+ uri = URI('http://localhost:6469/%2e%2e%2ftests.sh')
129
+ res = Net::HTTP.get_response(uri)
130
+ assert_equal("404", res.code)
131
+ end
132
+
133
+ def test_fetch_double_slash
134
+ uri = URI('http://localhost:6469/%2f/nest/something.txt')
135
+ res = Net::HTTP.get_response(uri)
136
+ assert_equal("404", res.code)
137
+ end
138
+
127
139
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: agoo
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.15.13
4
+ version: 2.15.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Ohler
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-10-20 00:00:00.000000000 Z
10
+ date: 2026-05-09 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: oj
@@ -38,16 +37,16 @@ executables:
38
37
  extensions:
39
38
  - ext/agoo/extconf.rb
40
39
  extra_rdoc_files:
41
- - README.md
42
40
  - CHANGELOG.md
43
41
  - LICENSE
42
+ - README.md
44
43
  - misc/flymd.md
44
+ - misc/glue-diagram.svg
45
45
  - misc/glue.md
46
46
  - misc/optimize.md
47
47
  - misc/push.md
48
48
  - misc/rails.md
49
49
  - misc/song.md
50
- - misc/glue-diagram.svg
51
50
  files:
52
51
  - CHANGELOG.md
53
52
  - LICENSE
@@ -183,7 +182,6 @@ metadata:
183
182
  documentation_uri: http://www.ohler.com/agoo/index.html
184
183
  source_code_uri: https://github.com/ohler55/agoo
185
184
  homepage: https://github.com/ohler55/agoo
186
- post_install_message:
187
185
  rdoc_options:
188
186
  - "-t"
189
187
  - Agoo
@@ -209,8 +207,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
209
207
  version: '0'
210
208
  requirements:
211
209
  - Linux or macOS
212
- rubygems_version: 3.5.11
213
- signing_key:
210
+ rubygems_version: 4.0.3
214
211
  specification_version: 4
215
212
  summary: An HTTP server
216
213
  test_files: