iodine 0.7.41 → 0.7.45
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
- data/.gitignore +1 -0
- data/CHANGELOG.md +24 -0
- data/README.md +2 -2
- data/SPEC-PubSub-Draft.md +89 -47
- data/SPEC-WebSocket-Draft.md +92 -55
- data/examples/async_task.ru +92 -0
- data/ext/iodine/extconf.rb +21 -16
- data/ext/iodine/fio.c +1108 -162
- data/ext/iodine/fio.h +49 -13
- data/ext/iodine/fio_cli.c +1 -1
- data/ext/iodine/fio_tls_missing.c +8 -0
- data/ext/iodine/fio_tls_openssl.c +8 -0
- data/ext/iodine/fio_tmpfile.h +13 -1
- data/ext/iodine/fiobj_data.c +6 -4
- data/ext/iodine/fiobj_data.h +2 -1
- data/ext/iodine/fiobj_hash.c +32 -6
- data/ext/iodine/fiobj_mustache.c +9 -0
- data/ext/iodine/fiobj_numbers.c +86 -8
- data/ext/iodine/fiobj_str.c +24 -11
- data/ext/iodine/fiobject.c +1 -1
- data/ext/iodine/fiobject.h +5 -3
- data/ext/iodine/http.c +66 -10
- data/ext/iodine/http1.c +2 -1
- data/ext/iodine/http1_parser.h +1065 -103
- data/ext/iodine/http_internal.c +1 -0
- data/ext/iodine/http_internal.h +4 -2
- data/ext/iodine/iodine.c +66 -1
- data/ext/iodine/iodine.h +3 -0
- data/ext/iodine/iodine_caller.c +48 -8
- data/ext/iodine/iodine_connection.c +24 -8
- data/ext/iodine/iodine_http.c +32 -8
- data/ext/iodine/iodine_mustache.c +2 -4
- data/ext/iodine/iodine_rack_io.c +21 -0
- data/ext/iodine/iodine_tcp.c +14 -0
- data/ext/iodine/iodine_tls.c +8 -0
- data/ext/iodine/mustache_parser.h +4 -0
- data/ext/iodine/redis_engine.c +14 -11
- data/ext/iodine/websockets.c +7 -3
- data/iodine.gemspec +5 -4
- data/lib/iodine/version.rb +1 -1
- data/lib/rack/handler/iodine.rb +6 -0
- metadata +15 -13
data/ext/iodine/http.c
CHANGED
@@ -18,6 +18,8 @@ Feel free to copy, use and enjoy according to the license provided.
|
|
18
18
|
#include <sys/types.h>
|
19
19
|
#include <unistd.h>
|
20
20
|
|
21
|
+
#include <pthread.h>
|
22
|
+
|
21
23
|
#ifndef HAVE_TM_TM_ZONE
|
22
24
|
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \
|
23
25
|
defined(__DragonFly__) || defined(__bsdi__) || defined(__ultrix) || \
|
@@ -33,6 +35,7 @@ Feel free to copy, use and enjoy according to the license provided.
|
|
33
35
|
#endif
|
34
36
|
#endif
|
35
37
|
|
38
|
+
#ifndef __MINGW32__
|
36
39
|
/* *****************************************************************************
|
37
40
|
SSL/TLS patch
|
38
41
|
***************************************************************************** */
|
@@ -56,6 +59,7 @@ fio_tls_alpn_add(void *tls, const char *protocol_name,
|
|
56
59
|
(void)udata_tls;
|
57
60
|
}
|
58
61
|
#pragma weak fio_tls_alpn_add
|
62
|
+
#endif
|
59
63
|
|
60
64
|
/* *****************************************************************************
|
61
65
|
Small Helpers
|
@@ -95,6 +99,7 @@ static inline void add_date(http_s *r) {
|
|
95
99
|
if (fio_last_tick().tv_sec > last_date_added) {
|
96
100
|
fio_lock(&date_lock);
|
97
101
|
if (fio_last_tick().tv_sec > last_date_added) { /* retest inside lock */
|
102
|
+
/* 32 chars are ok for a while, but http_time2str below has a buffer sized 48 chars and does a memcpy ... */
|
98
103
|
FIOBJ tmp = fiobj_str_buf(32);
|
99
104
|
FIOBJ old = current_date;
|
100
105
|
fiobj_str_resize(
|
@@ -764,6 +769,7 @@ void http_pause(http_s *h, void (*task)(http_pause_handle_s *http)) {
|
|
764
769
|
http_fio_protocol_s *p = (http_fio_protocol_s *)h->private_data.flag;
|
765
770
|
http_vtable_s *vtbl = (http_vtable_s *)h->private_data.vtbl;
|
766
771
|
http_pause_handle_s *http = fio_malloc(sizeof(*http));
|
772
|
+
FIO_ASSERT_ALLOC(http);
|
767
773
|
*http = (http_pause_handle_s){
|
768
774
|
.uuid = p->uuid,
|
769
775
|
.h = h,
|
@@ -845,6 +851,7 @@ static http_settings_s *http_settings_new(http_settings_s arg_settings) {
|
|
845
851
|
char *home = getenv("HOME");
|
846
852
|
size_t home_len = strlen(home);
|
847
853
|
char *tmp = malloc(settings->public_folder_length + home_len + 1);
|
854
|
+
FIO_ASSERT_ALLOC(tmp);
|
848
855
|
memcpy(tmp, home, home_len);
|
849
856
|
if (home[home_len - 1] == '/')
|
850
857
|
--home_len;
|
@@ -854,6 +861,7 @@ static http_settings_s *http_settings_new(http_settings_s arg_settings) {
|
|
854
861
|
settings->public_folder_length = strlen(settings->public_folder);
|
855
862
|
} else {
|
856
863
|
settings->public_folder = malloc(settings->public_folder_length + 1);
|
864
|
+
FIO_ASSERT_ALLOC(settings->public_folder);
|
857
865
|
memcpy((void *)settings->public_folder, arg_settings.public_folder,
|
858
866
|
settings->public_folder_length);
|
859
867
|
((uint8_t *)settings->public_folder)[settings->public_folder_length] = 0;
|
@@ -880,7 +888,7 @@ static void http_on_server_protocol_http1(intptr_t uuid, void *set,
|
|
880
888
|
if (!fio_http_at_capa)
|
881
889
|
FIO_LOG_WARNING("HTTP server at capacity");
|
882
890
|
fio_http_at_capa = 1;
|
883
|
-
http_send_error2(
|
891
|
+
http_send_error2(503, uuid, set);
|
884
892
|
fio_close(uuid);
|
885
893
|
}
|
886
894
|
return;
|
@@ -927,10 +935,12 @@ intptr_t http_listen(const char *port, const char *binding,
|
|
927
935
|
|
928
936
|
http_settings_s *settings = http_settings_new(arg_settings);
|
929
937
|
settings->is_client = 0;
|
938
|
+
#ifndef __MINGW32__
|
930
939
|
if (settings->tls) {
|
931
940
|
fio_tls_alpn_add(settings->tls, "http/1.1", http_on_server_protocol_http1,
|
932
941
|
NULL, NULL);
|
933
942
|
}
|
943
|
+
#endif
|
934
944
|
|
935
945
|
return fio_listen(.port = port, .address = binding, .tls = arg_settings.tls,
|
936
946
|
.on_finish = http_on_finish, .on_open = http_on_open,
|
@@ -1187,6 +1197,7 @@ static void on_websocket_http_connection_finished(http_settings_s *settings) {
|
|
1187
1197
|
#undef websocket_connect
|
1188
1198
|
int websocket_connect(const char *address, websocket_settings_s settings) {
|
1189
1199
|
websocket_settings_s *s = fio_malloc(sizeof(*s));
|
1200
|
+
FIO_ASSERT_ALLOC(s);
|
1190
1201
|
*s = settings;
|
1191
1202
|
return http_connect(address, NULL, .on_request = on_websocket_http_connected,
|
1192
1203
|
.on_response = on_websocket_http_connected,
|
@@ -2331,6 +2342,30 @@ size_t http_date2rfc2109(char *target, struct tm *tmbuf) {
|
|
2331
2342
|
return pos - target;
|
2332
2343
|
}
|
2333
2344
|
|
2345
|
+
static pthread_key_t cached_tick_key;
|
2346
|
+
static pthread_key_t cached_httpdate_key;
|
2347
|
+
static pthread_key_t cached_len_key;
|
2348
|
+
static pthread_once_t cached_once = PTHREAD_ONCE_INIT;
|
2349
|
+
static void init_cached_key(void) {
|
2350
|
+
pthread_key_create(&cached_tick_key, free);
|
2351
|
+
pthread_key_create(&cached_httpdate_key, free);
|
2352
|
+
pthread_key_create(&cached_len_key, free);
|
2353
|
+
}
|
2354
|
+
static void init_cached_key_ptr(void) {
|
2355
|
+
time_t *cached_tick = malloc(sizeof(time_t));
|
2356
|
+
FIO_ASSERT_ALLOC(cached_tick);
|
2357
|
+
memset(cached_tick, 0, sizeof(time_t));
|
2358
|
+
char *cached_httpdate = malloc(sizeof(char)*48);
|
2359
|
+
FIO_ASSERT_ALLOC(cached_tick);
|
2360
|
+
memset(cached_httpdate, 0, 48);
|
2361
|
+
size_t *cached_len = malloc(sizeof(size_t));
|
2362
|
+
*cached_len = 0;
|
2363
|
+
FIO_ASSERT_ALLOC(cached_len);
|
2364
|
+
pthread_setspecific(cached_tick_key, cached_tick);
|
2365
|
+
pthread_setspecific(cached_httpdate_key, cached_httpdate);
|
2366
|
+
pthread_setspecific(cached_len_key, cached_len);
|
2367
|
+
}
|
2368
|
+
|
2334
2369
|
/**
|
2335
2370
|
* Prints Unix time to a HTTP time formatted string.
|
2336
2371
|
*
|
@@ -2339,9 +2374,14 @@ size_t http_date2rfc2109(char *target, struct tm *tmbuf) {
|
|
2339
2374
|
*/
|
2340
2375
|
size_t http_time2str(char *target, const time_t t) {
|
2341
2376
|
/* pre-print time every 1 or 2 seconds or so. */
|
2342
|
-
|
2343
|
-
|
2344
|
-
|
2377
|
+
pthread_once(&cached_once, init_cached_key);
|
2378
|
+
char *cached_httpdate = pthread_getspecific(cached_httpdate_key);
|
2379
|
+
if (!cached_httpdate) {
|
2380
|
+
init_cached_key_ptr();
|
2381
|
+
cached_httpdate = pthread_getspecific(cached_httpdate_key);
|
2382
|
+
}
|
2383
|
+
time_t *cached_tick = pthread_getspecific(cached_tick_key);
|
2384
|
+
size_t *cached_len = pthread_getspecific(cached_len_key);
|
2345
2385
|
time_t last_tick = fio_last_tick().tv_sec;
|
2346
2386
|
if ((t | 7) < last_tick) {
|
2347
2387
|
/* this is a custom time, not "now", pass through */
|
@@ -2349,14 +2389,14 @@ size_t http_time2str(char *target, const time_t t) {
|
|
2349
2389
|
http_gmtime(t, &tm);
|
2350
2390
|
return http_date2str(target, &tm);
|
2351
2391
|
}
|
2352
|
-
if (last_tick > cached_tick) {
|
2392
|
+
if (last_tick > *cached_tick) {
|
2353
2393
|
struct tm tm;
|
2354
|
-
cached_tick = last_tick; /* refresh every second */
|
2394
|
+
*cached_tick = last_tick; /* refresh every second */
|
2355
2395
|
http_gmtime(last_tick, &tm);
|
2356
|
-
cached_len = http_date2str(cached_httpdate, &tm);
|
2396
|
+
*cached_len = http_date2str(cached_httpdate, &tm);
|
2357
2397
|
}
|
2358
|
-
memcpy(target, cached_httpdate, cached_len);
|
2359
|
-
return cached_len;
|
2398
|
+
memcpy(target, cached_httpdate, *cached_len);
|
2399
|
+
return *cached_len;
|
2360
2400
|
}
|
2361
2401
|
|
2362
2402
|
/* Credit to Jonathan Leffler for the idea of a unified conditional */
|
@@ -2519,12 +2559,28 @@ FIOBJ http_mimetype_find(char *file_ext, size_t file_ext_len) {
|
|
2519
2559
|
fio_mime_set_find(&fio_http_mime_types, hash, FIOBJ_INVALID));
|
2520
2560
|
}
|
2521
2561
|
|
2562
|
+
static pthread_key_t buffer_key;
|
2563
|
+
static pthread_once_t buffer_once = PTHREAD_ONCE_INIT;
|
2564
|
+
static void init_buffer_key(void) {
|
2565
|
+
pthread_key_create(&buffer_key, free);
|
2566
|
+
}
|
2567
|
+
static void init_buffer_ptr(void) {
|
2568
|
+
char *buffer = malloc(sizeof(char) * (LONGEST_FILE_EXTENSION_LENGTH + 1));
|
2569
|
+
FIO_ASSERT_ALLOC(buffer);
|
2570
|
+
memset(buffer, 0, sizeof(char) * (LONGEST_FILE_EXTENSION_LENGTH + 1));
|
2571
|
+
pthread_setspecific(buffer_key, buffer);
|
2572
|
+
}
|
2522
2573
|
/**
|
2523
2574
|
* Finds the mime-type associated with the URL.
|
2524
2575
|
* Remember to call `fiobj_free`.
|
2525
2576
|
*/
|
2526
2577
|
FIOBJ http_mimetype_find2(FIOBJ url) {
|
2527
|
-
|
2578
|
+
pthread_once(&buffer_once, init_buffer_key);
|
2579
|
+
char *buffer = pthread_getspecific(buffer_key);
|
2580
|
+
if (!buffer) {
|
2581
|
+
init_buffer_ptr();
|
2582
|
+
buffer = pthread_getspecific(buffer_key);
|
2583
|
+
}
|
2528
2584
|
fio_str_info_s ext = {.data = NULL};
|
2529
2585
|
FIOBJ mimetype;
|
2530
2586
|
if (!url)
|
data/ext/iodine/http1.c
CHANGED
@@ -375,6 +375,7 @@ static int http1_http2websocket_client(http_s *h, websocket_settings_s *args) {
|
|
375
375
|
p->p.settings->on_finish(p->p.settings);
|
376
376
|
/* Copy the Websocket setting arguments to the HTTP settings `udata` */
|
377
377
|
p->p.settings->udata = fio_malloc(sizeof(*args));
|
378
|
+
FIO_ASSERT_ALLOC(p->p.settings->udata);
|
378
379
|
((websocket_settings_s *)(p->p.settings->udata))[0] = *args;
|
379
380
|
/* Set callbacks */
|
380
381
|
p->p.settings->on_finish = http1_websocket_client_on_hangup; /* unknown */
|
@@ -820,7 +821,7 @@ void http1_destroy(fio_protocol_s *pr) {
|
|
820
821
|
http_s_destroy(&http1_pr2handle(p), 0);
|
821
822
|
// FIO_LOG_DEBUG("Deallocating HTTP/1.1 protocol %p(%d)=>%p", (void
|
822
823
|
// *)p->p.uuid, (int)fio_uuid2fd(p->p.uuid), (void *)p);
|
823
|
-
fio_free(p);
|
824
|
+
fio_free(p); // occasional Windows crash bug
|
824
825
|
}
|
825
826
|
|
826
827
|
/* *****************************************************************************
|