iodine 0.7.18 → 0.7.19

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: 664ebf25c0cad461467cdb2af2b789d3a0897721566c015bff60b68768a7e3ad
4
- data.tar.gz: cc31d5af68fd2a59dc8fa927af51c2228082f05ca7b69c2c4b31e1d208f88337
3
+ metadata.gz: a17af3bcb580a2154bb0114bf9a0e5d8bb7b361a58c217dc4b9aa471cc328401
4
+ data.tar.gz: 55498d33417433697f9deeb3d864f12af3cccdeb7c7f1a0cec6eb7a83ccc4a84
5
5
  SHA512:
6
- metadata.gz: ae79cb205f288cb84b14d92f7b987f7e350f747c560e3a6e23cb3c1f1d43864234e75dd7f8b71f179f3cecfc8841c0f1da53a41995502c2c8c8c6945c248cc86
7
- data.tar.gz: 705d7b0d312e1c3b7953cf503878a2c91a006cef1c7bf9612f83f8f3d97494208bdc8c2ef1a6a857839586525dcd3cbaa4e64758c597a5fd1d929a364f2b9b3c
6
+ metadata.gz: 3ed48224b228669f024c592708b805a0057ce53e11113693515ba953f6780bf1d8f6aeb448291b9e1c01a7495aa44a4d36fea90303996ff72aa9850a7bead669
7
+ data.tar.gz: bee740562fe189778db55c83c616db4509a16196abf44a8bf1d135432c0e4b99277fe4c91472a76f265d3d68c70f3ad680c6b54dd0254bd5d455f8f219560d93
@@ -6,6 +6,18 @@ 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.19
10
+
11
+ **Deprecation**: (`iodine`) deprecated the CLI option `-tls-password`, use `-tls-pass` instead.
12
+
13
+ **Security**: (`fio`) Slowloris mitigation is now part of the core library, where `FIO_SLOWLORIS_LIMIT` pending calls to `write` (currently 4,096 backlogged calls) will flag the connection as an attacker and close the connection. This protocol independent approach improves security.
14
+
15
+ **Fix**: (`iodine`) log open file / socket limit per worker on startup.
16
+
17
+ **Fix**: (`iodine`) application warm-up error was fixed. Deprecation warnings will still print for deprecated symbols loaded due to the warm-up sequence.
18
+
19
+ **Update**: (`iodine`, `cli`) Support the environment variables `"WORKERS"` and `"THREADS"` out of the box (jury is out regarding `"PORT"` and `"ADDRESS"`, just use CLI for now).
20
+
9
21
  #### Change log v.0.7.18
10
22
 
11
23
  **Fix** (`pubsub`) fixed pub/sub for longer WebSocket messages. Issue where network byte ordering wasn't always respected and integer bit size was wrong for larger payloads. Credit to Marouane Elmidaoui (@moxgeek) for exposing the issue.
data/exe/iodine CHANGED
@@ -47,13 +47,13 @@ module Iodine
47
47
  return app, opt
48
48
  end
49
49
 
50
- def self.perform_warmup
50
+ def self.perform_warmup(app)
51
51
  # load anything marked with `autoload`, since autoload isn't thread safe nor fork friendly.
52
- Iodine.run do
52
+ Iodine.on_state(:on_start) do
53
53
  Module.constants.each do |n|
54
54
  begin
55
55
  Object.const_get(n)
56
- rescue Exception => _e
56
+ rescue StandardError => _e
57
57
  end
58
58
  end
59
59
  ::Rack::Builder.new(app) do |r|
@@ -67,7 +67,7 @@ module Iodine
67
67
 
68
68
  def self.call
69
69
  app, opt = get_app_opts
70
- perform_warmup if Iodine::DEFAULT_SETTINGS[:warmup_]
70
+ perform_warmup(app) if Iodine::DEFAULT_SETTINGS[:warmup_]
71
71
  Iodine::Rack.run(app, opt)
72
72
  end
73
73
  end
@@ -76,6 +76,11 @@ Feel free to copy, use and enjoy according to the license provided.
76
76
  #define DEBUG_SPINLOCK 0
77
77
  #endif
78
78
 
79
+ /* Slowloris mitigation (must be less than 1<<16) */
80
+ #ifndef FIO_SLOWLORIS_LIMIT
81
+ #define FIO_SLOWLORIS_LIMIT (1 << 12)
82
+ #endif
83
+
79
84
  #if !defined(__clang__) && !defined(__GNUC__)
80
85
  #define __thread _Thread_value
81
86
  #endif
