1584Salexander.borisov@nginx.com /* 2584Salexander.borisov@nginx.com * Copyright (C) Alexander Borisov 3584Salexander.borisov@nginx.com * Copyright (C) NGINX, Inc. 4584Salexander.borisov@nginx.com */ 5584Salexander.borisov@nginx.com 6584Salexander.borisov@nginx.com #include <ruby/nxt_ruby.h> 7584Salexander.borisov@nginx.com 8584Salexander.borisov@nginx.com 9584Salexander.borisov@nginx.com #define NXT_RUBY_RACK_API_VERSION_MAJOR 1 10584Salexander.borisov@nginx.com #define NXT_RUBY_RACK_API_VERSION_MINOR 3 11584Salexander.borisov@nginx.com 12584Salexander.borisov@nginx.com #define NXT_RUBY_STRINGIZE_HELPER(x) #x 13584Salexander.borisov@nginx.com #define NXT_RUBY_STRINGIZE(x) NXT_RUBY_STRINGIZE_HELPER(x) 14584Salexander.borisov@nginx.com 15584Salexander.borisov@nginx.com #define NXT_RUBY_LIB_VERSION \ 16584Salexander.borisov@nginx.com NXT_RUBY_STRINGIZE(RUBY_API_VERSION_MAJOR) \ 17584Salexander.borisov@nginx.com "." NXT_RUBY_STRINGIZE(RUBY_API_VERSION_MINOR) \ 18584Salexander.borisov@nginx.com "." NXT_RUBY_STRINGIZE(RUBY_API_VERSION_TEENY) 19584Salexander.borisov@nginx.com 20584Salexander.borisov@nginx.com 21584Salexander.borisov@nginx.com typedef struct { 22584Salexander.borisov@nginx.com nxt_task_t *task; 23584Salexander.borisov@nginx.com nxt_str_t *script; 24584Salexander.borisov@nginx.com VALUE builder; 25584Salexander.borisov@nginx.com } nxt_ruby_rack_init_t; 26584Salexander.borisov@nginx.com 27584Salexander.borisov@nginx.com 28584Salexander.borisov@nginx.com static nxt_int_t nxt_ruby_init(nxt_task_t *task, nxt_common_app_conf_t *conf); 29584Salexander.borisov@nginx.com static VALUE nxt_ruby_init_basic(VALUE arg); 30584Salexander.borisov@nginx.com static nxt_int_t nxt_ruby_init_io(nxt_task_t *task); 31584Salexander.borisov@nginx.com static VALUE nxt_ruby_rack_init(nxt_ruby_rack_init_t *rack_init); 32584Salexander.borisov@nginx.com 33584Salexander.borisov@nginx.com static VALUE nxt_ruby_require_rubygems(VALUE arg); 34584Salexander.borisov@nginx.com static VALUE nxt_ruby_require_rack(VALUE arg); 35584Salexander.borisov@nginx.com static VALUE nxt_ruby_rack_parse_script(VALUE ctx); 36584Salexander.borisov@nginx.com static VALUE nxt_ruby_rack_env_create(VALUE arg); 37584Salexander.borisov@nginx.com static nxt_int_t nxt_ruby_run(nxt_task_t *task, nxt_app_rmsg_t *rmsg, 38584Salexander.borisov@nginx.com nxt_app_wmsg_t *wmsg); 39584Salexander.borisov@nginx.com 40584Salexander.borisov@nginx.com static VALUE nxt_ruby_rack_app_run(VALUE arg); 41584Salexander.borisov@nginx.com static nxt_int_t nxt_ruby_read_request(nxt_ruby_run_ctx_t *run_ctx, 42584Salexander.borisov@nginx.com VALUE hash_env); 43584Salexander.borisov@nginx.com nxt_inline nxt_int_t nxt_ruby_read_add_env(nxt_task_t *task, 44584Salexander.borisov@nginx.com nxt_app_rmsg_t *rmsg, VALUE hash_env, const char *name, nxt_str_t *str); 45584Salexander.borisov@nginx.com static nxt_int_t nxt_ruby_rack_result_status(VALUE result); 46584Salexander.borisov@nginx.com nxt_inline nxt_int_t nxt_ruby_write(nxt_task_t *task, nxt_app_wmsg_t *wmsg, 47584Salexander.borisov@nginx.com const u_char *data, size_t len, nxt_bool_t flush, nxt_bool_t last); 48584Salexander.borisov@nginx.com static nxt_int_t nxt_ruby_rack_result_headers(VALUE result); 49584Salexander.borisov@nginx.com static int nxt_ruby_hash_foreach(VALUE r_key, VALUE r_value, VALUE arg); 50584Salexander.borisov@nginx.com static nxt_int_t nxt_ruby_head_send_part(const char *key, size_t key_size, 51584Salexander.borisov@nginx.com const char *value, size_t value_size); 52584Salexander.borisov@nginx.com static nxt_int_t nxt_ruby_rack_result_body(VALUE result); 53584Salexander.borisov@nginx.com static nxt_int_t nxt_ruby_rack_result_body_file_write(VALUE filepath); 54584Salexander.borisov@nginx.com static VALUE nxt_ruby_rack_result_body_each(VALUE body); 55584Salexander.borisov@nginx.com 56584Salexander.borisov@nginx.com static void nxt_ruby_exception_log(nxt_task_t *task, uint32_t level, 57584Salexander.borisov@nginx.com const char *desc); 58584Salexander.borisov@nginx.com 59584Salexander.borisov@nginx.com static void nxt_ruby_atexit(nxt_task_t *task); 60584Salexander.borisov@nginx.com 61584Salexander.borisov@nginx.com 62584Salexander.borisov@nginx.com static uint32_t compat[] = { 63584Salexander.borisov@nginx.com NXT_VERNUM, NXT_DEBUG, 64584Salexander.borisov@nginx.com }; 65584Salexander.borisov@nginx.com 66584Salexander.borisov@nginx.com static VALUE nxt_ruby_rackup; 67584Salexander.borisov@nginx.com static VALUE nxt_ruby_call; 68584Salexander.borisov@nginx.com static VALUE nxt_ruby_env; 69584Salexander.borisov@nginx.com static VALUE nxt_ruby_io_input; 70584Salexander.borisov@nginx.com static VALUE nxt_ruby_io_error; 71584Salexander.borisov@nginx.com static nxt_ruby_run_ctx_t nxt_ruby_run_ctx; 72584Salexander.borisov@nginx.com 73584Salexander.borisov@nginx.com NXT_EXPORT nxt_application_module_t nxt_app_module = { 74584Salexander.borisov@nginx.com sizeof(compat), 75584Salexander.borisov@nginx.com compat, 76584Salexander.borisov@nginx.com nxt_string("ruby"), 77584Salexander.borisov@nginx.com nxt_string(NXT_RUBY_LIB_VERSION), 78584Salexander.borisov@nginx.com nxt_ruby_init, 79584Salexander.borisov@nginx.com nxt_ruby_run, 80584Salexander.borisov@nginx.com nxt_ruby_atexit, 81584Salexander.borisov@nginx.com }; 82584Salexander.borisov@nginx.com 83584Salexander.borisov@nginx.com 84584Salexander.borisov@nginx.com static nxt_int_t 85584Salexander.borisov@nginx.com nxt_ruby_init(nxt_task_t *task, nxt_common_app_conf_t *conf) 86584Salexander.borisov@nginx.com { 87584Salexander.borisov@nginx.com int state; 88584Salexander.borisov@nginx.com VALUE dummy, res; 89584Salexander.borisov@nginx.com nxt_ruby_rack_init_t rack_init; 90584Salexander.borisov@nginx.com 91584Salexander.borisov@nginx.com ruby_init(); 92584Salexander.borisov@nginx.com Init_stack(&dummy); 93584Salexander.borisov@nginx.com ruby_init_loadpath(); 94584Salexander.borisov@nginx.com ruby_script("NGINX_Unit"); 95584Salexander.borisov@nginx.com 96584Salexander.borisov@nginx.com rack_init.task = task; 97584Salexander.borisov@nginx.com rack_init.script = &conf->u.ruby.script; 98584Salexander.borisov@nginx.com 99584Salexander.borisov@nginx.com res = rb_protect(nxt_ruby_init_basic, 100584Salexander.borisov@nginx.com (VALUE) (uintptr_t) &rack_init, &state); 101584Salexander.borisov@nginx.com if (nxt_slow_path(res == Qnil || state != 0)) { 102584Salexander.borisov@nginx.com nxt_ruby_exception_log(task, NXT_LOG_ALERT, 103584Salexander.borisov@nginx.com "Failed to init basic variables"); 104584Salexander.borisov@nginx.com return NXT_ERROR; 105584Salexander.borisov@nginx.com } 106584Salexander.borisov@nginx.com 107584Salexander.borisov@nginx.com nxt_ruby_rackup = nxt_ruby_rack_init(&rack_init); 108584Salexander.borisov@nginx.com if (nxt_slow_path(nxt_ruby_rackup == Qnil)) { 109584Salexander.borisov@nginx.com return NXT_ERROR; 110584Salexander.borisov@nginx.com } 111584Salexander.borisov@nginx.com 112584Salexander.borisov@nginx.com nxt_ruby_call = rb_intern("call"); 113584Salexander.borisov@nginx.com if (nxt_slow_path(nxt_ruby_call == Qnil)) { 114584Salexander.borisov@nginx.com nxt_alert(task, "Ruby: Unable to find rack entry point"); 115584Salexander.borisov@nginx.com 116584Salexander.borisov@nginx.com return NXT_ERROR; 117584Salexander.borisov@nginx.com } 118584Salexander.borisov@nginx.com 119584Salexander.borisov@nginx.com nxt_ruby_env = rb_protect(nxt_ruby_rack_env_create, Qnil, &state); 120584Salexander.borisov@nginx.com if (nxt_slow_path(state != 0)) { 121584Salexander.borisov@nginx.com nxt_ruby_exception_log(task, NXT_LOG_ALERT, 122584Salexander.borisov@nginx.com "Failed to create 'environ' variable"); 123584Salexander.borisov@nginx.com return NXT_ERROR; 124584Salexander.borisov@nginx.com } 125584Salexander.borisov@nginx.com 126584Salexander.borisov@nginx.com rb_gc_register_address(&nxt_ruby_rackup); 127584Salexander.borisov@nginx.com rb_gc_register_address(&nxt_ruby_call); 128584Salexander.borisov@nginx.com rb_gc_register_address(&nxt_ruby_env); 129584Salexander.borisov@nginx.com 130584Salexander.borisov@nginx.com return NXT_OK; 131584Salexander.borisov@nginx.com } 132584Salexander.borisov@nginx.com 133584Salexander.borisov@nginx.com 134584Salexander.borisov@nginx.com static VALUE 135584Salexander.borisov@nginx.com nxt_ruby_init_basic(VALUE arg) 136584Salexander.borisov@nginx.com { 137584Salexander.borisov@nginx.com int state; 138584Salexander.borisov@nginx.com nxt_int_t rc; 139584Salexander.borisov@nginx.com nxt_ruby_rack_init_t *rack_init; 140584Salexander.borisov@nginx.com 141584Salexander.borisov@nginx.com rack_init = (nxt_ruby_rack_init_t *) (uintptr_t) arg; 142584Salexander.borisov@nginx.com 143584Salexander.borisov@nginx.com state = rb_enc_find_index("encdb"); 144584Salexander.borisov@nginx.com if (nxt_slow_path(state == 0)) { 145584Salexander.borisov@nginx.com nxt_alert(rack_init->task, 146584Salexander.borisov@nginx.com "Ruby: Failed to find encoding index 'encdb'"); 147584Salexander.borisov@nginx.com 148584Salexander.borisov@nginx.com return Qnil; 149584Salexander.borisov@nginx.com } 150584Salexander.borisov@nginx.com 151*609Salexander.borisov@nginx.com rb_funcall(rb_cObject, rb_intern("require"), 1, 152*609Salexander.borisov@nginx.com rb_str_new2("enc/trans/transdb")); 153*609Salexander.borisov@nginx.com 154584Salexander.borisov@nginx.com rc = nxt_ruby_init_io(rack_init->task); 155584Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 156584Salexander.borisov@nginx.com return Qnil; 157584Salexander.borisov@nginx.com } 158584Salexander.borisov@nginx.com 159584Salexander.borisov@nginx.com return arg; 160584Salexander.borisov@nginx.com } 161584Salexander.borisov@nginx.com 162584Salexander.borisov@nginx.com 163584Salexander.borisov@nginx.com static nxt_int_t 164584Salexander.borisov@nginx.com nxt_ruby_init_io(nxt_task_t *task) 165584Salexander.borisov@nginx.com { 166584Salexander.borisov@nginx.com VALUE rb, io_input, io_error; 167584Salexander.borisov@nginx.com 168584Salexander.borisov@nginx.com io_input = nxt_ruby_stream_io_input_init(); 169584Salexander.borisov@nginx.com rb = Data_Wrap_Struct(io_input, 0, 0, &nxt_ruby_run_ctx); 170584Salexander.borisov@nginx.com 171584Salexander.borisov@nginx.com nxt_ruby_io_input = rb_funcall(io_input, rb_intern("new"), 1, rb); 172584Salexander.borisov@nginx.com if (nxt_slow_path(nxt_ruby_io_input == Qnil)) { 173584Salexander.borisov@nginx.com nxt_alert(task, "Ruby: Failed to create environment 'rack.input' var"); 174584Salexander.borisov@nginx.com 175584Salexander.borisov@nginx.com return NXT_ERROR; 176584Salexander.borisov@nginx.com } 177584Salexander.borisov@nginx.com 178584Salexander.borisov@nginx.com io_error = nxt_ruby_stream_io_error_init(); 179584Salexander.borisov@nginx.com rb = Data_Wrap_Struct(io_error, 0, 0, &nxt_ruby_run_ctx); 180584Salexander.borisov@nginx.com 181584Salexander.borisov@nginx.com nxt_ruby_io_error = rb_funcall(io_error, rb_intern("new"), 1, rb); 182584Salexander.borisov@nginx.com if (nxt_slow_path(nxt_ruby_io_error == Qnil)) { 183584Salexander.borisov@nginx.com nxt_alert(task, "Ruby: Failed to create environment 'rack.error' var"); 184584Salexander.borisov@nginx.com 185584Salexander.borisov@nginx.com return NXT_ERROR; 186584Salexander.borisov@nginx.com } 187584Salexander.borisov@nginx.com 188584Salexander.borisov@nginx.com rb_gc_register_address(&nxt_ruby_io_input); 189584Salexander.borisov@nginx.com rb_gc_register_address(&nxt_ruby_io_error); 190584Salexander.borisov@nginx.com 191584Salexander.borisov@nginx.com return NXT_OK; 192584Salexander.borisov@nginx.com } 193584Salexander.borisov@nginx.com 194584Salexander.borisov@nginx.com 195584Salexander.borisov@nginx.com static VALUE 196584Salexander.borisov@nginx.com nxt_ruby_rack_init(nxt_ruby_rack_init_t *rack_init) 197584Salexander.borisov@nginx.com { 198584Salexander.borisov@nginx.com int state; 199584Salexander.borisov@nginx.com VALUE rack, rackup; 200584Salexander.borisov@nginx.com 201584Salexander.borisov@nginx.com rb_protect(nxt_ruby_require_rubygems, Qnil, &state); 202584Salexander.borisov@nginx.com if (nxt_slow_path(state != 0)) { 203584Salexander.borisov@nginx.com nxt_ruby_exception_log(rack_init->task, NXT_LOG_ALERT, 204584Salexander.borisov@nginx.com "Failed to require 'rubygems' package"); 205584Salexander.borisov@nginx.com return Qnil; 206584Salexander.borisov@nginx.com } 207584Salexander.borisov@nginx.com 208584Salexander.borisov@nginx.com rb_protect(nxt_ruby_require_rack, Qnil, &state); 209584Salexander.borisov@nginx.com if (nxt_slow_path(state != 0)) { 210584Salexander.borisov@nginx.com nxt_ruby_exception_log(rack_init->task, NXT_LOG_ALERT, 211584Salexander.borisov@nginx.com "Failed to require 'rack' package"); 212584Salexander.borisov@nginx.com return Qnil; 213584Salexander.borisov@nginx.com } 214584Salexander.borisov@nginx.com 215584Salexander.borisov@nginx.com rack = rb_const_get(rb_cObject, rb_intern("Rack")); 216584Salexander.borisov@nginx.com rack_init->builder = rb_const_get(rack, rb_intern("Builder")); 217584Salexander.borisov@nginx.com 218584Salexander.borisov@nginx.com rackup = rb_protect(nxt_ruby_rack_parse_script, 219584Salexander.borisov@nginx.com (VALUE) (uintptr_t) rack_init, &state); 220584Salexander.borisov@nginx.com if (nxt_slow_path(TYPE(rackup) != T_ARRAY || state != 0)) { 221584Salexander.borisov@nginx.com nxt_ruby_exception_log(rack_init->task, NXT_LOG_ALERT, 222584Salexander.borisov@nginx.com "Failed to parse rack script"); 223584Salexander.borisov@nginx.com return Qnil; 224584Salexander.borisov@nginx.com } 225584Salexander.borisov@nginx.com 226584Salexander.borisov@nginx.com if (nxt_slow_path(RARRAY_LEN(rackup) < 1)) { 227584Salexander.borisov@nginx.com nxt_alert(rack_init->task, "Ruby: Invalid rack config file"); 228584Salexander.borisov@nginx.com return Qnil; 229584Salexander.borisov@nginx.com } 230584Salexander.borisov@nginx.com 231584Salexander.borisov@nginx.com return RARRAY_PTR(rackup)[0]; 232584Salexander.borisov@nginx.com } 233584Salexander.borisov@nginx.com 234584Salexander.borisov@nginx.com 235584Salexander.borisov@nginx.com static VALUE 236584Salexander.borisov@nginx.com nxt_ruby_require_rubygems(VALUE arg) 237584Salexander.borisov@nginx.com { 238584Salexander.borisov@nginx.com return rb_funcall(rb_cObject, rb_intern("require"), 1, 239584Salexander.borisov@nginx.com rb_str_new2("rubygems")); 240584Salexander.borisov@nginx.com } 241584Salexander.borisov@nginx.com 242584Salexander.borisov@nginx.com 243584Salexander.borisov@nginx.com static VALUE 244584Salexander.borisov@nginx.com nxt_ruby_require_rack(VALUE arg) 245584Salexander.borisov@nginx.com { 246584Salexander.borisov@nginx.com return rb_funcall(rb_cObject, rb_intern("require"), 1, rb_str_new2("rack")); 247584Salexander.borisov@nginx.com } 248584Salexander.borisov@nginx.com 249584Salexander.borisov@nginx.com 250584Salexander.borisov@nginx.com static VALUE 251584Salexander.borisov@nginx.com nxt_ruby_rack_parse_script(VALUE ctx) 252584Salexander.borisov@nginx.com { 253584Salexander.borisov@nginx.com VALUE script, res; 254584Salexander.borisov@nginx.com nxt_ruby_rack_init_t *rack_init; 255584Salexander.borisov@nginx.com 256584Salexander.borisov@nginx.com rack_init = (nxt_ruby_rack_init_t *) (uintptr_t) ctx; 257584Salexander.borisov@nginx.com 258584Salexander.borisov@nginx.com script = rb_str_new((const char *) rack_init->script->start, 259584Salexander.borisov@nginx.com (long) rack_init->script->length); 260584Salexander.borisov@nginx.com 261584Salexander.borisov@nginx.com res = rb_funcall(rack_init->builder, rb_intern("parse_file"), 1, script); 262584Salexander.borisov@nginx.com 263584Salexander.borisov@nginx.com rb_str_free(script); 264584Salexander.borisov@nginx.com 265584Salexander.borisov@nginx.com return res; 266584Salexander.borisov@nginx.com } 267584Salexander.borisov@nginx.com 268584Salexander.borisov@nginx.com 269584Salexander.borisov@nginx.com static VALUE 270584Salexander.borisov@nginx.com nxt_ruby_rack_env_create(VALUE arg) 271584Salexander.borisov@nginx.com { 272584Salexander.borisov@nginx.com VALUE hash_env, version; 273584Salexander.borisov@nginx.com 274584Salexander.borisov@nginx.com hash_env = rb_hash_new(); 275584Salexander.borisov@nginx.com version = rb_ary_new(); 276584Salexander.borisov@nginx.com 277584Salexander.borisov@nginx.com rb_ary_push(version, UINT2NUM(NXT_RUBY_RACK_API_VERSION_MAJOR)); 278584Salexander.borisov@nginx.com rb_ary_push(version, UINT2NUM(NXT_RUBY_RACK_API_VERSION_MINOR)); 279584Salexander.borisov@nginx.com 280584Salexander.borisov@nginx.com rb_hash_aset(hash_env, rb_str_new2("rack.version"), version); 281584Salexander.borisov@nginx.com rb_hash_aset(hash_env, rb_str_new2("rack.url_scheme"), rb_str_new2("http")); 282584Salexander.borisov@nginx.com rb_hash_aset(hash_env, rb_str_new2("rack.input"), nxt_ruby_io_input); 283584Salexander.borisov@nginx.com rb_hash_aset(hash_env, rb_str_new2("rack.errors"), nxt_ruby_io_error); 284584Salexander.borisov@nginx.com rb_hash_aset(hash_env, rb_str_new2("rack.multithread"), Qfalse); 285584Salexander.borisov@nginx.com rb_hash_aset(hash_env, rb_str_new2("rack.multiprocess"), Qtrue); 286584Salexander.borisov@nginx.com rb_hash_aset(hash_env, rb_str_new2("rack.run_once"), Qfalse); 287584Salexander.borisov@nginx.com rb_hash_aset(hash_env, rb_str_new2("rack.hijack?"), Qfalse); 288584Salexander.borisov@nginx.com rb_hash_aset(hash_env, rb_str_new2("rack.hijack"), Qnil); 289584Salexander.borisov@nginx.com rb_hash_aset(hash_env, rb_str_new2("rack.hijack_io"), Qnil); 290584Salexander.borisov@nginx.com 291584Salexander.borisov@nginx.com return hash_env; 292584Salexander.borisov@nginx.com } 293584Salexander.borisov@nginx.com 294584Salexander.borisov@nginx.com 295584Salexander.borisov@nginx.com static nxt_int_t 296584Salexander.borisov@nginx.com nxt_ruby_run(nxt_task_t *task, nxt_app_rmsg_t *rmsg, nxt_app_wmsg_t *wmsg) 297584Salexander.borisov@nginx.com { 298584Salexander.borisov@nginx.com int state; 299584Salexander.borisov@nginx.com VALUE res; 300584Salexander.borisov@nginx.com 301584Salexander.borisov@nginx.com nxt_ruby_run_ctx.task = task; 302584Salexander.borisov@nginx.com nxt_ruby_run_ctx.rmsg = rmsg; 303584Salexander.borisov@nginx.com nxt_ruby_run_ctx.wmsg = wmsg; 304584Salexander.borisov@nginx.com 305584Salexander.borisov@nginx.com res = rb_protect(nxt_ruby_rack_app_run, Qnil, &state); 306584Salexander.borisov@nginx.com if (nxt_slow_path(state != 0)) { 307584Salexander.borisov@nginx.com nxt_ruby_exception_log(nxt_ruby_run_ctx.task, NXT_LOG_ERR, 308584Salexander.borisov@nginx.com "Failed to run ruby script"); 309584Salexander.borisov@nginx.com return NXT_ERROR; 310584Salexander.borisov@nginx.com } 311584Salexander.borisov@nginx.com 312584Salexander.borisov@nginx.com if (nxt_slow_path(res == Qnil)) { 313584Salexander.borisov@nginx.com return NXT_ERROR; 314584Salexander.borisov@nginx.com } 315584Salexander.borisov@nginx.com 316584Salexander.borisov@nginx.com return NXT_OK; 317584Salexander.borisov@nginx.com } 318584Salexander.borisov@nginx.com 319584Salexander.borisov@nginx.com 320584Salexander.borisov@nginx.com static VALUE 321584Salexander.borisov@nginx.com nxt_ruby_rack_app_run(VALUE arg) 322584Salexander.borisov@nginx.com { 323584Salexander.borisov@nginx.com VALUE env, result; 324584Salexander.borisov@nginx.com nxt_int_t rc; 325584Salexander.borisov@nginx.com 326584Salexander.borisov@nginx.com env = rb_hash_dup(nxt_ruby_env); 327584Salexander.borisov@nginx.com 328584Salexander.borisov@nginx.com rc = nxt_ruby_read_request(&nxt_ruby_run_ctx, env); 329584Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 330584Salexander.borisov@nginx.com nxt_alert(nxt_ruby_run_ctx.task, 331584Salexander.borisov@nginx.com "Ruby: Failed to process incoming request"); 332584Salexander.borisov@nginx.com 333584Salexander.borisov@nginx.com goto fail; 334584Salexander.borisov@nginx.com } 335584Salexander.borisov@nginx.com 336584Salexander.borisov@nginx.com result = rb_funcall(nxt_ruby_rackup, nxt_ruby_call, 1, env); 337584Salexander.borisov@nginx.com if (nxt_slow_path(TYPE(result) != T_ARRAY)) { 338584Salexander.borisov@nginx.com nxt_log(nxt_ruby_run_ctx.task, NXT_LOG_ERR, 339584Salexander.borisov@nginx.com "Ruby: Invalid response format from application"); 340584Salexander.borisov@nginx.com 341584Salexander.borisov@nginx.com goto fail; 342584Salexander.borisov@nginx.com } 343584Salexander.borisov@nginx.com 344584Salexander.borisov@nginx.com if (nxt_slow_path(RARRAY_LEN(result) != 3)) { 345584Salexander.borisov@nginx.com nxt_log(nxt_ruby_run_ctx.task, NXT_LOG_ERR, 346584Salexander.borisov@nginx.com "Ruby: Invalid response format from application. " 347584Salexander.borisov@nginx.com "Need 3 entries [Status, Headers, Body]"); 348584Salexander.borisov@nginx.com 349584Salexander.borisov@nginx.com goto fail; 350584Salexander.borisov@nginx.com } 351584Salexander.borisov@nginx.com 352584Salexander.borisov@nginx.com rc = nxt_ruby_rack_result_status(result); 353584Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 354584Salexander.borisov@nginx.com goto fail; 355584Salexander.borisov@nginx.com } 356584Salexander.borisov@nginx.com 357584Salexander.borisov@nginx.com rc = nxt_ruby_rack_result_headers(result); 358584Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 359584Salexander.borisov@nginx.com goto fail; 360584Salexander.borisov@nginx.com } 361584Salexander.borisov@nginx.com 362584Salexander.borisov@nginx.com rc = nxt_ruby_rack_result_body(result); 363584Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 364584Salexander.borisov@nginx.com goto fail; 365584Salexander.borisov@nginx.com } 366584Salexander.borisov@nginx.com 367584Salexander.borisov@nginx.com rc = nxt_app_msg_flush(nxt_ruby_run_ctx.task, nxt_ruby_run_ctx.wmsg, 1); 368584Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 369584Salexander.borisov@nginx.com goto fail; 370584Salexander.borisov@nginx.com } 371584Salexander.borisov@nginx.com 372584Salexander.borisov@nginx.com rb_hash_delete(env, rb_obj_id(env)); 373584Salexander.borisov@nginx.com 374584Salexander.borisov@nginx.com return result; 375584Salexander.borisov@nginx.com 376584Salexander.borisov@nginx.com fail: 377584Salexander.borisov@nginx.com 378584Salexander.borisov@nginx.com rb_hash_delete(env, rb_obj_id(env)); 379584Salexander.borisov@nginx.com 380584Salexander.borisov@nginx.com return Qnil; 381584Salexander.borisov@nginx.com } 382584Salexander.borisov@nginx.com 383584Salexander.borisov@nginx.com 384584Salexander.borisov@nginx.com static nxt_int_t 385584Salexander.borisov@nginx.com nxt_ruby_read_request(nxt_ruby_run_ctx_t *run_ctx, VALUE hash_env) 386584Salexander.borisov@nginx.com { 387584Salexander.borisov@nginx.com u_char *colon; 388584Salexander.borisov@nginx.com size_t query_size; 389584Salexander.borisov@nginx.com nxt_int_t rc; 390584Salexander.borisov@nginx.com nxt_str_t str, value, path, target; 391584Salexander.borisov@nginx.com nxt_str_t host, server_name, server_port; 392584Salexander.borisov@nginx.com nxt_task_t *task; 393584Salexander.borisov@nginx.com nxt_app_rmsg_t *rmsg; 394584Salexander.borisov@nginx.com 395584Salexander.borisov@nginx.com static nxt_str_t def_host = nxt_string("localhost"); 396584Salexander.borisov@nginx.com static nxt_str_t def_port = nxt_string("80"); 397584Salexander.borisov@nginx.com 398584Salexander.borisov@nginx.com task = run_ctx->task; 399584Salexander.borisov@nginx.com rmsg = run_ctx->rmsg; 400584Salexander.borisov@nginx.com 401584Salexander.borisov@nginx.com rc = nxt_ruby_read_add_env(task, rmsg, hash_env, "REQUEST_METHOD", &str); 402584Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 403584Salexander.borisov@nginx.com return NXT_ERROR; 404584Salexander.borisov@nginx.com } 405584Salexander.borisov@nginx.com 406584Salexander.borisov@nginx.com rc = nxt_ruby_read_add_env(task, rmsg, hash_env, "REQUEST_URI", &target); 407584Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 408584Salexander.borisov@nginx.com return NXT_ERROR; 409584Salexander.borisov@nginx.com } 410584Salexander.borisov@nginx.com 411584Salexander.borisov@nginx.com rc = nxt_app_msg_read_str(task, rmsg, &path); 412584Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 413584Salexander.borisov@nginx.com return NXT_ERROR; 414584Salexander.borisov@nginx.com } 415584Salexander.borisov@nginx.com 416584Salexander.borisov@nginx.com rc = nxt_app_msg_read_size(task, rmsg, &query_size); 417584Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 418584Salexander.borisov@nginx.com return NXT_ERROR; 419584Salexander.borisov@nginx.com } 420584Salexander.borisov@nginx.com 421584Salexander.borisov@nginx.com if (path.start == NULL || path.length == 0) { 422584Salexander.borisov@nginx.com path = target; 423584Salexander.borisov@nginx.com } 424584Salexander.borisov@nginx.com 425584Salexander.borisov@nginx.com rb_hash_aset(hash_env, rb_str_new2("PATH_INFO"), 426584Salexander.borisov@nginx.com rb_str_new((const char *) path.start, (long) path.length)); 427584Salexander.borisov@nginx.com 428584Salexander.borisov@nginx.com if (query_size > 0) { 429584Salexander.borisov@nginx.com query_size--; 430584Salexander.borisov@nginx.com 431584Salexander.borisov@nginx.com if (nxt_slow_path(target.length < query_size)) { 432584Salexander.borisov@nginx.com return NXT_ERROR; 433584Salexander.borisov@nginx.com } 434584Salexander.borisov@nginx.com 435584Salexander.borisov@nginx.com str.start = &target.start[query_size]; 436584Salexander.borisov@nginx.com str.length = target.length - query_size; 437584Salexander.borisov@nginx.com 438584Salexander.borisov@nginx.com rb_hash_aset(hash_env, rb_str_new2("QUERY_STRING"), 439584Salexander.borisov@nginx.com rb_str_new((const char *) str.start, (long) str.length)); 440584Salexander.borisov@nginx.com } 441584Salexander.borisov@nginx.com 442584Salexander.borisov@nginx.com rc = nxt_ruby_read_add_env(task, rmsg, hash_env, "SERVER_PROTOCOL", &str); 443584Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 444584Salexander.borisov@nginx.com return NXT_ERROR; 445584Salexander.borisov@nginx.com } 446584Salexander.borisov@nginx.com 447584Salexander.borisov@nginx.com rc = nxt_ruby_read_add_env(task, rmsg, hash_env, "REMOTE_ADDR", &str); 448584Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 449584Salexander.borisov@nginx.com return NXT_ERROR; 450584Salexander.borisov@nginx.com } 451584Salexander.borisov@nginx.com 452584Salexander.borisov@nginx.com rc = nxt_ruby_read_add_env(task, rmsg, hash_env, "SERVER_ADDR", &str); 453584Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 454584Salexander.borisov@nginx.com return NXT_ERROR; 455584Salexander.borisov@nginx.com } 456584Salexander.borisov@nginx.com 457584Salexander.borisov@nginx.com rc = nxt_app_msg_read_str(task, rmsg, &host); 458584Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 459584Salexander.borisov@nginx.com return NXT_ERROR; 460584Salexander.borisov@nginx.com } 461584Salexander.borisov@nginx.com 462584Salexander.borisov@nginx.com if (host.length == 0) { 463584Salexander.borisov@nginx.com host = def_host; 464584Salexander.borisov@nginx.com } 465584Salexander.borisov@nginx.com 466584Salexander.borisov@nginx.com colon = nxt_memchr(host.start, ':', host.length); 467584Salexander.borisov@nginx.com server_name = host; 468584Salexander.borisov@nginx.com 469584Salexander.borisov@nginx.com if (colon != NULL) { 470584Salexander.borisov@nginx.com server_name.length = colon - host.start; 471584Salexander.borisov@nginx.com 472584Salexander.borisov@nginx.com server_port.start = colon + 1; 473584Salexander.borisov@nginx.com server_port.length = host.length - server_name.length - 1; 474584Salexander.borisov@nginx.com 475584Salexander.borisov@nginx.com } else { 476584Salexander.borisov@nginx.com server_port = def_port; 477584Salexander.borisov@nginx.com } 478584Salexander.borisov@nginx.com 479584Salexander.borisov@nginx.com rb_hash_aset(hash_env, rb_str_new2("SERVER_NAME"), 480584Salexander.borisov@nginx.com rb_str_new((const char *) server_name.start, 481584Salexander.borisov@nginx.com (long) server_name.length)); 482584Salexander.borisov@nginx.com 483584Salexander.borisov@nginx.com rb_hash_aset(hash_env, rb_str_new2("SERVER_PORT"), 484584Salexander.borisov@nginx.com rb_str_new((const char *) server_port.start, 485584Salexander.borisov@nginx.com (long) server_port.length)); 486584Salexander.borisov@nginx.com 487584Salexander.borisov@nginx.com rc = nxt_ruby_read_add_env(task, rmsg, hash_env, "CONTENT_TYPE", &str); 488584Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 489584Salexander.borisov@nginx.com return NXT_ERROR; 490584Salexander.borisov@nginx.com } 491584Salexander.borisov@nginx.com 492584Salexander.borisov@nginx.com rc = nxt_ruby_read_add_env(task, rmsg, hash_env, "CONTENT_LENGTH", &str); 493584Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 494584Salexander.borisov@nginx.com return NXT_ERROR; 495584Salexander.borisov@nginx.com } 496584Salexander.borisov@nginx.com 497584Salexander.borisov@nginx.com for ( ;; ) { 498584Salexander.borisov@nginx.com rc = nxt_app_msg_read_str(task, rmsg, &str); 499584Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 500584Salexander.borisov@nginx.com return NXT_ERROR; 501584Salexander.borisov@nginx.com } 502584Salexander.borisov@nginx.com 503584Salexander.borisov@nginx.com if (nxt_slow_path(str.length == 0)) { 504584Salexander.borisov@nginx.com break; 505584Salexander.borisov@nginx.com } 506584Salexander.borisov@nginx.com 507584Salexander.borisov@nginx.com rc = nxt_app_msg_read_str(task, rmsg, &value); 508584Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 509584Salexander.borisov@nginx.com return NXT_ERROR; 510584Salexander.borisov@nginx.com } 511584Salexander.borisov@nginx.com 512584Salexander.borisov@nginx.com rb_hash_aset(hash_env, 513584Salexander.borisov@nginx.com rb_str_new((char *) str.start, (long) str.length), 514584Salexander.borisov@nginx.com rb_str_new((const char *) value.start, 515584Salexander.borisov@nginx.com (long) value.length)); 516584Salexander.borisov@nginx.com } 517584Salexander.borisov@nginx.com 518584Salexander.borisov@nginx.com rc = nxt_app_msg_read_size(task, rmsg, &run_ctx->body_preread_size); 519584Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 520584Salexander.borisov@nginx.com return NXT_ERROR; 521584Salexander.borisov@nginx.com } 522584Salexander.borisov@nginx.com 523584Salexander.borisov@nginx.com return NXT_OK; 524584Salexander.borisov@nginx.com } 525584Salexander.borisov@nginx.com 526584Salexander.borisov@nginx.com 527584Salexander.borisov@nginx.com nxt_inline nxt_int_t 528584Salexander.borisov@nginx.com nxt_ruby_read_add_env(nxt_task_t *task, nxt_app_rmsg_t *rmsg, VALUE hash_env, 529584Salexander.borisov@nginx.com const char *name, nxt_str_t *str) 530584Salexander.borisov@nginx.com { 531584Salexander.borisov@nginx.com nxt_int_t rc; 532584Salexander.borisov@nginx.com 533584Salexander.borisov@nginx.com rc = nxt_app_msg_read_str(task, rmsg, str); 534584Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 535584Salexander.borisov@nginx.com return rc; 536584Salexander.borisov@nginx.com } 537584Salexander.borisov@nginx.com 538584Salexander.borisov@nginx.com if (str->start == NULL) { 539584Salexander.borisov@nginx.com rb_hash_aset(hash_env, rb_str_new2(name), Qnil); 540584Salexander.borisov@nginx.com return NXT_OK; 541584Salexander.borisov@nginx.com } 542584Salexander.borisov@nginx.com 543584Salexander.borisov@nginx.com rb_hash_aset(hash_env, rb_str_new2(name), 544584Salexander.borisov@nginx.com rb_str_new((const char *) str->start, (long) str->length)); 545584Salexander.borisov@nginx.com 546584Salexander.borisov@nginx.com return NXT_OK; 547584Salexander.borisov@nginx.com } 548584Salexander.borisov@nginx.com 549584Salexander.borisov@nginx.com 550584Salexander.borisov@nginx.com static nxt_int_t 551584Salexander.borisov@nginx.com nxt_ruby_rack_result_status(VALUE result) 552584Salexander.borisov@nginx.com { 553584Salexander.borisov@nginx.com VALUE status; 554584Salexander.borisov@nginx.com u_char *p; 555584Salexander.borisov@nginx.com size_t len; 556584Salexander.borisov@nginx.com nxt_int_t rc; 557584Salexander.borisov@nginx.com u_char buf[3]; 558584Salexander.borisov@nginx.com 559584Salexander.borisov@nginx.com status = rb_ary_entry(result, 0); 560584Salexander.borisov@nginx.com 561584Salexander.borisov@nginx.com if (TYPE(status) == T_FIXNUM) { 562584Salexander.borisov@nginx.com nxt_sprintf(buf, buf + 3, "%03d", FIX2INT(status)); 563584Salexander.borisov@nginx.com 564584Salexander.borisov@nginx.com p = buf; 565584Salexander.borisov@nginx.com len = 3; 566584Salexander.borisov@nginx.com 567584Salexander.borisov@nginx.com } else if (TYPE(status) == T_STRING) { 568584Salexander.borisov@nginx.com p = (u_char *) RSTRING_PTR(status); 569584Salexander.borisov@nginx.com len = RSTRING_LEN(status); 570584Salexander.borisov@nginx.com 571584Salexander.borisov@nginx.com } else { 572584Salexander.borisov@nginx.com nxt_log(nxt_ruby_run_ctx.task, NXT_LOG_ERR, 573584Salexander.borisov@nginx.com "Ruby: Invalid response 'status' format from application"); 574584Salexander.borisov@nginx.com 575584Salexander.borisov@nginx.com return NXT_ERROR; 576584Salexander.borisov@nginx.com } 577584Salexander.borisov@nginx.com 578584Salexander.borisov@nginx.com rc = nxt_ruby_write(nxt_ruby_run_ctx.task, nxt_ruby_run_ctx.wmsg, 579584Salexander.borisov@nginx.com (u_char *) "Status: ", (sizeof("Status: ") - 1), 0, 0); 580584Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 581584Salexander.borisov@nginx.com return NXT_ERROR; 582584Salexander.borisov@nginx.com } 583584Salexander.borisov@nginx.com 584584Salexander.borisov@nginx.com rc = nxt_ruby_write(nxt_ruby_run_ctx.task, nxt_ruby_run_ctx.wmsg, 585584Salexander.borisov@nginx.com p, len, 0, 0); 586584Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 587584Salexander.borisov@nginx.com return NXT_ERROR; 588584Salexander.borisov@nginx.com } 589584Salexander.borisov@nginx.com 590584Salexander.borisov@nginx.com rc = nxt_ruby_write(nxt_ruby_run_ctx.task, nxt_ruby_run_ctx.wmsg, 591584Salexander.borisov@nginx.com (u_char *) "\r\n", (sizeof("\r\n") - 1), 0, 0); 592584Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 593584Salexander.borisov@nginx.com return NXT_ERROR; 594584Salexander.borisov@nginx.com } 595584Salexander.borisov@nginx.com 596584Salexander.borisov@nginx.com return NXT_OK; 597584Salexander.borisov@nginx.com } 598584Salexander.borisov@nginx.com 599584Salexander.borisov@nginx.com 600584Salexander.borisov@nginx.com nxt_inline nxt_int_t 601584Salexander.borisov@nginx.com nxt_ruby_write(nxt_task_t *task, nxt_app_wmsg_t *wmsg, 602584Salexander.borisov@nginx.com const u_char *data, size_t len, nxt_bool_t flush, nxt_bool_t last) 603584Salexander.borisov@nginx.com { 604584Salexander.borisov@nginx.com nxt_int_t rc; 605584Salexander.borisov@nginx.com 606584Salexander.borisov@nginx.com rc = nxt_app_msg_write_raw(task, wmsg, data, len); 607584Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 608584Salexander.borisov@nginx.com return rc; 609584Salexander.borisov@nginx.com } 610584Salexander.borisov@nginx.com 611584Salexander.borisov@nginx.com if (flush || last) { 612584Salexander.borisov@nginx.com rc = nxt_app_msg_flush(task, wmsg, last); 613584Salexander.borisov@nginx.com } 614584Salexander.borisov@nginx.com 615584Salexander.borisov@nginx.com return rc; 616584Salexander.borisov@nginx.com } 617584Salexander.borisov@nginx.com 618584Salexander.borisov@nginx.com 619584Salexander.borisov@nginx.com static nxt_int_t 620584Salexander.borisov@nginx.com nxt_ruby_rack_result_headers(VALUE result) 621584Salexander.borisov@nginx.com { 622584Salexander.borisov@nginx.com VALUE headers; 623584Salexander.borisov@nginx.com nxt_int_t rc; 624584Salexander.borisov@nginx.com 625584Salexander.borisov@nginx.com headers = rb_ary_entry(result, 1); 626584Salexander.borisov@nginx.com if (nxt_slow_path(TYPE(headers) != T_HASH)) { 627584Salexander.borisov@nginx.com nxt_log(nxt_ruby_run_ctx.task, NXT_LOG_ERR, 628584Salexander.borisov@nginx.com "Ruby: Invalid response 'headers' format from application"); 629584Salexander.borisov@nginx.com 630584Salexander.borisov@nginx.com return NXT_ERROR; 631584Salexander.borisov@nginx.com } 632584Salexander.borisov@nginx.com 633584Salexander.borisov@nginx.com rc = NXT_OK; 634584Salexander.borisov@nginx.com 635584Salexander.borisov@nginx.com rb_hash_foreach(headers, nxt_ruby_hash_foreach, (VALUE) (uintptr_t) &rc); 636584Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 637584Salexander.borisov@nginx.com return NXT_ERROR; 638584Salexander.borisov@nginx.com } 639584Salexander.borisov@nginx.com 640584Salexander.borisov@nginx.com rc = nxt_ruby_write(nxt_ruby_run_ctx.task, nxt_ruby_run_ctx.wmsg, 641584Salexander.borisov@nginx.com (u_char *) "\r\n", (sizeof("\r\n") - 1), 0, 0); 642584Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 643584Salexander.borisov@nginx.com return NXT_ERROR; 644584Salexander.borisov@nginx.com } 645584Salexander.borisov@nginx.com 646584Salexander.borisov@nginx.com return NXT_OK; 647584Salexander.borisov@nginx.com } 648584Salexander.borisov@nginx.com 649584Salexander.borisov@nginx.com 650584Salexander.borisov@nginx.com static int 651584Salexander.borisov@nginx.com nxt_ruby_hash_foreach(VALUE r_key, VALUE r_value, VALUE arg) 652584Salexander.borisov@nginx.com { 653584Salexander.borisov@nginx.com nxt_int_t rc, *rc_p; 654584Salexander.borisov@nginx.com const char *value, *value_end, *pos; 655584Salexander.borisov@nginx.com 656584Salexander.borisov@nginx.com rc_p = (nxt_int_t *) (uintptr_t) arg; 657584Salexander.borisov@nginx.com 658584Salexander.borisov@nginx.com if (nxt_slow_path(TYPE(r_key) != T_STRING)) { 659584Salexander.borisov@nginx.com nxt_log(nxt_ruby_run_ctx.task, NXT_LOG_ERR, 660584Salexander.borisov@nginx.com "Ruby: Wrong header entry 'key' from application"); 661584Salexander.borisov@nginx.com 662584Salexander.borisov@nginx.com goto fail; 663584Salexander.borisov@nginx.com } 664584Salexander.borisov@nginx.com 665584Salexander.borisov@nginx.com if (nxt_slow_path(TYPE(r_value) != T_STRING)) { 666584Salexander.borisov@nginx.com nxt_log(nxt_ruby_run_ctx.task, NXT_LOG_ERR, 667584Salexander.borisov@nginx.com "Ruby: Wrong header entry 'value' from application"); 668584Salexander.borisov@nginx.com 669584Salexander.borisov@nginx.com goto fail; 670584Salexander.borisov@nginx.com } 671584Salexander.borisov@nginx.com 672584Salexander.borisov@nginx.com value = RSTRING_PTR(r_value); 673584Salexander.borisov@nginx.com value_end = value + RSTRING_LEN(r_value); 674584Salexander.borisov@nginx.com 675584Salexander.borisov@nginx.com pos = value; 676584Salexander.borisov@nginx.com 677584Salexander.borisov@nginx.com for ( ;; ) { 678584Salexander.borisov@nginx.com pos = strchr(pos, '\n'); 679584Salexander.borisov@nginx.com 680584Salexander.borisov@nginx.com if (pos == NULL) { 681584Salexander.borisov@nginx.com break; 682584Salexander.borisov@nginx.com } 683584Salexander.borisov@nginx.com 684584Salexander.borisov@nginx.com rc = nxt_ruby_head_send_part(RSTRING_PTR(r_key), RSTRING_LEN(r_key), 685584Salexander.borisov@nginx.com value, pos - value); 686584Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 687584Salexander.borisov@nginx.com goto fail; 688584Salexander.borisov@nginx.com } 689584Salexander.borisov@nginx.com 690584Salexander.borisov@nginx.com pos++; 691584Salexander.borisov@nginx.com value = pos; 692584Salexander.borisov@nginx.com } 693584Salexander.borisov@nginx.com 694584Salexander.borisov@nginx.com if (value <= value_end) { 695584Salexander.borisov@nginx.com rc = nxt_ruby_head_send_part(RSTRING_PTR(r_key), RSTRING_LEN(r_key), 696584Salexander.borisov@nginx.com value, value_end - value); 697584Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 698584Salexander.borisov@nginx.com goto fail; 699584Salexander.borisov@nginx.com } 700584Salexander.borisov@nginx.com } 701584Salexander.borisov@nginx.com 702584Salexander.borisov@nginx.com *rc_p = NXT_OK; 703584Salexander.borisov@nginx.com 704584Salexander.borisov@nginx.com return ST_CONTINUE; 705584Salexander.borisov@nginx.com 706584Salexander.borisov@nginx.com fail: 707584Salexander.borisov@nginx.com 708584Salexander.borisov@nginx.com *rc_p = NXT_ERROR; 709584Salexander.borisov@nginx.com 710584Salexander.borisov@nginx.com return ST_STOP; 711584Salexander.borisov@nginx.com } 712584Salexander.borisov@nginx.com 713584Salexander.borisov@nginx.com 714584Salexander.borisov@nginx.com static nxt_int_t 715584Salexander.borisov@nginx.com nxt_ruby_head_send_part(const char *key, size_t key_size, 716584Salexander.borisov@nginx.com const char *value, size_t value_size) 717584Salexander.borisov@nginx.com { 718584Salexander.borisov@nginx.com nxt_int_t rc; 719584Salexander.borisov@nginx.com 720584Salexander.borisov@nginx.com rc = nxt_app_msg_write_raw(nxt_ruby_run_ctx.task, nxt_ruby_run_ctx.wmsg, 721584Salexander.borisov@nginx.com (u_char *) key, key_size); 722584Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 723584Salexander.borisov@nginx.com return rc; 724584Salexander.borisov@nginx.com } 725584Salexander.borisov@nginx.com 726584Salexander.borisov@nginx.com rc = nxt_app_msg_write_raw(nxt_ruby_run_ctx.task, nxt_ruby_run_ctx.wmsg, 727584Salexander.borisov@nginx.com (u_char *) ": ", (sizeof(": ") - 1)); 728584Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 729584Salexander.borisov@nginx.com return rc; 730584Salexander.borisov@nginx.com } 731584Salexander.borisov@nginx.com 732584Salexander.borisov@nginx.com rc = nxt_app_msg_write_raw(nxt_ruby_run_ctx.task, nxt_ruby_run_ctx.wmsg, 733584Salexander.borisov@nginx.com (u_char *) value, value_size); 734584Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 735584Salexander.borisov@nginx.com return rc; 736584Salexander.borisov@nginx.com } 737584Salexander.borisov@nginx.com 738584Salexander.borisov@nginx.com return nxt_app_msg_write_raw(nxt_ruby_run_ctx.task, nxt_ruby_run_ctx.wmsg, 739584Salexander.borisov@nginx.com (u_char *) "\r\n", (sizeof("\r\n") - 1)); 740584Salexander.borisov@nginx.com } 741584Salexander.borisov@nginx.com 742584Salexander.borisov@nginx.com 743584Salexander.borisov@nginx.com static nxt_int_t 744584Salexander.borisov@nginx.com nxt_ruby_rack_result_body(VALUE result) 745584Salexander.borisov@nginx.com { 746584Salexander.borisov@nginx.com VALUE fn, body; 747584Salexander.borisov@nginx.com nxt_int_t rc; 748584Salexander.borisov@nginx.com 749584Salexander.borisov@nginx.com body = rb_ary_entry(result, 2); 750584Salexander.borisov@nginx.com 751584Salexander.borisov@nginx.com if (rb_respond_to(body, rb_intern("to_path"))) { 752584Salexander.borisov@nginx.com 753584Salexander.borisov@nginx.com fn = rb_funcall(body, rb_intern("to_path"), 0); 754584Salexander.borisov@nginx.com if (nxt_slow_path(TYPE(fn) != T_STRING)) { 755584Salexander.borisov@nginx.com nxt_log(nxt_ruby_run_ctx.task, NXT_LOG_ERR, 756584Salexander.borisov@nginx.com "Ruby: Failed to get 'body' file path from application"); 757584Salexander.borisov@nginx.com 758584Salexander.borisov@nginx.com return NXT_ERROR; 759584Salexander.borisov@nginx.com } 760584Salexander.borisov@nginx.com 761584Salexander.borisov@nginx.com rc = nxt_ruby_rack_result_body_file_write(fn); 762584Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 763584Salexander.borisov@nginx.com return NXT_ERROR; 764584Salexander.borisov@nginx.com } 765584Salexander.borisov@nginx.com 766584Salexander.borisov@nginx.com } else if (rb_respond_to(body, rb_intern("each"))) { 767584Salexander.borisov@nginx.com rb_iterate(rb_each, body, nxt_ruby_rack_result_body_each, 0); 768584Salexander.borisov@nginx.com 769584Salexander.borisov@nginx.com } else { 770584Salexander.borisov@nginx.com nxt_log(nxt_ruby_run_ctx.task, NXT_LOG_ERR, 771584Salexander.borisov@nginx.com "Ruby: Invalid response 'body' format from application"); 772584Salexander.borisov@nginx.com 773584Salexander.borisov@nginx.com return NXT_ERROR; 774584Salexander.borisov@nginx.com } 775584Salexander.borisov@nginx.com 776584Salexander.borisov@nginx.com if (rb_respond_to(body, rb_intern("close"))) { 777584Salexander.borisov@nginx.com rb_funcall(body, rb_intern("close"), 0); 778584Salexander.borisov@nginx.com } 779584Salexander.borisov@nginx.com 780584Salexander.borisov@nginx.com return NXT_OK; 781584Salexander.borisov@nginx.com } 782584Salexander.borisov@nginx.com 783584Salexander.borisov@nginx.com 784584Salexander.borisov@nginx.com static nxt_int_t 785584Salexander.borisov@nginx.com nxt_ruby_rack_result_body_file_write(VALUE filepath) 786584Salexander.borisov@nginx.com { 787584Salexander.borisov@nginx.com size_t len; 788584Salexander.borisov@nginx.com ssize_t n; 789584Salexander.borisov@nginx.com nxt_off_t rest; 790584Salexander.borisov@nginx.com nxt_int_t rc; 791584Salexander.borisov@nginx.com nxt_file_t file; 792584Salexander.borisov@nginx.com nxt_file_info_t finfo; 793584Salexander.borisov@nginx.com u_char buf[8192]; 794584Salexander.borisov@nginx.com 795584Salexander.borisov@nginx.com nxt_memzero(&file, sizeof(nxt_file_t)); 796584Salexander.borisov@nginx.com 797584Salexander.borisov@nginx.com file.name = (nxt_file_name_t *) RSTRING_PTR(filepath); 798584Salexander.borisov@nginx.com 799584Salexander.borisov@nginx.com rc = nxt_file_open(nxt_ruby_run_ctx.task, &file, NXT_FILE_RDONLY, 800584Salexander.borisov@nginx.com NXT_FILE_OPEN, 0); 801584Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 802584Salexander.borisov@nginx.com nxt_log(nxt_ruby_run_ctx.task, NXT_LOG_ERR, 803584Salexander.borisov@nginx.com "Ruby: Failed to open 'body' file: %s", 804584Salexander.borisov@nginx.com (const char *) file.name); 805584Salexander.borisov@nginx.com 806584Salexander.borisov@nginx.com return NXT_ERROR; 807584Salexander.borisov@nginx.com } 808584Salexander.borisov@nginx.com 809584Salexander.borisov@nginx.com rc = nxt_file_info(&file, &finfo); 810584Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 811584Salexander.borisov@nginx.com nxt_log(nxt_ruby_run_ctx.task, NXT_LOG_ERR, 812584Salexander.borisov@nginx.com "Ruby: Failed to get 'body' file information: %s", 813584Salexander.borisov@nginx.com (const char *) file.name); 814584Salexander.borisov@nginx.com 815584Salexander.borisov@nginx.com goto fail; 816584Salexander.borisov@nginx.com } 817584Salexander.borisov@nginx.com 818584Salexander.borisov@nginx.com rest = nxt_file_size(&finfo); 819584Salexander.borisov@nginx.com 820584Salexander.borisov@nginx.com while (rest != 0) { 821584Salexander.borisov@nginx.com len = nxt_min(rest, (nxt_off_t) sizeof(buf)); 822584Salexander.borisov@nginx.com 823584Salexander.borisov@nginx.com n = nxt_file_read(&file, buf, len, nxt_file_size(&finfo) - rest); 824584Salexander.borisov@nginx.com if (nxt_slow_path(n != (ssize_t) len)) { 825584Salexander.borisov@nginx.com nxt_log(nxt_ruby_run_ctx.task, NXT_LOG_ERR, 826584Salexander.borisov@nginx.com "Ruby: Failed to read 'body' file"); 827584Salexander.borisov@nginx.com 828584Salexander.borisov@nginx.com goto fail; 829584Salexander.borisov@nginx.com } 830584Salexander.borisov@nginx.com 831584Salexander.borisov@nginx.com rest -= len; 832584Salexander.borisov@nginx.com 833584Salexander.borisov@nginx.com rc = nxt_app_msg_write_raw(nxt_ruby_run_ctx.task, nxt_ruby_run_ctx.wmsg, 834584Salexander.borisov@nginx.com buf, len); 835584Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 836584Salexander.borisov@nginx.com nxt_log(nxt_ruby_run_ctx.task, NXT_LOG_ERR, 837584Salexander.borisov@nginx.com "Ruby: Failed to write 'body' from application"); 838584Salexander.borisov@nginx.com 839584Salexander.borisov@nginx.com goto fail; 840584Salexander.borisov@nginx.com } 841584Salexander.borisov@nginx.com } 842584Salexander.borisov@nginx.com 843584Salexander.borisov@nginx.com nxt_file_close(nxt_ruby_run_ctx.task, &file); 844584Salexander.borisov@nginx.com 845584Salexander.borisov@nginx.com return NXT_OK; 846584Salexander.borisov@nginx.com 847584Salexander.borisov@nginx.com fail: 848584Salexander.borisov@nginx.com 849584Salexander.borisov@nginx.com nxt_file_close(nxt_ruby_run_ctx.task, &file); 850584Salexander.borisov@nginx.com 851584Salexander.borisov@nginx.com return NXT_ERROR; 852584Salexander.borisov@nginx.com } 853584Salexander.borisov@nginx.com 854584Salexander.borisov@nginx.com 855584Salexander.borisov@nginx.com static VALUE 856584Salexander.borisov@nginx.com nxt_ruby_rack_result_body_each(VALUE body) 857584Salexander.borisov@nginx.com { 858584Salexander.borisov@nginx.com nxt_int_t rc; 859584Salexander.borisov@nginx.com 860584Salexander.borisov@nginx.com if (TYPE(body) != T_STRING) { 861584Salexander.borisov@nginx.com return Qnil; 862584Salexander.borisov@nginx.com } 863584Salexander.borisov@nginx.com 864584Salexander.borisov@nginx.com rc = nxt_app_msg_write_raw(nxt_ruby_run_ctx.task, nxt_ruby_run_ctx.wmsg, 865584Salexander.borisov@nginx.com (u_char *) RSTRING_PTR(body), RSTRING_LEN(body)); 866584Salexander.borisov@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 867584Salexander.borisov@nginx.com nxt_log(nxt_ruby_run_ctx.task, NXT_LOG_ERR, 868584Salexander.borisov@nginx.com "Ruby: Failed to write 'body' from application"); 869584Salexander.borisov@nginx.com } 870584Salexander.borisov@nginx.com 871584Salexander.borisov@nginx.com return Qnil; 872584Salexander.borisov@nginx.com } 873584Salexander.borisov@nginx.com 874584Salexander.borisov@nginx.com 875584Salexander.borisov@nginx.com static void 876584Salexander.borisov@nginx.com nxt_ruby_exception_log(nxt_task_t *task, uint32_t level, const char *desc) 877584Salexander.borisov@nginx.com { 878584Salexander.borisov@nginx.com int i; 879584Salexander.borisov@nginx.com VALUE err, ary, eclass, msg; 880584Salexander.borisov@nginx.com 881584Salexander.borisov@nginx.com nxt_log(task, level, "Ruby: %s", desc); 882584Salexander.borisov@nginx.com 883584Salexander.borisov@nginx.com err = rb_errinfo(); 884584Salexander.borisov@nginx.com ary = rb_funcall(err, rb_intern("backtrace"), 0); 885584Salexander.borisov@nginx.com 886584Salexander.borisov@nginx.com if (RARRAY_LEN(ary) == 0) { 887584Salexander.borisov@nginx.com return; 888584Salexander.borisov@nginx.com } 889584Salexander.borisov@nginx.com 890584Salexander.borisov@nginx.com eclass = rb_class_name(rb_class_of(err)); 891584Salexander.borisov@nginx.com msg = rb_funcall(err, rb_intern("message"), 0); 892584Salexander.borisov@nginx.com 893584Salexander.borisov@nginx.com nxt_log(task, level, "Ruby: %s: %s (%s)", 894584Salexander.borisov@nginx.com RSTRING_PTR(RARRAY_PTR(ary)[0]), 895584Salexander.borisov@nginx.com RSTRING_PTR(msg), RSTRING_PTR(eclass)); 896584Salexander.borisov@nginx.com 897584Salexander.borisov@nginx.com for (i = 1; i < RARRAY_LEN(ary); i++) { 898584Salexander.borisov@nginx.com nxt_log(task, level, "from %s", RSTRING_PTR(RARRAY_PTR(ary)[i])); 899584Salexander.borisov@nginx.com } 900584Salexander.borisov@nginx.com } 901584Salexander.borisov@nginx.com 902584Salexander.borisov@nginx.com 903584Salexander.borisov@nginx.com static void 904584Salexander.borisov@nginx.com nxt_ruby_atexit(nxt_task_t *task) 905584Salexander.borisov@nginx.com { 906584Salexander.borisov@nginx.com rb_gc_unregister_address(&nxt_ruby_io_input); 907584Salexander.borisov@nginx.com rb_gc_unregister_address(&nxt_ruby_io_error); 908584Salexander.borisov@nginx.com 909584Salexander.borisov@nginx.com rb_gc_unregister_address(&nxt_ruby_rackup); 910584Salexander.borisov@nginx.com rb_gc_unregister_address(&nxt_ruby_call); 911584Salexander.borisov@nginx.com rb_gc_unregister_address(&nxt_ruby_env); 912584Salexander.borisov@nginx.com 913584Salexander.borisov@nginx.com ruby_cleanup(0); 914584Salexander.borisov@nginx.com } 915