Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

I can not proxy when using Async.sleep #354

Merged
merged 5 commits into from May 12, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
63 changes: 37 additions & 26 deletions src/http/ngx_http_mruby_async.c
Expand Up @@ -17,8 +17,6 @@
#include <mruby/proc.h>
#include <mruby/error.h>

#define ngx_mrb_resume_fiber(mrb, fiber) ngx_mrb_run_fiber(mrb, fiber, NULL)

typedef struct {
mrb_state *mrb;
mrb_value *fiber;
Expand Down Expand Up @@ -49,6 +47,13 @@ mrb_value ngx_mrb_start_fiber(ngx_http_request_t *r, mrb_state *mrb, struct RPro
{
mrb_value handler_proc;
mrb_value *fiber_proc;
ngx_http_mruby_ctx_t *ctx;

ctx = ngx_http_get_module_ctx(r, ngx_http_mruby_module);
if (ctx == NULL) {
mrb_raise(mrb, E_RUNTIME_ERROR, "ngx_http_get_module_ctx failed");
}
ctx->async_handler_result = result;

replace_stop(rproc->body.irep);
handler_proc = mrb_obj_value(mrb_proc_new(mrb, rproc->body.irep));
Expand Down Expand Up @@ -83,8 +88,8 @@ mrb_value ngx_mrb_run_fiber(mrb_state *mrb, mrb_value *fiber_proc, mrb_value *re
}
aliving = mrb_ary_entry(resume_result, 0);
handler_result = mrb_ary_entry(resume_result, 1);
// result called timer_handler is NULL via ngx_mrb_resume_fiber
if (result) {

if (!mrb_test(aliving)) {
*result = handler_result;
}

Expand All @@ -98,42 +103,48 @@ static void ngx_mrb_timer_handler(ngx_event_t *ev)
ngx_int_t rc = NGX_OK;

re = ev->data;
ctx = ngx_http_get_module_ctx(re->r, ngx_http_mruby_module);

if (re->fiber != NULL) {
ngx_mrb_push_request(re->r);
if (ctx != NULL) {
if (re->fiber != NULL) {
ngx_mrb_push_request(re->r);

if (mrb_test(ngx_mrb_resume_fiber(re->mrb, re->fiber))) {
// can resume the fiber and wait the epoll timer
return;
} else {
// can not resume the fiber, the fiber was finished
mrb_gc_unregister(re->mrb, *re->fiber);
re->fiber = NULL;
}
if (mrb_test(ngx_mrb_run_fiber(re->mrb, re->fiber, ctx->async_handler_result))) {
// can resume the fiber and wait the epoll timer
return;
} else {
// can not resume the fiber, the fiber was finished
mrb_gc_unregister(re->mrb, *re->fiber);
re->fiber = NULL;
}

ngx_http_run_posted_requests(re->r->connection);

ngx_http_run_posted_requests(re->r->connection);
if (re->mrb->exc) {
ngx_mrb_raise_error(re->mrb, mrb_obj_value(re->mrb->exc), re->r);
rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
}

if (re->mrb->exc) {
ngx_mrb_raise_error(re->mrb, mrb_obj_value(re->mrb->exc), re->r);
} else {
ngx_log_error(NGX_LOG_NOTICE, re->r->connection->log, 0,
"%s NOTICE %s:%d: unexpected error, fiber missing" MODULE_NAME, __func__, __LINE__);
rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
}

} else {
ngx_log_error(NGX_LOG_NOTICE, re->r->connection->log, 0,
"%s NOTICE %s:%d: unexpected error, fiber missing" MODULE_NAME, __func__, __LINE__);
rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
}

ctx = ngx_http_get_module_ctx(re->r, ngx_http_mruby_module);
if (ctx != NULL) {
if (rc != NGX_OK) {
re->r->headers_out.status = NGX_HTTP_INTERNAL_SERVER_ERROR;
}

rc = ngx_mrb_finalize_rputs(re->r, ctx);
} else {
rc = NGX_ERROR;
}

if (rc == NGX_DECLINED) {
re->r->phase_handler++;
ngx_http_core_run_phases(re->r);
return;
}
ngx_http_finalize_request(re->r, rc);
}

Expand Down Expand Up @@ -163,7 +174,7 @@ static mrb_value ngx_mrb_async_sleep(mrb_state *mrb, mrb_value self)
}

// suspend the Ruby handler on Nginx::Async.sleep
// resume the Ruby handler on ngx_mrb_resume_fiber() on ngx_mrb_timer_handler()
// resume the Ruby handler on on ngx_mrb_timer_handler()
mrb_fiber_yield(mrb, 0, NULL);

r = ngx_mrb_get_request();
Expand Down
5 changes: 3 additions & 2 deletions src/http/ngx_http_mruby_core.c
Expand Up @@ -144,8 +144,9 @@ static mrb_value ngx_mrb_send_header(mrb_state *mrb, mrb_value self)
if (r->headers_out.status == NGX_HTTP_OK) {
if (chain == NULL) {
r->headers_out.status = NGX_HTTP_INTERNAL_SERVER_ERROR;
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "%s ERROR %s: status code is 200, but response body is empty."
" return NGX_HTTP_INTERNAL_SERVER_ERROR",
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"%s ERROR %s: status code is 200, but response body is empty."
" return NGX_HTTP_INTERNAL_SERVER_ERROR",
MODULE_NAME, __func__);
}
}
Expand Down
1 change: 1 addition & 0 deletions src/http/ngx_http_mruby_core.h
Expand Up @@ -30,6 +30,7 @@ typedef struct ngx_http_mruby_ctx_t {
unsigned request_body_more : 1;
unsigned read_request_body_done : 1;
ngx_uint_t phase;
mrb_value *async_handler_result;
} ngx_http_mruby_ctx_t;

void ngx_mrb_raise_error(mrb_state *mrb, mrb_value obj, ngx_http_request_t *r);
Expand Down
21 changes: 13 additions & 8 deletions src/http/ngx_http_mruby_module.c
Expand Up @@ -434,7 +434,8 @@ static char *ngx_http_mruby_merge_srv_conf(ngx_conf_t *cf, void *parent, void *c
#if OPENSSL_VERSION_NUMBER >= 0x1000205fL
SSL_CTX_set_cert_cb(sscf->ssl.ctx, ngx_http_mruby_ssl_cert_handler, NULL);
#else
ngx_log_error(NGX_LOG_EMERG, cf->log, 0, MODULE_NAME
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
MODULE_NAME
" : mruby_ssl_handshake_handler : OpenSSL 1.0.2e or later required but found " OPENSSL_VERSION_TEXT);
return NGX_CONF_ERROR;
#endif
Expand Down Expand Up @@ -636,13 +637,15 @@ static ngx_int_t ngx_http_mruby_handler_init(ngx_http_core_main_conf_t *cmcf)
ngx_http_phases phases[] = {
NGX_HTTP_POST_READ_PHASE,
// NGX_HTTP_FIND_CONFIG_PHASE,
NGX_HTTP_SERVER_REWRITE_PHASE, NGX_HTTP_REWRITE_PHASE,
NGX_HTTP_SERVER_REWRITE_PHASE,
NGX_HTTP_REWRITE_PHASE,
// NGX_HTTP_POST_REWRITE_PHASE,
// NGX_HTTP_PREACCESS_PHASE,
NGX_HTTP_ACCESS_PHASE,
// NGX_HTTP_POST_ACCESS_PHASE,
// NGX_HTTP_TRY_FILES_PHASE,
NGX_HTTP_CONTENT_PHASE, NGX_HTTP_LOG_PHASE,
NGX_HTTP_CONTENT_PHASE,
NGX_HTTP_LOG_PHASE,
};
ngx_int_t phases_c;

Expand Down Expand Up @@ -1018,8 +1021,9 @@ static ngx_int_t ngx_http_mruby_shared_state_compile(ngx_conf_t *cf, ngx_mrb_sta
ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0, "%s NOTICE %s:%d: compile info: code->code.file=(%s) code->cache=(%d)",
MODULE_NAME, __func__, __LINE__, code->code.file, code->cache);
} else {
ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0, "%s NOTICE %s:%d: compile info: "
"code->code.string=(%s) code->cache=(%d)",
ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0,
"%s NOTICE %s:%d: compile info: "
"code->code.string=(%s) code->cache=(%d)",
MODULE_NAME, __func__, __LINE__, code->code.string, code->cache);
}

Expand Down Expand Up @@ -1186,9 +1190,10 @@ static char *ngx_http_mruby_exit_worker_inline(ngx_conf_t *cf, ngx_command_t *cm

static char *ngx_http_mruby_output_filter_error(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "mruby_output_filter{,_code} was deleted from v1.17.2, you should use "
"mruby_output_body_filter{,_code} for response body, or use "
"mruby_output_header_filter{,_code} for response headers.");
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"mruby_output_filter{,_code} was deleted from v1.17.2, you should use "
"mruby_output_body_filter{,_code} for response body, or use "
"mruby_output_header_filter{,_code} for response headers.");
return NGX_CONF_ERROR;
}

Expand Down
12 changes: 7 additions & 5 deletions src/http/ngx_http_mruby_request.c
Expand Up @@ -122,8 +122,9 @@ static mrb_value ngx_mrb_read_request_body(mrb_state *mrb, mrb_value self)
ngx_http_request_t *r = ngx_mrb_get_request();

if (r->method != NGX_HTTP_POST && r->method != NGX_HTTP_PUT) {
mrb_raise(mrb, E_RUNTIME_ERROR, "ngx_mrb_read_request_body can't read"
" when r->method is neither POST nor PUT");
mrb_raise(mrb, E_RUNTIME_ERROR,
"ngx_mrb_read_request_body can't read"
" when r->method is neither POST nor PUT");
}

return self;
Expand All @@ -135,8 +136,9 @@ static mrb_value ngx_mrb_get_request_body(mrb_state *mrb, mrb_value self)
ngx_http_request_t *r = ngx_mrb_get_request();

if (r->method != NGX_HTTP_POST && r->method != NGX_HTTP_PUT) {
mrb_raise(mrb, E_RUNTIME_ERROR, "ngx_mrb_read_request_body can't read"
" when r->method is neither POST nor PUT");
mrb_raise(mrb, E_RUNTIME_ERROR,
"ngx_mrb_read_request_body can't read"
" when r->method is neither POST nor PUT");
}

return mrb_funcall(mrb, v, "request_body", 0, NULL);
Expand Down Expand Up @@ -266,7 +268,7 @@ static ngx_int_t ngx_mrb_set_request_header(mrb_state *mrb, ngx_list_t *headers,
r->headers_out.server->value.len = val_len;
break;

// TODO: Add other built-in headers
// TODO: Add other built-in headers

default:
break;
Expand Down
3 changes: 2 additions & 1 deletion src/http/ngx_http_mruby_upstream.c
Expand Up @@ -34,7 +34,8 @@ static void ngx_mrb_upstream_context_free(mrb_state *mrb, void *p)
}

static const struct mrb_data_type ngx_mrb_upstream_context_type = {
"ngx_mrb_upstream_context", ngx_mrb_upstream_context_free,
"ngx_mrb_upstream_context",
ngx_mrb_upstream_context_free,
};

static mrb_value ngx_mrb_upstream_init(mrb_state *mrb, mrb_value self)
Expand Down
3 changes: 2 additions & 1 deletion src/stream/ngx_stream_mruby_connection.c
Expand Up @@ -31,7 +31,8 @@ static void ngx_stream_mrb_upstream_context_free(mrb_state *mrb, void *p)
}

