isomorfeus-iodine 0.7.45 → 0.7.48

Sign up to get free protection for your applications and to get access to all the features.
@@ -10,7 +10,7 @@
10
10
  static pthread_key_t iodine_GVL_state_key;
11
11
  static pthread_once_t iodine_GVL_state_once = PTHREAD_ONCE_INIT;
12
12
  static void init_iodine_GVL_state_key(void) {
13
- pthread_key_create(&iodine_GVL_state_key, NULL);
13
+ pthread_key_create(&iodine_GVL_state_key, NULL);
14
14
  }
15
15
  static void init_iodine_GVL_state_init(void) {
16
16
  uint8_t *gvl = malloc(sizeof(uint8_t));
@@ -31,7 +31,7 @@ typedef struct {
31
31
  ID method;
32
32
  int exception;
33
33
  VALUE (*protected_task)(VALUE tsk_);
34
- VALUE (*each_func)(VALUE block_arg, VALUE data, int argc, VALUE *argv);
34
+ rb_block_call_func_t each_func;
35
35
  VALUE each_udata;
36
36
  } iodine_rb_task_s;
37
37
 
@@ -158,9 +158,7 @@ static VALUE iodine_call2(VALUE obj, ID method, int argc, VALUE *argv) {
158
158
 
159
159
  /** Calls a Ruby method on a given object, protecting against exceptions. */
160
160
  static VALUE iodine_call_block(VALUE obj, ID method, int argc, VALUE *argv,
161
- VALUE udata,
162
- VALUE(each_func)(VALUE block_arg, VALUE udata,
163
- int argc, VALUE *argv)) {
161
+ VALUE udata, rb_block_call_func_t each_func) {
164
162
  iodine_rb_task_s task = {
165
163
  .obj = obj,
166
164
  .argc = argc,
@@ -186,7 +184,7 @@ static uint8_t iodine_in_GVL(void) {
186
184
  }
187
185
 
188
186
  /** Forces the GVL state flag. */
189
- static void iodine_set_GVL(uint8_t state) {
187
+ static void iodine_set_GVL(uint8_t state) {
190
188
  pthread_once(&iodine_GVL_state_once, init_iodine_GVL_state_key);
191
189
  uint8_t *iodine_GVL_state = pthread_getspecific(iodine_GVL_state_key);
192
190
  if (!iodine_GVL_state) {
@@ -1,27 +1,26 @@
1
- #ifndef H_IODINE_CALLER_H
2
- #define H_IODINE_CALLER_H
3
-
4
- #include "ruby.h"
5
-
6
- #include <stdint.h>
7
-
8
- extern struct IodineCaller_s {
9
- /** Calls a C function within the GVL (unprotected). */
10
- void *(*enterGVL)(void *(*func)(void *), void *arg);
11
- /** Calls a C function outside the GVL (no Ruby API calls allowed). */
12
- void *(*leaveGVL)(void *(*func)(void *), void *arg);
13
- /** Calls a Ruby method on a given object, protecting against exceptions. */
14
- VALUE (*call)(VALUE obj, ID method);
15
- /** Calls a Ruby method on a given object, protecting against exceptions. */
16
- VALUE (*call2)(VALUE obj, ID method, int argc, VALUE *argv);
17
- /** Calls a Ruby method on a given object, protecting against exceptions. */
18
- VALUE(*call_with_block)
19
- (VALUE obj, ID method, int argc, VALUE *argv, VALUE udata,
20
- VALUE (*block_func)(VALUE block_argv1, VALUE udata, int argc, VALUE *argv));
21
- /** Returns the GVL state flag. */
22
- uint8_t (*in_GVL)(void);
23
- /** Forces the GVL state flag. */
24
- void (*set_GVL)(uint8_t state);
25
- } IodineCaller;
26
-
27
- #endif
1
+ #ifndef H_IODINE_CALLER_H
2
+ #define H_IODINE_CALLER_H
3
+
4
+ #include "ruby.h"
5
+
6
+ #include <stdint.h>
7
+
8
+ extern struct IodineCaller_s {
9
+ /** Calls a C function within the GVL (unprotected). */
10
+ void *(*enterGVL)(void *(*func)(void *), void *arg);
11
+ /** Calls a C function outside the GVL (no Ruby API calls allowed). */
12
+ void *(*leaveGVL)(void *(*func)(void *), void *arg);
13
+ /** Calls a Ruby method on a given object, protecting against exceptions. */
14
+ VALUE (*call)(VALUE obj, ID method);
15
+ /** Calls a Ruby method on a given object, protecting against exceptions. */
16
+ VALUE (*call2)(VALUE obj, ID method, int argc, VALUE *argv);
17
+ /** Calls a Ruby method on a given object, protecting against exceptions. */
18
+ VALUE(*call_with_block)
19
+ (VALUE obj, ID method, int argc, VALUE *argv, VALUE udata, rb_block_call_func_t block_func);
20
+ /** Returns the GVL state flag. */
21
+ uint8_t (*in_GVL)(void);
22
+ /** Forces the GVL state flag. */
23
+ void (*set_GVL)(uint8_t state);
24
+ } IodineCaller;
25
+
26
+ #endif
@@ -900,7 +900,7 @@ void iodine_connection_init(void) {
900
900
  IodineStore.add(RAWSymbol);
901
901
 
902
902
  // define the Connection Class and it's methods
903
- ConnectionKlass = rb_define_class_under(IodineModule, "Connection", rb_cData);
903
+ ConnectionKlass = rb_define_class_under(IodineModule, "Connection", rb_cObject);
904
904
  rb_define_alloc_func(ConnectionKlass, iodine_connection_data_alloc_c);
905
905
  rb_define_method(ConnectionKlass, "write", iodine_connection_write, 1);
906
906
  rb_define_method(ConnectionKlass, "close", iodine_connection_close, 0);
@@ -1,282 +1,282 @@
1
- /*
2
- Copyright: Boaz segev, 2016-2017
3
- License: MIT
4
-
5
- Feel free to copy, use and enjoy according to the license provided.
6
- */
7
- #include "iodine.h"
8
-
9
- #include "http.h"
10
- #include <ruby/encoding.h>
11
-
12
- /*
13
- Add all sorts of useless stuff here.
14
- */
15
-
16
- static ID iodine_to_i_func_id;
17
- static rb_encoding *IodineUTF8Encoding;
18
-
19
- /* *****************************************************************************
20
- URL Decoding
21
- ***************************************************************************** */
22
- /**
23
- Decodes a URL encoded String in place.
24
-
25
- Raises an exception on error... but this might result in a partially decoded
26
- String.
27
- */
28
- static VALUE url_decode_inplace(VALUE self, VALUE str) {
29
- Check_Type(str, T_STRING);
30
- ssize_t len =
31
- http_decode_url(RSTRING_PTR(str), RSTRING_PTR(str), RSTRING_LEN(str));
32
- if (len < 0)
33
- rb_raise(rb_eRuntimeError, "Malformed URL string - couldn't decode (String "
34
- "might have been partially altered).");
35
- rb_str_set_len(str, len);
36
- return str;
37
- (void)self;
38
- }
39
-
40
- /**
41
- Decodes a URL encoded String, returning a new String with the decoded data.
42
- */
43
- static VALUE url_decode(VALUE self, VALUE str) {
44
- Check_Type(str, T_STRING);
45
- VALUE str2 = rb_str_buf_new(RSTRING_LEN(str));
46
- ssize_t len =
47
- http_decode_url(RSTRING_PTR(str2), RSTRING_PTR(str), RSTRING_LEN(str));
48
- if (len < 0)
49
- rb_raise(rb_eRuntimeError, "Malformed URL string - couldn't decode.");
50
- rb_str_set_len(str2, len);
51
- return str2;
52
- (void)self;
53
- }
54
-
55
- /**
56
- Decodes a percent encoded String (normally the "path" of a request), editing the
57
- String in place.
58
-
59
- Raises an exception on error... but this might result in a partially decoded
60
- String.
61
- */
62
- static VALUE path_decode_inplace(VALUE self, VALUE str) {
63
- Check_Type(str, T_STRING);
64
- ssize_t len =
65
- http_decode_path(RSTRING_PTR(str), RSTRING_PTR(str), RSTRING_LEN(str));
66
- if (len < 0)
67
- rb_raise(rb_eRuntimeError,
68
- "Malformed URL path string - couldn't decode (String "
69
- "might have been partially altered).");
70
- rb_str_set_len(str, len);
71
- return str;
72
- (void)self;
73
- }
74
-
75
- /**
76
- Decodes a percent encoded String (normally the "path" of a request), returning a
77
- new String with the decoded data.
78
- */
79
- static VALUE path_decode(VALUE self, VALUE str) {
80
- Check_Type(str, T_STRING);
81
- VALUE str2 = rb_str_buf_new(RSTRING_LEN(str));
82
- ssize_t len =
83
- http_decode_path(RSTRING_PTR(str2), RSTRING_PTR(str), RSTRING_LEN(str));
84
- if (len < 0)
85
- rb_raise(rb_eRuntimeError, "Malformed URL path string - couldn't decode.");
86
- rb_str_set_len(str2, len);
87
- return str2;
88
- (void)self;
89
- }
90
-
91
- /**
92
- Decodes a URL encoded String, returning a new String with the decoded data.
93
-
94
- This variation matches the Rack::Utils.unescape signature by accepting and
95
- mostly ignoring an optional Encoding argument.
96
- */
97
- static VALUE unescape(int argc, VALUE *argv, VALUE self) {
98
- if (argc < 1 || argc > 2)
99
- rb_raise(rb_eArgError,
100
- "wrong number of arguments (given %d, expected 1..2).", argc);
101
- VALUE str = argv[0];
102
- Check_Type(str, T_STRING);
103
- VALUE str2 = rb_str_buf_new(RSTRING_LEN(str));
104
- ssize_t len =
105
- http_decode_url(RSTRING_PTR(str2), RSTRING_PTR(str), RSTRING_LEN(str));
106
- if (len < 0)
107
- rb_raise(rb_eRuntimeError, "Malformed URL path string - couldn't decode.");
108
- rb_str_set_len(str2, len);
109
- rb_encoding *enc = IodineUTF8Encoding;
110
- if (argc == 2 && argv[1] != Qnil && argv[1] != Qfalse) {
111
- enc = rb_enc_get(argv[1]);
112
- if (!enc)
113
- enc = IodineUTF8Encoding;
114
- }
115
- rb_enc_associate(str2, enc);
116
- return str2;
117
- (void)self;
118
- }
119
-
120
- /* *****************************************************************************
121
- HTTP Dates
122
- ***************************************************************************** */
123
-
124
- /**
125
- Takes an optional Integer for Unix Time and returns a faster (though less
126
- localized) HTTP Date formatted String.
127
-
128
-
129
- Iodine::Rack.time2str => "Sun, 11 Jun 2017 06:14:08 GMT"
130
-
131
- Iodine::Rack.time2str(Time.now.to_i) => "Wed, 15 Nov 1995 06:25:24 GMT"
132
-
133
- Since Iodine uses time caching within it's reactor, using the default value
134
- (now) will be faster than providing an explicit time using `Time.now.to_i`.
135
-
136
- */
137
- static VALUE date_str(int argc, VALUE *argv, VALUE self) {
138
- if (argc > 1)
139
- rb_raise(rb_eArgError,
140
- "wrong number of arguments (given %d, expected 0..1).", argc);
141
- time_t last_tick;
142
- if (argc) {
143
- if (TYPE(argv[0]) != T_FIXNUM)
144
- argv[0] = rb_funcallv(argv[0], iodine_to_i_func_id, 0, NULL);
145
- Check_Type(argv[0], T_FIXNUM);
146
- last_tick =
147
- FIX2ULONG(argv[0]) ? FIX2ULONG(argv[0]) : fio_last_tick().tv_sec;
148
- } else
149
- last_tick = fio_last_tick().tv_sec;
150
- VALUE str = rb_str_buf_new(32);
151
- struct tm tm;
152
-
153
- http_gmtime(last_tick, &tm);
154
- size_t len = http_date2str(RSTRING_PTR(str), &tm);
155
- rb_str_set_len(str, len);
156
- return str;
157
- (void)self;
158
- }
159
-
160
- /**
161
- Takes `time` and returns a faster (though less localized) HTTP Date formatted
162
- String.
163
-
164
-
165
- Iodine::Rack.rfc2822(Time.now) => "Sun, 11 Jun 2017 06:14:08 -0000"
166
-
167
- Iodine::Rack.rfc2822(0) => "Sun, 11 Jun 2017 06:14:08 -0000"
168
-
169
- Since Iodine uses time caching within it's reactor, using the default value
170
- (by passing 0) will be faster than providing an explicit time using `Time.now`.
171
- */
172
- static VALUE iodine_rfc2822(VALUE self, VALUE rtm) {
173
- time_t last_tick;
174
- rtm = rb_funcallv(rtm, iodine_to_i_func_id, 0, NULL);
175
- last_tick = FIX2ULONG(rtm) ? FIX2ULONG(rtm) : fio_last_tick().tv_sec;
176
- VALUE str = rb_str_buf_new(34);
177
- struct tm tm;
178
-
179
- http_gmtime(last_tick, &tm);
180
- size_t len = http_date2rfc2822(RSTRING_PTR(str), &tm);
181
- rb_str_set_len(str, len);
182
- return str;
183
- (void)self;
184
- }
185
-
186
- /**
187
- Takes `time` and returns a faster (though less localized) HTTP Date formatted
188
- String.
189
-
190
-
191
- Iodine::Rack.rfc2109(Time.now) => "Sun, 11-Jun-2017 06:14:08 GMT"
192
-
193
- Iodine::Rack.rfc2109(0) => "Sun, 11-Jun-2017 06:14:08 GMT"
194
-
195
- Since Iodine uses time caching within it's reactor, using the default value
196
- (by passing 0) will be faster than providing an explicit time using `Time.now`.
197
- */
198
- static VALUE iodine_rfc2109(VALUE self, VALUE rtm) {
199
- time_t last_tick;
200
- rtm = rb_funcallv(rtm, iodine_to_i_func_id, 0, NULL);
201
- last_tick = FIX2ULONG(rtm) ? FIX2ULONG(rtm) : fio_last_tick().tv_sec;
202
- VALUE str = rb_str_buf_new(32);
203
- struct tm tm;
204
-
205
- http_gmtime(last_tick, &tm);
206
- size_t len = http_date2rfc2109(RSTRING_PTR(str), &tm);
207
- rb_str_set_len(str, len);
208
- return str;
209
- (void)self;
210
- }
211
-
212
- /* *****************************************************************************
213
- Ruby Initialization
214
- ***************************************************************************** */
215
-
216
- void iodine_init_helpers(void) {
217
- iodine_to_i_func_id = rb_intern("to_i");
218
- IodineUTF8Encoding = rb_enc_find("UTF-8");
219
- VALUE tmp = rb_define_module_under(IodineModule, "Rack");
220
- // clang-format off
221
- /*
222
- Iodine does NOT monkey patch Rack automatically. However, it's possible and recommended to moneky patch Rack::Utils to use the methods in this module.
223
-
224
- Choosing to monkey patch Rack::Utils could offer significant performance gains for some applications. i.e. (on my machine):
225
-
226
- require 'iodine'
227
- require 'rack'
228
- # a String in need of decoding
229
- s = '%E3%83%AB%E3%83%93%E3%82%A4%E3%82%B9%E3%81%A8'
230
- Benchmark.bm do |bm|
231
- # Pre-Patch
232
- bm.report(" Rack.unescape") {1_000_000.times { Rack::Utils.unescape s } }
233
- bm.report(" Rack.rfc2822") {1_000_000.times { Rack::Utils.rfc2822(Time.now) } }
234
- bm.report(" Rack.rfc2109") {1_000_000.times { Rack::Utils.rfc2109(Time.now) } }
235
- # Perform Patch
236
- Iodine.patch_rack
237
- puts " --- Monkey Patching Rack ---"
238
- # Post Patch
239
- bm.report("Patched.unescape") {1_000_000.times { Rack::Utils.unescape s } }
240
- bm.report(" Patched.rfc2822") {1_000_000.times { Rack::Utils.rfc2822(Time.now) } }
241
- bm.report(" Patched.rfc2109") {1_000_000.times { Rack::Utils.rfc2109(Time.now) } }
242
- end && nil
243
-
244
- Results:
245
- user system total real
246
- Rack.unescape 8.706881 0.019995 8.726876 ( 8.740530)
247
- Rack.rfc2822 3.270305 0.007519 3.277824 ( 3.279416)
248
- Rack.rfc2109 3.152188 0.003852 3.156040 ( 3.157975)
249
- --- Monkey Patching Rack ---
250
- Patched.unescape 0.327231 0.003125 0.330356 ( 0.337090)
251
- Patched.rfc2822 0.691304 0.003330 0.694634 ( 0.701172)
252
- Patched.rfc2109 0.685029 0.001956 0.686985 ( 0.687607)
253
-
254
- */
255
- tmp = rb_define_module_under(tmp, "Utils");
256
- // clang-format on
257
- rb_define_module_function(tmp, "decode_url!", url_decode_inplace, 1);
258
- rb_define_module_function(tmp, "decode_url", url_decode, 1);
259
- rb_define_module_function(tmp, "decode_path!", path_decode_inplace, 1);
260
- rb_define_module_function(tmp, "decode_path", path_decode, 1);
261
- rb_define_module_function(tmp, "time2str", date_str, -1);
262
- rb_define_module_function(tmp, "rfc2109", iodine_rfc2109, 1);
263
- rb_define_module_function(tmp, "rfc2822", iodine_rfc2822, 1);
264
-
265
- /*
266
- The monkey-patched methods are in this module, allowing Iodine::Rack::Utils to
267
- include non-patched methods as well.
268
- */
269
- tmp = rb_define_module_under(IodineBaseModule, "MonkeyPatch");
270
- tmp = rb_define_module_under(tmp, "RackUtils");
271
- // clang-format on
272
- /* we define it all twice for easier monkey patching */
273
- rb_define_method(tmp, "unescape", unescape, -1);
274
- rb_define_method(tmp, "unescape_path", path_decode, 1);
275
- rb_define_method(tmp, "rfc2109", iodine_rfc2109, 1);
276
- rb_define_method(tmp, "rfc2822", iodine_rfc2822, 1);
277
- rb_define_singleton_method(tmp, "unescape", unescape, -1);
278
- rb_define_singleton_method(tmp, "unescape_path", path_decode, 1);
279
- rb_define_singleton_method(tmp, "rfc2109", iodine_rfc2109, 1);
280
- rb_define_singleton_method(tmp, "rfc2822", iodine_rfc2822, 1);
281
- // rb_define_module_function(IodineUtils, "time2str", date_str, -1);
282
- }
1
+ /*
2
+ Copyright: Boaz segev, 2016-2017
3
+ License: MIT
4
+
5
+ Feel free to copy, use and enjoy according to the license provided.
6
+ */
7
+ #include "iodine.h"
8
+
9
+ #include "http.h"
10
+ #include <ruby/encoding.h>
11
+
12
+ /*
13
+ Add all sorts of useless stuff here.
14
+ */
15
+
16
+ static ID iodine_to_i_func_id;
17
+ static rb_encoding *IodineUTF8Encoding;
18
+
19
+ /* *****************************************************************************
20
+ URL Decoding
21
+ ***************************************************************************** */
22
+ /**
23
+ Decodes a URL encoded String in place.
24
+
25
+ Raises an exception on error... but this might result in a partially decoded
26
+ String.
27
+ */
28
+ static VALUE url_decode_inplace(VALUE self, VALUE str) {
29
+ Check_Type(str, T_STRING);
30
+ ssize_t len =
31
+ http_decode_url(RSTRING_PTR(str), RSTRING_PTR(str), RSTRING_LEN(str));
32
+ if (len < 0)
33
+ rb_raise(rb_eRuntimeError, "Malformed URL string - couldn't decode (String "
34
+ "might have been partially altered).");
35
+ rb_str_set_len(str, len);
36
+ return str;
37
+ (void)self;
38
+ }
39
+
40
+ /**
41
+ Decodes a URL encoded String, returning a new String with the decoded data.
42
+ */
43
+ static VALUE url_decode(VALUE self, VALUE str) {
44
+ Check_Type(str, T_STRING);
45
+ VALUE str2 = rb_str_buf_new(RSTRING_LEN(str));
46
+ ssize_t len =
47
+ http_decode_url(RSTRING_PTR(str2), RSTRING_PTR(str), RSTRING_LEN(str));
48
+ if (len < 0)
49
+ rb_raise(rb_eRuntimeError, "Malformed URL string - couldn't decode.");
50
+ rb_str_set_len(str2, len);
51
+ return str2;
52
+ (void)self;
53
+ }
54
+
55
+ /**
56
+ Decodes a percent encoded String (normally the "path" of a request), editing the
57
+ String in place.
58
+
59
+ Raises an exception on error... but this might result in a partially decoded
60
+ String.
61
+ */
62
+ static VALUE path_decode_inplace(VALUE self, VALUE str) {
63
+ Check_Type(str, T_STRING);
64
+ ssize_t len =
65
+ http_decode_path(RSTRING_PTR(str), RSTRING_PTR(str), RSTRING_LEN(str));
66
+ if (len < 0)
67
+ rb_raise(rb_eRuntimeError,
68
+ "Malformed URL path string - couldn't decode (String "
69
+ "might have been partially altered).");
70
+ rb_str_set_len(str, len);
71
+ return str;
72
+ (void)self;
73
+ }
74
+
75
+ /**
76
+ Decodes a percent encoded String (normally the "path" of a request), returning a
77
+ new String with the decoded data.
78
+ */
79
+ static VALUE path_decode(VALUE self, VALUE str) {
80
+ Check_Type(str, T_STRING);
81
+ VALUE str2 = rb_str_buf_new(RSTRING_LEN(str));
82
+ ssize_t len =
83
+ http_decode_path(RSTRING_PTR(str2), RSTRING_PTR(str), RSTRING_LEN(str));
84
+ if (len < 0)
85
+ rb_raise(rb_eRuntimeError, "Malformed URL path string - couldn't decode.");
86
+ rb_str_set_len(str2, len);
87
+ return str2;
88
+ (void)self;
89
+ }
90
+
91
+ /**
92
+ Decodes a URL encoded String, returning a new String with the decoded data.
93
+
94
+ This variation matches the Rack::Utils.unescape signature by accepting and
95
+ mostly ignoring an optional Encoding argument.
96
+ */
97
+ static VALUE unescape(int argc, VALUE *argv, VALUE self) {
98
+ if (argc < 1 || argc > 2)
99
+ rb_raise(rb_eArgError,
100
+ "wrong number of arguments (given %d, expected 1..2).", argc);
101
+ VALUE str = argv[0];
102
+ Check_Type(str, T_STRING);
103
+ VALUE str2 = rb_str_buf_new(RSTRING_LEN(str));
104
+ ssize_t len =
105
+ http_decode_url(RSTRING_PTR(str2), RSTRING_PTR(str), RSTRING_LEN(str));
106
+ if (len < 0)
107
+ rb_raise(rb_eRuntimeError, "Malformed URL path string - couldn't decode.");
108
+ rb_str_set_len(str2, len);
109
+ rb_encoding *enc = IodineUTF8Encoding;
110
+ if (argc == 2 && argv[1] != Qnil && argv[1] != Qfalse) {
111
+ enc = rb_enc_get(argv[1]);
112
+ if (!enc)
113
+ enc = IodineUTF8Encoding;
114
+ }
115
+ rb_enc_associate(str2, enc);
116
+ return str2;
117
+ (void)self;
118
+ }
119
+
120
+ /* *****************************************************************************
121
+ HTTP Dates
122
+ ***************************************************************************** */
123
+
124
+ /**
125
+ Takes an optional Integer for Unix Time and returns a faster (though less
126
+ localized) HTTP Date formatted String.
127
+
128
+
129
+ Iodine::Rack.time2str => "Sun, 11 Jun 2017 06:14:08 GMT"
130
+
131
+ Iodine::Rack.time2str(Time.now.to_i) => "Wed, 15 Nov 1995 06:25:24 GMT"
132
+
133
+ Since Iodine uses time caching within it's reactor, using the default value
134
+ (now) will be faster than providing an explicit time using `Time.now.to_i`.
135
+
136
+ */
137
+ static VALUE date_str(int argc, VALUE *argv, VALUE self) {
138
+ if (argc > 1)
139
+ rb_raise(rb_eArgError,
140
+ "wrong number of arguments (given %d, expected 0..1).", argc);
141
+ time_t last_tick;
142
+ if (argc) {
143
+ if (TYPE(argv[0]) != T_FIXNUM)
144
+ argv[0] = rb_funcallv(argv[0], iodine_to_i_func_id, 0, NULL);
145
+ Check_Type(argv[0], T_FIXNUM);
146
+ last_tick =
147
+ FIX2ULONG(argv[0]) ? FIX2ULONG(argv[0]) : fio_last_tick().tv_sec;
148
+ } else
149
+ last_tick = fio_last_tick().tv_sec;
150
+ VALUE str = rb_str_buf_new(32);
151
+ struct tm tm;
152
+
153
+ http_gmtime(last_tick, &tm);
154
+ size_t len = http_date2str(RSTRING_PTR(str), &tm);
155
+ rb_str_set_len(str, len);
156
+ return str;
157
+ (void)self;
158
+ }
159
+
160
+ /**
161
+ Takes `time` and returns a faster (though less localized) HTTP Date formatted
162
+ String.
163
+
164
+
165
+ Iodine::Rack.rfc2822(Time.now) => "Sun, 11 Jun 2017 06:14:08 -0000"
166
+
167
+ Iodine::Rack.rfc2822(0) => "Sun, 11 Jun 2017 06:14:08 -0000"
168
+
169
+ Since Iodine uses time caching within it's reactor, using the default value
170
+ (by passing 0) will be faster than providing an explicit time using `Time.now`.
171
+ */
172
+ static VALUE iodine_rfc2822(VALUE self, VALUE rtm) {
173
+ time_t last_tick;
174
+ rtm = rb_funcallv(rtm, iodine_to_i_func_id, 0, NULL);
175
+ last_tick = FIX2ULONG(rtm) ? FIX2ULONG(rtm) : fio_last_tick().tv_sec;
176
+ VALUE str = rb_str_buf_new(34);
177
+ struct tm tm;
178
+
179
+ http_gmtime(last_tick, &tm);
180
+ size_t len = http_date2rfc2822(RSTRING_PTR(str), &tm);
181
+ rb_str_set_len(str, len);
182
+ return str;
183
+ (void)self;
184
+ }
185
+
186
+ /**
187
+ Takes `time` and returns a faster (though less localized) HTTP Date formatted
188
+ String.
189
+
190
+
191
+ Iodine::Rack.rfc2109(Time.now) => "Sun, 11-Jun-2017 06:14:08 GMT"
192
+
193
+ Iodine::Rack.rfc2109(0) => "Sun, 11-Jun-2017 06:14:08 GMT"
194
+
195
+ Since Iodine uses time caching within it's reactor, using the default value
196
+ (by passing 0) will be faster than providing an explicit time using `Time.now`.
197
+ */
198
+ static VALUE iodine_rfc2109(VALUE self, VALUE rtm) {
199
+ time_t last_tick;
200
+ rtm = rb_funcallv(rtm, iodine_to_i_func_id, 0, NULL);
201
+ last_tick = FIX2ULONG(rtm) ? FIX2ULONG(rtm) : fio_last_tick().tv_sec;
202
+ VALUE str = rb_str_buf_new(32);
203
+ struct tm tm;
204
+
205
+ http_gmtime(last_tick, &tm);
206
+ size_t len = http_date2rfc2109(RSTRING_PTR(str), &tm);
207
+ rb_str_set_len(str, len);
208
+ return str;
209
+ (void)self;
210
+ }
211
+
212
+ /* *****************************************************************************
213
+ Ruby Initialization
214
+ ***************************************************************************** */
215
+
216
+ void iodine_init_helpers(void) {
217
+ iodine_to_i_func_id = rb_intern("to_i");
218
+ IodineUTF8Encoding = rb_enc_find("UTF-8");
219
+ VALUE tmp = rb_define_module_under(IodineModule, "Rack");
220
+ // clang-format off
221
+ /*
222
+ Iodine does NOT monkey patch Rack automatically. However, it's possible and recommended to moneky patch Rack::Utils to use the methods in this module.
223
+
224
+ Choosing to monkey patch Rack::Utils could offer significant performance gains for some applications. i.e. (on my machine):
225
+
226
+ require 'iodine'
227
+ require 'rack'
228
+ # a String in need of decoding
229
+ s = '%E3%83%AB%E3%83%93%E3%82%A4%E3%82%B9%E3%81%A8'
230
+ Benchmark.bm do |bm|
231
+ # Pre-Patch
232
+ bm.report(" Rack.unescape") {1_000_000.times { Rack::Utils.unescape s } }
233
+ bm.report(" Rack.rfc2822") {1_000_000.times { Rack::Utils.rfc2822(Time.now) } }
234
+ bm.report(" Rack.rfc2109") {1_000_000.times { Rack::Utils.rfc2109(Time.now) } }
235
+ # Perform Patch
236
+ Iodine.patch_rack
237
+ puts " --- Monkey Patching Rack ---"
238
+ # Post Patch
239
+ bm.report("Patched.unescape") {1_000_000.times { Rack::Utils.unescape s } }
240
+ bm.report(" Patched.rfc2822") {1_000_000.times { Rack::Utils.rfc2822(Time.now) } }
241
+ bm.report(" Patched.rfc2109") {1_000_000.times { Rack::Utils.rfc2109(Time.now) } }
242
+ end && nil
243
+
244
+ Results:
245
+ user system total real
246
+ Rack.unescape 8.706881 0.019995 8.726876 ( 8.740530)
247
+ Rack.rfc2822 3.270305 0.007519 3.277824 ( 3.279416)
248
+ Rack.rfc2109 3.152188 0.003852 3.156040 ( 3.157975)
249
+ --- Monkey Patching Rack ---
250
+ Patched.unescape 0.327231 0.003125 0.330356 ( 0.337090)
251
+ Patched.rfc2822 0.691304 0.003330 0.694634 ( 0.701172)
252
+ Patched.rfc2109 0.685029 0.001956 0.686985 ( 0.687607)
253
+
254
+ */
255
+ tmp = rb_define_module_under(tmp, "Utils");
256
+ // clang-format on
257
+ rb_define_module_function(tmp, "decode_url!", url_decode_inplace, 1);
258
+ rb_define_module_function(tmp, "decode_url", url_decode, 1);
259
+ rb_define_module_function(tmp, "decode_path!", path_decode_inplace, 1);
260
+ rb_define_module_function(tmp, "decode_path", path_decode, 1);
261
+ rb_define_module_function(tmp, "time2str", date_str, -1);
262
+ rb_define_module_function(tmp, "rfc2109", iodine_rfc2109, 1);
263
+ rb_define_module_function(tmp, "rfc2822", iodine_rfc2822, 1);
264
+
265
+ /*
266
+ The monkey-patched methods are in this module, allowing Iodine::Rack::Utils to
267
+ include non-patched methods as well.
268
+ */
269
+ tmp = rb_define_module_under(IodineBaseModule, "MonkeyPatch");
270
+ tmp = rb_define_module_under(tmp, "RackUtils");
271
+ // clang-format on
272
+ /* we define it all twice for easier monkey patching */
273
+ rb_define_method(tmp, "unescape", unescape, -1);
274
+ rb_define_method(tmp, "unescape_path", path_decode, 1);
275
+ rb_define_method(tmp, "rfc2109", iodine_rfc2109, 1);
276
+ rb_define_method(tmp, "rfc2822", iodine_rfc2822, 1);
277
+ rb_define_singleton_method(tmp, "unescape", unescape, -1);
278
+ rb_define_singleton_method(tmp, "unescape_path", path_decode, 1);
279
+ rb_define_singleton_method(tmp, "rfc2109", iodine_rfc2109, 1);
280
+ rb_define_singleton_method(tmp, "rfc2822", iodine_rfc2822, 1);
281
+ // rb_define_module_function(IodineUtils, "time2str", date_str, -1);
282
+ }