iodine 0.7.44 → 0.7.47

Sign up to get free protection for your applications and to get access to all the features.
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(uuid, 503, set);
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
- static __thread time_t cached_tick;
2343
- static __thread char cached_httpdate[48];
2344
- static __thread size_t cached_len;
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
- ? ((c)-48) \
2366
- : (((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F')) \
2367
- ? (((c) | 32) - 87) \
2368
- : ({ \
2369
- return -1; \
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
- (source[0] >= 'A' && source[0] <= 'F'))
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
- (source[1] >= 'A' && source[1] <= 'F'))
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
- static __thread char buffer[LONGEST_FILE_EXTENSION_LENGTH + 1];
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
  /* *****************************************************************************