iodine 0.2.1 → 0.2.2

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
  SHA1:
3
- metadata.gz: 72136c13b8660b82247aa72226d0fc5ef37cdd75
4
- data.tar.gz: cf96f47a2b9b0e99f833127ae0db4869ecd33761
3
+ metadata.gz: 6ad0af726b17fcc350121f1dbacbe34ae47724b9
4
+ data.tar.gz: 2d30bc235638f7a2e4aa203fb3f25dfa2d78fafe
5
5
  SHA512:
6
- metadata.gz: 5fb48e67f652c4b01e1ef20ca578a1a0b23cc32a6b80bb681985d52ea00b509239e7e153eb1fae3b738be24b9505e3c3782a53fc9ea7826c28449e95a8113cc9
7
- data.tar.gz: a828b6192aa581be423fb18ad6523a42db5edea8765f07f03705ffe56a4cfd0da24908fcb69d6296bfcb4d6333cb66da225c140fe25f0d0852602b296539fb0e
6
+ metadata.gz: 9f918ab4162ff89e65596bc3154d9bedaad2187a24fa4b2fe0707f06079afddad00e34e8879da340b47f3d5e4a900e83615effe8813db1cc5a99b9c83ff4d635
7
+ data.tar.gz: cddb06efa79664971a33714811d4c824dd7398d7c1b9573ac0081495b140c7163ebc2b635da466abf7a3465fe3d7c0c73899a855c91c329b923397e662213eb2
data/.gitignore CHANGED
@@ -12,3 +12,5 @@
12
12
  *.so
13
13
 
14
14
  .ruby-version
15
+
16
+ .DS_Store
@@ -6,6 +6,16 @@ Please notice that this change log contains changes for upcoming releases as wel
6
6
 
7
7
  ## Changes:
8
8
 
9
+ ***
10
+
11
+ Change log v.0.2.2
12
+
13
+ **Update** The static file service now supports `ETag` caching, sending a 304 (not changed) response for valid ETags.
14
+
15
+ **Update**: A performance warning now shows if the CPUs are significantly under-utilized (less than half are used) of if too many are utilized (more than double the amount of CPUs), warning against under-utilization or excessive context switching (respectively).
16
+
17
+ ***
18
+
9
19
  Change log v.0.2.1
10
20
 
