From f6227ca7e574a7cfaac95727cb97728957d20410 Mon Sep 17 00:00:00 2001 From: Thibault Charbonnier Date: Sat, 10 Apr 2021 00:14:29 -0700 Subject: [PATCH] feat(*) on_http_response_headers + runloop refactor --- src/common/proxy_wasm/ngx_proxy_wasm.c | 4 +- src/common/proxy_wasm/ngx_proxy_wasm.h | 12 +- src/common/proxy_wasm/ngx_proxy_wasm_host.c | 113 ++----- src/http/ngx_http_wasm.h | 30 +- src/http/ngx_http_wasm_host.c | 76 ++--- src/http/ngx_http_wasm_module.c | 121 ++++++-- src/http/ngx_http_wasm_util.c | 275 +++++++++++++----- src/http/proxy_wasm/ngx_http_proxy_wasm.c | 52 ++-- src/wasm/ngx_wasm.h | 3 +- src/wasm/ngx_wasm_ops.c | 99 +++---- src/wasm/ngx_wasm_ops.h | 4 +- src/wasm/ngx_wasm_util.c | 34 ++- src/wasm/vm/ngx_wavm.c | 12 +- src/wasm/vm/ngx_wavm_host.c | 4 +- t/02-http/001-wasm_call_directive.t | 2 +- t/03-proxy_wasm/001-proxy_wasm_directive.t | 12 +- t/03-proxy_wasm/002-on_tick.t | 8 +- t/03-proxy_wasm/003-on_http_phases.t | 141 ++++++++- .../102-proxy_send_http_response.t | 1 - t/TestWasm.pm | 3 +- .../proxy-wasm/hostcalls/src/lib.rs | 4 +- 21 files changed, 642 insertions(+), 368 deletions(-) diff --git a/src/common/proxy_wasm/ngx_proxy_wasm.c b/src/common/proxy_wasm/ngx_proxy_wasm.c index fdfc1688b..6722b85dd 100644 --- a/src/common/proxy_wasm/ngx_proxy_wasm.c +++ b/src/common/proxy_wasm/ngx_proxy_wasm.c @@ -18,7 +18,7 @@ ngx_proxy_wasm_func_lookup(ngx_proxy_wasm_t *pwm, const char *n) } -static ngx_proxy_wasm_abi_version_t +static ngx_proxy_wasm_abi_version_e ngx_proxy_wasm_abi_version(ngx_proxy_wasm_t *pwm) { size_t i; @@ -89,7 +89,7 @@ ngx_proxy_wasm_init(ngx_proxy_wasm_t *pwm) case NGX_PROXY_WASM_UNKNOWN: pwm->ecode = NGX_PROXY_WASM_ERR_UNKNOWN_ABI; - ngx_proxy_wasm_log_error(NGX_LOG_EMERG, pwm->log, pwm->ecode, NULL); + ngx_proxy_wasm_log_error(NGX_LOG_WASM_NYI, pwm->log, pwm->ecode, NULL); return NGX_ERROR; default: diff --git a/src/common/proxy_wasm/ngx_proxy_wasm.h b/src/common/proxy_wasm/ngx_proxy_wasm.h index 37dfa4b6f..b583dd23b 100644 --- a/src/common/proxy_wasm/ngx_proxy_wasm.h +++ b/src/common/proxy_wasm/ngx_proxy_wasm.h @@ -24,7 +24,7 @@ typedef enum { NGX_PROXY_WASM_0_2_1 = 2, NGX_PROXY_WASM_VNEXT = 3, NGX_PROXY_WASM_UNKNOWN = 4, -} ngx_proxy_wasm_abi_version_t; +} ngx_proxy_wasm_abi_version_e; typedef enum { @@ -133,9 +133,6 @@ struct ngx_proxy_wasm_s { ngx_log_t *log; ngx_wavm_module_t *module; ngx_wavm_linked_module_t *lmodule; - ngx_wavm_instance_t *instance; - ngx_wavm_ctx_t wvctx; - ngx_proxy_wasm_abi_version_t abi_version; /* dyn config */ @@ -155,6 +152,10 @@ struct ngx_proxy_wasm_s { * - tested: 0.1.0 */ + ngx_wavm_ctx_t wvctx; + ngx_wavm_instance_t *instance; + ngx_proxy_wasm_abi_version_e abi_version; + ngx_wavm_funcref_t *proxy_on_memory_allocate; /* context */ @@ -213,6 +214,9 @@ struct ngx_proxy_wasm_s { ngx_wavm_funcref_t *proxy_on_custom_callback; + /* control flow: flags */ + + unsigned trap:1; }; diff --git a/src/common/proxy_wasm/ngx_proxy_wasm_host.c b/src/common/proxy_wasm/ngx_proxy_wasm_host.c index 346c48963..256a5f7bf 100644 --- a/src/common/proxy_wasm/ngx_proxy_wasm_host.c +++ b/src/common/proxy_wasm/ngx_proxy_wasm_host.c @@ -27,7 +27,7 @@ ngx_proxy_wasm_get_map(ngx_wavm_instance_t *instance, return &r->headers_in.headers; default: - ngx_wasm_log_error(NGX_LOG_ALERT, instance->log, 0, + ngx_wasm_log_error(NGX_LOG_WASM_NYI, instance->log, 0, "NYI - get_map: %d", map_type); return NULL; @@ -135,7 +135,7 @@ ngx_proxy_wasm_hfuncs_proxy_log(ngx_wavm_instance_t *instance, break; default: - ngx_wasm_log_error(NGX_LOG_ALERT, instance->log, 0, + ngx_wasm_log_error(NGX_LOG_WASM_NYI, instance->log, 0, "NYI: unknown log level \"%d\"", log_level); return ngx_proxy_wasm_result_badarg(rets); @@ -274,24 +274,16 @@ static ngx_int_t ngx_proxy_wasm_hfuncs_send_http_response(ngx_wavm_instance_t *instance, wasm_val_t args[], wasm_val_t rets[]) { - size_t i; - int32_t status, reason_len, body_len, headers_len + int32_t status, reason_len, body_len, headers_len #if (NGX_DEBUG) - , grpc_status + , grpc_status #endif - ; - u_char *reason, *body, *marsh_headers, *p; - ngx_http_wasm_req_ctx_t *rctx = instance->ctx->data; - ngx_http_request_t *r = rctx->r; - ngx_int_t rc; - ngx_array_t *headers; - ngx_table_elt_t *elt; - ngx_buf_t *b; - ngx_chain_t *cl = NULL; - - if (r->connection->fd == NGX_WASM_BAD_FD || rctx->sent_last) { - return NGX_WAVM_BAD_CTX; - } + ; + u_char *reason, *body, *marsh_headers; + ngx_int_t rc; + ngx_array_t *headers = NULL; + ngx_http_wasm_req_ctx_t *rctx = instance->ctx->data; + ngx_http_request_t *r = rctx->r; status = args[0].of.i32; reason = ngx_wavm_memory_lift(instance->memory, args[1].of.i32); @@ -306,90 +298,39 @@ ngx_proxy_wasm_hfuncs_send_http_response(ngx_wavm_instance_t *instance, ngx_wasm_assert(grpc_status == -1); #endif - /* status */ - - if (status < 100 || status > 999) { - return ngx_proxy_wasm_result_badarg(rets); - } - - r->headers_out.status = status; - - if (r->err_status) { - r->err_status = 0; - } - - /* reason */ - - if (reason_len) { - reason_len += 5; /* "ddd \0" */ - p = ngx_palloc(r->pool, reason_len); - ngx_snprintf(p, reason_len, "%03ui %s", status, reason); - - r->headers_out.status_line.data = p; - r->headers_out.status_line.len = reason_len - 1; - } - - /* headers */ - if (headers_len) { - /* free (ngx_array_destroy): r->pool */ headers = ngx_proxy_wasm_pairs_unmarshal(r->pool, marsh_headers, headers_len); if (headers == NULL) { return ngx_proxy_wasm_result_err(rets); } - - for (i = 0; i < headers->nelts; i++) { - elt = &((ngx_table_elt_t *) headers->elts)[i]; - - rc = ngx_http_wasm_set_resp_header(r, elt->key, elt->value, 1); - if (rc != NGX_OK) { - return ngx_proxy_wasm_result_err(rets); - } - } } - /* body */ - - if (body_len) { - b = ngx_create_temp_buf(r->pool, body_len + sizeof(LF)); - if (b == NULL) { - return ngx_proxy_wasm_result_err(rets); - } + rc = ngx_http_wasm_stash_local_response(rctx, status, reason, reason_len, + headers, body, body_len); + switch (rc) { - b->last = ngx_copy(b->last, body, body_len); - //*b->last++ = LF; + case NGX_OK: + return ngx_proxy_wasm_result_ok(rets); - b->last_buf = 1; - b->last_in_chain = 1; - - cl = ngx_alloc_chain_link(r->connection->pool); - if (cl == NULL) { - return ngx_proxy_wasm_result_err(rets); - } + case NGX_ERROR: + return ngx_proxy_wasm_result_err(rets); - cl->buf = b; - cl->next = NULL; + case NGX_DECLINED: + return ngx_proxy_wasm_result_badarg(rets); - if (ngx_http_wasm_set_resp_content_length(r, body_len) != NGX_OK) { - return ngx_proxy_wasm_result_err(rets); - } - } + case NGX_ABORT: + return NGX_WAVM_BAD_USAGE; - rc = ngx_http_wasm_send_chain_link(r, cl); - if (rc == NGX_ERROR) { - return NGX_WAVM_ERROR; + default: + break; - } else if (rc == NGX_AGAIN) { - /* TODO: NYI - NGX_WAVM_AGAIN */ - return NGX_AGAIN; } - /* NGX_OK */ + /* unreachable */ - rctx->sent_last = 1; - - return ngx_proxy_wasm_result_ok(rets); + ngx_wasm_assert(0); + return NGX_WAVM_BUSY; } @@ -397,7 +338,7 @@ static ngx_int_t ngx_proxy_wasm_hfuncs_nop(ngx_wavm_instance_t *instance, wasm_val_t args[], wasm_val_t rets[]) { - ngx_wasm_log_error(NGX_LOG_ALERT, instance->log, 0, + ngx_wasm_log_error(NGX_LOG_WASM_NYI, instance->log, 0, "NYI: proxy_wasm hfunc"); return NGX_WAVM_BUSY; /* NYI */ diff --git a/src/http/ngx_http_wasm.h b/src/http/ngx_http_wasm.h index 8cd606c6f..639535bc5 100644 --- a/src/http/ngx_http_wasm.h +++ b/src/http/ngx_http_wasm.h @@ -26,23 +26,45 @@ typedef struct { /* control flow */ + ngx_http_handler_pt r_content_handler; + + ngx_int_t local_resp_status; + ngx_str_t local_resp_reason; + ngx_array_t *local_resp_headers; + ngx_chain_t *local_resp_body; + size_t local_resp_body_len; + unsigned local_resp:1; unsigned sent_last:1; unsigned finalized:1; } ngx_http_wasm_req_ctx_t; -void ngx_http_wasm_header_filter_init(void); +/* ops */ +ngx_int_t ngx_http_wasm_stash_local_response(ngx_http_wasm_req_ctx_t *rctx, + ngx_int_t status, u_char *reason, size_t reason_len, ngx_array_t *headers, + u_char *body, size_t body_len); +ngx_int_t ngx_http_wasm_flush_local_response(ngx_http_request_t *r, + ngx_http_wasm_req_ctx_t *rctx); -ngx_uint_t ngx_http_wasm_req_headers_count(ngx_http_request_t *r); -ngx_int_t ngx_http_wasm_send_header(ngx_http_request_t *r); -ngx_int_t ngx_http_wasm_send_chain_link(ngx_http_request_t *r, ngx_chain_t *in); +/* utils */ ngx_int_t ngx_http_wasm_set_resp_header(ngx_http_request_t *r, ngx_str_t key, ngx_str_t value, unsigned override); ngx_int_t ngx_http_wasm_set_resp_content_length(ngx_http_request_t *r, off_t cl); uintptr_t ngx_http_wasm_escape(u_char *dst, u_char *src, size_t size, ngx_http_wasm_escape_kind kind); +ngx_int_t ngx_http_wasm_send_chain_link(ngx_http_request_t *r, ngx_chain_t *in); +static ngx_inline ngx_uint_t +ngx_http_wasm_req_headers_count(ngx_http_request_t *r) +{ + return ngx_wasm_list_nelts(&r->headers_in.headers); +} +static ngx_inline ngx_uint_t +ngx_http_wasm_resp_headers_count(ngx_http_request_t *r) +{ + return ngx_wasm_list_nelts(&r->headers_out.headers); +} extern ngx_wavm_host_def_t ngx_http_wasm_host_interface; diff --git a/src/http/ngx_http_wasm_host.c b/src/http/ngx_http_wasm_host.c index dd5813ecc..af31e70ce 100644 --- a/src/http/ngx_http_wasm_host.c +++ b/src/http/ngx_http_wasm_host.c @@ -75,52 +75,58 @@ ngx_int_t ngx_http_wasm_hfuncs_resp_say(ngx_wavm_instance_t *instance, wasm_val_t args[], wasm_val_t rets[]) { - size_t len; - u_char *body; - ngx_int_t rc; - ngx_buf_t *b; - ngx_chain_t *cl; - ngx_http_wasm_req_ctx_t *rctx = instance->ctx->data; - ngx_http_request_t *r = rctx->r; + size_t len; + u_char *body; + ngx_int_t rc; + ngx_buf_t *b; + ngx_chain_t *cl; + ngx_http_wasm_req_ctx_t *rctx = instance->ctx->data; + ngx_http_request_t *r = rctx->r; - body = ngx_wavm_memory_lift(instance->memory, args[0].of.i32); - len = args[1].of.i32; + body = ngx_wavm_memory_lift(instance->memory, args[0].of.i32); + len = args[1].of.i32; - if (r->connection->fd == (ngx_socket_t) -1) { - return NGX_WAVM_BAD_CTX; - } + if (r->connection->fd == (ngx_socket_t) -1) { + return NGX_WAVM_BAD_CTX; + } - b = ngx_create_temp_buf(r->pool, len + sizeof(LF)); - if (b == NULL) { - return NGX_WAVM_ERROR; - } + if (rctx->finalized) { + return NGX_WAVM_BAD_USAGE; + } - b->last = ngx_copy(b->last, body, len); - *b->last++ = LF; + b = ngx_create_temp_buf(r->pool, len + sizeof(LF)); + if (b == NULL) { + return NGX_WAVM_ERROR; + } - b->last_buf = 1; - b->last_in_chain = 1; + b->last = ngx_copy(b->last, body, len); + *b->last++ = LF; - cl = ngx_alloc_chain_link(r->connection->pool); - if (cl == NULL) { - return NGX_WAVM_ERROR; - } + b->last_buf = 1; + b->last_in_chain = 1; - cl->buf = b; - cl->next = NULL; + cl = ngx_alloc_chain_link(r->connection->pool); + if (cl == NULL) { + return NGX_WAVM_ERROR; + } - rc = ngx_http_wasm_send_chain_link(r, cl); - if (rc == NGX_ERROR) { - return NGX_WAVM_ERROR; + cl->buf = b; + cl->next = NULL; - } else if (rc == NGX_AGAIN) { - /* TODO: NYI - NGX_WAVM_AGAIN */ - return NGX_AGAIN; - } + rc = ngx_http_wasm_send_chain_link(r, cl); + if (rc == NGX_ERROR) { + return NGX_WAVM_ERROR; - rctx->sent_last = 1; + } else if (rc == NGX_AGAIN) { + /* TODO: NYI - NGX_WAVM_AGAIN */ + return NGX_WAVM_AGAIN; + } - return NGX_WAVM_OK; + ngx_wasm_assert(rc == NGX_DONE || rc == NGX_OK); + + rctx->sent_last = 1; + + return NGX_WAVM_OK; } diff --git a/src/http/ngx_http_wasm_module.c b/src/http/ngx_http_wasm_module.c index 03233612e..8bbe66733 100644 --- a/src/http/ngx_http_wasm_module.c +++ b/src/http/ngx_http_wasm_module.c @@ -352,6 +352,9 @@ ngx_http_wasm_postconfig(ngx_conf_t *cf) static ngx_int_t ngx_http_wasm_init(ngx_cycle_t *cycle) { + ngx_http_next_header_filter = ngx_http_top_header_filter; + ngx_http_top_header_filter = ngx_http_wasm_header_filter_handler; + return NGX_OK; } @@ -454,6 +457,14 @@ ngx_http_wasm_rctx(ngx_http_request_t *r, ngx_http_wasm_req_ctx_t **out) cln->handler = ngx_http_wasm_cleanup; cln->data = &opctx->wvctx; + + if (r->content_handler != ngx_http_wasm_content_handler) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "wasm rctx injecting ngx_http_wasm_content_handler"); + + rctx->r_content_handler = r->content_handler; + r->content_handler = ngx_http_wasm_content_handler; + } } *out = rctx; @@ -462,6 +473,32 @@ ngx_http_wasm_rctx(ngx_http_request_t *r, ngx_http_wasm_req_ctx_t **out) } +static ngx_int_t +ngx_http_wasm_check_finalize(ngx_http_request_t *r, + ngx_http_wasm_req_ctx_t *rctx, ngx_int_t rc) +{ + if (rc == NGX_ERROR) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + if (rctx->sent_last) { + rc = NGX_DONE; + + if (!rctx->finalized) { + rctx->finalized = 1; + r->main->count++; + ngx_http_finalize_request(r, rc); + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "wasm rctx->sent_last: %d, rc: %d", + rctx->sent_last, rc); + } + + return rc; +} + + static ngx_int_t ngx_http_wasm_rewrite_handler(ngx_http_request_t *r) { @@ -476,9 +513,16 @@ ngx_http_wasm_rewrite_handler(ngx_http_request_t *r) rc = ngx_wasm_ops_resume(&rctx->opctx, NGX_HTTP_REWRITE_PHASE); if (rctx->sent_last) { - return NGX_OK; + rc = NGX_OK; + + } else if (rc == NGX_ERROR) { + rc = NGX_HTTP_INTERNAL_SERVER_ERROR; + r->content_handler = rctx->r_content_handler; } + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "wasm \"rewrite\" phase rc: %d", rc); + return rc; } @@ -496,7 +540,7 @@ ngx_http_wasm_preaccess_handler(ngx_http_request_t *r) rc = ngx_wasm_ops_resume(&rctx->opctx, NGX_HTTP_PREACCESS_PHASE); - return rc; + return ngx_http_wasm_check_finalize(r, rctx, rc); } @@ -513,7 +557,7 @@ ngx_http_wasm_access_handler(ngx_http_request_t *r) rc = ngx_wasm_ops_resume(&rctx->opctx, NGX_HTTP_ACCESS_PHASE); - return rc; + return ngx_http_wasm_check_finalize(r, rctx, rc); } @@ -529,24 +573,45 @@ ngx_http_wasm_content_handler(ngx_http_request_t *r) } rc = ngx_wasm_ops_resume(&rctx->opctx, NGX_HTTP_CONTENT_PHASE); + rc = ngx_http_wasm_check_finalize(r, rctx, rc); + if (rc == NGX_HTTP_INTERNAL_SERVER_ERROR || rc == NGX_DONE) { + return rc; + } - /* NYI */ - //return NGX_DECLINED + ngx_wasm_assert(rc == NGX_OK || rc == NGX_DECLINED); - return rc; -} + rc = ngx_http_wasm_flush_local_response(r, rctx); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "wasm flush_local_response rc: %d", rc); -void -ngx_http_wasm_header_filter_init(void) -{ - static unsigned c = 0; + switch (rc) { + + case NGX_OK: + /* flushed response */ + rctx->sent_last = 1; + rc = ngx_http_wasm_check_finalize(r, rctx, rc); + ngx_wasm_assert(rc == NGX_DONE); + break; + + case NGX_DECLINED: + if (rctx->r_content_handler) { + rc = rctx->r_content_handler(r); + } + + break; + + case NGX_AGAIN: /* TODO: catch */ + case NGX_ERROR: + default: + break; - if (!c) { - ngx_http_next_header_filter = ngx_http_top_header_filter; - ngx_http_top_header_filter = ngx_http_wasm_header_filter_handler; - c = 1; } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "wasm \"content\" phase rc: %d", rc); + + return rc; } @@ -556,25 +621,23 @@ ngx_http_wasm_header_filter_handler(ngx_http_request_t *r) ngx_int_t rc; ngx_http_wasm_req_ctx_t *rctx; - ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->connection->log, 0, - "proxy wasm header filter"); - rc = ngx_http_wasm_rctx(r, &rctx); - if (rc != NGX_OK) { - return rc; - } + if (rc == NGX_ERROR) { + return NGX_ERROR; - rc = ngx_wasm_ops_resume(&rctx->opctx, NGX_HTTP_WASM_HEADER_FILTER_PHASE); - if (rc == NGX_DECLINED) { + } else if (rc == NGX_DECLINED) { goto next_filter; - - } else if (rc != NGX_OK) { - return NGX_ERROR; } - //if (body_filter) { - // r->filter_need_in_memory = 1; - //} + ngx_wasm_assert(rc == NGX_OK); + + rc = ngx_wasm_ops_resume(&rctx->opctx, NGX_HTTP_WASM_HEADER_FILTER_PHASE); + if (rc == NGX_OK) { + rc = ngx_http_wasm_check_finalize(r, rctx, rc); + if (rc == NGX_DONE) { + return NGX_DONE; + } + } next_filter: diff --git a/src/http/ngx_http_wasm_util.c b/src/http/ngx_http_wasm_util.c index 1ee7bf7e5..a81bb8e5e 100644 --- a/src/http/ngx_http_wasm_util.c +++ b/src/http/ngx_http_wasm_util.c @@ -127,76 +127,6 @@ static ngx_http_wasm_header_t ngx_http_wasm_headers[] = { }; -ngx_uint_t -ngx_http_wasm_req_headers_count(ngx_http_request_t *r) -{ - ngx_uint_t c; - ngx_list_part_t *part; - - part = &r->headers_in.headers.part; - c = part->nelts; - - while (part->next != NULL) { - part = part->next; - c += part->nelts; - } - - return c; -} - - -ngx_int_t -ngx_http_wasm_send_header(ngx_http_request_t *r) -{ - if (r->header_sent) { - ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - "NYI - http wasm: catch header sent"); - return NGX_ERROR; - } - - if (!r->headers_out.status) { - r->headers_out.status = NGX_HTTP_OK; - } - - if (ngx_http_set_content_type(r) != NGX_OK) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - -#if 0 - ngx_http_clear_content_length(r); - ngx_http_clear_accept_ranges(r); -#endif - - return ngx_http_send_header(r); -} - - -ngx_int_t -ngx_http_wasm_send_chain_link(ngx_http_request_t *r, ngx_chain_t *in) -{ - ngx_int_t rc; - - rc = ngx_http_wasm_send_header(r); - - /* NGX_OK, NGX_ERROR, NGX_AGAIN, NGX_HTTP_* */ - - if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { - return rc; - } - - if (in == NULL) { - rc = ngx_http_send_special(r, NGX_HTTP_LAST); - if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { - return rc; - } - - return NGX_OK; - } - - return ngx_http_output_filter(r, in); -} - - ngx_int_t ngx_http_wasm_set_resp_header(ngx_http_request_t *r, ngx_str_t key, ngx_str_t value, unsigned override) @@ -608,3 +538,208 @@ ngx_http_copy_escaped(ngx_str_t *dst, ngx_pool_t *pool, return dst; } + + +ngx_int_t +ngx_http_wasm_send_chain_link(ngx_http_request_t *r, ngx_chain_t *in) +{ + ngx_int_t rc; + + if (!r->headers_out.status) { + r->headers_out.status = NGX_HTTP_OK; + } + + rc = ngx_http_send_header(r); + + if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { + /* NGX_ERROR, NGX_HTTP_* */ + return rc; + } + + /* NGX_OK, NGX_AGAIN */ + + if (in == NULL) { + rc = ngx_http_send_special(r, NGX_HTTP_LAST); + if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { + /* >= 300 */ + return rc; + } + + return NGX_OK; + } + + return ngx_http_output_filter(r, in); +} + + +/* ops */ + + +void +ngx_http_wasm_discard_local_response(ngx_http_wasm_req_ctx_t *rctx) +{ + ngx_http_request_t *r; + + r = rctx->r; + + rctx->local_resp = 0; + rctx->local_resp_status = 0; + rctx->local_resp_body_len = 0; + rctx->local_resp_reason.len = 0; + + if (rctx->local_resp_reason.data) { + ngx_pfree(r->pool, rctx->local_resp_reason.data); + } + + if (rctx->local_resp_headers) { + ngx_array_destroy(rctx->local_resp_headers); + rctx->local_resp_headers = NULL; + } + + if (rctx->local_resp_body) { + ngx_free_chain(r->pool, rctx->local_resp_body); + rctx->local_resp_body = NULL; + } +} + +ngx_int_t +ngx_http_wasm_stash_local_response(ngx_http_wasm_req_ctx_t *rctx, + ngx_int_t status, u_char *reason, size_t reason_len, ngx_array_t *headers, + u_char *body, size_t body_len) +{ + u_char *p = NULL; + ngx_buf_t *b = NULL; + ngx_chain_t *cl = NULL; + ngx_http_request_t *r = rctx->r; + + if (rctx->local_resp) { + ngx_wasm_log_error(NGX_LOG_ERR, r->connection->log, 0, + "local response already stashed"); + return NGX_ABORT; + } + + /* status */ + + if (status < 100 || status > 999) { + return NGX_DECLINED; + } + + rctx->local_resp_status = status; + + /* reason */ + + if (reason_len) { + reason_len += 5; /* "ddd \0" */ + p = ngx_pnalloc(r->pool, reason_len); + if (p == NULL) { + goto fail; + } + + ngx_snprintf(p, reason_len, "%03ui %s", status, reason); + + rctx->local_resp_reason.data = p; + rctx->local_resp_reason.len = reason_len; + } + + /* headers */ + + rctx->local_resp_headers = headers; + + /* body */ + + if (body_len) { + b = ngx_create_temp_buf(r->pool, body_len + sizeof(LF)); + if (b == NULL) { + goto fail; + } + + b->last = ngx_copy(b->last, body, body_len); + //*b->last++ = LF; + + b->last_buf = 1; + b->last_in_chain = 1; + + cl = ngx_alloc_chain_link(r->connection->pool); + if (cl == NULL) { + goto fail; + } + + cl->buf = b; + cl->next = NULL; + + rctx->local_resp_body = cl; + rctx->local_resp_body_len = body_len; + } + + rctx->local_resp = 1; + + return NGX_OK; + +fail: + + ngx_http_wasm_discard_local_response(rctx); + + return NGX_ERROR; +} + + +ngx_int_t +ngx_http_wasm_flush_local_response(ngx_http_request_t *r, + ngx_http_wasm_req_ctx_t *rctx) +{ + size_t i; + ngx_int_t rc; + ngx_table_elt_t *elt; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "wasm flushing local_response: %d", rctx->local_resp); + + if (!rctx->local_resp) { + return NGX_DECLINED; + } + + rc = ngx_http_discard_request_body(r); + if (rc != NGX_OK) { + return NGX_ERROR; + } + + r->headers_out.status = rctx->local_resp_status; + + if (r->err_status) { + r->err_status = 0; + } + + if (rctx->local_resp_reason.len) { + r->headers_out.status_line.data = rctx->local_resp_reason.data; + r->headers_out.status_line.len = rctx->local_resp_reason.len; + } + + if (rctx->local_resp_headers) { + for (i = 0; i < rctx->local_resp_headers->nelts; i++) { + elt = &((ngx_table_elt_t *) rctx->local_resp_headers->elts)[i]; + + rc = ngx_http_wasm_set_resp_header(r, elt->key, elt->value, 1); + if (rc != NGX_OK) { + return NGX_ERROR; + } + } + } + + if (rctx->local_resp_body_len) { + if (ngx_http_set_content_type(r) != NGX_OK) { + return NGX_ERROR; + } + + if (ngx_http_wasm_set_resp_content_length(r, rctx->local_resp_body_len) + != NGX_OK) + { + return NGX_ERROR; + } + } + + rc = ngx_http_wasm_send_chain_link(r, rctx->local_resp_body); + + rctx->sent_last = 1; + + return rc; +} diff --git a/src/http/proxy_wasm/ngx_http_proxy_wasm.c b/src/http/proxy_wasm/ngx_http_proxy_wasm.c index 02de3795e..0c9f28b41 100644 --- a/src/http/proxy_wasm/ngx_http_proxy_wasm.c +++ b/src/http/proxy_wasm/ngx_http_proxy_wasm.c @@ -58,46 +58,43 @@ ngx_int_t ngx_http_proxy_wasm_resume(ngx_proxy_wasm_t *pwm, ngx_wasm_phase_t *phase, ngx_wavm_ctx_t *wvctx) { - ngx_uint_t rc; + ngx_int_t rc; +#if (NGX_DEBUG) ngx_http_request_t *r; - ngx_http_wasm_req_ctx_t *rctx; - - rctx = (ngx_http_wasm_req_ctx_t *) wvctx->data; r = ngx_http_proxy_wasm_request(pwm); ngx_wasm_assert(wvctx->log == r->connection->log); +#endif + + if (pwm->trap) { + return NGX_DECLINED; + } switch (phase->index) { - case NGX_HTTP_PREACCESS_PHASE: + case NGX_HTTP_REWRITE_PHASE: rc = ngx_http_proxy_wasm_on_request_headers(pwm); - if (rc != NGX_OK) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + if (rc == NGX_OK) { + rc = NGX_DECLINED; } - /* NGX_OK */ - break; case NGX_HTTP_WASM_HEADER_FILTER_PHASE: rc = ngx_http_proxy_wasm_on_response_headers(pwm); if (rc != NGX_OK) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + rc = NGX_DECLINED; } - /* NGX_OK */ - break; case NGX_HTTP_LOG_PHASE: rc = ngx_proxy_wasm_on_log(pwm); if (rc != NGX_OK) { - return NGX_ERROR; + rc = NGX_ERROR; } - /* NGX_OK */ - break; default: @@ -106,16 +103,8 @@ ngx_http_proxy_wasm_resume(ngx_proxy_wasm_t *pwm, ngx_wasm_phase_t *phase, } - if (rctx->sent_last) { - rc = NGX_DONE; - - if (!rctx->finalized) { - rctx->finalized = 1; - - ngx_http_finalize_request(r, rc); - } - - /* NGX_DONE */ + if (rc == NGX_ERROR) { + pwm->trap = 1; } return rc; @@ -125,9 +114,9 @@ ngx_http_proxy_wasm_resume(ngx_proxy_wasm_t *pwm, ngx_wasm_phase_t *phase, static ngx_int_t ngx_http_proxy_wasm_on_request_headers(ngx_proxy_wasm_t *pwm) { - ngx_http_request_t *r; ngx_int_t ctxid; ngx_uint_t rc; + ngx_http_request_t *r; wasm_val_vec_t *rets; r = ngx_http_proxy_wasm_request(pwm); @@ -179,25 +168,26 @@ ngx_http_proxy_wasm_on_request_headers(ngx_proxy_wasm_t *pwm) static ngx_int_t ngx_http_proxy_wasm_on_response_headers(ngx_proxy_wasm_t *pwm) { - ngx_uint_t rc; ngx_int_t ctxid; + ngx_uint_t rc, nheaders; + ngx_http_request_t *r; wasm_val_vec_t *rets; + r = ngx_http_proxy_wasm_request(pwm); ctxid = ngx_http_proxy_wasm_ctxid(pwm); + nheaders = ngx_http_wasm_resp_headers_count(r); if (pwm->abi_version == NGX_PROXY_WASM_0_1_0) { /* 0.1.0 */ rc = ngx_wavm_instance_call_funcref(pwm->instance, pwm->proxy_on_http_response_headers, - &rets, ctxid, - 0); + &rets, ctxid, nheaders); } else { /* 0.2.0+ */ rc = ngx_wavm_instance_call_funcref(pwm->instance, pwm->proxy_on_http_response_headers, - &rets, ctxid, - 0, + &rets, ctxid, nheaders, 0); // TODO: end_of_stream } diff --git a/src/wasm/ngx_wasm.h b/src/wasm/ngx_wasm.h index 1fe650fb3..de1e50bf6 100644 --- a/src/wasm/ngx_wasm.h +++ b/src/wasm/ngx_wasm.h @@ -13,6 +13,7 @@ #endif #define NGX_LOG_DEBUG_WASM NGX_LOG_DEBUG_ALL +#define NGX_LOG_WASM_NYI NGX_LOG_ALERT #define NGX_WASM_MODULE 0x5741534d /* "WASM" */ #define NGX_WASM_CONF 0x00300000 @@ -61,13 +62,13 @@ typedef struct { ngx_wavm_t *ngx_wasm_main_vm(ngx_cycle_t *cycle); +ngx_uint_t ngx_wasm_list_nelts(ngx_list_t *list); ngx_int_t ngx_wasm_bytes_from_path(wasm_byte_vec_t *out, u_char *path, ngx_log_t *log); #if 0 ngx_connection_t *ngx_wasm_connection_create(ngx_pool_t *pool); void ngx_wasm_connection_destroy(ngx_connection_t *c); #endif - void ngx_wasm_log_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, const char *fmt, ...); diff --git a/src/wasm/ngx_wasm_ops.c b/src/wasm/ngx_wasm_ops.c index eb47f74c9..7af654abc 100644 --- a/src/wasm/ngx_wasm_ops.c +++ b/src/wasm/ngx_wasm_ops.c @@ -113,16 +113,12 @@ ngx_wasm_ops_engine_init(ngx_wasm_ops_engine_t *engine) break; default: - ngx_wasm_log_error(NGX_LOG_ALERT, engine->pool->log, 0, + ngx_wasm_log_error(NGX_LOG_WASM_NYI, engine->pool->log, 0, "unknown wasm op code: %d", op->code); return; } } - - if (pipeline->ops->nelts) { - ngx_http_wasm_header_filter_init(); - } } } @@ -154,7 +150,7 @@ ngx_wasm_ops_engine_destroy(ngx_wasm_ops_engine_t *engine) break; default: - ngx_wasm_log_error(NGX_LOG_ALERT, engine->pool->log, 0, + ngx_wasm_log_error(NGX_LOG_WASM_NYI, engine->pool->log, 0, "unknown wasm op code: %d", op->code); break; @@ -259,7 +255,7 @@ ngx_wasm_conf_add_op_call(ngx_conf_t *cf, ngx_wasm_ops_engine_t *ops_engine, } if (phase->on == 0) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unsupported phase \"%V\"", + ngx_conf_log_error(NGX_LOG_WASM_NYI, cf, 0, "unsupported phase \"%V\"", phase_name); return NULL; } @@ -302,8 +298,7 @@ ngx_wasm_conf_add_op_proxy_wasm(ngx_conf_t *cf, op->code = NGX_WASM_OP_PROXY_WASM; op->handler = ngx_wasm_op_proxy_wasm_handler; op->host = &ngx_proxy_wasm_host; - op->on_phases = (1 << NGX_HTTP_PREACCESS_PHASE) - | (1 << NGX_HTTP_ACCESS_PHASE) + op->on_phases = (1 << NGX_HTTP_REWRITE_PHASE) | (1 << NGX_HTTP_WASM_HEADER_FILTER_PHASE) | (1 << NGX_HTTP_LOG_PHASE); @@ -314,8 +309,6 @@ ngx_wasm_conf_add_op_proxy_wasm(ngx_conf_t *cf, op->conf.proxy_wasm.pwmodule = pwmodule; op->conf.proxy_wasm.pwmodule->module = op->module; - op->opbreak = 1; - return op; } @@ -328,7 +321,7 @@ ngx_wasm_ops_resume(ngx_wasm_op_ctx_t *ctx, ngx_uint_t phaseidx) ngx_wasm_ops_engine_t *ops_engine = ctx->ops_engine; ngx_wasm_ops_pipeline_t *pipeline; ngx_wasm_op_t *op; - ngx_int_t rc = NGX_OK; + ngx_int_t rc = NGX_DECLINED; if (ops_engine == NULL) { return NGX_DECLINED; @@ -336,9 +329,10 @@ ngx_wasm_ops_resume(ngx_wasm_op_ctx_t *ctx, ngx_uint_t phaseidx) phase = ngx_wasm_ops_engine_phase_lookup(ops_engine, phaseidx); if (phase == NULL) { - ngx_log_debug1(NGX_LOG_DEBUG_WASM, ctx->log, 0, - "wasm ops resume: no phase for index '%ui'", phase); - return NGX_DECLINED; + ngx_wasm_log_error(NGX_LOG_WARN, ctx->log, 0, + "ops resume: no phase for index '%ui'", + phase); + goto rc; } ngx_log_debug2(NGX_LOG_DEBUG_WASM, ctx->log, 0, @@ -347,73 +341,38 @@ ngx_wasm_ops_resume(ngx_wasm_op_ctx_t *ctx, ngx_uint_t phaseidx) pipeline = ctx->ops_engine->pipelines[phase->index]; if (pipeline == NULL) { - return NGX_DECLINED; + goto rc; } for (i = 0; i < pipeline->ops->nelts; i++) { op = ((ngx_wasm_op_t **) pipeline->ops->elts)[i]; if (op->lmodule == NULL) { - return NGX_ERROR; + rc = NGX_ERROR; + goto rc; } rc = op->handler(ctx, phase, op); - if (op->opbreak) { - dd("wasm ops opbreak rc: %ld", rc); - return rc; - } - - /* NGX_OK, NGX_ERROR */ - - if (rc == NGX_ERROR) { + if (rc == NGX_ERROR || rc > NGX_OK) { + /* NGX_ERROR, NGX_HTTP_* */ break; } - } - switch (phaseidx) { - - case NGX_HTTP_REWRITE_PHASE: - if (rc == NGX_ERROR) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + if (rc == NGX_OK) { + goto rc; } - rc = NGX_DECLINED; - break; + ngx_wasm_assert(rc != NGX_AGAIN); + ngx_wasm_assert(rc != NGX_DONE); - case NGX_HTTP_PREACCESS_PHASE: - if (rc == NGX_ERROR) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - rc = NGX_DECLINED; - break; - - case NGX_HTTP_ACCESS_PHASE: - if (rc == NGX_ERROR) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - rc = NGX_DECLINED; - break; - - case NGX_HTTP_CONTENT_PHASE: - if (rc == NGX_ERROR) { - return NGX_ERROR; - } - - /* NYI: NGX_DECLINED */ - - rc = NGX_DONE; - break; - - case NGX_HTTP_LOG_PHASE: - if (rc != NGX_OK) { - rc = NGX_ERROR; - } + /* NGX_DECLINED, NGX_HTTP_* */ + } - break; +rc: - } + ngx_log_debug2(NGX_LOG_DEBUG_WASM, ctx->log, 0, + "wasm ops \"%V\" phase rc: %d", + &phase->name, rc); return rc; } @@ -423,6 +382,7 @@ static ngx_int_t ngx_wasm_op_call_handler(ngx_wasm_op_ctx_t *ctx, ngx_wasm_phase_t *phase, ngx_wasm_op_t *op) { + ngx_int_t rc; ngx_wavm_instance_t *instance; ngx_wavm_funcref_t *funcref; @@ -442,7 +402,14 @@ ngx_wasm_op_call_handler(ngx_wasm_op_ctx_t *ctx, ngx_wasm_phase_t *phase, return NGX_ERROR; } - return ngx_wavm_instance_call_funcref_vec(instance, funcref, NULL, NULL); + rc = ngx_wavm_instance_call_funcref_vec(instance, funcref, NULL, NULL); + if (rc == NGX_ERROR) { + return rc; + } + + ngx_wasm_assert(rc == NGX_OK); + + return NGX_DECLINED; } diff --git a/src/wasm/ngx_wasm_ops.h b/src/wasm/ngx_wasm_ops.h index a898aa49e..c385f4e34 100644 --- a/src/wasm/ngx_wasm_ops.h +++ b/src/wasm/ngx_wasm_ops.h @@ -35,7 +35,7 @@ typedef struct { typedef struct { - ngx_proxy_wasm_t *pwmodule; + ngx_proxy_wasm_t *pwmodule; } ngx_wasm_op_proxy_wasm_t; @@ -51,8 +51,6 @@ struct ngx_wasm_op_s { ngx_wasm_op_call_t call; ngx_wasm_op_proxy_wasm_t proxy_wasm; } conf; - - unsigned opbreak:1; }; diff --git a/src/wasm/ngx_wasm_util.c b/src/wasm/ngx_wasm_util.c index 8be639c7e..f566294ef 100644 --- a/src/wasm/ngx_wasm_util.c +++ b/src/wasm/ngx_wasm_util.c @@ -7,18 +7,21 @@ #include -void -ngx_wasm_log_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, - const char *fmt, ...) +ngx_uint_t +ngx_wasm_list_nelts(ngx_list_t *list) { - va_list args; - u_char *p, errstr[NGX_MAX_ERROR_STR]; + ngx_uint_t c; + ngx_list_part_t *part; - va_start(args, fmt); - p = ngx_vsnprintf(errstr, NGX_MAX_ERROR_STR, fmt, args); - va_end(args); + part = &list->part; + c = part->nelts; - ngx_log_error_core(level, log, err, "[wasm] %*s", p - errstr, errstr); + while (part->next != NULL) { + part = part->next; + c += part->nelts; + } + + return c; } @@ -95,6 +98,19 @@ ngx_wasm_bytes_from_path(wasm_byte_vec_t *out, u_char *path, ngx_log_t *log) return rc; } +void +ngx_wasm_log_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, + const char *fmt, ...) +{ + va_list args; + u_char *p, errstr[NGX_MAX_ERROR_STR]; + + va_start(args, fmt); + p = ngx_vsnprintf(errstr, NGX_MAX_ERROR_STR, fmt, args); + va_end(args); + + ngx_log_error_core(level, log, err, "[wasm] %*s", p - errstr, errstr); +} #if 0 diff --git a/src/wasm/vm/ngx_wavm.c b/src/wasm/vm/ngx_wavm.c index 96e78384e..f28d31762 100644 --- a/src/wasm/vm/ngx_wavm.c +++ b/src/wasm/vm/ngx_wavm.c @@ -72,7 +72,7 @@ ngx_wavm_create(ngx_cycle_t *cycle, const ngx_str_t *name, error: ngx_wasm_log_error(NGX_LOG_EMERG, ngx_cycle->log, 0, - "failed to create \"%V\" vm: %s", + "failed creating \"%V\" vm: %s", name, NGX_WAVM_NOMEM_CHAR); if (vm) { @@ -179,7 +179,7 @@ ngx_wavm_init(ngx_wavm_t *vm) error: ngx_wavm_log_error(NGX_LOG_EMERG, vm->log, NULL, - "failed to initialize wasm VM"); + "failed initializing wasm VM"); done: @@ -198,7 +198,7 @@ ngx_wavm_load(ngx_wavm_t *vm) if (ngx_wavm_engine_init(vm) != NGX_OK) { ngx_wavm_log_error(NGX_LOG_EMERG, vm->log, NULL, - "failed init engine"); + "failed initializing engine"); return NGX_ERROR; } @@ -364,7 +364,7 @@ ngx_wavm_module_add(ngx_wavm_t *vm, ngx_str_t *name, ngx_str_t *path) error: ngx_wavm_log_error(NGX_LOG_EMERG, vm->log, NULL, - "failed to add \"%V\" module from \"%V\": %s", + "failed adding \"%V\" module from \"%V\": %s", name, path, err); if (module) { @@ -503,7 +503,7 @@ ngx_wavm_module_load(ngx_wavm_module_t *module) if (wasm_externtype_kind(wasm_importtype_type(importtype)) != WASM_EXTERN_FUNC) { - ngx_wavm_log_error(NGX_LOG_ALERT, vm->log, NULL, + ngx_wavm_log_error(NGX_LOG_WASM_NYI, vm->log, NULL, "NYI: module import type not supported"); goto failed; } @@ -1135,7 +1135,7 @@ ngx_wavm_val_vec_set(wasm_val_vec_t *out, const wasm_valtype_vec_t *valtypes, break; default: - ngx_wasm_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + ngx_wasm_log_error(NGX_LOG_WASM_NYI, ngx_cycle->log, 0, "NYI - variadic arg of valkind \"%u\"", valkind); diff --git a/src/wasm/vm/ngx_wavm_host.c b/src/wasm/vm/ngx_wavm_host.c index 02ba2a3e4..448dd6df5 100644 --- a/src/wasm/vm/ngx_wavm_host.c +++ b/src/wasm/vm/ngx_wavm_host.c @@ -187,11 +187,11 @@ ngx_wavm_hfuncs_trampoline(void *env, const wasm_val_vec_t* args, goto trap; case NGX_WAVM_BAD_CTX: - err = "bad context"; + err = "nginx hfuncs bad context"; goto trap; case NGX_WAVM_BAD_USAGE: - err = "bad usage"; + err = "nginx hfuncs bad usage"; goto trap; default: diff --git a/t/02-http/001-wasm_call_directive.t b/t/02-http/001-wasm_call_directive.t index 5a40a4a39..85fa50ac1 100644 --- a/t/02-http/001-wasm_call_directive.t +++ b/t/02-http/001-wasm_call_directive.t @@ -123,7 +123,7 @@ qr/\[emerg\] .*? unknown phase "foo"/ return 200; } --- error_log eval -qr/\[emerg\] .*? unsupported phase "post_read"/ +qr/\[alert\] .*? unsupported phase "post_read"/ --- no_error_log [error] [crit] diff --git a/t/03-proxy_wasm/001-proxy_wasm_directive.t b/t/03-proxy_wasm/001-proxy_wasm_directive.t index 01fbaf75d..44cdbc170 100644 --- a/t/03-proxy_wasm/001-proxy_wasm_directive.t +++ b/t/03-proxy_wasm/001-proxy_wasm_directive.t @@ -83,11 +83,13 @@ qr/\[emerg\] .*? invalid module name ""/ ) --- error_code: 500 --- error_log eval -qr/\[emerg\] .*? \[wasm\] unknown ABI version/ +[ + qr/\[alert\] .*? \[wasm\] unknown ABI version/, + qr/\[emerg\] .*? \[wasm\] unknown ABI version: proxy_wasm failed to resume/ +] --- no_error_log [warn] [error] -[alert] [crit] @@ -168,11 +170,13 @@ qr/\[emerg\] .*? \[wasm\] incompatible sdk interface: missing context init/ ) --- error_code: 500 --- error_log eval -qr/\[emerg\] .*? \[wasm\] unknown ABI version/ +[ + qr/\[alert\] .*? \[wasm\] unknown ABI version/, + qr/\[emerg\] .*? \[wasm\] unknown ABI version: proxy_wasm failed to resume/ +] --- no_error_log [warn] [error] -[alert] [crit] diff --git a/t/03-proxy_wasm/002-on_tick.t b/t/03-proxy_wasm/002-on_tick.t index 7618dc087..4e7100ece 100644 --- a/t/03-proxy_wasm/002-on_tick.t +++ b/t/03-proxy_wasm/002-on_tick.t @@ -57,10 +57,10 @@ __DATA__ --- ignore_response_body --- error_log eval [ - qr/\[info\] .*? \[wasm\] Ticking/, - qr/\[info\] .*? \[wasm\] from http_request_headers/, - qr/\[info\] .*? \[wasm\] from http_request_headers/, - qr/\[info\] .*? \[wasm\] Ticking/ + qr/\[info\] .*? \[wasm\] Ticking \<.*?\>$/, + qr/\[info\] .*? \[wasm\] from http_request_headers \<.*?\>, client: .*?, server: .*?, request:/, + qr/\[info\] .*? \[wasm\] from http_request_headers \<.*?\>, client: .*?, server: .*?, request:/, + qr/\[info\] .*? \[wasm\] Ticking \<.*?\>$/, ] --- no_error_log [error] diff --git a/t/03-proxy_wasm/003-on_http_phases.t b/t/03-proxy_wasm/003-on_http_phases.t index d0d4ce873..ec6ddba67 100644 --- a/t/03-proxy_wasm/003-on_http_phases.t +++ b/t/03-proxy_wasm/003-on_http_phases.t @@ -6,7 +6,9 @@ use t::TestWasm; skip_valgrind(); -plan tests => repeat_each() * (blocks() * 5); +#repeat_each(2); + +plan tests => repeat_each() * (blocks() * 7); run_tests(); @@ -23,17 +25,20 @@ __DATA__ proxy_wasm on_http_phases; echo ok; } ---- ignore_response_body +--- response_body +ok --- error_log eval qr/\[info\] .*? \[wasm\] #\d+ on_request_headers, 2 headers/ --- no_error_log [error] [emerg] [alert] +[crit] === TEST 2: proxy_wasm - on_response_headers +should log 0 response headers (TODO: include default headers) --- load_nginx_modules: ngx_http_echo_module --- main_config wasm { @@ -44,13 +49,15 @@ qr/\[info\] .*? \[wasm\] #\d+ on_request_headers, 2 headers/ proxy_wasm on_http_phases; echo ok; } ---- ignore_response_body +--- response_body +ok --- error_log eval qr/\[info\] .*? \[wasm\] #\d+ on_response_headers, 0 headers/ --- no_error_log [error] [emerg] [alert] +[crit] @@ -65,12 +72,134 @@ qr/\[info\] .*? \[wasm\] #\d+ on_response_headers, 0 headers/ proxy_wasm on_http_phases; echo ok; } ---- ignore_response_body +--- response_body +ok +--- error_log eval +qr/\[info\] .*? \[wasm\] #\d+ on_done/ +--- no_error_log +[error] +[emerg] +[alert] +[crit] + + + +=== TEST 4: proxy_wasm - missing default content handler +should cause HTTP 404 from static module (default content handler) +--- load_nginx_modules: ngx_http_echo_module +--- main_config + wasm { + module on_http_phases $TEST_NGINX_CRATES_DIR/on_http_phases.wasm; + } +--- config + location /t { + proxy_wasm on_http_phases; + echo_status 201; + } +--- error_code: 404 +--- response_body eval +qr/404 Not Found/ +--- error_log eval +[ + qr/\[error\] .*? open\(\) \".*?\" failed/, + qr/\[info\] .*? \[wasm\] #\d+ on_request_headers, 2 headers/, + qr/\[info\] .*? \[wasm\] #\d+ on_response_headers, 0 headers/, + qr/\[info\] .*? \[wasm\] #\d+ on_done/ +] +--- no_error_log +[crit] + + + +=== TEST 5: proxy_wasm - with 'return' (rewrite) +should produce a response in and of itself, proxy_wasm wraps around +--- main_config + wasm { + module on_http_phases $TEST_NGINX_CRATES_DIR/on_http_phases.wasm; + } +--- config + location /t { + proxy_wasm on_http_phases; + return 201; + } +--- error_code: 201 +--- response_body --- error_log eval [ - qr/\[info\] .*? \[wasm\] #\d+ on_done/, + qr/\[info\] .*? \[wasm\] #\d+ on_request_headers, 2 headers/, + qr/\[info\] .*? \[wasm\] #\d+ on_response_headers, 0 headers/, qr/\[info\] .*? \[wasm\] #\d+ on_done/ ] --- no_error_log [error] -[alert] +[crit] + + + +=== TEST 6: proxy_wasm - with 'proxy_pass' (content) +should produce a response from proxy_pass, proxy_wasm wraps around +--- main_config + wasm { + module on_http_phases $TEST_NGINX_CRATES_DIR/on_http_phases.wasm; + } +--- http_config eval +qq{ + upstream test_upstream { + server unix:$ENV{TEST_NGINX_UNIX_SOCKET}; + } + + server { + listen unix:$ENV{TEST_NGINX_UNIX_SOCKET}; + + location / { + return 201; + } + } +} +--- config + location /t { + proxy_wasm on_http_phases; + proxy_pass http://test_upstream/; + } +--- error_code: 201 +--- response_body +--- error_log eval +[ + qr/\[info\] .*? \[wasm\] #\d+ on_request_headers, 2 headers/, + qr/\[info\] .*? \[wasm\] #\d+ on_response_headers, 0 headers/, + qr/\[info\] .*? \[wasm\] #\d+ on_done/ +] +--- no_error_log +[error] +[crit] + + + +=== TEST 7: proxy_wasm - as subrequest +should not execute a log phase +--- load_nginx_modules: ngx_http_echo_module +--- main_config + wasm { + module on_http_phases $TEST_NGINX_CRATES_DIR/on_http_phases.wasm; + } +--- config + location /subrequest { + internal; + proxy_wasm on_http_phases; + return 201; + } + + location /t { + echo_subrequest GET '/subrequest'; + } +--- error_code: 200 +--- response_body +--- error_log eval +[ + qr/\[info\] .*? \[wasm\] #\d+ on_request_headers, 2 headers/, + qr/\[info\] .*? \[wasm\] #\d+ on_response_headers, 0 headers/, +] +--- no_error_log +on_done +[error] +[crit] diff --git a/t/03-proxy_wasm/102-proxy_send_http_response.t b/t/03-proxy_wasm/102-proxy_send_http_response.t index fcdd148a7..60f5a5fa0 100644 --- a/t/03-proxy_wasm/102-proxy_send_http_response.t +++ b/t/03-proxy_wasm/102-proxy_send_http_response.t @@ -56,7 +56,6 @@ GET /t/echo/status/300 === TEST 3: send_http_response() set status code (bad argument) should produce error page content from a panic, not from echo ---- TODO: handle "already borrowed mut" panic in log phase --- load_nginx_modules: ngx_http_echo_module --- wasm_modules: hostcalls --- config diff --git a/t/TestWasm.pm b/t/TestWasm.pm index 7fafc33c0..7bf37fb84 100644 --- a/t/TestWasm.pm +++ b/t/TestWasm.pm @@ -22,8 +22,9 @@ our @EXPORT = qw( skip_valgrind ); -$ENV{TEST_NGINX_HTML_DIR} = html_dir; $ENV{TEST_NGINX_CRATES_DIR} = $crates; +$ENV{TEST_NGINX_HTML_DIR} = html_dir(); +$ENV{TEST_NGINX_UNIX_SOCKET} = html_dir() . "/nginx.sock"; sub skip_valgrind { if ($ENV{TEST_NGINX_USE_VALGRIND} && $ENV{CI} diff --git a/t/lib/rust-tests/proxy-wasm/hostcalls/src/lib.rs b/t/lib/rust-tests/proxy-wasm/hostcalls/src/lib.rs index 8c21213c3..34ee84f83 100644 --- a/t/lib/rust-tests/proxy-wasm/hostcalls/src/lib.rs +++ b/t/lib/rust-tests/proxy-wasm/hostcalls/src/lib.rs @@ -97,9 +97,7 @@ impl RootContext for TestHttpHostcalls { impl Context for TestHttpHostcalls {} impl HttpContext for TestHttpHostcalls { - fn on_http_request_headers(&mut self, nheaders: usize) -> Action { - info!("number of request headers: {}", nheaders); - + fn on_http_request_headers(&mut self, _: usize) -> Action { match self.get_http_request_header(":path") { Some(path) => self.exec(path), _ => Action::Continue,