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.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE/bug_report.md +40 -40
- data/.github/workflows/ruby.yml +2 -2
- data/ext/iodine/fio_tmpfile.h +50 -50
- data/ext/iodine/fiobj_hash.c +409 -409
- data/ext/iodine/fiobj_numbers.c +344 -344
- data/ext/iodine/fiobj_str.c +433 -433
- data/ext/iodine/iodine_caller.c +4 -6
- data/ext/iodine/iodine_caller.h +26 -27
- data/ext/iodine/iodine_connection.c +1 -1
- data/ext/iodine/iodine_http.c +2 -1
- data/ext/iodine/iodine_mustache.c +1 -1
- data/ext/iodine/iodine_rack_io.c +281 -281
- data/ext/iodine/iodine_store.c +142 -142
- data/ext/iodine/iodine_tls.c +1 -1
- data/isomorfeus-iodine.gemspec +1 -0
- data/lib/iodine/version.rb +3 -3
- metadata +5 -5
data/ext/iodine/iodine_rack_io.c
CHANGED
@@ -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
|
+
};
|