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 +4 -4
- data/CHANGELOG.md +13 -0
- data/ext/agoo/agoo.c +2 -0
- data/ext/agoo/con.c +74 -43
- data/ext/agoo/debug.h +1 -0
- data/ext/agoo/domain.c +145 -0
- data/ext/agoo/domain.h +16 -0
- data/ext/agoo/early.c +28 -0
- data/ext/agoo/early.h +23 -0
- data/ext/agoo/early_hints.c +116 -0
- data/ext/agoo/early_hints.h +13 -0
- data/ext/agoo/gqleval.c +2 -2
- data/ext/agoo/graphql.c +1 -1
- data/ext/agoo/page.c +139 -52
- data/ext/agoo/page.h +4 -4
- data/ext/agoo/request.c +9 -1
- data/ext/agoo/res.c +65 -7
- data/ext/agoo/res.h +11 -8
- data/ext/agoo/rserver.c +75 -8
- data/ext/agoo/server.c +2 -0
- data/ext/agoo/server.h +1 -0
- data/ext/agoo/text.c +3 -0
- data/ext/agoo/text.h +6 -5
- data/lib/agoo/version.rb +1 -1
- data/test/domain_test.rb +84 -0
- data/test/early_hints_test.rb +104 -0
- data/test/rack_handler_test.rb +4 -4
- metadata +16 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c40533edbeaf9a5593680f15a5c7ad41ef5e1575b9235c10faf0ecb906bd472c
|
4
|
+
data.tar.gz: 81c3884669b222a050352386973bc40d79cdce7c748204d85825a684d91ecbe3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bc1b0f12bdb19c51a947fa73c981eab8e21b640448363c62d7433138f4320f39a317fc9937f5499398ab7414a15122533af23e2bcc25722bfa26844bdd9c9b7c
|
7
|
+
data.tar.gz: 939c1a7654f453b5d602097b0faed1010291040edddb4a67f99c0b14c50ac2944a45fc87c7e3eb758760a7ba9cf6c02f449aa54cb0daec5fe1864b331e2c1213
|
data/CHANGELOG.md
CHANGED
@@ -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
|
data/ext/agoo/agoo.c
CHANGED
@@ -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);
|
data/ext/agoo/con.c
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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 (
|
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 =
|
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
|
669
|
-
|
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
|
-
|
691
|
+
if (NULL == next && res->final) {
|
692
|
+
bool done = res->close;
|
677
693
|
|
678
|
-
|
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 =
|
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
|
-
|
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
|
776
|
-
|
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
|
-
|
802
|
+
if (NULL == next && res->final) {
|
803
|
+
bool done = res->close;
|
784
804
|
|
785
|
-
|
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 =
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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 !=
|
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 !=
|
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 !=
|
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 ==
|
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;
|
data/ext/agoo/debug.h
CHANGED
data/ext/agoo/domain.c
ADDED
@@ -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
|
+
}
|