agoo 2.8.4 → 2.9.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of agoo might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4a08f7cfbaf708e9ae15b2c14c67b7ad06279ffefc55d3f8cdf02bf79d23ec2a
4
- data.tar.gz: cdad36a0a5599a9114509b6eff0e219b2f128851f3d95bee344140cfa9f74ba0
3
+ metadata.gz: c40533edbeaf9a5593680f15a5c7ad41ef5e1575b9235c10faf0ecb906bd472c
4
+ data.tar.gz: 81c3884669b222a050352386973bc40d79cdce7c748204d85825a684d91ecbe3
5
5
  SHA512:
6
- metadata.gz: 923b3465e9b1c30e20bf627c2ef6b300574a9e475b9bef28d754845ccc5bf407fec7c48b68553189b55a26ee98a55671f9e2a571b7ba86ff2831c1fe16fb2cc5
7
- data.tar.gz: 7b401ec9acc4373d18815266d312b3b30bbd2ab7d523b8be003f3a680ea57bbe4c791c6ab63bf77d2401ee01ac37a596aa785b06b26261547f38c0fe5bf4f248
6
+ metadata.gz: bc1b0f12bdb19c51a947fa73c981eab8e21b640448363c62d7433138f4320f39a317fc9937f5499398ab7414a15122533af23e2bcc25722bfa26844bdd9c9b7c
7
+ data.tar.gz: 939c1a7654f453b5d602097b0faed1010291040edddb4a67f99c0b14c50ac2944a45fc87c7e3eb758760a7ba9cf6c02f449aa54cb0daec5fe1864b331e2c1213
@@ -4,6 +4,19 @@ All changes to the Agoo gem are documented here. Releases follow semantic versio
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [2.9.0] - 2019-07-26
8
+
9
+ Early hints and sub-domains
10
+
11
+ ### Added
12
+
13
+ - Support for early hints added. This includes a server option to
14
+ activate and then a proposed `early_hints` member of the `env`
15
+ argument to the Rack `#call` method.
16
+
17
+ - Sub-domains based on the host header in an HTTP request can now
18
+ be used to set up multiple root directories.
19
+
7
20
  ## [2.8.4] - 2019-06-14
8
21
 
9
22
  GraphQL with Rack
@@ -9,6 +9,7 @@
9
9
 
10
10
  #include "atomic.h"
11
11
  #include "debug.h"
12
+ #include "early_hints.h"
12
13
  #include "error_stream.h"
13
14
  #include "graphql.h"
14
15
  #include "log.h"
@@ -109,6 +110,7 @@ Init_agoo() {
109
110
  server_init(mod);
110
111
  upgraded_init(mod);
111
112
  graphql_init(mod);
113
+ early_hints_init(mod);
112
114
 
113
115
  rb_define_module_function(mod, "shutdown", ragoo_shutdown, 0);
114
116
  rb_define_module_function(mod, "publish", ragoo_publish, 2);
@@ -9,6 +9,7 @@
9
9
  #include "bind.h"
10
10
  #include "con.h"
11
11
  #include "debug.h"
12
+ #include "domain.h"
12
13
  #include "dtime.h"
13
14
  #include "hook.h"
14
15
  #include "http.h"
@@ -152,7 +153,7 @@ bad_request(agooCon c, int status, int line) {
152
153
  }
153
154
  c->res_tail = res;
154
155
  res->close = true;
155
- agoo_res_set_message(res, message);
156
+ agoo_res_message_push(res, message, true);
156
157
  }
157
158
  return HEAD_ERR;
158
159
  }
@@ -188,7 +189,7 @@ page_response(agooCon c, agooPage p, char *hend) {
188
189
  if (res->close) {
189
190
  c->closing = true;
190
191
  }
191
- agoo_res_set_message(res, p->resp);
192
+ agoo_res_message_push(res, p->resp, true);
192
193
 
193
194
  return false;
194
195
  }
@@ -213,7 +214,7 @@ push_error(agooUpgraded up, const char *msg, int mlen) {
213
214
  }
214
215
 
215
216
  static HeadReturn
