isomorfeus-iodine 0.7.45 → 0.7.46

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,281 +1,281 @@
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_rack_io.h"
8
-
9
- #include "iodine.h"
10
-
11
- #include <ruby/encoding.h>
12
- #include <ruby/io.h>
13
- #include <unistd.h>
14
-
15
- #ifndef _GNU_SOURCE
16
- #define _GNU_SOURCE
17
- #endif
18
-
19
- /* IodineRackIO manages a minimal interface to act as an IO wrapper according to
20
- these Rack specifications:
21
-
22
- The input stream is an IO-like object which contains the raw HTTP POST data.
23
- When applicable, its external encoding must be “ASCII-8BIT” and it must be
24
- opened in binary mode, for Ruby 1.9 compatibility. The input stream must respond
25
- to gets, each, read and rewind.
26
-
27
- gets must be called without arguments and return a string, or nil on EOF.
28
-
29
- read behaves like IO#read. Its signature is read([length, [buffer]]). If given,
30
- length must be a non-negative Integer (>= 0) or nil, and buffer must be a String
31
- and may not be nil. If length is given and not nil, then this method reads at
32
- most length bytes from the input stream. If length is not given or nil, then
33
- this method reads all data until EOF. When EOF is reached, this method returns
34
- nil if length is given and not nil, or “” if length is not given or is nil. If
35
- buffer is given, then the read data will be placed into buffer instead of a
36
- newly created String object.
37
-
38
- each must be called without arguments and only yield Strings.
39
-
40
- rewind must be called without arguments. It rewinds the input stream back to the
41
- beginning. It must not raise Errno::ESPIPE: that is, it may not be a pipe or a
42
- socket. Therefore, handler developers must buffer the input data into some
43
- rewindable object if the underlying input stream is not rewindable.
44
-
45
- close must never be called on the input stream.
46
-
47
- */
48
-
49
- /* *****************************************************************************
50
- Core data / helpers
51
- */
52
-
53
- static VALUE rRackIO;
54
-
55
- static ID env_id;
56
- static ID io_id;
57
-
58
- static VALUE R_INPUT; /* rack.input */
59
- static VALUE hijack_func_sym;
60
- static VALUE TCPSOCKET_CLASS;
61
- static ID for_fd_id;
62
- static ID iodine_fd_var_id;
63
- static ID iodine_new_func_id;
64
- #ifdef __MINGW32__
65
- static ID iodine_osffd_id;
66
- #endif
67
- static rb_encoding *IodineUTF8Encoding;
68
- static rb_encoding *IodineBinaryEncoding;
69
-
70
- #define set_handle(object, handle) \
71
- rb_ivar_set((object), iodine_fd_var_id, ULL2NUM((uintptr_t)handle))
72
-
73
- inline static http_s *get_handle(VALUE obj) {
74
- VALUE i = rb_ivar_get(obj, iodine_fd_var_id);
75
- #ifdef __MINGW32__
76
- return (http_s *)NUM2ULL(i);
77
- #else
78
- return (http_s *)FIX2ULONG(i);
79
- #endif
80
- }
81
-
82
- /* *****************************************************************************
83
- IO API
84
- */
85
-
86
- static inline FIOBJ get_data(VALUE self) {
87
- VALUE i = rb_ivar_get(self, io_id);
88
- #ifdef __MINGW32__
89
- return (FIOBJ)NUM2ULL(i);
90
- #else
91
- return (FIOBJ)FIX2ULONG(i);
92
- #endif
93
- }
94
-
95
- static VALUE rio_rewind(VALUE self) {
96
- FIOBJ io = get_data(self);
97
- if (!FIOBJ_TYPE_IS(io, FIOBJ_T_DATA))
98
- return Qnil;
99
- fiobj_data_seek(io, 0);
100
- return INT2NUM(0);
101
- }
102
- /**
103
- Gets returns a line. this is okay for small lines,
104
- but shouldn't really be used.
105
-
106
- Limited to ~ 1Mb of a line length.
107
- */
108
- static VALUE rio_gets(VALUE self) {
109
- FIOBJ io = get_data(self);
110
- if (!FIOBJ_TYPE_IS(io, FIOBJ_T_DATA))
111
- return Qnil;
112
- fio_str_info_s line = fiobj_data_gets(io);
113
- if (line.len) {
114
- VALUE buffer = rb_str_new(line.data, line.len);
115
- // make sure the buffer is binary encoded.
116
- rb_enc_associate(buffer, IodineBinaryEncoding);
117
- return buffer;
118
- }
119
- return Qnil;
120
- }
121
-
122
- // Reads data from the IO, according to the Rack specifications for `#read`.
123
- static VALUE rio_read(int argc, VALUE *argv, VALUE self) {
124
- FIOBJ io = get_data(self);
125
- VALUE buffer = Qnil;
126
- uint8_t ret_nil = 0;
127
- ssize_t len = 0;
128
- if (!FIOBJ_TYPE_IS(io, FIOBJ_T_DATA)) {
129
- return (argc > 0 && argv[0] != Qnil) ? Qnil : rb_str_buf_new(0);
130
- }
131
-
132
- // get the buffer object if given
133
- if (argc == 2) {
134
- Check_Type(argv[1], T_STRING);
135
- buffer = argv[1];
136
- }
137
- // get the length object, if given
138
- if (argc > 0 && argv[0] != Qnil) {
139
- Check_Type(argv[0], T_FIXNUM);
140
- len = FIX2LONG(argv[0]);
141
- if (len < 0)
142
- rb_raise(rb_eRangeError, "length should be bigger then 0.");
143
- if (len == 0)
144
- return rb_str_buf_new(0);
145
- ret_nil = 1;
146
- }
147
- // return if we're at the EOF.
148
- fio_str_info_s buf = fiobj_data_read(io, len);
149
- if (buf.len) {
150
- // create the buffer if we don't have one.
151
- if (buffer == Qnil) {
152
- // make sure the buffer is binary encoded.
153
- buffer = rb_enc_str_new(buf.data, buf.len, IodineBinaryEncoding);
154
- } else {
155
- // make sure the buffer is binary encoded.
156
- rb_enc_associate(buffer, IodineBinaryEncoding);
157
- if (rb_str_capacity(buffer) < (size_t)buf.len)
158
- rb_str_resize(buffer, buf.len);
159
- memcpy(RSTRING_PTR(buffer), buf.data, buf.len);
160
- rb_str_set_len(buffer, buf.len);
161
- }
162
- return buffer;
163
- }
164
- return ret_nil ? Qnil : rb_str_buf_new(0);
165
- }
166
-
167
- // Does nothing - this is controlled by the server.
168
- static VALUE rio_close(VALUE self) {
169
- // FIOBJ io = get_data(self);
170
- // fiobj_free(io); // we don't call fiobj_dup, do we?
171
- rb_ivar_set(self, io_id, INT2NUM(0));
172
- (void)self;
173
- return Qnil;
174
- }
175
-
176
- // Passes each line of the input to the block. This should be avoided.
177
- static VALUE rio_each(VALUE self) {
178
- rb_need_block();
179
- rio_rewind(self);
180
- VALUE str = Qnil;
181
- while ((str = rio_gets(self)) != Qnil) {
182
- rb_yield(str);
183
- }
184
- return self;
185
- }
186
-
187
- /* *****************************************************************************
188
- Hijacking
189
- */
190
-
191
- // defined by iodine_http
192
- extern VALUE IODINE_R_HIJACK; // for Rack: rack.hijack
193
- extern VALUE IODINE_R_HIJACK_CB; // for Rack: rack.hijack
194
- extern VALUE IODINE_R_HIJACK_IO; // for Rack: rack.hijack_io
195
-
196
- static VALUE rio_get_io(int argc, VALUE *argv, VALUE self) {
197
- if (TCPSOCKET_CLASS == Qnil)
198
- return Qfalse;
199
- VALUE env = rb_ivar_get(self, env_id);
200
- http_s *h = get_handle(self);
201
- if (h == NULL) {
202
- /* we're repeating ourselves, aren't we? */
203
- VALUE io = rb_hash_aref(env, IODINE_R_HIJACK_IO);
204
- return io;
205
- }
206
- // mark update
207
- set_handle(self, NULL);
208
- // hijack the IO object
209
- intptr_t uuid = http_hijack(h, NULL);
210
- #ifdef __MINGW32__
211
- int osffd = fio_osffd4fd(fio_uuid2fd(uuid));
212
- if (osffd == -1)
213
- return Qfalse;
214
- VALUE fd = INT2FIX(osffd);
215
- #else
216
- VALUE fd = INT2FIX(fio_uuid2fd(uuid));
217
- #endif
218
- // VALUE new_io = how the fuck do we create a new IO from the fd?
219
- VALUE new_io = IodineCaller.call2(TCPSOCKET_CLASS, for_fd_id, 1,
220
- &fd); // TCPSocket.for_fd(fd) ... cool...
221
- rb_hash_aset(env, IODINE_R_HIJACK_IO, new_io);
222
- if (argc)
223
- rb_hash_aset(env, IODINE_R_HIJACK_CB, *argv);
224
- return new_io;
225
- }
226
-
227
- /* *****************************************************************************
228
- C land API
229
- */
230
-
231
- // new object
232
- static VALUE new_rack_io(http_s *h, VALUE env) {
233
- VALUE rack_io = rb_funcall2(rRackIO, iodine_new_func_id, 0, NULL);
234
- rb_ivar_set(rack_io, io_id, ULL2NUM(h->body));
235
- set_handle(rack_io, h);
236
- rb_ivar_set(rack_io, env_id, env);
237
- rb_hash_aset(env, IODINE_R_INPUT, rack_io);
238
- rb_hash_aset(env, IODINE_R_HIJACK, rb_obj_method(rack_io, hijack_func_sym));
239
- return rack_io;
240
- }
241
-
242
- static void close_rack_io(VALUE rack_io) {
243
- // rio_close(rack_io);
244
- rb_ivar_set(rack_io, io_id, INT2NUM(0));
245
- set_handle(rack_io, NULL); /* this disables hijacking. */
246
- }
247
-
248
- // initialize library
249
- static void init_rack_io(void) {
250
- IodineUTF8Encoding = rb_enc_find("UTF-8");
251
- IodineBinaryEncoding = rb_enc_find("binary");
252
- rRackIO = rb_define_class_under(IodineBaseModule, "RackIO", rb_cObject);
253
-
254
- io_id = rb_intern("rack_io");
255
- env_id = rb_intern("env");
256
- for_fd_id = rb_intern("for_fd");
257
- iodine_fd_var_id = rb_intern("fd");
258
- iodine_new_func_id = rb_intern("new");
259
- #ifdef __MINGW32__
260
- iodine_osffd_id = rb_intern("osffd");
261
- #endif
262
- hijack_func_sym = ID2SYM(rb_intern("_hijack"));
263
-
264
- TCPSOCKET_CLASS = rb_const_get(rb_cObject, rb_intern("TCPSocket"));
265
- // IO methods
266
-
267
- rb_define_method(rRackIO, "rewind", rio_rewind, 0);
268
- rb_define_method(rRackIO, "gets", rio_gets, 0);
269
- rb_define_method(rRackIO, "read", rio_read, -1);
270
- rb_define_method(rRackIO, "close", rio_close, 0);
271
- rb_define_method(rRackIO, "each", rio_each, 0);
272
- rb_define_method(rRackIO, "_hijack", rio_get_io, -1);
273
- }
274
-
275
- ////////////////////////////////////////////////////////////////////////////
276
- // the API interface
277
- struct IodineRackIO IodineRackIO = {
278
- .create = new_rack_io,
279
- .close = close_rack_io,
280
- .init = init_rack_io,
281
- };
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_rack_io.h"
8
+
9
+ #include "iodine.h"
10
+
11
+ #include <ruby/encoding.h>
12
+ #include <ruby/io.h>
13
+ #include <unistd.h>
14
+
15
+ #ifndef _GNU_SOURCE
16
+ #define _GNU_SOURCE
17
+ #endif
18
+
19
+ /* IodineRackIO manages a minimal interface to act as an IO wrapper according to
20
+ these Rack specifications:
21
+
22
+ The input stream is an IO-like object which contains the raw HTTP POST data.
23
+ When applicable, its external encoding must be “ASCII-8BIT” and it must be
24
+ opened in binary mode, for Ruby 1.9 compatibility. The input stream must respond
25
+ to gets, each, read and rewind.
26
+
27
+ gets must be called without arguments and return a string, or nil on EOF.
28
+
29
+ read behaves like IO#read. Its signature is read([length, [buffer]]). If given,
30
+ length must be a non-negative Integer (>= 0) or nil, and buffer must be a String
31
+ and may not be nil. If length is given and not nil, then this method reads at
32
+ most length bytes from the input stream. If length is not given or nil, then
33
+ this method reads all data until EOF. When EOF is reached, this method returns
34
+ nil if length is given and not nil, or “” if length is not given or is nil. If
35
+ buffer is given, then the read data will be placed into buffer instead of a
36
+ newly created String object.
37
+
38
+ each must be called without arguments and only yield Strings.
39
+
40
+ rewind must be called without arguments. It rewinds the input stream back to the
41
+ beginning. It must not raise Errno::ESPIPE: that is, it may not be a pipe or a
42
+ socket. Therefore, handler developers must buffer the input data into some
43
+ rewindable object if the underlying input stream is not rewindable.
44
+
45
+ close must never be called on the input stream.
46
+
47
+ */
48
+
49
+ /* *****************************************************************************
50
+ Core data / helpers
51
+ */
52
+
53
+ static VALUE rRackIO;
54
+
55
+ static ID env_id;
56
+ static ID io_id;
57
+
58
+ static VALUE R_INPUT; /* rack.input */
59
+ static VALUE hijack_func_sym;
60
+ static VALUE TCPSOCKET_CLASS;
61
+ static ID for_fd_id;
62
+ static ID iodine_fd_var_id;
63
+ static ID iodine_new_func_id;
64
+ #ifdef __MINGW32__
65
+ static ID iodine_osffd_id;
66
+ #endif
67
+ static rb_encoding *IodineUTF8Encoding;
68
+ static rb_encoding *IodineBinaryEncoding;
69
+
70
+ #define set_handle(object, handle) \
71
+ rb_ivar_set((object), iodine_fd_var_id, ULL2NUM((uintptr_t)handle))
72
+
73
+ inline static http_s *get_handle(VALUE obj) {
74
+ VALUE i = rb_ivar_get(obj, iodine_fd_var_id);
75
+ #ifdef __MINGW32__
76
+ return (http_s *)NUM2ULL(i);
77
+ #else
78
+ return (http_s *)FIX2ULONG(i);
79
+ #endif
80
+ }
81
+
82
+ /* *****************************************************************************
83
+ IO API
84
+ */
85
+
86
+ static inline FIOBJ get_data(VALUE self) {
87
+ VALUE i = rb_ivar_get(self, io_id);
88
+ #ifdef __MINGW32__
89
+ return (FIOBJ)NUM2ULL(i);
90
+ #else
91
+ return (FIOBJ)FIX2ULONG(i);
92
+ #endif
93
+ }
94
+
95
+ static VALUE rio_rewind(VALUE self) {
96
+ FIOBJ io = get_data(self);
97
+ if (!FIOBJ_TYPE_IS(io, FIOBJ_T_DATA))
98
+ return Qnil;
99
+ fiobj_data_seek(io, 0);
100
+ return INT2NUM(0);
101
+ }
102
+ /**
103
+ Gets returns a line. this is okay for small lines,
104
+ but shouldn't really be used.
105
+
106
+ Limited to ~ 1Mb of a line length.
107
+ */
108
+ static VALUE rio_gets(VALUE self) {
109
+ FIOBJ io = get_data(self);
110
+ if (!FIOBJ_TYPE_IS(io, FIOBJ_T_DATA))
111
+ return Qnil;
112
+ fio_str_info_s line = fiobj_data_gets(io);
113
+ if (line.len) {
114
+ VALUE buffer = rb_str_new(line.data, line.len);
115
+ // make sure the buffer is binary encoded.
116
+ rb_enc_associate(buffer, IodineBinaryEncoding);
117
+ return buffer;
118
+ }
119
+ return Qnil;
120
+ }
121
+
122
+ // Reads data from the IO, according to the Rack specifications for `#read`.
123
+ static VALUE rio_read(int argc, VALUE *argv, VALUE self) {
124
+ FIOBJ io = get_data(self);
125
+ VALUE buffer = Qnil;
126
+ uint8_t ret_nil = 0;
127
+ ssize_t len = 0;
128
+ if (!FIOBJ_TYPE_IS(io, FIOBJ_T_DATA)) {
129
+ return (argc > 0 && argv[0] != Qnil) ? Qnil : rb_str_buf_new(0);
130
+ }
131
+
132
+ // get the buffer object if given
133
+ if (argc == 2) {
134
+ Check_Type(argv[1], T_STRING);
135
+ buffer = argv[1];
136
+ }
137
+ // get the length object, if given
138
+ if (argc > 0 && argv[0] != Qnil) {
139
+ Check_Type(argv[0], T_FIXNUM);
140
+ len = FIX2LONG(argv[0]);
141
+ if (len < 0)
142
+ rb_raise(rb_eRangeError, "length should be bigger then 0.");
143
+ if (len == 0)
144
+ return rb_str_buf_new(0);
145
+ ret_nil = 1;
146
+ }
147
+ // return if we're at the EOF.
148
+ fio_str_info_s buf = fiobj_data_read(io, len);
149
+ if (buf.len) {
150
+ // create the buffer if we don't have one.
151
+ if (buffer == Qnil) {
152
+ // make sure the buffer is binary encoded.
153
+ buffer = rb_enc_str_new(buf.data, buf.len, IodineBinaryEncoding);
154
+ } else {
155
+ // make sure the buffer is binary encoded.
156
+ rb_enc_associate(buffer, IodineBinaryEncoding);
157
+ if (rb_str_capacity(buffer) < (size_t)buf.len)
158
+ rb_str_resize(buffer, buf.len);
159
+ memcpy(RSTRING_PTR(buffer), buf.data, buf.len);
160
+ rb_str_set_len(buffer, buf.len);
161
+ }
162
+ return buffer;
163
+ }
164
+ return ret_nil ? Qnil : rb_str_buf_new(0);
165
+ }
166
+
167
+ // Does nothing - this is controlled by the server.
168
+ static VALUE rio_close(VALUE self) {
169
+ // FIOBJ io = get_data(self);
170
+ // fiobj_free(io); // we don't call fiobj_dup, do we?
171
+ rb_ivar_set(self, io_id, INT2NUM(0));
172
+ (void)self;
173
+ return Qnil;
174
+ }
175
+
176
+ // Passes each line of the input to the block. This should be avoided.
177
+ static VALUE rio_each(VALUE self) {
178
+ rb_need_block();
179
+ rio_rewind(self);
180
+ VALUE str = Qnil;
181
+ while ((str = rio_gets(self)) != Qnil) {
182
+ rb_yield(str);
183
+ }
184
+ return self;
185
+ }
186
+
187
+ /* *****************************************************************************
188
+ Hijacking
189
+ */
190
+
191
+ // defined by iodine_http
192
+ extern VALUE IODINE_R_HIJACK; // for Rack: rack.hijack
193
+ extern VALUE IODINE_R_HIJACK_CB; // for Rack: rack.hijack
194
+ extern VALUE IODINE_R_HIJACK_IO; // for Rack: rack.hijack_io
195
+
196
+ static VALUE rio_get_io(int argc, VALUE *argv, VALUE self) {
197
+ if (TCPSOCKET_CLASS == Qnil)
198
+ return Qfalse;
199
+ VALUE env = rb_ivar_get(self, env_id);
200
+ http_s *h = get_handle(self);
201
+ if (h == NULL) {
202
+ /* we're repeating ourselves, aren't we? */
203
+ VALUE io = rb_hash_aref(env, IODINE_R_HIJACK_IO);
204
+ return io;
205
+ }
206
+ // mark update
207
+ set_handle(self, NULL);
208
+ // hijack the IO object
209
+ intptr_t uuid = http_hijack(h, NULL);
210
+ #ifdef __MINGW32__
211
+ int osffd = fio_osffd4fd(fio_uuid2fd(uuid));
212
+ if (osffd == -1)
213
+ return Qfalse;
214
+ VALUE fd = INT2FIX(osffd);
215
+ #else
216
+ VALUE fd = INT2FIX(fio_uuid2fd(uuid));
217
+ #endif
218
+ // VALUE new_io = how the fuck do we create a new IO from the fd?
219
+ VALUE new_io = IodineCaller.call2(TCPSOCKET_CLASS, for_fd_id, 1,
220
+ &fd); // TCPSocket.for_fd(fd) ... cool...
221
+ rb_hash_aset(env, IODINE_R_HIJACK_IO, new_io);
222
+ if (argc)
223
+ rb_hash_aset(env, IODINE_R_HIJACK_CB, *argv);
224
+ return new_io;
225
+ }
226
+
227
+ /* *****************************************************************************
228
+ C land API
229
+ */
230
+
231
+ // new object
232
+ static VALUE new_rack_io(http_s *h, VALUE env) {
233
+ VALUE rack_io = rb_funcall2(rRackIO, iodine_new_func_id, 0, NULL);
234
+ rb_ivar_set(rack_io, io_id, ULL2NUM(h->body));
235
+ set_handle(rack_io, h);
236
+ rb_ivar_set(rack_io, env_id, env);
237
+ rb_hash_aset(env, IODINE_R_INPUT, rack_io);
238
+ rb_hash_aset(env, IODINE_R_HIJACK, rb_obj_method(rack_io, hijack_func_sym));
239
+ return rack_io;
240
+ }
241
+
242
+ static void close_rack_io(VALUE rack_io) {
243
+ // rio_close(rack_io);
244
+ rb_ivar_set(rack_io, io_id, INT2NUM(0));
245
+ set_handle(rack_io, NULL); /* this disables hijacking. */
246
+ }
247
+
248
+ // initialize library
249
+ static void init_rack_io(void) {
250
+ IodineUTF8Encoding = rb_enc_find("UTF-8");
251
+ IodineBinaryEncoding = rb_enc_find("binary");
252
+ rRackIO = rb_define_class_under(IodineBaseModule, "RackIO", rb_cObject);
253
+
254
+ io_id = rb_intern("rack_io");
255
+ env_id = rb_intern("env");
256
+ for_fd_id = rb_intern("for_fd");
257
+ iodine_fd_var_id = rb_intern("fd");
258
+ iodine_new_func_id = rb_intern("new");
259
+ #ifdef __MINGW32__
260
+ iodine_osffd_id = rb_intern("osffd");
261
+ #endif
262
+ hijack_func_sym = ID2SYM(rb_intern("_hijack"));
263
+
264
+ TCPSOCKET_CLASS = rb_const_get(rb_cObject, rb_intern("TCPSocket"));
265
+ // IO methods
266
+
267
+ rb_define_method(rRackIO, "rewind", rio_rewind, 0);
268
+ rb_define_method(rRackIO, "gets", rio_gets, 0);
269
+ rb_define_method(rRackIO, "read", rio_read, -1);
270
+ rb_define_method(rRackIO, "close", rio_close, 0);
271
+ rb_define_method(rRackIO, "each", rio_each, 0);
272
+ rb_define_method(rRackIO, "_hijack", rio_get_io, -1);
273
+ }
274
+
275
+ ////////////////////////////////////////////////////////////////////////////
276
+ // the API interface
277
+ struct IodineRackIO IodineRackIO = {
278
+ .create = new_rack_io,
279
+ .close = close_rack_io,
280
+ .init = init_rack_io,
281
+ };