iodine 0.7.16 → 0.7.17

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 (74) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +5 -4
  3. data/.yardopts +8 -0
  4. data/CHANGELOG.md +26 -0
  5. data/LICENSE.txt +1 -1
  6. data/LIMITS.md +6 -0
  7. data/README.md +93 -13
  8. data/{SPEC-Websocket-Draft.md → SPEC-WebSocket-Draft.md} +0 -0
  9. data/examples/tcp_client.rb +66 -0
  10. data/examples/x-sendfile.ru +14 -0
  11. data/exe/iodine +3 -3
  12. data/ext/iodine/extconf.rb +21 -0
  13. data/ext/iodine/fio.c +659 -69
  14. data/ext/iodine/fio.h +350 -95
  15. data/ext/iodine/fio_cli.c +4 -3
  16. data/ext/iodine/fio_json_parser.h +1 -1
  17. data/ext/iodine/fio_siphash.c +13 -11
  18. data/ext/iodine/fio_siphash.h +6 -3
  19. data/ext/iodine/fio_tls.h +129 -0
  20. data/ext/iodine/fio_tls_missing.c +634 -0
  21. data/ext/iodine/fio_tls_openssl.c +1011 -0
  22. data/ext/iodine/fio_tmpfile.h +1 -1
  23. data/ext/iodine/fiobj.h +1 -1
  24. data/ext/iodine/fiobj_ary.c +1 -1
  25. data/ext/iodine/fiobj_ary.h +1 -1
  26. data/ext/iodine/fiobj_data.c +1 -1
  27. data/ext/iodine/fiobj_data.h +1 -1
  28. data/ext/iodine/fiobj_hash.c +1 -1
  29. data/ext/iodine/fiobj_hash.h +1 -1
  30. data/ext/iodine/fiobj_json.c +18 -16
  31. data/ext/iodine/fiobj_json.h +1 -1
  32. data/ext/iodine/fiobj_mustache.c +4 -0
  33. data/ext/iodine/fiobj_mustache.h +4 -0
  34. data/ext/iodine/fiobj_numbers.c +1 -1
  35. data/ext/iodine/fiobj_numbers.h +1 -1
  36. data/ext/iodine/fiobj_str.c +3 -3
  37. data/ext/iodine/fiobj_str.h +1 -1
  38. data/ext/iodine/fiobject.c +1 -1
  39. data/ext/iodine/fiobject.h +8 -2
  40. data/ext/iodine/http.c +128 -337
  41. data/ext/iodine/http.h +11 -18
  42. data/ext/iodine/http1.c +6 -6
  43. data/ext/iodine/http1.h +1 -1
  44. data/ext/iodine/http1_parser.c +1 -1
  45. data/ext/iodine/http1_parser.h +1 -1
  46. data/ext/iodine/http_internal.c +10 -8
  47. data/ext/iodine/http_internal.h +13 -3
  48. data/ext/iodine/http_mime_parser.h +1 -1
  49. data/ext/iodine/iodine.c +806 -22
  50. data/ext/iodine/iodine.h +33 -0
  51. data/ext/iodine/iodine_connection.c +23 -18
  52. data/ext/iodine/iodine_http.c +239 -225
  53. data/ext/iodine/iodine_http.h +4 -1
  54. data/ext/iodine/iodine_mustache.c +59 -54
  55. data/ext/iodine/iodine_pubsub.c +1 -1
  56. data/ext/iodine/iodine_tcp.c +34 -100
  57. data/ext/iodine/iodine_tcp.h +4 -0
  58. data/ext/iodine/iodine_tls.c +267 -0
  59. data/ext/iodine/iodine_tls.h +13 -0
  60. data/ext/iodine/mustache_parser.h +1 -1
  61. data/ext/iodine/redis_engine.c +14 -6
  62. data/ext/iodine/redis_engine.h +1 -1
  63. data/ext/iodine/resp_parser.h +1 -1
  64. data/ext/iodine/websocket_parser.h +1 -1
  65. data/ext/iodine/websockets.c +1 -1
  66. data/ext/iodine/websockets.h +1 -1
  67. data/iodine.gemspec +2 -1
  68. data/lib/iodine.rb +19 -5
  69. data/lib/iodine/connection.rb +13 -0
  70. data/lib/iodine/mustache.rb +7 -24
  71. data/lib/iodine/tls.rb +16 -0
  72. data/lib/iodine/version.rb +1 -1
  73. data/lib/rack/handler/iodine.rb +1 -1
  74. metadata +15 -5
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright: Boaz Segev, 2018
2
+ Copyright: Boaz Segev, 2018-2019
3
3
  License: MIT
4
4
  */
5
5
  #ifndef H_FIO_TMPFILE_H
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright: Boaz Segev, 2017-2018
2
+ Copyright: Boaz Segev, 2017-2019
3
3
  License: MIT
4
4
  */
5
5
  #ifndef H_FIOBJ_H
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright: Boaz Segev, 2017-2018
2
+ Copyright: Boaz Segev, 2017-2019
3
3
  License: MIT
4
4
  */
5
5
  #include <fio.h>
@@ -1,6 +1,6 @@
1
1
  #ifndef FIOBJ_ARRAY_H
2
2
  /*
3
- Copyright: Boaz Segev, 2017-2018
3
+ Copyright: Boaz Segev, 2017-2019
4
4
  License: MIT
5
5
  */
6
6
 
@@ -1,7 +1,7 @@
1
1
  #if defined(__unix__) || defined(__APPLE__) || defined(__linux__) || \
2
2
  defined(__CYGWIN__) /* require POSIX */
3
3
  /*
4
- Copyright: Boaz Segev, 2017-2018
4
+ Copyright: Boaz Segev, 2017-2019
5
5
  License: MIT
6
6
  */
7
7
  #ifndef _GNU_SOURCE
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright: Boaz Segev, 2017-2018
2
+ Copyright: Boaz Segev, 2017-2019
3
3
  License: MIT
4
4
  */
5
5
  #if !defined(H_FIOBJ_IO_H) && (defined(__unix__) || defined(__APPLE__) || \
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright: Boaz Segev, 2017-2018
2
+ Copyright: Boaz Segev, 2017-2019
3
3
  License: MIT