216
- agoo_con_header_read(agooCon c, size_t *mlenp) {
217
+ con_header_read(agooCon c, size_t *mlenp) {
217
218
  char *hend = strstr(c->buf, "\r\n\r\n");
218
219
  agooMethod method;
219
220
  struct _agooSeg path;
@@ -326,21 +327,35 @@ agoo_con_header_read(agooCon c, size_t *mlenp) {
326
327
  *mlenp = mlen;
327
328
 
328
329
  if (AGOO_GET == method) {
329
- if (NULL != (p = group_get(&err, path.start, (int)(path.end - path.start)))) {
330
+ char root_buf[20148];
331
+ const char *root = NULL;
332
+
333
+ if (NULL != (p = agoo_group_get(&err, path.start, (int)(path.end - path.start)))) {
330
334
  if (page_response(c, p, hend)) {
331
335
  return bad_request(c, 500, __LINE__);
332
336
  }
333
337
  return HEAD_HANDLED;
334
338
  }
339
+ if (agoo_domain_use()) {
340
+ const char *host;
341
+ int vlen = 0;
342
+
343
+ if (NULL == (host = agoo_con_header_value(c->buf, (int)(hend - c->buf), "Host", &vlen))) {
344
+ return bad_request(c, 411, __LINE__);
345
+ }
346
+ ((char*)host)[vlen] = '\0';
347
+ root = agoo_domain_resolve(host, root_buf, sizeof(root_buf));
348
+ ((char*)host)[vlen] = '\r';
349
+ }
335
350
  if (agoo_server.root_first &&
336
- NULL != (p = agoo_page_get(&err, path.start, (int)(path.end - path.start)))) {
351
+ NULL != (p = agoo_page_get(&err, path.start, (int)(path.end - path.start), root))) {
337
352
  if (page_response(c, p, hend)) {
338
353
  return bad_request(c, 500, __LINE__);
339
354
  }
340
355
  return HEAD_HANDLED;
341
356
  }
342
357
  if (NULL == (hook = agoo_hook_find(agoo_server.hooks, method, &path))) {
343
- if (NULL != (p = agoo_page_get(&err, path.start, (int)(path.end - path.start)))) {
358
+ if (NULL != (p = agoo_page_get(&err, path.start, (int)(path.end - path.start), root))) {
344
359
  if (page_response(c, p, hend)) {
345
360
  return bad_request(c, 500, __LINE__);
346
361
  }
@@ -379,7 +394,11 @@ agoo_con_header_read(agooCon c, size_t *mlenp) {
379
394
  c->req->body.len = (unsigned int)clen;
380
395
  b = strstr(b, "\r\n");
381
396
  c->req->header.start = c->req->msg + (b + 2 - c->buf);
382
- c->req->header.len = (unsigned int)(hend - b - 2);
397
+ if (b < hend) {
398
+ c->req->header.len = (unsigned int)(hend - b - 2);
399
+ } else {
400
+ c->req->header.len = 0;
401
+ }
383
402
  c->req->res = NULL;
384
403
  c->req->hook = hook;
385
404
 
@@ -443,7 +462,7 @@ agoo_con_http_read(agooCon c) {
443
462
  if (NULL == c->req) {
444
463
  size_t mlen;
445
464
 
446
- switch (agoo_con_header_read(c, &mlen)) {
465
+ switch (con_header_read(c, &mlen)) {
447
466
  case HEAD_AGAIN:
448
467
  // Try again the next time. Didn't read enough..
449
468
  return false;
@@ -629,7 +648,7 @@ con_ws_read(agooCon c) {
629
648
  // return false to remove/close connection
630
649
  bool
631
650
  agoo_con_http_write(agooCon c) {
632
- agooText message = agoo_res_message(c->res_head);
651
+ agooText message = agoo_res_message_peek(c->res_head);
633
652
  ssize_t cnt;
634
653
 
635
654
  if (NULL == message) {
@@ -665,17 +684,21 @@ agoo_con_http_write(agooCon c) {
665
684
  }
666
685
  c->wcnt += cnt;
667
686
  if (c->wcnt == message->len) { // finished
668
- agooRes res = c->res_head;
669
- bool done = res->close;
687
+ agooRes res = c->res_head;
688
+ agooText next = agoo_res_message_next(res);
670
689
 
671
- c->res_head = res->next;
672
- if (res == c->res_tail) {
673
- c->res_tail = NULL;
674
- }
675
690
  c->wcnt = 0;
676
- agoo_res_destroy(res);
691
+ if (NULL == next && res->final) {
692
+ bool done = res->close;
677
693
 
678
- return !done;
694
+ c->res_head = res->next;
695
+ if (res == c->res_tail) {
696
+ c->res_tail = NULL;
697
+ }
698
+ agoo_res_destroy(res);
699
+
700
+ return !done;
701
+ }
679
702
  }
680
703
  return true;
681
704
  }
@@ -686,7 +709,7 @@ static const char pong_msg[] = "\x8a\x00";
686
709
  static bool
687
710
  con_ws_write(agooCon c) {
688
711
  agooRes res = c->res_head;
689
- agooText message = agoo_res_message(res);
712
+ agooText message = agoo_res_message_peek(res);
690
713
  ssize_t cnt;
691
714
 
692
715
  if (NULL == message) {
@@ -752,7 +775,7 @@ con_ws_write(agooCon c) {
752
775
  }
753
776
  t = agoo_ws_expand(message);
754
777
  if (t != message) {
755
- agoo_res_set_message(res, t);
778
+ agoo_res_message_push(res, t, true);
756
779
  message = t;
757
780
  }
758
781
  }
@@ -772,17 +795,21 @@ con_ws_write(agooCon c) {
772
795
  }
773
796
  c->wcnt += cnt;
774
797
  if (c->wcnt == message->len) { // finished
775
- agooRes res = c->res_head;
776
- bool done = res->close;
798
+ agooRes res = c->res_head;
799
+ agooText next = agoo_res_message_next(res);
777
800
 
778
- c->res_head = res->next;
779
- if (res == c->res_tail) {
780
- c->res_tail = NULL;
781
- }
782
801
  c->wcnt = 0;
783
- agoo_res_destroy(res);
802
+ if (NULL == next && res->final) {
803
+ bool done = res->close;
784
804
 
785
- return !done;
805
+ c->res_head = res->next;
806
+ if (res == c->res_tail) {
807
+ c->res_tail = NULL;
808
+ }
809
+ agoo_res_destroy(res);
810
+
811
+ return !done;
812
+ }
786
813
  }
787
814
  return true;
788
815
  }
@@ -790,7 +817,7 @@ con_ws_write(agooCon c) {
790
817
  static bool
791
818
  con_sse_write(agooCon c) {
792
819
  agooRes res = c->res_head;
793
- agooText message = agoo_res_message(res);
820
+ agooText message = agoo_res_message_peek(res);
794
821
  ssize_t cnt;
795
822
 
796
823
  if (NULL == message) {
@@ -807,7 +834,7 @@ con_sse_write(agooCon c) {
807
834
  }
808
835
  t = agoo_sse_expand(message);
809
836
  if (t != message) {
810
- agoo_res_set_message(res, t);
837
+ agoo_res_message_push(res, t, true);
811
838
  message = t;
812
839
  }
813
840
  }
@@ -826,17 +853,21 @@ con_sse_write(agooCon c) {
826
853
  }
827
854
  c->wcnt += cnt;
828
855
  if (c->wcnt == message->len) { // finished
829
- agooRes res = c->res_head;
830
- bool done = res->close;
856
+ agooText next = agoo_res_message_next(c->res_head);
831
857
 
832
- c->res_head = res->next;
833
- if (res == c->res_tail) {
834
- c->res_tail = NULL;
835
- }
836
858
  c->wcnt = 0;
837
- agoo_res_destroy(res);
859
+ if (NULL == next) {
860
+ agooRes res = c->res_head;
861
+ bool done = res->close;
862
+
863
+ c->res_head = res->next;
864
+ if (res == c->res_tail) {
865
+ c->res_tail = NULL;
866
+ }
867
+ agoo_res_destroy(res);
838
868
 
839
- return !done;
869
+ return !done;
870
+ }
840
871
  }
841
872
  return true;
842
873
  }
@@ -859,7 +890,7 @@ publish_pub(agooPub pub, agooConLoop loop) {
859
890
  }
860
891
  up->con->res_tail = res;
861
892
  res->con_kind = AGOO_CON_ANY;
862
- agoo_res_set_message(res, agoo_text_dup(pub->msg));
893
+ agoo_res_message_push(res, agoo_text_dup(pub->msg), true);
863
894
  cnt++;
864
895
  }
865
896
  }
@@ -933,7 +964,7 @@ process_pub_con(agooPub pub, agooConLoop loop) {
933
964
  }
934
965
  up->con->res_tail = res;
935
966
  res->con_kind = AGOO_CON_ANY;
936
- agoo_res_set_message(res, pub->msg);
967
+ agoo_res_message_push(res, pub->msg, true);
937
968
  }
938
969
  }
939
970
  break;
@@ -962,7 +993,7 @@ short
962
993
  agoo_con_http_events(agooCon c) {
963
994
  short events = 0;
964
995
 
965
- if (NULL != c->res_head && NULL != agoo_res_message(c->res_head)) {
996
+ if (NULL != c->res_head && NULL != c->res_head->message) {
966
997
  events = POLLIN | POLLOUT;
967
998
  } else if (!c->closing) {
968
999
  events = POLLIN;
@@ -974,7 +1005,7 @@ static short
974
1005
  con_ws_events(agooCon c) {
975
1006
  short events = 0;
976
1007
 
977
- if (NULL != c->res_head && (c->res_head->close || c->res_head->ping || NULL != agoo_res_message(c->res_head))) {
1008
+ if (NULL != c->res_head && (c->res_head->close || c->res_head->ping || NULL != c->res_head->message)) {
978
1009
  events = POLLIN | POLLOUT;
979
1010
  } else if (!c->closing) {
980
1011
  events = POLLIN;
@@ -986,7 +1017,7 @@ static short
986
1017
  con_sse_events(agooCon c) {
987
1018
  short events = 0;
988
1019
 
989
- if (NULL != c->res_head && NULL != agoo_res_message(c->res_head)) {
1020
+ if (NULL != c->res_head && NULL != c->res_head->message) {
990
1021
  events = POLLOUT;
991
1022
  }
992
1023
  return events;
@@ -997,7 +1028,7 @@ remove_dead_res(agooCon c) {
997
1028
  agooRes res;
998
1029
 
999
1030
  while (NULL != (res = c->res_head)) {
1000
- if (NULL == agoo_res_message(c->res_head) && !c->res_head->close && !c->res_head->ping) {
1031
+ if (NULL == agoo_res_message_peek(c->res_head) && !c->res_head->close && !c->res_head->ping) {
1001
1032
  break;
1002
1033
  }
1003
1034
  c->res_head = res->next;
@@ -4,6 +4,7 @@
4
4
  #define AGOO_DEBUG_H
5
5
 
6
6
  #include <stdlib.h>
7
+ #include <string.h>
7
8
 
8
9
  #ifdef MEM_DEBUG
9
10
 
@@ -0,0 +1,145 @@
1
+ // Copyright 2019 by Peter Ohler, All Rights Reserved
2
+
3
+ #include <inttypes.h>
4
+ #include <regex.h>
5
+ #include <stdio.h>
6
+
7
+ #include "debug.h"
8
+ #include "domain.h"
9
+
10
+ #define MAX_MATCH 8
11
+
12
+ typedef struct _domain {
13
+ struct _domain *next;
14
+ char *host;
15
+ char *path;
16
+ regex_t rhost;
17
+ } *Domain;
18
+
19
+ static Domain domains = NULL;
20
+
21
+ bool
22
+ agoo_domain_use() {
23
+ return NULL != domains;
24
+ }
25
+
26
+ int
27
+ agoo_domain_add(agooErr err, const char *host, const char *path) {
28
+ Domain d = (Domain)AGOO_CALLOC(1, sizeof(struct _domain));
29
+
30
+ if (NULL == d) {
31
+ return AGOO_ERR_MEM(err, "Domain");
32
+ }
33
+ if (NULL == (d->host = AGOO_STRDUP(host))) {
34
+ return AGOO_ERR_MEM(err, "Domain host");
35
+ }
36
+ if (NULL == (d->path = AGOO_STRDUP(path))) {
37
+ return AGOO_ERR_MEM(err, "Domain path");
38
+ }
39
+ if (NULL == domains) {
40
+ domains = d;
41
+ } else {
42
+ Domain last = domains;
43
+
44
+ for (; NULL != last->next; last = last->next) {
45
+ }
46
+ last->next = d;
47
+ }
48
+ return AGOO_ERR_OK;
49
+ }
50
+
51
+ int
52
+ agoo_domain_add_regex(agooErr err, const char *host, const char *path) {
53
+ Domain d = (Domain)AGOO_CALLOC(1, sizeof(struct _domain));
54
+
55
+ if (NULL == d) {
56
+ return AGOO_ERR_MEM(err, "Domain");
57
+ }
58
+ if (0 != regcomp(&d->rhost, host, REG_EXTENDED | REG_NEWLINE)) {
59
+ return agoo_err_set(err, AGOO_ERR_ARG, "invalid regex");
60
+ }
61
+ if (NULL == (d->path = AGOO_STRDUP(path))) {
62
+ return AGOO_ERR_MEM(err, "Domain path");
63
+ }
64
+ if (NULL == domains) {
65
+ domains = d;
66
+ } else {
67
+ Domain last = domains;
68
+
69
+ for (; NULL != last->next; last = last->next) {
70
+ }
71
+ last->next = d;
72
+ }
73
+ return AGOO_ERR_OK;
74
+ }
75
+
76
+ const char*
77
+ agoo_domain_resolve(const char *host, char *buf, size_t blen) {
78
+ Domain d;
79
+
80
+ for (d = domains; NULL != d; d = d->next) {
81
+ if (NULL != d->host) { // simple string compare
82
+ if (0 == strcmp(host, d->host)) {
83
+ return d->path;
84
+ }
85
+ } else {
86
+ regmatch_t matches[MAX_MATCH];
87
+ char *bend = buf + blen - 1;
88
+
89
+ if (0 == regexec(&d->rhost, host, MAX_MATCH, matches, 0)) {
90
+ char *b = buf;
91
+ char *p = d->path;
92
+
93
+ for (; '\0' != *p; p++) {
94
+ if ('$' == *p && '(' == *(p + 1)) {
95
+ const char *m;
96
+ char *end;
97
+ long i;
98
+ int start;
99
+ int len;
100
+
101
+ p += 2;
102
+ i = strtol(p, &end, 10);
103
+ if (')' != *end || MAX_MATCH <= i) {
104
+ continue;
105
+ }
106
+ p = end;
107
+ if (0 > (start = (int)matches[i].rm_so)) {
108
+ continue;
109
+ }
110
+ len = (int)matches[i].rm_eo - start;
111
+ if (bend - b <= len) {
112
+ continue;
113
+ }
114
+ for (m = host + start; 0 < len; len--) {
115
+ *b++ = *m++;
116
+ *b = '\0';
117
+ }
118
+ // TBD
119
+ } else {
120
+ *b++ = *p;
121
+ }
122
+ }
123
+ *b = '\0';
124
+ return buf;
125
+ }
126
+ }
127
+ }
128
+ return NULL;
129
+ }
130
+
131
+ void
132
+ agoo_domain_cleanup() {
133
+ Domain d;
134
+
135
+ while (NULL != (d = domains)) {
136
+ domains = d->next;
137
+ if (NULL == d->host) {
138
+ regfree(&d->rhost);
139
+ } else {
140
+ AGOO_FREE(d->host);
141
+ }
142
+ AGOO_FREE(d->path);
143
+ AGOO_FREE(d);
144
+ }
145
+ }