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