4
4
  */
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright: Boaz Segev, 2017-2018
2
+ Copyright: Boaz Segev, 2017-2019
3
3
  License: MIT
4
4
  */
5
5
  #ifndef H_FIOBJ_HASH_H
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright: Boaz Segev, 2017-2018
2
+ Copyright: Boaz Segev, 2017-2019
3
3
  License: MIT
4
4
  */
5
5
  #include <fiobj_json.h>
@@ -511,7 +511,7 @@ void fiobj_test_json(void) {
511
511
  TEST_ASSERT(o, "JSON object missing!\n");
512
512
  TEST_ASSERT(FIOBJ_TYPE_IS(o, FIOBJ_T_HASH),
513
513
  "JSON root not a dictionary (not a hash)!\n");
514
- FIOBJ tmp = fiobj_hash_get2(o, fio_siphash("array", 5));
514
+ FIOBJ tmp = fiobj_hash_get2(o, fiobj_hash_string("array", 5));
515
515
  TEST_ASSERT(FIOBJ_TYPE_IS(tmp, FIOBJ_T_ARRAY),
516
516
  "JSON 'array' not an Array!\n");
517
517
  TEST_ASSERT(fiobj_obj2num(fiobj_ary_index(tmp, 0)) == 1,
@@ -524,24 +524,26 @@ void fiobj_test_json(void) {
524
524
  "JSON 'array' index 3 type error!\n");
525
525
  TEST_ASSERT(!memcmp("boom", fiobj_obj2cstr(fiobj_ary_index(tmp, 3)).data, 4),
526
526
  "JSON 'array' index 3 error!\n");
527
- tmp = fiobj_hash_get2(o, fio_siphash("my", 2));
527
+ tmp = fiobj_hash_get2(o, fiobj_hash_string("my", 2));
528
528
  TEST_ASSERT(FIOBJ_TYPE_IS(tmp, FIOBJ_T_HASH),
529
529
  "JSON 'my:secret' not a Hash!\n");
530
- TEST_ASSERT(FIOBJ_TYPE_IS(fiobj_hash_get2(tmp, fio_siphash("secret", 6)),
531
- FIOBJ_T_NUMBER),
532
- "JSON 'my:secret' doesn't hold a number!\n");
533
- TEST_ASSERT(fiobj_obj2num(fiobj_hash_get2(tmp, fio_siphash("secret", 6))) ==
534
- 42,
535
- "JSON 'my:secret' not 42!\n");
536
- TEST_ASSERT(fiobj_hash_get2(o, fio_siphash("true", 4)) == fiobj_true(),
530
+ TEST_ASSERT(
531
+ FIOBJ_TYPE_IS(fiobj_hash_get2(tmp, fiobj_hash_string("secret", 6)),
532
+ FIOBJ_T_NUMBER),
533
+ "JSON 'my:secret' doesn't hold a number!\n");
534
+ TEST_ASSERT(
535
+ fiobj_obj2num(fiobj_hash_get2(tmp, fiobj_hash_string("secret", 6))) == 42,
536
+ "JSON 'my:secret' not 42!\n");
537
+ TEST_ASSERT(fiobj_hash_get2(o, fiobj_hash_string("true", 4)) == fiobj_true(),
537
538
  "JSON 'true' not true!\n");
538
- TEST_ASSERT(fiobj_hash_get2(o, fio_siphash("false", 5)) == fiobj_false(),
539
+ TEST_ASSERT(fiobj_hash_get2(o, fiobj_hash_string("false", 5)) ==
540
+ fiobj_false(),
539
541
  "JSON 'false' not false!\n");
540
- TEST_ASSERT(fiobj_hash_get2(o, fio_siphash("null", 4)) == fiobj_null(),
542
+ TEST_ASSERT(fiobj_hash_get2(o, fiobj_hash_string("null", 4)) == fiobj_null(),
541
543
  "JSON 'null' not null!\n");
542
- tmp = fiobj_hash_get2(o, fio_siphash("float", 5));
544
+ tmp = fiobj_hash_get2(o, fiobj_hash_string("float", 5));
543
545
  TEST_ASSERT(FIOBJ_TYPE_IS(tmp, FIOBJ_T_FLOAT), "JSON 'float' not a float!\n");
544
- tmp = fiobj_hash_get2(o, fio_siphash("string", 6));
546
+ tmp = fiobj_hash_get2(o, fiobj_hash_string("string", 6));
545
547
  TEST_ASSERT(FIOBJ_TYPE_IS(tmp, FIOBJ_T_STRING),
546
548
  "JSON 'string' not a string!\n");
547
549
  TEST_ASSERT(!strcmp(fiobj_obj2cstr(tmp).data, "I \"wrote\" this."),
@@ -558,11 +560,11 @@ void fiobj_test_json(void) {
558
560
  "JSON update failed to parse data.");
559
561
  fiobj_free(tmp);
560
562
 
561
- tmp = fiobj_hash_get2(o, fio_siphash("array", 5));
563
+ tmp = fiobj_hash_get2(o, fiobj_hash_string("array", 5));
562
564
  TEST_ASSERT(FIOBJ_TYPE_IS(tmp, FIOBJ_T_ARRAY),
563
565
  "JSON updated 'array' not an Array!\n");
564
566
  TEST_ASSERT(fiobj_ary_count(tmp) == 3, "JSON updated 'array' not updated?");
565
- tmp = fiobj_hash_get2(o, fio_siphash("float", 5));
567
+ tmp = fiobj_hash_get2(o, fiobj_hash_string("float", 5));
566
568
  TEST_ASSERT(FIOBJ_TYPE_IS(tmp, FIOBJ_T_FLOAT),
567
569
  "JSON updated (old) 'float' missing!\n");
568
570
  fiobj_free(o);
@@ -2,7 +2,7 @@
2
2
  #define H_FIOBJ_JSON_H
3
3
 
4
4
  /*
5
- Copyright: Boaz Segev, 2017-2018
5
+ Copyright: Boaz Segev, 2017-2019
6
6
  License: MIT
7
7
  */
8
8
 
@@ -1,3 +1,7 @@
1
+ /*
2
+ Copyright: Boaz Segev, 2018-2019
3
+ License: MIT
4
+ */
1
5
  #define INCLUDE_MUSTACHE_IMPLEMENTATION 1
2
6
  #include <mustache_parser.h>
3
7
 
@@ -1,3 +1,7 @@
1
+ /*
2
+ Copyright: Boaz Segev, 2018-2019
3
+ License: MIT
4
+ */
1
5
  #ifndef H_FIOBJ_MUSTACHE_H
2
6
  #define H_FIOBJ_MUSTACHE_H
3
7
 
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright: Boaz Segev, 2017-2018
2
+ Copyright: Boaz Segev, 2017-2019
3
3
  License: MIT
4
4
  */
5
5
 
@@ -1,7 +1,7 @@
1
1
  #ifndef H_FIOBJ_NUMBERS_H
2
2
  #define H_FIOBJ_NUMBERS_H
3
3
  /*
4
- Copyright: Boaz Segev, 2017-2018
4
+ Copyright: Boaz Segev, 2017-2019
5
5
  License: MIT
6
6
  */
7
7
 
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright: Boaz Segev, 2017-2018
2
+ Copyright: Boaz Segev, 2017-2019
3
3
  License: MIT
4
4
  */
5
5
 
@@ -324,13 +324,13 @@ size_t fiobj_str_concat(FIOBJ dest, FIOBJ obj) {
324
324
  uint64_t fiobj_str_hash(FIOBJ o) {
325
325
  assert(FIOBJ_TYPE_IS(o, FIOBJ_T_STRING));
326
326
  // if (obj2str(o)->is_small) {
327
- // return fio_siphash(STR_INTENAL_STR(o), STR_INTENAL_LEN(o));
327
+ // return fiobj_hash_string(STR_INTENAL_STR(o), STR_INTENAL_LEN(o));
328
328
  // } else
329
329
  if (obj2str(o)->hash) {
330
330
  return obj2str(o)->hash;
331
331
  }
332
332
  fio_str_info_s state = fio_str_info(&obj2str(o)->str);
333
- obj2str(o)->hash = fio_siphash(state.data, state.len);
333
+ obj2str(o)->hash = fiobj_hash_string(state.data, state.len);
334
334
  return obj2str(o)->hash;
335
335
  }
336
336
 
@@ -1,6 +1,6 @@
1
1
  #ifndef H_FIOBJ_STR_H
2
2
  /*
3
- Copyright: Boaz Segev, 2017-2018
3
+ Copyright: Boaz Segev, 2017-2019
4
4
  License: MIT
5
5
  */
6
6
  #define H_FIOBJ_STR_H
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright: Boaz Segev, 2017-2018
2
+ Copyright: Boaz Segev, 2017-2019
3
3
  License: MIT
4
4
  */
5
5
 
@@ -1,6 +1,6 @@
1
1
  #ifndef H_FIOBJECT_H
2
2
  /*
3
- Copyright: Boaz Segev, 2017-2018
3
+ Copyright: Boaz Segev, 2017-2019
4
4
  License: MIT
5
5
  */
6
6
 
@@ -27,6 +27,8 @@ types, abstracting some complexity and making dynamic type related tasks easier.
27
27
 
28
28
  #include <fio_siphash.h>
29
29
 
30
+ #include <fio.h>
31
+
30
32
  #if !defined(__GNUC__) && !defined(__clang__) && !defined(FIO_GNUC_BYPASS)
31
33
  #define __attribute__(...)
32
34
  #define __has_include(...) 0
@@ -552,7 +554,11 @@ FIO_INLINE uint64_t fiobj_obj2hash(const FIOBJ o) {
552
554
  if (!FIOBJ_IS_ALLOCATED(o))
553
555
  return (uint64_t)o;
554
556
  fio_str_info_s s = fiobj_obj2cstr(o);
555
- return fio_siphash(s.data, s.len);
557
+ return FIO_HASH_FN(s.data, s.len, &fiobj_each2, &fiobj_free_complex_object);
558
+ }
559
+
560
+ FIO_INLINE uint64_t fiobj_hash_string(const void *data, size_t len) {
561
+ return FIO_HASH_FN(data, len, &fiobj_each2, &fiobj_free_complex_object);
556
562
  }
557
563
 
558
564
  /**
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright: Boaz Segev, 2016-2018
2
+ Copyright: Boaz Segev, 2016-2019
3
3
  License: MIT
4
4
 
5
5
  Feel free to copy, use and enjoy according to the license provided.
@@ -28,42 +28,19 @@ SSL/TLS patch
28
28
  * The first protocol added will act as the default protocol to be selected.
29
29
  */
30
30
  void __attribute__((weak))
31
- fio_tls_proto_add(void *tls, const char *protocol_name,
32
- void (*callback)(intptr_t uuid, void *udata)) {
31
+ fio_tls_alpn_add(void *tls, const char *protocol_name,
32
+ void (*callback)(intptr_t uuid, void *udata_connection,
33
+ void *udata_tls),
34
+ void *udata_tls, void (*on_cleanup)(void *udata_tls)) {
33
35
  FIO_LOG_FATAL("HTTP SSL/TLS required but unavailable!");
34
36
  exit(-1);
35
37
  (void)tls;
36
38
  (void)protocol_name;
37
39
  (void)callback;
40
+ (void)on_cleanup;
41
+ (void)udata_tls;
38
42
  }
39
- #pragma weak fio_tls_proto_add
40
-
41
- void __attribute__((weak))
42
- fio_tls_accept(intptr_t uuid, void *tls, void *udata) {
43
- FIO_LOG_FATAL("HTTP SSL/TLS required but unavailable!");
44
- exit(-1);
45
- (void)uuid;
46
- (void)tls;
47
- (void)udata;
48
- }
49
- #pragma weak fio_tls_accept
50
-
51
- /**
52
- * Establishes an SSL/TLS connection as an SSL/TLS Server, using the specified
53
- * conetext / settings object.
54
- *
55
- * The `uuid` should be a socket UUID that is already connected to a peer (i.e.,
56
- * the result of `fio_accept`).
57
- */
58
- void __attribute__((weak))
59
- fio_tls_connect(intptr_t uuid, void *tls, void *udata) {
60
- FIO_LOG_FATAL("HTTP SSL/TLS required but unavailable!");
61
- exit(-1);
62
- (void)uuid;
63
- (void)tls;
64
- (void)udata;
65
- }
66
- #pragma weak fio_tls_connect
43
+ #pragma weak fio_tls_alpn_add
67
44
 
68
45
  /* *****************************************************************************
69
46
  Small Helpers
@@ -73,7 +50,7 @@ static inline int hex2byte(uint8_t *dest, const uint8_t *source);
73
50
  static inline void add_content_length(http_s *r, uintptr_t length) {
74
51
  static uint64_t cl_hash = 0;
75
52
  if (!cl_hash)
76
- cl_hash = fio_siphash("content-length", 14);
53
+ cl_hash = fiobj_hash_string("content-length", 14);
77
54
  if (!fiobj_hash_get2(r->private_data.out_headers, cl_hash)) {
78
55
  fiobj_hash_set(r->private_data.out_headers, HTTP_HEADER_CONTENT_LENGTH,
79
56
  fiobj_num_new(length));
@@ -82,7 +59,7 @@ static inline void add_content_length(http_s *r, uintptr_t length) {
82
59
  static inline void add_content_type(http_s *r) {
83
60
  static uint64_t ct_hash = 0;
84
61
  if (!ct_hash)
85
- ct_hash = fio_siphash("content-type", 12);
62
+ ct_hash = fiobj_hash_string("content-type", 12);
86
63
  if (!fiobj_hash_get2(r->private_data.out_headers, ct_hash)) {
87
64
  fiobj_hash_set(r->private_data.out_headers, HTTP_HEADER_CONTENT_TYPE,
88
65
  http_mimetype_find2(r->path));
@@ -95,10 +72,10 @@ static fio_lock_i date_lock;
95
72
  static inline void add_date(http_s *r) {
96
73
  static uint64_t date_hash = 0;
97
74
  if (!date_hash)
98
- date_hash = fio_siphash("date", 4);
75
+ date_hash = fiobj_hash_string("date", 4);
99
76
  static uint64_t mod_hash = 0;
100
77
  if (!mod_hash)
101
- mod_hash = fio_siphash("last-modified", 13);
78
+ mod_hash = fiobj_hash_string("last-modified", 13);
102
79
 
103
80
  if (fio_last_tick().tv_sec > last_date_added) {
104
81
  fio_lock(&date_lock);
@@ -312,13 +289,23 @@ int http_set_cookie(http_s *h, http_cookie_args_s cookie) {
312
289
  }
313
290
  } else
314
291
  cookie.max_age = -1;
292
+
293
+ if (http_settings(h) && http_settings(h)->is_client) {
294
+ if (!cookie.value) {
295
+ fiobj_free(c);
296
+ return -1;
297
+ }
298
+ set_header_add(h->private_data.out_headers, HTTP_HEADER_COOKIE, c);
299
+ return 0;
300
+ }
301
+
315
302
  t.data[len++] = ';';
316
303
  t.data[len++] = ' ';
317
304
 
318
305
  if (h->status_str || !h->status) { /* on first request status == 0 */
319
306
  static uint64_t cookie_hash;
320
307
  if (!cookie_hash)
321
- cookie_hash = fio_siphash("cookie", 6);
308
+ cookie_hash = fiobj_hash_string("cookie", 6);
322
309
  FIOBJ tmp = fiobj_hash_get2(h->private_data.out_headers, cookie_hash);
323
310
  if (!tmp) {
324
311
  set_header_add(h->private_data.out_headers, HTTP_HEADER_COOKIE, c);
@@ -419,10 +406,10 @@ int http_sendfile2(http_s *h, const char *prefix, size_t prefix_len,
419
406
  struct stat file_data = {.st_size = 0};
420
407
  static uint64_t accept_enc_hash = 0;
421
408
  if (!accept_enc_hash)
422
- accept_enc_hash = fio_siphash("accept-encoding", 15);
409
+ accept_enc_hash = fiobj_hash_string("accept-encoding", 15);
423
410
  static uint64_t range_hash = 0;
424
411
  if (!range_hash)
425
- range_hash = fio_siphash("range", 5);
412
+ range_hash = fiobj_hash_string("range", 5);
426
413
 
427
414
  /* create filename string */
428
415
  FIOBJ filename = fiobj_str_tmp();
@@ -503,7 +490,7 @@ found_file:
503
490
  /* set & test etag */
504
491
  uint64_t etag = (uint64_t)file_data.st_size;
505
492
  etag ^= (uint64_t)file_data.st_mtime;
506
- etag = fio_siphash(&etag, sizeof(uint64_t));
493
+ etag = fiobj_hash_string(&etag, sizeof(uint64_t));
507
494
  FIOBJ etag_str = fiobj_str_buf(32);
508
495
  fiobj_str_resize(etag_str,
509
496
  fio_base64_encode(fiobj_obj2cstr(etag_str).data,
@@ -514,7 +501,7 @@ found_file:
514
501
  {
515
502
  static uint64_t none_match_hash = 0;
516
503
  if (!none_match_hash)
517
- none_match_hash = fio_siphash("if-none-match", 13);
504
+ none_match_hash = fiobj_hash_string("if-none-match", 13);
518
505
  FIOBJ tmp2 = fiobj_hash_get2(h->headers, none_match_hash);
519
506
  if (tmp2 && fiobj_iseq(tmp2, etag_str)) {
520
507
  h->status = 304;
@@ -528,7 +515,7 @@ found_file:
528
515
  {
529
516
  static uint64_t ifrange_hash = 0;
530
517
  if (!ifrange_hash)
531
- ifrange_hash = fio_siphash("if-range", 8);
518
+ ifrange_hash = fiobj_hash_string("if-range", 8);
532
519
  FIOBJ tmp = fiobj_hash_get2(h->headers, ifrange_hash);
533
520
  if (tmp && fiobj_iseq(tmp, etag_str)) {
534
521
  fiobj_hash_delete2(h->headers, range_hash);
@@ -907,28 +894,28 @@ static void http_settings_free(http_settings_s *s) {
907
894
  Listening to HTTP connections
908
895
  ***************************************************************************** */
909
896
 
910
- static void http_on_server_protocol_http1(intptr_t uuid, void *set) {
911
- fio_protocol_s *pr = http1_new(uuid, set, NULL, 0);
912
- if (!pr)
913
- fio_close(uuid);
914
- }
897
+ static uint8_t fio_http_at_capa = 0;
915
898
 
916
- static void http_on_open(intptr_t uuid, void *set) {
917
- static uint8_t at_capa;
899
+ static void http_on_server_protocol_http1(intptr_t uuid, void *set,
900
+ void *ignr_) {
918
901
  fio_timeout_set(uuid, ((http_settings_s *)set)->timeout);
919
902
  if (fio_uuid2fd(uuid) >= ((http_settings_s *)set)->max_clients) {
920
- if (!at_capa)
903
+ if (!fio_http_at_capa)
921
904
  FIO_LOG_WARNING("HTTP server at capacity");
922
- at_capa = 1;
905
+ fio_http_at_capa = 1;
923
906
  http_send_error2(uuid, 503, set);
924
907
  fio_close(uuid);
925
908
  return;
926
909
  }
927
- at_capa = 0;
928
- if (((http_settings_s *)set)->tls)
929
- fio_tls_accept(uuid, ((http_settings_s *)set)->tls, set);
930
- else
931
- http_on_server_protocol_http1(uuid, set);
910
+ fio_http_at_capa = 0;
911
+ fio_protocol_s *pr = http1_new(uuid, set, NULL, 0);
912
+ if (!pr)
913
+ fio_close(uuid);
914
+ (void)ignr_;
915
+ }
916
+
917
+ static void http_on_open(intptr_t uuid, void *set) {
918
+ http_on_server_protocol_http1(uuid, set, NULL);
932
919
  }
933
920
 
934
921
  static void http_on_finish(intptr_t uuid, void *set) {
@@ -961,10 +948,11 @@ intptr_t http_listen(const char *port, const char *binding,
961
948
  http_settings_s *settings = http_settings_new(arg_settings);
962
949
  settings->is_client = 0;
963
950
  if (settings->tls) {
964
- fio_tls_proto_add(settings->tls, "http/1.1", http_on_server_protocol_http1);
951
+ fio_tls_alpn_add(settings->tls, "http/1.1", http_on_server_protocol_http1,
952
+ NULL, NULL);
965
953
  }
966
954
 
967
- return fio_listen(.port = port, .address = binding,
955
+ return fio_listen(.port = port, .address = binding, .tls = arg_settings.tls,
968
956
  .on_finish = http_on_finish, .on_open = http_on_open,
969
957
  .udata = settings);
970
958
  }
@@ -1008,9 +996,11 @@ static void http_on_open_client_perform(http_settings_s *set) {
1008
996
  http_s *h = set->udata;
1009
997
  set->on_response(h);
1010
998
  }
1011
- static void http_on_open_client_http1(intptr_t uuid, void *set_) {
999
+ static void http_on_open_client_http1(intptr_t uuid, void *set_,
1000
+ void *ignore_) {
1012
1001
  http_settings_s *set = set_;
1013
1002
  http_s *h = set->udata;
1003
+ fio_timeout_set(uuid, set->timeout);
1014
1004
  fio_protocol_s *pr = http1_new(uuid, set, NULL, 0);
1015
1005
  if (!pr) {
1016
1006
  fio_close(uuid);
@@ -1025,15 +1015,11 @@ static void http_on_open_client_http1(intptr_t uuid, void *set_) {
1025
1015
  h->private_data.flag = (uintptr_t)pr;
1026
1016
  h->private_data.vtbl = http1_vtable();
1027
1017
  http_on_open_client_perform(set);
1018
+ (void)ignore_;
1028
1019
  }
1029
1020
 
1030
1021
  static void http_on_open_client(intptr_t uuid, void *set_) {
1031
- http_settings_s *set = set_;
1032
- fio_timeout_set(uuid, set->timeout);
1033
- if (set->tls)
1034
- fio_tls_connect(uuid, set->tls, set_);
1035
- else
1036
- http_on_open_client_http1(uuid, set);
1022
+ http_on_open_client_http1(uuid, set_, NULL);
1037
1023
  }
1038
1024
 
1039
1025
  static void http_on_client_failed(intptr_t uuid, void *set_) {
@@ -1048,6 +1034,7 @@ static void http_on_client_failed(intptr_t uuid, void *set_) {
1048
1034
  (void)uuid;
1049
1035
  }
1050
1036
 
1037
+ intptr_t http_connect__(void); /* sublime text marker */
1051
1038
  /**
1052
1039
  * Connects to an HTTP server as a client.
1053
1040
  *
@@ -1062,9 +1049,9 @@ static void http_on_client_failed(intptr_t uuid, void *set_) {
1062
1049
  * Returns -1 on error and 0 on success. the `on_finish` callback is always
1063
1050
  * called.
1064
1051
  */
1065
- #undef http_connect
1066
- intptr_t http_connect(const char *address,
1067
- struct http_settings_s arg_settings) {
1052
+ intptr_t http_connect FIO_IGNORE_MACRO(const char *url,
1053
+ const char *unix_address,
1054
+ struct http_settings_s arg_settings) {
1068
1055
  if (!arg_settings.on_response && !arg_settings.on_upgrade) {
1069
1056
  FIO_LOG_ERROR("http_connect requires either an on_response "
1070
1057
  " or an on_upgrade callback.\n");
@@ -1072,71 +1059,69 @@ intptr_t http_connect(const char *address,
1072
1059
  goto on_error;
1073
1060
  }
1074
1061
  size_t len;
1075
- char *a, *p;
1062
+ char *a = NULL, *p = NULL;
1076
1063
  uint8_t is_websocket = 0;
1077
1064
  uint8_t is_secure = 0;
1078
1065
  FIOBJ path = FIOBJ_INVALID;
1079
- if (!address || (len = strlen(address)) <= 5) {
1066
+ if (!url && !unix_address) {
1080
1067
  FIO_LOG_ERROR("http_connect requires a valid address.");
1081
1068
  errno = EINVAL;
1082
1069
  goto on_error;
1083
1070
  }
1084
- // TODO: use http_url_parse
1085
- if (!strncasecmp(address, "ws", 2)) {
1086
- is_websocket = 1;
1087
- address += 2;
1088
- len -= 2;
1089
- } else if (len >= 7 && !strncasecmp(address, "http", 4)) {
1090
- address += 4;
1091
- len -= 4;
1092
- } else {
1093
- FIO_LOG_ERROR("http_connect requires a valid address.");
1094
- errno = EINVAL;
1095
- goto on_error;
1096
- }
1097
- /* parse address */
1098
- if (address[0] == 's') {
1099
- /* TODO: SSL/TLS */
1100
- is_secure = 1;
1101
- FIO_LOG_ERROR("http_connect doesn't support TLS/SSL just yet.");
1102
- errno = EINVAL;
1103
- goto on_error;
1104
- } else if (len <= 3 || strncmp(address, "://", 3)) {
1105
- FIO_LOG_ERROR("http_connect requires a valid address.");
1106
- errno = EINVAL;
1107
- goto on_error;
1108
- } else {
1109
- len -= 3;
1110
- address += 3;
1111
- a = fio_malloc(len + 1);
1112
- FIO_ASSERT_ALLOC(a);
1113
- memcpy(a, address, len + 1);
1114
- }
1115
- p = memchr(a, '/', len);
1116
- if (p) {
1117
- if (len - (p - a))
1118
- path = fiobj_str_new(p, len - (p - a));
1119
- len = p - a;
1120
- *p = 0;
1121
- }
1122
- p = memchr(a, ':', len);
1123
- if (p) {
1124
- len = p - a;
1125
- *p = 0;
1126
- if (a + len == p + 1) {
1127
- p = NULL;
1071
+ if (url) {
1072
+ fio_url_s u = fio_url_parse(url, strlen(url));
1073
+ if (u.scheme.data &&
1074
+ (u.scheme.len == 2 || (u.scheme.len == 3 && u.scheme.data[2] == 's')) &&
1075
+ u.scheme.data[0] == 'w' && u.scheme.data[1] == 's') {
1076
+ is_websocket = 1;
1077
+ is_secure = (u.scheme.len == 3);
1078
+ } else if (u.scheme.data &&
1079
+ (u.scheme.len == 4 ||
1080
+ (u.scheme.len == 5 && u.scheme.data[4] == 's')) &&
1081
+ u.scheme.data[0] == 'h' && u.scheme.data[1] == 't' &&
1082
+ u.scheme.data[2] == 't' && u.scheme.data[3] == 'p') {
1083
+ is_secure = (u.scheme.len == 5);
1084
+ }
1085
+ if (is_secure && !arg_settings.tls) {
1086
+ FIO_LOG_ERROR("Secure connections (%.*s) require a TLS object.",
1087
+ (int)u.scheme.len, u.scheme.data);
1088
+ errno = EINVAL;
1089
+ goto on_error;
1090
+ }
1091
+ if (u.path.data) {
1092
+ path = fiobj_str_new(
1093
+ u.path.data, strlen(u.path.data)); /* copy query and target as well */
1094
+ }
1095
+ if (unix_address) {
1096
+ a = (char *)unix_address;
1097
+ len = strlen(a);
1128
1098
  } else {
1129
- p++;
1130
- if (!len) {
1131
- a = (char *)"localhost";
1132
- len = 9;
1099
+ if (!u.host.data) {
1100
+ FIO_LOG_ERROR("http_connect requires a valid address.");
1101
+ errno = EINVAL;
1102
+ goto on_error;
1103
+ }
1104
+ /***** no more error handling, since memory is allocated *****/
1105
+ /* copy address */
1106
+ a = fio_malloc(u.host.len + 1);
1107
+ memcpy(a, u.host.data, u.host.len);
1108
+ a[u.host.len] = 0;
1109
+ len = u.host.len;
1110
+ /* copy port */
1111
+ if (u.port.data) {
1112
+ p = fio_malloc(u.port.len + 1);
1113
+ memcpy(p, u.port.data, u.port.len);
1114
+ p[u.port.len] = 0;
1115
+ } else if (is_secure) {
1116
+ p = fio_malloc(3 + 1);
1117
+ memcpy(p, "443", 3);
1118
+ p[3] = 0;
1119
+ } else {
1120
+ p = fio_malloc(2 + 1);
1121
+ memcpy(p, "80", 2);
1122
+ p[2] = 0;
1133
1123
  }
1134
1124
  }
1135
- } else {
1136
- if (is_secure)
1137
- p = (char *)"443";
1138
- else
1139
- p = (char *)"80";
1140
1125
  }
1141
1126
 
1142
1127
  /* set settings */
@@ -1144,9 +1129,10 @@ intptr_t http_connect(const char *address,
1144
1129
  arg_settings.timeout = 30;
1145
1130
  http_settings_s *settings = http_settings_new(arg_settings);
1146
1131
  settings->is_client = 1;
1147
- if (settings->tls) {
1148
- fio_tls_proto_add(settings->tls, "http/1.1", http_on_open_client_http1);
1149
- }
1132
+ // if (settings->tls) {
1133
+ // fio_tls_alpn_add(settings->tls, "http/1.1", http_on_open_client_http1,
1134
+ // NULL, NULL);
1135
+ // }
1150
1136
 
1151
1137
  if (!arg_settings.ws_timeout)
1152
1138
  settings->ws_timeout = 0; /* allow server to dictate timeout */
@@ -1159,29 +1145,32 @@ intptr_t http_connect(const char *address,
1159
1145
  h->status = 0;
1160
1146
  h->path = path;
1161
1147
  settings->udata = h;
1148
+ settings->tls = arg_settings.tls;
1162
1149
  http_set_header2(h, (fio_str_info_s){.data = (char *)"host", .len = 4},
1163
1150
  (fio_str_info_s){.data = a, .len = len});
1164
1151
  intptr_t ret;
1165
1152
  if (is_websocket) {
1166
1153
  /* force HTTP/1.1 */
1167
1154
  ret = fio_connect(.address = a, .port = p, .on_fail = http_on_client_failed,
1168
- .on_connect = http_on_open_client, .udata = settings);
1155
+ .on_connect = http_on_open_client, .udata = settings,
1156
+ .tls = arg_settings.tls);
1169
1157
  (void)0;
1170
1158
  } else {
1171
1159
  /* Allow for any HTTP version */
1172
1160
  ret = fio_connect(.address = a, .port = p, .on_fail = http_on_client_failed,
1173
- .on_connect = http_on_open_client, .udata = settings);
1161
+ .on_connect = http_on_open_client, .udata = settings,
1162
+ .tls = arg_settings.tls);
1174
1163
  (void)0;
1175
1164
  }
1176
- fio_free(a);
1165
+ if (a != unix_address)
1166
+ fio_free(a);
1167
+ fio_free(p);
1177
1168
  return ret;
1178
1169
  on_error:
1179
1170
  if (arg_settings.on_finish)
1180
1171
  arg_settings.on_finish(&arg_settings);
1181
1172
  return -1;
1182
1173
  }
1183
- #define http_connect(address, ...) \
1184
- http_connect((address), (struct http_settings_s){__VA_ARGS__})
1185
1174
 
1186
1175
  /* *****************************************************************************
1187
1176
  HTTP Websocket Connect
@@ -1213,7 +1202,7 @@ static void on_websocket_http_connection_finished(http_settings_s *settings) {
1213
1202
  int websocket_connect(const char *address, websocket_settings_s settings) {
1214
1203
  websocket_settings_s *s = fio_malloc(sizeof(*s));
1215
1204
  *s = settings;
1216
- return http_connect(address, .on_request = on_websocket_http_connected,
1205
+ return http_connect(address, NULL, .on_request = on_websocket_http_connected,
1217
1206
  .on_response = on_websocket_http_connected,
1218
1207
  .on_finish = on_websocket_http_connection_finished,
1219
1208
  .udata = s);
@@ -1671,7 +1660,8 @@ rebase:
1671
1660
  /* ensure array exists and it's an array + set nested_ary */
1672
1661
  const size_t len = ((cut1[-1] == ']') ? (size_t)((cut1 - 1) - name)
1673
1662
  : (size_t)(cut1 - name));
1674
- const uint64_t hash = fio_siphash(name, len); /* hash the current name */
1663
+ const uint64_t hash =
1664
+ fiobj_hash_string(name, len); /* hash the current name */
1675
1665
  nested_ary = fiobj_hash_get2(dest, hash);
1676
1666
  if (!nested_ary) {
1677
1667
  /* create a new nested array */
@@ -1708,7 +1698,8 @@ rebase:
1708
1698
  /* we have name[key]... */
1709
1699
  const size_t len = ((cut1[-1] == ']') ? (size_t)((cut1 - 1) - name)
1710
1700
  : (size_t)(cut1 - name));
1711
- const uint64_t hash = fio_siphash(name, len); /* hash the current name */
1701
+ const uint64_t hash =
1702
+ fiobj_hash_string(name, len); /* hash the current name */
1712
1703
  FIOBJ tmp = fiobj_hash_get2(dest, hash);
1713
1704
  if (!tmp) {
1714
1705
  /* hash doesn't exist, create it */
@@ -1762,7 +1753,7 @@ place_in_array:
1762
1753
  if (name[name_len - 1] == ']')
1763
1754
  --name_len;
1764
1755
  {
1765
- uint64_t hash = fio_siphash(name, name_len);
1756
+ uint64_t hash = fiobj_hash_string(name, name_len);
1766
1757
  FIOBJ ary = fiobj_hash_get2(dest, hash);
1767
1758
  if (!ary) {
1768
1759
  FIOBJ key = encoded ? http_urlstr2fiobj(name, name_len)
@@ -1948,7 +1939,7 @@ int http_parse_body(http_s *h) {
1948
1939
  if (!h->body)
1949
1940
  return -1;
1950
1941
  if (!content_type_hash)
1951
- content_type_hash = fio_siphash("content-type", 12);
1942
+ content_type_hash = fiobj_hash_string("content-type", 12);
1952
1943
  FIOBJ ct = fiobj_hash_get2(h->headers, content_type_hash);
1953
1944
  fio_str_info_s content_type = fiobj_obj2cstr(ct);
1954
1945
  if (content_type.len < 16)
@@ -2500,206 +2491,6 @@ ssize_t http_decode_path_unsafe(char *dest, const char *url_data) {
2500
2491
  *pos = 0;
2501
2492
  return pos - dest;
2502
2493
  }
2503
- /* *****************************************************************************
2504
- HTTP URL parsing
2505
- ***************************************************************************** */
2506
-
2507
- /**
2508
- * Parses the URI returning it's components and their lengths (no decoding
2509
- * performed, doesn't accept decoded URIs).
2510
- *
2511
- * The returned string are NOT NUL terminated, they are merely locations within
2512
- * the original string.
2513
- *
2514
- * This function expects any of the following formats:
2515
- *
2516
- * * `/complete_path?query#target`
2517
- *
2518
- * i.e.: /index.html?page=1#list
2519
- *
2520
- * * `host:port/complete_path?query#target`
2521
- *
2522
- * i.e.:
2523
- * example.com/index.html
2524
- * example.com:8080/index.html
2525
- *
2526
- * * `schema://user:password@host:port/path?query#target`
2527
- *
2528
- * i.e.: http://example.com/index.html?page=1#list
2529
- *
2530
- * Invalid formats might produce unexpected results. No error testing performed.
2531
- */
2532
- http_url_s http_url_parse(const char *url, size_t length) {
2533
- const char *end = url + length;
2534
- http_url_s result = {.scheme = {.data = (char *)url, .len = 0}};
2535
- if (length == 0) {
2536
- return result;
2537
- }
2538
- if (url[0] == '/') {
2539
- result.scheme.data = NULL;
2540
- goto parse_path;
2541
- }
2542
- /* test for scheme */
2543
- while (url < end && *url != ':' && *url != '/' && *url != '@') {
2544
- ++url;
2545
- }
2546
- result.scheme.len = url - result.scheme.data;
2547
- if (url + 3 >= end || url[1] != '/' || url[2] != '/') { /* host only? */
2548
- url = result.scheme.data;
2549
- result.scheme = (fio_str_info_s){.data = NULL};
2550
- goto after_scheme;
2551
- }
2552
-
2553
- url += 3;
2554
-
2555
- after_scheme:
2556
- result.user.data = (char *)url;
2557
- while (url < end) {
2558
- switch (*url) {
2559
- case '/':
2560
- /* no user name or password (or port) */
2561
- result.host.data = result.user.data;
2562
- result.user.data = NULL;
2563
- result.host.len = url - result.host.data;
2564
- goto parse_path;
2565
- break;
2566
- case '@':
2567
- /* user name only, no password */
2568
- result.user.len = url - result.user.data;
2569
- ++url;
2570
- goto parse_host;
2571
- break;
2572
- case ':':
2573
- /* user name and password (or host:port...) */
2574
- result.user.len = url - result.user.data;
2575
- ++url;
2576
- goto parse_password;
2577
- break;
2578
- default:
2579
- ++url;
2580
- break;
2581
- }
2582
- }
2583
- if (url == end) { /* possibily: http://example.com */
2584
- result.host.data = result.user.data;
2585
- result.user.data = NULL;
2586
- result.host.len = url - result.host.data;
2587
- return result;
2588
- }
2589
-
2590
- parse_password:
2591
- result.password.data = (char *)url;
2592
- while (url < end) {
2593
- switch (*url) {
2594
- case '/':
2595
- /* this wasn't a user:password, but host:port */
2596
- result.host = result.user;
2597
- result.port = result.password;
2598
- result.port.len = url - result.port.data;
2599
- result.user = result.password = (fio_str_info_s){.data = NULL};
2600
- goto parse_path;
2601
- break;
2602
- case '@':
2603
- /* done */
2604
- result.password.len = url - result.password.data;
2605
- ++url;
2606
- goto after_pass;
2607
- default:
2608
- ++url;
2609
- break;
2610
- }
2611
- }
2612
- after_pass:
2613
- if (url == end) { /* possibily: http://example.com:port */
2614
- result.host = result.user;
2615
- result.port = result.password;
2616
- result.port.len = url - result.port.data;
2617
- result.user = result.password = (fio_str_info_s){.data = NULL};
2618
- return result;
2619
- }
2620
- parse_host:
2621
- /* host:port parsing */
2622
- result.host.data = (char *)url;
2623
- while (url < end) {
2624
- switch (*url) {
2625
- case '/':
2626
- /* host only */
2627
- result.host.len = url - result.host.data;
2628
- goto parse_path;
2629
- break;
2630
- case ':':
2631
- /* done */
2632
- result.host.len = url - result.host.data;
2633
- ++url;
2634
- goto after_host;
2635
- break;
2636
- default:
2637
- ++url;
2638
- break;
2639
- }
2640
- }
2641
- after_host:
2642
-
2643
- if (url == end) { /* scheme://host only? */
2644
- result.host.len = end - result.host.data;
2645
- return result;
2646
- }
2647
- result.port.data = (char *)url;
2648
- while (url < end && *url != '/') {
2649
- ++url;
2650
- }
2651
- result.port.len = url - result.port.data;
2652
-
2653
- if (url == end) { /* scheme://host:port only? */
2654
- return result;
2655
- }
2656
-
2657
- if (url == end) { /* scheme://host only? */
2658
- return result;
2659
- }
2660
- /* path, query and target parsing */
2661
- parse_path:
2662
- result.path.data = (char *)url;
2663
- while (url < end && *url != '?') {
2664
- ++url;
2665
- }
2666
- result.path.len = url - result.path.data;
2667
- if (url == end) {
2668
- return result;
2669
- }
2670
- ++url;
2671
- result.query.data = (char *)url;
2672
- while (url < end && *url != '#') {
2673
- ++url;
2674
- }
2675
- result.query.len = url - result.query.data;
2676
- if (url == end) {
2677
- return result;
2678
- }
2679
- ++url;
2680
- result.target.data = (char *)url;
2681
- result.target.len = end - result.target.data;
2682
-
2683
- /* set any empty values to NULL */
2684
- if (!result.scheme.len)
2685
- result.scheme.data = NULL;
2686
- if (!result.user.len)
2687
- result.user.data = NULL;
2688
- if (!result.password.len)
2689
- result.password.data = NULL;
2690
- if (!result.host.len)
2691
- result.host.data = NULL;
2692
- if (!result.port.len)
2693
- result.port.data = NULL;
2694
- if (!result.path.len)
2695
- result.path.data = NULL;
2696
- if (!result.query.len)
2697
- result.query.data = NULL;
2698
- if (!result.target.len)
2699
- result.target.data = NULL;
2700
-
2701
- return result;
2702
- }
2703
2494
 
2704
2495
  /* *****************************************************************************
2705
2496
  Lookup Tables / functions
@@ -2719,7 +2510,7 @@ static fio_mime_set_s mime_types = FIO_SET_INIT;
2719
2510
  /** Registers a Mime-Type to be associated with the file extension. */
2720
2511
  void http_mimetype_register(char *file_ext, size_t file_ext_len,
2721
2512
  FIOBJ mime_type_str) {
2722
- uintptr_t hash = fio_siphash(file_ext, file_ext_len);
2513
+ uintptr_t hash = fiobj_hash_string(file_ext, file_ext_len);
2723
2514
  if (mime_type_str == FIOBJ_INVALID) {
2724
2515
  fio_mime_set_remove(&mime_types, hash, FIOBJ_INVALID, NULL);
2725
2516
  } else {
@@ -2739,7 +2530,7 @@ void http_mimetype_register(char *file_ext, size_t file_ext_len,
2739
2530
  * Remember to call `fiobj_free`.
2740
2531
  */
2741
2532
  FIOBJ http_mimetype_find(char *file_ext, size_t file_ext_len) {
2742
- uintptr_t hash = fio_siphash(file_ext, file_ext_len);
2533
+ uintptr_t hash = fiobj_hash_string(file_ext, file_ext_len);
2743
2534
  return fiobj_dup(fio_mime_set_find(&mime_types, hash, FIOBJ_INVALID));
2744
2535
  }
2745
2536