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 +4 -4
- data/.gitignore +2 -0
- data/CHANGELOG.md +10 -0
- data/README.md +6 -2
- data/ext/iodine/http_response.c +40 -5
- data/ext/iodine/iodine_core.c +17 -0
- data/lib/iodine.rb +8 -0
- data/lib/iodine/version.rb +1 -1
- data/logo.png +0 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6ad0af726b17fcc350121f1dbacbe34ae47724b9
|
4
|
+
data.tar.gz: 2d30bc235638f7a2e4aa203fb3f25dfa2d78fafe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9f918ab4162ff89e65596bc3154d9bedaad2187a24fa4b2fe0707f06079afddad00e34e8879da340b47f3d5e4a900e83615effe8813db1cc5a99b9c83ff4d635
|
7
|
+
data.tar.gz: cddb06efa79664971a33714811d4c824dd7398d7c1b9573ac0081495b140c7163ebc2b635da466abf7a3465fe3d7c0c73899a855c91c329b923397e662213eb2
|
data/CHANGELOG.md
CHANGED
@@ -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 -
|
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
|
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).
|
data/ext/iodine/http_response.c
CHANGED
@@ -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);
|
data/ext/iodine/iodine_core.c
CHANGED
@@ -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
|
}
|
data/lib/iodine.rb
CHANGED
@@ -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).
|
data/lib/iodine/version.rb
CHANGED
data/logo.png
ADDED
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.
|
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-
|
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
|