iodine 0.7.43 → 0.7.46
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 +4 -4
- data/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
- data/.gitignore +1 -0
- data/CHANGELOG.md +18 -0
- data/examples/etag.ru +16 -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 +75 -32
- 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 +64 -1
- data/ext/iodine/iodine.h +2 -0
- data/ext/iodine/iodine_caller.c +48 -8
- data/ext/iodine/iodine_connection.c +4 -0
- data/ext/iodine/iodine_http.c +28 -2
- data/ext/iodine/iodine_rack_io.c +15 -2
- 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
- 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
|
@@ -88,13 +92,12 @@ static inline void add_date(http_s *r) {
|
|
88
92
|
static uint64_t date_hash = 0;
|
89
93
|
if (!date_hash)
|
90
94
|
date_hash = fiobj_hash_string("date", 4);
|
91
|
-
static uint64_t mod_hash = 0;
|
92
|
-
if (!mod_hash)
|
93
|
-
mod_hash = fiobj_hash_string("last-modified", 13);
|
94
95
|
|
95
96
|
if (fio_last_tick().tv_sec > last_date_added) {
|
96
97
|
fio_lock(&date_lock);
|
97
98
|
if (fio_last_tick().tv_sec > last_date_added) { /* retest inside lock */
|
99
|
+
/* 32 chars are ok for a while, but http_time2str below has a buffer sized
|
100
|
+
* 48 chars and does a memcpy ... */
|
98
101
|
FIOBJ tmp = fiobj_str_buf(32);
|
99
102
|
FIOBJ old = current_date;
|
100
103
|
fiobj_str_resize(
|
@@ -110,11 +113,6 @@ static inline void add_date(http_s *r) {
|
|
110
113
|
fiobj_hash_set(r->private_data.out_headers, HTTP_HEADER_DATE,
|
111
114
|
fiobj_dup(current_date));
|
112
115
|
}
|
113
|
-
if (r->status_str == FIOBJ_INVALID &&
|
114
|
-
!fiobj_hash_get2(r->private_data.out_headers, mod_hash)) {
|
115
|
-
fiobj_hash_set(r->private_data.out_headers, HTTP_HEADER_LAST_MODIFIED,
|
116
|
-
fiobj_dup(current_date));
|
117
|
-
}
|
118
116
|
}
|
119
117
|
|
120
118
|
struct header_writer_s {
|
@@ -764,6 +762,7 @@ void http_pause(http_s *h, void (*task)(http_pause_handle_s *http)) {
|
|
764
762
|
http_fio_protocol_s *p = (http_fio_protocol_s *)h->private_data.flag;
|
765
763
|
http_vtable_s *vtbl = (http_vtable_s *)h->private_data.vtbl;
|
766
764
|
http_pause_handle_s *http = fio_malloc(sizeof(*http));
|
765
|
+
FIO_ASSERT_ALLOC(http);
|
767
766
|
*http = (http_pause_handle_s){
|
768
767
|
.uuid = p->uuid,
|
769
768
|
.h = h,
|
@@ -845,6 +844,7 @@ static http_settings_s *http_settings_new(http_settings_s arg_settings) {
|
|
845
844
|
char *home = getenv("HOME");
|
846
845
|
size_t home_len = strlen(home);
|
847
846
|
char *tmp = malloc(settings->public_folder_length + home_len + 1);
|
847
|
+
FIO_ASSERT_ALLOC(tmp);
|
848
848
|
memcpy(tmp, home, home_len);
|
849
849
|
if (home[home_len - 1] == '/')
|
850
850
|
--home_len;
|
@@ -854,6 +854,7 @@ static http_settings_s *http_settings_new(http_settings_s arg_settings) {
|
|
854
854
|
settings->public_folder_length = strlen(settings->public_folder);
|
855
855
|
} else {
|
856
856
|
settings->public_folder = malloc(settings->public_folder_length + 1);
|
857
|
+
FIO_ASSERT_ALLOC(settings->public_folder);
|
857
858
|
memcpy((void *)settings->public_folder, arg_settings.public_folder,
|
858
859
|
settings->public_folder_length);
|
859
860
|
((uint8_t *)settings->public_folder)[settings->public_folder_length] = 0;
|
@@ -880,7 +881,7 @@ static void http_on_server_protocol_http1(intptr_t uuid, void *set,
|
|
880
881
|
if (!fio_http_at_capa)
|
881
882
|
FIO_LOG_WARNING("HTTP server at capacity");
|
882
883
|
fio_http_at_capa = 1;
|
883
|
-
http_send_error2(
|
884
|
+
http_send_error2(503, uuid, set);
|
884
885
|
fio_close(uuid);
|
885
886
|
}
|
886
887
|
return;
|
@@ -927,10 +928,12 @@ intptr_t http_listen(const char *port, const char *binding,
|
|
927
928
|
|
928
929
|
http_settings_s *settings = http_settings_new(arg_settings);
|
929
930
|
settings->is_client = 0;
|
931
|
+
#ifndef __MINGW32__
|
930
932
|
if (settings->tls) {
|
931
933
|
fio_tls_alpn_add(settings->tls, "http/1.1", http_on_server_protocol_http1,
|
932
934
|
NULL, NULL);
|
933
935
|
}
|
936
|
+
#endif
|
934
937
|
|
935
938
|
return fio_listen(.port = port, .address = binding, .tls = arg_settings.tls,
|
936
939
|
.on_finish = http_on_finish, .on_open = http_on_open,
|
@@ -1187,6 +1190,7 @@ static void on_websocket_http_connection_finished(http_settings_s *settings) {
|
|
1187
1190
|
#undef websocket_connect
|
1188
1191
|
int websocket_connect(const char *address, websocket_settings_s settings) {
|
1189
1192
|
websocket_settings_s *s = fio_malloc(sizeof(*s));
|
1193
|
+
FIO_ASSERT_ALLOC(s);
|
1190
1194
|
*s = settings;
|
1191
1195
|
return http_connect(address, NULL, .on_request = on_websocket_http_connected,
|
1192
1196
|
.on_response = on_websocket_http_connected,
|
@@ -2331,6 +2335,30 @@ size_t http_date2rfc2109(char *target, struct tm *tmbuf) {
|
|
2331
2335
|
return pos - target;
|
2332
2336
|
}
|
2333
2337
|
|
2338
|
+
static pthread_key_t cached_tick_key;
|
2339
|
+
static pthread_key_t cached_httpdate_key;
|
2340
|
+
static pthread_key_t cached_len_key;
|
2341
|
+
static pthread_once_t cached_once = PTHREAD_ONCE_INIT;
|
2342
|
+
static void init_cached_key(void) {
|
2343
|
+
pthread_key_create(&cached_tick_key, free);
|
2344
|
+
pthread_key_create(&cached_httpdate_key, free);
|
2345
|
+
pthread_key_create(&cached_len_key, free);
|
2346
|
+
}
|
2347
|
+
static void init_cached_key_ptr(void) {
|
2348
|
+
time_t *cached_tick = malloc(sizeof(time_t));
|
2349
|
+
FIO_ASSERT_ALLOC(cached_tick);
|
2350
|
+
memset(cached_tick, 0, sizeof(time_t));
|
2351
|
+
char *cached_httpdate = malloc(sizeof(char) * 48);
|
2352
|
+
FIO_ASSERT_ALLOC(cached_tick);
|
2353
|
+
memset(cached_httpdate, 0, 48);
|
2354
|
+
size_t *cached_len = malloc(sizeof(size_t));
|
2355
|
+
*cached_len = 0;
|
2356
|
+
FIO_ASSERT_ALLOC(cached_len);
|
2357
|
+
pthread_setspecific(cached_tick_key, cached_tick);
|
2358
|
+
pthread_setspecific(cached_httpdate_key, cached_httpdate);
|
2359
|
+
pthread_setspecific(cached_len_key, cached_len);
|
2360
|
+
}
|
2361
|
+
|
2334
2362
|
/**
|
2335
2363
|
* Prints Unix time to a HTTP time formatted string.
|
2336
2364
|
*
|
@@ -2339,9 +2367,14 @@ size_t http_date2rfc2109(char *target, struct tm *tmbuf) {
|
|
2339
2367
|
*/
|
2340
2368
|
size_t http_time2str(char *target, const time_t t) {
|
2341
2369
|
/* pre-print time every 1 or 2 seconds or so. */
|
2342
|
-
|
2343
|
-
|
2344
|
-
|
2370
|
+
pthread_once(&cached_once, init_cached_key);
|
2371
|
+
char *cached_httpdate = pthread_getspecific(cached_httpdate_key);
|
2372
|
+
if (!cached_httpdate) {
|
2373
|
+
init_cached_key_ptr();
|
2374
|
+
cached_httpdate = pthread_getspecific(cached_httpdate_key);
|
2375
|
+
}
|
2376
|
+
time_t *cached_tick = pthread_getspecific(cached_tick_key);
|
2377
|
+
size_t *cached_len = pthread_getspecific(cached_len_key);
|
2345
2378
|
time_t last_tick = fio_last_tick().tv_sec;
|
2346
2379
|
if ((t | 7) < last_tick) {
|
2347
2380
|
/* this is a custom time, not "now", pass through */
|
@@ -2349,40 +2382,36 @@ size_t http_time2str(char *target, const time_t t) {
|
|
2349
2382
|
http_gmtime(t, &tm);
|
2350
2383
|
return http_date2str(target, &tm);
|
2351
2384
|
}
|
2352
|
-
if (last_tick > cached_tick) {
|
2385
|
+
if (last_tick > *cached_tick) {
|
2353
2386
|
struct tm tm;
|
2354
|
-
cached_tick = last_tick; /* refresh every second */
|
2387
|
+
*cached_tick = last_tick; /* refresh every second */
|
2355
2388
|
http_gmtime(last_tick, &tm);
|
2356
|
-
cached_len = http_date2str(cached_httpdate, &tm);
|
2389
|
+
*cached_len = http_date2str(cached_httpdate, &tm);
|
2357
2390
|
}
|
2358
|
-
memcpy(target, cached_httpdate, cached_len);
|
2359
|
-
return cached_len;
|
2391
|
+
memcpy(target, cached_httpdate, *cached_len);
|
2392
|
+
return *cached_len;
|
2360
2393
|
}
|
2361
2394
|
|
2362
2395
|
/* Credit to Jonathan Leffler for the idea of a unified conditional */
|
2363
2396
|
#define hex_val(c) \
|
2364
|
-
(((c) >= '0' && (c) <= '9')
|
2365
|
-
|
2366
|
-
|
2367
|
-
|
2368
|
-
|
2369
|
-
|
2370
|
-
0; \
|
2371
|
-
}))
|
2397
|
+
(((c) >= '0' && (c) <= '9') ? ((c)-48) \
|
2398
|
+
: (((c) | 32) >= 'a' && ((c) | 32) <= 'f') ? (((c) | 32) - 87) \
|
2399
|
+
: ({ \
|
2400
|
+
return -1; \
|
2401
|
+
0; \
|
2402
|
+
}))
|
2372
2403
|
static inline int hex2byte(uint8_t *dest, const uint8_t *source) {
|
2373
2404
|
if (source[0] >= '0' && source[0] <= '9')
|
2374
2405
|
*dest = (source[0] - '0');
|
2375
|
-
else if ((source[0] >= 'a' && source[0] <= 'f')
|
2376
|
-
|
2377
|
-
*dest = (source[0] | 32) - 87;
|
2406
|
+
else if ((source[0] | 32) >= 'a' && (source[0] | 32) <= 'f')
|
2407
|
+
*dest = (source[0] | 32) - ('a' - 10);
|
2378
2408
|
else
|
2379
2409
|
return -1;
|
2380
2410
|
*dest <<= 4;
|
2381
2411
|
if (source[1] >= '0' && source[1] <= '9')
|
2382
2412
|
*dest |= (source[1] - '0');
|
2383
|
-
else if ((source[1] >= 'a' && source[1] <= 'f')
|
2384
|
-
|
2385
|
-
*dest |= (source[1] | 32) - 87;
|
2413
|
+
else if ((source[1] | 32) >= 'a' && (source[1] | 32) <= 'f')
|
2414
|
+
*dest |= (source[1] | 32) - ('a' - 10);
|
2386
2415
|
else
|
2387
2416
|
return -1;
|
2388
2417
|
return 0;
|
@@ -2519,12 +2548,26 @@ FIOBJ http_mimetype_find(char *file_ext, size_t file_ext_len) {
|
|
2519
2548
|
fio_mime_set_find(&fio_http_mime_types, hash, FIOBJ_INVALID));
|
2520
2549
|
}
|
2521
2550
|
|
2551
|
+
static pthread_key_t buffer_key;
|
2552
|
+
static pthread_once_t buffer_once = PTHREAD_ONCE_INIT;
|
2553
|
+
static void init_buffer_key(void) { pthread_key_create(&buffer_key, free); }
|
2554
|
+
static void init_buffer_ptr(void) {
|
2555
|
+
char *buffer = malloc(sizeof(char) * (LONGEST_FILE_EXTENSION_LENGTH + 1));
|
2556
|
+
FIO_ASSERT_ALLOC(buffer);
|
2557
|
+
memset(buffer, 0, sizeof(char) * (LONGEST_FILE_EXTENSION_LENGTH + 1));
|
2558
|
+
pthread_setspecific(buffer_key, buffer);
|
2559
|
+
}
|
2522
2560
|
/**
|
2523
2561
|
* Finds the mime-type associated with the URL.
|
2524
2562
|
* Remember to call `fiobj_free`.
|
2525
2563
|
*/
|
2526
2564
|
FIOBJ http_mimetype_find2(FIOBJ url) {
|
2527
|
-
|
2565
|
+
pthread_once(&buffer_once, init_buffer_key);
|
2566
|
+
char *buffer = pthread_getspecific(buffer_key);
|
2567
|
+
if (!buffer) {
|
2568
|
+
init_buffer_ptr();
|
2569
|
+
buffer = pthread_getspecific(buffer_key);
|
2570
|
+
}
|
2528
2571
|
fio_str_info_s ext = {.data = NULL};
|
2529
2572
|
FIOBJ mimetype;
|
2530
2573
|
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
|
/* *****************************************************************************
|