rage-iodine 5.7.0 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/release.yml +0 -1
- data/CHANGELOG.md +2 -2
- data/ext/iodine/fio.c +29 -15
- data/ext/iodine/fio.h +12 -4
- data/ext/iodine/http.c +7 -7
- data/ext/iodine/http.h +0 -3
- data/ext/iodine/iodine_helpers.c +171 -62
- data/ext/iodine/scheduler.c +76 -20
- data/lib/iodine/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1595ec4d4f155fbc845b37ad096018a2a4bfa4f884c0ef96b7112d268fe86e89
|
|
4
|
+
data.tar.gz: 3185d0901b132a329509238b5188dcd29de1d4145a018adda6b3f9f215e008cf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4bbaa335fcd6202ac41a6449a5d8a38302c786b69348b66af733520e83c27bf4529c8a0e90dc7db5f19f8755aadfaf0c71edeb07fea904664b2cbf573da573f0
|
|
7
|
+
data.tar.gz: 991187eeb695f2128f83859e1025d62d580a1e41fc672822aaf7c8e5130edf15c83721e263a30799311766627fbd132393b50987486d137004f7ae439d11d0b8
|
data/CHANGELOG.md
CHANGED
|
@@ -6,9 +6,9 @@ Please notice that this change log contains changes for upcoming releases as wel
|
|
|
6
6
|
|
|
7
7
|
## Changes:
|
|
8
8
|
|
|
9
|
-
#### Change log v.
|
|
9
|
+
#### Change log v.6.0.0 (2026-09-06)
|
|
10
10
|
|
|
11
|
-
**Update**:
|
|
11
|
+
**Update**: Update scheduler `read`/`write` hooks
|
|
12
12
|
|
|
13
13
|
#### Change log v.5.6.0 (2026-09-06)
|
|
14
14
|
|
data/ext/iodine/fio.c
CHANGED
|
@@ -3687,12 +3687,12 @@ retry_int:
|
|
|
3687
3687
|
}
|
|
3688
3688
|
|
|
3689
3689
|
/**
|
|
3690
|
-
*
|
|
3691
|
-
* socker on error.
|
|
3690
|
+
* Performs a single read operation using the connection's read hook.
|
|
3692
3691
|
*
|
|
3693
|
-
* The
|
|
3692
|
+
* The return value and errno match the underlying read operation. The socket
|
|
3693
|
+
* isn't closed on error.
|
|
3694
3694
|
*/
|
|
3695
|
-
ssize_t
|
|
3695
|
+
ssize_t fio_read_once(intptr_t uuid, void *buffer, size_t count) {
|
|
3696
3696
|
if (!uuid_is_valid(uuid) || !uuid_data(uuid).open) {
|
|
3697
3697
|
errno = EBADF;
|
|
3698
3698
|
return -1;
|
|
@@ -3704,22 +3704,36 @@ ssize_t fio_read_unsafe(intptr_t uuid, void *buffer, size_t count) {
|
|
|
3704
3704
|
uuid_data(uuid).rw_hooks->read;
|
|
3705
3705
|
void *udata = uuid_data(uuid).rw_udata;
|
|
3706
3706
|
fio_unlock(&uuid_data(uuid).sock_lock);
|
|
3707
|
-
|
|
3708
|
-
ssize_t ret;
|
|
3709
|
-
retry_int:
|
|
3710
|
-
ret = rw_read(uuid, udata, buffer, count);
|
|
3707
|
+
ssize_t ret = rw_read(uuid, udata, buffer, count);
|
|
3711
3708
|
if (ret > 0) {
|
|
3712
3709
|
fio_touch(uuid);
|
|
3713
|
-
return ret;
|
|
3714
3710
|
}
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3711
|
+
return ret;
|
|
3712
|
+
}
|
|
3713
|
+
|
|
3714
|
+
/**
|
|
3715
|
+
* Performs a single write operation using the connection's write hook.
|
|
3716
|
+
*
|
|
3717
|
+
* The return value and errno match the underlying write operation. The socket
|
|
3718
|
+
* isn't closed on error and no data is queued for the reactor.
|
|
3719
|
+
*/
|
|
3720
|
+
ssize_t fio_write_once(intptr_t uuid, const void *buffer, size_t count) {
|
|
3721
|
+
if (!uuid_is_valid(uuid) || !uuid_data(uuid).open) {
|
|
3722
|
+
errno = EBADF;
|
|
3723
|
+
return -1;
|
|
3724
|
+
}
|
|
3725
|
+
if (count == 0)
|
|
3720
3726
|
return 0;
|
|
3727
|
+
fio_lock(&uuid_data(uuid).sock_lock);
|
|
3728
|
+
ssize_t (*rw_write)(intptr_t, void *, const void *, size_t) =
|
|
3729
|
+
uuid_data(uuid).rw_hooks->write;
|
|
3730
|
+
void *udata = uuid_data(uuid).rw_udata;
|
|
3731
|
+
fio_unlock(&uuid_data(uuid).sock_lock);
|
|
3732
|
+
ssize_t ret = rw_write(uuid, udata, buffer, count);
|
|
3733
|
+
if (ret > 0) {
|
|
3734
|
+
fio_touch(uuid);
|
|
3721
3735
|
}
|
|
3722
|
-
return
|
|
3736
|
+
return ret;
|
|
3723
3737
|
}
|
|
3724
3738
|
|
|
3725
3739
|
/**
|
data/ext/iodine/fio.h
CHANGED
|
@@ -1198,12 +1198,20 @@ size_t fio_local_addr(char *dest, size_t limit);
|
|
|
1198
1198
|
ssize_t fio_read(intptr_t uuid, void *buffer, size_t count);
|
|
1199
1199
|
|
|
1200
1200
|
/**
|
|
1201
|
-
*
|
|
1202
|
-
* socker on error.
|
|
1201
|
+
* Performs a single read operation using the connection's read hook.
|
|
1203
1202
|
*
|
|
1204
|
-
* The
|
|
1203
|
+
* The return value and errno match the underlying read operation. The socket
|
|
1204
|
+
* isn't closed on error.
|
|
1205
1205
|
*/
|
|
1206
|
-
ssize_t
|
|
1206
|
+
ssize_t fio_read_once(intptr_t uuid, void *buffer, size_t count);
|
|
1207
|
+
|
|
1208
|
+
/**
|
|
1209
|
+
* Performs a single write operation using the connection's write hook.
|
|
1210
|
+
*
|
|
1211
|
+
* The return value and errno match the underlying write operation. The socket
|
|
1212
|
+
* isn't closed on error and no data is queued for the reactor.
|
|
1213
|
+
*/
|
|
1214
|
+
ssize_t fio_write_once(intptr_t uuid, const void *buffer, size_t count);
|
|
1207
1215
|
|
|
1208
1216
|
/** The following structure is used for `fio_write2_fn` function arguments. */
|
|
1209
1217
|
typedef struct {
|
data/ext/iodine/http.c
CHANGED
|
@@ -1842,8 +1842,8 @@ typedef struct {
|
|
|
1842
1842
|
|
|
1843
1843
|
#define http_mime_parser2fio(parser) ((http_fio_mime_s *)(parser))
|
|
1844
1844
|
|
|
1845
|
-
/** Parse a
|
|
1846
|
-
void
|
|
1845
|
+
/** Parse a parameter key and add it to the `params` hash. Check `parse_nested_query_internal` for reference. */
|
|
1846
|
+
static void add_to_params(VALUE params, char *key, size_t key_len, VALUE value) {
|
|
1847
1847
|
char *pos = NULL;
|
|
1848
1848
|
if (key_len > 1) {
|
|
1849
1849
|
pos = memchr(key + 1, '[', key_len - 1);
|
|
@@ -1925,7 +1925,7 @@ void http_add_to_params(VALUE params, char *key, size_t key_len, VALUE value) {
|
|
|
1925
1925
|
if (RB_TYPE_P(nested_val, T_HASH)) {
|
|
1926
1926
|
char *n_pos_start = k_pos + 1, *n_pos_end = k_pos + 1;
|
|
1927
1927
|
|
|
1928
|
-
while (nested_val != Qnil &&
|
|
1928
|
+
while (nested_val != Qnil && *n_pos_start == '[' && *(n_pos_start + 1) != ']' && *n_pos_end != '&' && *n_pos_end != '=' && n_pos_end < end) {
|
|
1929
1929
|
n_pos_end++;
|
|
1930
1930
|
|
|
1931
1931
|
if (*n_pos_end == ']') {
|
|
@@ -2011,7 +2011,7 @@ static void http_mime_parser_on_data(http_mime_parser_s *parser, void *name,
|
|
|
2011
2011
|
// for regular values - just add them to params
|
|
2012
2012
|
if (!filename_len) {
|
|
2013
2013
|
VALUE r_value = rb_enc_str_new(value, value_len, IodineBinaryEncoding);
|
|
2014
|
-
|
|
2014
|
+
add_to_params(http_mime_parser2fio(parser)->params, name, name_len, r_value);
|
|
2015
2015
|
return;
|
|
2016
2016
|
}
|
|
2017
2017
|
|
|
@@ -2024,7 +2024,7 @@ static void http_mime_parser_on_data(http_mime_parser_s *parser, void *name,
|
|
|
2024
2024
|
close(file);
|
|
2025
2025
|
|
|
2026
2026
|
VALUE r_value = build_file_value(r_tempfile, filename, filename_len, mimetype, mimetype_len);
|
|
2027
|
-
|
|
2027
|
+
add_to_params(http_mime_parser2fio(parser)->params, name, name_len, r_value);
|
|
2028
2028
|
}
|
|
2029
2029
|
|
|
2030
2030
|
/** Called when the data didn't fit in the buffer. Data will be streamed. */
|
|
@@ -2073,7 +2073,7 @@ static void http_mime_parser_on_partial_end(http_mime_parser_s *parser) {
|
|
|
2073
2073
|
|
|
2074
2074
|
// for a file - add to params and close the fd
|
|
2075
2075
|
if (fio_parser->partial_fd) {
|
|
2076
|
-
|
|
2076
|
+
add_to_params(fio_parser->params, RSTRING_PTR(fio_parser->partial_name), RSTRING_LEN(fio_parser->partial_name), fio_parser->partial_tempfile);
|
|
2077
2077
|
close(fio_parser->partial_fd);
|
|
2078
2078
|
|
|
2079
2079
|
fio_parser->partial_name = Qnil;
|
|
@@ -2086,7 +2086,7 @@ static void http_mime_parser_on_partial_end(http_mime_parser_s *parser) {
|
|
|
2086
2086
|
FIOBJ slice = fiobj_data_slice(fio_parser->h->body, fio_parser->partial_offset, fio_parser->partial_length);
|
|
2087
2087
|
fio_str_info_s s_slice = fiobj_obj2cstr(slice);
|
|
2088
2088
|
VALUE r_value = rb_enc_str_new(s_slice.data, s_slice.len, IodineBinaryEncoding);
|
|
2089
|
-
|
|
2089
|
+
add_to_params(fio_parser->params, RSTRING_PTR(fio_parser->partial_name), RSTRING_LEN(fio_parser->partial_name), r_value);
|
|
2090
2090
|
|
|
2091
2091
|
fio_parser->partial_name = Qnil;
|
|
2092
2092
|
fio_parser->partial_length = 0;
|
data/ext/iodine/http.h
CHANGED
|
@@ -781,9 +781,6 @@ HTTP GET and POST parsing helpers
|
|
|
781
781
|
*/
|
|
782
782
|
VALUE http_parse_multipart(http_s *h, char *content_type, size_t content_type_len);
|
|
783
783
|
|
|
784
|
-
/** Adds a decoded parameter key and Ruby value to a nested parameters hash. */
|
|
785
|
-
void http_add_to_params(VALUE params, char *key, size_t key_len, VALUE value);
|
|
786
|
-
|
|
787
784
|
/**
|
|
788
785
|
* Parses the query part of an HTTP request/response. Uses `http_add2hash`.
|
|
789
786
|
*
|
data/ext/iodine/iodine_helpers.c
CHANGED
|
@@ -210,7 +210,7 @@ static VALUE iodine_rfc2109(VALUE self, VALUE rtm) {
|
|
|
210
210
|
}
|
|
211
211
|
|
|
212
212
|
/**
|
|
213
|
-
Convert query string into a Ruby object
|
|
213
|
+
Convert query string into a Ruby object in (almost always) one pass with no recursion.
|
|
214
214
|
|
|
215
215
|
|
|
216
216
|
Iodine::Rack::Utils.parse_nested_query("a=1&b[]=2&c[d]=3") # => { "a" => "1", "b" => ["2"], "c" => { "d" => "3" } }
|
|
@@ -240,68 +240,182 @@ Convert query string into a Ruby object without recursion.
|
|
|
240
240
|
Rack: 64257.9 i/s - 16.94x slower
|
|
241
241
|
|
|
242
242
|
*/
|
|
243
|
-
static VALUE build_query_component(char *str, size_t len,
|
|
244
|
-
uint8_t should_decode) {
|
|
245
|
-
VALUE result = rb_str_new(str, len);
|
|
246
|
-
if (should_decode) {
|
|
247
|
-
url_decode_inplace(Qnil, result);
|
|
248
|
-
}
|
|
249
|
-
return result;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
243
|
static VALUE parse_nested_query_internal(char *str, size_t len) {
|
|
244
|
+
uint8_t should_decode = 0;
|
|
253
245
|
VALUE params = rb_hash_new();
|
|
254
|
-
|
|
255
|
-
char *
|
|
246
|
+
|
|
247
|
+
char *pos = str, *k_pos = str, *v_pos = str;
|
|
248
|
+
const char *end = str + len;
|
|
256
249
|
|
|
257
250
|
while (pos < end) {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
251
|
+
k_pos++;
|
|
252
|
+
|
|
253
|
+
if (*k_pos == '=') { // plain param
|
|
254
|
+
v_pos = k_pos + 1;
|
|
255
|
+
while (*v_pos != '&' && v_pos < end) {
|
|
256
|
+
if (*v_pos == '%' || *v_pos == '+') {
|
|
257
|
+
should_decode = 1;
|
|
258
|
+
}
|
|
259
|
+
v_pos++;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
VALUE k = ID2SYM(rb_intern2(pos, k_pos - pos)), v = rb_str_new(k_pos + 1, v_pos - k_pos - 1);
|
|
263
|
+
if (should_decode) {
|
|
264
|
+
rb_hash_aset(params, k, url_decode_inplace(Qnil, v));
|
|
265
|
+
should_decode = 0;
|
|
266
|
+
} else {
|
|
267
|
+
rb_hash_aset(params, k, v);
|
|
268
|
+
}
|
|
269
|
+
pos = k_pos = v_pos + 1;
|
|
270
|
+
|
|
271
|
+
} else if (*k_pos == '[') { // things are about to get rough now
|
|
272
|
+
VALUE arr = Qnil, hsh = Qnil, hsh_key = Qnil;
|
|
273
|
+
VALUE k = ID2SYM(rb_intern2(pos, k_pos - pos)), v;
|
|
274
|
+
pos = k_pos;
|
|
275
|
+
uint8_t depth = 0;
|
|
276
|
+
|
|
277
|
+
while (*pos != '=' && pos < end) {
|
|
278
|
+
if (depth++ == PARAMS_MAX_DEPTH) {
|
|
279
|
+
rb_raise(rb_eRuntimeError, "Params too deep");
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (*pos == '[' && *(pos + 1) == ']') { // array
|
|
283
|
+
if (arr != Qnil) {
|
|
284
|
+
VALUE tmp = rb_ary_new();
|
|
285
|
+
rb_ary_push(arr, tmp);
|
|
286
|
+
arr = tmp;
|
|
287
|
+
} else if (hsh != Qnil) {
|
|
288
|
+
arr = rb_hash_aref(hsh, hsh_key);
|
|
289
|
+
if (arr == Qnil) {
|
|
290
|
+
arr = rb_ary_new();
|
|
291
|
+
rb_hash_aset(hsh, hsh_key, arr);
|
|
292
|
+
} else {
|
|
293
|
+
Check_Type(arr, T_ARRAY);
|
|
294
|
+
}
|
|
295
|
+
hsh = hsh_key = Qnil;
|
|
296
|
+
} else {
|
|
297
|
+
VALUE tmp = rb_hash_aref(params, k);
|
|
298
|
+
if (tmp != Qnil) {
|
|
299
|
+
Check_Type(tmp, T_ARRAY);
|
|
300
|
+
arr = tmp;
|
|
301
|
+
} else {
|
|
302
|
+
arr = rb_ary_new();
|
|
303
|
+
rb_hash_aset(params, k, arr);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
pos += 2;
|
|
308
|
+
|
|
309
|
+
} else if (*pos == '[' && *(pos + 1) != ']') { // hash
|
|
310
|
+
if (pos + 2 < end) {
|
|
311
|
+
k_pos = memchr(pos + 2, ']', end - pos - 2);
|
|
312
|
+
} else {
|
|
313
|
+
k_pos = NULL;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (!k_pos) {
|
|
317
|
+
rb_raise(rb_eRuntimeError, "Bad params");
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
VALUE prev_hsh_key = hsh_key;
|
|
321
|
+
hsh_key = ID2SYM(rb_intern2(pos + 1, k_pos - pos - 1));
|
|
322
|
+
|
|
323
|
+
if (hsh != Qnil) {
|
|
324
|
+
VALUE existing = rb_hash_aref(hsh, prev_hsh_key);
|
|
325
|
+
if (existing != Qnil) {
|
|
326
|
+
Check_Type(existing, T_HASH);
|
|
327
|
+
hsh = existing;
|
|
328
|
+
} else {
|
|
329
|
+
VALUE tmp = rb_hash_new();
|
|
330
|
+
rb_hash_aset(hsh, prev_hsh_key, tmp);
|
|
331
|
+
hsh = tmp;
|
|
332
|
+
}
|
|
333
|
+
} else if (arr != Qnil) {
|
|
334
|
+
VALUE nested_val = Qnil;
|
|
335
|
+
if (RARRAY_LEN(arr) != 0) {
|
|
336
|
+
VALUE tmp = rb_ary_entry(arr, -1);
|
|
337
|
+
Check_Type(tmp, T_HASH);
|
|
338
|
+
nested_val = rb_hash_aref(tmp, hsh_key);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// handle Rails' smart key grouping;
|
|
342
|
+
// "users[][data][id]=11&users[][data][name]=ross&users[][data][id]=22&users[][data][name]=chandler"
|
|
343
|
+
// should result in:
|
|
344
|
+
// { users: [{ data: { id: "11", name: "ross" } }, { data: { id: "22", name: "chandler" } }] }
|
|
345
|
+
if (RB_TYPE_P(nested_val, T_HASH)) {
|
|
346
|
+
char *n_pos_start = k_pos + 1, *n_pos_end = k_pos + 1;
|
|
347
|
+
|
|
348
|
+
while (nested_val != Qnil && *n_pos_start == '[' && *(n_pos_start + 1) != ']' && *n_pos_end != '&' && *n_pos_end != '=' && n_pos_end < end) {
|
|
349
|
+
n_pos_end++;
|
|
350
|
+
|
|
351
|
+
if (*n_pos_end == ']') {
|
|
352
|
+
VALUE nested_key = ID2SYM(rb_intern2(n_pos_start + 1, n_pos_end - n_pos_start - 1));
|
|
353
|
+
Check_Type(nested_val, T_HASH);
|
|
354
|
+
nested_val = rb_hash_aref(nested_val, nested_key);
|
|
355
|
+
n_pos_start = ++n_pos_end;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// use a new hash if there's none under this key or the existing one already has such key
|
|
361
|
+
if (RARRAY_LEN(arr) == 0 || nested_val != Qnil) {
|
|
362
|
+
hsh = rb_hash_new();
|
|
363
|
+
rb_ary_push(arr, hsh);
|
|
364
|
+
} else {
|
|
365
|
+
hsh = rb_ary_entry(arr, -1);
|
|
366
|
+
if (hsh != Qnil) {
|
|
367
|
+
Check_Type(hsh, T_HASH);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
arr = Qnil;
|
|
372
|
+
} else {
|
|
373
|
+
VALUE tmp = rb_hash_aref(params, k);
|
|
374
|
+
if (tmp != Qnil) {
|
|
375
|
+
Check_Type(tmp, T_HASH);
|
|
376
|
+
hsh = tmp;
|
|
377
|
+
} else {
|
|
378
|
+
hsh = rb_hash_new();
|
|
379
|
+
rb_hash_aset(params, k, hsh);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
pos = k_pos + 1;
|
|
384
|
+
|
|
269
385
|
} else {
|
|
270
|
-
|
|
386
|
+
pos++;
|
|
271
387
|
}
|
|
272
388
|
}
|
|
273
|
-
pair_end++;
|
|
274
|
-
}
|
|
275
389
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
size_t key_len = key_end - pos;
|
|
390
|
+
//
|
|
391
|
+
// write the final object into `params`
|
|
392
|
+
//
|
|
280
393
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
394
|
+
for (v_pos = pos + 1; *v_pos != '&' && v_pos < end; v_pos++) {
|
|
395
|
+
if (*v_pos == '%' || *v_pos == '+') {
|
|
396
|
+
should_decode = 1;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
286
399
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
} else if (key_len > 1 && memchr(key_data + 1, '[', key_len - 1)) {
|
|
293
|
-
value = rb_str_new(NULL, 0);
|
|
294
|
-
} else {
|
|
295
|
-
value = Qnil;
|
|
296
|
-
}
|
|
400
|
+
v = rb_str_new(pos + 1, v_pos - pos - 1);
|
|
401
|
+
if (should_decode) {
|
|
402
|
+
url_decode_inplace(Qnil, v);
|
|
403
|
+
should_decode = 0;
|
|
404
|
+
}
|
|
297
405
|
|
|
298
|
-
|
|
299
|
-
|
|
406
|
+
if (arr != Qnil) {
|
|
407
|
+
rb_ary_push(arr, v);
|
|
408
|
+
} else {
|
|
409
|
+
rb_hash_aset(hsh, hsh_key, v);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
pos = k_pos = v_pos + 1;
|
|
300
413
|
|
|
301
|
-
if (
|
|
302
|
-
|
|
414
|
+
} else if (*k_pos == '&' || k_pos >= end) {
|
|
415
|
+
VALUE k = ID2SYM(rb_intern2(pos, k_pos - pos));
|
|
416
|
+
rb_hash_aset(params, k, Qnil);
|
|
417
|
+
pos = k_pos + 1;
|
|
303
418
|
}
|
|
304
|
-
pos = pair_end + 1;
|
|
305
419
|
}
|
|
306
420
|
|
|
307
421
|
return params;
|
|
@@ -311,26 +425,21 @@ static VALUE parse_nested_query_internal(char *str, size_t len) {
|
|
|
311
425
|
Convert query string into a Ruby object.
|
|
312
426
|
*/
|
|
313
427
|
static VALUE parse_nested_query(VALUE self, VALUE r_str) {
|
|
428
|
+
return parse_nested_query_internal(RSTRING_PTR(r_str), RSTRING_LEN(r_str));
|
|
314
429
|
(void)self;
|
|
315
|
-
Check_Type(r_str, T_STRING);
|
|
316
|
-
VALUE result =
|
|
317
|
-
parse_nested_query_internal(RSTRING_PTR(r_str), RSTRING_LEN(r_str));
|
|
318
|
-
RB_GC_GUARD(r_str);
|
|
319
|
-
return result;
|
|
320
430
|
}
|
|
321
431
|
|
|
322
432
|
/**
|
|
323
433
|
Convert urlencoded body into a Ruby object.
|
|
324
434
|
*/
|
|
325
435
|
static VALUE parse_urlencoded_nested_query(VALUE self, VALUE r_str) {
|
|
436
|
+
ssize_t len = http_decode_url(RSTRING_PTR(r_str), RSTRING_PTR(r_str), RSTRING_LEN(r_str));
|
|
437
|
+
if (len < 0) {
|
|
438
|
+
rb_raise(rb_eRuntimeError, "Invalid encoding");
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
return parse_nested_query_internal(RSTRING_PTR(r_str), len);
|
|
326
442
|
(void)self;
|
|
327
|
-
Check_Type(r_str, T_STRING);
|
|
328
|
-
char *str = RSTRING_PTR(r_str);
|
|
329
|
-
size_t len = RSTRING_LEN(r_str);
|
|
330
|
-
|
|
331
|
-
VALUE result = parse_nested_query_internal(str, len);
|
|
332
|
-
RB_GC_GUARD(r_str);
|
|
333
|
-
return result;
|
|
334
443
|
}
|
|
335
444
|
|
|
336
445
|
/**
|
data/ext/iodine/scheduler.c
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
#include "iodine.h"
|
|
2
2
|
#include "iodine_store.h"
|
|
3
3
|
#include "ruby.h"
|
|
4
|
+
#include "ruby/fiber/scheduler.h"
|
|
5
|
+
#include "ruby/io/buffer.h"
|
|
4
6
|
|
|
5
7
|
#include <errno.h>
|
|
6
8
|
#include <stddef.h>
|
|
@@ -10,7 +12,7 @@
|
|
|
10
12
|
|
|
11
13
|
#include "fio.h"
|
|
12
14
|
|
|
13
|
-
#define IO_MAX_READ
|
|
15
|
+
#define IO_MAX_READ 65536
|
|
14
16
|
|
|
15
17
|
static ID call_id;
|
|
16
18
|
static uint8_t ATTACH_ON_READ_READY_CALLBACK;
|
|
@@ -151,51 +153,104 @@ static VALUE iodine_scheduler_attach(VALUE self, VALUE r_fd, VALUE r_waittype, V
|
|
|
151
153
|
(void)self;
|
|
152
154
|
}
|
|
153
155
|
|
|
154
|
-
static VALUE
|
|
156
|
+
static VALUE iodine_scheduler_write_async(VALUE self, VALUE r_fd, VALUE r_buffer, VALUE r_length, VALUE r_offset) {
|
|
155
157
|
Check_Type(r_fd, T_FIXNUM);
|
|
156
158
|
int fd = FIX2INT(r_fd);
|
|
157
159
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
+
const void *buffer;
|
|
161
|
+
size_t buffer_length;
|
|
162
|
+
rb_io_buffer_get_bytes_for_reading(r_buffer, &buffer, &buffer_length);
|
|
160
163
|
|
|
161
164
|
Check_Type(r_length, T_FIXNUM);
|
|
162
|
-
|
|
165
|
+
size_t length = NUM2SIZET(r_length);
|
|
163
166
|
|
|
164
167
|
Check_Type(r_offset, T_FIXNUM);
|
|
165
|
-
|
|
168
|
+
size_t offset = NUM2SIZET(r_offset);
|
|
169
|
+
|
|
170
|
+
if (offset > buffer_length || length > buffer_length - offset) {
|
|
171
|
+
return rb_fiber_scheduler_io_result(-1, EINVAL);
|
|
172
|
+
}
|
|
173
|
+
if (!length) {
|
|
174
|
+
return r_length;
|
|
175
|
+
}
|
|
166
176
|
|
|
167
177
|
void *cpy = fio_malloc(length);
|
|
168
|
-
memcpy(cpy, buffer, length);
|
|
169
|
-
fio_write2(fio_fd2uuid(fd), .data.buffer = cpy, .length = length, .
|
|
178
|
+
memcpy(cpy, (const char *)buffer + offset, length);
|
|
179
|
+
fio_write2(fio_fd2uuid(fd), .data.buffer = cpy, .length = length, .after.dealloc = fio_free);
|
|
170
180
|
|
|
171
181
|
return r_length;
|
|
172
182
|
|
|
173
183
|
(void)self;
|
|
174
184
|
}
|
|
175
185
|
|
|
176
|
-
static VALUE
|
|
186
|
+
static VALUE iodine_scheduler_write(VALUE self, VALUE r_fd, VALUE r_buffer, VALUE r_length, VALUE r_offset) {
|
|
177
187
|
Check_Type(r_fd, T_FIXNUM);
|
|
178
188
|
int fd = FIX2INT(r_fd);
|
|
179
189
|
|
|
190
|
+
const void *buffer;
|
|
191
|
+
size_t buffer_length;
|
|
192
|
+
rb_io_buffer_get_bytes_for_reading(r_buffer, &buffer, &buffer_length);
|
|
193
|
+
|
|
180
194
|
Check_Type(r_length, T_FIXNUM);
|
|
181
|
-
|
|
195
|
+
size_t length = NUM2SIZET(r_length);
|
|
182
196
|
|
|
183
|
-
|
|
184
|
-
|
|
197
|
+
Check_Type(r_offset, T_FIXNUM);
|
|
198
|
+
size_t offset = NUM2SIZET(r_offset);
|
|
199
|
+
|
|
200
|
+
if (offset > buffer_length || length > buffer_length - offset) {
|
|
201
|
+
return rb_fiber_scheduler_io_result(-1, EINVAL);
|
|
202
|
+
}
|
|
203
|
+
if (!length) {
|
|
204
|
+
return rb_fiber_scheduler_io_result(0, 0);
|
|
185
205
|
}
|
|
186
206
|
|
|
187
|
-
|
|
188
|
-
|
|
207
|
+
ssize_t result = fio_write_once(fio_fd2uuid(fd), (const char *)buffer + offset, length);
|
|
208
|
+
int error = result < 0 ? errno : 0;
|
|
209
|
+
return rb_fiber_scheduler_io_result(result, error);
|
|
210
|
+
|
|
211
|
+
(void)self;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
static VALUE iodine_scheduler_read(VALUE self, VALUE r_fd, VALUE r_buffer, VALUE r_length, VALUE r_offset) {
|
|
215
|
+
Check_Type(r_fd, T_FIXNUM);
|
|
216
|
+
int fd = FIX2INT(r_fd);
|
|
217
|
+
|
|
218
|
+
void *buffer;
|
|
219
|
+
size_t buffer_length;
|
|
220
|
+
rb_io_buffer_get_bytes_for_writing(r_buffer, &buffer, &buffer_length);
|
|
221
|
+
|
|
222
|
+
Check_Type(r_length, T_FIXNUM);
|
|
223
|
+
size_t length = NUM2SIZET(r_length);
|
|
224
|
+
|
|
225
|
+
Check_Type(r_offset, T_FIXNUM);
|
|
226
|
+
size_t offset = NUM2SIZET(r_offset);
|
|
227
|
+
|
|
228
|
+
if (offset > buffer_length || length > buffer_length - offset) {
|
|
229
|
+
return rb_fiber_scheduler_io_result(-1, EINVAL);
|
|
230
|
+
}
|
|
189
231
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
232
|
+
#if RUBY_FIBER_SCHEDULER_VERSION >= 4
|
|
233
|
+
if (length > IO_MAX_READ) {
|
|
234
|
+
length = IO_MAX_READ;
|
|
235
|
+
}
|
|
236
|
+
#else
|
|
237
|
+
if (length == 0) {
|
|
238
|
+
length = buffer_length - offset;
|
|
239
|
+
if (length > IO_MAX_READ) {
|
|
240
|
+
length = IO_MAX_READ;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
#endif
|
|
244
|
+
|
|
245
|
+
if (!length) {
|
|
246
|
+
return rb_fiber_scheduler_io_result(0, 0);
|
|
193
247
|
}
|
|
194
248
|
|
|
195
|
-
|
|
249
|
+
ssize_t result = fio_read_once(fio_fd2uuid(fd), (char *)buffer + offset, length);
|
|
250
|
+
int error = result < 0 ? errno : 0;
|
|
251
|
+
return rb_fiber_scheduler_io_result(result, error);
|
|
196
252
|
|
|
197
253
|
(void)self;
|
|
198
|
-
(void)r_offset;
|
|
199
254
|
}
|
|
200
255
|
|
|
201
256
|
static VALUE iodine_scheduler_close(VALUE self) {
|
|
@@ -219,8 +274,9 @@ void iodine_scheduler_initialize(void) {
|
|
|
219
274
|
VALUE SchedulerModule = rb_define_module_under(IodineModule, "Scheduler");
|
|
220
275
|
|
|
221
276
|
rb_define_module_function(SchedulerModule, "attach", iodine_scheduler_attach, 3);
|
|
277
|
+
rb_define_module_function(SchedulerModule, "write_async", iodine_scheduler_write_async, 4);
|
|
222
278
|
rb_define_module_function(SchedulerModule, "write", iodine_scheduler_write, 4);
|
|
223
|
-
rb_define_module_function(SchedulerModule, "read", iodine_scheduler_read,
|
|
279
|
+
rb_define_module_function(SchedulerModule, "read", iodine_scheduler_read, 4);
|
|
224
280
|
rb_define_module_function(SchedulerModule, "close", iodine_scheduler_close, 0);
|
|
225
281
|
|
|
226
282
|
VALUE cIO = rb_const_get(rb_cObject, rb_intern2("IO", 2));
|
data/lib/iodine/version.rb
CHANGED