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 +4 -4
- data/CHANGELOG.md +12 -0
- data/exe/iodine +4 -4
- data/ext/iodine/fio.c +83 -32
- data/ext/iodine/fio.h +68 -61
- data/ext/iodine/http.c +58 -92
- data/ext/iodine/http_internal.c +6 -0
- data/ext/iodine/iodine.c +24 -5
- data/ext/iodine/iodine_defer.c +20 -15
- data/ext/iodine/websockets.c +1 -2
- data/lib/iodine/version.rb +1 -1
- metadata +4 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a17af3bcb580a2154bb0114bf9a0e5d8bb7b361a58c217dc4b9aa471cc328401
|
4
|
+
data.tar.gz: 55498d33417433697f9deeb3d864f12af3cccdeb7c7f1a0cec6eb7a83ccc4a84
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3ed48224b228669f024c592708b805a0057ce53e11113693515ba953f6780bf1d8f6aeb448291b9e1c01a7495aa44a4d36fea90303996ff72aa9850a7bead669
|
7
|
+
data.tar.gz: bee740562fe189778db55c83c616db4509a16196abf44a8bf1d135432c0e4b99277fe4c91472a76f265d3d68c70f3ad680c6b54dd0254bd5d455f8f219560d93
|
data/CHANGELOG.md
CHANGED
@@ -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.
|
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
|
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
|
data/ext/iodine/fio.c
CHANGED
@@ -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
|
-
|
7436
|
-
|
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
|
-
|
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
|
-
|
7442
|
-
|
7443
|
-
|
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
|
-
|
7448
|
-
|
7449
|
-
|
7450
|
-
|
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
|
-
|
7460
|
-
|
7461
|
-
|
7462
|
-
|
7463
|
-
|
7464
|
-
|
7465
|
-
|
7466
|
-
|
7467
|
-
|
7468
|
-
|
7469
|
-
|
7470
|
-
|
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
|
|
data/ext/iodine/fio.h
CHANGED
@@ -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
|
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) >> (
|
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
|
-
|
2406
|
-
|
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(
|
2431
|
-
v
|
2432
|
-
v
|
2433
|
-
v
|
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
|
-
/*
|
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
|
-
|
2448
|
-
|
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)
|
2443
|
+
fio_risky_consume(v2, fio_str2u64(data + 16));
|
2455
2444
|
case 16: /* overflow */
|
2456
|
-
fio_risky_consume(fio_str2u64(data + 8)
|
2445
|
+
fio_risky_consume(v1, fio_str2u64(data + 8));
|
2457
2446
|
case 8: /* overflow */
|
2458
|
-
fio_risky_consume(fio_str2u64(data)
|
2447
|
+
fio_risky_consume(v0, fio_str2u64(data));
|
2459
2448
|
data += len & 24;
|
2460
2449
|
}
|
2461
2450
|
|
2462
|
-
|
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]) <<
|
2455
|
+
tmp |= ((uint64_t)data[6]) << 8;
|
2467
2456
|
case 6: /* overflow */
|
2468
|
-
tmp |= ((uint64_t)data[5]) <<
|
2457
|
+
tmp |= ((uint64_t)data[5]) << 16;
|
2469
2458
|
case 5: /* overflow */
|
2470
|
-
tmp |= ((uint64_t)data[4]) <<
|
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]) <<
|
2463
|
+
tmp |= ((uint64_t)data[2]) << 40;
|
2475
2464
|
case 2: /* overflow */
|
2476
|
-
tmp |= ((uint64_t)data[1]) <<
|
2465
|
+
tmp |= ((uint64_t)data[1]) << 48;
|
2477
2466
|
case 1: /* overflow */
|
2478
|
-
tmp |= ((uint64_t)data[0]) <<
|
2479
|
-
|
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(
|
2484
|
-
fio_lrot64(
|
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
|
-
|
2491
|
+
|
2492
|
+
result += v0 * RISKY_PRIME_1;
|
2487
2493
|
result ^= fio_lrot64(result, 13);
|
2488
|
-
result +=
|
2494
|
+
result += v1 * RISKY_PRIME_1;
|
2489
2495
|
result ^= fio_lrot64(result, 29);
|
2490
|
-
result +=
|
2496
|
+
result += v2 * RISKY_PRIME_1;
|
2491
2497
|
result ^= fio_lrot64(result, 33);
|
2492
|
-
result +=
|
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) *
|
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
|
data/ext/iodine/http.c
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
1150
|
-
|
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
|
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 =
|
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(&
|
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(&
|
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 =
|
2534
|
-
return fiobj_dup(
|
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(&
|
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;
|
data/ext/iodine/http_internal.c
CHANGED
@@ -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
|
}
|
data/ext/iodine/iodine.c
CHANGED
@@ -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,
|
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(
|
395
|
-
|
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-
|
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."
|
data/ext/iodine/iodine_defer.c
CHANGED
@@ -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
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
block
|
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
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
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
|
*/
|
data/ext/iodine/websockets.c
CHANGED
data/lib/iodine/version.rb
CHANGED
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.
|
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-
|
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.
|
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
|
-
|
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
|