iodine 0.7.6 → 0.7.7

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.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 978b528f65f3a43372f47339c6f76ced52bfc12264665bf57c0d2f285b2a4ad2
4
- data.tar.gz: b75b56ceebbda9a80510740f3d11425980a3562d46542e308e818fcf0fd9b219
3
+ metadata.gz: 5f1e30dc08b1f6e19e59689fc251f50d1fe2de15377c36d9d6c0244a3a569352
4
+ data.tar.gz: 3ea55ee5a0c809ba5f3bbde618beef72a2dd151242f5aadbf2b68c0d3a403d68
5
5
  SHA512:
6
- metadata.gz: bf003b8b3ddf3a1be5c81cee28588a31ed9af159ad5e2b49d69d3e1a8bc6cf75149ba4191bc80c8e55e55cf5a9fae6b47d7c615662a6073824086b91d1a5811f
7
- data.tar.gz: 923b37d94efd4e31d96743df37425334268c1c3a9fd51d44265f8a9603ff92346cc4d793e24a39203a93e5aabadf64981190ad88f843fb50fc276452ee6cb38e
6
+ metadata.gz: d0a8c45de3d93f4e7304a172b8111ea8cd0c5e727431fccb06982b930d596c571c3319819d72221dffe82cde14211bdefc1795ffc275fc8a5ba5255036bb81da
7
+ data.tar.gz: 537d0c329cf43df25ca7318b99d049cc590103e2b65bb90058dc246b6d0442404ec70eda473f6d97d6020f4b7f4163a270f0dcc2e8a9285298fd07ca4c712808
@@ -6,6 +6,10 @@ Please notice that this change log contains changes for upcoming releases as wel
6
6
 
7
7
  ## Changes:
8
8
 
9
+ #### Change log v.0.7.7
10
+
11
+ **Fix**: (facil.io) fixed critical issue with cookies, where no more than a single cookie could be set (duplicate headers would be zeroed out before being set). Credit to @ojab for exposing the issue.
12
+
9
13
  #### Change log v.0.7.6
10
14
 
11
15
  **Fix**: (facil.io edge) timeout review was experiencing some errors that could cause timeouts to be ignored. This was fixed in the facil.io edge branch.
@@ -1264,7 +1264,7 @@ void fio_expected_concurrency(int16_t *threads, int16_t *processes) {
1264
1264
  }
1265
1265
  #endif
1266
1266
  *threads = *processes = (int16_t)cpu_count;
