agoo 2.10.0 → 2.11.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 +7 -0
- data/README.md +5 -0
- data/ext/agoo/bind.c +64 -29
- data/ext/agoo/bind.h +1 -5
- data/ext/agoo/con.c +144 -61
- data/ext/agoo/con.h +6 -0
- data/ext/agoo/doc.c +0 -1
- data/ext/agoo/domain.c +0 -1
- data/ext/agoo/err.c +3 -4
- data/ext/agoo/err.h +1 -0
- data/ext/agoo/extconf.rb +9 -2
- data/ext/agoo/gqleval.c +1 -2
- data/ext/agoo/kinds.c +16 -0
- data/ext/agoo/kinds.h +3 -0
- data/ext/agoo/request.c +5 -1
- data/ext/agoo/rserver.c +21 -0
- data/ext/agoo/server.c +43 -2
- data/ext/agoo/server.h +11 -0
- data/lib/agoo/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 158117188fe96c69828c60595d0a38afe61bd10923f15236613ca7efbd323623
|
4
|
+
data.tar.gz: da8bea92f370d7e8d66c39c8ff693611e971e1805b11ccf8ecaaa8d9a01eabc3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3387636bc61cd62a24ac7b71f1678c74c8e564c857e580acff1f93144868cd5fe614d49607c3a150f9486b779d4e3b925d8f52c391b02685054bf7a862420256
|
7
|
+
data.tar.gz: 781c95aad1a5161b6d0c069051a748e2b83a5c00d1f44ac7d14a37f897bdec02fc792a1e694db1acb8b4d124b53cdb9758237b1206aece31810b7c6513858b0e
|
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,13 @@ All changes to the Agoo gem are documented here. Releases follow semantic versio
|
|
4
4
|
|
5
5
|
## [Unreleased]
|
6
6
|
|
7
|
+
## [2.11.0] - [2019-09-15]
|
8
|
+
|
9
|
+
TLS using OpenSSL
|
10
|
+
|
11
|
+
### Added
|
12
|
+
- TLS (SSL) support added.
|
13
|
+
|
7
14
|
## [2.10.0] - 2019-08-29
|
8
15
|
|
9
16
|
GraphQL subscriptions
|
data/README.md
CHANGED
@@ -88,6 +88,11 @@ Agoo is not available on Windows.
|
|
88
88
|
|
89
89
|
## News
|
90
90
|
|
91
|
+
- Version 2.11.0 supports GraphQL subscriptions. TLS (SSL,HTTPS)
|
92
|
+
support added. Examples for both. Related, the
|
93
|
+
[graphql-benchmark](https://github.com/the-benchmarker/graphql-benchmarks)
|
94
|
+
repo was given to [the-benchmarker](https://github.com/the-benchmarker).
|
95
|
+
|
91
96
|
- Agoo has a new GraphQL module with a simple, easy to use
|
92
97
|
API. Checkout the [hello](example/graphql/hello.rb) or
|
93
98
|
[song](example/graphql/song.rb) examples.
|
data/ext/agoo/bind.c
CHANGED
@@ -12,6 +12,7 @@
|
|
12
12
|
#include "bind.h"
|
13
13
|
#include "debug.h"
|
14
14
|
#include "log.h"
|
15
|
+
#include "server.h"
|
15
16
|
|
16
17
|
agooBind
|
17
18
|
agoo_bind_port(agooErr err, int port) {
|
@@ -19,11 +20,10 @@ agoo_bind_port(agooErr err, int port) {
|
|
19
20
|
|
20
21
|
if (NULL != b) {
|
21
22
|
char id[1024];
|
22
|
-
|
23
|
+
|
23
24
|
b->port = port;
|
24
25
|
b->family = AF_INET;
|
25
26
|
snprintf(id, sizeof(id) - 1, "http://:%d", port);
|
26
|
-
strcpy(b->scheme, "http");
|
27
27
|
if (NULL == (b->id = AGOO_STRDUP(id))) {
|
28
28
|
AGOO_ERR_MEM(err, "strdup()");
|
29
29
|
AGOO_FREE(b);
|
@@ -43,7 +43,7 @@ url_tcp(agooErr err, const char *url, const char *scheme) {
|
|
43
43
|
struct in_addr addr = { .s_addr = 0 };
|
44
44
|
int port;
|
45
45
|
agooBind b;
|
46
|
-
|
46
|
+
|
47
47
|
if (NULL == colon) {
|
48
48
|
port = 80;
|
49
49
|
} else if (15 < colon - url) {
|
@@ -74,8 +74,6 @@ url_tcp(agooErr err, const char *url, const char *scheme) {
|
|
74
74
|
AGOO_FREE(b);
|
75
75
|
return NULL;
|
76
76
|
}
|
77
|
-
strncpy(b->scheme, scheme, sizeof(b->scheme));
|
78
|
-
b->scheme[sizeof(b->scheme) - 1] = '\0';
|
79
77
|
b->kind = AGOO_CON_HTTP;
|
80
78
|
b->read = NULL;
|
81
79
|
b->write = NULL;
|
@@ -84,7 +82,7 @@ url_tcp(agooErr err, const char *url, const char *scheme) {
|
|
84
82
|
return b;
|
85
83
|
}
|
86
84
|
AGOO_ERR_MEM(err, "Bind");
|
87
|
-
|
85
|
+
|
88
86
|
return b;
|
89
87
|
}
|
90
88
|
|
@@ -95,7 +93,7 @@ url_tcp6(agooErr err, const char *url, const char *scheme) {
|
|
95
93
|
int port = 80;
|
96
94
|
char buf[256];
|
97
95
|
agooBind b;
|
98
|
-
|
96
|
+
|
99
97
|
if (':' == *(end + 1)) {
|
100
98
|
port = atoi(end + 2);
|
101
99
|
}
|
@@ -117,9 +115,7 @@ url_tcp6(agooErr err, const char *url, const char *scheme) {
|
|
117
115
|
AGOO_ERR_MEM(err, "strdup()");
|
118
116
|
AGOO_FREE(b);
|
119
117
|
return NULL;
|
120
|
-
}
|
121
|
-
strncpy(b->scheme, scheme, sizeof(b->scheme));
|
122
|
-
b->scheme[sizeof(b->scheme) - 1] = '\0';
|
118
|
+
}
|
123
119
|
b->kind = AGOO_CON_HTTP;
|
124
120
|
b->read = NULL;
|
125
121
|
b->write = NULL;
|
@@ -128,7 +124,7 @@ url_tcp6(agooErr err, const char *url, const char *scheme) {
|
|
128
124
|
return b;
|
129
125
|
}
|
130
126
|
AGOO_ERR_MEM(err, "Bind");
|
131
|
-
|
127
|
+
|
132
128
|
return b;
|
133
129
|
}
|
134
130
|
|
@@ -143,7 +139,7 @@ url_named(agooErr err, const char *url) {
|
|
143
139
|
if (NULL != b) {
|
144
140
|
const char *fmt = "unix://%s";
|
145
141
|
char id[1024];
|
146
|
-
|
142
|
+
|
147
143
|
if (NULL == (b->name = AGOO_STRDUP(url))) {
|
148
144
|
AGOO_ERR_MEM(err, "strdup()");
|
149
145
|
AGOO_FREE(b);
|
@@ -155,7 +151,6 @@ url_named(agooErr err, const char *url) {
|
|
155
151
|
AGOO_FREE(b);
|
156
152
|
return NULL;
|
157
153
|
}
|
158
|
-
strcpy(b->scheme, "unix");
|
159
154
|
b->kind = AGOO_CON_HTTP;
|
160
155
|
b->read = NULL;
|
161
156
|
b->write = NULL;
|
@@ -170,8 +165,60 @@ url_named(agooErr err, const char *url) {
|
|
170
165
|
|
171
166
|
static agooBind
|
172
167
|
url_ssl(agooErr err, const char *url) {
|
173
|
-
|
168
|
+
char *colon = index(url, ':');
|
169
|
+
struct in_addr addr = { .s_addr = 0 };
|
170
|
+
int port;
|
171
|
+
agooBind b;
|
172
|
+
|
173
|
+
#ifdef HAVE_OPENSSL_SSL_H
|
174
|
+
if (NULL == agoo_server.ssl_ctx) {
|
175
|
+
agoo_err_set(err, AGOO_ERR_ARG, "https requires an SSL certificate and private key. (%s)", url);
|
176
|
+
return NULL;
|
177
|
+
}
|
178
|
+
#else
|
179
|
+
agoo_err_set(err, AGOO_ERR_ARG, "https requires OpenSSL. Rebuild with OpenSSL. (%s)", url);
|
174
180
|
return NULL;
|
181
|
+
#endif
|
182
|
+
if (NULL == colon) {
|
183
|
+
port = 443;
|
184
|
+
} else if (15 < colon - url) {
|
185
|
+
agoo_err_set(err, AGOO_ERR_ARG, "https bind address is not valid, too long. (%s)", url);
|
186
|
+
return NULL;
|
187
|
+
} else if (':' == *url) {
|
188
|
+
port = atoi(colon + 1);
|
189
|
+
} else {
|
190
|
+
char buf[32];
|
191
|
+
|
192
|
+
strncpy(buf, url, colon - url);
|
193
|
+
buf[colon - url] = '\0';
|
194
|
+
if (0 == inet_aton(buf, &addr)) {
|
195
|
+
agoo_err_set(err, AGOO_ERR_ARG, "https bind address is not valid. (%s)", url);
|
196
|
+
return NULL;
|
197
|
+
}
|
198
|
+
port = atoi(colon + 1);
|
199
|
+
}
|
200
|
+
if (NULL != (b = (agooBind)AGOO_CALLOC(1, sizeof(struct _agooBind)))) {
|
201
|
+
char id[64];
|
202
|
+
|
203
|
+
b->port = port;
|
204
|
+
b->addr4 = addr;
|
205
|
+
b->family = AF_INET;
|
206
|
+
snprintf(id, sizeof(id), "https://%s:%d", inet_ntoa(addr), port);
|
207
|
+
if (NULL == (b->id = AGOO_STRDUP(id))) {
|
208
|
+
AGOO_ERR_MEM(err, "strdup()");
|
209
|
+
AGOO_FREE(b);
|
210
|
+
return NULL;
|
211
|
+
}
|
212
|
+
b->kind = AGOO_CON_HTTPS;
|
213
|
+
b->read = NULL;
|
214
|
+
b->write = NULL;
|
215
|
+
b->events = NULL;
|
216
|
+
|
217
|
+
return b;
|
218
|
+
}
|
219
|
+
AGOO_ERR_MEM(err, "Bind");
|
220
|
+
|
221
|
+
return b;
|
175
222
|
}
|
176
223
|
|
177
224
|
agooBind
|
@@ -197,7 +244,7 @@ agoo_bind_url(agooErr err, const char *url) {
|
|
197
244
|
if (0 == strncmp("ssl://", url, 6)) {
|
198
245
|
return url_ssl(err, url + 6);
|
199
246
|
}
|
200
|
-
// All others assume
|
247
|
+
// All others assume http
|
201
248
|
{
|
202
249
|
char *colon = index(url, ':');
|
203
250
|
char scheme[8];
|
@@ -220,9 +267,6 @@ void
|
|
220
267
|
agoo_bind_destroy(agooBind b) {
|
221
268
|
AGOO_FREE(b->id);
|
222
269
|
AGOO_FREE(b->name);
|
223
|
-
AGOO_FREE(b->key);
|
224
|
-
AGOO_FREE(b->cert);
|
225
|
-
AGOO_FREE(b->ca);
|
226
270
|
AGOO_FREE(b);
|
227
271
|
}
|
228
272
|
|
@@ -239,9 +283,9 @@ usual_listen(agooErr err, agooBind b) {
|
|
239
283
|
|
240
284
|
return agoo_err_set(err, errno, "Server failed to open server socket. %s.", strerror(errno));
|
241
285
|
}
|
242
|
-
#ifdef OSX_OS
|
286
|
+
#ifdef OSX_OS
|
243
287
|
setsockopt(b->fd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval));
|
244
|
-
#endif
|
288
|
+
#endif
|
245
289
|
setsockopt(b->fd, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval));
|
246
290
|
setsockopt(b->fd, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(optval));
|
247
291
|
if (AF_INET6 == b->family) {
|
@@ -298,20 +342,11 @@ named_listen(agooErr err, agooBind b) {
|
|
298
342
|
return AGOO_ERR_OK;
|
299
343
|
}
|
300
344
|
|
301
|
-
static int
|
302
|
-
ssl_listen(agooErr err, agooBind b) {
|
303
|
-
// TBD
|
304
|
-
return AGOO_ERR_OK;
|
305
|
-
}
|
306
|
-
|
307
345
|
int
|
308
346
|
agoo_bind_listen(agooErr err, agooBind b) {
|
309
347
|
if (NULL != b->name) {
|
310
348
|
return named_listen(err, b);
|
311
349
|
}
|
312
|
-
if (NULL != b->key) {
|
313
|
-
return ssl_listen(err, b);
|
314
|
-
}
|
315
350
|
return usual_listen(err, b);
|
316
351
|
}
|
317
352
|
|
data/ext/agoo/bind.h
CHANGED
@@ -22,16 +22,12 @@ typedef struct _agooBind {
|
|
22
22
|
struct in_addr addr4;
|
23
23
|
struct in6_addr addr6;
|
24
24
|
};
|
25
|
-
agooConKind kind;
|
26
25
|
bool (*read)(struct _agooCon *c);
|
27
26
|
bool (*write)(struct _agooCon *c);
|
28
27
|
short (*events)(struct _agooCon *c);
|
29
|
-
char scheme[8];
|
30
28
|
char *name; // if set then Unix file
|
31
|
-
char *key; // if set then SSL
|
32
|
-
char *cert;
|
33
|
-
char *ca;
|
34
29
|
char *id;
|
30
|
+
agooConKind kind;
|
35
31
|
} *agooBind;
|
36
32
|
|
37
33
|
extern agooBind agoo_bind_url(agooErr err, const char *url);
|
data/ext/agoo/con.c
CHANGED
@@ -83,6 +83,12 @@ agoo_con_destroy(agooCon c) {
|
|
83
83
|
agoo_ws_req_close(c);
|
84
84
|
}
|
85
85
|
if (0 < c->sock) {
|
86
|
+
#ifdef HAVE_OPENSSL_SSL_H
|
87
|
+
if (NULL != c->ssl) {
|
88
|
+
SSL_free(c->ssl);
|
89
|
+
c->ssl = NULL;
|
90
|
+
}
|
91
|
+
#endif
|
86
92
|
close(c->sock);
|
87
93
|
c->sock = 0;
|
88
94
|
}
|
@@ -282,7 +288,7 @@ con_header_read(agooCon c, size_t *mlenp) {
|
|
282
288
|
}
|
283
289
|
if (agoo_req_cat.on) {
|
284
290
|
*hend = '\0';
|
285
|
-
agoo_log_cat(&agoo_req_cat, "%llu: %s", (unsigned long long)c->id, c->buf);
|
291
|
+
agoo_log_cat(&agoo_req_cat, "%s %llu: %s", agoo_con_kind_str(c->bind->kind), (unsigned long long)c->id, c->buf);
|
286
292
|
*hend = '\r';
|
287
293
|
}
|
288
294
|
for (b = c->buf; ' ' != *b; b++) {
|
@@ -480,6 +486,18 @@ check_upgrade(agooCon c) {
|
|
480
486
|
}
|
481
487
|
}
|
482
488
|
|
489
|
+
#ifdef HAVE_OPENSSL_SSL_H
|
490
|
+
static void
|
491
|
+
con_ssl_error(agooCon c, const char *filename, int line) {
|
492
|
+
char buf[224];
|
493
|
+
unsigned long e = ERR_get_error();
|
494
|
+
|
495
|
+
c->dead = true;
|
496
|
+
ERR_error_string_n(e, buf, sizeof(buf));
|
497
|
+
agoo_log_cat(&agoo_error_cat, "%s at %s:%d", buf, filename, line);
|
498
|
+
}
|
499
|
+
#endif
|
500
|
+
|
483
501
|
bool
|
484
502
|
agoo_con_http_read(agooCon c) {
|
485
503
|
ssize_t cnt;
|
@@ -487,10 +505,34 @@ agoo_con_http_read(agooCon c) {
|
|
487
505
|
if (c->dead || 0 == c->sock || c->closing) {
|
488
506
|
return true;
|
489
507
|
}
|
490
|
-
if (
|
491
|
-
|
508
|
+
if (AGOO_CON_HTTPS == c->bind->kind) {
|
509
|
+
#ifdef HAVE_OPENSSL_SSL_H
|
510
|
+
if (NULL != c->req) {
|
511
|
+
cnt = SSL_read(c->ssl, c->req->msg + c->bcnt, c->req->mlen - c->bcnt);
|
512
|
+
} else {
|
513
|
+
cnt = SSL_read(c->ssl, c->buf + c->bcnt, sizeof(c->buf) - c->bcnt - 1);
|
514
|
+
}
|
515
|
+
if (0 > cnt) {
|
516
|
+
unsigned long e = ERR_get_error();
|
517
|
+
|
518
|
+
if (0 == e) {
|
519
|
+
cnt = 0;
|
520
|
+
return false;
|
521
|
+
} else {
|
522
|
+
con_ssl_error(c, __FILE__, __LINE__);
|
523
|
+
return true;
|
524
|
+
}
|
525
|
+
}
|
526
|
+
#else
|
527
|
+
agoo_log_cat(&agoo_error_cat, "SSL not included in the build.");
|
528
|
+
c->dead = true;
|
529
|
+
#endif
|
492
530
|
} else {
|
493
|
-
|
531
|
+
if (NULL != c->req) {
|
532
|
+
cnt = recv(c->sock, c->req->msg + c->bcnt, c->req->mlen - c->bcnt, 0);
|
533
|
+
} else {
|
534
|
+
cnt = recv(c->sock, c->buf + c->bcnt, sizeof(c->buf) - c->bcnt - 1, 0);
|
535
|
+
}
|
494
536
|
}
|
495
537
|
c->timeout = dtime() + CON_TIMEOUT;
|
496
538
|
if (0 >= cnt) {
|
@@ -544,7 +586,7 @@ agoo_con_http_read(agooCon c) {
|
|
544
586
|
long mlen;
|
545
587
|
|
546
588
|
if (agoo_debug_cat.on && NULL != c->req && NULL != c->req->body.start) {
|
547
|
-
agoo_log_cat(&agoo_debug_cat, "request on %llu: %s", (unsigned long long)c->id, c->req->body.start);
|
589
|
+
agoo_log_cat(&agoo_debug_cat, "%s request on %llu: %s", agoo_con_kind_str(c->bind->kind), (unsigned long long)c->id, c->req->body.start);
|
548
590
|
}
|
549
591
|
if (NULL == (res = agoo_res_create(c))) {
|
550
592
|
c->req = NULL;
|
@@ -584,6 +626,79 @@ agoo_con_http_read(agooCon c) {
|
|
584
626
|
return false;
|
585
627
|
}
|
586
628
|
|
629
|
+
// return false to remove/close connection
|
630
|
+
bool
|
631
|
+
agoo_con_http_write(agooCon c) {
|
632
|
+
agooRes res = agoo_con_res_pop(c);
|
633
|
+
agooText message = agoo_res_message_peek(res);
|
634
|
+
ssize_t cnt;
|
635
|
+
|
636
|
+
if (NULL == message) {
|
637
|
+
return true;
|
638
|
+
}
|
639
|
+
c->timeout = dtime() + CON_TIMEOUT;
|
640
|
+
if (0 == c->wcnt) {
|
641
|
+
if (agoo_resp_cat.on) {
|
642
|
+
char buf[4096];
|
643
|
+
char *hend = strstr(message->text, "\r\n\r\n");
|
644
|
+
|
645
|
+
if (NULL == hend) {
|
646
|
+
hend = message->text + message->len;
|
647
|
+
}
|
648
|
+
if ((long)sizeof(buf) <= hend - message->text) {
|
649
|
+
hend = message->text + sizeof(buf) - 1;
|
650
|
+
}
|
651
|
+
memcpy(buf, message->text, hend - message->text);
|
652
|
+
buf[hend - message->text] = '\0';
|
653
|
+
agoo_log_cat(&agoo_resp_cat, "%s %llu: %s", agoo_con_kind_str(c->bind->kind), (unsigned long long)c->id, buf);
|
654
|
+
}
|
655
|
+
if (agoo_debug_cat.on) {
|
656
|
+
agoo_log_cat(&agoo_debug_cat, "%s response on %llu: %s", agoo_con_kind_str(c->bind->kind), (unsigned long long)c->id, message->text);
|
657
|
+
}
|
658
|
+
}
|
659
|
+
if (AGOO_CON_HTTPS == c->bind->kind) {
|
660
|
+
#ifdef HAVE_OPENSSL_SSL_H
|
661
|
+
if (0 >= (cnt = SSL_write(c->ssl, message->text + c->wcnt, message->len - c->wcnt))) {
|
662
|
+
unsigned long e = ERR_get_error();
|
663
|
+
|
664
|
+
if (0 == e) {
|
665
|
+
return true;
|
666
|
+
}
|
667
|
+
con_ssl_error(c, __FILE__, __LINE__);
|
668
|
+
return false;
|
669
|
+
}
|
670
|
+
#else
|
671
|
+
agoo_log_cat(&agoo_error_cat, "SSL not included in the build.");
|
672
|
+
c->dead = true;
|
673
|
+
#endif
|
674
|
+
} else {
|
675
|
+
if (0 > (cnt = send(c->sock, message->text + c->wcnt, message->len - c->wcnt, MSG_DONTWAIT))) {
|
676
|
+
if (EAGAIN == errno) {
|
677
|
+
return true;
|
678
|
+
}
|
679
|
+
agoo_log_cat(&agoo_error_cat, "Socket error @ %llu.", (unsigned long long)c->id);
|
680
|
+
|
681
|
+
return false;
|
682
|
+
}
|
683
|
+
}
|
684
|
+
c->wcnt += cnt;
|
685
|
+
if (c->wcnt == message->len) { // finished
|
686
|
+
agooText next = agoo_res_message_next(res);
|
687
|
+
|
688
|
+
c->wcnt = 0;
|
689
|
+
if (NULL == next && res->final) {
|
690
|
+
bool done = res->close;
|
691
|
+
|
692
|
+
agoo_res_destroy(res);
|
693
|
+
|
694
|
+
return !done;
|
695
|
+
}
|
696
|
+
}
|
697
|
+
agoo_con_res_prepend(c, res);
|
698
|
+
|
699
|
+
return true;
|
700
|
+
}
|
701
|
+
|
587
702
|
static bool
|
588
703
|
con_ws_read(agooCon c) {
|
589
704
|
ssize_t cnt;
|
@@ -692,62 +807,6 @@ con_ws_read(agooCon c) {
|
|
692
807
|
return false;
|
693
808
|
}
|
694
809
|
|
695
|
-
// return false to remove/close connection
|
696
|
-
bool
|
697
|
-
agoo_con_http_write(agooCon c) {
|
698
|
-
agooRes res = agoo_con_res_pop(c);
|
699
|
-
agooText message = agoo_res_message_peek(res);
|
700
|
-
ssize_t cnt;
|
701
|
-
|
702
|
-
if (NULL == message) {
|
703
|
-
return true;
|
704
|
-
}
|
705
|
-
c->timeout = dtime() + CON_TIMEOUT;
|
706
|
-
if (0 == c->wcnt) {
|
707
|
-
if (agoo_resp_cat.on) {
|
708
|
-
char buf[4096];
|
709
|
-
char *hend = strstr(message->text, "\r\n\r\n");
|
710
|
-
|
711
|
-
if (NULL == hend) {
|
712
|
-
hend = message->text + message->len;
|
713
|
-
}
|
714
|
-
if ((long)sizeof(buf) <= hend - message->text) {
|
715
|
-
hend = message->text + sizeof(buf) - 1;
|
716
|
-
}
|
717
|
-
memcpy(buf, message->text, hend - message->text);
|
718
|
-
buf[hend - message->text] = '\0';
|
719
|
-
agoo_log_cat(&agoo_resp_cat, "%llu: %s", (unsigned long long)c->id, buf);
|
720
|
-
}
|
721
|
-
if (agoo_debug_cat.on) {
|
722
|
-
agoo_log_cat(&agoo_debug_cat, "response on %llu: %s", (unsigned long long)c->id, message->text);
|
723
|
-
}
|
724
|
-
}
|
725
|
-
if (0 > (cnt = send(c->sock, message->text + c->wcnt, message->len - c->wcnt, MSG_DONTWAIT))) {
|
726
|
-
if (EAGAIN == errno) {
|
727
|
-
return true;
|
728
|
-
}
|
729
|
-
agoo_log_cat(&agoo_error_cat, "Socket error @ %llu.", (unsigned long long)c->id);
|
730
|
-
|
731
|
-
return false;
|
732
|
-
}
|
733
|
-
c->wcnt += cnt;
|
734
|
-
if (c->wcnt == message->len) { // finished
|
735
|
-
agooText next = agoo_res_message_next(res);
|
736
|
-
|
737
|
-
c->wcnt = 0;
|
738
|
-
if (NULL == next && res->final) {
|
739
|
-
bool done = res->close;
|
740
|
-
|
741
|
-
agoo_res_destroy(res);
|
742
|
-
|
743
|
-
return !done;
|
744
|
-
}
|
745
|
-
}
|
746
|
-
agoo_con_res_prepend(c, res);
|
747
|
-
|
748
|
-
return true;
|
749
|
-
}
|
750
|
-
|
751
810
|
static const char ping_msg[] = "\x89\x00";
|
752
811
|
static const char pong_msg[] = "\x8a\x00";
|
753
812
|
|
@@ -1171,6 +1230,24 @@ queue_ready_io(void *ctx) {
|
|
1171
1230
|
return AGOO_READY_IN;
|
1172
1231
|
}
|
1173
1232
|
|
1233
|
+
static void
|
1234
|
+
con_ssl_setup(agooCon c) {
|
1235
|
+
#ifdef HAVE_OPENSSL_SSL_H
|
1236
|
+
if (NULL == (c->ssl = SSL_new(agoo_server.ssl_ctx))) {
|
1237
|
+
con_ssl_error(c, __FILE__, __LINE__);
|
1238
|
+
}
|
1239
|
+
if (!SSL_set_fd(c->ssl, c->sock)) {
|
1240
|
+
con_ssl_error(c, __FILE__, __LINE__);
|
1241
|
+
}
|
1242
|
+
if (!SSL_accept(c->ssl)) {
|
1243
|
+
con_ssl_error(c, __FILE__, __LINE__);
|
1244
|
+
}
|
1245
|
+
#else
|
1246
|
+
agoo_log_cat(&agoo_error_cat, "SSL not included in the build.");
|
1247
|
+
c->dead = true;
|
1248
|
+
#endif
|
1249
|
+
}
|
1250
|
+
|
1174
1251
|
static bool
|
1175
1252
|
con_queue_ready_read(agooReady ready, void *ctx) {
|
1176
1253
|
agooConLoop loop = (agooConLoop)ctx;
|
@@ -1184,6 +1261,9 @@ con_queue_ready_read(agooReady ready, void *ctx) {
|
|
1184
1261
|
agoo_log_cat(&agoo_error_cat, "Failed to add connection to manager. %s", err.msg);
|
1185
1262
|
agoo_err_clear(&err);
|
1186
1263
|
}
|
1264
|
+
if (AGOO_CON_HTTPS == c->bind->kind) {
|
1265
|
+
con_ssl_setup(c);
|
1266
|
+
}
|
1187
1267
|
}
|
1188
1268
|
return true;
|
1189
1269
|
}
|
@@ -1249,6 +1329,9 @@ agoo_con_loop(void *x) {
|
|
1249
1329
|
agoo_log_cat(&agoo_error_cat, "Failed to add connection to manager. %s", err.msg);
|
1250
1330
|
agoo_err_clear(&err);
|
1251
1331
|
}
|
1332
|
+
if (AGOO_CON_HTTPS == c->bind->kind) {
|
1333
|
+
con_ssl_setup(c);
|
1334
|
+
}
|
1252
1335
|
}
|
1253
1336
|
while (NULL != (pub = (agooPub)agoo_queue_pop(&loop->pub_queue, 0.0))) {
|
1254
1337
|
process_pub_con(pub, loop);
|
data/ext/agoo/con.h
CHANGED
@@ -7,6 +7,9 @@
|
|
7
7
|
#include <pthread.h>
|
8
8
|
#include <stdbool.h>
|
9
9
|
#include <stdint.h>
|
10
|
+
#ifdef HAVE_OPENSSL_SSL_H
|
11
|
+
#include <openssl/ssl.h>
|
12
|
+
#endif
|
10
13
|
|
11
14
|
#include "err.h"
|
12
15
|
#include "req.h"
|
@@ -59,6 +62,9 @@ typedef struct _agooCon {
|
|
59
62
|
|
60
63
|
struct _agooUpgraded *up; // only set for push connections
|
61
64
|
struct _gqlSub *gsub; // for graphql subscription
|
65
|
+
#ifdef HAVE_OPENSSL_SSL_H
|
66
|
+
SSL *ssl;
|
67
|
+
#endif
|
62
68
|
agooConLoop loop;
|
63
69
|
} *agooCon;
|
64
70
|
|
data/ext/agoo/doc.c
CHANGED
@@ -283,7 +283,6 @@ read_number(agooErr err, agooDoc doc) {
|
|
283
283
|
for (; '0' <= *doc->cur && *doc->cur <= '9'; doc->cur++) {
|
284
284
|
exp = exp * 10 + (*doc->cur - '0');
|
285
285
|
if (EXP_MAX <= exp) {
|
286
|
-
// TBD maybe just ignore extra and continue till the end
|
287
286
|
agoo_doc_err(doc, err, "number has too many digits");
|
288
287
|
return NULL;
|
289
288
|
}
|
data/ext/agoo/domain.c
CHANGED
data/ext/agoo/err.c
CHANGED
@@ -25,7 +25,7 @@ agoo_err_set(agooErr err, int code, const char *fmt, ...) {
|
|
25
25
|
int
|
26
26
|
agoo_err_no(agooErr err, const char *fmt, ...) {
|
27
27
|
int cnt = 0;
|
28
|
-
|
28
|
+
|
29
29
|
if (NULL != fmt) {
|
30
30
|
va_list ap;
|
31
31
|
|
@@ -53,7 +53,7 @@ agoo_err_clear(agooErr err) {
|
|
53
53
|
const char*
|
54
54
|
agoo_err_str(agooErrCode code) {
|
55
55
|
const char *str = NULL;
|
56
|
-
|
56
|
+
|
57
57
|
if (code < AGOO_ERR_START) {
|
58
58
|
str = strerror(code);
|
59
59
|
}
|
@@ -72,6 +72,7 @@ agoo_err_str(agooErrCode code) {
|
|
72
72
|
case AGOO_ERR_TOO_MANY: str = "too many"; break;
|
73
73
|
case AGOO_ERR_TYPE: str = "type error"; break;
|
74
74
|
case AGOO_ERR_EVAL: str = "eval error"; break;
|
75
|
+
case AGOO_ERR_TLS: str = "TLS error"; break;
|
75
76
|
default: str = "unknown error"; break;
|
76
77
|
}
|
77
78
|
}
|
@@ -82,5 +83,3 @@ int
|
|
82
83
|
agoo_err_memory(agooErr err, const char *type, const char *file, int line) {
|
83
84
|
return agoo_err_set(err, AGOO_ERR_MEMORY, "Failed to allocate memory for a %s at %s:%d.", type, file, line);
|
84
85
|
}
|
85
|
-
|
86
|
-
|
data/ext/agoo/err.h
CHANGED
data/ext/agoo/extconf.rb
CHANGED
@@ -3,15 +3,22 @@ require 'rbconfig'
|
|
3
3
|
|
4
4
|
extension_name = 'agoo'
|
5
5
|
dir_config(extension_name)
|
6
|
+
dir_config('openssl')
|
6
7
|
|
7
|
-
|
8
|
+
if 'x86_64-linux' == RUBY_PLATFORM
|
9
|
+
$CFLAGS += " -DPLATFORM_LINUX -std=gnu11"
|
10
|
+
else
|
11
|
+
$CFLAGS += ' -std=c11'
|
12
|
+
end
|
8
13
|
|
9
14
|
# Adding the __attribute__ flag only works with gcc compilers and even then it
|
10
|
-
# does not work to check args with varargs
|
15
|
+
# does not work to check args with varargs so just remove the check.
|
11
16
|
CONFIG['warnflags'].slice!(/ -Wsuggest-attribute=format/)
|
12
17
|
|
13
18
|
have_header('stdatomic.h')
|
14
19
|
#have_header('sys/epoll.h')
|
20
|
+
have_header('openssl/ssl.h')
|
21
|
+
have_library('ssl')
|
15
22
|
|
16
23
|
create_makefile(File.join(extension_name, extension_name))
|
17
24
|
|
data/ext/agoo/gqleval.c
CHANGED
@@ -39,7 +39,6 @@ static const char variables_str[] = "variables";
|
|
39
39
|
|
40
40
|
gqlValue (*gql_doc_eval_func)(agooErr err, gqlDoc doc) = NULL;
|
41
41
|
|
42
|
-
// TBD errors should have message, location, and path
|
43
42
|
static void
|
44
43
|
err_resp(agooRes res, agooErr err, int status) {
|
45
44
|
char buf[1024];
|
@@ -540,7 +539,7 @@ eval_post(agooErr err, agooReq req) {
|
|
540
539
|
for (link = m->value->members; NULL != link; link = link->next) {
|
541
540
|
gqlVar v = gql_op_var_create(err, link->key, link->value->type, link->value);
|
542
541
|
|
543
|
-
link->value = NULL;
|
542
|
+
link->value = NULL;
|
544
543
|
if (NULL == v) {
|
545
544
|
goto DONE;
|
546
545
|
}
|
data/ext/agoo/kinds.c
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
// Copyright (c) 2019, Peter Ohler, All rights reserved.
|
2
|
+
|
3
|
+
#include "kinds.h"
|
4
|
+
|
5
|
+
const char*
|
6
|
+
agoo_con_kind_str(agooConKind kind) {
|
7
|
+
switch (kind) {
|
8
|
+
case AGOO_CON_ANY: return "ANY";
|
9
|
+
case AGOO_CON_HTTP: return "HTTP";
|
10
|
+
case AGOO_CON_HTTPS: return "HTTPS";
|
11
|
+
case AGOO_CON_WS: return "WS";
|
12
|
+
case AGOO_CON_SSE: return "SSE";
|
13
|
+
default: break;
|
14
|
+
}
|
15
|
+
return "UNKNOWN";
|
16
|
+
}
|
data/ext/agoo/kinds.h
CHANGED
data/ext/agoo/request.c
CHANGED
@@ -23,6 +23,7 @@ static VALUE empty_val = Qundef;
|
|
23
23
|
static VALUE get_val = Qundef;
|
24
24
|
static VALUE head_val = Qundef;
|
25
25
|
static VALUE http_val = Qundef;
|
26
|
+
static VALUE https_val = Qundef;
|
26
27
|
static VALUE options_val = Qundef;
|
27
28
|
static VALUE patch_val = Qundef;
|
28
29
|
static VALUE path_info_val = Qundef;
|
@@ -262,7 +263,9 @@ rack_version(VALUE self) {
|
|
262
263
|
|
263
264
|
static VALUE
|
264
265
|
req_rack_url_scheme(agooReq r) {
|
265
|
-
|
266
|
+
if (AGOO_CON_HTTPS == r->res->con->bind->kind) {
|
267
|
+
return https_val;
|
268
|
+
}
|
266
269
|
return http_val;
|
267
270
|
}
|
268
271
|
|
@@ -691,6 +694,7 @@ request_init(VALUE mod) {
|
|
691
694
|
get_val = rb_str_new_cstr("GET"); rb_gc_register_address(&get_val);
|
692
695
|
head_val = rb_str_new_cstr("HEAD"); rb_gc_register_address(&head_val);
|
693
696
|
http_val = rb_str_new_cstr("http"); rb_gc_register_address(&http_val);
|
697
|
+
https_val = rb_str_new_cstr("https"); rb_gc_register_address(&https_val);
|
694
698
|
options_val = rb_str_new_cstr("OPTIONS"); rb_gc_register_address(&options_val);
|
695
699
|
patch_val = rb_str_new_cstr("PATCH"); rb_gc_register_address(&patch_val);
|
696
700
|
path_info_val = rb_str_new_cstr("PATH_INFO"); rb_gc_register_address(&path_info_val);
|
data/ext/agoo/rserver.c
CHANGED
@@ -160,6 +160,21 @@ configure(agooErr err, int port, const char *root, VALUE options) {
|
|
160
160
|
}
|
161
161
|
}
|
162
162
|
}
|
163
|
+
if (Qnil != (v = rb_hash_lookup(options, ID2SYM(rb_intern("ssl_cert"))))) {
|
164
|
+
rb_check_type(v, T_STRING);
|
165
|
+
const char *cert =StringValuePtr(v);
|
166
|
+
|
167
|
+
if (Qnil != (v = rb_hash_lookup(options, ID2SYM(rb_intern("ssl_key"))))) {
|
168
|
+
rb_check_type(v, T_STRING);
|
169
|
+
const char *key =StringValuePtr(v);
|
170
|
+
|
171
|
+
if (AGOO_ERR_OK != agoo_server_ssl_init(err, cert, key)) {
|
172
|
+
rb_raise(rb_eArgError, "%s", err->msg);
|
173
|
+
}
|
174
|
+
} else {
|
175
|
+
rb_raise(rb_eArgError, "An ssl_key must be provided if an ssl_cert was provided.");
|
176
|
+
}
|
177
|
+
}
|
163
178
|
if (Qnil != (v = rb_hash_lookup(options, ID2SYM(rb_intern("bind"))))) {
|
164
179
|
int len;
|
165
180
|
int i;
|
@@ -258,6 +273,12 @@ configure(agooErr err, int port, const char *root, VALUE options) {
|
|
258
273
|
* - *:bind* [_String_|_Array_] a binding or array of binds. Examples are: "http ://127.0.0.1:6464", "unix:///tmp/agoo.socket", "http ://[::1]:6464, or to not restrict the address "http ://:6464".
|
259
274
|
*
|
260
275
|
* - *:graphql* [_String_] path to GraphQL endpoint if support for GraphQL is desired.
|
276
|
+
*
|
277
|
+
* - *:max_push_pending* [_Integer_] maximum number or outstanding push messages, less than 1000.
|
278
|
+
*
|
279
|
+
* - *:ssl_sert* [_String_] filepath to the SSL certificate file.
|
280
|
+
*
|
281
|
+
* - *:ssl_key* [_String_] filepath to the SSL private key file.
|
261
282
|
*/
|
262
283
|
static VALUE
|
263
284
|
rserver_init(int argc, VALUE *argv, VALUE self) {
|
data/ext/agoo/server.c
CHANGED
@@ -34,8 +34,6 @@ double agoo_io_loop_ratio = 0.5;
|
|
34
34
|
|
35
35
|
int
|
36
36
|
agoo_server_setup(agooErr err) {
|
37
|
-
long i;
|
38
|
-
|
39
37
|
memset(&agoo_server, 0, sizeof(struct _agooServer));
|
40
38
|
pthread_mutex_init(&agoo_server.up_lock, 0);
|
41
39
|
agoo_server.up_list = NULL;
|
@@ -47,6 +45,8 @@ agoo_server_setup(agooErr err) {
|
|
47
45
|
AGOO_ERR_OK != agoo_queue_multi_init(err, &agoo_server.eval_queue, 1024, true, true)) {
|
48
46
|
return err->code;
|
49
47
|
}
|
48
|
+
long i;
|
49
|
+
|
50
50
|
agoo_server.loop_max = 4;
|
51
51
|
if (0 < (i = sysconf(_SC_NPROCESSORS_ONLN))) {
|
52
52
|
i = (int)(i * agoo_io_loop_ratio);
|
@@ -58,6 +58,41 @@ agoo_server_setup(agooErr err) {
|
|
58
58
|
return AGOO_ERR_OK;
|
59
59
|
}
|
60
60
|
|
61
|
+
#ifdef HAVE_OPENSSL_SSL_H
|
62
|
+
static int
|
63
|
+
ssl_error(agooErr err, const char *filename, int line) {
|
64
|
+
char buf[224];
|
65
|
+
unsigned long e = ERR_get_error();
|
66
|
+
|
67
|
+
ERR_error_string_n(e, buf, sizeof(buf));
|
68
|
+
|
69
|
+
return agoo_err_set(err, AGOO_ERR_TLS, "%s at %s:%d", buf, filename, line);
|
70
|
+
}
|
71
|
+
#endif
|
72
|
+
|
73
|
+
int
|
74
|
+
agoo_server_ssl_init(agooErr err, const char *cert_pem, const char *key_pem) {
|
75
|
+
#ifdef HAVE_OPENSSL_SSL_H
|
76
|
+
SSL_load_error_strings();
|
77
|
+
SSL_library_init();
|
78
|
+
if (NULL == (agoo_server.ssl_ctx = SSL_CTX_new(SSLv23_server_method()))) {
|
79
|
+
return ssl_error(err, __FILE__, __LINE__);
|
80
|
+
}
|
81
|
+
SSL_CTX_set_ecdh_auto(agoo_server.ssl_ctx, 1);
|
82
|
+
|
83
|
+
if (!SSL_CTX_use_certificate_file(agoo_server.ssl_ctx, cert_pem, SSL_FILETYPE_PEM)) {
|
84
|
+
return ssl_error(err, __FILE__, __LINE__);
|
85
|
+
}
|
86
|
+
if (!SSL_CTX_use_PrivateKey_file(agoo_server.ssl_ctx, key_pem, SSL_FILETYPE_PEM)) {
|
87
|
+
return ssl_error(err, __FILE__, __LINE__);
|
88
|
+
}
|
89
|
+
if (!SSL_CTX_check_private_key(agoo_server.ssl_ctx)) {
|
90
|
+
return agoo_err_set(err, AGOO_ERR_TLS, "TLS private key check failed");
|
91
|
+
}
|
92
|
+
#endif
|
93
|
+
return AGOO_ERR_OK;
|
94
|
+
}
|
95
|
+
|
61
96
|
static void
|
62
97
|
add_con_loop() {
|
63
98
|
struct _agooErr err = AGOO_ERR_INIT;
|
@@ -255,6 +290,12 @@ agoo_server_shutdown(const char *app_name, void (*stop)()) {
|
|
255
290
|
agoo_pages_cleanup();
|
256
291
|
agoo_http_cleanup();
|
257
292
|
agoo_domain_cleanup();
|
293
|
+
#ifdef HAVE_OPENSSL_SSL_H
|
294
|
+
if (NULL != agoo_server.ssl_ctx) {
|
295
|
+
SSL_CTX_free(agoo_server.ssl_ctx);
|
296
|
+
EVP_cleanup();
|
297
|
+
}
|
298
|
+
#endif
|
258
299
|
}
|
259
300
|
}
|
260
301
|
|
data/ext/agoo/server.h
CHANGED
@@ -6,6 +6,12 @@
|
|
6
6
|
#include <pthread.h>
|
7
7
|
#include <stdbool.h>
|
8
8
|
|
9
|
+
#ifdef HAVE_OPENSSL_SSL_H
|
10
|
+
#include <openssl/bio.h>
|
11
|
+
#include <openssl/ssl.h>
|
12
|
+
#include <openssl/err.h>
|
13
|
+
#endif
|
14
|
+
|
9
15
|
#include "atomic.h"
|
10
16
|
#include "bind.h"
|
11
17
|
#include "err.h"
|
@@ -28,6 +34,7 @@ typedef struct _agooServer {
|
|
28
34
|
bool pedantic;
|
29
35
|
bool root_first;
|
30
36
|
bool rack_early_hints;
|
37
|
+
bool tls;
|
31
38
|
pthread_t listen_thread;
|
32
39
|
struct _agooQueue con_queue;
|
33
40
|
agooHook hooks;
|
@@ -48,6 +55,9 @@ typedef struct _agooServer {
|
|
48
55
|
void *env_nil_value;
|
49
56
|
void *ctx_nil_value;
|
50
57
|
|
58
|
+
#ifdef HAVE_OPENSSL_SSL_H
|
59
|
+
SSL_CTX *ssl_ctx;
|
60
|
+
#endif
|
51
61
|
// A count of the running threads from the wrapper or the server managed
|
52
62
|
// threads.
|
53
63
|
atomic_int running;
|
@@ -56,6 +66,7 @@ typedef struct _agooServer {
|
|
56
66
|
extern int agoo_server_setup(agooErr err);
|
57
67
|
extern void agoo_server_shutdown(const char *app_name, void (*stop)());
|
58
68
|
extern void agoo_server_bind(agooBind b);
|
69
|
+
extern int agoo_server_ssl_init(agooErr err, const char *cert_pem, const char *key_pem);
|
59
70
|
|
60
71
|
extern int setup_listen(agooErr err);
|
61
72
|
extern int agoo_server_start(agooErr err, const char *app_name, const char *version);
|
data/lib/agoo/version.rb
CHANGED
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.
|
4
|
+
version: 2.11.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: 2019-
|
11
|
+
date: 2019-09-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: oj
|
@@ -88,6 +88,7 @@ files:
|
|
88
88
|
- ext/agoo/hook.h
|
89
89
|
- ext/agoo/http.c
|
90
90
|
- ext/agoo/http.h
|
91
|
+
- ext/agoo/kinds.c
|
91
92
|
- ext/agoo/kinds.h
|
92
93
|
- ext/agoo/log.c
|
93
94
|
- ext/agoo/log.h
|