1584Salexander.borisov@nginx.com 
2584Salexander.borisov@nginx.com /*
3584Salexander.borisov@nginx.com  * Copyright (C) Alexander Borisov
4584Salexander.borisov@nginx.com  * Copyright (C) NGINX, Inc.
5584Salexander.borisov@nginx.com  */
6584Salexander.borisov@nginx.com 
7584Salexander.borisov@nginx.com #include <ruby/nxt_ruby.h>
8*743Smax.romanov@nginx.com #include <nxt_unit.h>
9584Salexander.borisov@nginx.com 
10584Salexander.borisov@nginx.com 
11584Salexander.borisov@nginx.com static VALUE nxt_ruby_stream_io_new(VALUE class, VALUE wrap);
12584Salexander.borisov@nginx.com static VALUE nxt_ruby_stream_io_initialize(int argc, VALUE *argv, VALUE self);
13584Salexander.borisov@nginx.com static VALUE nxt_ruby_stream_io_gets(VALUE obj, VALUE args);
14584Salexander.borisov@nginx.com static VALUE nxt_ruby_stream_io_each(VALUE obj, VALUE args);
15584Salexander.borisov@nginx.com static VALUE nxt_ruby_stream_io_read(VALUE obj, VALUE args);
16584Salexander.borisov@nginx.com static VALUE nxt_ruby_stream_io_rewind(VALUE obj, VALUE args);
17584Salexander.borisov@nginx.com static VALUE nxt_ruby_stream_io_puts(VALUE obj, VALUE args);
18584Salexander.borisov@nginx.com static VALUE nxt_ruby_stream_io_write(VALUE obj, VALUE args);
19584Salexander.borisov@nginx.com nxt_inline long nxt_ruby_stream_io_s_write(nxt_ruby_run_ctx_t *run_ctx,
20584Salexander.borisov@nginx.com     VALUE val);
21584Salexander.borisov@nginx.com static VALUE nxt_ruby_stream_io_flush(VALUE obj, VALUE args);
22584Salexander.borisov@nginx.com 
23584Salexander.borisov@nginx.com 
24584Salexander.borisov@nginx.com VALUE
25584Salexander.borisov@nginx.com nxt_ruby_stream_io_input_init(void)
26584Salexander.borisov@nginx.com {
27584Salexander.borisov@nginx.com     VALUE  stream_io;
28584Salexander.borisov@nginx.com 
29584Salexander.borisov@nginx.com     stream_io = rb_define_class("NGINX_Unit_Stream_IO_Read", rb_cData);
30584Salexander.borisov@nginx.com 
31584Salexander.borisov@nginx.com     rb_gc_register_address(&stream_io);
32584Salexander.borisov@nginx.com 
33584Salexander.borisov@nginx.com     rb_define_singleton_method(stream_io, "new", nxt_ruby_stream_io_new, 1);
34584Salexander.borisov@nginx.com     rb_define_method(stream_io, "initialize", nxt_ruby_stream_io_initialize, -1);
35584Salexander.borisov@nginx.com     rb_define_method(stream_io, "gets", nxt_ruby_stream_io_gets, 0);
36584Salexander.borisov@nginx.com     rb_define_method(stream_io, "each", nxt_ruby_stream_io_each, 0);
37584Salexander.borisov@nginx.com     rb_define_method(stream_io, "read", nxt_ruby_stream_io_read, -2);
38584Salexander.borisov@nginx.com     rb_define_method(stream_io, "rewind", nxt_ruby_stream_io_rewind, 0);
39584Salexander.borisov@nginx.com 
40584Salexander.borisov@nginx.com     return stream_io;
41584Salexander.borisov@nginx.com }
42584Salexander.borisov@nginx.com 
43584Salexander.borisov@nginx.com 
44584Salexander.borisov@nginx.com VALUE
45584Salexander.borisov@nginx.com nxt_ruby_stream_io_error_init(void)
46584Salexander.borisov@nginx.com {
47584Salexander.borisov@nginx.com     VALUE  stream_io;
48584Salexander.borisov@nginx.com 
49584Salexander.borisov@nginx.com     stream_io = rb_define_class("NGINX_Unit_Stream_IO_Error", rb_cData);
50584Salexander.borisov@nginx.com 
51584Salexander.borisov@nginx.com     rb_gc_register_address(&stream_io);
52584Salexander.borisov@nginx.com 
53584Salexander.borisov@nginx.com     rb_define_singleton_method(stream_io, "new", nxt_ruby_stream_io_new, 1);
54584Salexander.borisov@nginx.com     rb_define_method(stream_io, "initialize", nxt_ruby_stream_io_initialize, -1);
55584Salexander.borisov@nginx.com     rb_define_method(stream_io, "puts", nxt_ruby_stream_io_puts, -2);
56584Salexander.borisov@nginx.com     rb_define_method(stream_io, "write", nxt_ruby_stream_io_write, -2);
57584Salexander.borisov@nginx.com     rb_define_method(stream_io, "flush", nxt_ruby_stream_io_flush, 0);
58584Salexander.borisov@nginx.com 
59584Salexander.borisov@nginx.com     return stream_io;
60584Salexander.borisov@nginx.com }
61584Salexander.borisov@nginx.com 
62584Salexander.borisov@nginx.com 
63584Salexander.borisov@nginx.com static VALUE
64584Salexander.borisov@nginx.com nxt_ruby_stream_io_new(VALUE class, VALUE wrap)
65584Salexander.borisov@nginx.com {
66584Salexander.borisov@nginx.com     VALUE               self;
67584Salexander.borisov@nginx.com     nxt_ruby_run_ctx_t  *run_ctx;
68584Salexander.borisov@nginx.com 
69584Salexander.borisov@nginx.com     Data_Get_Struct(wrap, nxt_ruby_run_ctx_t, run_ctx);
70584Salexander.borisov@nginx.com     self = Data_Wrap_Struct(class, 0, 0, run_ctx);
71584Salexander.borisov@nginx.com 
72584Salexander.borisov@nginx.com     rb_obj_call_init(self, 0, NULL);
73584Salexander.borisov@nginx.com 
74584Salexander.borisov@nginx.com     return self;
75584Salexander.borisov@nginx.com }
76584Salexander.borisov@nginx.com 
77584Salexander.borisov@nginx.com 
78584Salexander.borisov@nginx.com static VALUE
79584Salexander.borisov@nginx.com nxt_ruby_stream_io_initialize(int argc, VALUE *argv, VALUE self)
80584Salexander.borisov@nginx.com {
81584Salexander.borisov@nginx.com     return self;
82584Salexander.borisov@nginx.com }
83584Salexander.borisov@nginx.com 
84584Salexander.borisov@nginx.com 
85584Salexander.borisov@nginx.com static VALUE
86584Salexander.borisov@nginx.com nxt_ruby_stream_io_gets(VALUE obj, VALUE args)
87584Salexander.borisov@nginx.com {
88*743Smax.romanov@nginx.com     VALUE                    buf;
89*743Smax.romanov@nginx.com     char                     *p;
90*743Smax.romanov@nginx.com     size_t                   size, b_size;
91*743Smax.romanov@nginx.com     nxt_unit_buf_t           *b;
92*743Smax.romanov@nginx.com     nxt_ruby_run_ctx_t       *run_ctx;
93*743Smax.romanov@nginx.com     nxt_unit_request_info_t  *req;
94584Salexander.borisov@nginx.com 
95584Salexander.borisov@nginx.com     Data_Get_Struct(obj, nxt_ruby_run_ctx_t, run_ctx);
96584Salexander.borisov@nginx.com 
97*743Smax.romanov@nginx.com     req = run_ctx->req;
98*743Smax.romanov@nginx.com 
99*743Smax.romanov@nginx.com     if (req->content_length == 0) {
100584Salexander.borisov@nginx.com         return Qnil;
101584Salexander.borisov@nginx.com     }
102584Salexander.borisov@nginx.com 
103*743Smax.romanov@nginx.com     size = 0;
104*743Smax.romanov@nginx.com 
105*743Smax.romanov@nginx.com     for (b = req->content_buf; b; b = nxt_unit_buf_next(b)) {
106*743Smax.romanov@nginx.com         b_size = b->end - b->free;
107*743Smax.romanov@nginx.com         p = memchr(b->free, '\n', b_size);
108*743Smax.romanov@nginx.com 
109*743Smax.romanov@nginx.com         if (p != NULL) {
110*743Smax.romanov@nginx.com             p++;
111*743Smax.romanov@nginx.com             size += p - b->free;
112*743Smax.romanov@nginx.com             break;
113*743Smax.romanov@nginx.com         }
114*743Smax.romanov@nginx.com 
115*743Smax.romanov@nginx.com         size += b_size;
116*743Smax.romanov@nginx.com     }
117*743Smax.romanov@nginx.com 
118*743Smax.romanov@nginx.com     buf = rb_str_buf_new(size);
119584Salexander.borisov@nginx.com 
120584Salexander.borisov@nginx.com     if (buf == Qnil) {
121584Salexander.borisov@nginx.com         return Qnil;
122584Salexander.borisov@nginx.com     }
123584Salexander.borisov@nginx.com 
124*743Smax.romanov@nginx.com     size = nxt_unit_request_read(req, RSTRING_PTR(buf), size);
125*743Smax.romanov@nginx.com 
126*743Smax.romanov@nginx.com     rb_str_set_len(buf, size);
127584Salexander.borisov@nginx.com 
128584Salexander.borisov@nginx.com     return buf;
129584Salexander.borisov@nginx.com }
130584Salexander.borisov@nginx.com 
131584Salexander.borisov@nginx.com 
132584Salexander.borisov@nginx.com static VALUE
133584Salexander.borisov@nginx.com nxt_ruby_stream_io_each(VALUE obj, VALUE args)
134584Salexander.borisov@nginx.com {
135584Salexander.borisov@nginx.com     VALUE  chunk;
136584Salexander.borisov@nginx.com 
137584Salexander.borisov@nginx.com     if (rb_block_given_p() == 0) {
138584Salexander.borisov@nginx.com         rb_raise(rb_eArgError, "Expected block on rack.input 'each' method");
139584Salexander.borisov@nginx.com     }
140584Salexander.borisov@nginx.com 
141584Salexander.borisov@nginx.com     for ( ;; ) {
142584Salexander.borisov@nginx.com         chunk = nxt_ruby_stream_io_gets(obj, Qnil);
143584Salexander.borisov@nginx.com 
144584Salexander.borisov@nginx.com         if (chunk == Qnil) {
145584Salexander.borisov@nginx.com             return Qnil;
146584Salexander.borisov@nginx.com         }
147584Salexander.borisov@nginx.com 
148584Salexander.borisov@nginx.com         rb_yield(chunk);
149584Salexander.borisov@nginx.com     }
150584Salexander.borisov@nginx.com 
151584Salexander.borisov@nginx.com     return Qnil;
152584Salexander.borisov@nginx.com }
153584Salexander.borisov@nginx.com 
154584Salexander.borisov@nginx.com 
155584Salexander.borisov@nginx.com static VALUE
156584Salexander.borisov@nginx.com nxt_ruby_stream_io_read(VALUE obj, VALUE args)
157584Salexander.borisov@nginx.com {
158584Salexander.borisov@nginx.com     VALUE                buf;
159584Salexander.borisov@nginx.com     long                 copy_size, u_size;
160584Salexander.borisov@nginx.com     nxt_ruby_run_ctx_t  *run_ctx;
161584Salexander.borisov@nginx.com 
162584Salexander.borisov@nginx.com     Data_Get_Struct(obj, nxt_ruby_run_ctx_t, run_ctx);
163584Salexander.borisov@nginx.com 
164*743Smax.romanov@nginx.com     copy_size = run_ctx->req->content_length;
165584Salexander.borisov@nginx.com 
166584Salexander.borisov@nginx.com     if (RARRAY_LEN(args) > 0 && TYPE(RARRAY_PTR(args)[0]) == T_FIXNUM) {
167584Salexander.borisov@nginx.com         u_size = NUM2LONG(RARRAY_PTR(args)[0]);
168584Salexander.borisov@nginx.com 
169584Salexander.borisov@nginx.com         if (u_size < 0 || copy_size == 0) {
170584Salexander.borisov@nginx.com             return Qnil;
171584Salexander.borisov@nginx.com         }
172584Salexander.borisov@nginx.com 
173584Salexander.borisov@nginx.com         if (copy_size > u_size) {
174584Salexander.borisov@nginx.com             copy_size = u_size;
175584Salexander.borisov@nginx.com         }
176584Salexander.borisov@nginx.com     }
177584Salexander.borisov@nginx.com 
178584Salexander.borisov@nginx.com     if (copy_size == 0) {
179584Salexander.borisov@nginx.com         return rb_str_new_cstr("");
180584Salexander.borisov@nginx.com     }
181584Salexander.borisov@nginx.com 
182584Salexander.borisov@nginx.com     buf = rb_str_buf_new(copy_size);
183584Salexander.borisov@nginx.com 
184584Salexander.borisov@nginx.com     if (nxt_slow_path(buf == Qnil)) {
185584Salexander.borisov@nginx.com         return Qnil;
186584Salexander.borisov@nginx.com     }
187584Salexander.borisov@nginx.com 
188*743Smax.romanov@nginx.com     copy_size = nxt_unit_request_read(run_ctx->req, RSTRING_PTR(buf),
189*743Smax.romanov@nginx.com                                       copy_size);
190584Salexander.borisov@nginx.com 
191584Salexander.borisov@nginx.com     if (RARRAY_LEN(args) > 1 && TYPE(RARRAY_PTR(args)[1]) == T_STRING) {
192584Salexander.borisov@nginx.com 
193584Salexander.borisov@nginx.com         rb_str_set_len(RARRAY_PTR(args)[1], 0);
194584Salexander.borisov@nginx.com         rb_str_cat(RARRAY_PTR(args)[1], RSTRING_PTR(buf), copy_size);
195584Salexander.borisov@nginx.com     }
196584Salexander.borisov@nginx.com 
197*743Smax.romanov@nginx.com     rb_str_set_len(buf, copy_size);
198584Salexander.borisov@nginx.com 
199584Salexander.borisov@nginx.com     return buf;
200584Salexander.borisov@nginx.com }
201584Salexander.borisov@nginx.com 
202584Salexander.borisov@nginx.com 
203584Salexander.borisov@nginx.com static VALUE
204584Salexander.borisov@nginx.com nxt_ruby_stream_io_rewind(VALUE obj, VALUE args)
205584Salexander.borisov@nginx.com {
206584Salexander.borisov@nginx.com     return Qnil;
207584Salexander.borisov@nginx.com }
208584Salexander.borisov@nginx.com 
209584Salexander.borisov@nginx.com 
210584Salexander.borisov@nginx.com static VALUE
211584Salexander.borisov@nginx.com nxt_ruby_stream_io_puts(VALUE obj, VALUE args)
212584Salexander.borisov@nginx.com {
213584Salexander.borisov@nginx.com     nxt_ruby_run_ctx_t  *run_ctx;
214584Salexander.borisov@nginx.com 
215584Salexander.borisov@nginx.com     if (RARRAY_LEN(args) != 1) {
216584Salexander.borisov@nginx.com         return Qnil;
217584Salexander.borisov@nginx.com     }
218584Salexander.borisov@nginx.com 
219584Salexander.borisov@nginx.com     Data_Get_Struct(obj, nxt_ruby_run_ctx_t, run_ctx);
220584Salexander.borisov@nginx.com 
221584Salexander.borisov@nginx.com     nxt_ruby_stream_io_s_write(run_ctx, RARRAY_PTR(args)[0]);
222584Salexander.borisov@nginx.com 
223584Salexander.borisov@nginx.com     return Qnil;
224584Salexander.borisov@nginx.com }
225584Salexander.borisov@nginx.com 
226584Salexander.borisov@nginx.com 
227584Salexander.borisov@nginx.com static VALUE
228584Salexander.borisov@nginx.com nxt_ruby_stream_io_write(VALUE obj, VALUE args)
229584Salexander.borisov@nginx.com {
230584Salexander.borisov@nginx.com     long                len;
231584Salexander.borisov@nginx.com     nxt_ruby_run_ctx_t  *run_ctx;
232584Salexander.borisov@nginx.com 
233584Salexander.borisov@nginx.com     if (RARRAY_LEN(args) != 1) {
234584Salexander.borisov@nginx.com         return Qnil;
235584Salexander.borisov@nginx.com     }
236584Salexander.borisov@nginx.com 
237584Salexander.borisov@nginx.com     Data_Get_Struct(obj, nxt_ruby_run_ctx_t, run_ctx);
238584Salexander.borisov@nginx.com 
239584Salexander.borisov@nginx.com     len = nxt_ruby_stream_io_s_write(run_ctx, RARRAY_PTR(args)[0]);
240584Salexander.borisov@nginx.com 
241584Salexander.borisov@nginx.com     return LONG2FIX(len);
242584Salexander.borisov@nginx.com }
243584Salexander.borisov@nginx.com 
244584Salexander.borisov@nginx.com 
245584Salexander.borisov@nginx.com nxt_inline long
246584Salexander.borisov@nginx.com nxt_ruby_stream_io_s_write(nxt_ruby_run_ctx_t *run_ctx, VALUE val)
247584Salexander.borisov@nginx.com {
248584Salexander.borisov@nginx.com     if (nxt_slow_path(val == Qnil)) {
249584Salexander.borisov@nginx.com         return 0;
250584Salexander.borisov@nginx.com     }
251584Salexander.borisov@nginx.com 
252584Salexander.borisov@nginx.com     if (TYPE(val) != T_STRING) {
253584Salexander.borisov@nginx.com         val = rb_funcall(val, rb_intern("to_s"), 0);
254584Salexander.borisov@nginx.com 
255584Salexander.borisov@nginx.com         if (TYPE(val) != T_STRING) {
256584Salexander.borisov@nginx.com             return 0;
257584Salexander.borisov@nginx.com         }
258584Salexander.borisov@nginx.com     }
259584Salexander.borisov@nginx.com 
260*743Smax.romanov@nginx.com     nxt_unit_req_error(run_ctx->req, "Ruby: %s", RSTRING_PTR(val));
261584Salexander.borisov@nginx.com 
262584Salexander.borisov@nginx.com     return RSTRING_LEN(val);
263584Salexander.borisov@nginx.com }
264584Salexander.borisov@nginx.com 
265584Salexander.borisov@nginx.com 
266584Salexander.borisov@nginx.com static VALUE
267584Salexander.borisov@nginx.com nxt_ruby_stream_io_flush(VALUE obj, VALUE args)
268584Salexander.borisov@nginx.com {
269584Salexander.borisov@nginx.com     return Qnil;
270584Salexander.borisov@nginx.com }
271