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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a17af3bcb580a2154bb0114bf9a0e5d8bb7b361a58c217dc4b9aa471cc328401
4
- data.tar.gz: 55498d33417433697f9deeb3d864f12af3cccdeb7c7f1a0cec6eb7a83ccc4a84
3
+ metadata.gz: 69bfcfdbbca3218b3e1865afa22a9ccfcbeb8cbbe5eadacbcac978b3bb11d1ec
4
+ data.tar.gz: 474d23c9adfd030ef247fb695630ea7a81337170f173aa25ac898689605dcaef
5
5
  SHA512:
6
- metadata.gz: 3ed48224b228669f024c592708b805a0057ce53e11113693515ba953f6780bf1d8f6aeb448291b9e1c01a7495aa44a4d36fea90303996ff72aa9850a7bead669
7
- data.tar.gz: bee740562fe189778db55c83c616db4509a16196abf44a8bf1d135432c0e4b99277fe4c91472a76f265d3d68c70f3ad680c6b54dd0254bd5d455f8f219560d93
6
+ metadata.gz: b30cb2e9178c39a10458af0368733d2b35dda7f2d5b3a95870ee3147f782a29fd4270358606c7be8459a8924f383bfcb382feb45f58f59bab181fdc158728ca0
7
+ data.tar.gz: 1ced424fdbc203a0e8efc9739b6a9cd99b3f4bf616f482f677ff9a6c87a336a9c453563d8338f3fc908ed50150699fd1d9bb5a11de4eb69da93869403685791b
@@ -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.listen2http` it's possible to run multiple HTTP applications (please remember not to set more than a single application on a single TCP/IP port).
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
- ### Running the web server
47
+ ### Installing and Running Iodine
48
48
 
49
- Using the iodine server is easy, simply add iodine as a gem to your Rack application:
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.6'
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
- Iodine will calculate, when possible, a good enough default concurrency model for lightweight applications... this might not fit your application if you use heavier database access or other blocking calls.
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
- The common model of 16 threads and 4 processes can be easily adopted:
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
- During development, it's more common to use a single process and a few threads:
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
- bundler exec iodine -p $PORT -t 16 -w 1
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 by adding a single line to the application. i.e. (a `config.ru` example):
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.listen2http public: '/my/public/folder'
101
- # for static file service, we only need a single thread per worker.
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
@@ -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 << 12)
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) != -1 && \
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
- #if DEBUB
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[3];
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, 3, NULL, 0, NULL);
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
- /* initialize memory allocator */
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 `sock_max_capacity`.");
3492
+ FIO_LOG_WARNING("`getrlimit` failed in `fio_lib_init`.");
3493
+ perror("\terrno:");
3503
3494
  } else {
3504
- // #if defined(__APPLE__) /* Apple's getrlimit is broken. */
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
- // #endif
3510
-
3511
- if (rlim.rlim_cur > FIO_MAX_SOCK_CAPACITY)
3512
- rlim.rlim_cur = FIO_MAX_SOCK_CAPACITY;
3513
-
3514
- if (!setrlimit(RLIMIT_NOFILE, &rlim))
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
  }
@@ -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,
@@ -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 -tls-pass"),
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). |
@@ -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
- fprintf(stderr, "Iodine Server Error:"
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.
@@ -1,3 +1,3 @@
1
1
  module Iodine
2
- VERSION = '0.7.19'.freeze
2
+ VERSION = '0.7.20'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: iodine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.19
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-27 00:00:00.000000000 Z
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.19.
223
+ post_install_message: 'Thank you for installing Iodine 0.7.20.
224
224
 
225
225
  '
226
226
  rdoc_options: []