iodine 0.7.41 → 0.7.45

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
  3. data/.gitignore +1 -0
  4. data/CHANGELOG.md +24 -0
  5. data/README.md +2 -2
  6. data/SPEC-PubSub-Draft.md +89 -47
  7. data/SPEC-WebSocket-Draft.md +92 -55
  8. data/examples/async_task.ru +92 -0
  9. data/ext/iodine/extconf.rb +21 -16
  10. data/ext/iodine/fio.c +1108 -162
  11. data/ext/iodine/fio.h +49 -13
  12. data/ext/iodine/fio_cli.c +1 -1
  13. data/ext/iodine/fio_tls_missing.c +8 -0
  14. data/ext/iodine/fio_tls_openssl.c +8 -0
  15. data/ext/iodine/fio_tmpfile.h +13 -1
  16. data/ext/iodine/fiobj_data.c +6 -4
  17. data/ext/iodine/fiobj_data.h +2 -1
  18. data/ext/iodine/fiobj_hash.c +32 -6
  19. data/ext/iodine/fiobj_mustache.c +9 -0
  20. data/ext/iodine/fiobj_numbers.c +86 -8
  21. data/ext/iodine/fiobj_str.c +24 -11
  22. data/ext/iodine/fiobject.c +1 -1
  23. data/ext/iodine/fiobject.h +5 -3
  24. data/ext/iodine/http.c +66 -10
  25. data/ext/iodine/http1.c +2 -1
  26. data/ext/iodine/http1_parser.h +1065 -103
  27. data/ext/iodine/http_internal.c +1 -0
  28. data/ext/iodine/http_internal.h +4 -2
  29. data/ext/iodine/iodine.c +66 -1
  30. data/ext/iodine/iodine.h +3 -0
  31. data/ext/iodine/iodine_caller.c +48 -8
  32. data/ext/iodine/iodine_connection.c +24 -8
  33. data/ext/iodine/iodine_http.c +32 -8
  34. data/ext/iodine/iodine_mustache.c +2 -4
  35. data/ext/iodine/iodine_rack_io.c +21 -0
  36. data/ext/iodine/iodine_tcp.c +14 -0
  37. data/ext/iodine/iodine_tls.c +8 -0
  38. data/ext/iodine/mustache_parser.h +4 -0
  39. data/ext/iodine/redis_engine.c +14 -11
  40. data/ext/iodine/websockets.c +7 -3
  41. data/iodine.gemspec +5 -4
  42. data/lib/iodine/version.rb +1 -1
  43. data/lib/rack/handler/iodine.rb +6 -0
  44. 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(uuid, 503, set);
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
- static __thread time_t cached_tick;
2343
- static __thread char cached_httpdate[48];
2344
- static __thread size_t cached_len;
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
- static __thread char buffer[LONGEST_FILE_EXTENSION_LENGTH + 1];
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
  /* *****************************************************************************