iodine 0.6.5 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of iodine might be problematic. Click here for more details.

Files changed (98) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -0
  3. data/README.md +4 -4
  4. data/SPEC-Websocket-Draft.md +3 -6
  5. data/bin/mustache.rb +128 -0
  6. data/examples/test_template.mustache +16 -0
  7. data/ext/iodine/fio.c +9397 -0
  8. data/ext/iodine/fio.h +4723 -0
  9. data/ext/iodine/fio_ary.h +353 -54
  10. data/ext/iodine/fio_cli.c +351 -361
  11. data/ext/iodine/fio_cli.h +84 -105
  12. data/ext/iodine/fio_hashmap.h +70 -16
  13. data/ext/iodine/fio_json_parser.h +35 -24
  14. data/ext/iodine/fio_siphash.c +104 -4
  15. data/ext/iodine/fio_siphash.h +18 -2
  16. data/ext/iodine/fio_str.h +1218 -0
  17. data/ext/iodine/fio_tmpfile.h +1 -1
  18. data/ext/iodine/fiobj.h +13 -8
  19. data/ext/iodine/fiobj4sock.h +6 -8
  20. data/ext/iodine/fiobj_ary.c +107 -17
  21. data/ext/iodine/fiobj_ary.h +36 -4
  22. data/ext/iodine/fiobj_data.c +146 -127
  23. data/ext/iodine/fiobj_data.h +25 -23
  24. data/ext/iodine/fiobj_hash.c +7 -7
  25. data/ext/iodine/fiobj_hash.h +6 -5
  26. data/ext/iodine/fiobj_json.c +20 -17
  27. data/ext/iodine/fiobj_json.h +5 -5
  28. data/ext/iodine/fiobj_mem.h +71 -0
  29. data/ext/iodine/fiobj_mustache.c +310 -0
  30. data/ext/iodine/fiobj_mustache.h +40 -0
  31. data/ext/iodine/fiobj_numbers.c +199 -94
  32. data/ext/iodine/fiobj_numbers.h +7 -7
  33. data/ext/iodine/fiobj_str.c +142 -333
  34. data/ext/iodine/fiobj_str.h +65 -55
  35. data/ext/iodine/fiobject.c +49 -11
  36. data/ext/iodine/fiobject.h +40 -39
  37. data/ext/iodine/http.c +382 -190
  38. data/ext/iodine/http.h +124 -80
  39. data/ext/iodine/http1.c +99 -127
  40. data/ext/iodine/http1.h +5 -5
  41. data/ext/iodine/http1_parser.c +3 -2
  42. data/ext/iodine/http1_parser.h +2 -2
  43. data/ext/iodine/http_internal.c +14 -12
  44. data/ext/iodine/http_internal.h +25 -19
  45. data/ext/iodine/iodine.c +37 -18
  46. data/ext/iodine/iodine.h +4 -0
  47. data/ext/iodine/iodine_caller.c +9 -2
  48. data/ext/iodine/iodine_caller.h +2 -0
  49. data/ext/iodine/iodine_connection.c +82 -117
  50. data/ext/iodine/iodine_defer.c +57 -50
  51. data/ext/iodine/iodine_defer.h +0 -1
  52. data/ext/iodine/iodine_fiobj2rb.h +4 -2
  53. data/ext/iodine/iodine_helpers.c +4 -4
  54. data/ext/iodine/iodine_http.c +25 -32
  55. data/ext/iodine/iodine_json.c +2 -1
  56. data/ext/iodine/iodine_mustache.c +423 -0
  57. data/ext/iodine/iodine_mustache.h +6 -0
  58. data/ext/iodine/iodine_pubsub.c +48 -153
  59. data/ext/iodine/iodine_pubsub.h +5 -4
  60. data/ext/iodine/iodine_rack_io.c +7 -5
  61. data/ext/iodine/iodine_store.c +16 -13
  62. data/ext/iodine/iodine_tcp.c +26 -34
  63. data/ext/iodine/mustache_parser.h +1085 -0
  64. data/ext/iodine/redis_engine.c +740 -646
  65. data/ext/iodine/redis_engine.h +13 -15
  66. data/ext/iodine/resp_parser.h +11 -5
  67. data/ext/iodine/websocket_parser.h +13 -13
  68. data/ext/iodine/websockets.c +240 -393
  69. data/ext/iodine/websockets.h +52 -113
  70. data/lib/iodine.rb +1 -1
  71. data/lib/iodine/mustache.rb +140 -0
  72. data/lib/iodine/version.rb +1 -1
  73. metadata +15 -28
  74. data/ext/iodine/defer.c +0 -566
  75. data/ext/iodine/defer.h +0 -148
  76. data/ext/iodine/evio.c +0 -26
  77. data/ext/iodine/evio.h +0 -161
  78. data/ext/iodine/evio_callbacks.c +0 -26
  79. data/ext/iodine/evio_epoll.c +0 -251
  80. data/ext/iodine/evio_kqueue.c +0 -194
  81. data/ext/iodine/facil.c +0 -2325
  82. data/ext/iodine/facil.h +0 -616
  83. data/ext/iodine/fio_base64.c +0 -277
  84. data/ext/iodine/fio_base64.h +0 -71
  85. data/ext/iodine/fio_llist.h +0 -257
  86. data/ext/iodine/fio_mem.c +0 -675
  87. data/ext/iodine/fio_mem.h +0 -143
  88. data/ext/iodine/fio_random.c +0 -248
  89. data/ext/iodine/fio_random.h +0 -45
  90. data/ext/iodine/fio_sha1.c +0 -362
  91. data/ext/iodine/fio_sha1.h +0 -107
  92. data/ext/iodine/fio_sha2.c +0 -842
  93. data/ext/iodine/fio_sha2.h +0 -169
  94. data/ext/iodine/pubsub.c +0 -867
  95. data/ext/iodine/pubsub.h +0 -221
  96. data/ext/iodine/sock.c +0 -1366
  97. data/ext/iodine/sock.h +0 -566
  98. data/ext/iodine/spnlock.inc +0 -111
@@ -5,11 +5,10 @@ License: MIT
5
5
  Feel free to copy, use and enjoy according to the license provided.
6
6
  */
7
7
 
8
- #include "spnlock.inc"
8
+ #include <fio.h>
9
9
 
10
- #include "fio_base64.h"
11
- #include "http1.h"
12
- #include "http_internal.h"
10
+ #include <http1.h>
11
+ #include <http_internal.h>
13
12
 
14
13
  #include <ctype.h>
15
14
  #include <fcntl.h>
@@ -19,8 +18,6 @@ Feel free to copy, use and enjoy according to the license provided.
19
18
  #include <sys/types.h>
20
19
  #include <unistd.h>
21
20
 
22
- #include "fio_mem.h"
23
-
24
21
  /* *****************************************************************************
25
22
  Patch for OSX version < 10.12 from https://stackoverflow.com/a/9781275/4025095
26
23
  ***************************************************************************** */
