iodine 0.7.24 → 0.7.25
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 +6 -0
- data/ext/iodine/extconf.rb +68 -4
- data/ext/iodine/fio.c +83 -48
- data/ext/iodine/fio.h +23 -6
- data/ext/iodine/fio_tls_missing.c +1 -1
- data/ext/iodine/hpack.h +206 -60
- data/iodine.gemspec +1 -1
- data/lib/iodine.rb +17 -0
- data/lib/iodine/version.rb +1 -1
- data/lib/rack/handler/iodine.rb +1 -1
- metadata +3 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 78a87730fe356cbad1e97b0f8b236aa0d11922a5f4d9a2bc0dcd0b2d78ed76b9
|
4
|
+
data.tar.gz: 78867a8cb0fa36d09a642e1bde58226e7bc1db8286890d2fa393021607e05319
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c300c420d934e36214360481db13975971934d34566c172e301b3f9432263bdbb1a8fe3fec0002dab56485749cc49519d940735ef21d545b0b83fa5bd5cd024e
|
7
|
+
data.tar.gz: d38221c36a4a2c889d68e0992b8e1da0f62ad93a5114b4dc74953f72d5dd959bb71b82b3a28b2b2913b0251f983e8d30b5e0c7d4f9fb4b3e930f272e7424d9db
|
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,12 @@ 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.25
|
10
|
+
|
11
|
+
**Fix**: (`iodine`) fixed host name binding when running `iodine` using `rackup` or through `Rack`. Credit to @adam12 (Adam Daniels) for PR #60.
|
12
|
+
|
13
|
+
**Fix**: (`iodine`) removed bundler requirement in the `iodine.gemspec` file.
|
14
|
+
|
9
15
|
#### Change log v.0.7.24
|
10
16
|
|
11
17
|
**Fix**: (`fio`) fixed server shutdown on pub/sub stress, where internal pub/sub stress was mistakingly identified as a Slowloris attack. Credit to @moxgeek (Marouane Elmidaoui) for exposing this issue (plezi#32).
|
data/ext/iodine/extconf.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
require 'mkmf'
|
2
2
|
|
3
|
-
abort 'Missing a Linux/Unix OS evented API (epoll/kqueue).' unless have_func('kevent') || have_func('epoll_ctl')
|
4
|
-
|
5
3
|
if ENV['CC']
|
6
4
|
ENV['CPP'] ||= ENV['CC']
|
7
5
|
puts "detected user prefered compiler (#{ENV['CC']}):", `#{ENV['CC']} -v`
|
@@ -29,6 +27,72 @@ else
|
|
29
27
|
puts 'using an unknown (old?) compiler... who knows if this will work out... we hope.'
|
30
28
|
end
|
31
29
|
|
30
|
+
|
31
|
+
|
32
|
+
# Test polling
|
33
|
+
def iodine_test_polling_support
|
34
|
+
iodine_poll_test_kqueue = <<EOS
|
35
|
+
\#define _GNU_SOURCE
|
36
|
+
\#include <stdlib.h>
|
37
|
+
\#include <sys/event.h>
|
38
|
+
int main(void) {
|
39
|
+
int fd = kqueue();
|
40
|
+
}
|
41
|
+
EOS
|
42
|
+
|
43
|
+
iodine_poll_test_epoll = <<EOS
|
44
|
+
\#define _GNU_SOURCE
|
45
|
+
\#include <stdlib.h>
|
46
|
+
\#include <stdio.h>
|
47
|
+
\#include <sys/types.h>
|
48
|
+
\#include <sys/stat.h>
|
49
|
+
\#include <fcntl.h>
|
50
|
+
\#include <sys/epoll.h>
|
51
|
+
int main(void) {
|
52
|
+
int fd = epoll_create1(EPOLL_CLOEXEC);
|
53
|
+
}
|
54
|
+
EOS
|
55
|
+
|
56
|
+
iodine_poll_test_poll = <<EOS
|
57
|
+
\#define _GNU_SOURCE
|
58
|
+
\#include <stdlib.h>
|
59
|
+
\#include <poll.h>
|
60
|
+
int main(void) {
|
61
|
+
struct pollfd plist[18];
|
62
|
+
memset(plist, 0, sizeof(plist[0]) * 18);
|
63
|
+
poll(plist, 1, 1);
|
64
|
+
}
|
65
|
+
EOS
|
66
|
+
|
67
|
+
# Test for manual selection and then TRY_COMPILE with each polling engine
|
68
|
+
if ENV['FIO_POLL']
|
69
|
+
puts "skipping polling tests, enforcing manual selection of: poll"
|
70
|
+
$defs << "-DFIO_ENGINE_POLL"
|
71
|
+
elsif ENV['FIO_FORCE_POLL']
|
72
|
+
puts "skipping polling tests, enforcing manual selection of: poll"
|
73
|
+
$defs << "-DFIO_ENGINE_POLL"
|
74
|
+
elsif ENV['FIO_FORCE_EPOLL']
|
75
|
+
puts "skipping polling tests, enforcing manual selection of: epoll"
|
76
|
+
$defs << "-DFIO_ENGINE_EPOLL"
|
77
|
+
elsif ENV['FIO_FORCE_KQUEUE']
|
78
|
+
puts "* Skipping polling tests, enforcing manual selection of: kqueue"
|
79
|
+
$defs << "-DFIO_ENGINE_KQUEUE"
|
80
|
+
elsif try_compile(iodine_poll_test_epoll)
|
81
|
+
puts "detected `epoll`"
|
82
|
+
$defs << "-DFIO_ENGINE_EPOLL"
|
83
|
+
elsif try_compile(iodine_poll_test_kqueue)
|
84
|
+
puts "detected `kqueue`"
|
85
|
+
$defs << "-DFIO_ENGINE_KQUEUE"
|
86
|
+
elsif try_compile(iodine_poll_test_poll)
|
87
|
+
puts "detected `poll` - this is suboptimal fallback!"
|
88
|
+
$defs << "-DFIO_ENGINE_POLL"
|
89
|
+
else
|
90
|
+
puts "* WARNING: No supported polling engine! expecting compilation to fail."
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
iodine_test_polling_support()
|
95
|
+
|
32
96
|
# Test for OpenSSL version equal to 1.0.0 or greater.
|
33
97
|
unless ENV['NO_SSL'] || ENV['NO_TLS'] || ENV["DISABLE_SSL"]
|
34
98
|
OPENSSL_TEST_CODE = <<EOS
|
@@ -55,10 +119,10 @@ EOS
|
|
55
119
|
rescue LoadError
|
56
120
|
else
|
57
121
|
if have_library('crypto') && have_library('ssl')
|
58
|
-
puts "
|
122
|
+
puts "detected OpenSSL library, testing for version and required functions."
|
59
123
|
if try_compile(OPENSSL_TEST_CODE)
|
60
124
|
$defs << "-DHAVE_OPENSSL"
|
61
|
-
puts "
|
125
|
+
puts "confirmed OpenSSL to be version 1.1.0 or above (#{OpenSSL::OPENSSL_LIBRARY_VERSION})...\n* compiling with HAVE_OPENSSL."
|
62
126
|
else
|
63
127
|
puts "FAILED: OpenSSL version not supported (#{OpenSSL::OPENSSL_LIBRARY_VERSION} is too old)."
|
64
128
|
end
|
data/ext/iodine/fio.c
CHANGED
@@ -44,7 +44,8 @@ Feel free to copy, use and enjoy according to the license provided.
|
|
44
44
|
#if !FIO_ENGINE_POLL && !FIO_ENGINE_EPOLL && !FIO_ENGINE_KQUEUE
|
45
45
|
#if defined(__linux__)
|
46
46
|
#define FIO_ENGINE_EPOLL 1
|
47
|
-
#elif defined(__APPLE__) || defined(
|
47
|
+
#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
|
48
|
+
defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__)
|
48
49
|
#define FIO_ENGINE_KQUEUE 1
|
49
50
|
#else
|
50
51
|
#define FIO_ENGINE_POLL 1
|
@@ -1345,6 +1346,15 @@ Section Start Marker
|
|
1345
1346
|
|
1346
1347
|
volatile uint8_t fio_signal_children_flag = 0;
|
1347
1348
|
|
1349
|
+
/* store old signal handlers to propegate signal handling */
|
1350
|
+
static struct sigaction fio_old_sig_chld;
|
1351
|
+
static struct sigaction fio_old_sig_pipe;
|
1352
|
+
static struct sigaction fio_old_sig_term;
|
1353
|
+
static struct sigaction fio_old_sig_int;
|
1354
|
+
#if !FIO_DISABLE_HOT_RESTART
|
1355
|
+
static struct sigaction fio_old_sig_usr1;
|
1356
|
+
#endif
|
1357
|
+
|
1348
1358
|
/*
|
1349
1359
|
* Zombie Reaping
|
1350
1360
|
* With thanks to Dr Graham D Shaw.
|
@@ -1356,15 +1366,20 @@ static void reap_child_handler(int sig) {
|
|
1356
1366
|
while (waitpid(-1, NULL, WNOHANG) > 0)
|
1357
1367
|
;
|
1358
1368
|
errno = old_errno;
|
1369
|
+
if (fio_old_sig_chld.sa_handler != SIG_IGN &&
|
1370
|
+
fio_old_sig_chld.sa_handler != SIG_DFL)
|
1371
|
+
fio_old_sig_chld.sa_handler(sig);
|
1359
1372
|
}
|
1360
1373
|
|
1361
1374
|
/* initializes zombie reaping for the process */
|
1362
1375
|
void fio_reap_children(void) {
|
1363
1376
|
struct sigaction sa;
|
1377
|
+
if (fio_old_sig_chld.sa_handler)
|
1378
|
+
return;
|
1364
1379
|
sa.sa_handler = reap_child_handler;
|
1365
1380
|
sigemptyset(&sa.sa_mask);
|
1366
1381
|
sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;
|
1367
|
-
if (sigaction(SIGCHLD, &sa,
|
1382
|
+
if (sigaction(SIGCHLD, &sa, &fio_old_sig_chld) == -1) {
|
1368
1383
|
perror("Child reaping initialization failed");
|
1369
1384
|
kill(0, SIGINT);
|
1370
1385
|
exit(errno);
|
@@ -1373,66 +1388,87 @@ void fio_reap_children(void) {
|
|
1373
1388
|
|
1374
1389
|
/* handles the SIGUSR1, SIGINT and SIGTERM signals. */
|
1375
1390
|
static void sig_int_handler(int sig) {
|
1391
|
+
struct sigaction *old = NULL;
|
1376
1392
|
switch (sig) {
|
1377
1393
|
#if !FIO_DISABLE_HOT_RESTART
|
1378
1394
|
case SIGUSR1:
|
1379
1395
|
fio_signal_children_flag = 1;
|
1396
|
+
old = &fio_old_sig_usr1;
|
1380
1397
|
break;
|
1381
1398
|
#endif
|
1382
|
-
case SIGINT:
|
1399
|
+
case SIGINT: /* fallthrough */
|
1400
|
+
if (!old)
|
1401
|
+
old = &fio_old_sig_int;
|
1383
1402
|
case SIGTERM: /* fallthrough */
|
1403
|
+
if (!old)
|
1404
|
+
old = &fio_old_sig_term;
|
1384
1405
|
fio_stop();
|
1385
1406
|
break;
|
1407
|
+
case SIGPIPE: /* fallthrough */
|
1408
|
+
if (!old)
|
1409
|
+
old = &fio_old_sig_pipe;
|
1386
1410
|
default:
|
1387
1411
|
break;
|
1388
1412
|
}
|
1413
|
+
/* propagate signale handling to previous existing handler (if any) */
|
1414
|
+
if (old->sa_handler != SIG_IGN && old->sa_handler != SIG_DFL)
|
1415
|
+
old->sa_handler(sig);
|
1389
1416
|
}
|
1390
1417
|
|
1391
1418
|
/* setup handling for the SIGUSR1, SIGPIPE, SIGINT and SIGTERM signals. */
|
1392
1419
|
static void fio_signal_handler_setup(void) {
|
1393
1420
|
/* setup signal handling */
|
1394
|
-
struct sigaction act
|
1395
|
-
|
1396
|
-
|
1421
|
+
struct sigaction act;
|
1422
|
+
if (fio_old_sig_int.sa_handler)
|
1423
|
+
return;
|
1424
|
+
|
1425
|
+
memset(&act, 0, sizeof(act));
|
1397
1426
|
|
1398
1427
|
act.sa_handler = sig_int_handler;
|
1399
1428
|
sigemptyset(&act.sa_mask);
|
1400
1429
|
act.sa_flags = SA_RESTART | SA_NOCLDSTOP;
|
1401
1430
|
|
1402
|
-
if (sigaction(SIGINT, &act, &
|
1431
|
+
if (sigaction(SIGINT, &act, &fio_old_sig_int)) {
|
1403
1432
|
perror("couldn't set signal handler");
|
1404
1433
|
return;
|
1405
1434
|
};
|
1406
1435
|
|
1407
|
-
if (sigaction(SIGTERM, &act, &
|
1436
|
+
if (sigaction(SIGTERM, &act, &fio_old_sig_term)) {
|
1408
1437
|
perror("couldn't set signal handler");
|
1409
1438
|
return;
|
1410
1439
|
};
|
1411
1440
|
#if !FIO_DISABLE_HOT_RESTART
|
1412
|
-
if (sigaction(SIGUSR1, &act, &
|
1441
|
+
if (sigaction(SIGUSR1, &act, &fio_old_sig_usr1)) {
|
1413
1442
|
perror("couldn't set signal handler");
|
1414
1443
|
return;
|
1415
1444
|
};
|
1416
1445
|
#endif
|
1417
1446
|
|
1418
1447
|
act.sa_handler = SIG_IGN;
|
1419
|
-
if (sigaction(SIGPIPE, &act, &
|
1448
|
+
if (sigaction(SIGPIPE, &act, &fio_old_sig_pipe)) {
|
1420
1449
|
perror("couldn't set signal handler");
|
1421
1450
|
return;
|
1422
1451
|
};
|
1423
1452
|
}
|
1424
|
-
|
1425
|
-
|
1426
|
-
|
1453
|
+
|
1454
|
+
void fio_signal_handler_reset(void) {
|
1455
|
+
struct sigaction old;
|
1456
|
+
if (!fio_old_sig_int.sa_handler)
|
1457
|
+
return;
|
1427
1458
|
memset(&old, 0, sizeof(old));
|
1428
|
-
|
1429
|
-
|
1430
|
-
sigaction(
|
1431
|
-
|
1459
|
+
sigaction(SIGINT, &fio_old_sig_int, &old);
|
1460
|
+
sigaction(SIGTERM, &fio_old_sig_term, &old);
|
1461
|
+
sigaction(SIGPIPE, &fio_old_sig_pipe, &old);
|
1462
|
+
if (fio_old_sig_chld.sa_handler)
|
1463
|
+
sigaction(SIGCHLD, &fio_old_sig_chld, &old);
|
1432
1464
|
#if !FIO_DISABLE_HOT_RESTART
|
1433
|
-
sigaction(SIGUSR1, &
|
1465
|
+
sigaction(SIGUSR1, &fio_old_sig_usr1, &old);
|
1466
|
+
memset(&fio_old_sig_usr1, 0, sizeof(fio_old_sig_usr1));
|
1434
1467
|
#endif
|
1435
|
-
|
1468
|
+
memset(&fio_old_sig_int, 0, sizeof(fio_old_sig_int));
|
1469
|
+
memset(&fio_old_sig_term, 0, sizeof(fio_old_sig_term));
|
1470
|
+
memset(&fio_old_sig_pipe, 0, sizeof(fio_old_sig_pipe));
|
1471
|
+
memset(&fio_old_sig_chld, 0, sizeof(fio_old_sig_chld));
|
1436
1472
|
}
|
1437
1473
|
|
1438
1474
|
/**
|
@@ -2552,17 +2588,17 @@ Internal socket flushing related functions
|
|
2552
2588
|
#define BUFFER_FILE_READ_SIZE 49152
|
2553
2589
|
#endif
|
2554
2590
|
|
2555
|
-
#
|
2556
|
-
|
2591
|
+
#if !defined(USE_SENDFILE) && !defined(USE_SENDFILE_LINUX) && \
|
2592
|
+
!defined(USE_SENDFILE_BSD) && !defined(USE_SENDFILE_APPLE)
|
2557
2593
|
#if defined(__linux__) /* linux sendfile works */
|
2558
2594
|
#include <sys/sendfile.h>
|
2559
|
-
#define
|
2560
|
-
#elif defined(
|
2595
|
+
#define USE_SENDFILE_LINUX 1
|
2596
|
+
#elif defined(__FreeBSD__) /* FreeBSD sendfile should work - not tested */
|
2561
2597
|
#include <sys/uio.h>
|
2562
|
-
#define
|
2598
|
+
#define USE_SENDFILE_BSD 1
|
2563
2599
|
#elif defined(__APPLE__) /* Is the apple sendfile still broken? */
|
2564
2600
|
#include <sys/uio.h>
|
2565
|
-
#define
|
2601
|
+
#define USE_SENDFILE_APPLE 2
|
2566
2602
|
#else /* sendfile might not be available - always set to 0 */
|
2567
2603
|
#define USE_SENDFILE 0
|
2568
2604
|
#endif
|
@@ -2638,7 +2674,7 @@ read_error:
|
|
2638
2674
|
return -1;
|
2639
2675
|
}
|
2640
2676
|
|
2641
|
-
#if
|
2677
|
+
#if USE_SENDFILE_LINUX /* linux sendfile API */
|
2642
2678
|
|
2643
2679
|
static int fio_sock_sendfile_from_fd(int fd, fio_packet_s *packet) {
|
2644
2680
|
ssize_t sent;
|
@@ -2652,15 +2688,14 @@ static int fio_sock_sendfile_from_fd(int fd, fio_packet_s *packet) {
|
|
2652
2688
|
return sent;
|
2653
2689
|
}
|
2654
2690
|
|
2655
|
-
#elif
|
2656
|
-
(defined(__APPLE__) || defined(__unix__)) /* BSD / Apple API */
|
2691
|
+
#elif USE_SENDFILE_LINUX_BSD || USE_SENDFILE_APPLE /* FreeBSD / Apple API */
|
2657
2692
|
|
2658
2693
|
static int fio_sock_sendfile_from_fd(int fd, fio_packet_s *packet) {
|
2659
2694
|
off_t act_sent = 0;
|
2660
2695
|
ssize_t ret = 0;
|
2661
2696
|
while (packet->length) {
|
2662
2697
|
act_sent = packet->length;
|
2663
|
-
#if
|
2698
|
+
#if USE_SENDFILE_APPLE
|
2664
2699
|
ret = sendfile(packet->data.fd, fd, packet->offset, &act_sent, NULL, 0);
|
2665
2700
|
#else
|
2666
2701
|
ret = sendfile(packet->data.fd, fd, packet->offset, (size_t)act_sent, NULL,
|
@@ -2682,8 +2717,8 @@ error:
|
|
2682
2717
|
}
|
2683
2718
|
|
2684
2719
|
#else
|
2685
|
-
static int (*
|
2686
|
-
|
2720
|
+
static int (*fio_sock_sendfile_from_fd)(int fd, struct packet_s *packet) =
|
2721
|
+
fio_sock_write_from_fd;
|
2687
2722
|
|
2688
2723
|
#endif
|
2689
2724
|
|
@@ -3541,23 +3576,23 @@ static void __attribute__((constructor)) fio_lib_init(void) {
|
|
3541
3576
|
fio_pubsub_initialize();
|
3542
3577
|
#if DEBUG
|
3543
3578
|
#if FIO_ENGINE_POLL
|
3544
|
-
|
3545
|
-
|
3546
|
-
|
3547
|
-
|
3548
|
-
|
3549
|
-
|
3550
|
-
|
3551
|
-
|
3552
|
-
|
3579
|
+
FIO_LOG_INFO("facil.io " FIO_VERSION_STRING " capacity initialization:\n"
|
3580
|
+
"* Meximum open files %zu out of %zu\n"
|
3581
|
+
"* Allocating %zu bytes for state handling.\n"
|
3582
|
+
"* %zu bytes per connection + %zu for state handling.",
|
3583
|
+
capa, (size_t)rlim.rlim_max,
|
3584
|
+
(sizeof(*fio_data) + (capa * (sizeof(*fio_data->poll))) +
|
3585
|
+
(capa * (sizeof(*fio_data->info)))),
|
3586
|
+
(sizeof(*fio_data->poll) + sizeof(*fio_data->info)),
|
3587
|
+
sizeof(*fio_data));
|
3553
3588
|
#else
|
3554
|
-
|
3555
|
-
|
3556
|
-
|
3557
|
-
|
3558
|
-
|
3559
|
-
|
3560
|
-
|
3589
|
+
FIO_LOG_INFO("facil.io " FIO_VERSION_STRING " capacity initialization:\n"
|
3590
|
+
"* Meximum open files %zu out of %zu\n"
|
3591
|
+
"* Allocating %zu bytes for state handling.\n"
|
3592
|
+
"* %zu bytes per connection + %zu for state handling.",
|
3593
|
+
capa, (size_t)rlim.rlim_max,
|
3594
|
+
(sizeof(*fio_data) + (capa * (sizeof(*fio_data->info)))),
|
3595
|
+
(sizeof(*fio_data->info)), sizeof(*fio_data));
|
3561
3596
|
#endif
|
3562
3597
|
#endif
|
3563
3598
|
}
|
@@ -3874,7 +3909,7 @@ void fio_start FIO_IGNORE_MACRO(struct fio_start_args args) {
|
|
3874
3909
|
|
3875
3910
|
fio_state_callback_force(FIO_CALL_PRE_START);
|
3876
3911
|
|
3877
|
-
|
3912
|
+
FIO_LOG_INFO(
|
3878
3913
|
"Server is running %u %s X %u %s with facil.io " FIO_VERSION_STRING
|
3879
3914
|
" (%s)\n"
|
3880
3915
|
"* Detected capacity: %d open file limit\n"
|
data/ext/iodine/fio.h
CHANGED
@@ -168,10 +168,10 @@ Version and helper macros
|
|
168
168
|
|
169
169
|
#ifndef FIO_PRINT_STATE
|
170
170
|
/**
|
171
|
-
* Enables the FIO_LOG_STATE(msg,...) macro, which prints information
|
172
|
-
* messages to stderr.
|
171
|
+
* Enables the depraceted FIO_LOG_STATE(msg,...) macro, which prints information
|
172
|
+
* level messages to stderr.
|
173
173
|
*/
|
174
|
-
#define FIO_PRINT_STATE
|
174
|
+
#define FIO_PRINT_STATE 0
|
175
175
|
#endif
|
176
176
|
|
177
177
|
#ifndef FIO_PUBSUB_SUPPORT
|
@@ -463,7 +463,9 @@ int __attribute__((weak)) FIO_LOG_LEVEL;
|
|
463
463
|
#endif
|
464
464
|
|
465
465
|
#if FIO_PRINT_STATE
|
466
|
-
#define FIO_LOG_STATE(...)
|
466
|
+
#define FIO_LOG_STATE(...) \
|
467
|
+
FIO_LOG_PRINT(FIO_LOG_LEVEL_INFO, \
|
468
|
+
"WARNING: FIO_LOG_STATE is deprecated\n" __VA_ARGS__)
|
467
469
|
#else
|
468
470
|
#define FIO_LOG_STATE(...)
|
469
471
|
#endif
|
@@ -987,6 +989,18 @@ pid_t fio_parent_pid(void);
|
|
987
989
|
*/
|
988
990
|
void fio_reap_children(void);
|
989
991
|
|
992
|
+
/**
|
993
|
+
* Resets any existing signal handlers, restoring their state to before they
|
994
|
+
* were set by facil.io.
|
995
|
+
*
|
996
|
+
* This stops both child reaping (`fio_reap_children`) and the default facil.io
|
997
|
+
* signal handlers (i.e., CTRL-C).
|
998
|
+
*
|
999
|
+
* This function will be called automatically by facil.io whenever facil.io
|
1000
|
+
* stops.
|
1001
|
+
*/
|
1002
|
+
void fio_signal_handler_reset(void);
|
1003
|
+
|
990
1004
|
/**
|
991
1005
|
* Returns the last time the server reviewed any pending IO events.
|
992
1006
|
*/
|
@@ -2159,8 +2173,9 @@ FIO_FUNC inline uintptr_t fio_ct_if2(uintptr_t cond, uintptr_t a, uintptr_t b) {
|
|
2159
2173
|
#endif
|
2160
2174
|
|
2161
2175
|
/* Note: using BIG_ENDIAN invokes false positives on some systems */
|
2162
|
-
#if
|
2163
|
-
|
2176
|
+
#if !defined(__BIG_ENDIAN__)
|
2177
|
+
/* nothing to do */
|
2178
|
+
#elif (defined(__LITTLE_ENDIAN__) && !__LITTLE_ENDIAN__) || \
|
2164
2179
|
(defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
|
2165
2180
|
#define __BIG_ENDIAN__ 1
|
2166
2181
|
#elif !defined(__BIG_ENDIAN__) && !defined(__BYTE_ORDER__) && \
|
@@ -2208,12 +2223,14 @@ FIO_FUNC inline uintptr_t fio_ct_if2(uintptr_t cond, uintptr_t a, uintptr_t b) {
|
|
2208
2223
|
/** 32Bit right rotation, inlined. */
|
2209
2224
|
#define fio_rrot32(i, bits) \
|
2210
2225
|
(((uint32_t)(i) >> ((bits)&31UL)) | ((uint32_t)(i) << ((-(bits)) & 31UL)))
|
2226
|
+
|
2211
2227
|
/** 64Bit left rotation, inlined. */
|
2212
2228
|
#define fio_lrot64(i, bits) \
|
2213
2229
|
(((uint64_t)(i) << ((bits)&63UL)) | ((uint64_t)(i) >> ((-(bits)) & 63UL)))
|
2214
2230
|
/** 64Bit right rotation, inlined. */
|
2215
2231
|
#define fio_rrot64(i, bits) \
|
2216
2232
|
(((uint64_t)(i) >> ((bits)&63UL)) | ((uint64_t)(i) << ((-(bits)) & 63UL)))
|
2233
|
+
|
2217
2234
|
/** unknown size element - left rotation, inlined. */
|
2218
2235
|
#define fio_lrot(i, bits) \
|
2219
2236
|
(((i) << ((bits) & ((sizeof((i)) << 3) - 1))) | \
|
@@ -134,7 +134,7 @@ static inline void fio_alpn_destroy(alpn_s *obj) {
|
|
134
134
|
#include <fio.h>
|
135
135
|
|
136
136
|
/* *****************************************************************************
|
137
|
-
The SSL/TLS type
|
137
|
+
The SSL/TLS Context type
|
138
138
|
***************************************************************************** */
|
139
139
|
|
140
140
|
/** An opaque type used for the SSL/TLS functions. */
|
data/ext/iodine/hpack.h
CHANGED
@@ -27,32 +27,22 @@
|
|
27
27
|
#define HPACK_MAX_TABLE_SIZE 65535
|
28
28
|
|
29
29
|
/* *****************************************************************************
|
30
|
-
|
30
|
+
Required Callbacks
|
31
31
|
***************************************************************************** */
|
32
32
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
uint8_t data[];
|
37
|
-
} sstring_s;
|
38
|
-
|
39
|
-
/** An HTTP/2 Header */
|
40
|
-
typedef struct http2_header_s {
|
41
|
-
sstring_s *name;
|
42
|
-
sstring_s *value;
|
43
|
-
} http2_header_s;
|
44
|
-
|
45
|
-
/** An HTTP/2 Header Collection */
|
46
|
-
typedef struct http2_header_array_s {
|
47
|
-
size_t len;
|
48
|
-
http2_header_s headers[];
|
49
|
-
} http2_header_array_s;
|
33
|
+
/* *****************************************************************************
|
34
|
+
Types
|
35
|
+
***************************************************************************** */
|
50
36
|
|
51
37
|
/** The HPACK context. */
|
52
38
|
typedef struct hpack_context_s hpack_context_s;
|
53
39
|
|
54
40
|
/* *****************************************************************************
|
55
|
-
API
|
41
|
+
Context API
|
42
|
+
***************************************************************************** */
|
43
|
+
|
44
|
+
/* *****************************************************************************
|
45
|
+
Primitive Types API
|
56
46
|
***************************************************************************** */
|
57
47
|
|
58
48
|
/**
|
@@ -98,6 +88,70 @@ static inline int hpack_string_pack(void *dest, size_t limit, void *data,
|
|
98
88
|
static inline int hpack_string_unpack(void *dest, size_t limit, void *encoded,
|
99
89
|
size_t len, size_t *pos);
|
100
90
|
|
91
|
+
/* *****************************************************************************
|
92
|
+
Static table API
|
93
|
+
***************************************************************************** */
|
94
|
+
|
95
|
+
/**
|
96
|
+
* Sets the provided pointers with the information in the static header table.
|
97
|
+
*
|
98
|
+
* The `index` is 1..61 (not zero based).
|
99
|
+
*
|
100
|
+
* Set `get_value` to 1 to collect the value data rather then the header name.
|
101
|
+
*
|
102
|
+
* Returns -1 if request is out of bounds.
|
103
|
+
*/
|
104
|
+
static int hpack_header_static_find(uint8_t index, uint8_t get_value,
|
105
|
+
const char **name, size_t *len);
|
106
|
+
|
107
|
+
/* *****************************************************************************
|
108
|
+
Huffman API (internal)
|
109
|
+
***************************************************************************** */
|
110
|
+
|
111
|
+
/* the huffman encoding map */
|
112
|
+
typedef const struct {
|
113
|
+
const uint32_t code;
|
114
|
+
const uint8_t bits;
|
115
|
+
} huffman_encode_s;
|
116
|
+
static const huffman_encode_s huffman_encode_table[];
|
117
|
+
|
118
|
+
/* the huffman decoding binary tree type */
|
119
|
+
typedef struct {
|
120
|
+
const int16_t value; // value, -1 == none.
|
121
|
+
const uint8_t offset[2]; // offset for 0 and one. 0 == leaf node.
|
122
|
+
} huffman_decode_s;
|
123
|
+
static const huffman_decode_s huffman_decode_tree[];
|
124
|
+
|
125
|
+
/**
|
126
|
+
* Unpack (de-compress) using HPACK huffman - returns the number of bytes
|
127
|
+
* written and advances the position marker.
|
128
|
+
*/
|
129
|
+
static MAYBE_UNUSED int hpack_huffman_unpack(void *dest, size_t limit,
|
130
|
+
void *encoded, size_t len,
|
131
|
+
size_t *pos);
|
132
|
+
|
133
|
+
/**
|
134
|
+
* Pack (compress) using HPACK huffman - returns the number of bytes written or
|
135
|
+
* required.
|
136
|
+
*/
|
137
|
+
static MAYBE_UNUSED int hpack_huffman_pack(void *dest, const int limit,
|
138
|
+
void *data, size_t len);
|
139
|
+
|
140
|
+
/* *****************************************************************************
|
141
|
+
|
142
|
+
|
143
|
+
|
144
|
+
|
145
|
+
|
146
|
+
Implementation
|
147
|
+
|
148
|
+
|
149
|
+
|
150
|
+
|
151
|
+
|
152
|
+
|
153
|
+
***************************************************************************** */
|
154
|
+
|
101
155
|
/* *****************************************************************************
|
102
156
|
Integer encoding
|
103
157
|
***************************************************************************** */
|
@@ -185,39 +239,6 @@ static inline int64_t hpack_int_unpack(void *data_, size_t len, uint8_t prefix,
|
|
185
239
|
return (int64_t)result;
|
186
240
|
}
|
187
241
|
|
188
|
-
/* *****************************************************************************
|
189
|
-
Huffman (internal API)
|
190
|
-
***************************************************************************** */
|
191
|
-
|
192
|
-
/* the huffman encoding map */
|
193
|
-
typedef const struct {
|
194
|
-
const uint32_t code;
|
195
|
-
const uint8_t bits;
|
196
|
-
} huffman_encode_s;
|
197
|
-
static const huffman_encode_s huffman_encode_table[];
|
198
|
-
|
199
|
-
/* the huffman decoding binary tree type */
|
200
|
-
typedef struct {
|
201
|
-
const int16_t value; // value, -1 == none.
|
202
|
-
const uint8_t offset[2]; // offset for 0 and one. 0 == leaf node.
|
203
|
-
} huffman_decode_s;
|
204
|
-
static const huffman_decode_s huffman_decode_tree[];
|
205
|
-
|
206
|
-
/**
|
207
|
-
* Unpack (de-compress) using HPACK huffman - returns the number of bytes
|
208
|
-
* written and advances the position marker.
|
209
|
-
*/
|
210
|
-
static MAYBE_UNUSED int hpack_huffman_unpack(void *dest, size_t limit,
|
211
|
-
void *encoded, size_t len,
|
212
|
-
size_t *pos);
|
213
|
-
|
214
|
-
/**
|
215
|
-
* Pack (compress) using HPACK huffman - returns the number of bytes written or
|
216
|
-
* required.
|
217
|
-
*/
|
218
|
-
static MAYBE_UNUSED int hpack_huffman_pack(void *dest, const int limit,
|
219
|
-
void *data, size_t len);
|
220
|
-
|
221
242
|
/* *****************************************************************************
|
222
243
|
String encoding
|
223
244
|
***************************************************************************** */
|
@@ -402,9 +423,111 @@ calc_final_length:
|
|
402
423
|
}
|
403
424
|
|
404
425
|
/* *****************************************************************************
|
426
|
+
Header static table lookup
|
427
|
+
***************************************************************************** */
|
428
|
+
|
429
|
+
const static struct {
|
430
|
+
struct hpack_static_data_s {
|
431
|
+
const char *val;
|
432
|
+
const size_t len;
|
433
|
+
} data[2];
|
434
|
+
} MAYBE_UNUSED hpack_static_table[] = {
|
435
|
+
/* [0] */ {.data = {{.len = 0}, {.len = 0}}},
|
436
|
+
{.data = {{.val = ":authority", .len = 10}, {.len = 0}}},
|
437
|
+
{.data = {{.val = ":method", .len = 7}, {.val = "GET", .len = 3}}},
|
438
|
+
{.data = {{.val = ":method", .len = 7}, {.val = "POST", .len = 4}}},
|
439
|
+
{.data = {{.val = ":path", .len = 5}, {.val = "/", .len = 1}}},
|
440
|
+
{.data = {{.val = ":path", .len = 5}, {.val = "/index.html", .len = 11}}},
|
441
|
+
{.data = {{.val = ":scheme", .len = 7}, {.val = "http", .len = 0}}},
|
442
|
+
{.data = {{.val = ":scheme", .len = 7}, {.val = "https", .len = 0}}},
|
443
|
+
{.data = {{.val = ":status", .len = 7}, {.val = "200", .len = 0}}},
|
444
|
+
{.data = {{.val = ":status", .len = 7}, {.val = "204", .len = 0}}},
|
445
|
+
{.data = {{.val = ":status", .len = 7}, {.val = "206", .len = 0}}},
|
446
|
+
{.data = {{.val = ":status", .len = 7}, {.val = "304", .len = 0}}},
|
447
|
+
{.data = {{.val = ":status", .len = 7}, {.val = "400", .len = 0}}},
|
448
|
+
{.data = {{.val = ":status", .len = 7}, {.val = "404", .len = 0}}},
|
449
|
+
{.data = {{.val = ":status", .len = 7}, {.val = "500", .len = 0}}},
|
450
|
+
{.data = {{.val = "accept-charset", .len = 14}, {.len = 0}}},
|
451
|
+
{.data = {{.val = "accept-encoding", .len = 15},
|
452
|
+
{.val = "gzip, deflate", .len = 13}}},
|
453
|
+
{.data = {{.val = "accept-language", .len = 15}, {.len = 0}}},
|
454
|
+
{.data = {{.val = "accept-ranges", .len = 13}, {.len = 0}}},
|
455
|
+
{.data = {{.val = "accept", .len = 6}, {.len = 0}}},
|
456
|
+
{.data = {{.val = "access-control-allow-origin", .len = 27}, {.len = 0}}},
|
457
|
+
{.data = {{.val = "age", .len = 3}, {.len = 0}}},
|
458
|
+
{.data = {{.val = "allow", .len = 5}, {.len = 0}}},
|
459
|
+
{.data = {{.val = "authorization", .len = 13}, {.len = 0}}},
|
460
|
+
{.data = {{.val = "cache-control", .len = 13}, {.len = 0}}},
|
461
|
+
{.data = {{.val = "content-disposition", .len = 0}, {.len = 0}}},
|
462
|
+
{.data = {{.val = "content-encoding", .len = 16}, {.len = 0}}},
|
463
|
+
{.data = {{.val = "content-language", .len = 16}, {.len = 0}}},
|
464
|
+
{.data = {{.val = "content-length", .len = 14}, {.len = 0}}},
|
465
|
+
{.data = {{.val = "content-location", .len = 16}, {.len = 0}}},
|
466
|
+
{.data = {{.val = "content-range", .len = 13}, {.len = 0}}},
|
467
|
+
{.data = {{.val = "content-type", .len = 12}, {.len = 0}}},
|
468
|
+
{.data = {{.val = "cookie", .len = 6}, {.len = 0}}},
|
469
|
+
{.data = {{.val = "date", .len = 4}, {.len = 0}}},
|
470
|
+
{.data = {{.val = "etag", .len = 4}, {.len = 0}}},
|
471
|
+
{.data = {{.val = "expect", .len = 6}, {.len = 0}}},
|
472
|
+
{.data = {{.val = "expires", .len = 7}, {.len = 0}}},
|
473
|
+
{.data = {{.val = "from", .len = 4}, {.len = 0}}},
|
474
|
+
{.data = {{.val = "host", .len = 4}, {.len = 0}}},
|
475
|
+
{.data = {{.val = "if-match", .len = 8}, {.len = 0}}},
|
476
|
+
{.data = {{.val = "if-modified-since", .len = 17}, {.len = 0}}},
|
477
|
+
{.data = {{.val = "if-none-match", .len = 13}, {.len = 0}}},
|
478
|
+
{.data = {{.val = "if-range", .len = 8}, {.len = 0}}},
|
479
|
+
{.data = {{.val = "if-unmodified-since", .len = 19}, {.len = 0}}},
|
480
|
+
{.data = {{.val = "last-modified", .len = 13}, {.len = 0}}},
|
481
|
+
{.data = {{.val = "link", .len = 4}, {.len = 0}}},
|
482
|
+
{.data = {{.val = "location", .len = 8}, {.len = 0}}},
|
483
|
+
{.data = {{.val = "max-forwards", .len = 12}, {.len = 0}}},
|
484
|
+
{.data = {{.val = "proxy-authenticate", .len = 18}, {.len = 0}}},
|
485
|
+
{.data = {{.val = "proxy-authorization", .len = 19}, {.len = 0}}},
|
486
|
+
{.data = {{.val = "range", .len = 5}, {.len = 0}}},
|
487
|
+
{.data = {{.val = "referer", .len = 7}, {.len = 0}}},
|
488
|
+
{.data = {{.val = "refresh", .len = 7}, {.len = 0}}},
|
489
|
+
{.data = {{.val = "retry-after", .len = 11}, {.len = 0}}},
|
490
|
+
{.data = {{.val = "server", .len = 6}, {.len = 0}}},
|
491
|
+
{.data = {{.val = "set-cookie", .len = 10}, {.len = 0}}},
|
492
|
+
{.data = {{.val = "strict-transport-security", .len = 25}, {.len = 0}}},
|
493
|
+
{.data = {{.val = "transfer-encoding", .len = 17}, {.len = 0}}},
|
494
|
+
{.data = {{.val = "user-agent", .len = 10}, {.len = 0}}},
|
495
|
+
{.data = {{.val = "vary", .len = 4}, {.len = 0}}},
|
496
|
+
{.data = {{.val = "via", .len = 3}, {.len = 0}}},
|
497
|
+
{.data = {{.val = "www-authenticate", .len = 16}, {.len = 0}}},
|
498
|
+
};
|
499
|
+
|
500
|
+
static MAYBE_UNUSED int hpack_header_static_find(uint8_t index,
|
501
|
+
uint8_t requested_type,
|
502
|
+
const char **name,
|
503
|
+
size_t *len) {
|
504
|
+
if (requested_type > 1 ||
|
505
|
+
index >= (sizeof(hpack_static_table) / sizeof(hpack_static_table[0])))
|
506
|
+
goto err;
|
507
|
+
struct hpack_static_data_s d = hpack_static_table[index].data[requested_type];
|
508
|
+
*name = d.val;
|
509
|
+
*len = d.len;
|
510
|
+
return 0;
|
511
|
+
err:
|
512
|
+
|
513
|
+
*name = NULL;
|
514
|
+
*len = 0;
|
515
|
+
return -1;
|
516
|
+
}
|
517
|
+
|
518
|
+
/* *****************************************************************************
|
519
|
+
|
520
|
+
|
521
|
+
|
522
|
+
|
523
|
+
|
524
|
+
|
525
|
+
Testing
|
526
|
+
|
527
|
+
|
528
|
+
|
405
529
|
|
406
530
|
|
407
|
-
Testing
|
408
531
|
|
409
532
|
|
410
533
|
***************************************************************************** */
|
@@ -712,12 +835,14 @@ void hpack_test(void) {
|
|
712
835
|
|
713
836
|
|
714
837
|
|
838
|
+
|
715
839
|
Auto-generate binary tree from table data
|
716
840
|
|
717
841
|
|
718
842
|
|
719
843
|
|
720
844
|
|
845
|
+
|
721
846
|
***************************************************************************** */
|
722
847
|
|
723
848
|
#if HPACK_BUILD_HPACK_STRUCT
|
@@ -953,7 +1078,7 @@ void huffman__print_tree(void) {
|
|
953
1078
|
(tree[i].value == -1) ? 0 : encode_table[tree[i].value].code,
|
954
1079
|
(tree[i].value == -1) ? 0 : encode_table[tree[i].value].bits);
|
955
1080
|
}
|
956
|
-
fprintf(stderr, "};\n\n\n
|
1081
|
+
fprintf(stderr, "};\n\n\n**************( stop copying )**************\n\n");
|
957
1082
|
for (int i = 0; i < 256; ++i) {
|
958
1083
|
uint8_t data[4] = {0};
|
959
1084
|
uint8_t result = 0;
|
@@ -985,9 +1110,21 @@ int main(void) {
|
|
985
1110
|
#endif
|
986
1111
|
|
987
1112
|
/* *****************************************************************************
|
988
|
-
|
989
|
-
|
990
|
-
|
1113
|
+
|
1114
|
+
|
1115
|
+
|
1116
|
+
|
1117
|
+
|
1118
|
+
|
1119
|
+
Paste auto-generated data here
|
1120
|
+
|
1121
|
+
|
1122
|
+
|
1123
|
+
|
1124
|
+
|
1125
|
+
|
1126
|
+
|
1127
|
+
***************************************************************************** */
|
991
1128
|
|
992
1129
|
/** Static Huffman encoding map, left aligned */
|
993
1130
|
static const huffman_encode_s huffman_encode_table[] = {
|
@@ -1768,8 +1905,17 @@ static const huffman_decode_s huffman_decode_tree[] = {
|
|
1768
1905
|
};
|
1769
1906
|
|
1770
1907
|
/* *****************************************************************************
|
1771
|
-
|
1772
|
-
|
1773
|
-
|
1908
|
+
|
1909
|
+
|
1910
|
+
|
1911
|
+
|
1912
|
+
|
1913
|
+
Don't overwrite this
|
1914
|
+
|
1915
|
+
|
1916
|
+
|
1917
|
+
|
1918
|
+
|
1919
|
+
***************************************************************************** */
|
1774
1920
|
|
1775
1921
|
#endif /* H_HPACK_H */
|
data/iodine.gemspec
CHANGED
@@ -37,7 +37,7 @@ Gem::Specification.new do |spec|
|
|
37
37
|
spec.requirements << 'Ruby >= 2.5.0 recommended.'
|
38
38
|
spec.requirements << 'TLS requires OpenSSL >= 1.1.0'
|
39
39
|
|
40
|
-
spec.add_development_dependency 'bundler', '>= 1.10', '< 2.0'
|
40
|
+
# spec.add_development_dependency 'bundler', '>= 1.10', '< 2.0'
|
41
41
|
spec.add_development_dependency 'rake', '~> 12.0', '< 13.0'
|
42
42
|
spec.add_development_dependency 'minitest', '>=5', '< 6.0'
|
43
43
|
spec.add_development_dependency 'rake-compiler', '>= 1', '< 2.0'
|
data/lib/iodine.rb
CHANGED
@@ -130,6 +130,23 @@ module Iodine
|
|
130
130
|
end
|
131
131
|
end
|
132
132
|
|
133
|
+
### trap some signals to avoid exception reports
|
134
|
+
begin
|
135
|
+
old_sigint = Signal.trap("SIGINT") { old_sigint.call if old_sigint.respond_to?(:call) }
|
136
|
+
rescue Exception
|
137
|
+
end
|
138
|
+
begin
|
139
|
+
old_sigterm = Signal.trap("SIGTERM") { old_sigterm.call if old_sigterm.respond_to?(:call) }
|
140
|
+
rescue Exception
|
141
|
+
end
|
142
|
+
begin
|
143
|
+
old_sigpipe = Signal.trap("SIGPIPE") { old_sigpipe.call if old_sigpipe.respond_to?(:call) }
|
144
|
+
rescue Exception
|
145
|
+
end
|
146
|
+
begin
|
147
|
+
old_sigusr1 = Signal.trap("SIGUSR1") { old_sigusr1.call if old_sigusr1.respond_to?(:call) }
|
148
|
+
rescue Exception
|
149
|
+
end
|
133
150
|
end
|
134
151
|
|
135
152
|
require 'rack/handler/iodine' unless defined? ::Iodine::Rack::IODINE_RACK_LOADED
|
data/lib/iodine/version.rb
CHANGED
data/lib/rack/handler/iodine.rb
CHANGED
@@ -7,7 +7,7 @@ module Iodine
|
|
7
7
|
# Runs a Rack app, as par the Rack handler requirements.
|
8
8
|
def self.run(app, options = {})
|
9
9
|
# nested applications... is that a thing?
|
10
|
-
Iodine.listen(service: :http, handler: app, port: options[:Port], address: options[:
|
10
|
+
Iodine.listen(service: :http, handler: app, port: options[:Port], address: options[:Host])
|
11
11
|
|
12
12
|
# start Iodine
|
13
13
|
Iodine.start
|
metadata
CHANGED
@@ -1,35 +1,15 @@
|
|
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.25
|
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-02-
|
11
|
+
date: 2019-02-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: bundler
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ">="
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '1.10'
|
20
|
-
- - "<"
|
21
|
-
- !ruby/object:Gem::Version
|
22
|
-
version: '2.0'
|
23
|
-
type: :development
|
24
|
-
prerelease: false
|
25
|
-
version_requirements: !ruby/object:Gem::Requirement
|
26
|
-
requirements:
|
27
|
-
- - ">="
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version: '1.10'
|
30
|
-
- - "<"
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
version: '2.0'
|
33
13
|
- !ruby/object:Gem::Dependency
|
34
14
|
name: rake
|
35
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -221,7 +201,7 @@ licenses:
|
|
221
201
|
- MIT
|
222
202
|
metadata:
|
223
203
|
allowed_push_host: https://rubygems.org
|
224
|
-
post_install_message: 'Thank you for installing Iodine 0.7.
|
204
|
+
post_install_message: 'Thank you for installing Iodine 0.7.25.
|
225
205
|
|
226
206
|
'
|
227
207
|
rdoc_options: []
|