isomorfeus-iodine 0.8.1 → 0.8.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +20 -0
- data/README.md +782 -782
- data/examples/config.ru +3 -0
- data/examples/rack3.ru +12 -0
- data/ext/iodine_ext/extconf.rb +1 -0
- data/ext/iodine_ext/fio.c +5 -3
- data/ext/iodine_ext/http1_parser.h +1065 -103
- data/ext/iodine_ext/iodine_connection.c +10 -6
- data/ext/iodine_ext/iodine_http.c +23 -11
- data/ext/iodine_ext/websocket_parser.h +1 -0
- data/ext/iodine_ext/websockets.c +28 -11
- data/lib/iodine/version.rb +1 -1
- data/lib/rack/handler/iodine.rb +1 -1
- metadata +4 -4
- data/.travis.yml +0 -32
@@ -518,10 +518,10 @@ static iodine_sub_args_s iodine_subscribe_args(int argc, VALUE *argv) {
|
|
518
518
|
/* single argument must be a Hash / channel name */
|
519
519
|
if (TYPE(argv[0]) == T_HASH) {
|
520
520
|
rb_opt = argv[0];
|
521
|
-
ret.channel = rb_hash_aref(argv[0], to_id);
|
521
|
+
ret.channel = rb_hash_aref(argv[0], ID2SYM(to_id));
|
522
522
|
if (ret.channel == Qnil || ret.channel == Qfalse) {
|
523
523
|
/* temporary backport support */
|
524
|
-
ret.channel = rb_hash_aref(argv[0], channel_id);
|
524
|
+
ret.channel = rb_hash_aref(argv[0], ID2SYM(channel_id));
|
525
525
|
if (ret.channel != Qnil) {
|
526
526
|
FIO_LOG_WARNING("use of :channel in subscribe is deprecated.");
|
527
527
|
}
|
@@ -546,13 +546,16 @@ static iodine_sub_args_s iodine_subscribe_args(int argc, VALUE *argv) {
|
|
546
546
|
Check_Type(ret.channel, T_STRING);
|
547
547
|
|
548
548
|
if (rb_opt) {
|
549
|
-
|
549
|
+
VALUE tmp = Qnil;
|
550
|
+
if ((tmp = rb_hash_aref(rb_opt, ID2SYM(as_id))) != Qnil &&
|
551
|
+
TYPE(tmp) == T_SYMBOL && rb_sym2id(tmp) == binary_id) {
|
550
552
|
ret.binary = 1;
|
551
553
|
}
|
552
|
-
if (rb_hash_aref(rb_opt, match_id)
|
554
|
+
if ((tmp = rb_hash_aref(rb_opt, ID2SYM(match_id))) != Qnil &&
|
555
|
+
TYPE(tmp) == T_SYMBOL && rb_sym2id(tmp) == redis_id) {
|
553
556
|
ret.pattern = FIO_MATCH_GLOB;
|
554
557
|
}
|
555
|
-
ret.block = rb_hash_aref(rb_opt, handler_id);
|
558
|
+
ret.block = rb_hash_aref(rb_opt, ID2SYM(handler_id));
|
556
559
|
if (ret.block != Qnil) {
|
557
560
|
IodineStore.add(ret.block);
|
558
561
|
}
|
@@ -900,7 +903,8 @@ void iodine_connection_init(void) {
|
|
900
903
|
IodineStore.add(RAWSymbol);
|
901
904
|
|
902
905
|
// define the Connection Class and it's methods
|
903
|
-
ConnectionKlass =
|
906
|
+
ConnectionKlass =
|
907
|
+
rb_define_class_under(IodineModule, "Connection", rb_cObject);
|
904
908
|
rb_define_alloc_func(ConnectionKlass, iodine_connection_data_alloc_c);
|
905
909
|
rb_define_method(ConnectionKlass, "write", iodine_connection_write, 1);
|
906
910
|
rb_define_method(ConnectionKlass, "close", iodine_connection_close, 0);
|
@@ -477,6 +477,10 @@ Handling the HTTP response
|
|
477
477
|
static int for_each_header_data(VALUE key, VALUE val, VALUE h_) {
|
478
478
|
http_s *h = (http_s *)h_;
|
479
479
|
// fprintf(stderr, "For_each - headers\n");
|
480
|
+
if (TYPE(val) == T_NIL || TYPE(key) == T_NIL)
|
481
|
+
return ST_CONTINUE;
|
482
|
+
if (TYPE(val) == T_ARRAY)
|
483
|
+
goto array_style_multi_value;
|
480
484
|
if (TYPE(key) != T_STRING)
|
481
485
|
key = IodineCaller.call(key, iodine_to_s_id);
|
482
486
|
if (TYPE(key) != T_STRING)
|
@@ -515,6 +519,14 @@ static int for_each_header_data(VALUE key, VALUE val, VALUE h_) {
|
|
515
519
|
fiobj_free(name);
|
516
520
|
// no errors, return 0
|
517
521
|
return ST_CONTINUE;
|
522
|
+
|
523
|
+
array_style_multi_value:
|
524
|
+
for (size_t i = 0, end = RARRAY_LEN(val); i < end; ++i) {
|
525
|
+
if (for_each_header_data(key, RARRAY_AREF(val, i), h_) == ST_CONTINUE)
|
526
|
+
continue;
|
527
|
+
return ST_STOP;
|
528
|
+
}
|
529
|
+
return ST_CONTINUE;
|
518
530
|
}
|
519
531
|
|
520
532
|
// writes the body to the response object
|
@@ -941,15 +953,15 @@ intptr_t iodine_http_listen(iodine_connection_args_s args){
|
|
941
953
|
support_xsendfile = 1;
|
942
954
|
}
|
943
955
|
IodineStore.add(args.handler);
|
944
|
-
|
945
|
-
|
956
|
+
#ifdef __MINGW32__
|
957
|
+
intptr_t uuid = http_listen(
|
946
958
|
args.port.data, args.address.data, .on_request = on_rack_request,
|
947
959
|
.on_upgrade = on_rack_upgrade, .udata = (void *)args.handler,
|
948
960
|
.timeout = args.timeout, .ws_timeout = args.ping,
|
949
961
|
.ws_max_msg_size = args.max_msg, .max_header_size = args.max_headers,
|
950
962
|
.on_finish = free_iodine_http, .log = args.log,
|
951
963
|
.max_body_size = args.max_body, .public_folder = args.public.data);
|
952
|
-
|
964
|
+
#else
|
953
965
|
intptr_t uuid = http_listen(
|
954
966
|
args.port.data, args.address.data, .on_request = on_rack_request,
|
955
967
|
.on_upgrade = on_rack_upgrade, .udata = (void *)args.handler,
|
@@ -957,7 +969,7 @@ intptr_t iodine_http_listen(iodine_connection_args_s args){
|
|
957
969
|
.ws_max_msg_size = args.max_msg, .max_header_size = args.max_headers,
|
958
970
|
.on_finish = free_iodine_http, .log = args.log,
|
959
971
|
.max_body_size = args.max_body, .public_folder = args.public.data);
|
960
|
-
|
972
|
+
#endif
|
961
973
|
if (uuid == -1)
|
962
974
|
return uuid;
|
963
975
|
|
@@ -1067,11 +1079,11 @@ intptr_t iodine_ws_connect(iodine_connection_args_s args) {
|
|
1067
1079
|
FIOBJ url_tmp = FIOBJ_INVALID;
|
1068
1080
|
if (!args.url.data) {
|
1069
1081
|
url_tmp = fiobj_str_buf(64);
|
1070
|
-
|
1082
|
+
#ifndef __MINGW32__
|
1071
1083
|
if (args.tls)
|
1072
1084
|
fiobj_str_write(url_tmp, "wss://", 6);
|
1073
1085
|
else
|
1074
|
-
|
1086
|
+
#endif
|
1075
1087
|
fiobj_str_write(url_tmp, "ws://", 5);
|
1076
1088
|
if (!is_unix_socket) {
|
1077
1089
|
fiobj_str_write(url_tmp, args.address.data, args.address.len);
|
@@ -1088,11 +1100,11 @@ intptr_t iodine_ws_connect(iodine_connection_args_s args) {
|
|
1088
1100
|
}
|
1089
1101
|
|
1090
1102
|
#ifdef __MINGW32__
|
1091
|
-
intptr_t uuid =
|
1092
|
-
args.url.data, (is_unix_socket ? args.address.data : NULL),
|
1093
|
-
|
1094
|
-
|
1095
|
-
|
1103
|
+
intptr_t uuid =
|
1104
|
+
http_connect(args.url.data, (is_unix_socket ? args.address.data : NULL),
|
1105
|
+
.udata = request_data_create(&args),
|
1106
|
+
.on_response = ws_client_http_connected,
|
1107
|
+
.on_finish = ws_client_http_connection_finished);
|
1096
1108
|
#else
|
1097
1109
|
intptr_t uuid = http_connect(
|
1098
1110
|
args.url.data, (is_unix_socket ? args.address.data : NULL),
|
@@ -453,6 +453,7 @@ static uint64_t websocket_consume(void *buffer, uint64_t len, void *udata,
|
|
453
453
|
fprintf(stderr, "ERROR: WebSocket protocol error - unmasked data.\n");
|
454
454
|
#endif
|
455
455
|
websocket_on_protocol_error(udata);
|
456
|
+
return 0;
|
456
457
|
}
|
457
458
|
/* call callback */
|
458
459
|
switch (pos[0] & 15) {
|
data/ext/iodine_ext/websockets.c
CHANGED
@@ -28,7 +28,8 @@ Feel free to copy, use and enjoy according to the license provided.
|
|
28
28
|
|
29
29
|
#include <websocket_parser.h>
|
30
30
|
|
31
|
-
#if !defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__) &&
|
31
|
+
#if !defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__) && \
|
32
|
+
!defined(__MINGW32__)
|
32
33
|
#include <endian.h>
|
33
34
|
#if !defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__) && \
|
34
35
|
__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
@@ -126,6 +127,8 @@ struct ws_s {
|
|
126
127
|
struct buffer_s buffer;
|
127
128
|
/** data length (how much of the buffer actually used). */
|
128
129
|
size_t length;
|
130
|
+
/** total data length (including continuation frames). */
|
131
|
+
size_t total_length;
|
129
132
|
/** message buffer. */
|
130
133
|
FIOBJ msg;
|
131
134
|
/** latest text state. */
|
@@ -154,20 +157,24 @@ static void websocket_on_unwrapped(void *ws_p, void *msg, uint64_t len,
|
|
154
157
|
char first, char last, char text,
|
155
158
|
unsigned char rsv) {
|
156
159
|
ws_s *ws = ws_p;
|
160
|
+
if (!ws)
|
161
|
+
return;
|
157
162
|
if (last && first) {
|
158
163
|
ws->on_message(ws, (fio_str_info_s){.data = msg, .len = len},
|
159
164
|
(uint8_t)text);
|
160
165
|
return;
|
161
166
|
}
|
167
|
+
if (ws->msg == FIOBJ_INVALID)
|
168
|
+
ws->msg = fiobj_str_buf(len);
|
169
|
+
ws->total_length += len;
|
162
170
|
if (first) {
|
163
171
|
ws->is_text = (uint8_t)text;
|
164
|
-
if (ws->msg == FIOBJ_INVALID)
|
165
|
-
ws->msg = fiobj_str_buf(len);
|
166
|
-
fiobj_str_resize(ws->msg, 0);
|
167
172
|
}
|
168
173
|
fiobj_str_write(ws->msg, msg, len);
|
169
174
|
if (last) {
|
170
175
|
ws->on_message(ws, fiobj_obj2cstr(ws->msg), ws->is_text);
|
176
|
+
fiobj_str_resize(ws->msg, 0);
|
177
|
+
ws->total_length = 0;
|
171
178
|
}
|
172
179
|
|
173
180
|
(void)rsv;
|
@@ -183,15 +190,19 @@ static void websocket_on_protocol_ping(void *ws_p, void *msg_, uint64_t len) {
|
|
183
190
|
fio_write2(ws->fd, .data.buffer = buff, .length = len);
|
184
191
|
} else {
|
185
192
|
if (((ws_s *)ws)->is_client) {
|
186
|
-
fio_write2(ws->fd, .data.buffer = "\
|
193
|
+
fio_write2(ws->fd, .data.buffer = "\x8a\x80mask", .length = 6,
|
187
194
|
.after.dealloc = FIO_DEALLOC_NOOP);
|
188
195
|
} else {
|
189
|
-
fio_write2(ws->fd, .data.buffer = "\
|
196
|
+
fio_write2(ws->fd, .data.buffer = "\x8a\x00", .length = 2,
|
190
197
|
.after.dealloc = FIO_DEALLOC_NOOP);
|
191
198
|
}
|
192
199
|
}
|
200
|
+
FIO_LOG_DEBUG("Received ping and sent pong for Websocket %p (%d)", ws_p,
|
201
|
+
(int)(((ws_s *)ws_p)->fd));
|
193
202
|
}
|
194
203
|
static void websocket_on_protocol_pong(void *ws_p, void *msg, uint64_t len) {
|
204
|
+
FIO_LOG_DEBUG("Received pong for Websocket %p (%d)", ws_p,
|
205
|
+
(int)(((ws_s *)ws_p)->fd));
|
195
206
|
(void)len;
|
196
207
|
(void)msg;
|
197
208
|
(void)ws_p;
|
@@ -220,6 +231,7 @@ static void ws_ping(intptr_t fd, fio_protocol_s *ws) {
|
|
220
231
|
fio_write2(fd, .data.buffer = "\x89\x00", .length = 2,
|
221
232
|
.after.dealloc = FIO_DEALLOC_NOOP);
|
222
233
|
}
|
234
|
+
FIO_LOG_DEBUG("Sent ping for Websocket %p (%d)", (void *)ws, (int)fd);
|
223
235
|
}
|
224
236
|
|
225
237
|
static void on_close(intptr_t uuid, fio_protocol_s *_ws) {
|
@@ -238,10 +250,10 @@ static uint8_t on_shutdown(intptr_t fd, fio_protocol_s *ws) {
|
|
238
250
|
if (ws && ((ws_s *)ws)->on_shutdown)
|
239
251
|
((ws_s *)ws)->on_shutdown((ws_s *)ws);
|
240
252
|
if (((ws_s *)ws)->is_client) {
|
241
|
-
fio_write2(fd, .data.buffer = "\
|
253
|
+
fio_write2(fd, .data.buffer = "\x88\x80MASK", .length = 6,
|
242
254
|
.after.dealloc = FIO_DEALLOC_NOOP);
|
243
255
|
} else {
|
244
|
-
fio_write2(fd, .data.buffer = "\
|
256
|
+
fio_write2(fd, .data.buffer = "\x88\x00", .length = 2,
|
245
257
|
.after.dealloc = FIO_DEALLOC_NOOP);
|
246
258
|
}
|
247
259
|
return 0;
|
@@ -255,7 +267,7 @@ static void on_data(intptr_t sockfd, fio_protocol_s *ws_) {
|
|
255
267
|
websocket_buffer_peek(ws->buffer.data, ws->length);
|
256
268
|
const uint64_t raw_length = info.packet_length + info.head_length;
|
257
269
|
/* test expected data amount */
|
258
|
-
if (ws->max_msg_size < raw_length) {
|
270
|
+
if (ws->max_msg_size < raw_length + ws->total_length) {
|
259
271
|
/* too big */
|
260
272
|
websocket_close(ws);
|
261
273
|
return;
|
@@ -728,8 +740,13 @@ int websocket_write(ws_s *ws, fio_str_info_s msg, uint8_t is_text) {
|
|
728
740
|
}
|
729
741
|
/** Closes a websocket connection. */
|
730
742
|
void websocket_close(ws_s *ws) {
|
731
|
-
|
732
|
-
|
743
|
+
if (ws->is_client) {
|
744
|
+
fio_write2(ws->fd, .data.buffer = "\x88\x80MASK", .length = 6,
|
745
|
+
.after.dealloc = FIO_DEALLOC_NOOP);
|
746
|
+
} else {
|
747
|
+
fio_write2(ws->fd, .data.buffer = "\x88\x00", .length = 2,
|
748
|
+
.after.dealloc = FIO_DEALLOC_NOOP);
|
749
|
+
}
|
733
750
|
fio_close(ws->fd);
|
734
751
|
return;
|
735
752
|
}
|
data/lib/iodine/version.rb
CHANGED
data/lib/rack/handler/iodine.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'iodine' unless defined?(::Iodine::VERSION)
|
2
2
|
|
3
3
|
module Iodine
|
4
|
-
# Iodine's {Iodine::Rack} module provides a Rack
|
4
|
+
# Iodine's {Iodine::Rack} module provides a Rack compliant interface (connecting Iodine to Rack) for an HTTP and Websocket Server.
|
5
5
|
module Rack
|
6
6
|
|
7
7
|
# Runs a Rack app, as par the Rack handler requirements.
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: isomorfeus-iodine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jan Biedermann
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-12-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rackup
|
@@ -152,7 +152,6 @@ files:
|
|
152
152
|
- ".gitignore"
|
153
153
|
- ".gitlab-ci.yml"
|
154
154
|
- ".rspec"
|
155
|
-
- ".travis.yml"
|
156
155
|
- ".yardopts"
|
157
156
|
- CHANGELOG.md
|
158
157
|
- Gemfile
|
@@ -177,6 +176,7 @@ files:
|
|
177
176
|
- examples/etag.ru
|
178
177
|
- examples/hello.ru
|
179
178
|
- examples/pubsub_engine.ru
|
179
|
+
- examples/rack3.ru
|
180
180
|
- examples/redis.ru
|
181
181
|
- examples/shootout.ru
|
182
182
|
- examples/sub-protocols.ru
|
@@ -275,7 +275,7 @@ metadata:
|
|
275
275
|
github_repo: ssh://github.com/isomorfeus/gems
|
276
276
|
source_code_uri: https://github.com/isomorfeus/isomorfeus-iodine
|
277
277
|
post_install_message: |-
|
278
|
-
Thank you for installing Iodine 0.8.
|
278
|
+
Thank you for installing Iodine 0.8.2.
|
279
279
|
Remember: if iodine supports your business, it's only fair to give value back (code contributions / donations) to Bo, see https://github.com/boazsegev/iodine
|
280
280
|
rdoc_options: []
|
281
281
|
require_paths:
|
data/.travis.yml
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
language: ruby
|
2
|
-
arch:
|
3
|
-
- amd64
|
4
|
-
- arm64
|
5
|
-
os:
|
6
|
-
- linux
|
7
|
-
# - osx
|
8
|
-
before_install:
|
9
|
-
- gem install bundler -v 1.10.6
|
10
|
-
- bundle install
|
11
|
-
rvm:
|
12
|
-
- 2.7.1
|
13
|
-
- 2.6.5
|
14
|
-
- 2.5.7
|
15
|
-
- 2.4.9
|
16
|
-
- 2.3.8
|
17
|
-
- 2.2.2
|
18
|
-
notifications:
|
19
|
-
email: false
|
20
|
-
sudo: required
|
21
|
-
dist: xenial
|
22
|
-
addons:
|
23
|
-
apt:
|
24
|
-
sources:
|
25
|
-
- ubuntu-toolchain-r-test
|
26
|
-
packages:
|
27
|
-
- gcc
|
28
|
-
script:
|
29
|
-
- echo CFLAGS = $CFLAGS
|
30
|
-
- echo cflags = $cflags
|
31
|
-
- bundle exec rake install
|
32
|
-
- env VERBOSE=1 bundle exec rspec --format documentation
|