11
21
  **Notice**: The [Rack Websocket Draft](https://github.com/rack/rack/pull/1107) does not support the `each` and `defer` methods. Although I tried to maintain these as part of the draft, the community preferred to leave the implementation of these to the client (rather then the server). If collisions occur, these methods might be removed in the future.
data/README.md CHANGED
@@ -1,10 +1,12 @@
1
- # Iodine - a C kqueue/epoll EventMachine alternative (pre-release)
1
+ # Iodine - HTTP / Websocket Server & EventMachine alternative: C kqueue/epoll extension
2
+ [![Logo](https://github.com/boazsegev/iodine/raw/master/logo.png)](https://github.com/boazsegev/iodine)
3
+
2
4
  [![Build Status](https://travis-ci.org/boazsegev/iodine.svg?branch=master)](https://travis-ci.org/boazsegev/iodine)
3
5
  [![Gem Version](https://badge.fury.io/rb/iodine.svg)](https://badge.fury.io/rb/iodine)
4
6
  [![Inline docs](http://inch-ci.org/github/boazsegev/iodine.svg?branch=master)](http://www.rubydoc.info/github/boazsegev/iodine/master/frames)
5
7
  [![GitHub](https://img.shields.io/badge/GitHub-Open%20Source-blue.svg)](https://github.com/boazsegev/iodine)
6
8
 
7
- Iodine 0.2.0 (pre-release) makes writing Object Oriented **Network Services** easy to write.
9
+ Iodine makes writing Object Oriented **Network Services** easy to write.
8
10
 
9
11
  Iodine is an **evented** framework with a simple API that builds off a low level [C code library](https://github.com/boazsegev/c-server-tools) with support for **epoll** and **kqueue** - this means that:
10
12
 
@@ -45,6 +47,8 @@ Puma's model of 16 threads and 4 processes is easily adopted and proved to provi
45
47
  bundler exec iodine -p $PORT -t 16 -w 4
46
48
  ```
47
49
 
50
+ It should be noted that Websocket support means that no automatic process scaling is provided... It is important to use `iodine` with the `-w` option and set the number of desired processes (ideally equal to the number of CPU cores).
51
+
48
52
  ### Static file serving support
49
53
 
50
54
  Iodine supports static file serving that allows the server to serve static files directly, with no Ruby layer (all from C-land).
@@ -1,4 +1,6 @@
1
1
  #include "http.h"
2
+ #include "siphash.h"
3
+ #include "base64.h"
2
4
  #include "http_response_http1.h"
3
5
  #include <netinet/in.h>
4
6
  #include <netinet/ip.h>
@@ -203,6 +205,7 @@ int http_response_sendfile2(http_response_s *response, http_request_s *request,
203
205
  const char *file_path_unsafe,
204
206
  size_t path_unsafe_len, uint8_t log) {
205
207
  static char *HEAD = "HEAD";
208
+ char buffer[64]; /* we'll need this a few times along the way */
206
209
  if (request == NULL || (file_path_safe == NULL && file_path_unsafe == NULL))
207
210
  return -1;
208
211
  http_response_s tmp_response;
@@ -265,10 +268,6 @@ int http_response_sendfile2(http_response_s *response, http_request_s *request,
265
268
  http_response_log_start(response);
266
269
  }
267
270
 
268
- if (*((uint32_t *)request->method) == *((uint32_t *)HEAD)) {
269
- forward_func(response, response_finish, response);
270
- }
271
-
272
271
  // we have a file, time to handle response details.
273
272
  int file = open(fname, O_RDONLY);
274
273
  if (file == -1) {
@@ -286,12 +285,31 @@ int http_response_sendfile2(http_response_s *response, http_request_s *request,
286
285
  .name_length = 12, .value = mime);
287
286
  }
288
287
  }
288
+ /* add ETag */
289
+ uint64_t sip = file_data.st_size;
290
+ sip ^= file_data.st_mtime;
291
+ sip = siphash24(&sip, sizeof(uint64_t), SIPHASH_DEFAULT_KEY);
292
+ bscrypt_base64_encode(buffer, (void *)&sip, 8);
293
+ http_response_write_header(response, .name = "ETag", .name_length = 4,
294
+ .value = buffer, .value_length = 12);
289
295
 
290
296
  response->last_modified = file_data.st_mtime;
291
297
  http_response_write_header(response, .name = "Cache-Control",
292
298
  .name_length = 13, .value = "public, max-age=3600",
293
299
  .value_length = 20);
294
300
 
301
+ /* check etag */
302
+ if ((ext = http_request_find_header(request, "if-none-match", 13)) &&
303
+ memcmp(ext, buffer, 12) == 0) {
304
+ /* send back 304 */
305
+ response->status = 304;
306
+ close(file);
307
+ perform_func(response, response_finish, response);
308
+ if (log)
309
+ http_response_log_finish(response);
310
+ return 0;
311
+ }
312
+
295
313
  // Range handling
296
314
  if ((ext = http_request_find_header(request, "range", 5)) &&
297
315
  (ext[0] | 32) == 'b' && (ext[1] | 32) == 'y' && (ext[2] | 32) == 't' &&
@@ -320,7 +338,6 @@ int http_response_sendfile2(http_response_s *response, http_request_s *request,
320
338
  // going to the EOF (big chunk or EOL requested) - send as file
321
339
  if (finish >= file_data.st_size)
322
340
  finish = file_data.st_size;
323
- char buffer[64];
324
341
  char *pos = buffer + 6;
325
342
  memcpy(buffer, "bytes ", 6);
326
343
  pos += http_ul2a(pos, start);
@@ -336,6 +353,15 @@ int http_response_sendfile2(http_response_s *response, http_request_s *request,
336
353
  .name_length = 13, .value = "bytes",
337
354
  .value_length = 5);
338
355
 
356
+ if (*((uint32_t *)request->method) == *((uint32_t *)HEAD)) {
357
+ response->content_length = 0;
358
+ close(file);
359
+ perform_func(response, response_finish, response);
360
+ if (log)
361
+ http_response_log_finish(response);
362
+ return 0;
363
+ }
364
+
339
365
  http_response_sendfile(response, file, start, finish - start + 1);
340
366
  if (log)
341
367
  http_response_log_finish(response);
@@ -347,6 +373,15 @@ invalid_range:
347
373
  .name_length = 13, .value = "none",
348
374
  .value_length = 4);
349
375
 
376
+ if (*((uint32_t *)request->method) == *((uint32_t *)HEAD)) {
377
+ response->content_length = 0;
378
+ close(file);
379
+ perform_func(response, response_finish, response);
380
+ if (log)
381
+ http_response_log_finish(response);
382
+ return 0;
383
+ }
384
+
350
385
  http_response_sendfile(response, file, 0, file_data.st_size);
351
386
  if (log)
352
387
  http_response_log_finish(response);
@@ -550,10 +550,27 @@ Running the server
550
550
  */
551
551
 
552
552
  static void *srv_start_no_gvl(void *_) {
553
+ // collect requested settings
553
554
  VALUE rb_th_i = rb_iv_get(Iodine, "@threads");
554
555
  VALUE rb_pr_i = rb_iv_get(Iodine, "@processes");
555
556
  size_t threads = (TYPE(rb_th_i) == T_FIXNUM) ? FIX2ULONG(rb_th_i) : 0;
556
557
  size_t processes = (TYPE(rb_pr_i) == T_FIXNUM) ? FIX2ULONG(rb_pr_i) : 0;
558
+ // print a warnning if settings are sub optimal
559
+ #ifdef _SC_NPROCESSORS_ONLN
560
+ size_t cpu_count = sysconf(_SC_NPROCESSORS_ONLN);
561
+ if ((processes << 1) < cpu_count || processes > (cpu_count << 1))
562
+ fprintf(
563
+ stderr, "* Performance warnning:\n"
564
+ " - This computer has %lu CPUs available and you'll be "
565
+ "utilizing %lu processes.\n - %s\n"
566
+ " - Use the command line option: `-w %lu`\n"
567
+ " - Or, within Ruby: `Iodine.processes = %lu`\n",
568
+ cpu_count, processes,
569
+ (processes < cpu_count
570
+ ? "Some CPUs won't be utilized, inhibiting performance."
571
+ : "This causes excessive context switches, wasting resources."),
572
+ cpu_count, cpu_count);
573
+ #endif
557
574
  server_run(.threads = threads, .processes = processes);
558
575
  return NULL;
559
576
  }
@@ -30,6 +30,14 @@ module Iodine
30
30
  @threads = (ARGV.index('-t') && ARGV[ARGV.index('-t') + 1]) || ENV['MAX_THREADS']
31
31
  @processes = (ARGV.index('-w') && ARGV[ARGV.index('-w') + 1]) || ENV['MAX_WORKERS']
32
32
  @threads = @threads.to_i if @threads
33
+ if @processes == 'auto'
34
+ begin
35
+ require 'etc'
36
+ @processes = Etc.nprocessors
37
+ rescue Exception
38
+ warn "This version of Ruby doesn't support automatic CPU core detection."
39
+ end
40
+ end
33
41
  @processes = @processes.to_i if @processes
34
42
 
35
43
  # Get/Set the number of threads used in the thread pool (a static thread pool). Can be 1 (single working thread, the main thread will sleep) and can be 0 (the main thread will be used as the only active thread).
@@ -1,3 +1,3 @@
1
1
  module Iodine
2
- VERSION = '0.2.1'.freeze
2
+ VERSION = '0.2.2'.freeze
3
3
  end
Binary file
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.2.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Boaz Segev
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-08-29 00:00:00.000000000 Z
11
+ date: 2016-09-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -172,6 +172,7 @@ files:
172
172
  - lib/iodine/protocol.rb
173
173
  - lib/iodine/version.rb
174
174
  - lib/rack/handler/iodine.rb
175
+ - logo.png
175
176
  homepage: https://github.com/boazsegev/iodine
176
177
  licenses:
177
178
  - MIT