Module: Iodine::Rack::Utils
- Defined in:
- lib/iodine/rack_utils.rb,
ext/iodine/iodine_helpers.c
Overview
Choosing to monkey patch Rack::Utils could offer significant performance gains for some applications. i.e. (on my machine):
require 'iodine'
require 'rack'
# a String in need of decoding
s = '%E3%83%AB%E3%83%93%E3%82%A4%E3%82%B9%E3%81%A8'
Benchmark.bm do |bm|
# Pre-Patch
bm.report(" Rack.unescape") {1_000_000.times { Rack::Utils.unescape s } }
bm.report(" Rack.rfc2822") {1_000_000.times { Rack::Utils.rfc2822(Time.now) } }
bm.report(" Rack.rfc2109") {1_000_000.times { Rack::Utils.rfc2109(Time.now) } }
# Perform Patch
Iodine.patch_rack
puts " --- Monkey Patching Rack ---"
# Post Patch
bm.report("Patched.unescape") {1_000_000.times { Rack::Utils.unescape s } }
bm.report(" Patched.rfc2822") {1_000_000.times { Rack::Utils.rfc2822(Time.now) } }
bm.report(" Patched.rfc2109") {1_000_000.times { Rack::Utils.rfc2109(Time.now) } }
end && nil
Results:
user system total real
Rack.unescape 8.706881 0.019995 8.726876 ( 8.740530)
Rack.rfc2822 3.270305 0.007519 3.277824 ( 3.279416)
Rack.rfc2109 3.152188 0.003852 3.156040 ( 3.157975)
--- Monkey Patching Rack ---
Patched.unescape 0.327231 0.003125 0.330356 ( 0.337090)
Patched.rfc2822 0.691304 0.003330 0.694634 ( 0.701172)
Patched.rfc2109 0.685029 0.001956 0.686985 ( 0.687607)
Iodine uses the same code internally for HTTP timestamping (adding missing Date headers) and logging.
Class Method Summary collapse
-
.decode_path(str) ⇒ Object
Decodes a percent encoded String (normally the "path" of a request), returning a new String with the decoded data.
-
.decode_path!(str) ⇒ Object
Decodes a percent encoded String (normally the "path" of a request), editing the String in place.
-
.decode_url(str) ⇒ Object
Decodes a URL encoded String, returning a new String with the decoded data.
-
.decode_url!(str) ⇒ Object
Decodes a URL encoded String in place.
-
.parse_multipart(rack_io, content_type) ⇒ Object
Convert multipart/form-data into a Ruby object.
-
.parse_nested_query(r_str) ⇒ Object
Convert query string into a Ruby object.
-
.parse_urlencoded_nested_query(r_str) ⇒ Object
Convert urlencoded body into a Ruby object.
-
.rfc2109(rtm) ⇒ Object
Takes
timeand returns a faster (though less localized) HTTP Date formatted String. -
.rfc2822(rtm) ⇒ Object
Takes
timeand returns a faster (though less localized) HTTP Date formatted String. -
.time2str(*args) ⇒ Object
Takes an optional Integer for Unix Time and returns a faster (though less localized) HTTP Date formatted String.
Class Method Details
.decode_path(str) ⇒ Object
Decodes a percent encoded String (normally the "path" of a request), returning a new String with the decoded data.
79 80 81 82 83 84 85 86 87 88 89 |
# File 'ext/iodine/iodine_helpers.c', line 79
static VALUE path_decode(VALUE self, VALUE str) {
Check_Type(str, T_STRING);
VALUE str2 = rb_str_buf_new(RSTRING_LEN(str));
ssize_t len =
http_decode_path(RSTRING_PTR(str2), RSTRING_PTR(str), RSTRING_LEN(str));
if (len < 0)
rb_raise(rb_eRuntimeError, "Malformed URL path string - couldn't decode.");
rb_str_set_len(str2, len);
return str2;
(void)self;
}
|
.decode_path!(str) ⇒ Object
Decodes a percent encoded String (normally the "path" of a request), editing the String in place.
Raises an exception on error... but this might result in a partially decoded String.
62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'ext/iodine/iodine_helpers.c', line 62
static VALUE path_decode_inplace(VALUE self, VALUE str) {
Check_Type(str, T_STRING);
ssize_t len =
http_decode_path(RSTRING_PTR(str), RSTRING_PTR(str), RSTRING_LEN(str));
if (len < 0)
rb_raise(rb_eRuntimeError,
"Malformed URL path string - couldn't decode (String "
"might have been partially altered).");
rb_str_set_len(str, len);
return str;
(void)self;
}
|
.decode_url(str) ⇒ Object
Decodes a URL encoded String, returning a new String with the decoded data.
43 44 45 46 47 48 49 50 51 52 53 |
# File 'ext/iodine/iodine_helpers.c', line 43
static VALUE url_decode(VALUE self, VALUE str) {
Check_Type(str, T_STRING);
VALUE str2 = rb_str_buf_new(RSTRING_LEN(str));
ssize_t len =
http_decode_url(RSTRING_PTR(str2), RSTRING_PTR(str), RSTRING_LEN(str));
if (len < 0)
rb_raise(rb_eRuntimeError, "Malformed URL string - couldn't decode.");
rb_str_set_len(str2, len);
return str2;
(void)self;
}
|
.decode_url!(str) ⇒ Object
Decodes a URL encoded String in place.
Raises an exception on error... but this might result in a partially decoded String.
28 29 30 31 32 33 34 35 36 37 38 |
# File 'ext/iodine/iodine_helpers.c', line 28
static VALUE url_decode_inplace(VALUE self, VALUE str) {
Check_Type(str, T_STRING);
ssize_t len =
http_decode_url(RSTRING_PTR(str), RSTRING_PTR(str), RSTRING_LEN(str));
if (len < 0)
rb_raise(rb_eRuntimeError, "Malformed URL string - couldn't decode (String "
"might have been partially altered).");
rb_str_set_len(str, len);
return str;
(void)self;
}
|
.parse_multipart(rack_io, content_type) ⇒ Object
Convert multipart/form-data into a Ruby object.
448 449 450 451 452 453 454 455 456 457 |
# File 'ext/iodine/iodine_helpers.c', line 448
static VALUE parse_multipart(VALUE self, VALUE rack_io, VALUE content_type) {
http_s *h = IodineRackIO.get_handle(rack_io);
if (content_type == Qnil) {
rb_raise(rb_eRuntimeError, "Incorrect content type for multipart request");
}
return http_parse_multipart(h, RSTRING_PTR(content_type), RSTRING_LEN(content_type));
(void)self;
}
|
.parse_nested_query(r_str) ⇒ Object
Convert query string into a Ruby object.
427 428 429 430 |
# File 'ext/iodine/iodine_helpers.c', line 427
static VALUE parse_nested_query(VALUE self, VALUE r_str) {
return parse_nested_query_internal(RSTRING_PTR(r_str), RSTRING_LEN(r_str));
(void)self;
}
|
.parse_urlencoded_nested_query(r_str) ⇒ Object
Convert urlencoded body into a Ruby object.
435 436 437 438 439 440 441 442 443 |
# File 'ext/iodine/iodine_helpers.c', line 435
static VALUE parse_urlencoded_nested_query(VALUE self, VALUE r_str) {
ssize_t len = http_decode_url(RSTRING_PTR(r_str), RSTRING_PTR(r_str), RSTRING_LEN(r_str));
if (len < 0) {
rb_raise(rb_eRuntimeError, "Invalid encoding");
}
return parse_nested_query_internal(RSTRING_PTR(r_str), len);
(void)self;
}
|
.rfc2109(rtm) ⇒ Object
Takes time and returns a faster (though less localized) HTTP Date formatted
String.
Iodine::Rack.rfc2109(Time.now) => "Sun, 11-Jun-2017 06:14:08 GMT"
Iodine::Rack.rfc2109(0) => "Sun, 11-Jun-2017 06:14:08 GMT"
Since Iodine uses time caching within it's reactor, using the default value
(by passing 0) will be faster than providing an explicit time using Time.now.
198 199 200 201 202 203 204 205 206 207 208 209 210 |
# File 'ext/iodine/iodine_helpers.c', line 198
static VALUE iodine_rfc2109(VALUE self, VALUE rtm) {
time_t last_tick;
rtm = rb_funcallv(rtm, iodine_to_i_func_id, 0, NULL);
last_tick = FIX2ULONG(rtm) ? FIX2ULONG(rtm) : fio_last_tick().tv_sec;
VALUE str = rb_str_buf_new(32);
struct tm tm;
http_gmtime(last_tick, &tm);
size_t len = http_date2rfc2109(RSTRING_PTR(str), &tm);
rb_str_set_len(str, len);
return str;
(void)self;
}
|
.rfc2822(rtm) ⇒ Object
Takes time and returns a faster (though less localized) HTTP Date formatted
String.
Iodine::Rack.rfc2822(Time.now) => "Sun, 11 Jun 2017 06:14:08 -0000"
Iodine::Rack.rfc2822(0) => "Sun, 11 Jun 2017 06:14:08 -0000"
Since Iodine uses time caching within it's reactor, using the default value
(by passing 0) will be faster than providing an explicit time using Time.now.
172 173 174 175 176 177 178 179 180 181 182 183 184 |
# File 'ext/iodine/iodine_helpers.c', line 172
static VALUE iodine_rfc2822(VALUE self, VALUE rtm) {
time_t last_tick;
rtm = rb_funcallv(rtm, iodine_to_i_func_id, 0, NULL);
last_tick = FIX2ULONG(rtm) ? FIX2ULONG(rtm) : fio_last_tick().tv_sec;
VALUE str = rb_str_buf_new(34);
struct tm tm;
http_gmtime(last_tick, &tm);
size_t len = http_date2rfc2822(RSTRING_PTR(str), &tm);
rb_str_set_len(str, len);
return str;
(void)self;
}
|
.time2str(*args) ⇒ Object
Takes an optional Integer for Unix Time and returns a faster (though less localized) HTTP Date formatted String.
Iodine::Rack.time2str => "Sun, 11 Jun 2017 06:14:08 GMT"
Iodine::Rack.time2str(Time.now.to_i) => "Wed, 15 Nov 1995 06:25:24 GMT"
Since Iodine uses time caching within it's reactor, using the default value
(now) will be faster than providing an explicit time using Time.now.to_i.
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
# File 'ext/iodine/iodine_helpers.c', line 137
static VALUE date_str(int argc, VALUE *argv, VALUE self) {
if (argc > 1)
rb_raise(rb_eArgError,
"wrong number of arguments (given %d, expected 0..1).", argc);
time_t last_tick;
if (argc) {
if (TYPE(argv[0]) != T_FIXNUM)
argv[0] = rb_funcallv(argv[0], iodine_to_i_func_id, 0, NULL);
Check_Type(argv[0], T_FIXNUM);
last_tick =
FIX2ULONG(argv[0]) ? FIX2ULONG(argv[0]) : fio_last_tick().tv_sec;
} else
last_tick = fio_last_tick().tv_sec;
VALUE str = rb_str_buf_new(32);
struct tm tm;
http_gmtime(last_tick, &tm);
size_t len = http_date2str(RSTRING_PTR(str), &tm);
rb_str_set_len(str, len);
return str;
(void)self;
}
|