iodine 0.7.19 → 0.7.20
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 +14 -0
- data/README.md +50 -14
- data/ext/iodine/fio.c +40 -52
- data/ext/iodine/http1.c +17 -4
- data/ext/iodine/iodine.c +5 -2
- data/ext/iodine/iodine_http.c +1 -3
- data/ext/iodine/websocket_parser.h +1 -2
- data/lib/iodine/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 69bfcfdbbca3218b3e1865afa22a9ccfcbeb8cbbe5eadacbcac978b3bb11d1ec
|
4
|
+
data.tar.gz: 474d23c9adfd030ef247fb695630ea7a81337170f173aa25ac898689605dcaef
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b30cb2e9178c39a10458af0368733d2b35dda7f2d5b3a95870ee3147f782a29fd4270358606c7be8459a8924f383bfcb382feb45f58f59bab181fdc158728ca0
|
7
|
+
data.tar.gz: 1ced424fdbc203a0e8efc9739b6a9cd99b3f4bf616f482f677ff9a6c87a336a9c453563d8338f3fc908ed50150699fd1d9bb5a11de4eb69da93869403685791b
|
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,20 @@ 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.20
|
10
|
+
|
11
|
+
**Security**: (`fio`) lower Slowloris detection limits (backlog limit is now 1,024 responses / messages per client).
|
12
|
+
|
13
|
+
**Security**: (`http`) HTTP/1.1 slow client throttling - new requests will not be consumed until pending responses were sent. Since HTTP/1.1 is a response-request protocol, this protocol specific approach should protect the HTTP application against slow clients.
|
14
|
+
|
15
|
+
**Fix**: (`iodine`) remove redundant Content-Type printout. Credit to @giovannibonetti (Giovanni Bonetti) for exposing the issue (#53).
|
16
|
+
|
17
|
+
**Fix**: (`fio`) fix capacity maximization log to accommodate issues where `getrlimit` would return a `rlim_max` that's too high for `rlim_cur` (macOS).
|
18
|
+
|
19
|
+
**Fix**: (`fio`) fix uninitialized `kqueue` message in `fio_poll_remove_fd`.
|
20
|
+
|
21
|
+
**Fix**: (`docs`) @giovannibonetti (Giovanni Bonetti) fixed an error in the Rails README section, PR #52.
|
22
|
+
|
9
23
|
#### Change log v.0.7.19
|
10
24
|
|
11
25
|
**Deprecation**: (`iodine`) deprecated the CLI option `-tls-password`, use `-tls-pass` instead.
|
data/README.md
CHANGED
@@ -40,32 +40,69 @@ Iodine is a C extension for Ruby, developed and optimized for Ruby MRI 2.2.2 and
|
|
40
40
|
|
41
41
|
Iodine includes a light and fast HTTP and Websocket server written in C that was written according to the [Rack interface specifications](http://www.rubydoc.info/github/rack/rack/master/file/SPEC) and the [Websocket draft extension](./SPEC-Websocket-Draft.md).
|
42
42
|
|
43
|
-
With `Iodine.
|
43
|
+
With `Iodine.listen service: :http` it's possible to run multiple HTTP applications (please remember not to set more than a single application on a single TCP/IP port).
|
44
44
|
|
45
45
|
Iodine also supports native process cluster Pub/Sub and a native RedisEngine to easily scale iodine's Pub/Sub horizontally.
|
46
46
|
|
47
|
-
###
|
47
|
+
### Installing and Running Iodine
|
48
48
|
|
49
|
-
|
49
|
+
Install iodine on any Linux / BSD / macOS system using:
|
50
|
+
|
51
|
+
```bash
|
52
|
+
gem install iodine
|
53
|
+
```
|
54
|
+
|
55
|
+
Using the iodine server is easy, simply add iodine as a gem to your Rails / Sinatra / Rack application's `Gemfile`:
|
50
56
|
|
51
57
|
```ruby
|
52
|
-
gem 'iodine', '~>0.
|
58
|
+
gem 'iodine', '~>0.7'
|
59
|
+
```
|
60
|
+
|
61
|
+
Then start your application from the command-line / terminal using iodine:
|
62
|
+
|
63
|
+
```bash
|
64
|
+
bundler exec iodine
|
53
65
|
```
|
54
66
|
|
55
|
-
|
67
|
+
### Running with Rails
|
68
|
+
|
69
|
+
On Rails:
|
70
|
+
|
71
|
+
1. Replace the `puma` gem with the `iodine` gem.
|
72
|
+
|
73
|
+
1. Remove the `config/puma.rb` file (or comment out the code).
|
74
|
+
|
75
|
+
1. Optionally, it's possible to add a `config/initializers/iodine.rb` file. For example:
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
# Iodine setup - use conditional setup to allow command-line arguments to override these:
|
79
|
+
if(defined?(Iodine))
|
80
|
+
Iodine.threads = ENV.fetch("RAILS_MAX_THREADS") { 5 } if Iodine.threads.zero?
|
81
|
+
Iodine.workers = ENV.fetch("WEB_CONCURRENCY") { 2 } if Iodine.workers.zero?
|
82
|
+
Iodine::DEFAULT_SETTINGS[:port] = ENV.fetch("PORT") if ENV.fetch("PORT")
|
83
|
+
end
|
84
|
+
```
|
85
|
+
|
86
|
+
When using native WebSockets with Rails, middle-ware is probably the best approach. A guide for this approach will, hopefully, get published in the future.
|
87
|
+
|
88
|
+
### Optimizing Iodine's Concurrency
|
56
89
|
|
57
90
|
To get the most out of iodine, consider the amount of CPU cores available and the concurrency level the application requires.
|
58
91
|
|
59
|
-
|
92
|
+
Iodine will calculate, when possible, a good enough default concurrency model. See if this works for your application or customize according to the application's needs.
|
93
|
+
|
94
|
+
Command line arguments allow easy access to different options, including concurrency levels. i.e., to set up 16 threads and 4 processes:
|
60
95
|
|
61
96
|
```bash
|
62
97
|
bundler exec iodine -p $PORT -t 16 -w 4
|
63
98
|
```
|
64
99
|
|
65
|
-
|
100
|
+
The environment variables `THREADS` and `WORKERS` are automatically recognized when iodine is first required, allowing environment specific customization. i.e.:
|
66
101
|
|
67
102
|
```bash
|
68
|
-
|
103
|
+
export THREADS=16
|
104
|
+
export WORKERS=-1 # negative values are fractions of CPU cores.
|
105
|
+
bundler exec iodine -p $PORT
|
69
106
|
```
|
70
107
|
|
71
108
|
### Heap Fragmentation Protection
|
@@ -92,13 +129,13 @@ This can be done when starting the server from the command line:
|
|
92
129
|
bundler exec iodine -p $PORT -t 16 -w 4 -www /my/public/folder
|
93
130
|
```
|
94
131
|
|
95
|
-
Or
|
132
|
+
Or using a simple Ruby script. i.e. (a `my_server.rb` example):
|
96
133
|
|
97
134
|
```ruby
|
98
135
|
require 'iodine'
|
99
136
|
# static file service
|
100
|
-
Iodine.
|
101
|
-
# for static file service, we only need a single thread
|
137
|
+
Iodine.listen, service: :http, public: '/my/public/folder'
|
138
|
+
# for static file service, we only need a single thread and a single worker.
|
102
139
|
Iodine.threads = 1
|
103
140
|
Iodine.start
|
104
141
|
```
|
@@ -257,8 +294,8 @@ end
|
|
257
294
|
* Iodine's Redis client does *not* support multiple databases. This is both because [database scoping is ignored by Redis during pub/sub](https://redis.io/topics/pubsub#database-amp-scoping) and because [Redis Cluster doesn't support multiple databases](https://redis.io/topics/cluster-spec). This indicated that multiple database support just isn't worth the extra effort and performance hit.
|
258
295
|
|
259
296
|
* The iodine Redis client will use two Redis connections for the whole process cluster (a single publishing connection and a single subscription connection), minimizing the Redis load and network bandwidth.
|
260
|
-
|
261
|
-
Connections will be automatically re-established if timeouts or errors occur.
|
297
|
+
|
298
|
+
* Connections will be automatically re-established if timeouts or errors occur.
|
262
299
|
|
263
300
|
### Hot Restart
|
264
301
|
|
@@ -436,7 +473,6 @@ When benchmarking using a VM (crossing machine boundaries, single thread, single
|
|
436
473
|
|
437
474
|
* Puma performed at 2,521.56 req/sec, consuming ~27.5Mb of memory.
|
438
475
|
|
439
|
-
|
440
476
|
I have doubts about my own benchmarks and I recommend benchmarking the performance for yourself using `wrk` or `ab`:
|
441
477
|
|
442
478
|
```bash
|
data/ext/iodine/fio.c
CHANGED
@@ -78,7 +78,7 @@ Feel free to copy, use and enjoy according to the license provided.
|
|
78
78
|
|
79
79
|
/* Slowloris mitigation (must be less than 1<<16) */
|
80
80
|
#ifndef FIO_SLOWLORIS_LIMIT
|
81
|
-
#define FIO_SLOWLORIS_LIMIT (1 <<
|
81
|
+
#define FIO_SLOWLORIS_LIMIT (1 << 10)
|
82
82
|
#endif
|
83
83
|
|
84
84
|
#if !defined(__clang__) && !defined(__GNUC__)
|
@@ -383,7 +383,7 @@ inline static void protocol_unlock(fio_protocol_s *pr,
|
|
383
383
|
|
384
384
|
/** returns 1 if the UUID is valid and 0 if it isn't. */
|
385
385
|
#define uuid_is_valid(uuid) \
|
386
|
-
((intptr_t)(uuid)
|
386
|
+
((intptr_t)(uuid) >= 0 && \
|
387
387
|
((uint32_t)fio_uuid2fd((uuid))) < fio_data->capa && \
|
388
388
|
((uintptr_t)(uuid)&0xFF) == uuid_data((uuid)).counter)
|
389
389
|
|
@@ -1620,9 +1620,7 @@ static void fio_poll_init(void) {
|
|
1620
1620
|
}
|
1621
1621
|
return;
|
1622
1622
|
error:
|
1623
|
-
|
1624
|
-
perror("ERROR: (evoid) failed to initialize");
|
1625
|
-
#endif
|
1623
|
+
FIO_LOG_FATAL("couldn't initialize epoll.");
|
1626
1624
|
fio_poll_close();
|
1627
1625
|
exit(errno);
|
1628
1626
|
return;
|
@@ -1804,13 +1802,12 @@ static inline void fio_poll_add(intptr_t fd) {
|
|
1804
1802
|
FIO_FUNC inline void fio_poll_remove_fd(intptr_t fd) {
|
1805
1803
|
if (evio_fd < 0)
|
1806
1804
|
return;
|
1807
|
-
struct kevent chevent[
|
1805
|
+
struct kevent chevent[2];
|
1808
1806
|
EV_SET(chevent, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
|
1809
1807
|
EV_SET(chevent + 1, fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
|
1810
|
-
EV_SET(chevent + 2, fd, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
|
1811
1808
|
do {
|
1812
1809
|
errno = 0;
|
1813
|
-
kevent(evio_fd, chevent,
|
1810
|
+
kevent(evio_fd, chevent, 2, NULL, 0, NULL);
|
1814
1811
|
} while (errno == EINTR);
|
1815
1812
|
}
|
1816
1813
|
|
@@ -1818,7 +1815,7 @@ static size_t fio_poll(void) {
|
|
1818
1815
|
if (evio_fd < 0)
|
1819
1816
|
return -1;
|
1820
1817
|
int timeout_millisec = fio_timer_calc_first_interval();
|
1821
|
-
struct kevent events[FIO_POLL_MAX_EVENTS];
|
1818
|
+
struct kevent events[FIO_POLL_MAX_EVENTS] = {{0}};
|
1822
1819
|
|
1823
1820
|
const struct timespec timeout = {
|
1824
1821
|
.tv_sec = (timeout_millisec / 1000),
|
@@ -1831,23 +1828,13 @@ static size_t fio_poll(void) {
|
|
1831
1828
|
for (int i = 0; i < active_count; i++) {
|
1832
1829
|
// test for event(s) type
|
1833
1830
|
if (events[i].filter == EVFILT_WRITE) {
|
1834
|
-
// we can only write if there's no error in the socket
|
1835
1831
|
fio_defer_push_urgent(deferred_on_ready,
|
1836
1832
|
((void *)fd2uuid(events[i].udata)), NULL);
|
1837
1833
|
} else if (events[i].filter == EVFILT_READ) {
|
1838
1834
|
fio_defer_push_task(deferred_on_data, (void *)fd2uuid(events[i].udata),
|
1839
1835
|
NULL);
|
1840
1836
|
}
|
1841
|
-
// connection errors should be reported after `read` in case there's data
|
1842
|
-
// left in the buffer... not that the edge case matters.
|
1843
1837
|
if (events[i].flags & (EV_EOF | EV_ERROR)) {
|
1844
|
-
// errors are hendled as disconnections (on_close)
|
1845
|
-
// FIO_LOG_DEBUG("%p: %s\n", events[i].udata,
|
1846
|
-
// (events[i].flags & EV_EOF)
|
1847
|
-
// ? "EV_EOF"
|
1848
|
-
// : (events[i].flags & EV_ERROR) ? "EV_ERROR" :
|
1849
|
-
// "WTF?");
|
1850
|
-
// uuid_data(events[i].udata).open = 0;
|
1851
1838
|
fio_force_close_in_poll(fd2uuid(events[i].udata));
|
1852
1839
|
}
|
1853
1840
|
}
|
@@ -1951,7 +1938,7 @@ static inline void fio_poll_remove_write(int fd) {
|
|
1951
1938
|
/** returns non-zero if events were scheduled, 0 if idle */
|
1952
1939
|
static size_t fio_poll(void) {
|
1953
1940
|
/* shrink fd poll range */
|
1954
|
-
size_t end = fio_data->capa;
|
1941
|
+
size_t end = fio_data->capa; // max_protocol_fd might break TLS
|
1955
1942
|
size_t start = 0;
|
1956
1943
|
struct pollfd *list = NULL;
|
1957
1944
|
fio_lock(&fio_data->lock);
|
@@ -2924,15 +2911,10 @@ ssize_t fio_flush(intptr_t uuid) {
|
|
2924
2911
|
if (fio_trylock(&uuid_data(uuid).sock_lock))
|
2925
2912
|
goto would_block;
|
2926
2913
|
|
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
|
-
}
|
2933
2914
|
if (uuid_data(uuid).packet) {
|
2934
2915
|
tmp = uuid_data(uuid).packet->write_func(fio_uuid2fd(uuid),
|
2935
2916
|
uuid_data(uuid).packet);
|
2917
|
+
const size_t old_count = uuid_data(uuid).packet_count;
|
2936
2918
|
if (tmp == 0) {
|
2937
2919
|
errno = ECONNRESET;
|
2938
2920
|
fio_unlock(&uuid_data(uuid).sock_lock);
|
@@ -2941,6 +2923,12 @@ ssize_t fio_flush(intptr_t uuid) {
|
|
2941
2923
|
} else if (tmp < 0) {
|
2942
2924
|
goto test_errno;
|
2943
2925
|
}
|
2926
|
+
|
2927
|
+
if (old_count >= 1024 && uuid_data(uuid).packet_count == old_count) {
|
2928
|
+
/* Slowloris attack assumed */
|
2929
|
+
goto attacked;
|
2930
|
+
}
|
2931
|
+
|
2944
2932
|
} else {
|
2945
2933
|
flushed = uuid_data(uuid).rw_hooks->flush(uuid, uuid_data(uuid).rw_udata);
|
2946
2934
|
if (flushed < 0) {
|
@@ -2980,6 +2968,14 @@ flushed:
|
|
2980
2968
|
touchfd(fio_uuid2fd(uuid));
|
2981
2969
|
fio_unlock(&uuid_data(uuid).sock_lock);
|
2982
2970
|
return 1;
|
2971
|
+
|
2972
|
+
attacked:
|
2973
|
+
/* don't close, just detach from facil.io and mark uuid as invalid */
|
2974
|
+
FIO_LOG_WARNING("(facil.io) possible Slowloris attack from %.*s",
|
2975
|
+
(int)fio_peer_addr(uuid).len, fio_peer_addr(uuid).data);
|
2976
|
+
fio_unlock(&uuid_data(uuid).sock_lock);
|
2977
|
+
fio_clear_fd(fio_uuid2fd(uuid), 0);
|
2978
|
+
return -1;
|
2983
2979
|
}
|
2984
2980
|
|
2985
2981
|
/** `fio_flush_all` attempts flush all the open connections. */
|
@@ -3482,13 +3478,7 @@ static void fio_mem_init(void);
|
|
3482
3478
|
static void fio_cluster_init(void);
|
3483
3479
|
static void fio_pubsub_initialize(void);
|
3484
3480
|
static void __attribute__((constructor)) fio_lib_init(void) {
|
3485
|
-
/*
|
3486
|
-
fio_mem_init();
|
3487
|
-
/* initialize polling engine */
|
3488
|
-
fio_poll_init();
|
3489
|
-
/* initialize the cluster engine */
|
3490
|
-
fio_pubsub_initialize();
|
3491
|
-
/* detect socket capacity */
|
3481
|
+
/* detect socket capacity - MUST be first...*/
|
3492
3482
|
ssize_t capa = 0;
|
3493
3483
|
{
|
3494
3484
|
#ifdef _SC_OPEN_MAX
|
@@ -3499,22 +3489,27 @@ static void __attribute__((constructor)) fio_lib_init(void) {
|
|
3499
3489
|
// try to maximize limits - collect max and set to max
|
3500
3490
|
struct rlimit rlim = {.rlim_max = 0};
|
3501
3491
|
if (getrlimit(RLIMIT_NOFILE, &rlim) == -1) {
|
3502
|
-
FIO_LOG_WARNING("`getrlimit` failed in `
|
3492
|
+
FIO_LOG_WARNING("`getrlimit` failed in `fio_lib_init`.");
|
3493
|
+
perror("\terrno:");
|
3503
3494
|
} else {
|
3504
|
-
|
3505
|
-
// rlim.rlim_cur = rlim.rlim_max >= FOPEN_MAX ? FOPEN_MAX :
|
3506
|
-
// rlim.rlim_max;
|
3507
|
-
// #else
|
3495
|
+
rlim_t original = rlim.rlim_cur;
|
3508
3496
|
rlim.rlim_cur = rlim.rlim_max;
|
3509
|
-
|
3510
|
-
|
3511
|
-
|
3512
|
-
|
3513
|
-
|
3514
|
-
|
3515
|
-
getrlimit(RLIMIT_NOFILE, &rlim);
|
3497
|
+
if (rlim.rlim_cur > FIO_MAX_SOCK_CAPACITY) {
|
3498
|
+
rlim.rlim_cur = rlim.rlim_max = FIO_MAX_SOCK_CAPACITY;
|
3499
|
+
}
|
3500
|
+
while (setrlimit(RLIMIT_NOFILE, &rlim) == -1 && rlim.rlim_cur > original)
|
3501
|
+
--rlim.rlim_cur;
|
3502
|
+
getrlimit(RLIMIT_NOFILE, &rlim);
|
3516
3503
|
capa = rlim.rlim_cur;
|
3504
|
+
if (capa > 1024) /* leave a slice of room */
|
3505
|
+
capa -= 16;
|
3517
3506
|
}
|
3507
|
+
/* initialize memory allocator */
|
3508
|
+
fio_mem_init();
|
3509
|
+
/* initialize polling engine */
|
3510
|
+
fio_poll_init();
|
3511
|
+
/* initialize the cluster engine */
|
3512
|
+
fio_pubsub_initialize();
|
3518
3513
|
#if DEBUG
|
3519
3514
|
#if FIO_ENGINE_POLL
|
3520
3515
|
FIO_LOG_STATE("facil.io " FIO_VERSION_STRING " capacity initialization:\n"
|
@@ -10544,10 +10539,6 @@ Poll (not kqueue or epoll) tests
|
|
10544
10539
|
FIO_FUNC void fio_poll_test(void) {
|
10545
10540
|
fprintf(stderr, "=== Testing poll add / remove fd\n");
|
10546
10541
|
fio_poll_add(5);
|
10547
|
-
FIO_ASSERT(fio_data->start == 5,
|
10548
|
-
"fio_poll_add didn't update start position (%u)", fio_data->start);
|
10549
|
-
FIO_ASSERT(fio_data->end == 6, "fio_poll_add didn't update end position (%u)",
|
10550
|
-
fio_data->end);
|
10551
10542
|
FIO_ASSERT(fio_data->poll[5].fd == 5, "fio_poll_add didn't set used fd data");
|
10552
10543
|
FIO_ASSERT(fio_data->poll[5].events ==
|
10553
10544
|
(FIO_POLL_READ_EVENTS | FIO_POLL_WRITE_EVENTS),
|
@@ -10578,9 +10569,6 @@ FIO_FUNC void fio_poll_test(void) {
|
|
10578
10569
|
"fio_poll_remove (both) didn't reset unused fd data");
|
10579
10570
|
FIO_ASSERT(fio_data->poll[7].events == 0,
|
10580
10571
|
"fio_poll_remove (both) didn't reset unused fd flags");
|
10581
|
-
FIO_ASSERT(fio_data->end == 6,
|
10582
|
-
"fio_poll_remove (both) didn't update end position (%u)",
|
10583
|
-
fio_data->end);
|
10584
10572
|
fio_poll_remove_fd(5);
|
10585
10573
|
fprintf(stderr, "\n* passed.\n");
|
10586
10574
|
}
|
data/ext/iodine/http1.c
CHANGED
@@ -666,16 +666,22 @@ static int http1_on_body_chunk(http1_parser_s *parser, char *data,
|
|
666
666
|
|
667
667
|
/** called when a protocol error occurred. */
|
668
668
|
static int http1_on_error(http1_parser_s *parser) {
|
669
|
+
FIO_LOG_DEBUG("HTTP parser error.");
|
669
670
|
fio_close(parser2http(parser)->p.uuid);
|
670
671
|
return -1;
|
671
672
|
}
|
672
673
|
|
673
674
|
/* *****************************************************************************
|
674
675
|
Connection Callbacks
|
675
|
-
*****************************************************************************
|
676
|
-
*/
|
676
|
+
***************************************************************************** */
|
677
677
|
|
678
678
|
static inline void http1_consume_data(intptr_t uuid, http1pr_s *p) {
|
679
|
+
if (fio_pending(uuid) > 4) { /* throttle busy clients (slowloris) */
|
680
|
+
fio_suspend(uuid);
|
681
|
+
FIO_LOG_DEBUG("(HTTP/1,1) throttling client at %.*s",
|
682
|
+
(int)fio_peer_addr(uuid).len, fio_peer_addr(uuid).data);
|
683
|
+
return;
|
684
|
+
}
|
679
685
|
ssize_t i = 0;
|
680
686
|
size_t org_len = p->buf_len;
|
681
687
|
int pipeline_limit = 8;
|
@@ -739,6 +745,13 @@ static void http1_on_close(intptr_t uuid, fio_protocol_s *protocol) {
|
|
739
745
|
(void)uuid;
|
740
746
|
}
|
741
747
|
|
748
|
+
/** called when the connection was closed, but will not run concurrently */
|
749
|
+
static void http1_on_ready(intptr_t uuid, fio_protocol_s *protocol) {
|
750
|
+
/* resume slow clients from suspension */
|
751
|
+
fio_force_event(uuid, FIO_EVENT_ON_DATA);
|
752
|
+
(void)protocol;
|
753
|
+
}
|
754
|
+
|
742
755
|
/** called when a data is available for the first time */
|
743
756
|
static void http1_on_data_first_time(intptr_t uuid, fio_protocol_s *protocol) {
|
744
757
|
http1pr_s *p = (http1pr_s *)protocol;
|
@@ -764,8 +777,7 @@ static void http1_on_data_first_time(intptr_t uuid, fio_protocol_s *protocol) {
|
|
764
777
|
|
765
778
|
/* *****************************************************************************
|
766
779
|
Public API
|
767
|
-
*****************************************************************************
|
768
|
-
*/
|
780
|
+
***************************************************************************** */
|
769
781
|
|
770
782
|
/** Creates an HTTP1 protocol object and handles any unread data in the buffer
|
771
783
|
* (if any). */
|
@@ -781,6 +793,7 @@ fio_protocol_s *http1_new(uintptr_t uuid, http_settings_s *settings,
|
|
781
793
|
{
|
782
794
|
.on_data = http1_on_data_first_time,
|
783
795
|
.on_close = http1_on_close,
|
796
|
+
.on_ready = http1_on_ready,
|
784
797
|
},
|
785
798
|
.p.uuid = uuid,
|
786
799
|
.p.settings = settings,
|
data/ext/iodine/iodine.c
CHANGED
@@ -375,6 +375,8 @@ static VALUE iodine_cli_parse(VALUE self) {
|
|
375
375
|
FIO_CLI_PRINT_HEADER("Concurrency:"),
|
376
376
|
FIO_CLI_INT("-workers -w number of processes to use."),
|
377
377
|
FIO_CLI_INT("-threads -t number of threads per process."),
|
378
|
+
FIO_CLI_PRINT("Negative concurrency values "
|
379
|
+
"map to fractions of available CPU cores."),
|
378
380
|
FIO_CLI_PRINT_HEADER("HTTP Settings:"),
|
379
381
|
FIO_CLI_STRING("-public -www public folder, for static file service."),
|
380
382
|
FIO_CLI_BOOL("-log -v HTTP request logging."),
|
@@ -396,7 +398,8 @@ static VALUE iodine_cli_parse(VALUE self) {
|
|
396
398
|
FIO_CLI_STRING(
|
397
399
|
"-tls-pass -tls-password the password (if any) protecting the "
|
398
400
|
"private key file."),
|
399
|
-
FIO_CLI_PRINT("\t\t-tls-password is deprecated, use
|
401
|
+
FIO_CLI_PRINT("\t\t\x1B[1m-tls-password\x1B[0m is deprecated, use "
|
402
|
+
"\x1B[1m-tls-pass\x1B[0m"),
|
400
403
|
FIO_CLI_PRINT_HEADER("Connecting Iodine to Redis:"),
|
401
404
|
FIO_CLI_STRING(
|
402
405
|
"-redis -r an optional Redis URL server address. Default: none."),
|
@@ -922,7 +925,7 @@ Supported Settigs:
|
|
922
925
|
| `:url` | URL indicating service type, host name and port. Path will be parsed as a Unix socket. |
|
923
926
|
| `:handler` | (deprecated: `:app`) see details below. |
|
924
927
|
| `:address` | an IP address or a unix socket address. Only relevant if `:url` is missing. |
|
925
|
-
| `:log` | (HTTP only) request logging. |
|
928
|
+
| `:log` | (HTTP only) request logging. For global verbosity see {Iodine.verbosity} |
|
926
929
|
| `:max_body` | (HTTP only) maximum upload size allowed per request before disconnection (in Mb). |
|
927
930
|
| `:max_headers` | (HTTP only) maximum total header length allowed per request (in Kb). |
|
928
931
|
| `:max_msg` | (WebSockets only) maximum message size pre message (in Kb). |
|
data/ext/iodine/iodine_http.c
CHANGED
@@ -398,7 +398,6 @@ static inline VALUE copy2env(iodine_http_request_handle_s *handle) {
|
|
398
398
|
if (ct) {
|
399
399
|
tmp = fiobj_obj2cstr(ct);
|
400
400
|
if (tmp.len && tmp.data) {
|
401
|
-
fprintf(stderr, "Content type: %s\n", tmp.data);
|
402
401
|
rb_hash_aset(env, CONTENT_TYPE,
|
403
402
|
rb_enc_str_new(tmp.data, tmp.len, IodineBinaryEncoding));
|
404
403
|
fiobj_hash_delete2(h->headers, content_type_hash);
|
@@ -519,8 +518,7 @@ static VALUE for_each_body_string(VALUE str, VALUE body_) {
|
|
519
518
|
// fprintf(stderr, "For_each - body\n");
|
520
519
|
// write body
|
521
520
|
if (TYPE(str) != T_STRING) {
|
522
|
-
|
523
|
-
"response body was not a String\n");
|
521
|
+
FIO_LOG_ERROR("(Iodine) response body not a String\n");
|
524
522
|
return Qfalse;
|
525
523
|
}
|
526
524
|
if (RSTRING_LEN(str) && RSTRING_PTR(str)) {
|
@@ -373,8 +373,7 @@ static uint64_t websocket_client_wrap(void *target, void *msg, uint64_t len,
|
|
373
373
|
|
374
374
|
/* *****************************************************************************
|
375
375
|
Message unwrapping
|
376
|
-
*****************************************************************************
|
377
|
-
*/
|
376
|
+
***************************************************************************** */
|
378
377
|
|
379
378
|
/**
|
380
379
|
* Returns all known information regarding the upcoming message.
|
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.20
|
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-31 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.20.
|
224
224
|
|
225
225
|
'
|
226
226
|
rdoc_options: []
|