1*584Salexander.borisov@nginx.com 2*584Salexander.borisov@nginx.com /* 3*584Salexander.borisov@nginx.com * Copyright (C) Alexander Borisov 4*584Salexander.borisov@nginx.com * Copyright (C) NGINX, Inc. 5*584Salexander.borisov@nginx.com */ 6*584Salexander.borisov@nginx.com 7*584Salexander.borisov@nginx.com #include <ruby/nxt_ruby.h> 8*584Salexander.borisov@nginx.com 9*584Salexander.borisov@nginx.com 10*584Salexander.borisov@nginx.com static VALUE nxt_ruby_stream_io_new(VALUE class, VALUE wrap); 11*584Salexander.borisov@nginx.com static VALUE nxt_ruby_stream_io_initialize(int argc, VALUE *argv, VALUE self); 12*584Salexander.borisov@nginx.com static VALUE nxt_ruby_stream_io_gets(VALUE obj, VALUE args); 13*584Salexander.borisov@nginx.com static size_t nxt_ruby_stream_io_read_line(nxt_app_rmsg_t *rmsg, VALUE str); 14*584Salexander.borisov@nginx.com static VALUE nxt_ruby_stream_io_each(VALUE obj, VALUE args); 15*584Salexander.borisov@nginx.com static VALUE nxt_ruby_stream_io_read(VALUE obj, VALUE args); 16*584Salexander.borisov@nginx.com static VALUE nxt_ruby_stream_io_rewind(VALUE obj, VALUE args); 17*584Salexander.borisov@nginx.com static VALUE nxt_ruby_stream_io_puts(VALUE obj, VALUE args); 18*584Salexander.borisov@nginx.com static VALUE nxt_ruby_stream_io_write(VALUE obj, VALUE args); 19*584Salexander.borisov@nginx.com nxt_inline long nxt_ruby_stream_io_s_write(nxt_ruby_run_ctx_t *run_ctx, 20*584Salexander.borisov@nginx.com VALUE val); 21*584Salexander.borisov@nginx.com static VALUE nxt_ruby_stream_io_flush(VALUE obj, VALUE args); 22*584Salexander.borisov@nginx.com 23*584Salexander.borisov@nginx.com 24*584Salexander.borisov@nginx.com VALUE 25*584Salexander.borisov@nginx.com nxt_ruby_stream_io_input_init(void) 26*584Salexander.borisov@nginx.com { 27*584Salexander.borisov@nginx.com VALUE stream_io; 28*584Salexander.borisov@nginx.com 29*584Salexander.borisov@nginx.com stream_io = rb_define_class("NGINX_Unit_Stream_IO_Read", rb_cData); 30*584Salexander.borisov@nginx.com 31*584Salexander.borisov@nginx.com rb_gc_register_address(&stream_io); 32*584Salexander.borisov@nginx.com 33*584Salexander.borisov@nginx.com rb_define_singleton_method(stream_io, "new", nxt_ruby_stream_io_new, 1); 34*584Salexander.borisov@nginx.com rb_define_method(stream_io, "initialize", nxt_ruby_stream_io_initialize, -1); 35*584Salexander.borisov@nginx.com rb_define_method(stream_io, "gets", nxt_ruby_stream_io_gets, 0); 36*584Salexander.borisov@nginx.com rb_define_method(stream_io, "each", nxt_ruby_stream_io_each, 0); 37*584Salexander.borisov@nginx.com rb_define_method(stream_io, "read", nxt_ruby_stream_io_read, -2); 38*584Salexander.borisov@nginx.com rb_define_method(stream_io, "rewind", nxt_ruby_stream_io_rewind, 0); 39*584Salexander.borisov@nginx.com 40*584Salexander.borisov@nginx.com return stream_io; 41*584Salexander.borisov@nginx.com } 42*584Salexander.borisov@nginx.com 43*584Salexander.borisov@nginx.com 44*584Salexander.borisov@nginx.com VALUE 45*584Salexander.borisov@nginx.com nxt_ruby_stream_io_error_init(void) 46*584Salexander.borisov@nginx.com { 47*584Salexander.borisov@nginx.com VALUE stream_io; 48*584Salexander.borisov@nginx.com 49*584Salexander.borisov@nginx.com stream_io = rb_define_class("NGINX_Unit_Stream_IO_Error", rb_cData); 50*584Salexander.borisov@nginx.com 51*584Salexander.borisov@nginx.com rb_gc_register_address(&stream_io); 52*584Salexander.borisov@nginx.com 53*584Salexander.borisov@nginx.com rb_define_singleton_method(stream_io, "new", nxt_ruby_stream_io_new, 1); 54*584Salexander.borisov@nginx.com rb_define_method(stream_io, "initialize", nxt_ruby_stream_io_initialize, -1); 55*584Salexander.borisov@nginx.com rb_define_method(stream_io, "puts", nxt_ruby_stream_io_puts, -2); 56*584Salexander.borisov@nginx.com rb_define_method(stream_io, "write", nxt_ruby_stream_io_write, -2); 57*584Salexander.borisov@nginx.com rb_define_method(stream_io, "flush", nxt_ruby_stream_io_flush, 0); 58*584Salexander.borisov@nginx.com 59*584Salexander.borisov@nginx.com return stream_io; 60*584Salexander.borisov@nginx.com } 61*584Salexander.borisov@nginx.com 62*584Salexander.borisov@nginx.com 63*584Salexander.borisov@nginx.com static VALUE 64*584Salexander.borisov@nginx.com nxt_ruby_stream_io_new(VALUE class, VALUE wrap) 65*584Salexander.borisov@nginx.com { 66*584Salexander.borisov@nginx.com VALUE self; 67*584Salexander.borisov@nginx.com nxt_ruby_run_ctx_t *run_ctx; 68*584Salexander.borisov@nginx.com 69*584Salexander.borisov@nginx.com Data_Get_Struct(wrap, nxt_ruby_run_ctx_t, run_ctx); 70*584Salexander.borisov@nginx.com self = Data_Wrap_Struct(class, 0, 0, run_ctx); 71*584Salexander.borisov@nginx.com 72*584Salexander.borisov@nginx.com rb_obj_call_init(self, 0, NULL); 73*584Salexander.borisov@nginx.com 74*584Salexander.borisov@nginx.com return self; 75*584Salexander.borisov@nginx.com } 76*584Salexander.borisov@nginx.com 77*584Salexander.borisov@nginx.com 78*584Salexander.borisov@nginx.com static VALUE 79*584Salexander.borisov@nginx.com nxt_ruby_stream_io_initialize(int argc, VALUE *argv, VALUE self) 80*584Salexander.borisov@nginx.com { 81*584Salexander.borisov@nginx.com return self; 82*584Salexander.borisov@nginx.com } 83*584Salexander.borisov@nginx.com 84*584Salexander.borisov@nginx.com 85*584Salexander.borisov@nginx.com static VALUE 86*584Salexander.borisov@nginx.com nxt_ruby_stream_io_gets(VALUE obj, VALUE args) 87*584Salexander.borisov@nginx.com { 88*584Salexander.borisov@nginx.com VALUE buf; 89*584Salexander.borisov@nginx.com nxt_ruby_run_ctx_t *run_ctx; 90*584Salexander.borisov@nginx.com 91*584Salexander.borisov@nginx.com Data_Get_Struct(obj, nxt_ruby_run_ctx_t, run_ctx); 92*584Salexander.borisov@nginx.com 93*584Salexander.borisov@nginx.com if (run_ctx->body_preread_size == 0) { 94*584Salexander.borisov@nginx.com return Qnil; 95*584Salexander.borisov@nginx.com } 96*584Salexander.borisov@nginx.com 97*584Salexander.borisov@nginx.com buf = rb_str_buf_new(1); 98*584Salexander.borisov@nginx.com 99*584Salexander.borisov@nginx.com if (buf == Qnil) { 100*584Salexander.borisov@nginx.com return Qnil; 101*584Salexander.borisov@nginx.com } 102*584Salexander.borisov@nginx.com 103*584Salexander.borisov@nginx.com run_ctx->body_preread_size -= nxt_ruby_stream_io_read_line(run_ctx->rmsg, 104*584Salexander.borisov@nginx.com buf); 105*584Salexander.borisov@nginx.com 106*584Salexander.borisov@nginx.com return buf; 107*584Salexander.borisov@nginx.com } 108*584Salexander.borisov@nginx.com 109*584Salexander.borisov@nginx.com 110*584Salexander.borisov@nginx.com static size_t 111*584Salexander.borisov@nginx.com nxt_ruby_stream_io_read_line(nxt_app_rmsg_t *rmsg, VALUE str) 112*584Salexander.borisov@nginx.com { 113*584Salexander.borisov@nginx.com size_t len, size; 114*584Salexander.borisov@nginx.com u_char *p; 115*584Salexander.borisov@nginx.com nxt_buf_t *buf; 116*584Salexander.borisov@nginx.com 117*584Salexander.borisov@nginx.com len = 0; 118*584Salexander.borisov@nginx.com 119*584Salexander.borisov@nginx.com for (buf = rmsg->buf; buf != NULL; buf = buf->next) { 120*584Salexander.borisov@nginx.com 121*584Salexander.borisov@nginx.com size = nxt_buf_mem_used_size(&buf->mem); 122*584Salexander.borisov@nginx.com p = memchr(buf->mem.pos, '\n', size); 123*584Salexander.borisov@nginx.com 124*584Salexander.borisov@nginx.com if (p != NULL) { 125*584Salexander.borisov@nginx.com p++; 126*584Salexander.borisov@nginx.com size = p - buf->mem.pos; 127*584Salexander.borisov@nginx.com 128*584Salexander.borisov@nginx.com rb_str_cat(str, (const char *) buf->mem.pos, size); 129*584Salexander.borisov@nginx.com 130*584Salexander.borisov@nginx.com len += size; 131*584Salexander.borisov@nginx.com buf->mem.pos = p; 132*584Salexander.borisov@nginx.com 133*584Salexander.borisov@nginx.com break; 134*584Salexander.borisov@nginx.com } 135*584Salexander.borisov@nginx.com 136*584Salexander.borisov@nginx.com rb_str_cat(str, (const char *) buf->mem.pos, size); 137*584Salexander.borisov@nginx.com 138*584Salexander.borisov@nginx.com len += size; 139*584Salexander.borisov@nginx.com buf->mem.pos = buf->mem.free; 140*584Salexander.borisov@nginx.com } 141*584Salexander.borisov@nginx.com 142*584Salexander.borisov@nginx.com rmsg->buf = buf; 143*584Salexander.borisov@nginx.com 144*584Salexander.borisov@nginx.com return len; 145*584Salexander.borisov@nginx.com } 146*584Salexander.borisov@nginx.com 147*584Salexander.borisov@nginx.com 148*584Salexander.borisov@nginx.com static VALUE 149*584Salexander.borisov@nginx.com nxt_ruby_stream_io_each(VALUE obj, VALUE args) 150*584Salexander.borisov@nginx.com { 151*584Salexander.borisov@nginx.com VALUE chunk; 152*584Salexander.borisov@nginx.com 153*584Salexander.borisov@nginx.com if (rb_block_given_p() == 0) { 154*584Salexander.borisov@nginx.com rb_raise(rb_eArgError, "Expected block on rack.input 'each' method"); 155*584Salexander.borisov@nginx.com } 156*584Salexander.borisov@nginx.com 157*584Salexander.borisov@nginx.com for ( ;; ) { 158*584Salexander.borisov@nginx.com chunk = nxt_ruby_stream_io_gets(obj, Qnil); 159*584Salexander.borisov@nginx.com 160*584Salexander.borisov@nginx.com if (chunk == Qnil) { 161*584Salexander.borisov@nginx.com return Qnil; 162*584Salexander.borisov@nginx.com } 163*584Salexander.borisov@nginx.com 164*584Salexander.borisov@nginx.com rb_yield(chunk); 165*584Salexander.borisov@nginx.com } 166*584Salexander.borisov@nginx.com 167*584Salexander.borisov@nginx.com return Qnil; 168*584Salexander.borisov@nginx.com } 169*584Salexander.borisov@nginx.com 170*584Salexander.borisov@nginx.com 171*584Salexander.borisov@nginx.com static VALUE 172*584Salexander.borisov@nginx.com nxt_ruby_stream_io_read(VALUE obj, VALUE args) 173*584Salexander.borisov@nginx.com { 174*584Salexander.borisov@nginx.com VALUE buf; 175*584Salexander.borisov@nginx.com long copy_size, u_size; 176*584Salexander.borisov@nginx.com size_t len; 177*584Salexander.borisov@nginx.com nxt_ruby_run_ctx_t *run_ctx; 178*584Salexander.borisov@nginx.com 179*584Salexander.borisov@nginx.com Data_Get_Struct(obj, nxt_ruby_run_ctx_t, run_ctx); 180*584Salexander.borisov@nginx.com 181*584Salexander.borisov@nginx.com copy_size = run_ctx->body_preread_size; 182*584Salexander.borisov@nginx.com 183*584Salexander.borisov@nginx.com if (RARRAY_LEN(args) > 0 && TYPE(RARRAY_PTR(args)[0]) == T_FIXNUM) { 184*584Salexander.borisov@nginx.com u_size = NUM2LONG(RARRAY_PTR(args)[0]); 185*584Salexander.borisov@nginx.com 186*584Salexander.borisov@nginx.com if (u_size < 0 || copy_size == 0) { 187*584Salexander.borisov@nginx.com return Qnil; 188*584Salexander.borisov@nginx.com } 189*584Salexander.borisov@nginx.com 190*584Salexander.borisov@nginx.com if (copy_size > u_size) { 191*584Salexander.borisov@nginx.com copy_size = u_size; 192*584Salexander.borisov@nginx.com } 193*584Salexander.borisov@nginx.com } 194*584Salexander.borisov@nginx.com 195*584Salexander.borisov@nginx.com if (copy_size == 0) { 196*584Salexander.borisov@nginx.com return rb_str_new_cstr(""); 197*584Salexander.borisov@nginx.com } 198*584Salexander.borisov@nginx.com 199*584Salexander.borisov@nginx.com buf = rb_str_buf_new(copy_size); 200*584Salexander.borisov@nginx.com 201*584Salexander.borisov@nginx.com if (nxt_slow_path(buf == Qnil)) { 202*584Salexander.borisov@nginx.com return Qnil; 203*584Salexander.borisov@nginx.com } 204*584Salexander.borisov@nginx.com 205*584Salexander.borisov@nginx.com len = nxt_app_msg_read_raw(run_ctx->task, run_ctx->rmsg, 206*584Salexander.borisov@nginx.com RSTRING_PTR(buf), (size_t) copy_size); 207*584Salexander.borisov@nginx.com 208*584Salexander.borisov@nginx.com if (RARRAY_LEN(args) > 1 && TYPE(RARRAY_PTR(args)[1]) == T_STRING) { 209*584Salexander.borisov@nginx.com 210*584Salexander.borisov@nginx.com rb_str_set_len(RARRAY_PTR(args)[1], 0); 211*584Salexander.borisov@nginx.com rb_str_cat(RARRAY_PTR(args)[1], RSTRING_PTR(buf), copy_size); 212*584Salexander.borisov@nginx.com } 213*584Salexander.borisov@nginx.com 214*584Salexander.borisov@nginx.com rb_str_set_len(buf, (long) len); 215*584Salexander.borisov@nginx.com 216*584Salexander.borisov@nginx.com run_ctx->body_preread_size -= len; 217*584Salexander.borisov@nginx.com 218*584Salexander.borisov@nginx.com return buf; 219*584Salexander.borisov@nginx.com } 220*584Salexander.borisov@nginx.com 221*584Salexander.borisov@nginx.com 222*584Salexander.borisov@nginx.com static VALUE 223*584Salexander.borisov@nginx.com nxt_ruby_stream_io_rewind(VALUE obj, VALUE args) 224*584Salexander.borisov@nginx.com { 225*584Salexander.borisov@nginx.com return Qnil; 226*584Salexander.borisov@nginx.com } 227*584Salexander.borisov@nginx.com 228*584Salexander.borisov@nginx.com 229*584Salexander.borisov@nginx.com static VALUE 230*584Salexander.borisov@nginx.com nxt_ruby_stream_io_puts(VALUE obj, VALUE args) 231*584Salexander.borisov@nginx.com { 232*584Salexander.borisov@nginx.com nxt_ruby_run_ctx_t *run_ctx; 233*584Salexander.borisov@nginx.com 234*584Salexander.borisov@nginx.com if (RARRAY_LEN(args) != 1) { 235*584Salexander.borisov@nginx.com return Qnil; 236*584Salexander.borisov@nginx.com } 237*584Salexander.borisov@nginx.com 238*584Salexander.borisov@nginx.com Data_Get_Struct(obj, nxt_ruby_run_ctx_t, run_ctx); 239*584Salexander.borisov@nginx.com 240*584Salexander.borisov@nginx.com nxt_ruby_stream_io_s_write(run_ctx, RARRAY_PTR(args)[0]); 241*584Salexander.borisov@nginx.com 242*584Salexander.borisov@nginx.com return Qnil; 243*584Salexander.borisov@nginx.com } 244*584Salexander.borisov@nginx.com 245*584Salexander.borisov@nginx.com 246*584Salexander.borisov@nginx.com static VALUE 247*584Salexander.borisov@nginx.com nxt_ruby_stream_io_write(VALUE obj, VALUE args) 248*584Salexander.borisov@nginx.com { 249*584Salexander.borisov@nginx.com long len; 250*584Salexander.borisov@nginx.com nxt_ruby_run_ctx_t *run_ctx; 251*584Salexander.borisov@nginx.com 252*584Salexander.borisov@nginx.com if (RARRAY_LEN(args) != 1) { 253*584Salexander.borisov@nginx.com return Qnil; 254*584Salexander.borisov@nginx.com } 255*584Salexander.borisov@nginx.com 256*584Salexander.borisov@nginx.com Data_Get_Struct(obj, nxt_ruby_run_ctx_t, run_ctx); 257*584Salexander.borisov@nginx.com 258*584Salexander.borisov@nginx.com len = nxt_ruby_stream_io_s_write(run_ctx, RARRAY_PTR(args)[0]); 259*584Salexander.borisov@nginx.com 260*584Salexander.borisov@nginx.com return LONG2FIX(len); 261*584Salexander.borisov@nginx.com } 262*584Salexander.borisov@nginx.com 263*584Salexander.borisov@nginx.com 264*584Salexander.borisov@nginx.com nxt_inline long 265*584Salexander.borisov@nginx.com nxt_ruby_stream_io_s_write(nxt_ruby_run_ctx_t *run_ctx, VALUE val) 266*584Salexander.borisov@nginx.com { 267*584Salexander.borisov@nginx.com if (nxt_slow_path(val == Qnil)) { 268*584Salexander.borisov@nginx.com return 0; 269*584Salexander.borisov@nginx.com } 270*584Salexander.borisov@nginx.com 271*584Salexander.borisov@nginx.com if (TYPE(val) != T_STRING) { 272*584Salexander.borisov@nginx.com val = rb_funcall(val, rb_intern("to_s"), 0); 273*584Salexander.borisov@nginx.com 274*584Salexander.borisov@nginx.com if (TYPE(val) != T_STRING) { 275*584Salexander.borisov@nginx.com return 0; 276*584Salexander.borisov@nginx.com } 277*584Salexander.borisov@nginx.com } 278*584Salexander.borisov@nginx.com 279*584Salexander.borisov@nginx.com nxt_log_error(NXT_LOG_ERR, run_ctx->task->log, "Ruby: %s", 280*584Salexander.borisov@nginx.com RSTRING_PTR(val)); 281*584Salexander.borisov@nginx.com 282*584Salexander.borisov@nginx.com return RSTRING_LEN(val); 283*584Salexander.borisov@nginx.com } 284*584Salexander.borisov@nginx.com 285*584Salexander.borisov@nginx.com 286*584Salexander.borisov@nginx.com static VALUE 287*584Salexander.borisov@nginx.com nxt_ruby_stream_io_flush(VALUE obj, VALUE args) 288*584Salexander.borisov@nginx.com { 289*584Salexander.borisov@nginx.com return Qnil; 290*584Salexander.borisov@nginx.com } 291