static const struct mrb_data_type ngx_stream_mrb_upstream_context_type = {
"ngx_stream_mrb_upstream_context", ngx_stream_mrb_upstream_context_free,
"ngx_stream_mrb_upstream_context",
ngx_stream_mrb_upstream_context_free,
};

static mrb_value ngx_stream_mrb_connection_init(mrb_state *mrb, mrb_value self)
Expand Down
5 changes: 3 additions & 2 deletions src/stream/ngx_stream_mruby_module.c
Expand Up @@ -401,8 +401,9 @@ static ngx_int_t ngx_stream_mruby_shared_state_compile(ngx_conf_t *cf, mrb_state
ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0, "%s NOTICE %s:%d: compile info: code->code.file=(%s)", MODULE_NAME,
__func__, __LINE__, code->code.file);
} else {
ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0, "%s NOTICE %s:%d: compile info: "
"code->code.string=(%s)",
ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0,
"%s NOTICE %s:%d: compile info: "
"code->code.string=(%s)",
MODULE_NAME, __func__, __LINE__, code->code.string);
}

Expand Down
15 changes: 15 additions & 0 deletions test/conf/nginx.conf
Expand Up @@ -812,6 +812,21 @@ http {
Nginx.rputs "foo"
';
}

location /sleep_with_proxy {
mruby_rewrite_handler_code '
Nginx::Async.sleep 3000
u = Nginx::Upstream.new "mruby_upstream"
u.server = "127.0.0.1:58081"
';
proxy_pass http://mruby_upstream/;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_send_timeout 2s;
proxy_read_timeout 2s;
proxy_connect_timeout 2s;
}

location /alias_return {
mruby_rewrite_handler_code '
Nginx.status_code = 204
Expand Down
6 changes: 6 additions & 0 deletions test/t/ngx_mruby.rb
Expand Up @@ -655,6 +655,12 @@ def is_async_supported?
t.assert_equal 'hoge', res["body"]
t.assert_equal 200, res.code
end

t.assert('ngx_mruby - Nginx.Async.sleep with proxy', 'location /sleep_with_proxy') do
res = HttpRequest.new.get base + '/sleep_with_proxy'
t.assert_equal 'proxy test ok', res["body"]
t.assert_equal 200, res.code
end
end


Expand Down