iodine 0.7.44 → 0.7.47
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 +14 -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 +63 -0
- data/ext/iodine/iodine.h +2 -0
- data/ext/iodine/iodine_caller.c +48 -8
- data/ext/iodine/iodine_http.c +24 -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 +13 -11
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
|
/* *****************************************************************************
|