@@ -148,14 +153,14 @@ typedef struct {
148
153
  fio_packet_s *packet;
149
154
  /** the last packet in the queue. */
150
155
  fio_packet_s **packet_last;
151
- /** The number of pending packets that are in the queue. */
152
- size_t packet_count;
153
156
  /* Data sent so far */
154
157
  size_t sent;
155
158
  /* fd protocol */
156
159
  fio_protocol_s *protocol;
157
160
  /* timer handler */
158
161
  time_t active;
162
+ /** The number of pending packets that are in the queue. */
163
+ uint16_t packet_count;
159
164
  /* timeout settings */
160
165
  uint8_t timeout;
161
166
  /* indicates that the fd should be considered scheduled (added to poll) */
@@ -2919,6 +2924,12 @@ ssize_t fio_flush(intptr_t uuid) {
2919
2924
  if (fio_trylock(&uuid_data(uuid).sock_lock))
2920
2925
  goto would_block;
2921
2926
 
2927
+ if (uuid_data(uuid).packet_count >= FIO_SLOWLORIS_LIMIT) {
2928
+ /* Slowloris attack assumed */
2929
+ fio_unlock(&uuid_data(uuid).sock_lock);
2930
+ uuid_data(uuid).close = 1;
2931
+ goto closed;
2932
+ }
2922
2933
  if (uuid_data(uuid).packet) {
2923
2934
  tmp = uuid_data(uuid).packet->write_func(fio_uuid2fd(uuid),
2924
2935
  uuid_data(uuid).packet);
@@ -6785,6 +6796,7 @@ void fio_mem_init(void) {}
6785
6796
  Memory Copying by 16 byte units
6786
6797
  ***************************************************************************** */
6787
6798
 
6799
+ /** used internally, only when memory addresses are known to be aligned */
6788
6800
  static inline void fio_memcpy(void *__restrict dest_, void *__restrict src_,
6789
6801
  size_t units) {
6790
6802
  #if __SIZEOF_INT128__ == 9 /* a 128bit type exists... but tests favor 64bit */
@@ -7432,42 +7444,81 @@ void *realloc(void *ptr, size_t new_size) { return fio_realloc(ptr, new_size); }
7432
7444
 
7433
7445
  ***************************************************************************** */
7434
7446
 
7435
- static inline void fio_random_data(fio_sha2_s *sha2) {
7436
- struct {
7447
+ /* tested for randomness using code from: http://xoshiro.di.unimi.it/hwd.php */
7448
+ uint64_t fio_rand64(void) {
7449
+ /* modeled after xoroshiro128+, by David Blackman and Sebastiano Vigna */
7450
+ static __thread uint64_t s[2]; /* random state */
7451
+ static __thread uint16_t c; /* seed counter */
7452
+ const uint64_t P[] = {0x37701261ED6C16C7ULL, 0x764DBBB75F3B3E0DULL};
7453
+ if (c++ == 0) {
7454
+ /* re-seed state every 65,536 requests */
7437
7455
  #ifdef RUSAGE_SELF
7438
7456
  struct rusage rusage;
7439
- #endif
7457
+ getrusage(RUSAGE_SELF, &rusage);
7458
+ s[0] = fio_risky_hash(&rusage, sizeof(rusage), s[0]);
7459
+ s[1] = fio_risky_hash(&rusage, sizeof(rusage), s[0]);
7460
+ #else
7440
7461
  struct timespec clk;
7441
- time_t the_time;
7442
- uint64_t more[8];
7443
- } junk_data;
7444
- #ifdef RUSAGE_SELF
7445
- getrusage(RUSAGE_SELF, &junk_data.rusage);
7462
+ clock_gettime(CLOCK_REALTIME, &clk);
7463
+ s[0] = fio_risky_hash(&clk, sizeof(clk), s[0]);
7464
+ s[1] = fio_risky_hash(&clk, sizeof(clk), s[0]);
7446
7465
  #endif
7447
- clock_gettime(CLOCK_REALTIME, &junk_data.clk);
7448
- time(&junk_data.the_time);
7449
- fio_sha2_write(sha2, &junk_data, sizeof(junk_data));
7450
- fio_sha2_result(sha2);
7451
- }
7452
-
7453
- uint64_t fio_rand64(void) {
7454
- fio_sha2_s sha2 = fio_sha2_init(SHA_512);
7455
- fio_random_data(&sha2);
7456
- return sha2.digest.i64[0];
7466
+ }
7467
+ s[0] += fio_lrot64(s[0], 33) * P[0];
7468
+ s[1] += fio_lrot64(s[1], 33) * P[1];
7469
+ return fio_lrot64(s[0], 31) + fio_lrot64(s[1], 29);
7457
7470
  }
7458
7471
 
7459
- void fio_rand_bytes(void *target, size_t length) {
7460
- fio_sha2_s sha2 = fio_sha2_init(SHA_512);
7461
- fio_random_data(&sha2);
7462
-
7463
- while (length >= 64) {
7464
- memcpy(target, sha2.digest.str, 64);
7465
- length -= 64;
7466
- target = (void *)((uintptr_t)target + 64);
7467
- fio_random_data(&sha2);
7468
- }
7469
- if (length) {
7470
- memcpy(target, sha2.digest.str, length);
7472
+ /* copies 64 bits of randomness (8 bytes) repeatedly... */
7473
+ void fio_rand_bytes(void *data_, size_t len) {
7474
+ if (!data_ || !len)
7475
+ return;
7476
+ uint8_t *data = data_;
7477
+ /* unroll 32 bytes / 256 bit writes */
7478
+ for (size_t i = (len >> 5); i; --i) {
7479
+ const uint64_t t0 = fio_rand64();
7480
+ const uint64_t t1 = fio_rand64();
7481
+ const uint64_t t2 = fio_rand64();
7482
+ const uint64_t t3 = fio_rand64();
7483
+ fio_u2str64(data, t0);
7484
+ fio_u2str64(data + 8, t1);
7485
+ fio_u2str64(data + 16, t2);
7486
+ fio_u2str64(data + 24, t3);
7487
+ data += 32;
7488
+ }
7489
+ uint64_t tmp;
7490
+ /* 64 bit steps */
7491
+ switch (len & 24) {
7492
+ case 24:
7493
+ tmp = fio_rand64();
7494
+ fio_u2str64(data + 16, tmp);
7495
+ case 16: /* overflow */
7496
+ tmp = fio_rand64();
7497
+ fio_u2str64(data + 8, tmp);
7498
+ case 8: /* overflow */
7499
+ tmp = fio_rand64();
7500
+ fio_u2str64(data, tmp);
7501
+ data += len & 24;
7502
+ }
7503
+ if ((len & 7)) {
7504
+ tmp = fio_rand64();
7505
+ /* leftover bytes */
7506
+ switch ((len & 7)) {
7507
+ case 7: /* overflow */
7508
+ data[6] = (tmp >> 8) & 0xFF;
7509
+ case 6: /* overflow */
7510
+ data[5] = (tmp >> 16) & 0xFF;
7511
+ case 5: /* overflow */
7512
+ data[4] = (tmp >> 24) & 0xFF;
7513
+ case 4: /* overflow */
7514
+ data[3] = (tmp >> 32) & 0xFF;
7515
+ case 3: /* overflow */
7516
+ data[2] = (tmp >> 40) & 0xFF;
7517
+ case 2: /* overflow */
7518
+ data[1] = (tmp >> 48) & 0xFF;
7519
+ case 1: /* overflow */
7520
+ data[0] = (tmp >> 56) & 0xFF;
7521
+ }
7471
7522
  }
7472
7523
  }
7473
7524
 
@@ -110,7 +110,7 @@ Version and helper macros
110
110
  #define FIO_VERSION_MAJOR 0
111
111
  #define FIO_VERSION_MINOR 7
112
112
  #define FIO_VERSION_PATCH 0
113
- #define FIO_VERSION_BETA 7
113
+ #define FIO_VERSION_BETA 8
114
114
 
115
115
  /* Automatically convert version data to a string constant - ignore these two */
116
116
  #define FIO_MACRO2STR_STEP2(macro) #macro
@@ -264,6 +264,8 @@ C++ extern start
264
264
  /* support C++ */
265
265
  #ifdef __cplusplus
266
266
  extern "C" {
267
+ /* C++ keyword was deprecated */
268
+ #define register
267
269
  #endif
268
270
 
269
271
  /* *****************************************************************************
@@ -2206,7 +2208,8 @@ FIO_FUNC inline uintptr_t fio_ct_if2(uintptr_t cond, uintptr_t a, uintptr_t b) {
2206
2208
  ((i) >> ((-(bits)) & ((sizeof((i)) << 3) - 1))))
2207
2209
  /** unknown size element - right rotation, inlined. */
2208
2210
  #define fio_rrot(i, bits) \
2209
- (((i) >> (bits)) | ((i) << ((-(bits)) & ((sizeof((i)) << 3) - 1))))
2211
+ (((i) >> ((bits) & ((sizeof((i)) << 3) - 1))) | \
2212
+ ((i) << ((-(bits)) & ((sizeof((i)) << 3) - 1))))
2210
2213
 
2211
2214
  /** Converts an unaligned network ordered byte stream to a 16 bit number. */
2212
2215
  #define fio_str2u16(c) \
@@ -2401,104 +2404,108 @@ uint8_t __attribute__((weak)) fio_hash_secret_marker2;
2401
2404
  Risky Hash (always available, even if using only the fio.h header)
2402
2405
  ***************************************************************************** */
2403
2406
 
2404
- /**
2405
- * Computes a facil.io Risky Hash, modeled after the amazing
2406
- * [xxHash](https://github.com/Cyan4973/xxHash) (which has a BSD license)
2407
- * and named "Risky Hash" because writing your own hashing function is a risky
2408
- * business, full of pitfalls, hours of testing and security risks...
2409
- *
2410
- * Risky Hash isn't as battle tested as SipHash, but it did pass the
2411
- * [SMHasher](https://github.com/rurban/smhasher) tests with wonderful results,
2412
- * can be used for processing safe data and is easy (and short) to implement.
2413
- */
2414
- inline FIO_FUNC uintptr_t fio_risky_hash(const void *data_, size_t len,
2415
- uint64_t seed) {
2416
- /* The primes used by Risky Hash */
2417
- const uint64_t primes[] = {
2418
- 0xFBBA3FA15B22113B, // 1111101110111010001111111010000101011011001000100001000100111011
2419
- 0xAB137439982B86C9, // 1010101100010011011101000011100110011000001010111000011011001001
2420
- };
2421
- /* The consumption vectors initialized state */
2422
- uint64_t v[4] = {
2423
- seed ^ primes[1],
2424
- ~seed + primes[1],
2425
- fio_lrot64(seed, 17) ^ primes[1],
2426
- fio_lrot64(seed, 33) + primes[1],
2427
- };
2407
+ /* Risky Hash primes */
2408
+ #define RISKY_PRIME_0 0xFBBA3FA15B22113B
2409
+ #define RISKY_PRIME_1 0xAB137439982B86C9
2428
2410
 
2429
- /* Risky Hash consumption round */
2430
- #define fio_risky_consume(w, i) \
2431
- v[i] ^= (w); \
2432
- v[i] = fio_lrot64(v[i], 33) + (w); \
2433
- v[i] *= primes[0];
2434
-
2435
- /* compilers could, hopefully, optimize this code for SIMD */
2436
- #define fio_risky_consume256(w0, w1, w2, w3) \
2437
- fio_risky_consume(w0, 0); \
2438
- fio_risky_consume(w1, 1); \
2439
- fio_risky_consume(w2, 2); \
2440
- fio_risky_consume(w3, 3);
2411
+ /* Risky Hash consumption round, accepts a state word s and an input word w */
2412
+ #define fio_risky_consume(v, w) \
2413
+ (v) += (w); \
2414
+ (v) = fio_lrot64((v), 33); \
2415
+ (v) += (w); \
2416
+ (v) *= RISKY_PRIME_0;
2441
2417
 
2418
+ /* Computes a facil.io Risky Hash. */
2419
+ FIO_FUNC inline uint64_t fio_risky_hash(const void *data_, size_t len,
2420
+ uint64_t seed) {
2442
2421
  /* reading position */
2443
2422
  const uint8_t *data = (uint8_t *)data_;
2444
2423
 
2445
- /* consume 256bit blocks */
2424
+ /* The consumption vectors initialized state */
2425
+ register uint64_t v0 = seed ^ RISKY_PRIME_1;
2426
+ register uint64_t v1 = ~seed + RISKY_PRIME_1;
2427
+ register uint64_t v2 =
2428
+ fio_lrot64(seed, 17) ^ ((~RISKY_PRIME_1) + RISKY_PRIME_0);
2429
+ register uint64_t v3 = fio_lrot64(seed, 33) + (~RISKY_PRIME_1);
2430
+
2431
+ /* consume 256 bit blocks */
2446
2432
  for (size_t i = len >> 5; i; --i) {
2447
- fio_risky_consume256(fio_str2u64(data), fio_str2u64(data + 8),
2448
- fio_str2u64(data + 16), fio_str2u64(data + 24));
2433
+ fio_risky_consume(v0, fio_str2u64(data));
2434
+ fio_risky_consume(v1, fio_str2u64(data + 8));
2435
+ fio_risky_consume(v2, fio_str2u64(data + 16));
2436
+ fio_risky_consume(v3, fio_str2u64(data + 24));
2449
2437
  data += 32;
2450
2438
  }
2439
+
2451
2440
  /* Consume any remaining 64 bit words. */
2452
2441
  switch (len & 24) {
2453
2442
  case 24:
2454
- fio_risky_consume(fio_str2u64(data + 16), 2);
2443
+ fio_risky_consume(v2, fio_str2u64(data + 16));
2455
2444
  case 16: /* overflow */
2456
- fio_risky_consume(fio_str2u64(data + 8), 1);
2445
+ fio_risky_consume(v1, fio_str2u64(data + 8));
2457
2446
  case 8: /* overflow */
2458
- fio_risky_consume(fio_str2u64(data), 0);
2447
+ fio_risky_consume(v0, fio_str2u64(data));
2459
2448
  data += len & 24;
2460
2449
  }
2461
2450
 
2462
- uintptr_t tmp = 0;
2451
+ uint64_t tmp = 0;
2463
2452
  /* consume leftover bytes, if any */
2464
2453
  switch ((len & 7)) {
2465
2454
  case 7: /* overflow */
2466
- tmp |= ((uint64_t)data[6]) << 56;
2455
+ tmp |= ((uint64_t)data[6]) << 8;
2467
2456
  case 6: /* overflow */
2468
- tmp |= ((uint64_t)data[5]) << 48;
2457
+ tmp |= ((uint64_t)data[5]) << 16;
2469
2458
  case 5: /* overflow */
2470
- tmp |= ((uint64_t)data[4]) << 40;
2459
+ tmp |= ((uint64_t)data[4]) << 24;
2471
2460
  case 4: /* overflow */
2472
2461
  tmp |= ((uint64_t)data[3]) << 32;
2473
2462
  case 3: /* overflow */
2474
- tmp |= ((uint64_t)data[2]) << 24;
2463
+ tmp |= ((uint64_t)data[2]) << 40;
2475
2464
  case 2: /* overflow */
2476
- tmp |= ((uint64_t)data[1]) << 16;
2465
+ tmp |= ((uint64_t)data[1]) << 48;
2477
2466
  case 1: /* overflow */
2478
- tmp |= ((uint64_t)data[0]) << 8;
2479
- fio_risky_consume(tmp, 3);
2467
+ tmp |= ((uint64_t)data[0]) << 56;
2468
+ /* ((len >> 3) & 3) is a 0...3 value indicating consumption vector */
2469
+ switch ((len >> 3) & 3) {
2470
+ case 3:
2471
+ fio_risky_consume(v3, tmp);
2472
+ break;
2473
+ case 2:
2474
+ fio_risky_consume(v2, tmp);
2475
+ break;
2476
+ case 1:
2477
+ fio_risky_consume(v1, tmp);
2478
+ break;
2479
+ case 0:
2480
+ fio_risky_consume(v0, tmp);
2481
+ break;
2482
+ }
2480
2483
  }
2481
2484
 
2482
2485
  /* merge and mix */
2483
- uint64_t result = fio_lrot64(v[0], 17) + fio_lrot64(v[1], 13) +
2484
- fio_lrot64(v[2], 47) + fio_lrot64(v[3], 57);
2486
+ uint64_t result = fio_lrot64(v0, 17) + fio_lrot64(v1, 13) +
2487
+ fio_lrot64(v2, 47) + fio_lrot64(v3, 57);
2488
+
2489
+ len ^= (len << 33);
2485
2490
  result += len;
2486
- result += v[0] * primes[1];
2491
+
2492
+ result += v0 * RISKY_PRIME_1;
2487
2493
  result ^= fio_lrot64(result, 13);
2488
- result += v[1] * primes[1];
2494
+ result += v1 * RISKY_PRIME_1;
2489
2495
  result ^= fio_lrot64(result, 29);
2490
- result += v[2] * primes[1];
2496
+ result += v2 * RISKY_PRIME_1;
2491
2497
  result ^= fio_lrot64(result, 33);
2492
- result += v[3] * primes[1];
2498
+ result += v3 * RISKY_PRIME_1;
2493
2499
  result ^= fio_lrot64(result, 51);
2494
2500
 
2495
2501
  /* irreversible avalanche... I think */
2496
- result ^= (result >> 29) * primes[0];
2502
+ result ^= (result >> 29) * RISKY_PRIME_0;
2497
2503
  return result;
2504
+ }
2498
2505
 
2499
- #undef fio_risky_consume256
2500
2506
  #undef fio_risky_consume
2501
- }
2507
+ #undef FIO_RISKY_PRIME_0
2508
+ #undef FIO_RISKY_PRIME_1
2502
2509
 
2503
2510
  /* *****************************************************************************
2504
2511
  SipHash
@@ -166,6 +166,7 @@ int http_set_header2(http_s *r, fio_str_info_s n, fio_str_info_s v) {
166
166
  fiobj_free(tmp);
167
167
  return ret;
168
168
  }
169
+
169
170
  /**
170
171
  * Sets a response cookie, taking ownership of the value object, but NOT the
171
172
  * name object (so name objects could be reused in future responses).
@@ -189,102 +190,50 @@ int http_set_cookie(http_s *h, http_cookie_args_s cookie) {
189
190
  size_t len = 0;
190
191
  FIOBJ c = fiobj_str_buf(capa);
191
192
  fio_str_info_s t = fiobj_obj2cstr(c);
193
+
194
+ #define copy_cookie_ch(ch_var) \
195
+ if (invalid_cookie_##ch_var##_char[(uint8_t)cookie.ch_var[tmp]]) { \
196
+ if (!warn_illegal) { \
197
+ ++warn_illegal; \
198
+ FIO_LOG_WARNING("illegal char 0x%.2x in cookie " #ch_var " (in %s)\n" \
199
+ " automatic %% encoding applied", \
200
+ cookie.ch_var[tmp], cookie.ch_var); \
201
+ } \
202
+ t.data[len++] = '%'; \
203
+ t.data[len++] = hex_chars[((uint8_t)cookie.ch_var[tmp] >> 4) & 0x0F]; \
204
+ t.data[len++] = hex_chars[(uint8_t)cookie.ch_var[tmp] & 0x0F]; \
205
+ } else { \
206
+ t.data[len++] = cookie.ch_var[tmp]; \
207
+ } \
208
+ tmp += 1; \
209
+ if (capa <= len + 3) { \
210
+ capa += 32; \
211
+ fiobj_str_capa_assert(c, capa); \
212
+ t = fiobj_obj2cstr(c); \
213
+ }
214
+
192
215
  if (cookie.name) {
216
+ size_t tmp = 0;
193
217
  if (cookie.name_len) {
194
- size_t tmp = 0;
195
218
  while (tmp < cookie.name_len) {
196
- if (invalid_cookie_name_char[(uint8_t)cookie.name[tmp]]) {
197
- if (!warn_illegal) {
198
- ++warn_illegal;
199
- FIO_LOG_WARNING("illegal char 0x%.2x in cookie name (in %s)\n"
200
- " automatic %% encoding applied",
201
- cookie.name[tmp], cookie.name);
202
- }
203
- t.data[len++] = '%';
204
- t.data[len++] = hex_chars[(cookie.name[tmp] >> 4) & 0x0F];
205
- t.data[len++] = hex_chars[cookie.name[tmp] & 0x0F];
206
- } else {
207
- t.data[len++] = cookie.name[tmp];
208
- }
209
- tmp += 1;
210
- if (capa <= len + 3) {
211
- capa += 32;
212
- fiobj_str_capa_assert(c, capa);
213
- t = fiobj_obj2cstr(c);
214
- }
219
+ copy_cookie_ch(name);
215
220
  }
216
221
  } else {
217
- size_t tmp = 0;
218
222
  while (cookie.name[tmp]) {
219
- if (invalid_cookie_name_char[(uint8_t)cookie.name[tmp]]) {
220
- if (!warn_illegal) {
221
- ++warn_illegal;
222
- FIO_LOG_WARNING("illegal char 0x%.2x in cookie name (in %s)\n"
223
- " automatic %% encoding applied",
224
- cookie.name[tmp], cookie.name);
225
- }
226
- t.data[len++] = '%';
227
- t.data[len++] = hex_chars[(cookie.name[tmp] >> 4) & 0x0F];
228
- t.data[len++] = hex_chars[cookie.name[tmp] & 0x0F];
229
- } else {
230
- t.data[len++] = cookie.name[tmp];
231
- }
232
- tmp += 1;
233
- if (capa <= len + 4) {
234
- capa += 32;
235
- fiobj_str_capa_assert(c, capa);
236
- t = fiobj_obj2cstr(c);
237
- }
223
+ copy_cookie_ch(name);
238
224
  }
239
225
  }
240
226
  }
241
227
  t.data[len++] = '=';
242
228
  if (cookie.value) {
229
+ size_t tmp = 0;
243
230
  if (cookie.value_len) {
244
- size_t tmp = 0;
245
231
  while (tmp < cookie.value_len) {
246
- if (invalid_cookie_value_char[(uint8_t)cookie.value[tmp]]) {
247
- if (!warn_illegal) {
248
- ++warn_illegal;
249
- FIO_LOG_WARNING("illegal char 0x%.2x in cookie value (in %s)\n"
250
- " automatic %% encoding applied",
251
- cookie.value[tmp], cookie.name);
252
- }
253
- t.data[len++] = '%';
254
- t.data[len++] = hex_chars[(cookie.value[tmp] >> 4) & 0x0F];
255
- t.data[len++] = hex_chars[cookie.value[tmp] & 0x0F];
256
- } else {
257
- t.data[len++] = cookie.value[tmp];
258
- }
259
- tmp += 1;
260
- if (capa <= len + 3) {
261
- capa += 32;
262
- fiobj_str_capa_assert(c, capa);
263
- t = fiobj_obj2cstr(c);
264
- }
232
+ copy_cookie_ch(value);
265
233
  }
266
234
  } else {
267
- size_t tmp = 0;
268
235
  while (cookie.value[tmp]) {
269
- if (invalid_cookie_value_char[(uint8_t)cookie.value[tmp]]) {
270
- if (!warn_illegal) {
271
- ++warn_illegal;
272
- FIO_LOG_WARNING("illegal char 0x%.2x in cookie value (in %s)\n"
273
- " automatic %% encoding applied",
274
- cookie.value[tmp], cookie.name);
275
- }
276
- t.data[len++] = '%';
277
- t.data[len++] = hex_chars[(cookie.value[tmp] >> 4) & 0x0F];
278
- t.data[len++] = hex_chars[cookie.value[tmp] & 0x0F];
279
- } else {
280
- t.data[len++] = cookie.value[tmp];
281
- }
282
- tmp += 1;
283
- if (capa <= len + 3) {
284
- capa += 32;
285
- fiobj_str_capa_assert(c, capa);
286
- t = fiobj_obj2cstr(c);
287
- }
236
+ copy_cookie_ch(value);
288
237
  }
289
238
  }
290
239
  } else
@@ -1058,8 +1007,8 @@ intptr_t http_connect FIO_IGNORE_MACRO(const char *url,
1058
1007
  errno = EINVAL;
1059
1008
  goto on_error;
1060
1009
  }
1061
- size_t len;
1062
- char *a = NULL, *p = NULL;
1010
+ size_t len = 0, h_len = 0;
1011
+ char *a = NULL, *p = NULL, *host = NULL;
1063
1012
  uint8_t is_websocket = 0;
1064
1013
  uint8_t is_secure = 0;
1065
1014
  FIOBJ path = FIOBJ_INVALID;
@@ -1094,7 +1043,8 @@ intptr_t http_connect FIO_IGNORE_MACRO(const char *url,
1094
1043
  }
1095
1044
  if (unix_address) {
1096
1045
  a = (char *)unix_address;
1097
- len = strlen(a);
1046
+ h_len = len = strlen(a);
1047
+ host = a;
1098
1048
  } else {
1099
1049
  if (!u.host.data) {
1100
1050
  FIO_LOG_ERROR("http_connect requires a valid address.");
@@ -1122,6 +1072,10 @@ intptr_t http_connect FIO_IGNORE_MACRO(const char *url,
1122
1072
  p[2] = 0;
1123
1073
  }
1124
1074
  }
1075
+ if (u.host.data) {
1076
+ host = u.host.data;
1077
+ h_len = u.host.len;
1078
+ }
1125
1079
  }
1126
1080
 
1127
1081
  /* set settings */
@@ -1146,8 +1100,9 @@ intptr_t http_connect FIO_IGNORE_MACRO(const char *url,
1146
1100
  h->path = path;
1147
1101
  settings->udata = h;
1148
1102
  settings->tls = arg_settings.tls;
1149
- http_set_header2(h, (fio_str_info_s){.data = (char *)"host", .len = 4},
1150
- (fio_str_info_s){.data = a, .len = len});
1103
+ if (host)
1104
+ http_set_header2(h, (fio_str_info_s){.data = (char *)"host", .len = 4},
1105
+ (fio_str_info_s){.data = host, .len = h_len});
1151
1106
  intptr_t ret;
1152
1107
  if (is_websocket) {
1153
1108
  /* force HTTP/1.1 */
@@ -2496,42 +2451,53 @@ ssize_t http_decode_path_unsafe(char *dest, const char *url_data) {
2496
2451
  Lookup Tables / functions
2497
2452
  ***************************************************************************** */
2498
2453
 
2454
+ #define FIO_FORCE_MALLOC_TMP 1 /* use malloc for the mime registry */
2499
2455
  #define FIO_SET_NAME fio_mime_set
2500
2456
  #define FIO_SET_OBJ_TYPE FIOBJ
2501
2457
  #define FIO_SET_OBJ_COMPARE(o1, o2) (1)
2458
+ #define FIO_SET_OBJ_COPY(dest, o) (dest) = fiobj_dup((o))
2502
2459
  #define FIO_SET_OBJ_DESTROY(o) fiobj_free((o))
2503
2460
 
2504
2461
  #include <fio.h>
2505
2462
 
2506
- static fio_mime_set_s mime_types = FIO_SET_INIT;
2463
+ static fio_mime_set_s fio_http_mime_types = FIO_SET_INIT;
2507
2464
 
2508
2465
  #define LONGEST_FILE_EXTENSION_LENGTH 15
2509
2466
 
2510
2467
  /** Registers a Mime-Type to be associated with the file extension. */
2511
2468
  void http_mimetype_register(char *file_ext, size_t file_ext_len,
2512
2469
  FIOBJ mime_type_str) {
2513
- uintptr_t hash = fiobj_hash_string(file_ext, file_ext_len);
2470
+ uintptr_t hash = FIO_HASH_FN(file_ext, file_ext_len, 0, 0);
2514
2471
  if (mime_type_str == FIOBJ_INVALID) {
2515
- fio_mime_set_remove(&mime_types, hash, FIOBJ_INVALID, NULL);
2472
+ fio_mime_set_remove(&fio_http_mime_types, hash, FIOBJ_INVALID, NULL);
2516
2473
  } else {
2517
2474
  FIOBJ old = FIOBJ_INVALID;
2518
- fio_mime_set_overwrite(&mime_types, hash, mime_type_str, &old);
2475
+ fio_mime_set_overwrite(&fio_http_mime_types, hash, mime_type_str, &old);
2519
2476
  if (old != FIOBJ_INVALID) {
2520
2477
  FIO_LOG_WARNING("mime-type collision: %.*s was %s, now %s",
2521
2478
  (int)file_ext_len, file_ext, fiobj_obj2cstr(old).data,
2522
2479
  fiobj_obj2cstr(mime_type_str).data);
2523
2480
  fiobj_free(old);
2524
2481
  }
2482
+ fiobj_free(mime_type_str); /* move ownership to the registry */
2525
2483
  }
2526
2484
  }
2527
2485
 
2486
+ /** Registers a Mime-Type to be associated with the file extension. */
2487
+ void http_mimetype_stats(void) {
2488
+ FIO_LOG_DEBUG("HTTP MIME hash storage count/capa: %zu / %zu",
2489
+ fio_mime_set_count(&fio_http_mime_types),
2490
+ fio_mime_set_capa(&fio_http_mime_types));
2491
+ }
2492
+
2528
2493
  /**
2529
2494
  * Finds the mime-type associated with the file extension.
2530
2495
  * Remember to call `fiobj_free`.
2531
2496
  */
2532
2497
  FIOBJ http_mimetype_find(char *file_ext, size_t file_ext_len) {
2533
- uintptr_t hash = fiobj_hash_string(file_ext, file_ext_len);
2534
- return fiobj_dup(fio_mime_set_find(&mime_types, hash, FIOBJ_INVALID));
2498
+ uintptr_t hash = FIO_HASH_FN(file_ext, file_ext_len, 0, 0);
2499
+ return fiobj_dup(
2500
+ fio_mime_set_find(&fio_http_mime_types, hash, FIOBJ_INVALID));
2535
2501
  }
2536
2502
 
2537
2503
  /**
@@ -2574,7 +2540,7 @@ finish:
2574
2540
 
2575
2541
  /** Clears the Mime-Type registry (it will be empty afterthis call). */
2576
2542
  void http_mimetype_clear(void) {
2577
- fio_mime_set_free(&mime_types);
2543
+ fio_mime_set_free(&fio_http_mime_types);
2578
2544
  fiobj_free(current_date);
2579
2545
  current_date = FIOBJ_INVALID;
2580
2546
  last_date_added = 0;
@@ -147,6 +147,8 @@ static __attribute__((constructor)) void http_lib_constructor(void) {
147
147
  fio_state_callback_add(FIO_CALL_AT_EXIT, http_lib_cleanup, NULL);
148
148
  }
149
149
 
150
+ void http_mimetype_stats(void);
151
+
150
152
  static void http_lib_cleanup(void *ignr_) {
151
153
  (void)ignr_;
152
154
  http_mimetype_clear();
@@ -185,8 +187,11 @@ static void http_lib_cleanup(void *ignr_) {
185
187
  HTTPLIB_RESET(HTTP_HVALUE_WS_VERSION);
186
188
 
187
189
  #undef HTTPLIB_RESET
190
+ http_mimetype_stats();
188
191
  }
189
192
 
193
+ void http_mimetype_stats(void);
194
+
190
195
  static void http_lib_init(void *ignr_) {
191
196
  (void)ignr_;
192
197
  if (HTTP_HEADER_ACCEPT_RANGES)
@@ -1268,4 +1273,5 @@ static void http_lib_init(void *ignr_) {
1268
1273
  REGISTER_MIME("zirz", "application/vnd.zul");
1269
1274
  REGISTER_MIME("zmm", "application/vnd.handheld-entertainment+xml");
1270
1275
  #undef REGISTER_MIME
1276
+ http_mimetype_stats();
1271
1277
  }
@@ -233,9 +233,11 @@ static void iodine_print_startup_message(iodine_start_params_s params) {
233
233
  " * Iodine %s\n * Ruby %s\n"
234
234
  " * facil.io " FIO_VERSION_STRING " (%s)\n"
235
235
  " * %d Workers X %d Threads per worker.\n"
236
+ " * Maximum %zu open files / sockets per worker.\n"
236
237
  " * Master (root) process: %d.\n",
237
238
  StringValueCStr(iodine_version), StringValueCStr(ruby_version),
238
- fio_engine(), params.workers, params.threads, fio_parent_pid());
239
+ fio_engine(), params.workers, params.threads, fio_capa(),
240
+ fio_parent_pid());
239
241
  (void)params;
240
242
  }
241
243
 
@@ -391,8 +393,10 @@ static VALUE iodine_cli_parse(VALUE self) {
391
393
  FIO_CLI_STRING(
392
394
  "-tls-cert -cert the SSL/TLS public certificate file name."),
393
395
  FIO_CLI_STRING("-tls-key -key the SSL/TLS private key file name."),
394
- FIO_CLI_STRING("-tls-password the password (if any) protecting the "
395
- "private key file."),
396
+ FIO_CLI_STRING(
397
+ "-tls-pass -tls-password the password (if any) protecting the "
398
+ "private key file."),
399
+ FIO_CLI_PRINT("\t\t-tls-password is deprecated, use -tls-pass"),
396
400
  FIO_CLI_PRINT_HEADER("Connecting Iodine to Redis:"),
397
401
  FIO_CLI_STRING(
398
402
  "-redis -r an optional Redis URL server address. Default: none."),
@@ -409,10 +413,18 @@ static VALUE iodine_cli_parse(VALUE self) {
409
413
  if (level > 0 && level < 100)
410
414
  FIO_LOG_LEVEL = level;
411
415
  }
412
-
416
+ if (!fio_cli_get("-w") && getenv("WEB_CONCURRENCY")) {
417
+ fio_cli_set("-w", getenv("WEB_CONCURRENCY"));
418
+ }
419
+ if (!fio_cli_get("-w") && getenv("WORKERS")) {
420
+ fio_cli_set("-w", getenv("WORKERS"));
421
+ }
413
422
  if (fio_cli_get("-w")) {
414
423
  iodine_workers_set(IodineModule, INT2NUM(fio_cli_get_i("-w")));
415
424
  }
425
+ if (!fio_cli_get("-t") && getenv("THREADS")) {
426
+ fio_cli_set("-t", getenv("THREADS"));
427
+ }
416
428
  if (fio_cli_get("-t")) {
417
429
  iodine_threads_set(IodineModule, INT2NUM(fio_cli_get_i("-t")));
418
430
  }
@@ -422,6 +434,9 @@ static VALUE iodine_cli_parse(VALUE self) {
422
434
  if (fio_cli_get_bool("-warmup")) {
423
435
  rb_hash_aset(defaults, ID2SYM(rb_intern("warmup_")), Qtrue);
424
436
  }
437
+ // if (!fio_cli_get("-b") && getenv("ADDRESS")) {
438
+ // fio_cli_set("-b", getenv("ADDRESS"));
439
+ // }
425
440
  if (fio_cli_get("-b")) {
426
441
  if (fio_cli_get("-b")[0] == '/' ||
427
442
  (fio_cli_get("-b")[0] == '.' && fio_cli_get("-b")[1] == '/')) {
@@ -433,6 +448,10 @@ static VALUE iodine_cli_parse(VALUE self) {
433
448
  fio_cli_get("-p"));
434
449
  }
435
450
  fio_cli_set("-p", "0");
451
+ } else {
452
+ // if (!fio_cli_get("-p") && getenv("PORT")) {
453
+ // fio_cli_set("-p", getenv("PORT"));
454
+ // }
436
455
  }
437
456
  rb_hash_aset(defaults, address_sym, rb_str_new_cstr(fio_cli_get("-b")));
438
457
  }
@@ -484,7 +503,7 @@ static VALUE iodine_cli_parse(VALUE self) {
484
503
  }
485
504
  if (fio_cli_get("-tls-key") && fio_cli_get("-tls-cert")) {
486
505
  fio_tls_cert_add(tls, NULL, fio_cli_get("-tls-cert"),
487
- fio_cli_get("-tls-key"), fio_cli_get("-tls-password"));
506
+ fio_cli_get("-tls-key"), fio_cli_get("-tls-pass"));
488
507
  } else {
489
508
  if (!fio_cli_get_bool("-tls"))
490
509
  FIO_LOG_ERROR("TLS support requires both key and certificate."
@@ -240,17 +240,19 @@ static VALUE iodine_defer_run_after(VALUE self, VALUE milliseconds) {
240
240
  }
241
241
  return block;
242
242
  }
243
+
244
+ // clang-format off
243
245
  /**
244
246
  Runs the required block after the specified number of milliseconds have passed.
245
247
  Time is counted only once Iodine started running (using {Iodine.start}).
246
248
 
247
249
  Accepts:
248
250
 
249
- milliseconds:: the number of milliseconds between event repetitions.
250
-
251
- repetitions:: the number of event repetitions. Defaults to 0 (never ending).
252
-
253
- block:: (required) a block is required, as otherwise there is nothing to
251
+ | | |
252
+ |---|---|
253
+ | `:milliseconds` | the number of milliseconds between event repetitions.|
254
+ | `:repetitions` | the number of event repetitions. Defaults to 0 (never ending).|
255
+ | `:block` | (required) a block is required, as otherwise there is nothing to|
254
256
  perform.
255
257
 
256
258
  The event will repeat itself until the number of repetitions had been delpeted.
@@ -258,6 +260,7 @@ The event will repeat itself until the number of repetitions had been delpeted.
258
260
  Always returns a copy of the block object.
259
261
  */
260
262
  static VALUE iodine_defer_run_every(int argc, VALUE *argv, VALUE self) {
263
+ // clang-format on
261
264
  (void)(self);
262
265
  VALUE milliseconds, repetitions, block;
263
266
 
@@ -304,16 +307,18 @@ Sets a block of code to run when Iodine's core state is updated.
304
307
 
305
308
  The state event Symbol can be any of the following:
306
309
 
307
- :pre_start :: the block will be called once before starting up the IO reactor.
308
- :before_fork :: the block will be called before each time the IO reactor forks a new worker.
309
- :after_fork :: the block will be called after each fork (both in parent and workers).
310
- :enter_child :: the block will be called by a worker process right after forking.
311
- :enter_master :: the block will be called by the master process after spawning a worker (after forking).
312
- :on_start :: the block will be called every time a *worker* proceess starts. In single process mode, the master process is also a worker.
313
- :on_parent_crush :: the block will be called by each worker the moment it detects the master process crashed.
314
- :on_child_crush :: the block will be called by the parent (master) after a worker process crashed.
315
- :start_shutdown :: the block will be called before starting the shutdown sequence.
316
- :on_finish :: the block will be called just before finishing up (both on chlid and parent processes).
310
+ | | |
311
+ |---|---|
312
+ | `:pre_start` | the block will be called once before starting up the IO reactor. |
313
+ | `:before_fork` | the block will be called before each time the IO reactor forks a new worker. |
314
+ | `:after_fork` | the block will be called after each fork (both in parent and workers). |
315
+ | `:enter_child` | the block will be called by a worker process right after forking. |
316
+ | `:enter_master` | the block will be called by the master process after spawning a worker (after forking). |
317
+ | `:on_start` | the block will be called every time a *worker* proceess starts. In single process mode, the master process is also a worker. |
318
+ | `:on_parent_crush` | the block will be called by each worker the moment it detects the master process crashed. |
319
+ | `:on_child_crush` | the block will be called by the parent (master) after a worker process crashed. |
320
+ | `:start_shutdown` | the block will be called before starting the shutdown sequence. |
321
+ | `:on_finish` | the block will be called just before finishing up (both on chlid and parent processes). |
317
322
 
318
323
  Code runs in both the parent and the child.
319
324
  */
@@ -87,8 +87,7 @@ struct buffer_s resize_ws_buffer(ws_s *owner, struct buffer_s buff) {
87
87
  }
88
88
  void free_ws_buffer(ws_s *owner, struct buffer_s buff) {
89
89
  (void)(owner);
90
- if (buff.data)
91
- free(buff.data);
90
+ free(buff.data);
92
91
  }
93
92
 
94
93
  #undef round_up_buffer_size
@@ -1,3 +1,3 @@
1
1
  module Iodine
2
- VERSION = '0.7.18'.freeze
2
+ VERSION = '0.7.19'.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.18
4
+ version: 0.7.19
5
5
  platform: ruby
6
6
  authors:
7
7
  - Boaz Segev
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-01-18 00:00:00.000000000 Z
11
+ date: 2019-01-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -220,7 +220,7 @@ licenses:
220
220
  - MIT
221
221
  metadata:
222
222
  allowed_push_host: https://rubygems.org
223
- post_install_message: 'Thank you for installing Iodine 0.7.18.
223
+ post_install_message: 'Thank you for installing Iodine 0.7.19.
224
224
 
225
225
  '
226
226
  rdoc_options: []
@@ -243,8 +243,7 @@ requirements:
243
243
  - Ruby >= 2.2.2 required for Rack 2.
244
244
  - Ruby >= 2.5.0 recommended.
245
245
  - TLS requires OpenSSL >= 1.1.0
246
- rubyforge_project:
247
- rubygems_version: 2.7.7
246
+ rubygems_version: 3.0.1
248
247
  signing_key:
249
248
  specification_version: 4
250
249
  summary: iodine - a fast HTTP / Websocket Server with Pub/Sub support, optimized for