1267
- if (cpu_count > FIO_CPU_CORES_LIMIT) {
1267
+ if (cpu_count > 3) {
1268
1268
  /* leave a core available for the kernel */
1269
1269
  --(*processes);
1270
1270
  }
@@ -1288,7 +1288,7 @@ void fio_expected_concurrency(int16_t *threads, int16_t *processes) {
1288
1288
  *processes = -1 * *threads;
1289
1289
  *threads = tmp_threads;
1290
1290
  if (cpu_adjust && (*processes * tmp_threads) >= cpu_count &&
1291
- cpu_count > FIO_CPU_CORES_LIMIT) {
1291
+ cpu_count > 3) {
1292
1292
  /* leave a core available for the kernel */
1293
1293
  --*processes;
1294
1294
  }
@@ -2734,7 +2734,7 @@ const fio_rw_hook_s FIO_DEFAULT_RW_HOOKS = {
2734
2734
  /** Sets a socket hook state (a pointer to the struct). */
2735
2735
  int fio_rw_hook_set(intptr_t uuid, fio_rw_hook_s *rw_hooks, void *udata) {
2736
2736
  if (fio_is_closed(uuid))
2737
- return -1;
2737
+ goto invalid_uuid;
2738
2738
  if (!rw_hooks->read)
2739
2739
  rw_hooks->read = fio_hooks_default_read;
2740
2740
  if (!rw_hooks->write)
@@ -2745,18 +2745,26 @@ int fio_rw_hook_set(intptr_t uuid, fio_rw_hook_s *rw_hooks, void *udata) {
2745
2745
  rw_hooks->before_close = fio_hooks_default_before_close;
2746
2746
  if (!rw_hooks->cleanup)
2747
2747
  rw_hooks->cleanup = fio_hooks_default_cleanup;
2748
- uuid = fio_uuid2fd(uuid);
2748
+ intptr_t fd = fio_uuid2fd(uuid);
2749
2749
  fio_rw_hook_s *old_rw_hooks;
2750
2750
  void *old_udata;
2751
- fio_lock(&fd_data(uuid).sock_lock);
2752
- old_rw_hooks = fd_data(uuid).rw_hooks;
2753
- old_udata = fd_data(uuid).rw_udata;
2754
- fd_data(uuid).rw_hooks = rw_hooks;
2755
- fd_data(uuid).rw_udata = udata;
2756
- fio_unlock(&fd_data(uuid).sock_lock);
2751
+ fio_lock(&fd_data(fd).sock_lock);
2752
+ if (fd2uuid(fd) != uuid) {
2753
+ fio_unlock(&fd_data(fd).sock_lock);
2754
+ goto invalid_uuid;
2755
+ }
2756
+ old_rw_hooks = fd_data(fd).rw_hooks;
2757
+ old_udata = fd_data(fd).rw_udata;
2758
+ fd_data(fd).rw_hooks = rw_hooks;
2759
+ fd_data(fd).rw_udata = udata;
2760
+ fio_unlock(&fd_data(fd).sock_lock);
2757
2761
  if (old_rw_hooks && old_rw_hooks->cleanup)
2758
2762
  old_rw_hooks->cleanup(old_udata);
2759
2763
  return 0;
2764
+ invalid_uuid:
2765
+ if (!rw_hooks->cleanup)
2766
+ rw_hooks->cleanup(udata);
2767
+ return -1;
2760
2768
  }
2761
2769
 
2762
2770
  /* *****************************************************************************
@@ -7975,6 +7983,7 @@ FIO_FUNC inline void fio_str_test(void) {
7975
7983
  }
7976
7984
  fprintf(stderr, "* reviewing reference counting `fio_str_free2` (2/2).\n");
7977
7985
  fio_str_free2(s);
7986
+ fprintf(stderr, "* finished reference counting test.\n");
7978
7987
  }
7979
7988
  fio_str_free(&str);
7980
7989
  if (1) {
@@ -8032,7 +8041,17 @@ FIO_FUNC inline void fio_str_test(void) {
8032
8041
  str = FIO_STR_INIT_STATIC("Welcome");
8033
8042
  fio_str_info_s state = fio_str_write(&str, " Home", 5);
8034
8043
  FIO_ASSERT(state.capa > 0, "Static string not converted to non-static.");
8035
- fio_str_free(&str);
8044
+ FIO_ASSERT(str.dealloc, "MIssing static string deallocation function"
8045
+ " after `fio_str_write`.");
8046
+
8047
+ fprintf(stderr, "* reviewing `fio_str_detach`.\n");
8048
+ char *cstr = fio_str_detach(&str);
8049
+ FIO_ASSERT(cstr, "`fio_str_detach` returned NULL");
8050
+ FIO_ASSERT(!memcmp(cstr, "Welcome Home\0", 13),
8051
+ "`fio_str_detach` string error");
8052
+ fio_free(cstr);
8053
+ FIO_ASSERT(fio_str_len(&str) == 0, "`fio_str_detach` data wasn't cleared.");
8054
+ // fio_str_free(&str);
8036
8055
  }
8037
8056
  fprintf(stderr, "* passed.\n");
8038
8057
  }
@@ -1226,7 +1226,10 @@ typedef struct fio_rw_hook_s {
1226
1226
  */
1227
1227
  ssize_t (*flush)(intptr_t uuid, void *udata);
1228
1228
  /**
1229
- * Called to perform cleanup after the socket was closed.
1229
+ * Called to perform cleanup after the socket was closed or a new read/write
1230
+ * hook was set using `fio_rw_hook_set`.
1231
+ *
1232
+ * This callback is always called, even if `fio_rw_hook_set` fails.
1230
1233
  * */
1231
1234
  void (*cleanup)(void *udata);
1232
1235
  } fio_rw_hook_s;
@@ -3023,7 +3026,8 @@ typedef struct {
3023
3026
  * The `capacity` value should exclude the NUL character (if exists).
3024
3027
  */
3025
3028
  #define FIO_STR_INIT_STATIC(buffer) \
3026
- ((fio_str_s){.data = (buffer), .len = strlen((buffer)), .dealloc = NULL})
3029
+ ((fio_str_s){ \
3030
+ .data = (char *)(buffer), .len = strlen((buffer)), .dealloc = NULL})
3027
3031
 
3028
3032
  /**
3029
3033
  * Allocates a new fio_str_s object on the heap and initializes it.
@@ -3086,6 +3090,20 @@ FIO_FUNC void fio_str_free2(fio_str_s *s);
3086
3090
  inline FIO_FUNC ssize_t fio_str_send_free2(const intptr_t uuid,
3087
3091
  const fio_str_s *str);
3088
3092
 
3093
+ /**
3094
+ * Returns a C string with the existing data, clearing the `fio_str_s` object's
3095
+ * String.
3096
+ *
3097
+ * Note: the String data is removed from the container, but the container isn't
3098
+ * freed.
3099
+ *
3100
+ * Returns NULL if there's no String data.
3101
+ *
3102
+ * Remember to `fio_free` the returned data and - if required - `fio_str_free2`
3103
+ * the container.
3104
+ */
3105
+ FIO_FUNC char *fio_str_detach(fio_str_s *s);
3106
+
3089
3107
  /* *****************************************************************************
3090
3108
  String API - String state (data pointers, length, capacity, etc')
3091
3109
  ***************************************************************************** */
@@ -3394,6 +3412,58 @@ FIO_FUNC void fio_str_free2(fio_str_s *s) {
3394
3412
  FIO_FREE(s);
3395
3413
  }
3396
3414
 
3415
+ /**
3416
+ * Returns a C string with the existing data, clearing the `fio_str_s` object's
3417
+ * String.
3418
+ *
3419
+ * Note: the String data is removed from the container, but the container isn't
3420
+ * freed.
3421
+ *
3422
+ * Returns NULL if there's no String data.
3423
+ *
3424
+ * Remember to `fio_free` the returned data and - if required - `fio_str_free2`
3425
+ * the container.
3426
+ */
3427
+ FIO_FUNC char *fio_str_detach(fio_str_s *s) {
3428
+ if (!s)
3429
+ return NULL;
3430
+ fio_str_info_s i = fio_str_info(s);
3431
+ if (s->small || !s->data) {
3432
+ if (!i.len) {
3433
+ i.data = NULL;
3434
+ goto finish;
3435
+ }
3436
+ /* make a copy */
3437
+ void *tmp = FIO_MALLOC(i.len + 1);
3438
+ memcpy(tmp, i.data, i.len + 1);
3439
+ i.data = tmp;
3440
+ } else {
3441
+ if (!i.len && s->data) {
3442
+ if (s->dealloc)
3443
+ s->dealloc(s->data);
3444
+ i.data = NULL;
3445
+ } else if (s->dealloc != FIO_FREE) {
3446
+ /* make a copy */
3447
+ void *tmp = FIO_MALLOC(i.len + 1);
3448
+ memcpy(tmp, i.data, i.len + 1);
3449
+ i.data = tmp;
3450
+ if (s->dealloc)
3451
+ s->dealloc(s->data);
3452
+ }
3453
+ }
3454
+ finish:
3455
+ #ifdef FIO_STR_NO_REF
3456
+ *s = (fio_str_s){.small = 1};
3457
+
3458
+ #else
3459
+ *s = (fio_str_s){
3460
+ .small = s->small,
3461
+ .ref = s->ref,
3462
+ };
3463
+ #endif
3464
+ return i.data;
3465
+ }
3466
+
3397
3467
  /** Returns the String's length in bytes. */
3398
3468
  inline FIO_FUNC size_t fio_str_len(fio_str_s *s) {
3399
3469
  return (s->small || !s->data) ? (s->small >> 1) : s->len;
@@ -3474,8 +3544,8 @@ String Implementation - Memory management
3474
3544
  * directly to `mmap` (due to their size, usually over 12KB).
3475
3545
  */
3476
3546
  #define ROUND_UP_CAPA2WORDS(num) \
3477
- (((num + 1) & (sizeof(long double) - 1)) \
3478
- ? ((num + 1) | (sizeof(long double) - 1)) \
3547
+ ((((num) + 1) & (sizeof(long double) - 1)) \
3548
+ ? (((num) + 1) | (sizeof(long double) - 1)) \
3479
3549
  : (num))
3480
3550
  /**
3481
3551
  * Requires the String to have at least `needed` capacity. Returns the current
@@ -3499,6 +3569,7 @@ FIO_FUNC fio_str_info_s fio_str_capa_assert(fio_str_s *s, size_t needed) {
3499
3569
  memcpy(tmp, s->data, s->len);
3500
3570
  if (s->dealloc)
3501
3571
  s->dealloc(s->data);
3572
+ s->dealloc = FIO_FREE;
3502
3573
  }
3503
3574
  s->capa = needed;
3504
3575
  s->data = tmp;
@@ -4184,9 +4255,14 @@ static FIO_ARY_TYPE const FIO_NAME(s___const_invalid_object);
4184
4255
  /* minimizes allocation "dead space" by alligning allocated length to 16bytes */
4185
4256
  #undef FIO_ARY_SIZE2WORDS
4186
4257
  #define FIO_ARY_SIZE2WORDS(size) \
4187
- ((sizeof(FIO_ARY_TYPE) & 15) ? (((size) & ~(sizeof(FIO_ARY_TYPE) - 1)) + \
4188
- (16 - (sizeof(FIO_ARY_TYPE) - 1))) \
4189
- : (size))
4258
+ ((sizeof(FIO_ARY_TYPE) & 1) \
4259
+ ? (((size) & (~15)) + 16) \
4260
+ : (sizeof(FIO_ARY_TYPE) & 2) \
4261
+ ? (((size) & (~7)) + 8) \
4262
+ : (sizeof(FIO_ARY_TYPE) & 4) \
4263
+ ? (((size) & (~3)) + 4) \
4264
+ : (sizeof(FIO_ARY_TYPE) & 8) ? (((size) & (~1)) + 2) \
4265
+ : (size))
4190
4266
 
4191
4267
  /* *****************************************************************************
4192
4268
  Array API
@@ -25,7 +25,7 @@ License: MIT
25
25
  } while (0)
26
26
  #define FIO_SET_OBJ_TYPE FIOBJ
27
27
  #define FIO_SET_OBJ_COMPARE(o1, o2) fiobj_iseq((o1), (o2))
28
- #define FIO_SET_OBJ_COPY(dest, obj) ((dest) = (obj)) /* take ownership */
28
+ #define FIO_SET_OBJ_COPY(dest, obj) ((dest) = fiobj_dup(obj))
29
29
  #define FIO_SET_OBJ_DESTROY(obj) \
30
30
  do { \
31
31
  fiobj_free((obj)); \
@@ -201,6 +201,7 @@ int fiobj_hash_set(FIOBJ hash, FIOBJ key, FIOBJ obj) {
201
201
  if (FIOBJ_TYPE_IS(key, FIOBJ_T_STRING))
202
202
  fiobj_str_freeze(key);
203
203
  fio_hash___insert(&obj2hash(hash)->hash, fiobj_obj2hash(key), key, obj, NULL);
204
+ fiobj_free(obj); /* take ownership - free the user's reference. */
204
205
  return 0;
205
206
  }
206
207
 
@@ -239,6 +240,7 @@ FIOBJ fiobj_hash_replace(FIOBJ hash, FIOBJ key, FIOBJ obj) {
239
240
  assert(hash && FIOBJ_TYPE_IS(hash, FIOBJ_T_HASH));
240
241
  FIOBJ old = FIOBJ_INVALID;
241
242
  fio_hash___insert(&obj2hash(hash)->hash, fiobj_obj2hash(key), key, obj, &old);
243
+ fiobj_free(obj); /* take ownership - free the user's reference. */
242
244
  return old;
243
245
  }
244
246
 
@@ -270,7 +272,8 @@ FIOBJ fiobj_hash_remove2(FIOBJ hash, uint64_t hash_value) {
270
272
  * Returns -1 on type error or if the object never existed.
271
273
  */
272
274
  int fiobj_hash_delete(FIOBJ hash, FIOBJ key) {
273
- return fiobj_hash_remove(hash, key);
275
+ return fio_hash___remove(&obj2hash(hash)->hash, fiobj_obj2hash(key), key,
276
+ NULL);
274
277
  }
275
278
 
276
279
  /**
@@ -42,11 +42,30 @@ static inline int patch_clock_gettime(int clk_id, struct timespec *t) {
42
42
  /* *****************************************************************************
43
43
  SSL/TLS patch
44
44
  ***************************************************************************** */
45
- void __attribute__((weak)) fio_tls_accept(intptr_t uuid, void *tls) {
45
+
46
+ /**
47
+ * Adds an ALPN protocol callback to the SSL/TLS context.
48
+ *
49
+ * The first protocol added will act as the default protocol to be selected.
50
+ */
51
+ void __attribute__((weak))
52
+ fio_tls_proto_add(void *tls, const char *protocol_name,
53
+ void (*callback)(intptr_t uuid, void *udata)) {
54
+ FIO_LOG_FATAL("HTTP SSL/TLS required but unavailable!");
55
+ exit(-1);
56
+ (void)tls;
57
+ (void)protocol_name;
58
+ (void)callback;
59
+ }
60
+ #pragma weak fio_tls_proto_add
61
+
62
+ void __attribute__((weak))
63
+ fio_tls_accept(intptr_t uuid, void *tls, void *udata) {
46
64
  FIO_LOG_FATAL("HTTP SSL/TLS required but unavailable!");
47
65
  exit(-1);
48
66
  (void)uuid;
49
67
  (void)tls;
68
+ (void)udata;
50
69
  }
51
70
  #pragma weak fio_tls_accept
52
71
 
@@ -57,11 +76,13 @@ void __attribute__((weak)) fio_tls_accept(intptr_t uuid, void *tls) {
57
76
  * The `uuid` should be a socket UUID that is already connected to a peer (i.e.,
58
77
  * the result of `fio_accept`).
59
78
  */
60
- void __attribute__((weak)) fio_tls_connect(intptr_t uuid, void *tls) {
79
+ void __attribute__((weak))
80
+ fio_tls_connect(intptr_t uuid, void *tls, void *udata) {
61
81
  FIO_LOG_FATAL("HTTP SSL/TLS required but unavailable!");
62
82
  exit(-1);
63
83
  (void)uuid;
64
84
  (void)tls;
85
+ (void)udata;
65
86
  }
66
87
  #pragma weak fio_tls_connect
67
88
 
@@ -177,8 +198,7 @@ int http_set_header(http_s *r, FIOBJ name, FIOBJ value) {
177
198
  return 0;
178
199
  }
179
200
  /**
180
- * Sets a response header, taking ownership of the value object, but NOT the
181
- * name object (so name objects could be reused in future responses).
201
+ * Sets a response header.
182
202
  *
183
203
  * Returns -1 on error and 0 on success.
184
204
  */
@@ -907,10 +927,14 @@ static void http_settings_free(http_settings_s *s) {
907
927
  Listening to HTTP connections
908
928
  ***************************************************************************** */
909
929
 
930
+ static void http_on_server_protocol_http1(intptr_t uuid, void *set) {
931
+ fio_protocol_s *pr = http1_new(uuid, set, NULL, 0);
932
+ if (!pr)
933
+ fio_close(uuid);
934
+ }
935
+
910
936
  static void http_on_open(intptr_t uuid, void *set) {
911
937
  static uint8_t at_capa;
912
- if (((http_settings_s *)set)->tls)
913
- fio_tls_accept(uuid, ((http_settings_s *)set)->tls);
914
938
  fio_timeout_set(uuid, ((http_settings_s *)set)->timeout);
915
939
  if (fio_uuid2fd(uuid) >= ((http_settings_s *)set)->max_clients) {
916
940
  if (!at_capa)
@@ -921,9 +945,10 @@ static void http_on_open(intptr_t uuid, void *set) {
921
945
  return;
922
946
  }
923
947
  at_capa = 0;
924
- fio_protocol_s *pr = http1_new(uuid, set, NULL, 0);
925
- if (!pr)
926
- fio_close(uuid);
948
+ if (((http_settings_s *)set)->tls)
949
+ fio_tls_accept(uuid, ((http_settings_s *)set)->tls, set);
950
+ else
951
+ http_on_server_protocol_http1(uuid, set);
927
952
  }
928
953
 
929
954
  static void http_on_finish(intptr_t uuid, void *set) {
@@ -955,6 +980,9 @@ intptr_t http_listen(const char *port, const char *binding,
955
980
 
956
981
  http_settings_s *settings = http_settings_new(arg_settings);
957
982
  settings->is_client = 0;
983
+ if (settings->tls) {
984
+ fio_tls_proto_add(settings->tls, "http/1.1", http_on_server_protocol_http1);
985
+ }
958
986
 
959
987
  return fio_listen(.port = port, .address = binding,
960
988
  .on_finish = http_on_finish, .on_open = http_on_open,
@@ -996,13 +1024,13 @@ static void http_on_close_client(intptr_t uuid, fio_protocol_s *protocol) {
996
1024
  http_settings_free(set);
997
1025
  }
998
1026
 
999
- static void http_on_open_client(intptr_t uuid, void *set_) {
1027
+ static void http_on_open_client_perform(http_settings_s *set) {
1028
+ http_s *h = set->udata;
1029
+ set->on_response(h);
1030
+ }
1031
+ static void http_on_open_client_http1(intptr_t uuid, void *set_) {
1000
1032
  http_settings_s *set = set_;
1001
1033
  http_s *h = set->udata;
1002
- set->udata = h->udata;
1003
- if (set->tls)
1004
- fio_tls_connect(uuid, set->tls);
1005
- fio_timeout_set(uuid, set->timeout);
1006
1034
  fio_protocol_s *pr = http1_new(uuid, set, NULL, 0);
1007
1035
  if (!pr) {
1008
1036
  fio_close(uuid);
@@ -1016,7 +1044,16 @@ static void http_on_open_client(intptr_t uuid, void *set_) {
1016
1044
  }
1017
1045
  h->private_data.flag = (uintptr_t)pr;
1018
1046
  h->private_data.vtbl = http1_vtable();
1019
- set->on_response(h);
1047
+ http_on_open_client_perform(set);
1048
+ }
1049
+
1050
+ static void http_on_open_client(intptr_t uuid, void *set_) {
1051
+ http_settings_s *set = set_;
1052
+ fio_timeout_set(uuid, set->timeout);
1053
+ if (set->tls)
1054
+ fio_tls_connect(uuid, set->tls, set_);
1055
+ else
1056
+ http_on_open_client_http1(uuid, set);
1020
1057
  }
1021
1058
 
1022
1059
  static void http_on_client_failed(intptr_t uuid, void *set_) {
@@ -1127,6 +1164,10 @@ intptr_t http_connect(const char *address,
1127
1164
  arg_settings.timeout = 30;
1128
1165
  http_settings_s *settings = http_settings_new(arg_settings);
1129
1166
  settings->is_client = 1;
1167
+ if (settings->tls) {
1168
+ fio_tls_proto_add(settings->tls, "http/1.1", http_on_open_client_http1);
1169
+ }
1170
+
1130
1171
  if (!arg_settings.ws_timeout)
1131
1172
  settings->ws_timeout = 0; /* allow server to dictate timeout */
1132
1173
  if (!arg_settings.timeout)
@@ -148,8 +148,7 @@ typedef struct {
148
148
  int http_set_header(http_s *h, FIOBJ name, FIOBJ value);
149
149
 
150
150
  /**
151
- * Sets a response header, taking ownership of the value object, but NOT the
152
- * name object (so name objects could be reused in future responses).
151
+ * Sets a response header.
153
152
  *
154
153
  * Returns -1 on error and 0 on success.
155
154
  */
@@ -217,8 +217,8 @@ static inline void set_header_add(FIOBJ hash, FIOBJ name, FIOBJ value) {
217
217
  fiobj_ary_push(tmp, old);
218
218
  old = tmp;
219
219
  }
220
- fiobj_ary_push(old, value);
221
- fiobj_hash_replace(hash, name, old);
220
+ fiobj_ary_push(old, value); /* value is owned by both hash and array */
221
+ fiobj_hash_replace(hash, name, old); /* don't free `value` (leave in array) */
222
222
  }
223
223
 
224
224
  #endif /* H_HTTP_INTERNAL_H */
@@ -467,6 +467,7 @@ static int for_each_header_data(VALUE key, VALUE val, VALUE h_) {
467
467
  char *val_s = RSTRING_PTR(val);
468
468
  int val_len = RSTRING_LEN(val);
469
469
  // make the headers lowercase
470
+
470
471
  FIOBJ name = fiobj_str_new(key_s, key_len);
471
472
  {
472
473
  fio_str_info_s tmp = fiobj_obj2cstr(name);
@@ -475,16 +476,17 @@ static int for_each_header_data(VALUE key, VALUE val, VALUE h_) {
475
476
  }
476
477
  }
477
478
  // scan the value for newline (\n) delimiters
478
- int pos_s = 0, pos_e = 0;
479
- while (pos_e < val_len) {
479
+ char *pos_s = val_s;
480
+ char *pos_e = val_s + val_len;
481
+ while (pos_s < pos_e) {
480
482
  // scanning for newline (\n) delimiters
481
- while (pos_e < val_len && val_s[pos_e] != '\n')
482
- pos_e++;
483
- http_set_header(h, name, fiobj_str_new(val_s + pos_s, pos_e - pos_s));
484
- // fprintf(stderr, "For_each - headers: wrote header\n");
483
+ char *const start = pos_s;
484
+ pos_s = memchr(pos_s, '\n', pos_e - pos_s);
485
+ if (!pos_s)
486
+ pos_s = pos_e;
487
+ http_set_header(h, name, fiobj_str_new(start, (pos_s - start)));
485
488
  // move forward (skip the '\n' if exists)
486
- ++pos_e;
487
- pos_s = pos_e;
489
+ ++pos_s;
488
490
  }
489
491
  fiobj_free(name);
490
492
  // no errors, return 0
@@ -1,3 +1,3 @@
1
1
  module Iodine
2
- VERSION = '0.7.6'.freeze
2
+ VERSION = '0.7.7'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: iodine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.6
4
+ version: 0.7.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Boaz Segev
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-11-05 00:00:00.000000000 Z
11
+ date: 2018-11-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -244,7 +244,7 @@ licenses:
244
244
  - MIT
245
245
  metadata:
246
246
  allowed_push_host: https://rubygems.org
247
- post_install_message: 'Thank you for installing Iodine 0.7.6.
247
+ post_install_message: 'Thank you for installing Iodine 0.7.7.
248
248
 
249
249
  '
250
250
  rdoc_options: []