@@ -68,7 +65,7 @@ static inline void add_content_type(http_s *r) {
68
65
 
69
66
  static FIOBJ current_date;
70
67
  static time_t last_date_added;
71
- static spn_lock_i date_lock;
68
+ static fio_lock_i date_lock;
72
69
  static inline void add_date(http_s *r) {
73
70
  static uint64_t date_hash = 0;
74
71
  if (!date_hash)
@@ -77,18 +74,18 @@ static inline void add_date(http_s *r) {
77
74
  if (!mod_hash)
78
75
  mod_hash = fio_siphash("last-modified", 13);
79
76
 
80
- if (facil_last_tick().tv_sec > last_date_added) {
81
- spn_lock(&date_lock);
82
- if (facil_last_tick().tv_sec > last_date_added) { /* retest inside lock */
77
+ if (fio_last_tick().tv_sec > last_date_added) {
78
+ fio_lock(&date_lock);
79
+ if (fio_last_tick().tv_sec > last_date_added) { /* retest inside lock */
83
80
  FIOBJ tmp = fiobj_str_buf(32);
84
81
  FIOBJ old = current_date;
85
- fiobj_str_resize(tmp, http_time2str(fiobj_obj2cstr(tmp).data,
86
- facil_last_tick().tv_sec));
87
- last_date_added = facil_last_tick().tv_sec;
82
+ fiobj_str_resize(
83
+ tmp, http_time2str(fiobj_obj2cstr(tmp).data, fio_last_tick().tv_sec));
84
+ last_date_added = fio_last_tick().tv_sec;
88
85
  current_date = tmp;
89
86
  fiobj_free(old);
90
87
  }
91
- spn_unlock(&date_lock);
88
+ fio_unlock(&date_lock);
92
89
  }
93
90
 
94
91
  if (!fiobj_hash_get2(r->private_data.out_headers, date_hash)) {
@@ -119,8 +116,8 @@ static int write_header(FIOBJ o, void *w_) {
119
116
  fiobj_each1(o, 0, write_header, w);
120
117
  return 0;
121
118
  }
122
- fio_cstr_s name = fiobj_obj2cstr(w->name);
123
- fio_cstr_s str = fiobj_obj2cstr(o);
119
+ fio_str_info_s name = fiobj_obj2cstr(w->name);
120
+ fio_str_info_s str = fiobj_obj2cstr(o);
124
121
  if (!str.data)
125
122
  return 0;
126
123
  fiobj_str_write(w->dest, name.data, name.len);
@@ -159,11 +156,11 @@ int http_set_header(http_s *r, FIOBJ name, FIOBJ value) {
159
156
  *
160
157
  * Returns -1 on error and 0 on success.
161
158
  */
162
- int http_set_header2(http_s *r, fio_cstr_s n, fio_cstr_s v) {
163
- if (HTTP_INVALID_HANDLE(r) || !n.data || !n.length || (v.data && !v.length))
159
+ int http_set_header2(http_s *r, fio_str_info_s n, fio_str_info_s v) {
160
+ if (HTTP_INVALID_HANDLE(r) || !n.data || !n.len || (v.data && !v.len))
164
161
  return -1;
165
- FIOBJ tmp = fiobj_str_new(n.data, n.length);
166
- int ret = http_set_header(r, tmp, fiobj_str_new(v.data, v.length));
162
+ FIOBJ tmp = fiobj_str_new(n.data, n.len);
163
+ int ret = http_set_header(r, tmp, fiobj_str_new(v.data, v.len));
167
164
  fiobj_free(tmp);
168
165
  return ret;
169
166
  }
@@ -179,8 +176,9 @@ int http_set_cookie(http_s *h, http_cookie_args_s cookie) {
179
176
  HTTP_ASSERT(h, "Can't set cookie for NULL HTTP handler!");
180
177
  #endif
181
178
  if (HTTP_INVALID_HANDLE(h) || cookie.name_len >= 32768 ||
182
- cookie.value_len >= 131072)
179
+ cookie.value_len >= 131072) {
183
180
  return -1;
181
+ }
184
182
 
185
183
  static int warn_illegal = 0;
186
184
 
@@ -188,7 +186,7 @@ int http_set_cookie(http_s *h, http_cookie_args_s cookie) {
188
186
  size_t capa = cookie.name_len + cookie.value_len + 128;
189
187
  size_t len = 0;
190
188
  FIOBJ c = fiobj_str_buf(capa);
191
- fio_cstr_s t = fiobj_obj2cstr(c);
189
+ fio_str_info_s t = fiobj_obj2cstr(c);
192
190
  if (cookie.name) {
193
191
  if (cookie.name_len) {
194
192
  size_t tmp = 0;
@@ -408,13 +406,15 @@ int http_sendfile2(http_s *h, const char *prefix, size_t prefix_len,
408
406
  /* create filename string */
409
407
  FIOBJ filename = fiobj_str_tmp();
410
408
  if (prefix && prefix_len) {
409
+ /* start with prefix path */
411
410
  if (encoded && prefix[prefix_len - 1] == '/' && encoded[0] == '/')
412
411
  --prefix_len;
413
412
  fiobj_str_capa_assert(filename, prefix_len + encoded_len + 4);
414
413
  fiobj_str_write(filename, prefix, prefix_len);
415
414
  }
416
415
  {
417
- fio_cstr_s tmp = fiobj_obj2cstr(filename);
416
+ /* decode filename in cases where it's URL encoded */
417
+ fio_str_info_s tmp = fiobj_obj2cstr(filename);
418
418
  if (encoded) {
419
419
  char *pos = (char *)encoded;
420
420
  const char *end = encoded + encoded_len;
@@ -427,7 +427,7 @@ int http_sendfile2(http_s *h, const char *prefix, size_t prefix_len,
427
427
  if (*pos == '%') {
428
428
  // decode hex value
429
429
  // this is a percent encoded value.
430
- if (hex2byte(tmp.bytes + tmp.len, (uint8_t *)pos + 1))
430
+ if (hex2byte((uint8_t *)tmp.data + tmp.len, (uint8_t *)pos + 1))
431
431
  return -1;
432
432
  tmp.len++;
433
433
  pos += 3;
@@ -445,12 +445,12 @@ int http_sendfile2(http_s *h, const char *prefix, size_t prefix_len,
445
445
  int file = -1;
446
446
  uint8_t is_gz = 0;
447
447
 
448
- fio_cstr_s s = fiobj_obj2cstr(filename);
448
+ fio_str_info_s s = fiobj_obj2cstr(filename);
449
449
  {
450
450
  FIOBJ tmp = fiobj_hash_get2(h->headers, accept_enc_hash);
451
451
  if (!tmp)
452
452
  goto no_gzip_support;
453
- fio_cstr_s ac_str = fiobj_obj2cstr(tmp);
453
+ fio_str_info_s ac_str = fiobj_obj2cstr(tmp);
454
454
  if (!ac_str.data || !strstr(ac_str.data, "gzip"))
455
455
  goto no_gzip_support;
456
456
  if (s.data[s.len - 3] != '.' || s.data[s.len - 2] != 'g' ||
@@ -517,7 +517,7 @@ found_file:
517
517
  /* range ahead... */
518
518
  if (FIOBJ_TYPE_IS(tmp, FIOBJ_T_ARRAY))
519
519
  tmp = fiobj_ary_index(tmp, 0);
520
- fio_cstr_s range = fiobj_obj2cstr(tmp);
520
+ fio_str_info_s range = fiobj_obj2cstr(tmp);
521
521
  if (!range.data || memcmp("bytes=", range.data, 6))
522
522
  goto open_file;
523
523
  char *pos = range.data + 6;
@@ -548,11 +548,14 @@ found_file:
548
548
  }
549
549
  h->status = 206;
550
550
 
551
- http_set_header(h, HTTP_HEADER_CONTENT_RANGE,
552
- fiobj_strprintf("bytes %lu-%lu/%lu",
553
- (unsigned long)start_at,
554
- (unsigned long)(start_at + length - 1),
555
- (unsigned long)file_data.st_size));
551
+ {
552
+ FIOBJ cranges = fiobj_str_buf(1);
553
+ fiobj_str_printf(cranges, "bytes %lu-%lu/%lu",
554
+ (unsigned long)start_at,
555
+ (unsigned long)(start_at + length - 1),
556
+ (unsigned long)file_data.st_size);
557
+ http_set_header(h, HTTP_HEADER_CONTENT_RANGE, cranges);
558
+ }
556
559
  http_set_header(h, HTTP_HEADER_ACCEPT_RANGES,
557
560
  fiobj_dup(HTTP_HVALUE_BYTES));
558
561
  }
@@ -563,8 +566,8 @@ found_file:
563
566
  switch (s.len) {
564
567
  case 7:
565
568
  if (!strncasecmp("options", s.data, 7)) {
566
- http_set_header2(h, (fio_cstr_s){.data = "allow", .len = 5},
567
- (fio_cstr_s){.data = "GET, HEAD", .len = 9});
569
+ http_set_header2(h, (fio_str_info_s){.data = "allow", .len = 5},
570
+ (fio_str_info_s){.data = "GET, HEAD", .len = 9});
568
571
  h->status = 200;
569
572
  http_finish(h);
570
573
  return 0;
@@ -650,7 +653,7 @@ int http_send_error(http_s *r, size_t error) {
650
653
  http2protocol(r)->settings->public_folder_length, buffer,
651
654
  pos)) {
652
655
  http_set_header(r, HTTP_HEADER_CONTENT_TYPE, http_mimetype_find("txt", 3));
653
- fio_cstr_s t = http_status2str(error);
656
+ fio_str_info_s t = http_status2str(error);
654
657
  http_send_body(r, t.data, t.len);
655
658
  }
656
659
  return 0;
@@ -675,7 +678,7 @@ void http_finish(http_s *r) {
675
678
  * Returns -1 on error and 0 on success.
676
679
  */
677
680
  int http_push_data(http_s *r, void *data, uintptr_t length, FIOBJ mime_type) {
678
- if (!r || !(http_protocol_s *)r->private_data.flag)
681
+ if (!r || !(http_fio_protocol_s *)r->private_data.flag)
679
682
  return -1;
680
683
  return ((http_vtable_s *)r->private_data.vtbl)
681
684
  ->http_push_data(r, data, length, mime_type);
@@ -699,44 +702,40 @@ int http_push_file(http_s *h, FIOBJ filename, FIOBJ mime_type) {
699
702
  * Upgrades an HTTP/1.1 connection to a Websocket connection.
700
703
  */
701
704
  #undef http_upgrade2ws
702
- int http_upgrade2ws(websocket_settings_s args) {
703
- if (!args.http) {
705
+ int http_upgrade2ws(http_s *h, websocket_settings_s args) {
706
+ if (!h) {
704
707
  fprintf(stderr,
705
708
  "ERROR: `http_upgrade2ws` requires a valid `http_s` handle.");
706
709
  goto error;
707
710
  }
708
- if (HTTP_INVALID_HANDLE(args.http))
711
+ if (HTTP_INVALID_HANDLE(h))
709
712
  goto error;
710
- return ((http_vtable_s *)args.http->private_data.vtbl)->http2websocket(&args);
713
+ return ((http_vtable_s *)h->private_data.vtbl)->http2websocket(h, &args);
711
714
  error:
712
715
  if (args.on_close)
713
- args.on_close(0, args.udata);
716
+ args.on_close(-1, args.udata);
714
717
  return -1;
715
718
  }
716
719
 
717
720
  /* *****************************************************************************
718
721
  Pause / Resume
719
722
  ***************************************************************************** */
720
- typedef struct {
723
+ struct http_pause_handle_s {
721
724
  uintptr_t uuid;
722
725
  http_s *h;
723
726
  void *udata;
724
727
  void (*task)(http_s *);
725
728
  void (*fallback)(void *);
726
- } http_pause_handle_s;
729
+ };
727
730
 
728
731
  /** Returns the `udata` associated with the paused opaque handle */
729
- void *http_paused_udata_get(void *http_) {
730
- const http_pause_handle_s *http = http_;
731
- return http->udata;
732
- }
732
+ void *http_paused_udata_get(http_pause_handle_s *http) { return http->udata; }
733
733
 
734
734
  /**
735
735
  * Sets the `udata` associated with the paused opaque handle, returning the
736
736
  * old value.
737
737
  */
738
- void *http_paused_udata_set(void *http_, void *udata) {
739
- http_pause_handle_s *http = http_;
738
+ void *http_paused_udata_set(http_pause_handle_s *http, void *udata) {
740
739
  void *old = http->udata;
741
740
  http->udata = udata;
742
741
  return old;
@@ -749,8 +748,8 @@ static void http_pause_wrapper(void *h_, void *task_) {
749
748
  }
750
749
 
751
750
  /* perform the resume task within of the connection's lock */
752
- static void http_resume_wrapper(intptr_t uuid, protocol_s *p_, void *arg) {
753
- http_protocol_s *p = (http_protocol_s *)p_;
751
+ static void http_resume_wrapper(intptr_t uuid, fio_protocol_s *p_, void *arg) {
752
+ http_fio_protocol_s *p = (http_fio_protocol_s *)p_;
754
753
  http_pause_handle_s *http = arg;
755
754
  http_s *h = http->h;
756
755
  h->udata = http->udata;
@@ -774,39 +773,40 @@ static void http_resume_fallback_wrapper(intptr_t uuid, void *arg) {
774
773
  /**
775
774
  * Defers the request / response handling for later.
776
775
  */
777
- void http_pause(http_s *h, void (*task)(void *http)) {
776
+ void http_pause(http_s *h, void (*task)(http_pause_handle_s *http)) {
778
777
  if (HTTP_INVALID_HANDLE(h)) {
779
778
  return;
780
779
  }
781
- http_protocol_s *p = (http_protocol_s *)h->private_data.flag;
780
+ http_fio_protocol_s *p = (http_fio_protocol_s *)h->private_data.flag;
782
781
  http_vtable_s *vtbl = (http_vtable_s *)h->private_data.vtbl;
783
782
  http_pause_handle_s *http = fio_malloc(sizeof(*http));
784
783
  *http = (http_pause_handle_s){
785
- .uuid = p->uuid, .h = h, .udata = h->udata,
784
+ .uuid = p->uuid,
785
+ .h = h,
786
+ .udata = h->udata,
786
787
  };
787
788
  vtbl->http_on_pause(h, p);
788
- defer(http_pause_wrapper, http, (void *)((uintptr_t)task));
789
+ fio_defer(http_pause_wrapper, http, (void *)((uintptr_t)task));
789
790
  }
790
791
 
791
792
  /**
792
793
  * Defers the request / response handling for later.
793
794
  */
794
- void http_resume(void *http_, void (*task)(http_s *h),
795
+ void http_resume(http_pause_handle_s *http, void (*task)(http_s *h),
795
796
  void (*fallback)(void *udata)) {
796
- if (!http_)
797
+ if (!http)
797
798
  return;
798
- http_pause_handle_s *http = http_;
799
799
  http->task = task;
800
800
  http->fallback = fallback;
801
- facil_defer(.uuid = http->uuid, .arg = http, .type = FIO_PR_LOCK_TASK,
802
- .task = http_resume_wrapper,
803
- .fallback = http_resume_fallback_wrapper);
801
+ fio_defer_io_task(http->uuid, .udata = http, .type = FIO_PR_LOCK_TASK,
802
+ .task = http_resume_wrapper,
803
+ .fallback = http_resume_fallback_wrapper);
804
804
  }
805
805
 
806
806
  /**
807
807
  * Hijacks the socket away from the HTTP protocol and away from facil.io.
808
808
  */
809
- intptr_t http_hijack(http_s *h, fio_cstr_s *leftover) {
809
+ intptr_t http_hijack(http_s *h, fio_str_info_s *leftover) {
810
810
  if (!h)
811
811
  return -1;
812
812
  return ((http_vtable_s *)h->private_data.vtbl)->http_hijack(h, leftover);
@@ -844,9 +844,9 @@ http_settings_s *http_settings_new(http_settings_s arg_settings) {
844
844
  if (!arg_settings.max_header_size)
845
845
  arg_settings.max_header_size = 32 * 1024; /* defaults to 32Kib seconds */
846
846
  if (arg_settings.max_clients <= 0 ||
847
- arg_settings.max_clients + HTTP_BUSY_UNLESS_HAS_FDS >
848
- sock_max_capacity()) {
849
- arg_settings.max_clients = sock_max_capacity();
847
+ (size_t)(arg_settings.max_clients + HTTP_BUSY_UNLESS_HAS_FDS) >
848
+ fio_capa()) {
849
+ arg_settings.max_clients = fio_capa();
850
850
  if ((ssize_t)arg_settings.max_clients - HTTP_BUSY_UNLESS_HAS_FDS > 0)
851
851
  arg_settings.max_clients -= HTTP_BUSY_UNLESS_HAS_FDS;
852
852
  }
@@ -888,19 +888,19 @@ Listening to HTTP connections
888
888
 
889
889
  static void http_on_open(intptr_t uuid, void *set) {
890
890
  static uint8_t at_capa;
891
- facil_set_timeout(uuid, ((http_settings_s *)set)->timeout);
892
- if (sock_uuid2fd(uuid) >= ((http_settings_s *)set)->max_clients) {
891
+ fio_timeout_set(uuid, ((http_settings_s *)set)->timeout);
892
+ if (fio_uuid2fd(uuid) >= ((http_settings_s *)set)->max_clients) {
893
893
  if (!at_capa)
894
894
  fprintf(stderr, "WARNING: HTTP server at capacity\n");
895
895
  at_capa = 1;
896
896
  http_send_error2(uuid, 503, set);
897
- sock_close(uuid);
897
+ fio_close(uuid);
898
898
  return;
899
899
  }
900
900
  at_capa = 0;
901
- protocol_s *pr = http1_new(uuid, set, NULL, 0);
901
+ fio_protocol_s *pr = http1_new(uuid, set, NULL, 0);
902
902
  if (!pr)
903
- sock_close(uuid);
903
+ fio_close(uuid);
904
904
  }
905
905
 
906
906
  static void http_on_finish(intptr_t uuid, void *set) {
@@ -921,8 +921,9 @@ static void http_on_finish(intptr_t uuid, void *set) {
921
921
  * Returns -1 on error and 0 on success.
922
922
  */
923
923
  #undef http_listen
924
- int http_listen(const char *port, const char *binding,
925
- struct http_settings_s arg_settings) {
924
+ intptr_t http_listen(const char *port, const char *binding,
925
+ struct http_settings_s arg_settings) {
926
+ http_lib_init();
926
927
  if (arg_settings.on_request == NULL) {
927
928
  fprintf(stderr, "ERROR: http_listen requires the .on_request parameter "
928
929
  "to be set\n");
@@ -933,9 +934,9 @@ int http_listen(const char *port, const char *binding,
933
934
  http_settings_s *settings = http_settings_new(arg_settings);
934
935
  settings->is_client = 0;
935
936
 
936
- return facil_listen(.port = port, .address = binding,
937
- .on_finish = http_on_finish, .on_open = http_on_open,
938
- .udata = settings);
937
+ return fio_listen(.port = port, .address = binding,
938
+ .on_finish = http_on_finish, .on_open = http_on_open,
939
+ .udata = settings);
939
940
  }
940
941
  /** Listens to HTTP connections at the specified `port` and `binding`. */
941
942
  #define http_listen(port, binding, ...) \
@@ -947,25 +948,25 @@ int http_listen(const char *port, const char *binding,
947
948
  * Returns NULL on error (i.e., connection was lost).
948
949
  */
949
950
  struct http_settings_s *http_settings(http_s *r) {
950
- return ((http_protocol_s *)r->private_data.flag)->settings;
951
+ return ((http_fio_protocol_s *)r->private_data.flag)->settings;
951
952
  }
952
953
 
953
954
  /**
954
955
  * Returns the direct address of the connected peer (likely an intermediary).
955
956
  */
956
- sock_peer_addr_s http_peer_addr(http_s *h) {
957
- return sock_peer_addr(((http_protocol_s *)h->private_data.flag)->uuid);
957
+ fio_str_info_s http_peer_addr(http_s *h) {
958
+ return fio_peer_addr(((http_fio_protocol_s *)h->private_data.flag)->uuid);
958
959
  }
959
960
 
960
961
  /* *****************************************************************************
961
962
  HTTP client connections
962
963
  ***************************************************************************** */
963
964
 
964
- static void http_on_close_client(intptr_t uuid, protocol_s *protocol) {
965
- http_protocol_s *p = (http_protocol_s *)protocol;
965
+ static void http_on_close_client(intptr_t uuid, fio_protocol_s *protocol) {
966
+ http_fio_protocol_s *p = (http_fio_protocol_s *)protocol;
966
967
  http_settings_s *set = p->settings;
967
- void (**original)(intptr_t, protocol_s *) =
968
- (void (**)(intptr_t, protocol_s *))(set + 1);
968
+ void (**original)(intptr_t, fio_protocol_s *) =
969
+ (void (**)(intptr_t, fio_protocol_s *))(set + 1);
969
970
  if (set->on_finish)
970
971
  set->on_finish(set);
971
972
 
@@ -977,15 +978,15 @@ static void http_on_open_client(intptr_t uuid, void *set_) {
977
978
  http_settings_s *set = set_;
978
979
  http_s *h = set->udata;
979
980
  set->udata = h->udata;
980
- facil_set_timeout(uuid, set->timeout);
981
- protocol_s *pr = http1_new(uuid, set, NULL, 0);
981
+ fio_timeout_set(uuid, set->timeout);
982
+ fio_protocol_s *pr = http1_new(uuid, set, NULL, 0);
982
983
  if (!pr) {
983
- sock_close(uuid);
984
+ fio_close(uuid);
984
985
  return;
985
986
  }
986
987
  { /* store the original on_close at the end of the struct, we wrap it. */
987
- void (**original)(intptr_t, protocol_s *) =
988
- (void (**)(intptr_t, protocol_s *))(set + 1);
988
+ void (**original)(intptr_t, fio_protocol_s *) =
989
+ (void (**)(intptr_t, fio_protocol_s *))(set + 1);
989
990
  *original = pr->on_close;
990
991
  pr->on_close = http_on_close_client;
991
992
  }
@@ -1021,13 +1022,15 @@ static void http_on_client_failed(intptr_t uuid, void *set_) {
1021
1022
  * called.
1022
1023
  */
1023
1024
  #undef http_connect
1024
- int http_connect(const char *address, struct http_settings_s arg_settings) {
1025
+ intptr_t http_connect(const char *address,
1026
+ struct http_settings_s arg_settings) {
1025
1027
  if (!arg_settings.on_response && !arg_settings.on_upgrade) {
1026
1028
  fprintf(stderr, "ERROR: http_connect requires either an on_response "
1027
1029
  " or an on_upgrade callback.\n");
1028
1030
  errno = EINVAL;
1029
- return -1;
1031
+ goto on_error;
1030
1032
  }
1033
+ http_lib_init();
1031
1034
  size_t len;
1032
1035
  char *a, *p;
1033
1036
  uint8_t is_websocket = 0;
@@ -1036,8 +1039,9 @@ int http_connect(const char *address, struct http_settings_s arg_settings) {
1036
1039
  if (!address || (len = strlen(address)) <= 5) {
1037
1040
  fprintf(stderr, "ERROR: http_connect requires a valid address.\n");
1038
1041
  errno = EINVAL;
1039
- return -1;
1042
+ goto on_error;
1040
1043
  }
1044
+ // TODO: use http_url_parse
1041
1045
  if (!strncasecmp(address, "ws", 2)) {
1042
1046
  is_websocket = 1;
1043
1047
  address += 2;
@@ -1048,7 +1052,7 @@ int http_connect(const char *address, struct http_settings_s arg_settings) {
1048
1052
  } else {
1049
1053
  fprintf(stderr, "ERROR: http_connect requires a valid address.\n");
1050
1054
  errno = EINVAL;
1051
- return -1;
1055
+ goto on_error;
1052
1056
  }
1053
1057
  /* parse address */
1054
1058
  if (address[0] == 's') {
@@ -1057,11 +1061,11 @@ int http_connect(const char *address, struct http_settings_s arg_settings) {
1057
1061
  fprintf(stderr, "ERROR: http_connect doesn't support TLS/SSL "
1058
1062
  "just yet.\n");
1059
1063
  errno = EINVAL;
1060
- return -1;
1064
+ goto on_error;
1061
1065
  } else if (len <= 3 || strncmp(address, "://", 3)) {
1062
1066
  fprintf(stderr, "ERROR: http_connect requires a valid address.\n");
1063
1067
  errno = EINVAL;
1064
- return -1;
1068
+ goto on_error;
1065
1069
  } else {
1066
1070
  len -= 3;
1067
1071
  address += 3;
@@ -1115,24 +1119,26 @@ int http_connect(const char *address, struct http_settings_s arg_settings) {
1115
1119
  h->status = 0;
1116
1120
  h->path = path;
1117
1121
  settings->udata = h;
1118
- http_set_header2(h, (fio_cstr_s){.data = "host", .len = 4},
1119
- (fio_cstr_s){.data = a, .len = len});
1122
+ http_set_header2(h, (fio_str_info_s){.data = "host", .len = 4},
1123
+ (fio_str_info_s){.data = a, .len = len});
1120
1124
  intptr_t ret;
1121
1125
  if (is_websocket) {
1122
1126
  /* force HTTP/1.1 */
1123
- ret =
1124
- facil_connect(.address = a, .port = p, .on_fail = http_on_client_failed,
1127
+ ret = fio_connect(.address = a, .port = p, .on_fail = http_on_client_failed,
1125
1128
  .on_connect = http_on_open_client, .udata = settings);
1126
1129
  (void)0;
1127
1130
  } else {
1128
1131
  /* Allow for any HTTP version */
1129
- ret =
1130
- facil_connect(.address = a, .port = p, .on_fail = http_on_client_failed,
1132
+ ret = fio_connect(.address = a, .port = p, .on_fail = http_on_client_failed,
1131
1133
  .on_connect = http_on_open_client, .udata = settings);
1132
1134
  (void)0;
1133
1135
  }
1134
1136
  fio_free(a);
1135
1137
  return ret;
1138
+ on_error:
1139
+ if (arg_settings.on_finish)
1140
+ arg_settings.on_finish(&arg_settings);
1141
+ return -1;
1136
1142
  }
1137
1143
  #define http_connect(address, ...) \
1138
1144
  http_connect((address), (struct http_settings_s){__VA_ARGS__})
@@ -1145,13 +1151,12 @@ HTTP Websocket Connect
1145
1151
  static void on_websocket_http_connected(http_s *h) {
1146
1152
  websocket_settings_s *s = h->udata;
1147
1153
  h->udata = http_settings(h)->udata = NULL;
1148
- s->http = h;
1149
1154
  if (!h->path) {
1150
1155
  fprintf(stderr, "WARNING: (websocket client) path not specified in "
1151
1156
  "address, assuming root!\n");
1152
1157
  h->path = fiobj_str_new("/", 1);
1153
1158
  }
1154
- http_upgrade2ws(*s);
1159
+ http_upgrade2ws(h, *s);
1155
1160
  fio_free(s);
1156
1161
  }
1157
1162
 
@@ -1187,7 +1192,7 @@ Note:
1187
1192
  ***************************************************************************** */
1188
1193
 
1189
1194
  static inline void http_sse_copy2str(FIOBJ dest, char *prefix, size_t pre_len,
1190
- fio_cstr_s data) {
1195
+ fio_str_info_s data) {
1191
1196
  if (!data.len)
1192
1197
  return;
1193
1198
  const char *stop = data.data + data.len;
@@ -1208,29 +1213,29 @@ static inline void http_sse_copy2str(FIOBJ dest, char *prefix, size_t pre_len,
1208
1213
  }
1209
1214
 
1210
1215
  /** The on message callback. the `*msg` pointer is to a temporary object. */
1211
- static void http_sse_on_message(pubsub_message_s *msg) {
1216
+ static void http_sse_on_message(fio_msg_s *msg) {
1212
1217
  http_sse_internal_s *sse = msg->udata1;
1213
1218
  struct http_sse_subscribe_args *args = msg->udata2;
1214
- if (args->on_message) {
1215
- /* perform a callback */
1216
- protocol_s *pr = facil_protocol_try_lock(sse->uuid, FIO_PR_LOCK_TASK);
1217
- if (!pr)
1218
- goto postpone;
1219
- args->on_message(&sse->sse, msg->channel, msg->message, args->udata);
1220
- facil_protocol_unlock(pr, FIO_PR_LOCK_TASK);
1221
- return;
1222
- }
1223
- /* write directly to HTTP stream / connection */
1224
- fio_cstr_s m = fiobj_obj2cstr(msg->message);
1225
- http_sse_write(&sse->sse, .data = m);
1226
-
1219
+ /* perform a callback */
1220
+ fio_protocol_s *pr = fio_protocol_try_lock(sse->uuid, FIO_PR_LOCK_TASK);
1221
+ if (!pr)
1222
+ goto postpone;
1223
+ args->on_message(&sse->sse, msg->channel, msg->msg, args->udata);
1224
+ fio_protocol_unlock(pr, FIO_PR_LOCK_TASK);
1227
1225
  return;
1228
1226
  postpone:
1229
1227
  if (errno == EBADF)
1230
1228
  return;
1231
- pubsub_defer(msg);
1229
+ fio_message_defer(msg);
1232
1230
  return;
1233
1231
  }
1232
+
1233
+ static void http_sse_on_message__direct(http_sse_s *sse, fio_str_info_s channel,
1234
+ fio_str_info_s msg, void *udata) {
1235
+ http_sse_write(sse, .data = msg);
1236
+ (void)udata;
1237
+ (void)channel;
1238
+ }
1234
1239
  /** An optional callback for when a subscription is fully canceled. */
1235
1240
  static void http_sse_on_unsubscribe(void *sse_, void *args_) {
1236
1241
  http_sse_internal_s *sse = sse_;
@@ -1261,24 +1266,24 @@ uintptr_t http_sse_subscribe(http_sse_s *sse_,
1261
1266
  http_sse_internal_s *sse = FIO_LS_EMBD_OBJ(http_sse_internal_s, sse, sse_);
1262
1267
  if (sse->uuid == -1)
1263
1268
  return 0;
1269
+ if (!args.on_message)
1270
+ args.on_message = http_sse_on_message__direct;
1264
1271
  struct http_sse_subscribe_args *udata = malloc(sizeof(*udata));
1265
- if (!udata)
1266
- return 0;
1272
+ FIO_ASSERT_ALLOC(udata);
1267
1273
  *udata = args;
1268
1274
 
1269
- spn_add(&sse->ref, 1);
1270
- pubsub_sub_pt sub =
1271
- pubsub_subscribe(.channel = args.channel,
1272
- .on_message = http_sse_on_message,
1273
- .on_unsubscribe = http_sse_on_unsubscribe, .udata1 = sse,
1274
- .udata2 = udata, .use_pattern = args.use_pattern);
1275
+ fio_atomic_add(&sse->ref, 1);
1276
+ subscription_s *sub =
1277
+ fio_subscribe(.channel = args.channel, .on_message = http_sse_on_message,
1278
+ .on_unsubscribe = http_sse_on_unsubscribe, .udata1 = sse,
1279
+ .udata2 = udata, .match = args.match);
1275
1280
  if (!sub)
1276
1281
  return 0;
1277
1282
 
1278
- spn_lock(&sse->lock);
1283
+ fio_lock(&sse->lock);
1279
1284
  fio_ls_push(&sse->subscriptions, sub);
1280
1285
  fio_ls_s *pos = sse->subscriptions.prev;
1281
- spn_unlock(&sse->lock);
1286
+ fio_unlock(&sse->lock);
1282
1287
  return (uintptr_t)pos;
1283
1288
  }
1284
1289
 
@@ -1289,11 +1294,11 @@ void http_sse_unsubscribe(http_sse_s *sse_, uintptr_t subscription) {
1289
1294
  if (!sse_ || !subscription)
1290
1295
  return;
1291
1296
  http_sse_internal_s *sse = FIO_LS_EMBD_OBJ(http_sse_internal_s, sse, sse_);
1292
- pubsub_sub_pt sub = (pubsub_sub_pt)((fio_ls_s *)subscription)->obj;
1293
- spn_lock(&sse->lock);
1297
+ subscription_s *sub = (subscription_s *)((fio_ls_s *)subscription)->obj;
1298
+ fio_lock(&sse->lock);
1294
1299
  fio_ls_remove((fio_ls_s *)subscription);
1295
- spn_unlock(&sse->lock);
1296
- pubsub_unsubscribe(sub);
1300
+ fio_unlock(&sse->lock);
1301
+ fio_unsubscribe(sub);
1297
1302
  }
1298
1303
 
1299
1304
  #undef http_upgrade2sse
@@ -1321,7 +1326,7 @@ void http_sse_set_timout(http_sse_s *sse_, uint8_t timeout) {
1321
1326
  if (!sse_)
1322
1327
  return;
1323
1328
  http_sse_internal_s *sse = FIO_LS_EMBD_OBJ(http_sse_internal_s, sse, sse_);
1324
- facil_set_timeout(sse->uuid, timeout);
1329
+ fio_timeout_set(sse->uuid, timeout);
1325
1330
  }
1326
1331
 
1327
1332
  #undef http_sse_write
@@ -1330,7 +1335,7 @@ void http_sse_set_timout(http_sse_s *sse_, uint8_t timeout) {
1330
1335
  */
1331
1336
  int http_sse_write(http_sse_s *sse, struct http_sse_write_args args) {
1332
1337
  if (!sse || !(args.id.len + args.data.len + args.event.len) ||
1333
- sock_isclosed(FIO_LS_EMBD_OBJ(http_sse_internal_s, sse, sse)->uuid))
1338
+ fio_is_closed(FIO_LS_EMBD_OBJ(http_sse_internal_s, sse, sse)->uuid))
1334
1339
  return -1;
1335
1340
  FIOBJ buf;
1336
1341
  {
@@ -1354,11 +1359,11 @@ int http_sse_write(http_sse_s *sse, struct http_sse_write_args args) {
1354
1359
  }
1355
1360
 
1356
1361
  /**
1357
- * Get the connection's UUID (for facil_defer and similar use cases).
1362
+ * Get the connection's UUID (for fio_defer and similar use cases).
1358
1363
  */
1359
1364
  intptr_t http_sse2uuid(http_sse_s *sse) {
1360
1365
  if (!sse ||
1361
- sock_isclosed(FIO_LS_EMBD_OBJ(http_sse_internal_s, sse, sse)->uuid))
1366
+ fio_is_closed(FIO_LS_EMBD_OBJ(http_sse_internal_s, sse, sse)->uuid))
1362
1367
  return -1;
1363
1368
  return FIO_LS_EMBD_OBJ(http_sse_internal_s, sse, sse)->uuid;
1364
1369
  }
@@ -1368,7 +1373,7 @@ intptr_t http_sse2uuid(http_sse_s *sse) {
1368
1373
  */
1369
1374
  int http_sse_close(http_sse_s *sse) {
1370
1375
  if (!sse ||
1371
- sock_isclosed(FIO_LS_EMBD_OBJ(http_sse_internal_s, sse, sse)->uuid))
1376
+ fio_is_closed(FIO_LS_EMBD_OBJ(http_sse_internal_s, sse, sse)->uuid))
1372
1377
  return -1;
1373
1378
  return FIO_LS_EMBD_OBJ(http_sse_internal_s, sse, sse)
1374
1379
  ->vtable->http_sse_close(sse);
@@ -1380,7 +1385,7 @@ int http_sse_close(http_sse_s *sse) {
1380
1385
  * Returns the same object (increases a reference count, no allocation is made).
1381
1386
  */
1382
1387
  http_sse_s *http_sse_dup(http_sse_s *sse) {
1383
- spn_add(&FIO_LS_EMBD_OBJ(http_sse_internal_s, sse, sse)->ref, 1);
1388
+ fio_atomic_add(&FIO_LS_EMBD_OBJ(http_sse_internal_s, sse, sse)->ref, 1);
1384
1389
  return sse;
1385
1390
  }
1386
1391
 
@@ -1445,7 +1450,7 @@ void http_parse_query(http_s *h) {
1445
1450
  return;
1446
1451
  if (!h->params)
1447
1452
  h->params = fiobj_hash_new();
1448
- fio_cstr_s q = fiobj_obj2cstr(h->query);
1453
+ fio_str_info_s q = fiobj_obj2cstr(h->query);
1449
1454
  do {
1450
1455
  char *cut = memchr(q.data, '&', q.len);
1451
1456
  if (!cut)
@@ -1472,8 +1477,8 @@ static inline void http_parse_cookies_cookie_str(FIOBJ dest, FIOBJ str,
1472
1477
  uint8_t is_url_encoded) {
1473
1478
  if (!FIOBJ_TYPE_IS(str, FIOBJ_T_STRING))
1474
1479
  return;
1475
- fio_cstr_s s = fiobj_obj2cstr(str);
1476
- while (s.length) {
1480
+ fio_str_info_s s = fiobj_obj2cstr(str);
1481
+ while (s.len) {
1477
1482
  if (s.data[0] == ' ') {
1478
1483
  ++s.data;
1479
1484
  --s.len;
@@ -1487,10 +1492,10 @@ static inline void http_parse_cookies_cookie_str(FIOBJ dest, FIOBJ str,
1487
1492
  cut2 = s.data + s.len;
1488
1493
  http_add2hash(dest, s.data, cut - s.data, cut + 1, (cut2 - (cut + 1)),
1489
1494
  is_url_encoded);
1490
- if ((size_t)((cut2 + 1) - s.data) > s.length)
1491
- s.length = 0;
1495
+ if ((size_t)((cut2 + 1) - s.data) > s.len)
1496
+ s.len = 0;
1492
1497
  else
1493
- s.length -= ((cut2 + 1) - s.data);
1498
+ s.len -= ((cut2 + 1) - s.data);
1494
1499
  s.data = cut2 + 1;
1495
1500
  }
1496
1501
  }
@@ -1498,7 +1503,7 @@ static inline void http_parse_cookies_setcookie_str(FIOBJ dest, FIOBJ str,
1498
1503
  uint8_t is_url_encoded) {
1499
1504
  if (!FIOBJ_TYPE_IS(str, FIOBJ_T_STRING))
1500
1505
  return;
1501
- fio_cstr_s s = fiobj_obj2cstr(str);
1506
+ fio_str_info_s s = fiobj_obj2cstr(str);
1502
1507
  char *cut = memchr(s.data, '=', s.len);
1503
1508
  if (!cut)
1504
1509
  cut = s.data;
@@ -1566,10 +1571,10 @@ void http_parse_cookies(http_s *h, uint8_t is_url_encoded) {
1566
1571
  * * "name[][key]" references a nested Hash within an array. Hash keys will be
1567
1572
  * unique (repeating a key advances the hash).
1568
1573
  * * These rules can be nested (i.e. "name[][key1][][key2]...")
1569
- * * "name[][]" is an error (there's no way for the parser to analyse
1570
- * dimentions)
1574
+ * * "name[][]" is an error (there's no way for the parser to analyze
1575
+ * dimensions)
1571
1576
  *
1572
- * Note: names can't begine with "[" or end with "]" as these are reserved
1577
+ * Note: names can't begin with "[" or end with "]" as these are reserved
1573
1578
  * characters.
1574
1579
  */
1575
1580
  int http_add2hash2(FIOBJ dest, char *name, size_t name_len, FIOBJ val,
@@ -1755,10 +1760,10 @@ error:
1755
1760
  * * "name[][key]" references a nested Hash within an array. Hash keys will be
1756
1761
  * unique (repeating a key advances the hash).
1757
1762
  * * These rules can be nested (i.e. "name[][key1][][key2]...")
1758
- * * "name[][]" is an error (there's no way for the parser to analyse
1759
- * dimentions)
1763
+ * * "name[][]" is an error (there's no way for the parser to analyze
1764
+ * dimensions)
1760
1765
  *
1761
- * Note: names can't begine with "[" or end with "]" as these are reserved
1766
+ * Note: names can't begin with "[" or end with "]" as these are reserved
1762
1767
  * characters.
1763
1768
  */
1764
1769
  int http_add2hash(FIOBJ dest, char *name, size_t name_len, char *value,
@@ -1770,12 +1775,12 @@ int http_add2hash(FIOBJ dest, char *name, size_t name_len, char *value,
1770
1775
  /* *****************************************************************************
1771
1776
  HTTP Body Parsing
1772
1777
  ***************************************************************************** */
1773
- #include "http_mime_parser.h"
1778
+ #include <http_mime_parser.h>
1774
1779
 
1775
1780
  typedef struct {
1776
1781
  http_mime_parser_s p;
1777
1782
  http_s *h;
1778
- fio_cstr_s buffer;
1783
+ fio_str_info_s buffer;
1779
1784
  size_t pos;
1780
1785
  size_t partial_offset;
1781
1786
  size_t partial_length;
@@ -1797,7 +1802,7 @@ static void http_mime_parser_on_data(http_mime_parser_s *parser, void *name,
1797
1802
  }
1798
1803
  FIOBJ n = fiobj_str_new(name, name_len);
1799
1804
  fiobj_str_write(n, "[data]", 6);
1800
- fio_cstr_s tmp = fiobj_obj2cstr(n);
1805
+ fio_str_info_s tmp = fiobj_obj2cstr(n);
1801
1806
  http_add2hash(http_mime_parser2fio(parser)->h->params, tmp.data, tmp.len,
1802
1807
  value, value_len, 0);
1803
1808
  fiobj_str_resize(n, name_len);
@@ -1826,7 +1831,8 @@ static void http_mime_parser_on_partial_start(
1826
1831
  return;
1827
1832
 
1828
1833
  fiobj_str_write(http_mime_parser2fio(parser)->partial_name, "[type]", 6);
1829
- fio_cstr_s tmp = fiobj_obj2cstr(http_mime_parser2fio(parser)->partial_name);
1834
+ fio_str_info_s tmp =
1835
+ fiobj_obj2cstr(http_mime_parser2fio(parser)->partial_name);
1830
1836
  http_add2hash(http_mime_parser2fio(parser)->h->params, tmp.data, tmp.len,
1831
1837
  mimetype, mimetype_len, 0);
1832
1838
 
@@ -1855,7 +1861,8 @@ static void http_mime_parser_on_partial_data(http_mime_parser_s *parser,
1855
1861
  /** Called when the partial data is complete. */
1856
1862
  static void http_mime_parser_on_partial_end(http_mime_parser_s *parser) {
1857
1863
 
1858
- fio_cstr_s tmp = fiobj_obj2cstr(http_mime_parser2fio(parser)->partial_name);
1864
+ fio_str_info_s tmp =
1865
+ fiobj_obj2cstr(http_mime_parser2fio(parser)->partial_name);
1859
1866
  http_add2hash2(http_mime_parser2fio(parser)->h->params, tmp.data, tmp.len,
1860
1867
  fiobj_data_slice(http_mime_parser2fio(parser)->h->body,
1861
1868
  http_mime_parser2fio(parser)->partial_offset,
@@ -1892,7 +1899,7 @@ int http_parse_body(http_s *h) {
1892
1899
  if (!content_type_hash)
1893
1900
  content_type_hash = fio_siphash("content-type", 12);
1894
1901
  FIOBJ ct = fiobj_hash_get2(h->headers, content_type_hash);
1895
- fio_cstr_s content_type = fiobj_obj2cstr(ct);
1902
+ fio_str_info_s content_type = fiobj_obj2cstr(ct);
1896
1903
  if (content_type.len < 16)
1897
1904
  return -1;
1898
1905
  if (content_type.len >= 33 &&
@@ -1970,7 +1977,7 @@ FIOBJ http_req2str(http_s *h) {
1970
1977
  fiobj_str_join(w.dest, h->query);
1971
1978
  }
1972
1979
  {
1973
- fio_cstr_s t = fiobj_obj2cstr(h->version);
1980
+ fio_str_info_s t = fiobj_obj2cstr(h->version);
1974
1981
  if (t.len < 6 || t.data[5] != '1')
1975
1982
  fiobj_str_write(w.dest, " HTTP/1.1\r\n", 10);
1976
1983
  else {
@@ -1985,7 +1992,7 @@ FIOBJ http_req2str(http_s *h) {
1985
1992
  fiobj_str_write(w.dest, "\r\n", 2);
1986
1993
  if (h->body) {
1987
1994
  // fiobj_data_seek(h->body, 0);
1988
- // fio_cstr_s t = fiobj_data_read(h->body, 0);
1995
+ // fio_str_info_s t = fiobj_data_read(h->body, 0);
1989
1996
  // fiobj_str_write(w.dest, t.data, t.len);
1990
1997
  fiobj_str_join(w.dest, h->body);
1991
1998
  }
@@ -2000,23 +2007,15 @@ void http_write_log(http_s *h) {
2000
2007
 
2001
2008
  struct timespec start, end;
2002
2009
  clock_gettime(CLOCK_REALTIME, &end);
2003
- start = facil_last_tick();
2004
-
2005
- fio_cstr_s buff = fiobj_obj2cstr(l);
2006
-
2007
- // TODO Guess IP address from headers (forwarded) where possible
2008
- sock_peer_addr_s addrinfo =
2009
- sock_peer_addr(((http_protocol_s *)h->private_data.flag)->uuid);
2010
- if (addrinfo.addrlen) {
2011
- if (inet_ntop(
2012
- addrinfo.addr->sa_family,
2013
- addrinfo.addr->sa_family == AF_INET
2014
- ? (void *)&((struct sockaddr_in *)addrinfo.addr)->sin_addr
2015
- : (void *)&((struct sockaddr_in6 *)addrinfo.addr)->sin6_addr,
2016
- buff.data, 128)) {
2017
- buff.len = strlen(buff.data);
2018
- }
2010
+ start = fio_last_tick();
2011
+
2012
+ {
2013
+ // TODO Guess IP address from headers (forwarded) where possible
2014
+ fio_str_info_s peer = fio_peer_addr(http2protocol(h)->uuid);
2015
+ fiobj_str_write(l, peer.data, peer.len);
2019
2016
  }
2017
+ fio_str_info_s buff = fiobj_obj2cstr(l);
2018
+
2020
2019
  if (buff.len == 0) {
2021
2020
  memcpy(buff.data, "[unknown]", 9);
2022
2021
  buff.len = 9;
@@ -2026,9 +2025,9 @@ void http_write_log(http_s *h) {
2026
2025
  fiobj_str_resize(l, buff.len);
2027
2026
  {
2028
2027
  FIOBJ date;
2029
- spn_lock(&date_lock);
2028
+ fio_lock(&date_lock);
2030
2029
  date = fiobj_dup(current_date);
2031
- spn_unlock(&date_lock);
2030
+ fio_unlock(&date_lock);
2032
2031
  fiobj_str_join(l, current_date);
2033
2032
  fiobj_free(date);
2034
2033
  }
@@ -2319,15 +2318,15 @@ size_t http_date2rfc2109(char *target, struct tm *tmbuf) {
2319
2318
  /**
2320
2319
  * Prints Unix time to a HTTP time formatted string.
2321
2320
  *
2322
- * This variation implements chached results for faster processeing, at the
2321
+ * This variation implements cached results for faster processing, at the
2323
2322
  * price of a less accurate string.
2324
2323
  */
2325
2324
  size_t http_time2str(char *target, const time_t t) {
2326
2325
  /* pre-print time every 1 or 2 seconds or so. */
2327
2326
  static __thread time_t cached_tick;
2328
2327
  static __thread char cached_httpdate[48];
2329
- static __thread size_t chached_len;
2330
- time_t last_tick = facil_last_tick().tv_sec;
2328
+ static __thread size_t cached_len;
2329
+ time_t last_tick = fio_last_tick().tv_sec;
2331
2330
  if ((t | 7) < last_tick) {
2332
2331
  /* this is a custom time, not "now", pass through */
2333
2332
  struct tm tm;
@@ -2338,10 +2337,10 @@ size_t http_time2str(char *target, const time_t t) {
2338
2337
  struct tm tm;
2339
2338
  cached_tick = last_tick; /* refresh every second */
2340
2339
  http_gmtime(last_tick, &tm);
2341
- chached_len = http_date2str(cached_httpdate, &tm);
2340
+ cached_len = http_date2str(cached_httpdate, &tm);
2342
2341
  }
2343
- memcpy(target, cached_httpdate, chached_len);
2344
- return chached_len;
2342
+ memcpy(target, cached_httpdate, cached_len);
2343
+ return cached_len;
2345
2344
  }
2346
2345
 
2347
2346
  /* Credit to Jonathan Leffler for the idea of a unified conditional */
@@ -2450,11 +2449,192 @@ ssize_t http_decode_path_unsafe(char *dest, const char *url_data) {
2450
2449
  *pos = 0;
2451
2450
  return pos - dest;
2452
2451
  }
2452
+ /* *****************************************************************************
2453
+ HTTP URL parsing
2454
+ ***************************************************************************** */
2455
+
2456
+ /**
2457
+ * Parses the URI returning it's components and their lengths (no decoding
2458
+ * performed, doesn't accept decoded URIs).
2459
+ *
2460
+ * The returned string are NOT NUL terminated, they are merely locations within
2461
+ * the original string.
2462
+ *
2463
+ * This function expects any of the following formats:
2464
+ *
2465
+ * * `/complete_path?query#target`
2466
+ *
2467
+ * i.e.: /index.html?page=1#list
2468
+ *
2469
+ * * `host:port/complete_path?query#target`
2470
+ *
2471
+ * i.e.:
2472
+ * example.com/index.html
2473
+ * example.com:8080/index.html
2474
+ *
2475
+ * * `schema://user:password@host:port/path?query#target`
2476
+ *
2477
+ * i.e.: http://example.com/index.html?page=1#list
2478
+ *
2479
+ * Invalid formats might produce unexpected results. No error testing performed.
2480
+ */
2481
+ http_url_s http_url_parse(const char *url, size_t length) {
2482
+ const char *end = url + length;
2483
+ http_url_s result = {.scheme = {.data = (char *)url, .len = 0}};
2484
+ if (length == 0) {
2485
+ return result;
2486
+ }
2487
+ if (url[0] == '/') {
2488
+ result.scheme.data = NULL;
2489
+ goto parse_path;
2490
+ }
2491
+ /* test for scheme */
2492
+ while (url < end && *url != ':' && *url != '/' && *url != '@') {
2493
+ ++url;
2494
+ }
2495
+ result.scheme.len = url - result.scheme.data;
2496
+ if (url + 3 >= end || url[1] != '/' || url[2] != '/') { /* host only? */
2497
+ url = result.scheme.data;
2498
+ result.scheme = (fio_str_info_s){.data = NULL};
2499
+ goto after_scheme;
2500
+ }
2501
+
2502
+ url += 3;
2503
+
2504
+ after_scheme:
2505
+ result.user.data = (char *)url;
2506
+ while (url < end) {
2507
+ switch (*url) {
2508
+ case '/':
2509
+ /* no user name or password (or port) */
2510
+ result.host.data = result.user.data;
2511
+ result.user.data = NULL;
2512
+ result.host.len = url - result.host.data;
2513
+ goto parse_path;
2514
+ break;
2515
+ case '@':
2516
+ /* user name only, no password */
2517
+ result.user.len = url - result.user.data;
2518
+ ++url;
2519
+ goto parse_host;
2520
+ break;
2521
+ case ':':
2522
+ /* user name and password (or host:port...) */
2523
+ result.user.len = url - result.user.data;
2524
+ ++url;
2525
+ goto parse_password;
2526
+ break;
2527
+ default:
2528
+ ++url;
2529
+ break;
2530
+ }
2531
+ }
2532
+ if (url == end) { /* possibily: http://example.com */
2533
+ result.host.data = result.user.data;
2534
+ result.user.data = NULL;
2535
+ result.host.len = url - result.host.data;
2536
+ return result;
2537
+ }
2538
+
2539
+ parse_password:
2540
+ result.password.data = (char *)url;
2541
+ while (url < end) {
2542
+ switch (*url) {
2543
+ case '/':
2544
+ /* this wasn't a user:password, but host:port */
2545
+ result.host = result.user;
2546
+ result.port = result.password;
2547
+ result.port.len = url - result.port.data;
2548
+ result.user = result.password = (fio_str_info_s){.data = NULL};
2549
+ goto parse_path;
2550
+ break;
2551
+ case '@':
2552
+ /* done */
2553
+ result.password.len = url - result.password.data;
2554
+ ++url;
2555
+ goto after_pass;
2556
+ default:
2557
+ ++url;
2558
+ break;
2559
+ }
2560
+ }
2561
+ after_pass:
2562
+ if (url == end) { /* possibily: http://example.com:port */
2563
+ result.host = result.user;
2564
+ result.port = result.password;
2565
+ result.port.len = url - result.port.data;
2566
+ result.user = result.password = (fio_str_info_s){.data = NULL};
2567
+ return result;
2568
+ }
2569
+ parse_host:
2570
+ /* host:port parsing */
2571
+ result.host.data = (char *)url;
2572
+ while (url < end) {
2573
+ switch (*url) {
2574
+ case '/':
2575
+ /* host only */
2576
+ result.host.len = url - result.host.data;
2577
+ goto parse_path;
2578
+ break;
2579
+ case ':':
2580
+ /* done */
2581
+ result.host.len = url - result.host.data;
2582
+ ++url;
2583
+ goto after_host;
2584
+ break;
2585
+ default:
2586
+ ++url;
2587
+ break;
2588
+ }
2589
+ }
2590
+ after_host:
2591
+
2592
+ if (url == end) { /* scheme://host only? */
2593
+ result.host.len = end - result.host.data;
2594
+ return result;
2595
+ }
2596
+ result.port.data = (char *)url;
2597
+ while (url < end && *url != '/') {
2598
+ ++url;
2599
+ }
2600
+ result.port.len = url - result.port.data;
2601
+
2602
+ if (url == end) { /* scheme://host:port only? */
2603
+ return result;
2604
+ }
2605
+
2606
+ if (url == end) { /* scheme://host only? */
2607
+ return result;
2608
+ }
2609
+ /* path, query and target parsing */
2610
+ parse_path:
2611
+ result.path.data = (char *)url;
2612
+ while (url < end && *url != '?') {
2613
+ ++url;
2614
+ }
2615
+ result.path.len = url - result.path.data;
2616
+ if (url == end) {
2617
+ return result;
2618
+ }
2619
+ ++url;
2620
+ result.query.data = (char *)url;
2621
+ while (url < end && *url != '#') {
2622
+ ++url;
2623
+ }
2624
+ result.query.len = url - result.query.data;
2625
+ if (url == end) {
2626
+ return result;
2627
+ }
2628
+ ++url;
2629
+ result.target.data = (char *)url;
2630
+ result.target.len = end - result.target.data;
2631
+ return result;
2632
+ }
2453
2633
 
2454
2634
  /* *****************************************************************************
2455
2635
  Lookup Tables / functions
2456
2636
  ***************************************************************************** */
2457
- #include "fio_hashmap.h"
2637
+ #include <fio_hashmap.h>
2458
2638
 
2459
2639
  static fio_hash_s mime_types;
2460
2640
 
@@ -2497,11 +2677,11 @@ FIOBJ http_mimetype_find(char *file_ext, size_t file_ext_len) {
2497
2677
  */
2498
2678
  FIOBJ http_mimetype_find2(FIOBJ url) {
2499
2679
  static __thread char buffer[LONGEST_FILE_EXTENSION_LENGTH + 1];
2500
- fio_cstr_s ext = {.data = NULL};
2680
+ fio_str_info_s ext = {.data = NULL};
2501
2681
  FIOBJ mimetype;
2502
2682
  if (!url)
2503
2683
  goto finish;
2504
- fio_cstr_s tmp = fiobj_obj2cstr(url);
2684
+ fio_str_info_s tmp = fiobj_obj2cstr(url);
2505
2685
  uint8_t steps = 1;
2506
2686
  while (tmp.len > steps || steps >= LONGEST_FILE_EXTENSION_LENGTH) {
2507
2687
  switch (tmp.data[tmp.len - steps]) {
@@ -2584,12 +2764,12 @@ static char invalid_cookie_value_char[256] = {
2584
2764
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
2585
2765
 
2586
2766
  // clang-format off
2587
- #define HTTP_SET_STATUS_STR(status, str) [status-100] = { .buffer = (str), .length = (sizeof(str) - 1) }
2767
+ #define HTTP_SET_STATUS_STR(status, str) [status-100] = { .data = (str), .len = (sizeof(str) - 1) }
2588
2768
  // clang-format on
2589
2769
 
2590
2770
  /** Returns the status as a C string struct */
2591
- fio_cstr_s http_status2str(uintptr_t status) {
2592
- static const fio_cstr_s status2str[] = {
2771
+ fio_str_info_s http_status2str(uintptr_t status) {
2772
+ static const fio_str_info_s status2str[] = {
2593
2773
  HTTP_SET_STATUS_STR(100, "Continue"),
2594
2774
  HTTP_SET_STATUS_STR(101, "Switching Protocols"),
2595
2775
  HTTP_SET_STATUS_STR(102, "Processing"),
@@ -2655,13 +2835,25 @@ fio_cstr_s http_status2str(uintptr_t status) {
2655
2835
  HTTP_SET_STATUS_STR(510, "Not Extended"),
2656
2836
  HTTP_SET_STATUS_STR(511, "Network Authentication Required"),
2657
2837
  };
2658
- fio_cstr_s ret = (fio_cstr_s){.length = 0, .buffer = NULL};
2838
+ fio_str_info_s ret = (fio_str_info_s){.len = 0, .data = NULL};
2659
2839
  if (status >= 100 &&
2660
2840
  (status - 100) < sizeof(status2str) / sizeof(status2str[0]))
2661
2841
  ret = status2str[status - 100];
2662
- if (!ret.buffer) {
2842
+ if (!ret.data) {
2663
2843
  ret = status2str[400];
2664
2844
  }
2665
2845
  return ret;
2666
2846
  }
2667
2847
  #undef HTTP_SET_STATUS_STR
2848
+
2849
+ #if DEBUG
2850
+ void http_tests(void) {
2851
+ fprintf(stderr, "=== Testing HTTP helpers\n");
2852
+ #define TEST_ASSERT(cond, ...) \
2853
+ if (!(cond)) { \
2854
+ fprintf(stderr, "* " __VA_ARGS__); \
2855
+ fprintf(stderr, "Testing failed.\n"); \
2856
+ exit(-1); \
2857
+ }
2858
+ }
2859
+ #endif