From aedb999fe19d47ca0faf91752d7be4b227c51021 Mon Sep 17 00:00:00 2001 From: Max Romanov Date: Tue, 5 Mar 2019 15:38:48 +0300 Subject: Including port message header into message size limit. Before this fix, large plain message (i.e. configuration) send may fail with the 'Message too big' error, because internal fragmentation implementation does not account for 16 byte message header. This closes #167 issue on GitHub. --- src/nxt_port_socket.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/nxt_port_socket.c b/src/nxt_port_socket.c index 01fe2dab..8694ef65 100644 --- a/src/nxt_port_socket.c +++ b/src/nxt_port_socket.c @@ -349,6 +349,8 @@ nxt_port_write_handler(nxt_task_t *task, void *obj, void *data) iov[0].iov_len += sizeof(msg->tracking_msg); } + sb.limit -= iov[0].iov_len; + nxt_sendbuf_mem_coalesce(task, &sb); plain_size = sb.size; -- cgit From 0ab83370cb8e70a4440589051f14d99ae8cec588 Mon Sep 17 00:00:00 2001 From: Max Romanov Date: Tue, 5 Mar 2019 15:38:49 +0300 Subject: Handling ENOBUFS error same was as EAGAIN. Unlike EAGAIN, ENOBUFS returned on OSX when trying to send many relatively small (64 bytes) fragments. Found during investigation of #167 issue on GitHub. --- src/nxt_errno.h | 1 + src/nxt_socketpair.c | 13 +++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nxt_errno.h b/src/nxt_errno.h index b3d7105a..e3ce8349 100644 --- a/src/nxt_errno.h +++ b/src/nxt_errno.h @@ -45,6 +45,7 @@ typedef int nxt_err_t; #define NXT_EILSEQ EILSEQ #define NXT_ETIME ETIME #define NXT_ENOMOREFILES 0 +#define NXT_ENOBUFS ENOBUFS #if (NXT_HPUX) /* HP-UX uses EWOULDBLOCK instead of EAGAIN. */ diff --git a/src/nxt_socketpair.c b/src/nxt_socketpair.c index a7396b31..0adbe1f6 100644 --- a/src/nxt_socketpair.c +++ b/src/nxt_socketpair.c @@ -94,9 +94,14 @@ nxt_socketpair_send(nxt_fd_event_t *ev, nxt_fd_t fd, nxt_iobuf_t *iob, case NXT_EAGAIN: nxt_debug(ev->task, "sendmsg(%d) not ready", ev->fd); - ev->write_ready = 0; + break; - return NXT_AGAIN; + /* + * Returned (at least on OSX) when trying to send many small messages. + */ + case NXT_ENOBUFS: + nxt_debug(ev->task, "sendmsg(%d) no buffers", ev->fd); + break; case NXT_EINTR: nxt_debug(ev->task, "sendmsg(%d) interrupted", ev->fd); @@ -108,6 +113,10 @@ nxt_socketpair_send(nxt_fd_event_t *ev, nxt_fd_t fd, nxt_iobuf_t *iob, return NXT_ERROR; } + + ev->write_ready = 0; + + return NXT_AGAIN; } } -- cgit From 42b66ec654a1169bdc5f8e3acf1b6af1787dbd27 Mon Sep 17 00:00:00 2001 From: Max Romanov Date: Tue, 5 Mar 2019 15:38:50 +0300 Subject: Fixing EAGAIN processing for port message send. Sending large plain (exceeding port's max_size, not in shared memory) messages causes message fragmentation. First message fragment is sent successfully, but the next fragment may fail with the EAGAIN error. In this case, the message has to be pushed back to queue head for additional processing. Related to #167 issue on GitHub. --- src/nxt_port_socket.c | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/nxt_port_socket.c b/src/nxt_port_socket.c index 8694ef65..85da89c8 100644 --- a/src/nxt_port_socket.c +++ b/src/nxt_port_socket.c @@ -195,7 +195,24 @@ nxt_port_msg_create(nxt_task_t *task, nxt_port_send_msg_t *m) static nxt_port_send_msg_t * -nxt_port_msg_push(nxt_task_t *task, nxt_port_t *port, nxt_port_send_msg_t *msg) +nxt_port_msg_insert_head(nxt_task_t *task, nxt_port_t *port, + nxt_port_send_msg_t *msg) +{ + if (msg->work.data == NULL) { + msg = nxt_port_msg_create(task, msg); + } + + if (msg != NULL) { + nxt_queue_insert_head(&port->messages, &msg->link); + } + + return msg; +} + + +static nxt_port_send_msg_t * +nxt_port_msg_insert_tail(nxt_task_t *task, nxt_port_t *port, + nxt_port_send_msg_t *msg) { if (msg->work.data == NULL) { msg = nxt_port_msg_create(task, msg); @@ -260,7 +277,7 @@ nxt_port_socket_twrite(nxt_task_t *task, nxt_port_t *port, nxt_uint_t type, } else { nxt_thread_mutex_lock(&port->write_mutex); - res = nxt_port_msg_push(task, port, &msg); + res = nxt_port_msg_insert_tail(task, port, &msg); nxt_thread_mutex_unlock(&port->write_mutex); @@ -409,7 +426,7 @@ nxt_port_write_handler(nxt_task_t *task, void *obj, void *data) } data = NULL; - if (nxt_port_msg_push(task, port, msg) != NULL) { + if (nxt_port_msg_insert_tail(task, port, msg) != NULL) { use_delta++; } } @@ -424,16 +441,17 @@ nxt_port_write_handler(nxt_task_t *task, void *obj, void *data) data = NULL; } - } else if (nxt_slow_path(n == NXT_ERROR)) { + } else { if (msg->link.next == NULL) { - if (nxt_port_msg_push(task, port, msg) != NULL) { + if (nxt_port_msg_insert_head(task, port, msg) != NULL) { use_delta++; } } - goto fail; - } - /* n == NXT_AGAIN */ + if (nxt_slow_path(n == NXT_ERROR)) { + goto fail; + } + } } while (port->socket.write_ready); -- cgit From ddd2e8cc3676e81abd098baa2b8d262a74be8cee Mon Sep 17 00:00:00 2001 From: Max Romanov Date: Tue, 5 Mar 2019 15:38:51 +0300 Subject: Improving port message fragment recognition. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is required to assemble fragmented messages correctly. Stream identifier is unique only for messages generated within a process, but the (stream, pid) pair should be enough to avoid collisions. Adding reply_port seems redundant because it's enough to add stream to a pid. This closes #199 issue on GitHub. Thanks to 洪志道 (Hong Zhi Dao). --- src/nxt_port_socket.c | 52 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/nxt_port_socket.c b/src/nxt_port_socket.c index 85da89c8..a426df31 100644 --- a/src/nxt_port_socket.c +++ b/src/nxt_port_socket.c @@ -638,15 +638,24 @@ nxt_port_read_handler(nxt_task_t *task, void *obj, void *data) } +typedef struct { + uint32_t stream; + uint32_t pid; +} nxt_port_frag_key_t; + + static nxt_int_t nxt_port_lvlhsh_frag_test(nxt_lvlhsh_query_t *lhq, void *data) { nxt_port_recv_msg_t *fmsg; + nxt_port_frag_key_t *frag_key; fmsg = data; + frag_key = (nxt_port_frag_key_t *) lhq->key.start; - if (lhq->key.length == sizeof(uint32_t) - && *(uint32_t *) lhq->key.start == fmsg->port_msg.stream) + if (lhq->key.length == sizeof(nxt_port_frag_key_t) + && frag_key->stream == fmsg->port_msg.stream + && frag_key->pid == (uint32_t) fmsg->port_msg.pid) { return NXT_OK; } @@ -684,6 +693,7 @@ nxt_port_frag_start(nxt_task_t *task, nxt_port_t *port, nxt_int_t res; nxt_lvlhsh_query_t lhq; nxt_port_recv_msg_t *fmsg; + nxt_port_frag_key_t frag_key; nxt_debug(task, "start frag stream #%uD", msg->port_msg.stream); @@ -695,9 +705,12 @@ nxt_port_frag_start(nxt_task_t *task, nxt_port_t *port, *fmsg = *msg; - lhq.key_hash = nxt_murmur_hash2(&fmsg->port_msg.stream, sizeof(uint32_t)); - lhq.key.length = sizeof(uint32_t); - lhq.key.start = (u_char *) &fmsg->port_msg.stream; + frag_key.stream = fmsg->port_msg.stream; + frag_key.pid = fmsg->port_msg.pid; + + lhq.key_hash = nxt_murmur_hash2(&frag_key, sizeof(nxt_port_frag_key_t)); + lhq.key.length = sizeof(nxt_port_frag_key_t); + lhq.key.start = (u_char *) &frag_key; lhq.proto = &lvlhsh_frag_proto; lhq.replace = 0; lhq.value = fmsg; @@ -730,17 +743,24 @@ nxt_port_frag_start(nxt_task_t *task, nxt_port_t *port, static nxt_port_recv_msg_t * -nxt_port_frag_find(nxt_task_t *task, nxt_port_t *port, uint32_t stream, - nxt_bool_t last) +nxt_port_frag_find(nxt_task_t *task, nxt_port_t *port, nxt_port_recv_msg_t *msg) { - nxt_int_t res; - nxt_lvlhsh_query_t lhq; + nxt_int_t res; + nxt_bool_t last; + nxt_lvlhsh_query_t lhq; + nxt_port_frag_key_t frag_key; + + last = msg->port_msg.mf == 0; + + nxt_debug(task, "%s frag stream #%uD", last ? "last" : "next", + msg->port_msg.stream); - nxt_debug(task, "%s frag stream #%uD", last ? "last" : "next", stream); + frag_key.stream = msg->port_msg.stream; + frag_key.pid = msg->port_msg.pid; - lhq.key_hash = nxt_murmur_hash2(&stream, sizeof(uint32_t)); - lhq.key.length = sizeof(uint32_t); - lhq.key.start = (u_char *) &stream; + lhq.key_hash = nxt_murmur_hash2(&frag_key, sizeof(nxt_port_frag_key_t)); + lhq.key.length = sizeof(nxt_port_frag_key_t); + lhq.key.start = (u_char *) &frag_key; lhq.proto = &lvlhsh_frag_proto; lhq.pool = port->mem_pool; @@ -753,7 +773,8 @@ nxt_port_frag_find(nxt_task_t *task, nxt_port_t *port, uint32_t stream, return lhq.value; default: - nxt_log(task, NXT_LOG_INFO, "frag stream #%uD not found", stream); + nxt_log(task, NXT_LOG_INFO, "frag stream #%uD not found", + frag_key.stream); return NULL; } @@ -793,8 +814,7 @@ nxt_port_read_msg_process(nxt_task_t *task, nxt_port_t *port, if (nxt_slow_path(msg->port_msg.nf != 0)) { - fmsg = nxt_port_frag_find(task, port, msg->port_msg.stream, - msg->port_msg.mf == 0); + fmsg = nxt_port_frag_find(task, port, msg); if (nxt_slow_path(fmsg == NULL)) { goto fmsg_failed; -- cgit From dccb4cf3548724fbec993c5bb83edf928d0b23bf Mon Sep 17 00:00:00 2001 From: Alexander Borisov Date: Wed, 6 Mar 2019 15:26:45 +0300 Subject: Removed unnecessary abstraction layer. --- src/nxt_application.c | 28 ------- src/nxt_application.h | 56 ------------- src/nxt_http.h | 4 + src/nxt_http_request.c | 82 ++----------------- src/nxt_router.c | 215 ++++++++++++++++++++++++++----------------------- src/nxt_router.h | 2 +- 6 files changed, 127 insertions(+), 260 deletions(-) (limited to 'src') diff --git a/src/nxt_application.c b/src/nxt_application.c index a2827b75..f63b90fb 100644 --- a/src/nxt_application.c +++ b/src/nxt_application.c @@ -36,8 +36,6 @@ static nxt_app_module_t *nxt_app_module_load(nxt_task_t *task, const char *name); static nxt_int_t nxt_app_set_environment(nxt_conf_value_t *environment); -static void nxt_app_http_release(nxt_task_t *task, void *obj, void *data); - static uint32_t compat[] = { NXT_VERNUM, NXT_DEBUG, @@ -431,32 +429,6 @@ nxt_app_set_environment(nxt_conf_value_t *environment) } -nxt_int_t -nxt_app_http_req_done(nxt_task_t *task, nxt_app_parse_ctx_t *ar) -{ - ar->timer.handler = nxt_app_http_release; - nxt_timer_add(task->thread->engine, &ar->timer, 0); - - return NXT_OK; -} - - -static void -nxt_app_http_release(nxt_task_t *task, void *obj, void *data) -{ - nxt_timer_t *timer; - nxt_app_parse_ctx_t *ar; - - timer = obj; - - nxt_debug(task, "http app release"); - - ar = nxt_timer_data(timer, nxt_app_parse_ctx_t, timer); - - nxt_mp_release(ar->request->mem_pool); -} - - nxt_app_lang_module_t * nxt_app_lang_module(nxt_runtime_t *rt, nxt_str_t *name) { diff --git a/src/nxt_application.h b/src/nxt_application.h index 781f05e0..7ff4bb11 100644 --- a/src/nxt_application.h +++ b/src/nxt_application.h @@ -99,62 +99,6 @@ struct nxt_common_app_conf_s { }; -typedef struct { - nxt_str_t method; - nxt_str_t target; - nxt_str_t version; - nxt_str_t path; - nxt_str_t query; - nxt_str_t server_name; - - nxt_list_t *fields; - - nxt_str_t cookie; - nxt_str_t content_length; - nxt_str_t content_type; - - off_t parsed_content_length; - nxt_bool_t done; - - size_t bufs; - nxt_buf_t *buf; -} nxt_app_request_header_t; - - -typedef struct { - size_t preread_size; - nxt_bool_t done; - - nxt_buf_t *buf; -} nxt_app_request_body_t; - - -typedef struct { - nxt_app_request_header_t header; - nxt_app_request_body_t body; - - nxt_str_t remote; - nxt_str_t local; -} nxt_app_request_t; - - -typedef struct nxt_app_parse_ctx_s nxt_app_parse_ctx_t; - - -struct nxt_app_parse_ctx_s { - nxt_app_request_t r; - nxt_http_request_t *request; - nxt_timer_t timer; - void *timer_data; - nxt_http_request_parse_t parser; - nxt_http_request_parse_t resp_parser; - nxt_mp_t *mem_pool; -}; - - -nxt_int_t nxt_app_http_req_done(nxt_task_t *task, nxt_app_parse_ctx_t *ctx); - - struct nxt_app_module_s { size_t compat_length; uint32_t *compat; diff --git a/src/nxt_http.h b/src/nxt_http.h index 23c406d3..3cf3e38e 100644 --- a/src/nxt_http.h +++ b/src/nxt_http.h @@ -114,6 +114,7 @@ struct nxt_http_request_s { const nxt_http_request_state_t *state; nxt_str_t host; + nxt_str_t server_name; nxt_str_t target; nxt_str_t version; nxt_str_t *method; @@ -131,6 +132,9 @@ struct nxt_http_request_s { nxt_sockaddr_t *remote; nxt_sockaddr_t *local; + nxt_timer_t timer; + void *timer_data; + nxt_buf_t *last; nxt_http_response_t resp; diff --git a/src/nxt_http_request.c b/src/nxt_http_request.c index 724b0808..3c763dd0 100644 --- a/src/nxt_http_request.c +++ b/src/nxt_http_request.c @@ -322,31 +322,17 @@ nxt_http_pass_t * nxt_http_request_application(nxt_task_t *task, nxt_http_request_t *r, nxt_http_pass_t *pass) { - nxt_int_t ret; - nxt_event_engine_t *engine; - nxt_app_parse_ctx_t *ar; + nxt_event_engine_t *engine; nxt_debug(task, "http request application"); - ar = nxt_mp_zget(r->mem_pool, sizeof(nxt_app_parse_ctx_t)); - if (nxt_slow_path(ar == NULL)) { - nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); - return NULL; - } - - ar->request = r; - ar->mem_pool = r->mem_pool; nxt_mp_retain(r->mem_pool); - // STUB engine = task->thread->engine; - ar->timer.task = &engine->task; - ar->timer.work_queue = &engine->fast_work_queue; - ar->timer.log = engine->task.log; - ar->timer.bias = NXT_TIMER_DEFAULT_BIAS; - - ar->r.remote.start = nxt_sockaddr_address(r->remote); - ar->r.remote.length = r->remote->address_length; + r->timer.task = &engine->task; + r->timer.work_queue = &engine->fast_work_queue; + r->timer.log = engine->task.log; + r->timer.bias = NXT_TIMER_DEFAULT_BIAS; /* * TODO: need an application flag to get local address @@ -354,66 +340,14 @@ nxt_http_request_application(nxt_task_t *task, nxt_http_request_t *r, */ nxt_http_request_local_addr(task, r); - if (nxt_fast_path(r->local != NULL)) { - ar->r.local.start = nxt_sockaddr_address(r->local); - ar->r.local.length = r->local->address_length; - } - - ar->r.header.fields = r->fields; - ar->r.header.done = 1; - ar->r.header.version = r->version; - - if (r->method != NULL) { - ar->r.header.method = *r->method; - } - if (r->host.length != 0) { - ar->r.header.server_name = r->host; + r->server_name = r->host; } else { - nxt_str_set(&ar->r.header.server_name, "localhost"); - } - - ar->r.header.target = r->target; - - if (r->path != NULL) { - ar->r.header.path = *r->path; - } - - if (r->args != NULL) { - ar->r.header.query = *r->args; - } - - if (r->content_type != NULL) { - ar->r.header.content_type.length = r->content_type->value_length; - ar->r.header.content_type.start = r->content_type->value; - } - - if (r->content_length != NULL) { - ar->r.header.content_length.length = r->content_length->value_length; - ar->r.header.content_length.start = r->content_length->value; - } - - if (r->cookie != NULL) { - ar->r.header.cookie.length = r->cookie->value_length; - ar->r.header.cookie.start = r->cookie->value; - } - - if (r->body != NULL) { - ar->r.body.buf = r->body; - ar->r.body.preread_size = r->content_length_n; - ar->r.header.parsed_content_length = r->content_length_n; - } - - ar->r.body.done = 1; - - ret = nxt_http_parse_request_init(&ar->resp_parser, r->mem_pool); - if (nxt_slow_path(ret != NXT_OK)) { - nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); - return NULL; + nxt_str_set(&r->server_name, "localhost"); } - nxt_router_process_http_request(task, ar, pass->u.application); + nxt_router_process_http_request(task, r, pass->u.application); return NULL; } diff --git a/src/nxt_router.c b/src/nxt_router.c index e46e8f82..0f56c885 100644 --- a/src/nxt_router.c +++ b/src/nxt_router.c @@ -62,7 +62,7 @@ typedef struct { uint32_t stream; nxt_app_t *app; nxt_port_t *app_port; - nxt_app_parse_ctx_t *ap; + nxt_http_request_t *request; nxt_msg_info_t msg_info; nxt_req_app_link_t *ra; @@ -75,7 +75,7 @@ struct nxt_req_app_link_s { nxt_atomic_t use_count; nxt_port_t *app_port; nxt_port_t *reply_port; - nxt_app_parse_ctx_t *ap; + nxt_http_request_t *request; nxt_msg_info_t msg_info; nxt_req_conn_link_t *rc; @@ -264,8 +264,8 @@ static nxt_int_t nxt_router_app_port(nxt_task_t *task, nxt_app_t *app, static void nxt_router_app_prepare_request(nxt_task_t *task, nxt_req_app_link_t *ra); -static nxt_buf_t *nxt_router_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, - nxt_port_t *port, const nxt_str_t *prefix); +static nxt_buf_t *nxt_router_prepare_msg(nxt_task_t *task, + nxt_http_request_t *r, nxt_port_t *port, const nxt_str_t *prefix); static void nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data); static void nxt_router_adjust_idle_timer(nxt_task_t *task, void *obj, @@ -282,6 +282,11 @@ static void nxt_http_request_send_body(nxt_task_t *task, void *obj, void *data); static void nxt_router_app_joint_use(nxt_task_t *task, nxt_app_joint_t *app_joint, int i); +static nxt_int_t nxt_router_http_request_done(nxt_task_t *task, + nxt_http_request_t *r); +static void nxt_router_http_request_release(nxt_task_t *task, void *obj, + void *data); + static nxt_router_t *nxt_router; static const nxt_str_t http_prefix = nxt_string("HTTP_"); @@ -502,7 +507,7 @@ nxt_router_ra_init(nxt_task_t *task, nxt_req_app_link_t *ra, ra->rc = rc; rc->ra = ra; ra->reply_port = engine->port; - ra->ap = rc->ap; + ra->request = rc->request; ra->work.handler = NULL; ra->work.task = &engine->task; @@ -521,7 +526,7 @@ nxt_router_ra_create(nxt_task_t *task, nxt_req_app_link_t *ra_src) return ra_src; } - mp = ra_src->ap->mem_pool; + mp = ra_src->request->mem_pool; ra = nxt_mp_alloc(mp, sizeof(nxt_req_app_link_t)); @@ -645,16 +650,16 @@ nxt_router_ra_release(nxt_task_t *task, nxt_req_app_link_t *ra) if (rc != NULL) { if (nxt_slow_path(ra->err_code != 0)) { - nxt_http_request_error(task, rc->ap->request, ra->err_code); + nxt_http_request_error(task, rc->request, ra->err_code); } else { rc->app_port = ra->app_port; rc->msg_info = ra->msg_info; if (rc->app->timeout != 0) { - rc->ap->timer.handler = nxt_router_app_timeout; - rc->ap->timer_data = rc; - nxt_timer_add(task->thread->engine, &rc->ap->timer, + rc->request->timer.handler = nxt_router_app_timeout; + rc->request->timer_data = rc; + nxt_timer_add(task->thread->engine, &rc->request->timer, rc->app->timeout); } @@ -817,12 +822,12 @@ nxt_router_rc_unlink(nxt_task_t *task, nxt_req_conn_link_t *rc) rc->app = NULL; } - if (rc->ap != NULL) { - rc->ap->timer_data = NULL; + if (rc->request != NULL) { + rc->request->timer_data = NULL; - nxt_app_http_req_done(task, rc->ap); + nxt_router_http_request_done(task, rc->request); - rc->ap = NULL; + rc->request = NULL; } } @@ -3380,9 +3385,10 @@ nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, size_t dump_size; nxt_int_t ret; nxt_buf_t *b; + nxt_unit_field_t *f; + nxt_http_field_t *field; nxt_http_request_t *r; nxt_req_conn_link_t *rc; - nxt_app_parse_ctx_t *ar; nxt_unit_response_t *resp; b = msg->buf; @@ -3398,12 +3404,12 @@ nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, b = NULL; } - ar = rc->ap; - if (nxt_slow_path(ar == NULL)) { + r = rc->request; + if (nxt_slow_path(r == NULL)) { return; } - if (ar->request->error) { + if (r->error) { nxt_router_rc_unlink(task, rc); return; } @@ -3411,15 +3417,15 @@ nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, if (msg->port_msg.last != 0) { nxt_debug(task, "router data create last buf"); - nxt_buf_chain_add(&b, nxt_http_buf_last(ar->request)); + nxt_buf_chain_add(&b, nxt_http_buf_last(r)); nxt_router_rc_unlink(task, rc); } else { if (rc->app != NULL && rc->app->timeout != 0) { - ar->timer.handler = nxt_router_app_timeout; - ar->timer_data = rc; - nxt_timer_add(task->thread->engine, &ar->timer, rc->app->timeout); + r->timer.handler = nxt_router_app_timeout; + r->timer_data = rc; + nxt_timer_add(task->thread->engine, &r->timer, rc->app->timeout); } } @@ -3432,8 +3438,6 @@ nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, msg->buf = NULL; } - r = ar->request; - if (r->header_sent) { nxt_buf_chain_add(&r->out, b); nxt_http_request_send_body(task, r, NULL); @@ -3451,11 +3455,8 @@ nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, goto fail; } - nxt_unit_field_t *f; - nxt_http_field_t *field; - for (f = resp->fields; f < resp->fields + resp->fields_count; f++) { - field = nxt_list_add(ar->resp_parser.fields); + field = nxt_list_add(r->resp.fields); if (nxt_slow_path(field == NULL)) { goto fail; @@ -3473,15 +3474,8 @@ nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, (size_t) field->name_length, field->name, (size_t) field->value_length, field->value); } - r->status = resp->status; -/* - ret = nxt_http_parse_fields(&ar->resp_parser, &b->mem); - if (nxt_slow_path(ret != NXT_DONE)) { - goto fail; - } -*/ - r->resp.fields = ar->resp_parser.fields; + r->status = resp->status; ret = nxt_http_fields_process(r->resp.fields, &nxt_response_fields_hash, r); @@ -3590,8 +3584,8 @@ nxt_router_response_error_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, } } - if (rc->ap != NULL) { - nxt_http_request_error(task, rc->ap->request, + if (rc->request != NULL) { + nxt_http_request_error(task, rc->request, NXT_HTTP_SERVICE_UNAVAILABLE); } @@ -4452,17 +4446,15 @@ nxt_router_app_port(nxt_task_t *task, nxt_app_t *app, nxt_req_app_link_t *ra) void -nxt_router_process_http_request(nxt_task_t *task, nxt_app_parse_ctx_t *ar, +nxt_router_process_http_request(nxt_task_t *task, nxt_http_request_t *r, nxt_app_t *app) { nxt_int_t res; nxt_port_t *port; nxt_event_engine_t *engine; - nxt_http_request_t *r; nxt_req_app_link_t ra_local, *ra; nxt_req_conn_link_t *rc; - r = ar->request; engine = task->thread->engine; rc = nxt_port_rpc_register_handler_ex(task, engine->port, @@ -4480,7 +4472,7 @@ nxt_router_process_http_request(nxt_task_t *task, nxt_app_parse_ctx_t *ar, nxt_router_app_use(task, app, 1); - rc->ap = ar; + rc->request = r; ra = &ra_local; nxt_router_ra_init(task, ra, rc); @@ -4511,17 +4503,15 @@ nxt_router_dummy_buf_completion(nxt_task_t *task, void *obj, void *data) static void nxt_router_app_prepare_request(nxt_task_t *task, nxt_req_app_link_t *ra) { - uint32_t request_failed; - nxt_buf_t *buf; - nxt_int_t res; - nxt_port_t *port, *c_port, *reply_port; - nxt_app_parse_ctx_t *ap; + uint32_t request_failed; + nxt_buf_t *buf; + nxt_int_t res; + nxt_port_t *port, *c_port, *reply_port; nxt_assert(ra->app_port != NULL); port = ra->app_port; reply_port = ra->reply_port; - ap = ra->ap; request_failed = 1; @@ -4539,7 +4529,7 @@ nxt_router_app_prepare_request(nxt_task_t *task, nxt_req_app_link_t *ra) nxt_process_connected_port_add(port->process, reply_port); } - buf = nxt_router_prepare_msg(task, &ap->r, port, + buf = nxt_router_prepare_msg(task, ra->request, port, nxt_app_msg_prefix[port->app->type]); if (nxt_slow_path(buf == NULL)) { @@ -4642,34 +4632,33 @@ nxt_fields_next(nxt_fields_iter_t *i) static nxt_buf_t * -nxt_router_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, +nxt_router_prepare_msg(nxt_task_t *task, nxt_http_request_t *r, nxt_port_t *port, const nxt_str_t *prefix) { - void *target_pos, *query_pos; - u_char *pos, *end, *p, c; - size_t fields_count, req_size, size, free_size; - size_t copy_size; - nxt_buf_t *b, *buf, *out, **tail; - nxt_http_field_t *field, *dup; - nxt_unit_field_t *dst_field; - nxt_fields_iter_t iter, dup_iter; - nxt_unit_request_t *req; - nxt_app_request_header_t *h; - - h = &r->header; + void *target_pos, *query_pos; + u_char *pos, *end, *p, c; + size_t fields_count, req_size, size, free_size; + size_t copy_size; + nxt_off_t content_length; + nxt_buf_t *b, *buf, *out, **tail; + nxt_http_field_t *field, *dup; + nxt_unit_field_t *dst_field; + nxt_fields_iter_t iter, dup_iter; + nxt_unit_request_t *req; req_size = sizeof(nxt_unit_request_t) - + h->method.length + 1 - + h->version.length + 1 - + r->remote.length + 1 - + r->local.length + 1 - + h->server_name.length + 1 - + h->target.length + 1 - + (h->path.start != h->target.start ? h->path.length + 1 : 0); - + + r->method->length + 1 + + r->version.length + 1 + + r->remote->length + 1 + + r->local->length + 1 + + r->server_name.length + 1 + + r->target.length + 1 + + (r->path->start != r->target.start ? r->path->length + 1 : 0); + + content_length = r->content_length_n < 0 ? 0 : r->content_length_n; fields_count = 0; - nxt_list_each(field, h->fields) { + nxt_list_each(field, r->fields) { fields_count++; req_size += field->name_length + prefix->length + 1 @@ -4686,7 +4675,7 @@ nxt_router_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, } out = nxt_port_mmap_get_buf(task, port, - nxt_min(req_size + r->body.preread_size, PORT_MMAP_DATA_SIZE)); + nxt_min(req_size + content_length, PORT_MMAP_DATA_SIZE)); if (nxt_slow_path(out == NULL)) { return NULL; } @@ -4694,57 +4683,58 @@ nxt_router_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, req = (nxt_unit_request_t *) out->mem.free; out->mem.free += req_size; - req->content_length = h->parsed_content_length; + req->content_length = content_length; p = (u_char *) (req->fields + fields_count); nxt_debug(task, "fields_count=%d", (int) fields_count); - req->method_length = h->method.length; + req->method_length = r->method->length; nxt_unit_sptr_set(&req->method, p); - p = nxt_cpymem(p, h->method.start, h->method.length); + p = nxt_cpymem(p, r->method->start, r->method->length); *p++ = '\0'; - req->version_length = h->version.length; + req->version_length = r->version.length; nxt_unit_sptr_set(&req->version, p); - p = nxt_cpymem(p, h->version.start, h->version.length); + p = nxt_cpymem(p, r->version.start, r->version.length); *p++ = '\0'; - req->remote_length = r->remote.length; + req->remote_length = r->remote->address_length; nxt_unit_sptr_set(&req->remote, p); - p = nxt_cpymem(p, r->remote.start, r->remote.length); + p = nxt_cpymem(p, nxt_sockaddr_address(r->remote), + r->remote->address_length); *p++ = '\0'; - req->local_length = r->local.length; + req->local_length = r->local->address_length; nxt_unit_sptr_set(&req->local, p); - p = nxt_cpymem(p, r->local.start, r->local.length); + p = nxt_cpymem(p, nxt_sockaddr_address(r->local), r->local->address_length); *p++ = '\0'; - req->server_name_length = h->server_name.length; + req->server_name_length = r->server_name.length; nxt_unit_sptr_set(&req->server_name, p); - p = nxt_cpymem(p, h->server_name.start, h->server_name.length); + p = nxt_cpymem(p, r->server_name.start, r->server_name.length); *p++ = '\0'; target_pos = p; - req->target_length = h->target.length; + req->target_length = (uint32_t) r->target.length; nxt_unit_sptr_set(&req->target, p); - p = nxt_cpymem(p, h->target.start, h->target.length); + p = nxt_cpymem(p, r->target.start, r->target.length); *p++ = '\0'; - req->path_length = h->path.length; - if (h->path.start == h->target.start) { + req->path_length = (uint32_t) r->path->length; + if (r->path->start == r->target.start) { nxt_unit_sptr_set(&req->path, target_pos); } else { nxt_unit_sptr_set(&req->path, p); - p = nxt_cpymem(p, h->path.start, h->path.length); + p = nxt_cpymem(p, r->path->start, r->path->length); *p++ = '\0'; } - req->query_length = h->query.length; - if (h->query.start != NULL) { + req->query_length = r->args != NULL ? (uint32_t) r->args->length : 0; + if (r->args != NULL && r->args->start != NULL) { query_pos = nxt_pointer_to(target_pos, - h->query.start - h->target.start); + r->args->start - r->target.start); nxt_unit_sptr_set(&req->query, query_pos); @@ -4758,7 +4748,7 @@ nxt_router_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, dst_field = req->fields; - for (field = nxt_fields_first(h->fields, &iter); + for (field = nxt_fields_first(r->fields, &iter); field != NULL; field = nxt_fields_next(&iter)) { @@ -4771,13 +4761,13 @@ nxt_router_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, dst_field->name_length = field->name_length + prefix->length; dst_field->value_length = field->value_length; - if (field->value == h->content_length.start) { + if (field == r->content_length) { req->content_length_field = dst_field - req->fields; - } else if (field->value == h->content_type.start) { + } else if (field == r->content_type) { req->content_type_field = dst_field - req->fields; - } else if (field->value == h->cookie.start) { + } else if (field == r->cookie) { req->cookie_field = dst_field - req->fields; } @@ -4846,14 +4836,14 @@ nxt_router_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, dst_field++; } - req->fields_count = dst_field - req->fields; + req->fields_count = (uint32_t) (dst_field - req->fields); nxt_unit_sptr_set(&req->preread_content, out->mem.free); buf = out; tail = &buf->next; - for (b = r->body.buf; b != NULL; b = b->next) { + for (b = r->body; b != NULL; b = b->next) { size = nxt_buf_mem_used_size(&b->mem); pos = b->mem.pos; @@ -4913,8 +4903,8 @@ nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data) nxt_port_t *port; nxt_timer_t *timer; nxt_queue_link_t *lnk; + nxt_http_request_t *r; nxt_req_app_link_t *pending_ra; - nxt_app_parse_ctx_t *ar; nxt_req_conn_link_t *rc; nxt_port_select_state_t state; @@ -4922,8 +4912,8 @@ nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data) nxt_debug(task, "router app timeout"); - ar = nxt_timer_data(timer, nxt_app_parse_ctx_t, timer); - rc = ar->timer_data; + r = nxt_timer_data(timer, nxt_http_request_t, timer); + rc = r->timer_data; app = rc->app; if (app == NULL) { @@ -4994,7 +4984,30 @@ nxt_router_app_timeout(nxt_task_t *task, void *obj, void *data) generate_error: - nxt_http_request_error(task, ar->request, NXT_HTTP_SERVICE_UNAVAILABLE); + nxt_http_request_error(task, r, NXT_HTTP_SERVICE_UNAVAILABLE); nxt_router_rc_unlink(task, rc); } + + +static nxt_int_t +nxt_router_http_request_done(nxt_task_t *task, nxt_http_request_t *r) +{ + r->timer.handler = nxt_router_http_request_release; + nxt_timer_add(task->thread->engine, &r->timer, 0); + + return NXT_OK; +} + + +static void +nxt_router_http_request_release(nxt_task_t *task, void *obj, void *data) +{ + nxt_http_request_t *r; + + nxt_debug(task, "http app release"); + + r = nxt_timer_data(obj, nxt_http_request_t, timer); + + nxt_mp_release(r->mem_pool); +} diff --git a/src/nxt_router.h b/src/nxt_router.h index dec56bd5..a876b9a4 100644 --- a/src/nxt_router.h +++ b/src/nxt_router.h @@ -192,7 +192,7 @@ void nxt_router_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg); void nxt_router_access_log_reopen_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg); -void nxt_router_process_http_request(nxt_task_t *task, nxt_app_parse_ctx_t *ar, +void nxt_router_process_http_request(nxt_task_t *task, nxt_http_request_t *r, nxt_app_t *app); void nxt_router_app_port_close(nxt_task_t *task, nxt_port_t *port); nxt_app_t *nxt_router_listener_application(nxt_router_temp_conf_t *tmcf, -- cgit From 22de5fcddfacd8d241ae2926125e0151b9e6e651 Mon Sep 17 00:00:00 2001 From: Andrey Zelenkov Date: Mon, 11 Mar 2019 17:31:59 +0300 Subject: Style. --- src/java/nginx/unit/Context.java | 6 +++--- src/nodejs/unit-http/unit.cpp | 2 +- src/nxt_buf.h | 2 +- src/nxt_epoll_engine.c | 2 +- src/nxt_hpux_sendfile.c | 4 ++-- src/nxt_http_parse.c | 2 +- src/nxt_job_resolve.c | 16 ++++++++-------- src/nxt_kqueue_engine.c | 2 +- src/nxt_main_process.c | 2 +- src/nxt_php_sapi.c | 2 +- src/nxt_poll_engine.c | 2 +- src/nxt_port.c | 2 +- src/nxt_port_memory.c | 4 ++-- src/nxt_sockaddr.c | 16 ++++++++-------- src/nxt_socket.h | 4 ++-- src/nxt_socketpair.c | 4 ++-- src/nxt_sprintf.c | 12 ++++++------ src/nxt_timer.h | 2 +- src/nxt_unicode_lowcase.pl | 6 +++--- src/nxt_unit.c | 4 ++-- 20 files changed, 48 insertions(+), 48 deletions(-) (limited to 'src') diff --git a/src/java/nginx/unit/Context.java b/src/java/nginx/unit/Context.java index 643a336b..f6d5e339 100644 --- a/src/java/nginx/unit/Context.java +++ b/src/java/nginx/unit/Context.java @@ -306,7 +306,7 @@ public class Context implements ServletContext, InitParams PrintWriter writer = response.getWriter(); for (String n : ls) { - writer.println("" + n + "
"); + writer.println("" + n + "
"); } writer.close(); @@ -547,7 +547,7 @@ public class Context implements ServletContext, InitParams j = j.getParent(); } } - system_loader = j; + system_loader = j; } private boolean isSystemPath(String path) @@ -1733,7 +1733,7 @@ public class Context implements ServletContext, InitParams @Override public FileVisitResult visitFile( - Path file, BasicFileAttributes attrs) + Path file, BasicFileAttributes attrs) throws IOException { Files.delete(file); return FileVisitResult.CONTINUE; diff --git a/src/nodejs/unit-http/unit.cpp b/src/nodejs/unit-http/unit.cpp index 60b0412a..dcff1186 100644 --- a/src/nodejs/unit-http/unit.cpp +++ b/src/nodejs/unit-http/unit.cpp @@ -467,7 +467,7 @@ Unit::add_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port) } -inline bool +inline bool operator == (const nxt_unit_port_id_t &p1, const nxt_unit_port_id_t &p2) { return p1.pid == p2.pid && p1.id == p2.id; diff --git a/src/nxt_buf.h b/src/nxt_buf.h index d9d4ee1b..9c22d650 100644 --- a/src/nxt_buf.h +++ b/src/nxt_buf.h @@ -206,7 +206,7 @@ nxt_buf_set_last(b) \ #define \ nxt_buf_clear_last(b) \ - (b)->is_last = 0 + (b)->is_last = 0 #define \ diff --git a/src/nxt_epoll_engine.c b/src/nxt_epoll_engine.c index 9f9c8f62..9cdaab9b 100644 --- a/src/nxt_epoll_engine.c +++ b/src/nxt_epoll_engine.c @@ -1059,7 +1059,7 @@ nxt_epoll_edge_conn_io_connect(nxt_task_t *task, void *obj, void *data) state = c->write_state; - switch (nxt_socket_connect(task, c->socket.fd, c->remote) ){ + switch (nxt_socket_connect(task, c->socket.fd, c->remote)) { case NXT_OK: c->socket.write_ready = 1; diff --git a/src/nxt_hpux_sendfile.c b/src/nxt_hpux_sendfile.c index 3c42c559..df200b64 100644 --- a/src/nxt_hpux_sendfile.c +++ b/src/nxt_hpux_sendfile.c @@ -13,7 +13,7 @@ ssize_t nxt_hpux_event_conn_io_sendfile(nxt_event_conn_t *c, nxt_buf_t *b, size_t limit); static ssize_t nxt_sys_sendfile(int s, int fd, off_t offset, size_t nbytes, - const struct iovec *hdtrl, int flags) + const struct iovec *hdtrl, int flags) { return -1; } @@ -23,7 +23,7 @@ static ssize_t nxt_sys_sendfile(int s, int fd, off_t offset, size_t nbytes, /* sendfile() is not declared if _XOPEN_SOURCE_EXTENDED is defined. */ sbsize_t sendfile(int s, int fd, off_t offset, bsize_t nbytes, - const struct iovec *hdtrl, int flags); + const struct iovec *hdtrl, int flags); #define nxt_sys_sendfile sendfile diff --git a/src/nxt_http_parse.c b/src/nxt_http_parse.c index 34eaaaf9..64e4bf35 100644 --- a/src/nxt_http_parse.c +++ b/src/nxt_http_parse.c @@ -119,7 +119,7 @@ nxt_http_parse_request_init(nxt_http_request_parse_t *rp, nxt_mp_t *mp) rp->mem_pool = mp; rp->fields = nxt_list_create(mp, 8, sizeof(nxt_http_field_t)); - if (nxt_slow_path(rp->fields == NULL)){ + if (nxt_slow_path(rp->fields == NULL)) { return NXT_ERROR; } diff --git a/src/nxt_job_resolve.c b/src/nxt_job_resolve.c index a1317756..0f1fb9aa 100644 --- a/src/nxt_job_resolve.c +++ b/src/nxt_job_resolve.c @@ -59,11 +59,11 @@ nxt_job_resolve(nxt_job_resolve_t *jbr) case AF_INET6: #endif case AF_INET: - n++; - break; + n++; + break; default: - break; + break; } } @@ -81,15 +81,15 @@ nxt_job_resolve(nxt_job_resolve_t *jbr) switch (r->ai_addr->sa_family) { #if (NXT_INET6) case AF_INET6: - length = NXT_INET6_ADDR_STR_LEN; - break; + length = NXT_INET6_ADDR_STR_LEN; + break; #endif case AF_INET: - length = NXT_INET_ADDR_STR_LEN; - break; + length = NXT_INET_ADDR_STR_LEN; + break; default: - continue; + continue; } sa = nxt_sockaddr_create(mp, r->ai_addr, r->ai_addrlen, length); diff --git a/src/nxt_kqueue_engine.c b/src/nxt_kqueue_engine.c index 0e68fbdc..0212b331 100644 --- a/src/nxt_kqueue_engine.c +++ b/src/nxt_kqueue_engine.c @@ -856,7 +856,7 @@ nxt_kqueue_conn_io_connect(nxt_task_t *task, void *obj, void *data) state = c->write_state; - switch (nxt_socket_connect(task, c->socket.fd, c->remote) ){ + switch (nxt_socket_connect(task, c->socket.fd, c->remote)) { case NXT_OK: c->socket.write_ready = 1; diff --git a/src/nxt_main_process.c b/src/nxt_main_process.c index f756bff7..40682eb9 100644 --- a/src/nxt_main_process.c +++ b/src/nxt_main_process.c @@ -842,7 +842,7 @@ nxt_main_process_sigusr1_handler(nxt_task_t *task, void *obj, void *data) nxt_mp_destroy(mp); return; - } + } fail: diff --git a/src/nxt_php_sapi.c b/src/nxt_php_sapi.c index 80321a85..4b71de5c 100644 --- a/src/nxt_php_sapi.c +++ b/src/nxt_php_sapi.c @@ -699,7 +699,7 @@ fail: static int nxt_php_startup(sapi_module_struct *sapi_module) { - return php_module_startup(sapi_module, NULL, 0); + return php_module_startup(sapi_module, NULL, 0); } diff --git a/src/nxt_poll_engine.c b/src/nxt_poll_engine.c index acb44a22..f514e0a9 100644 --- a/src/nxt_poll_engine.c +++ b/src/nxt_poll_engine.c @@ -370,7 +370,7 @@ nxt_poll_commit_changes(nxt_event_engine_t *engine) retval = NXT_ERROR; - next: + next: change++; diff --git a/src/nxt_port.c b/src/nxt_port.c index 30719ad3..aff46666 100644 --- a/src/nxt_port.c +++ b/src/nxt_port.c @@ -510,7 +510,7 @@ nxt_port_post(nxt_task_t *task, nxt_port_t *port, pw = nxt_zalloc(sizeof(nxt_port_work_t)); if (nxt_slow_path(pw == NULL)) { - return NXT_ERROR; + return NXT_ERROR; } nxt_atomic_fetch_add(&port->use_count, 1); diff --git a/src/nxt_port_memory.c b/src/nxt_port_memory.c index 774f1f33..b908041c 100644 --- a/src/nxt_port_memory.c +++ b/src/nxt_port_memory.c @@ -49,10 +49,10 @@ nxt_port_mmap_at(nxt_port_mmaps_t *port_mmaps, uint32_t i) while (i + 1 > cap) { if (cap < 16) { - cap = cap * 2; + cap = cap * 2; } else { - cap = cap + cap / 2; + cap = cap + cap / 2; } } diff --git a/src/nxt_sockaddr.c b/src/nxt_sockaddr.c index a001c730..99cf54b4 100644 --- a/src/nxt_sockaddr.c +++ b/src/nxt_sockaddr.c @@ -197,23 +197,23 @@ nxt_getsockname(nxt_task_t *task, nxt_mp_t *mp, nxt_socket_t s) switch (sockaddr.buf.sa_family) { #if (NXT_INET6) case AF_INET6: - length = NXT_INET6_ADDR_STR_LEN; - break; + length = NXT_INET6_ADDR_STR_LEN; + break; #endif #if (NXT_HAVE_UNIX_DOMAIN) case AF_UNIX: - length = nxt_length("unix:") + socklen; + length = nxt_length("unix:") + socklen; #endif - break; + break; case AF_INET: - length = NXT_INET_ADDR_STR_LEN; - break; + length = NXT_INET_ADDR_STR_LEN; + break; default: - length = 0; - break; + length = 0; + break; } return nxt_sockaddr_create(mp, &sockaddr.buf, socklen, length); diff --git a/src/nxt_socket.h b/src/nxt_socket.h index 42ef6c53..3f00648d 100644 --- a/src/nxt_socket.h +++ b/src/nxt_socket.h @@ -112,9 +112,9 @@ NXT_EXPORT nxt_int_t nxt_socketpair_create(nxt_task_t *task, nxt_socket_t *pair); NXT_EXPORT void nxt_socketpair_close(nxt_task_t *task, nxt_socket_t *pair); NXT_EXPORT ssize_t nxt_socketpair_send(nxt_fd_event_t *ev, nxt_fd_t fd, - nxt_iobuf_t *iob, nxt_uint_t niob); + nxt_iobuf_t *iob, nxt_uint_t niob); NXT_EXPORT ssize_t nxt_socketpair_recv(nxt_fd_event_t *ev, nxt_fd_t *fd, - nxt_iobuf_t *iob, nxt_uint_t niob); + nxt_iobuf_t *iob, nxt_uint_t niob); #define \ diff --git a/src/nxt_socketpair.c b/src/nxt_socketpair.c index 0adbe1f6..10ea562e 100644 --- a/src/nxt_socketpair.c +++ b/src/nxt_socketpair.c @@ -21,9 +21,9 @@ static ssize_t nxt_sendmsg(nxt_socket_t s, nxt_fd_t fd, nxt_iobuf_t *iob, - nxt_uint_t niob); + nxt_uint_t niob); static ssize_t nxt_recvmsg(nxt_socket_t s, nxt_fd_t *fd, nxt_iobuf_t *iob, - nxt_uint_t niob); + nxt_uint_t niob); nxt_int_t diff --git a/src/nxt_sprintf.c b/src/nxt_sprintf.c index 0b387883..240f47ef 100644 --- a/src/nxt_sprintf.c +++ b/src/nxt_sprintf.c @@ -76,12 +76,12 @@ nxt_sprintf(u_char *buf, u_char *end, const char *fmt, ...) */ typedef struct { - u_char *end; - const u_char *hex; - uint32_t width; - int32_t frac_width; - uint8_t max_width; - u_char padding; + u_char *end; + const u_char *hex; + uint32_t width; + int32_t frac_width; + uint8_t max_width; + u_char padding; } nxt_sprintf_t; diff --git a/src/nxt_timer.h b/src/nxt_timer.h index 4199f0dd..3ccff848 100644 --- a/src/nxt_timer.h +++ b/src/nxt_timer.h @@ -69,7 +69,7 @@ typedef struct { nxt_uint_t mchanges; nxt_uint_t nchanges; - nxt_timer_change_t *changes; + nxt_timer_change_t *changes; } nxt_timers_t; diff --git a/src/nxt_unicode_lowcase.pl b/src/nxt_unicode_lowcase.pl index 974ae23a..abf64965 100644 --- a/src/nxt_unicode_lowcase.pl +++ b/src/nxt_unicode_lowcase.pl @@ -29,9 +29,9 @@ my $last_block_size = $max_lowcase % BLOCK_SIZE + 1; for my $block (sort { $a <=> $b } keys %blocks) { - if ($max_block < $block) { - $max_block = $block; - } + if ($max_block < $block) { + $max_block = $block; + } } diff --git a/src/nxt_unit.c b/src/nxt_unit.c index 6339aec5..88c7fa6a 100644 --- a/src/nxt_unit.c +++ b/src/nxt_unit.c @@ -1946,10 +1946,10 @@ nxt_unit_mmap_at(nxt_unit_mmaps_t *mmaps, uint32_t i) while (i + 1 > cap) { if (cap < 16) { - cap = cap * 2; + cap = cap * 2; } else { - cap = cap + cap / 2; + cap = cap + cap / 2; } } -- cgit From f49379215a0177ebf14aab7185bdbf8bc2f76f47 Mon Sep 17 00:00:00 2001 From: Max Romanov Date: Mon, 18 Mar 2019 19:55:34 +0300 Subject: Setting request error flag in error handler. Absence of this flag is the reason of memory leak in case when client disconnected before receiving all response data. --- src/nxt_http_request.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/nxt_http_request.c b/src/nxt_http_request.c index 3c763dd0..7ba2dfd5 100644 --- a/src/nxt_http_request.c +++ b/src/nxt_http_request.c @@ -523,6 +523,8 @@ nxt_http_request_error_handler(nxt_task_t *task, void *obj, void *data) nxt_debug(task, "http request error handler"); + r->error = 1; + if (proto.any != NULL) { nxt_http_proto_discard[r->protocol](task, r, nxt_http_buf_last(r)); } -- cgit From 39e147a858e7d135aa224a308b4d41061e00c296 Mon Sep 17 00:00:00 2001 From: Max Romanov Date: Mon, 18 Mar 2019 19:55:39 +0300 Subject: Removing unused local variable. --- src/nxt_router.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'src') diff --git a/src/nxt_router.c b/src/nxt_router.c index 0f56c885..f546887b 100644 --- a/src/nxt_router.c +++ b/src/nxt_router.c @@ -3382,7 +3382,6 @@ static void nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data) { - size_t dump_size; nxt_int_t ret; nxt_buf_t *b; nxt_unit_field_t *f; @@ -3394,12 +3393,6 @@ nxt_router_response_ready_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, b = msg->buf; rc = data; - dump_size = nxt_buf_used_size(b); - - if (dump_size > 300) { - dump_size = 300; - } - if (msg->size == 0) { b = NULL; } -- cgit From 452ce0789e8e8f1ac98cc0ed7efce03656a3d616 Mon Sep 17 00:00:00 2001 From: Max Romanov Date: Thu, 21 Mar 2019 13:55:57 +0300 Subject: Adjusting request schema value according to connection tls state. This closes #223 issue on GitHub. --- src/go/unit/nxt_cgo_lib.c | 4 ++++ src/go/unit/request.go | 7 +++++++ src/java/nginx/unit/Request.java | 6 ++++-- src/java/nxt_jni_Request.c | 17 +++++++++++++++++ src/nxt_h1proto.c | 17 +++++++++++++++++ src/nxt_http.h | 4 +++- src/nxt_http_request.c | 15 +++++++++------ src/nxt_php_sapi.c | 4 ++++ src/nxt_python_wsgi.c | 27 +++++++-------------------- src/nxt_router.c | 2 ++ src/nxt_unit_request.h | 1 + src/perl/nxt_perl_psgi.c | 5 ++++- src/ruby/nxt_ruby.c | 4 +++- 13 files changed, 82 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/go/unit/nxt_cgo_lib.c b/src/go/unit/nxt_cgo_lib.c index 98a23482..cc1228f5 100644 --- a/src/go/unit/nxt_cgo_lib.c +++ b/src/go/unit/nxt_cgo_lib.c @@ -83,6 +83,10 @@ nxt_cgo_request_handler(nxt_unit_request_info_t *req) nxt_go_request_set_remote_addr(go_req, nxt_cgo_str_init(&remote_addr, &r->remote, r->remote_length)); + if (r->tls) { + nxt_go_request_set_tls(go_req); + } + nxt_go_request_handler(go_req, (uintptr_t) req->unit->data); } diff --git a/src/go/unit/request.go b/src/go/unit/request.go index 829a2c64..ad56cabb 100644 --- a/src/go/unit/request.go +++ b/src/go/unit/request.go @@ -14,6 +14,7 @@ import ( "io" "net/http" "net/url" + "crypto/tls" "unsafe" ) @@ -125,6 +126,12 @@ func nxt_go_request_set_remote_addr(go_req uintptr, addr *C.nxt_cgo_str_t) { get_request(go_req).req.RemoteAddr = C.GoStringN(addr.start, addr.length) } +//export nxt_go_request_set_tls +func nxt_go_request_set_tls(go_req uintptr) { + + get_request(go_req).req.TLS = &tls.ConnectionState{ } +} + //export nxt_go_request_handler func nxt_go_request_handler(go_req uintptr, h uintptr) { r := get_request(go_req) diff --git a/src/java/nginx/unit/Request.java b/src/java/nginx/unit/Request.java index dc73c656..b46d3f59 100644 --- a/src/java/nginx/unit/Request.java +++ b/src/java/nginx/unit/Request.java @@ -980,11 +980,13 @@ public class Request implements HttpServletRequest, DynamicPathRequest @Override public boolean isSecure() { - log("isSecure"); + trace("isSecure"); - return false; + return isSecure(req_ptr); } + private static native boolean isSecure(long req_ptr); + @Override public void removeAttribute(String name) { diff --git a/src/java/nxt_jni_Request.c b/src/java/nxt_jni_Request.c index 6fb9cb44..a9fbe0e4 100644 --- a/src/java/nxt_jni_Request.c +++ b/src/java/nxt_jni_Request.c @@ -56,6 +56,8 @@ static jstring JNICALL nxt_java_Request_getServerName(JNIEnv *env, jclass cls, jlong req_ptr); static jint JNICALL nxt_java_Request_getServerPort(JNIEnv *env, jclass cls, jlong req_ptr); +static jboolean JNICALL nxt_java_Request_isSecure(JNIEnv *env, jclass cls, + jlong req_ptr); static void JNICALL nxt_java_Request_log(JNIEnv *env, jclass cls, jlong req_info_ptr, jstring msg, jint msg_len); static void JNICALL nxt_java_Request_trace(JNIEnv *env, jclass cls, @@ -166,6 +168,10 @@ nxt_java_initRequest(JNIEnv *env, jobject cl) (char *) "(J)I", nxt_java_Request_getServerPort }, + { (char *) "isSecure", + (char *) "(J)Z", + nxt_java_Request_isSecure }, + { (char *) "log", (char *) "(JLjava/lang/String;I)V", nxt_java_Request_log }, @@ -603,6 +609,17 @@ nxt_java_Request_getServerPort(JNIEnv *env, jclass cls, jlong req_ptr) } +static jboolean JNICALL +nxt_java_Request_isSecure(JNIEnv *env, jclass cls, jlong req_ptr) +{ + nxt_unit_request_t *r; + + r = nxt_jlong2ptr(req_ptr); + + return r->tls != 0; +} + + static void JNICALL nxt_java_Request_log(JNIEnv *env, jclass cls, jlong req_info_ptr, jstring msg, jint msg_len) diff --git a/src/nxt_h1proto.c b/src/nxt_h1proto.c index 07e3c7bc..3a822042 100644 --- a/src/nxt_h1proto.c +++ b/src/nxt_h1proto.c @@ -35,6 +35,7 @@ static void nxt_h1p_request_body_read(nxt_task_t *task, nxt_http_request_t *r); static void nxt_h1p_conn_request_body_read(nxt_task_t *task, void *obj, void *data); static void nxt_h1p_request_local_addr(nxt_task_t *task, nxt_http_request_t *r); +static void nxt_h1p_request_tls(nxt_task_t *task, nxt_http_request_t *r); static void nxt_h1p_request_header_send(nxt_task_t *task, nxt_http_request_t *r); static void nxt_h1p_request_send(nxt_task_t *task, nxt_http_request_t *r, @@ -103,6 +104,13 @@ const nxt_http_proto_local_addr_t nxt_http_proto_local_addr[3] = { }; +const nxt_http_proto_tls_t nxt_http_proto_tls[3] = { + nxt_h1p_request_tls, + NULL, + NULL, +}; + + const nxt_http_proto_header_send_t nxt_http_proto_header_send[3] = { nxt_h1p_request_header_send, NULL, @@ -813,6 +821,15 @@ nxt_h1p_request_local_addr(nxt_task_t *task, nxt_http_request_t *r) } +static void +nxt_h1p_request_tls(nxt_task_t *task, nxt_http_request_t *r) +{ +#if (NXT_TLS) + r->tls = r->proto.h1->conn->u.tls; +#endif +} + + #define NXT_HTTP_LAST_SUCCESS \ (NXT_HTTP_OK + nxt_nitems(nxt_http_success) - 1) diff --git a/src/nxt_http.h b/src/nxt_http.h index 3cf3e38e..00c13599 100644 --- a/src/nxt_http.h +++ b/src/nxt_http.h @@ -131,6 +131,7 @@ struct nxt_http_request_s { nxt_sockaddr_t *remote; nxt_sockaddr_t *local; + void *tls; nxt_timer_t timer; void *timer_data; @@ -169,6 +170,7 @@ typedef void (*nxt_http_proto_body_read_t)(nxt_task_t *task, nxt_http_request_t *r); typedef void (*nxt_http_proto_local_addr_t)(nxt_task_t *task, nxt_http_request_t *r); +typedef void (*nxt_http_proto_tls_t)(nxt_task_t *task, nxt_http_request_t *r); typedef void (*nxt_http_proto_header_send_t)(nxt_task_t *task, nxt_http_request_t *r); typedef void (*nxt_http_proto_send_t)(nxt_task_t *task, nxt_http_request_t *r, @@ -190,7 +192,6 @@ nxt_http_request_t *nxt_http_request_create(nxt_task_t *task); void nxt_http_request_error(nxt_task_t *task, nxt_http_request_t *r, nxt_http_status_t status); void nxt_http_request_read_body(nxt_task_t *task, nxt_http_request_t *r); -void nxt_http_request_local_addr(nxt_task_t *task, nxt_http_request_t *r); void nxt_http_request_header_send(nxt_task_t *task, nxt_http_request_t *r); void nxt_http_request_send(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *out); @@ -225,6 +226,7 @@ extern nxt_lvlhsh_t nxt_response_fields_hash; extern const nxt_http_proto_body_read_t nxt_http_proto_body_read[]; extern const nxt_http_proto_local_addr_t nxt_http_proto_local_addr[]; +extern const nxt_http_proto_tls_t nxt_http_proto_tls[]; extern const nxt_http_proto_header_send_t nxt_http_proto_header_send[]; extern const nxt_http_proto_send_t nxt_http_proto_send[]; extern const nxt_http_proto_body_bytes_sent_t nxt_http_proto_body_bytes_sent[]; diff --git a/src/nxt_http_request.c b/src/nxt_http_request.c index 7ba2dfd5..3ba7ffe7 100644 --- a/src/nxt_http_request.c +++ b/src/nxt_http_request.c @@ -11,6 +11,8 @@ static nxt_int_t nxt_http_validate_host(nxt_str_t *host, nxt_mp_t *mp); static void nxt_http_request_start(nxt_task_t *task, void *obj, void *data); static void nxt_http_request_pass(nxt_task_t *task, void *obj, void *data); +static void nxt_http_request_proto_info(nxt_task_t *task, + nxt_http_request_t *r); static void nxt_http_request_mem_buf_completion(nxt_task_t *task, void *obj, void *data); static void nxt_http_request_done(nxt_task_t *task, void *obj, void *data); @@ -338,7 +340,7 @@ nxt_http_request_application(nxt_task_t *task, nxt_http_request_t *r, * TODO: need an application flag to get local address * required by "SERVER_ADDR" in Pyhton and PHP. Not used in Go. */ - nxt_http_request_local_addr(task, r); + nxt_http_request_proto_info(task, r); if (r->host.length != 0) { r->server_name = r->host; @@ -353,20 +355,21 @@ nxt_http_request_application(nxt_task_t *task, nxt_http_request_t *r, } -void -nxt_http_request_read_body(nxt_task_t *task, nxt_http_request_t *r) +static void +nxt_http_request_proto_info(nxt_task_t *task, nxt_http_request_t *r) { if (r->proto.any != NULL) { - nxt_http_proto_body_read[r->protocol](task, r); + nxt_http_proto_local_addr[r->protocol](task, r); + nxt_http_proto_tls[r->protocol](task, r); } } void -nxt_http_request_local_addr(nxt_task_t *task, nxt_http_request_t *r) +nxt_http_request_read_body(nxt_task_t *task, nxt_http_request_t *r) { if (r->proto.any != NULL) { - nxt_http_proto_local_addr[r->protocol](task, r); + nxt_http_proto_body_read[r->protocol](task, r); } } diff --git a/src/nxt_php_sapi.c b/src/nxt_php_sapi.c index 4b71de5c..a6ec6c60 100644 --- a/src/nxt_php_sapi.c +++ b/src/nxt_php_sapi.c @@ -929,6 +929,10 @@ nxt_php_register_variables(zval *track_vars_array TSRMLS_DC) track_vars_array TSRMLS_CC); nxt_php_set_cstr(req, "SERVER_PORT", "80", 2, track_vars_array TSRMLS_CC); + if (r->tls) { + nxt_php_set_cstr(req, "HTTPS", "on", 2, track_vars_array TSRMLS_CC); + } + f_end = r->fields + r->fields_count; for (f = r->fields; f < f_end; f++) { name = nxt_unit_sptr_get(&f->name); diff --git a/src/nxt_python_wsgi.c b/src/nxt_python_wsgi.c index 6478f38c..a6d5f217 100644 --- a/src/nxt_python_wsgi.c +++ b/src/nxt_python_wsgi.c @@ -619,26 +619,6 @@ nxt_python_create_environ(nxt_task_t *task) } - obj = PyString_FromStringAndSize("http", nxt_length("http")); - - if (nxt_slow_path(obj == NULL)) { - nxt_alert(task, - "Python failed to create the \"wsgi.url_scheme\" environ value"); - goto fail; - } - - if (nxt_slow_path(PyDict_SetItemString(environ, "wsgi.url_scheme", obj) - != 0)) - { - nxt_alert(task, - "Python failed to set the \"wsgi.url_scheme\" environ value"); - goto fail; - } - - Py_DECREF(obj); - obj = NULL; - - if (nxt_slow_path(PyType_Ready(&nxt_py_input_type) != 0)) { nxt_alert(task, "Python failed to initialize the \"wsgi.input\" type object"); @@ -726,6 +706,13 @@ nxt_python_get_environ(nxt_python_run_ctx_t *ctx) RC(nxt_python_add_sptr(ctx, "REMOTE_ADDR", &r->remote, r->remote_length)); RC(nxt_python_add_sptr(ctx, "SERVER_ADDR", &r->local, r->local_length)); + if (r->tls) { + RC(nxt_python_add_str(ctx, "wsgi.url_scheme", "https", 5)); + + } else { + RC(nxt_python_add_str(ctx, "wsgi.url_scheme", "http", 4)); + } + RC(nxt_python_add_sptr(ctx, "SERVER_PROTOCOL", &r->version, r->version_length)); diff --git a/src/nxt_router.c b/src/nxt_router.c index f546887b..149a0ff3 100644 --- a/src/nxt_router.c +++ b/src/nxt_router.c @@ -4703,6 +4703,8 @@ nxt_router_prepare_msg(nxt_task_t *task, nxt_http_request_t *r, p = nxt_cpymem(p, nxt_sockaddr_address(r->local), r->local->address_length); *p++ = '\0'; + req->tls = (r->tls != NULL); + req->server_name_length = r->server_name.length; nxt_unit_sptr_set(&req->server_name, p); p = nxt_cpymem(p, r->server_name.start, r->server_name.length); diff --git a/src/nxt_unit_request.h b/src/nxt_unit_request.h index 88d569a6..2207cefa 100644 --- a/src/nxt_unit_request.h +++ b/src/nxt_unit_request.h @@ -19,6 +19,7 @@ struct nxt_unit_request_s { uint8_t version_length; uint8_t remote_length; uint8_t local_length; + uint8_t tls; uint32_t server_name_length; uint32_t target_length; uint32_t path_length; diff --git a/src/perl/nxt_perl_psgi.c b/src/perl/nxt_perl_psgi.c index 0b4b31d7..b99d3269 100644 --- a/src/perl/nxt_perl_psgi.c +++ b/src/perl/nxt_perl_psgi.c @@ -656,8 +656,11 @@ nxt_perl_psgi_env_create(PerlInterpreter *my_perl, RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.version"), newRV_noinc((SV *) array_version))); + RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.url_scheme"), - newSVpv("http", 4))); + r->tls ? newSVpv("https", 5) + : newSVpv("http", 4))); + RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.input"), SvREFCNT_inc(nxt_perl_psgi_arg_input.io))); RC(nxt_perl_psgi_add_value(my_perl, hash_env, NL("psgi.errors"), diff --git a/src/ruby/nxt_ruby.c b/src/ruby/nxt_ruby.c index b2398abe..ab9f7020 100644 --- a/src/ruby/nxt_ruby.c +++ b/src/ruby/nxt_ruby.c @@ -327,7 +327,6 @@ nxt_ruby_rack_env_create(VALUE arg) rb_ary_push(version, UINT2NUM(NXT_RUBY_RACK_API_VERSION_MINOR)); rb_hash_aset(hash_env, rb_str_new2("rack.version"), version); - rb_hash_aset(hash_env, rb_str_new2("rack.url_scheme"), rb_str_new2("http")); rb_hash_aset(hash_env, rb_str_new2("rack.input"), nxt_ruby_io_input); rb_hash_aset(hash_env, rb_str_new2("rack.errors"), nxt_ruby_io_error); rb_hash_aset(hash_env, rb_str_new2("rack.multithread"), Qfalse); @@ -454,6 +453,9 @@ nxt_ruby_read_request(VALUE hash_env) r->server_name_length); nxt_ruby_add_str(hash_env, NL("SERVER_PORT"), "80", 2); + rb_hash_aset(hash_env, rb_str_new2("rack.url_scheme"), + r->tls ? rb_str_new2("https") : rb_str_new2("http")); + for (i = 0; i < r->fields_count; i++) { f = r->fields + i; -- cgit From 687f83fbd00b4f72da06f497f5bfe2af06716a3a Mon Sep 17 00:00:00 2001 From: Max Romanov Date: Fri, 22 Mar 2019 15:32:35 +0300 Subject: Style fixing. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This closes #233 issue on GitHub. Thanks to 洪志道 (Hong Zhi Dao). --- src/nxt_conf_validation.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/nxt_conf_validation.c b/src/nxt_conf_validation.c index 5653b9eb..ee87b0f6 100644 --- a/src/nxt_conf_validation.c +++ b/src/nxt_conf_validation.c @@ -1268,6 +1268,7 @@ nxt_conf_vldt_java_classpath(nxt_conf_validation_t *vldt, nxt_conf_value_t *valu return NXT_OK; } + static nxt_int_t nxt_conf_vldt_java_option(nxt_conf_validation_t *vldt, nxt_conf_value_t *value) { -- cgit From 1b7514dca386e26503eac90bd3518a950d7f9a5c Mon Sep 17 00:00:00 2001 From: Max Romanov Date: Fri, 22 Mar 2019 15:32:40 +0300 Subject: Destroying pool in case of error. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This closes #233 issue on GitHub. Thanks to 洪志道 (Hong Zhi Dao). --- src/nxt_controller.c | 1 + src/nxt_runtime.c | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/nxt_controller.c b/src/nxt_controller.c index 29838bd9..d5534f49 100644 --- a/src/nxt_controller.c +++ b/src/nxt_controller.c @@ -184,6 +184,7 @@ nxt_controller_start(nxt_task_t *task, void *data) vldt.pool = nxt_mp_create(1024, 128, 256, 32); if (nxt_slow_path(vldt.pool == NULL)) { + nxt_mp_destroy(mp); return NXT_ERROR; } diff --git a/src/nxt_runtime.c b/src/nxt_runtime.c index 547c7494..06478f72 100644 --- a/src/nxt_runtime.c +++ b/src/nxt_runtime.c @@ -53,14 +53,13 @@ nxt_runtime_create(nxt_task_t *task) nxt_app_lang_module_t *lang; mp = nxt_mp_create(1024, 128, 256, 32); - if (nxt_slow_path(mp == NULL)) { return NXT_ERROR; } rt = nxt_mp_zget(mp, sizeof(nxt_runtime_t)); if (nxt_slow_path(rt == NULL)) { - return NXT_ERROR; + goto fail; } task->thread->runtime = rt; -- cgit From 6c694d4b47b626918e09d386a7d1f66844f76fd8 Mon Sep 17 00:00:00 2001 From: Max Romanov Date: Fri, 22 Mar 2019 15:32:58 +0300 Subject: Ignoring EPERM error when changing application process uid/gid. This closes #228 issue on GitHub. --- src/nxt_process.c | 49 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/nxt_process.c b/src/nxt_process.c index 59520297..c4aef21c 100644 --- a/src/nxt_process.c +++ b/src/nxt_process.c @@ -136,9 +136,11 @@ nxt_process_start(nxt_task_t *task, nxt_process_t *process) nxt_random_init(&thread->random); - if (init->user_cred != NULL && getuid() == 0) { - /* Super-user. */ - + if (init->user_cred != NULL) { + /* + * Changing user credentials requires either root privileges + * or CAP_SETUID and CAP_SETGID capabilities on Linux. + */ ret = nxt_user_cred_set(task, init->user_cred); if (ret != NXT_OK) { goto fail; @@ -434,11 +436,7 @@ nxt_user_cred_get(nxt_task_t *task, nxt_user_cred_t *uc, const char *group) uc->base_gid = grp->gr_gid; } - if (getuid() == 0) { - return nxt_user_groups_get(task, uc); - } - - return NXT_OK; + return nxt_user_groups_get(task, uc); } @@ -505,14 +503,26 @@ nxt_user_groups_get(nxt_task_t *task, nxt_user_cred_t *uc) if (nsaved == -1) { nxt_alert(task, "getgroups(%d) failed %E", nsaved, nxt_errno); - goto fail; + goto free; } nxt_debug(task, "getgroups(): %d", nsaved); if (initgroups(uc->user, uc->base_gid) != 0) { - nxt_alert(task, "initgroups(%s, %d) failed", uc->user, uc->base_gid); - goto restore; + if (nxt_errno == NXT_EPERM) { + nxt_log(task, NXT_LOG_NOTICE, + "initgroups(%s, %d) failed %E, ignored", + uc->user, uc->base_gid, nxt_errno); + + ret = NXT_OK; + + goto free; + + } else { + nxt_alert(task, "initgroups(%s, %d) failed %E", + uc->user, uc->base_gid, nxt_errno); + goto restore; + } } ngroups = getgroups(0, NULL); @@ -567,7 +577,7 @@ restore: ret = NXT_ERROR; } -fail: +free: nxt_free(saved); @@ -582,8 +592,15 @@ nxt_user_cred_set(nxt_task_t *task, nxt_user_cred_t *uc) uc->user, (uint64_t) uc->uid, (uint64_t) uc->base_gid); if (setgid(uc->base_gid) != 0) { - nxt_alert(task, "setgid(%d) failed %E", uc->base_gid, nxt_errno); - return NXT_ERROR; + if (nxt_errno == NXT_EPERM) { + nxt_log(task, NXT_LOG_NOTICE, "setgid(%d) failed %E, ignored", + uc->base_gid, nxt_errno); + return NXT_OK; + + } else { + nxt_alert(task, "setgid(%d) failed %E", uc->base_gid, nxt_errno); + return NXT_ERROR; + } } if (uc->gids != NULL) { @@ -595,8 +612,8 @@ nxt_user_cred_set(nxt_task_t *task, nxt_user_cred_t *uc) } else { /* MacOSX fallback. */ if (initgroups(uc->user, uc->base_gid) != 0) { - nxt_alert(task, "initgroups(%s, %d) failed", - uc->user, uc->base_gid); + nxt_alert(task, "initgroups(%s, %d) failed %E", + uc->user, uc->base_gid, nxt_errno); return NXT_ERROR; } } -- cgit From b96e5fd8481f79935967fed56c71f72d16c59f6b Mon Sep 17 00:00:00 2001 From: Max Romanov Date: Mon, 25 Mar 2019 14:49:28 +0300 Subject: Turning off port read event state after main process fork. Master port stores two file descriptors and works as a read port on the master process side. After a fork, the port switches into write mode and the read socket closes, but the same event structure is used for the write socket. However, the inherited structure remained in read state, telling the epoll engine to use MOD operation instead of ADD. The patch resets read event state, so the engine may write using proper ADD operation. --- src/nxt_port_socket.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/nxt_port_socket.c b/src/nxt_port_socket.c index a426df31..c9b5105b 100644 --- a/src/nxt_port_socket.c +++ b/src/nxt_port_socket.c @@ -566,6 +566,7 @@ void nxt_port_read_close(nxt_port_t *port) { port->socket.read_ready = 0; + port->socket.read = NXT_EVENT_INACTIVE; nxt_socket_close(port->socket.task, port->pair[0]); port->pair[0] = -1; } -- cgit From aca42de18ad9877db7e4a7f598a4c5cb55644fe8 Mon Sep 17 00:00:00 2001 From: Max Romanov Date: Mon, 1 Apr 2019 16:40:33 +0300 Subject: Adding syntax sugar. With exceptions and overloads. --- src/nodejs/unit-http/binding.gyp | 9 + src/nodejs/unit-http/binding_pub.gyp | 9 + src/nodejs/unit-http/nxt_napi.h | 656 +++++++++++++++++++++++++++ src/nodejs/unit-http/unit.cpp | 827 +++++++++-------------------------- src/nodejs/unit-http/unit.h | 35 +- 5 files changed, 882 insertions(+), 654 deletions(-) create mode 100644 src/nodejs/unit-http/nxt_napi.h (limited to 'src') diff --git a/src/nodejs/unit-http/binding.gyp b/src/nodejs/unit-http/binding.gyp index ee09bfed..55d965bd 100644 --- a/src/nodejs/unit-http/binding.gyp +++ b/src/nodejs/unit-http/binding.gyp @@ -1,6 +1,15 @@ { 'targets': [{ 'target_name': "unit-http", + 'cflags!': [ '-fno-exceptions' ], + 'cflags_cc!': [ '-fno-exceptions' ], + 'conditions': [ + ['OS=="mac"', { + 'xcode_settings': { + 'GCC_ENABLE_CPP_EXCEPTIONS': 'YES' + } + }] + ], 'sources': ["unit.cpp", "addon.cpp"], 'include_dirs': [ " + + +#ifdef __cplusplus +extern "C" { +#endif + +#include "version.h" +#include + +#if NXT_VERNUM != NXT_NODE_VERNUM +#error "libunit version mismatch." +#endif + +#include +#include + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +struct nxt_napi { + + struct exception { + exception(const char *s) : str(s) { } + + const char *str; + }; + + + nxt_napi(napi_env env) : env_(env) { } + + + inline napi_value + coerce_to_string(napi_value val) + { + napi_value res; + napi_status status; + + status = napi_coerce_to_string(env_, val, &res); + if (status != napi_ok) { + throw exception("Failed to coerce to string"); + } + + return res; + } + + + inline napi_value + create_buffer(size_t size, void **data) + { + napi_value res; + napi_status status; + + status = napi_create_buffer(env_, size, data, &res); + if (status != napi_ok) { + throw exception("Failed to create buffer"); + } + + return res; + } + + + inline napi_value + create_function(const char *name, size_t len, napi_callback cb, void *data) + { + napi_value res; + napi_status status; + + status = napi_create_function(env_, name, len, cb, data, &res); + if (status != napi_ok) { + throw exception("Failed to create function"); + } + + return res; + } + + + inline napi_value + create_function(napi_callback cb) + { + return create_function(NULL, 0, cb, NULL); + } + + + inline napi_value + create_object() + { + napi_value res; + napi_status status; + + status = napi_create_object(env_, &res); + if (status != napi_ok) { + throw exception("Failed to create object"); + } + + return res; + } + + + inline napi_ref + create_reference(napi_value val, int ref_count = 1) + { + napi_ref res; + napi_status status; + + status = napi_create_reference(env_, val, ref_count, &res); + if (status != napi_ok) { + throw exception("Failed to create reference"); + } + + return res; + } + + + inline napi_value + create_string_latin1(const char *str, size_t len) + { + napi_value res; + napi_status status; + + status = napi_create_string_latin1(env_, str, len, &res); + if (status != napi_ok) { + throw exception("Failed to create latin1 string"); + } + + return res; + } + + + inline napi_value + create_string_latin1(nxt_unit_sptr_t &str, size_t len) + { + const char *p; + + p = (const char *) nxt_unit_sptr_get(&str); + + return create_string_latin1(p, len); + } + + + inline napi_value + define_class(const char *name, napi_callback ctor, size_t prop_count, + const napi_property_descriptor* props) + { + napi_value res; + napi_status status; + + status = napi_define_class(env_, name, NAPI_AUTO_LENGTH, ctor, nullptr, + prop_count, props, &res); + if (status != napi_ok) { + throw exception("Failed to define class"); + } + + return res; + } + + + inline void + delete_reference(napi_ref ref) + { + napi_delete_reference(env_, ref); + } + + + inline uint32_t + get_array_length(napi_value val) + { + uint32_t res; + napi_status status; + + status = napi_get_array_length(env_, val, &res); + if (status != napi_ok) { + throw exception("Failed to get array length"); + } + + return res; + } + + + inline napi_value + get_cb_info(napi_callback_info info, size_t &argc, napi_value *argv) + { + napi_value res; + napi_status status; + + status = napi_get_cb_info(env_, info, &argc, argv, &res, nullptr); + if (status != napi_ok) { + throw exception("Failed to get arguments from js"); + } + + return res; + } + + + inline napi_value + get_cb_info(napi_callback_info info) + { + napi_value res; + napi_status status; + + status = napi_get_cb_info(env_, info, nullptr, nullptr, &res, nullptr); + if (status != napi_ok) { + throw exception("Failed to get arguments from js"); + } + + return res; + } + + + inline napi_value + get_element(napi_value obj, uint32_t i) + { + napi_value res; + napi_status status; + + status = napi_get_element(env_, obj, i, &res); + if (status != napi_ok) { + throw exception("Failed to get element"); + } + + return res; + } + + + inline napi_value + get_named_property(napi_value obj, const char *name) + { + napi_value res; + napi_status status; + + status = napi_get_named_property(env_, obj, name, &res); + if (status != napi_ok) { + throw exception("Failed to get named property"); + } + + return res; + } + + + inline napi_value + get_new_target(napi_callback_info info) + { + napi_value res; + napi_status status; + + status = napi_get_new_target(env_, info, &res); + if (status != napi_ok) { + throw exception("Failed to get new target"); + } + + return res; + } + + + inline napi_value + get_property(napi_value val, napi_value key) + { + napi_value res; + napi_status status; + + status = napi_get_property(env_, val, key, &res); + if (status != napi_ok) { + throw exception("Failed to get property"); + } + + return res; + } + + + inline napi_value + get_property_names(napi_value val) + { + napi_value res; + napi_status status; + + status = napi_get_property_names(env_, val, &res); + if (status != napi_ok) { + throw exception("Failed to get property names"); + } + + return res; + } + + + inline napi_value + get_reference_value(napi_ref ref) + { + napi_value res; + napi_status status; + + status = napi_get_reference_value(env_, ref, &res); + if (status != napi_ok) { + throw exception("Failed to get reference value"); + } + + return res; + } + + + inline nxt_unit_request_info_t * + get_request_info(napi_value obj) + { + int64_t n; + napi_status status; + + status = napi_get_value_int64(env_, obj, &n); + if (status != napi_ok) { + throw exception("Failed to get request pointer"); + } + + return (nxt_unit_request_info_t *) (intptr_t) n; + } + + + inline size_t + get_value_string_latin1(napi_value val, char *buf, size_t bufsize) + { + size_t res; + napi_status status; + + status = napi_get_value_string_latin1(env_, val, buf, bufsize, &res); + if (status != napi_ok) { + throw exception("Failed to get string latin1"); + } + + return res; + } + + + inline uint32_t + get_value_uint32(napi_value obj) + { + uint32_t res; + napi_status status; + + status = napi_get_value_uint32(env_, obj, &res); + if (status != napi_ok) { + throw exception("Failed to get uint32_t"); + } + + return res; + } + + + inline bool + is_array(napi_value val) + { + bool res; + napi_status status; + + status = napi_is_array(env_, val, &res); + if (status != napi_ok) { + throw exception("Failed to confirm value is array"); + } + + return res; + } + + + inline napi_value + make_callback(napi_async_context ctx, napi_value val, napi_value func, + int argc, const napi_value *argv) + { + napi_value res, ex; + napi_status status; + + status = napi_make_callback(env_, ctx, val, func, argc, argv, &res); + if (status != napi_ok) { + if (status != napi_pending_exception) { + throw exception("Failed to make callback"); + } + + status = napi_get_and_clear_last_exception(env_, &ex); + if (status != napi_ok) { + throw exception("Failed to get and clear last exception"); + } + + /* Logging a description of the error and call stack. */ + status = napi_fatal_exception(env_, ex); + if (status != napi_ok) { + throw exception("Failed napi_fatal_exception()"); + } + } + + return res; + } + + + inline napi_value + new_instance(napi_value ctor) + { + napi_value res; + napi_status status; + + status = napi_new_instance(env_, ctor, 0, NULL, &res); + if (status != napi_ok) { + throw exception("Failed to create instance"); + } + + return res; + } + + + inline napi_value + new_instance(napi_value ctor, napi_value param) + { + napi_value res; + napi_status status; + + status = napi_new_instance(env_, ctor, 1, ¶m, &res); + if (status != napi_ok) { + throw exception("Failed to create instance"); + } + + return res; + } + + + inline void + set_element(napi_value obj, uint32_t i, napi_value val) + { + napi_status status; + + status = napi_set_element(env_, obj, i, val); + if (status != napi_ok) { + throw exception("Failed to set element"); + } + } + + + inline void + set_named_property(napi_value obj, const char *name, napi_value val) + { + napi_status status; + + status = napi_set_named_property(env_, obj, name, val); + if (status != napi_ok) { + throw exception("Failed to set named property"); + } + } + + + inline void + set_named_property(napi_value obj, const char *name, napi_callback cb) + { + set_named_property(obj, name, create_function(cb)); + } + + + inline napi_value + set_named_property(napi_value obj, const char *name, nxt_unit_sptr_t &val, + size_t len) + { + napi_value str; + + str = create_string_latin1(val, len); + + set_named_property(obj, name, str); + + return str; + } + + + inline void + set_named_property(napi_value obj, const char *name, intptr_t val) + { + napi_value ptr; + napi_status status; + + status = napi_create_int64(env_, val, &ptr); + if (status != napi_ok) { + throw exception("Failed to create int64"); + } + + set_named_property(obj, name, ptr); + } + + + inline void + throw_error(const char *str) + { + napi_throw_error(env_, NULL, str); + } + + + inline void + throw_error(const exception &e) + { + napi_throw_error(env_, NULL, e.str); + } + + + inline napi_valuetype + type_of(napi_value val) + { + napi_status status; + napi_valuetype res; + + status = napi_typeof(env_, val, &res); + if (status != napi_ok) { + throw exception("Failed to get typeof"); + } + + return res; + } + + + inline void * + unwrap(napi_value val) + { + void *res; + napi_status status; + + status = napi_unwrap(env_, val, &res); + if (status != napi_ok) { + throw exception("Failed to unwrap"); + } + + return res; + } + + + inline napi_ref + wrap(napi_value val, void *obj, napi_finalize fin_cb, void *hint = nullptr) + { + napi_ref res; + napi_status status; + + status = napi_wrap(env_, val, obj, fin_cb, hint, &res); + if (status != napi_ok) { + throw exception("Failed to wrap"); + } + + return res; + } + + + inline + operator napi_env() + { + return env_; + } + + + napi_env env() + { + return env_; + } + +private: + napi_env env_; +}; + + +struct nxt_handle_scope : public nxt_napi { + nxt_handle_scope(napi_env env) : nxt_napi(env) + { + napi_status status; + + status = napi_open_handle_scope(env, &scope_); + if (status != napi_ok) { + throw exception("Failed to open handle scope"); + } + } + + ~nxt_handle_scope() + { + napi_status status; + + status = napi_close_handle_scope(env(), scope_); + if (status != napi_ok) { + throw_error("Failed to close handle scope"); + } + } + +private: + napi_handle_scope scope_; +}; + + +struct nxt_async_context : public nxt_napi { + nxt_async_context(napi_env env, const char *name) : + nxt_napi(env) + { + napi_value name_val; + napi_status status; + + name_val = create_string_latin1(name, NAPI_AUTO_LENGTH); + + status = napi_async_init(env, NULL, name_val, &context_); + if (status != napi_ok) { + throw exception("Failed to init async object"); + } + } + + operator napi_async_context() { + return context_; + } + + ~nxt_async_context() + { + napi_status status; + + status = napi_async_destroy(env(), context_); + if (status != napi_ok) { + throw_error("Failed to destroy async object"); + } + } + +private: + napi_async_context context_; +}; + + +struct nxt_callback_scope : public nxt_napi { + nxt_callback_scope(nxt_async_context& ctx) : + nxt_napi(ctx.env()) + { + napi_value resource; + napi_status status; + + resource = create_object(); + + status = napi_open_callback_scope(env(), resource, ctx, &scope_); + if (status != napi_ok) { + throw exception("Failed to open callback scope"); + } + } + + ~nxt_callback_scope() + { + napi_status status; + + status = napi_close_callback_scope(env(), scope_); + if (status != napi_ok) { + throw_error("Failed to close callback scope"); + } + } + +private: + napi_callback_scope scope_; +}; + + +#endif /* _NXT_NODEJS_NAPI_H_INCLUDED_ */ diff --git a/src/nodejs/unit-http/unit.cpp b/src/nodejs/unit-http/unit.cpp index dcff1186..e4072851 100644 --- a/src/nodejs/unit-http/unit.cpp +++ b/src/nodejs/unit-http/unit.cpp @@ -20,9 +20,9 @@ struct nxt_nodejs_ctx_t { }; -Unit::Unit(napi_env env): - env_(env), - wrapper_(nullptr), +Unit::Unit(napi_env env, napi_value jsthis): + nxt_napi(env), + wrapper_(wrap(jsthis, this, destroy)), unit_ctx_(nullptr) { } @@ -30,15 +30,15 @@ Unit::Unit(napi_env env): Unit::~Unit() { - napi_delete_reference(env_, wrapper_); + delete_reference(wrapper_); } napi_value Unit::init(napi_env env, napi_value exports) { - napi_value cons, fn; - napi_status status; + nxt_napi napi(env); + napi_value cons; napi_property_descriptor properties[] = { { "createServer", 0, create_server, 0, 0, 0, napi_default, 0 }, @@ -46,61 +46,22 @@ Unit::init(napi_env env, napi_value exports) { "_read", 0, _read, 0, 0, 0, napi_default, 0 } }; - status = napi_define_class(env, "Unit", NAPI_AUTO_LENGTH, create, nullptr, - 3, properties, &cons); - if (status != napi_ok) { - goto failed; - } + try { + cons = napi.define_class("Unit", create, 3, properties); + constructor_ = napi.create_reference(cons); - status = napi_create_reference(env, cons, 1, &constructor_); - if (status != napi_ok) { - goto failed; - } + napi.set_named_property(exports, "Unit", cons); + napi.set_named_property(exports, "unit_response_headers", + response_send_headers); + napi.set_named_property(exports, "unit_response_write", response_write); + napi.set_named_property(exports, "unit_response_end", response_end); - status = napi_set_named_property(env, exports, "Unit", cons); - if (status != napi_ok) { - goto failed; - } - - status = napi_create_function(env, NULL, 0, response_send_headers, NULL, - &fn); - if (status != napi_ok) { - goto failed; - } - - status = napi_set_named_property(env, exports, - "unit_response_headers", fn); - if (status != napi_ok) { - goto failed; - } - - status = napi_create_function(env, NULL, 0, response_write, NULL, &fn); - if (status != napi_ok) { - goto failed; - } - - status = napi_set_named_property(env, exports, "unit_response_write", fn); - if (status != napi_ok) { - goto failed; - } - - status = napi_create_function(env, NULL, 0, response_end, NULL, &fn); - if (status != napi_ok) { - goto failed; - } - - status = napi_set_named_property(env, exports, "unit_response_end", fn); - if (status != napi_ok) { - goto failed; + } catch (exception &e) { + napi.throw_error(e); + return nullptr; } return exports; - -failed: - - napi_throw_error(env, NULL, "Failed to define Unit class"); - - return nullptr; } @@ -116,63 +77,36 @@ Unit::destroy(napi_env env, void *nativeObject, void *finalize_hint) napi_value Unit::create(napi_env env, napi_callback_info info) { - Unit *obj; - napi_ref ref; - napi_value target, cons, instance, jsthis; - napi_status status; + Unit *obj; + nxt_napi napi(env); + napi_ref ref; + napi_value target, cons, instance, jsthis; - status = napi_get_new_target(env, info, &target); - if (status != napi_ok) { - goto failed; - } + try { + target = napi.get_new_target(info); - if (target != nullptr) { - /* Invoked as constructor: `new Unit(...)` */ - status = napi_get_cb_info(env, info, nullptr, nullptr, &jsthis, - nullptr); - if (status != napi_ok) { - goto failed; - } + if (target != nullptr) { + /* Invoked as constructor: `new Unit(...)`. */ + jsthis = napi.get_cb_info(info); - obj = new Unit(env); + obj = new Unit(env, jsthis); - status = napi_wrap(env, jsthis, reinterpret_cast(obj), - destroy, nullptr, &obj->wrapper_); - if (status != napi_ok) { - goto failed; - } + ref = napi.create_reference(jsthis); - status = napi_create_reference(env, jsthis, 1, &ref); - if (status != napi_ok) { - goto failed; + return jsthis; } - return jsthis; - } - - /* Invoked as plain function `Unit(...)`, turn into construct call. */ - status = napi_get_reference_value(env, constructor_, &cons); - if (status != napi_ok) { - goto failed; - } - - status = napi_new_instance(env, cons, 0, nullptr, &instance); - if (status != napi_ok) { - goto failed; - } + /* Invoked as plain function `Unit(...)`, turn into construct call. */ + cons = napi.get_reference_value(constructor_); + instance = napi.new_instance(cons); + ref = napi.create_reference(instance); - status = napi_create_reference(env, instance, 1, &ref); - if (status != napi_ok) { - goto failed; + } catch (exception &e) { + napi.throw_error(e); + return nullptr; } return instance; - -failed: - - napi_throw_error(env, NULL, "Failed to create Unit object"); - - return nullptr; } @@ -181,20 +115,19 @@ Unit::create_server(napi_env env, napi_callback_info info) { Unit *obj; size_t argc; + nxt_napi napi(env); napi_value jsthis, argv; - napi_status status; nxt_unit_init_t unit_init; argc = 1; - status = napi_get_cb_info(env, info, &argc, &argv, &jsthis, nullptr); - if (status != napi_ok) { - goto failed; - } + try { + jsthis = napi.get_cb_info(info, argc, &argv); + obj = (Unit *) napi.unwrap(jsthis); - status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); - if (status != napi_ok) { - goto failed; + } catch (exception &e) { + napi.throw_error(e); + return nullptr; } memset(&unit_init, 0, sizeof(nxt_unit_init_t)); @@ -230,40 +163,22 @@ Unit::listen(napi_env env, napi_callback_info info) napi_value Unit::_read(napi_env env, napi_callback_info info) { - Unit *obj; void *data; size_t argc; - int64_t req_pointer; + nxt_napi napi(env); napi_value jsthis, buffer, argv; - napi_status status; nxt_unit_request_info_t *req; argc = 1; - status = napi_get_cb_info(env, info, &argc, &argv, &jsthis, nullptr); - if (status != napi_ok) { - napi_throw_error(env, NULL, "Failed to get arguments from js"); - return nullptr; - } - - status = napi_unwrap(env, jsthis, reinterpret_cast(&obj)); - if (status != napi_ok) { - napi_throw_error(env, NULL, "Failed to get Unit object form js"); - return nullptr; - } - - status = napi_get_value_int64(env, argv, &req_pointer); - if (status != napi_ok) { - napi_throw_error(env, NULL, "Failed to get request pointer"); - return nullptr; - } + try { + jsthis = napi.get_cb_info(info, argc, &argv); - req = (nxt_unit_request_info_t *) (uintptr_t) req_pointer; + req = napi.get_request_info(argv); + buffer = napi.create_buffer((size_t) req->content_length, &data); - status = napi_create_buffer(env, (size_t) req->content_length, - &data, &buffer); - if (status != napi_ok) { - napi_throw_error(env, NULL, "Failed to create request buffer"); + } catch (exception &e) { + napi.throw_error(e); return nullptr; } @@ -276,138 +191,38 @@ Unit::_read(napi_env env, napi_callback_info info) void Unit::request_handler(nxt_unit_request_info_t *req) { - Unit *obj; - napi_value socket, request, response, global, server_obj, except; - napi_value emit_events, events_res, async_name, resource_object; - napi_status status; - napi_async_context async_context; - napi_callback_scope async_scope; - napi_value events_args[3]; + Unit *obj; + napi_value socket, request, response, server_obj; + napi_value emit_events; + napi_value events_args[3]; obj = reinterpret_cast(req->unit->data); - napi_handle_scope scope; - status = napi_open_handle_scope(obj->env_, &scope); - if (status != napi_ok) { - napi_throw_error(obj->env_, NULL, "Failed to create handle scope"); - return; - } + try { + nxt_handle_scope scope(obj->env()); - server_obj = obj->get_server_object(); - if (server_obj == nullptr) { - napi_throw_error(obj->env_, NULL, "Failed to get server object"); - return; - } + server_obj = obj->get_server_object(); - status = napi_get_global(obj->env_, &global); - if (status != napi_ok) { - napi_throw_error(obj->env_, NULL, "Failed to get global variable"); - return; - } + socket = obj->create_socket(server_obj, req); + request = obj->create_request(server_obj, socket); + response = obj->create_response(server_obj, socket, request, req); - socket = obj->create_socket(server_obj, req); - if (socket == nullptr) { - napi_throw_error(obj->env_, NULL, "Failed to create socket object"); - return; - } + obj->create_headers(req, request); - request = obj->create_request(server_obj, socket); - if (request == nullptr) { - napi_throw_error(obj->env_, NULL, "Failed to create request object"); - return; - } + emit_events = obj->get_named_property(server_obj, "emit_events"); - response = obj->create_response(server_obj, socket, request, req, obj); - if (response == nullptr) { - napi_throw_error(obj->env_, NULL, "Failed to create response object"); - return; - } - - status = obj->create_headers(req, request); - if (status != napi_ok) { - napi_throw_error(obj->env_, NULL, "Failed to create headers"); - return; - } - - status = napi_get_named_property(obj->env_, server_obj, "emit_events", - &emit_events); - if (status != napi_ok) { - napi_throw_error(obj->env_, NULL, "Failed to get " - "'emit_events' function"); - return; - } + events_args[0] = server_obj; + events_args[1] = request; + events_args[2] = response; - events_args[0] = server_obj; - events_args[1] = request; - events_args[2] = response; + nxt_async_context async_context(obj->env(), "unit_request_handler"); + nxt_callback_scope async_scope(async_context); - status = napi_create_string_utf8(obj->env_, "unit_request_handler", - sizeof("unit_request_handler") - 1, - &async_name); - if (status != napi_ok) { - napi_throw_error(obj->env_, NULL, "Failed to create utf-8 string"); - return; - } + obj->make_callback(async_context, server_obj, emit_events, + 3, events_args); - status = napi_async_init(obj->env_, NULL, async_name, &async_context); - if (status != napi_ok) { - napi_throw_error(obj->env_, NULL, "Failed to init async object"); - return; - } - - status = napi_create_object(obj->env_, &resource_object); - if (status != napi_ok) { - napi_throw_error(obj->env_, NULL, "Failed to create object for " - "callback scope"); - return; - } - - status = napi_open_callback_scope(obj->env_, resource_object, async_context, - &async_scope); - if (status != napi_ok) { - napi_throw_error(obj->env_, NULL, "Failed to open callback scope"); - return; - } - - status = napi_make_callback(obj->env_, async_context, server_obj, - emit_events, 3, events_args, &events_res); - if (status != napi_ok) { - if (status != napi_pending_exception) { - napi_throw_error(obj->env_, NULL, "Failed to make callback"); - return; - } - - status = napi_get_and_clear_last_exception(obj->env_, &except); - if (status != napi_ok) { - napi_throw_error(obj->env_, NULL, - "Failed to get and clear last exception"); - return; - } - - /* Logging a description of the error and call stack. */ - status = napi_fatal_exception(obj->env_, except); - if (status != napi_ok) { - napi_throw_error(obj->env_, NULL, "Failed to call " - "napi_fatal_exception() function"); - return; - } - } - - status = napi_close_callback_scope(obj->env_, async_scope); - if (status != napi_ok) { - napi_throw_error(obj->env_, NULL, "Failed to close callback scope"); - return; - } - - status = napi_async_destroy(obj->env_, async_context); - if (status != napi_ok) { - napi_throw_error(obj->env_, NULL, "Failed to destroy async object"); - return; - } - - status = napi_close_handle_scope(obj->env_, scope); - if (status != napi_ok) { - napi_throw_error(obj->env_, NULL, "Failed to close handle scope"); + } catch (exception &e) { + obj->throw_error(e); } } @@ -432,14 +247,14 @@ Unit::add_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port) obj = reinterpret_cast(ctx->unit->data); if (fcntl(port->in_fd, F_SETFL, O_NONBLOCK) == -1) { - napi_throw_error(obj->env_, NULL, "Failed to upgrade read" + obj->throw_error("Failed to upgrade read" " file descriptor to O_NONBLOCK"); return -1; } - status = napi_get_uv_event_loop(obj->env_, &loop); + status = napi_get_uv_event_loop(obj->env(), &loop); if (status != napi_ok) { - napi_throw_error(obj->env_, NULL, "Failed to get uv.loop"); + obj->throw_error("Failed to get uv.loop"); return NXT_UNIT_ERROR; } @@ -447,13 +262,13 @@ Unit::add_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port) err = uv_poll_init(loop, &node_ctx->poll, port->in_fd); if (err < 0) { - napi_throw_error(obj->env_, NULL, "Failed to init uv.poll"); + obj->throw_error("Failed to init uv.poll"); return NXT_UNIT_ERROR; } err = uv_poll_start(&node_ctx->poll, UV_READABLE, nxt_uv_read_callback); if (err < 0) { - napi_throw_error(obj->env_, NULL, "Failed to start uv.poll"); + obj->throw_error("Failed to start uv.poll"); return NXT_UNIT_ERROR; } @@ -505,173 +320,71 @@ Unit::quit(nxt_unit_ctx_t *ctx) napi_value Unit::get_server_object() { - napi_value unit_obj, server_obj; - napi_status status; + napi_value unit_obj; - status = napi_get_reference_value(env_, wrapper_, &unit_obj); - if (status != napi_ok) { - return nullptr; - } - - status = napi_get_named_property(env_, unit_obj, "server", &server_obj); - if (status != napi_ok) { - return nullptr; - } + unit_obj = get_reference_value(wrapper_); - return server_obj; + return get_named_property(unit_obj, "server"); } -napi_status +void Unit::create_headers(nxt_unit_request_info_t *req, napi_value request) { uint32_t i; - const char *p; - napi_value headers, raw_headers, str; + napi_value headers, raw_headers; napi_status status; - nxt_unit_field_t *f; nxt_unit_request_t *r; r = req->request; - status = napi_create_object(env_, &headers); - if (status != napi_ok) { - return status; - } + headers = create_object(); - status = napi_create_array_with_length(env_, r->fields_count * 2, + status = napi_create_array_with_length(env(), r->fields_count * 2, &raw_headers); if (status != napi_ok) { - return status; + throw exception("Failed to create array"); } for (i = 0; i < r->fields_count; i++) { - f = r->fields + i; - - status = this->append_header(f, headers, raw_headers, i); - if (status != napi_ok) { - return status; - } - } - - status = napi_set_named_property(env_, request, "headers", headers); - if (status != napi_ok) { - return status; - } - - status = napi_set_named_property(env_, request, "rawHeaders", raw_headers); - if (status != napi_ok) { - return status; - } - - p = (const char *) nxt_unit_sptr_get(&r->version); - - status = napi_create_string_latin1(env_, p, r->version_length, &str); - if (status != napi_ok) { - return status; - } - - status = napi_set_named_property(env_, request, "httpVersion", str); - if (status != napi_ok) { - return status; - } - - p = (const char *) nxt_unit_sptr_get(&r->method); - - status = napi_create_string_latin1(env_, p, r->method_length, &str); - if (status != napi_ok) { - return status; - } - - status = napi_set_named_property(env_, request, "method", str); - if (status != napi_ok) { - return status; - } - - p = (const char *) nxt_unit_sptr_get(&r->target); - - status = napi_create_string_latin1(env_, p, r->target_length, &str); - if (status != napi_ok) { - return status; - } - - status = napi_set_named_property(env_, request, "url", str); - if (status != napi_ok) { - return status; + append_header(r->fields + i, headers, raw_headers, i); } - return napi_ok; + set_named_property(request, "headers", headers); + set_named_property(request, "rawHeaders", raw_headers); + set_named_property(request, "httpVersion", r->version, r->version_length); + set_named_property(request, "method", r->method, r->method_length); + set_named_property(request, "url", r->target, r->target_length); } -inline napi_status +inline void Unit::append_header(nxt_unit_field_t *f, napi_value headers, - napi_value raw_headers, uint32_t idx) + napi_value raw_headers, uint32_t idx) { - const char *name, *value; + const char *name; napi_value str, vstr; - napi_status status; - - value = (const char *) nxt_unit_sptr_get(&f->value); - - status = napi_create_string_latin1(env_, value, f->value_length, &vstr); - if (status != napi_ok) { - return status; - } name = (const char *) nxt_unit_sptr_get(&f->name); - status = napi_set_named_property(env_, headers, name, vstr); - if (status != napi_ok) { - return status; - } + vstr = set_named_property(headers, name, f->value, f->value_length); + str = create_string_latin1(name, f->name_length); - status = napi_create_string_latin1(env_, name, f->name_length, &str); - if (status != napi_ok) { - return status; - } - - status = napi_set_element(env_, raw_headers, idx * 2, str); - if (status != napi_ok) { - return status; - } - - status = napi_set_element(env_, raw_headers, idx * 2 + 1, vstr); - if (status != napi_ok) { - return status; - } - - return napi_ok; + set_element(raw_headers, idx * 2, str); + set_element(raw_headers, idx * 2 + 1, vstr); } napi_value Unit::create_socket(napi_value server_obj, nxt_unit_request_info_t *req) { - napi_value constructor, return_val, req_pointer; - napi_status status; + napi_value constructor, return_val; - status = napi_get_named_property(env_, server_obj, "socket", - &constructor); - if (status != napi_ok) { - return nullptr; - } - - status = napi_new_instance(env_, constructor, 0, NULL, &return_val); - if (status != napi_ok) { - return nullptr; - } + constructor = get_named_property(server_obj, "socket"); - status = napi_create_int64(env_, (uintptr_t) req, &req_pointer); - if (status != napi_ok) { - return nullptr; - } + return_val = new_instance(constructor); - status = napi_set_named_property(env_, return_val, "req_pointer", - req_pointer); - if (status != napi_ok) { - return nullptr; - } + set_named_property(return_val, "req_pointer", (intptr_t) req); return return_val; } @@ -680,25 +393,13 @@ Unit::create_socket(napi_value server_obj, nxt_unit_request_info_t *req) napi_value Unit::create_request(napi_value server_obj, napi_value socket) { - napi_value constructor, return_val; - napi_status status; + napi_value constructor, return_val; - status = napi_get_named_property(env_, server_obj, "request", - &constructor); - if (status != napi_ok) { - return nullptr; - } + constructor = get_named_property(server_obj, "request"); - status = napi_new_instance(env_, constructor, 1, &server_obj, - &return_val); - if (status != napi_ok) { - return nullptr; - } + return_val = new_instance(constructor, server_obj); - status = napi_set_named_property(env_, return_val, "socket", socket); - if (status != napi_ok) { - return nullptr; - } + set_named_property(return_val, "socket", socket); return return_val; } @@ -706,37 +407,16 @@ Unit::create_request(napi_value server_obj, napi_value socket) napi_value Unit::create_response(napi_value server_obj, napi_value socket, - napi_value request, nxt_unit_request_info_t *req, - Unit *obj) + napi_value request, nxt_unit_request_info_t *req) { - napi_value constructor, return_val, req_num; - napi_status status; - - status = napi_get_named_property(env_, server_obj, "response", - &constructor); - if (status != napi_ok) { - return nullptr; - } + napi_value constructor, return_val; - status = napi_new_instance(env_, constructor, 1, &request, &return_val); - if (status != napi_ok) { - return nullptr; - } - - status = napi_set_named_property(env_, return_val, "socket", socket); - if (status != napi_ok) { - return nullptr; - } + constructor = get_named_property(server_obj, "response"); - status = napi_create_int64(env_, (int64_t) (uintptr_t) req, &req_num); - if (status != napi_ok) { - return nullptr; - } + return_val = new_instance(constructor, request); - status = napi_set_named_property(env_, return_val, "_req_point", req_num); - if (status != napi_ok) { - return nullptr; - } + set_named_property(return_val, "socket", socket); + set_named_property(return_val, "_req_point", (intptr_t) req); return return_val; } @@ -749,13 +429,12 @@ Unit::response_send_headers(napi_env env, napi_callback_info info) char *ptr, *name_ptr; bool is_array; size_t argc, name_len, value_len; - int64_t req_p; uint32_t status_code, header_len, keys_len, array_len; uint32_t keys_count, i, j; uint16_t hash; + nxt_napi napi(env); napi_value this_arg, headers, keys, name, value, array_val; napi_value req_num, array_entry; - napi_status status; napi_valuetype val_type; nxt_unit_field_t *f; nxt_unit_request_info_t *req; @@ -763,137 +442,97 @@ Unit::response_send_headers(napi_env env, napi_callback_info info) argc = 5; - status = napi_get_cb_info(env, info, &argc, argv, &this_arg, NULL); - if (status != napi_ok) { - return nullptr; - } + try { + this_arg = napi.get_cb_info(info, argc, argv); + if (argc != 5) { + napi.throw_error("Wrong args count. Expected: " + "statusCode, headers, headers count, " + "headers length"); + return nullptr; + } - if (argc != 5) { - napi_throw_error(env, NULL, "Wrong args count. Need three: " - "statusCode, headers, headers count, headers length"); - return nullptr; - } + req_num = napi.get_named_property(argv[0], "_req_point"); - status = napi_get_named_property(env, argv[0], "_req_point", &req_num); - if (status != napi_ok) { - napi_throw_error(env, NULL, "Failed to get request pointer"); - return nullptr; - } + req = napi.get_request_info(req_num); - status = napi_get_value_int64(env, req_num, &req_p); - if (status != napi_ok) { - napi_throw_error(env, NULL, "Failed to get request pointer"); - return nullptr; - } + status_code = napi.get_value_uint32(argv[1]); + keys_count = napi.get_value_uint32(argv[3]); + header_len = napi.get_value_uint32(argv[4]); - req = (nxt_unit_request_info_t *) (uintptr_t) req_p; + /* Need to reserve extra byte for C-string 0-termination. */ + header_len++; - status = napi_get_value_uint32(env, argv[1], &status_code); - if (status != napi_ok) { - goto failed; - } + headers = argv[2]; - status = napi_get_value_uint32(env, argv[3], &keys_count); - if (status != napi_ok) { - goto failed; - } + ret = nxt_unit_response_init(req, status_code, keys_count, header_len); + if (ret != NXT_UNIT_OK) { + napi.throw_error("Failed to create response"); + return nullptr; + } - status = napi_get_value_uint32(env, argv[4], &header_len); - if (status != napi_ok) { - goto failed; - } + keys = napi.get_property_names(headers); + keys_len = napi.get_array_length(keys); - /* Need to reserve extra byte for C-string 0-termination. */ - header_len++; + ptr = req->response_buf->free; - headers = argv[2]; + for (i = 0; i < keys_len; i++) { + name = napi.get_element(keys, i); - ret = nxt_unit_response_init(req, status_code, keys_count, header_len); - if (ret != NXT_UNIT_OK) { - goto failed; - } + array_entry = napi.get_property(headers, name); - status = napi_get_property_names(env, headers, &keys); - if (status != napi_ok) { - goto failed; - } + name = napi.get_element(array_entry, 0); + value = napi.get_element(array_entry, 1); - status = napi_get_array_length(env, keys, &keys_len); - if (status != napi_ok) { - goto failed; - } + name_len = napi.get_value_string_latin1(name, ptr, header_len); + name_ptr = ptr; - ptr = req->response_buf->free; + ptr += name_len; + header_len -= name_len; - for (i = 0; i < keys_len; i++) { - status = napi_get_element(env, keys, i, &name); - if (status != napi_ok) { - goto failed; - } + hash = nxt_unit_field_hash(name_ptr, name_len); - status = napi_get_property(env, headers, name, &array_entry); - if (status != napi_ok) { - goto failed; - } + is_array = napi.is_array(value); - status = napi_get_element(env, array_entry, 0, &name); - if (status != napi_ok) { - goto failed; - } + if (is_array) { + array_len = napi.get_array_length(value); - status = napi_get_element(env, array_entry, 1, &value); - if (status != napi_ok) { - goto failed; - } + for (j = 0; j < array_len; j++) { + array_val = napi.get_element(value, j); - status = napi_get_value_string_latin1(env, name, ptr, header_len, - &name_len); - if (status != napi_ok) { - goto failed; - } + val_type = napi.type_of(array_val); - name_ptr = ptr; + if (val_type != napi_string) { + array_val = napi.coerce_to_string(array_val); + } - ptr += name_len; - header_len -= name_len; + value_len = napi.get_value_string_latin1(array_val, ptr, + header_len); - hash = nxt_unit_field_hash(name_ptr, name_len); + f = req->response->fields + req->response->fields_count; + f->skip = 0; - status = napi_is_array(env, value, &is_array); - if (status != napi_ok) { - goto failed; - } + nxt_unit_sptr_set(&f->name, name_ptr); - if (is_array) { - status = napi_get_array_length(env, value, &array_len); - if (status != napi_ok) { - goto failed; - } + f->name_length = name_len; + f->hash = hash; - for (j = 0; j < array_len; j++) { - status = napi_get_element(env, value, j, &array_val); - if (status != napi_ok) { - goto failed; - } + nxt_unit_sptr_set(&f->value, ptr); + f->value_length = (uint32_t) value_len; + + ptr += value_len; + header_len -= value_len; - napi_typeof(env, array_val, &val_type); - if (status != napi_ok) { - goto failed; + req->response->fields_count++; } + } else { + val_type = napi.type_of(value); + if (val_type != napi_string) { - status = napi_coerce_to_string(env, array_val, &array_val); - if (status != napi_ok) { - goto failed; - } + value = napi.coerce_to_string(value); } - status = napi_get_value_string_latin1(env, array_val, ptr, - header_len, - &value_len); - if (status != napi_ok) { - goto failed; - } + value_len = napi.get_value_string_latin1(value, ptr, header_len); f = req->response->fields + req->response->fields_count; f->skip = 0; @@ -911,60 +550,22 @@ Unit::response_send_headers(napi_env env, napi_callback_info info) req->response->fields_count++; } - - } else { - napi_typeof(env, value, &val_type); - if (status != napi_ok) { - goto failed; - } - - if (val_type != napi_string) { - status = napi_coerce_to_string(env, value, &value); - if (status != napi_ok) { - goto failed; - } - } - - status = napi_get_value_string_latin1(env, value, ptr, header_len, - &value_len); - if (status != napi_ok) { - goto failed; - } - - f = req->response->fields + req->response->fields_count; - f->skip = 0; - - nxt_unit_sptr_set(&f->name, name_ptr); - - f->name_length = name_len; - f->hash = hash; - - nxt_unit_sptr_set(&f->value, ptr); - f->value_length = (uint32_t) value_len; - - ptr += value_len; - header_len -= value_len; - - req->response->fields_count++; } + + } catch (exception &e) { + napi.throw_error(e); + return nullptr; } req->response_buf->free = ptr; ret = nxt_unit_response_send(req); if (ret != NXT_UNIT_OK) { - goto failed; + napi.throw_error("Failed to send response"); + return nullptr; } return this_arg; - -failed: - - req->response->fields_count = 0; - - napi_throw_error(env, NULL, "Failed to write headers"); - - return nullptr; } @@ -974,8 +575,8 @@ Unit::response_write(napi_env env, napi_callback_info info) int ret; char *ptr; size_t argc, have_buf_len; - int64_t req_p; uint32_t buf_len; + nxt_napi napi(env); napi_value this_arg, req_num; napi_status status; nxt_unit_buf_t *buf; @@ -985,39 +586,23 @@ Unit::response_write(napi_env env, napi_callback_info info) argc = 3; - status = napi_get_cb_info(env, info, &argc, argv, &this_arg, NULL); - if (status != napi_ok) { - goto failed; - } - - if (argc != 3) { - napi_throw_error(env, NULL, "Wrong args count. Need two: " - "chunk, chunk length"); - return nullptr; - } - - status = napi_get_named_property(env, argv[0], "_req_point", &req_num); - if (status != napi_ok) { - napi_throw_error(env, NULL, "Failed to get request pointer"); - return nullptr; - } + try { + this_arg = napi.get_cb_info(info, argc, argv); + if (argc != 3) { + throw exception("Wrong args count. Expected: " + "chunk, chunk length"); + } - status = napi_get_value_int64(env, req_num, &req_p); - if (status != napi_ok) { - napi_throw_error(env, NULL, "Failed to get request pointer"); - return nullptr; - } + req_num = napi.get_named_property(argv[0], "_req_point"); + req = napi.get_request_info(req_num); - req = (nxt_unit_request_info_t *) (uintptr_t) req_p; + buf_len = napi.get_value_uint32(argv[2]); - status = napi_get_value_uint32(env, argv[2], &buf_len); - if (status != napi_ok) { - goto failed; - } + buf_type = napi.type_of(argv[1]); - status = napi_typeof(env, argv[1], &buf_type); - if (status != napi_ok) { - goto failed; + } catch (exception &e) { + napi.throw_error(e); + return nullptr; } buf_len++; @@ -1055,7 +640,7 @@ Unit::response_write(napi_env env, napi_callback_info info) failed: - napi_throw_error(env, NULL, "Failed to write body"); + napi.throw_error("Failed to write body"); return nullptr; } @@ -1065,33 +650,23 @@ napi_value Unit::response_end(napi_env env, napi_callback_info info) { size_t argc; - int64_t req_p; + nxt_napi napi(env); napi_value resp, this_arg, req_num; - napi_status status; nxt_unit_request_info_t *req; argc = 1; - status = napi_get_cb_info(env, info, &argc, &resp, &this_arg, NULL); - if (status != napi_ok) { - napi_throw_error(env, NULL, "Failed to finalize sending body"); - return nullptr; - } + try { + this_arg = napi.get_cb_info(info, argc, &resp); - status = napi_get_named_property(env, resp, "_req_point", &req_num); - if (status != napi_ok) { - napi_throw_error(env, NULL, "Failed to get request pointer"); - return nullptr; - } + req_num = napi.get_named_property(resp, "_req_point"); + req = napi.get_request_info(req_num); - status = napi_get_value_int64(env, req_num, &req_p); - if (status != napi_ok) { - napi_throw_error(env, NULL, "Failed to get request pointer"); + } catch (exception &e) { + napi.throw_error(e); return nullptr; } - req = (nxt_unit_request_info_t *) (uintptr_t) req_p; - nxt_unit_request_done(req, NXT_UNIT_OK); return this_arg; diff --git a/src/nodejs/unit-http/unit.h b/src/nodejs/unit-http/unit.h index db85e85c..e76d805a 100644 --- a/src/nodejs/unit-http/unit.h +++ b/src/nodejs/unit-http/unit.h @@ -6,34 +6,15 @@ #ifndef _NXT_NODEJS_UNIT_H_INCLUDED_ #define _NXT_NODEJS_UNIT_H_INCLUDED_ -#include +#include "nxt_napi.h" -#ifdef __cplusplus -extern "C" { -#endif -#include "version.h" -#include - -#if NXT_VERNUM != NXT_NODE_VERNUM -#error "libunit version mismatch." -#endif - -#include -#include - - -#ifdef __cplusplus -} /* extern "C" */ -#endif - - -class Unit { +class Unit : public nxt_napi { public: static napi_value init(napi_env env, napi_value exports); private: - Unit(napi_env env); + Unit(napi_env env, napi_value jsthis); ~Unit(); static napi_value create(napi_env env, napi_callback_info info); @@ -56,7 +37,7 @@ private: napi_value create_response(napi_value server_obj, napi_value socket, napi_value request, - nxt_unit_request_info_t *req, Unit *obj); + nxt_unit_request_info_t *req); static napi_value response_send_headers(napi_env env, napi_callback_info info); @@ -64,18 +45,16 @@ private: static napi_value response_write(napi_env env, napi_callback_info info); static napi_value response_end(napi_env env, napi_callback_info info); - napi_status create_headers(nxt_unit_request_info_t *req, - napi_value request); + void create_headers(nxt_unit_request_info_t *req, napi_value request); - inline napi_status append_header(nxt_unit_field_t *f, napi_value headers, + void append_header(nxt_unit_field_t *f, napi_value headers, napi_value raw_headers, uint32_t idx); static napi_ref constructor_; - napi_env env_; napi_ref wrapper_; nxt_unit_ctx_t *unit_ctx_; }; -#endif /* _NXT_NODEJS_H_INCLUDED_ */ +#endif /* _NXT_NODEJS_UNIT_H_INCLUDED_ */ -- cgit From 8557cb366092ea1bbc88386bdd79b9dad5867f19 Mon Sep 17 00:00:00 2001 From: Max Romanov Date: Mon, 1 Apr 2019 16:40:40 +0300 Subject: Introducing close event to notify about server stop. This closes #236 on GitHub. Thanks to 0xcdcdcdcd. --- src/nodejs/unit-http/http_server.js | 4 ++++ src/nodejs/unit-http/unit.cpp | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+) (limited to 'src') diff --git a/src/nodejs/unit-http/http_server.js b/src/nodejs/unit-http/http_server.js index 057a1f26..0ac5d649 100755 --- a/src/nodejs/unit-http/http_server.js +++ b/src/nodejs/unit-http/http_server.js @@ -387,6 +387,10 @@ Server.prototype.emit_events = function (server, req, res) { }); }; +Server.prototype.emit_close = function () { + this.emit('close'); +}; + function connectionListener(socket) { } diff --git a/src/nodejs/unit-http/unit.cpp b/src/nodejs/unit-http/unit.cpp index e4072851..e0cfaba3 100644 --- a/src/nodejs/unit-http/unit.cpp +++ b/src/nodejs/unit-http/unit.cpp @@ -313,6 +313,27 @@ Unit::remove_port(nxt_unit_ctx_t *ctx, nxt_unit_port_id_t *port_id) void Unit::quit(nxt_unit_ctx_t *ctx) { + Unit *obj; + napi_value server_obj, emit_close; + + obj = reinterpret_cast(ctx->unit->data); + + try { + nxt_handle_scope scope(obj->env()); + + server_obj = obj->get_server_object(); + + emit_close = obj->get_named_property(server_obj, "emit_close"); + + nxt_async_context async_context(obj->env(), "unit_quit"); + nxt_callback_scope async_scope(async_context); + + obj->make_callback(async_context, server_obj, emit_close, 0, NULL); + + } catch (exception &e) { + obj->throw_error(e); + } + nxt_unit_done(ctx); } -- cgit From 56101e47eebbb818718772c85a8ff3e689ef7bcd Mon Sep 17 00:00:00 2001 From: Max Romanov Date: Mon, 1 Apr 2019 16:40:49 +0300 Subject: Adding 'connection' to request as an alias to 'socket'. Adding actual 'remoteAddress' and 'localAddress' into socket object. This closes #232 issue on GitHub. --- src/nodejs/unit-http/unit.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/nodejs/unit-http/unit.cpp b/src/nodejs/unit-http/unit.cpp index e0cfaba3..6da890ce 100644 --- a/src/nodejs/unit-http/unit.cpp +++ b/src/nodejs/unit-http/unit.cpp @@ -399,15 +399,20 @@ Unit::append_header(nxt_unit_field_t *f, napi_value headers, napi_value Unit::create_socket(napi_value server_obj, nxt_unit_request_info_t *req) { - napi_value constructor, return_val; + napi_value constructor, res; + nxt_unit_request_t *r; + + r = req->request; constructor = get_named_property(server_obj, "socket"); - return_val = new_instance(constructor); + res = new_instance(constructor); - set_named_property(return_val, "req_pointer", (intptr_t) req); + set_named_property(res, "req_pointer", (intptr_t) req); + set_named_property(res, "remoteAddress", r->remote, r->remote_length); + set_named_property(res, "localAddress", r->local, r->local_length); - return return_val; + return res; } @@ -421,6 +426,7 @@ Unit::create_request(napi_value server_obj, napi_value socket) return_val = new_instance(constructor, server_obj); set_named_property(return_val, "socket", socket); + set_named_property(return_val, "connection", socket); return return_val; } @@ -437,6 +443,7 @@ Unit::create_response(napi_value server_obj, napi_value socket, return_val = new_instance(constructor, request); set_named_property(return_val, "socket", socket); + set_named_property(return_val, "connection", socket); set_named_property(return_val, "_req_point", (intptr_t) req); return return_val; -- cgit From 6241099db26d6451441887604be5e4ebc4e61885 Mon Sep 17 00:00:00 2001 From: Max Romanov Date: Tue, 2 Apr 2019 16:07:49 +0300 Subject: Removing unused variables and assignments. Warnings introduced in 53533ba0097c commit. --- src/nodejs/unit-http/unit.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/nodejs/unit-http/unit.cpp b/src/nodejs/unit-http/unit.cpp index 6da890ce..ebde01ce 100644 --- a/src/nodejs/unit-http/unit.cpp +++ b/src/nodejs/unit-http/unit.cpp @@ -77,9 +77,7 @@ Unit::destroy(napi_env env, void *nativeObject, void *finalize_hint) napi_value Unit::create(napi_env env, napi_callback_info info) { - Unit *obj; nxt_napi napi(env); - napi_ref ref; napi_value target, cons, instance, jsthis; try { @@ -89,9 +87,8 @@ Unit::create(napi_env env, napi_callback_info info) /* Invoked as constructor: `new Unit(...)`. */ jsthis = napi.get_cb_info(info); - obj = new Unit(env, jsthis); - - ref = napi.create_reference(jsthis); + new Unit(env, jsthis); + napi.create_reference(jsthis); return jsthis; } @@ -99,7 +96,7 @@ Unit::create(napi_env env, napi_callback_info info) /* Invoked as plain function `Unit(...)`, turn into construct call. */ cons = napi.get_reference_value(constructor_); instance = napi.new_instance(cons); - ref = napi.create_reference(instance); + napi.create_reference(instance); } catch (exception &e) { napi.throw_error(e); @@ -166,13 +163,13 @@ Unit::_read(napi_env env, napi_callback_info info) void *data; size_t argc; nxt_napi napi(env); - napi_value jsthis, buffer, argv; + napi_value buffer, argv; nxt_unit_request_info_t *req; argc = 1; try { - jsthis = napi.get_cb_info(info, argc, &argv); + napi.get_cb_info(info, argc, &argv); req = napi.get_request_info(argv); buffer = napi.create_buffer((size_t) req->content_length, &data); -- cgit From 7b839bf5da772d4bf61a3be95fbdbb6d4591ba63 Mon Sep 17 00:00:00 2001 From: Valentin Bartenev Date: Wed, 3 Apr 2019 18:40:47 +0300 Subject: Backed out changeset f74d4dd9c3db. This closes #240 issue on GitHub. --- src/nodejs/unit-http/http_server.js | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src') diff --git a/src/nodejs/unit-http/http_server.js b/src/nodejs/unit-http/http_server.js index 0ac5d649..ae8e204a 100755 --- a/src/nodejs/unit-http/http_server.js +++ b/src/nodejs/unit-http/http_server.js @@ -197,6 +197,14 @@ function writeHead(statusCode, reason, obj) { } }; +/* + * Some Node.js packages are known to be using this undocumented function, + * notably "compression" middleware. + */ +ServerResponse.prototype._implicitHeader = function _implicitHeader() { + this.writeHead(this.statusCode); +}; + ServerResponse.prototype._writeBody = function(chunk, encoding, callback) { var contentLength = 0; -- cgit From 8339b1515816ec8d3661514dc3edb73874580977 Mon Sep 17 00:00:00 2001 From: Igor Sysoev Date: Wed, 10 Apr 2019 13:47:34 +0300 Subject: Added support for wildcards in the middle of match patterns. --- src/nxt_conf_validation.c | 27 ++++++++-- src/nxt_http_route.c | 126 ++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 129 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/nxt_conf_validation.c b/src/nxt_conf_validation.c index ee87b0f6..e2e1b89e 100644 --- a/src/nxt_conf_validation.c +++ b/src/nxt_conf_validation.c @@ -741,6 +741,12 @@ nxt_conf_vldt_match_pattern(nxt_conf_validation_t *vldt, nxt_str_t pattern; nxt_uint_t i, first, last; + enum { + sw_none, + sw_side, + sw_middle + } state; + if (nxt_conf_type(value) != NXT_CONF_STRING) { return nxt_conf_vldt_error(vldt, "The \"match\" patterns must be strings."); @@ -754,17 +760,32 @@ nxt_conf_vldt_match_pattern(nxt_conf_validation_t *vldt, first = (pattern.start[0] == '!'); last = pattern.length - 1; + state = sw_none; for (i = first; i != pattern.length; i++) { + ch = pattern.start[i]; if (ch != '*') { continue; } - if (i != first && i != last) { - return nxt_conf_vldt_error(vldt, "The \"match\" patterns can only " - "contain \"*\" markers at the sides."); + switch (state) { + case sw_none: + state = (i == first) ? sw_side : sw_middle; + break; + + case sw_side: + if (i == last) { + break; + } + + /* Fall through. */ + + case sw_middle: + return nxt_conf_vldt_error(vldt, "The \"match\" patterns can " + "either contain \"*\" markers at " + "the sides or only one in the middle."); } } diff --git a/src/nxt_http_route.c b/src/nxt_http_route.c index 133c39ab..f1076b88 100644 --- a/src/nxt_http_route.c +++ b/src/nxt_http_route.c @@ -21,6 +21,7 @@ typedef enum { typedef enum { NXT_HTTP_ROUTE_PATTERN_EXACT = 0, NXT_HTTP_ROUTE_PATTERN_BEGIN, + NXT_HTTP_ROUTE_PATTERN_MIDDLE, NXT_HTTP_ROUTE_PATTERN_END, NXT_HTTP_ROUTE_PATTERN_SUBSTRING, } nxt_http_route_pattern_type_t; @@ -41,7 +42,10 @@ typedef struct { typedef struct { - nxt_str_t test; + u_char *start1; + u_char *start2; + uint32_t length1; + uint32_t length2; uint32_t min_length; nxt_http_route_pattern_type_t type:8; @@ -90,6 +94,8 @@ static int nxt_http_pattern_compare(const void *one, const void *two); static nxt_int_t nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp, nxt_conf_value_t *cv, nxt_http_route_pattern_t *pattern, nxt_http_route_pattern_case_t pattern_case); +static u_char *nxt_http_route_pattern_copy(nxt_mp_t *mp, nxt_str_t *test, + nxt_http_route_pattern_case_t pattern_case); static void nxt_http_route_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, nxt_http_route_t *route); @@ -107,6 +113,8 @@ static nxt_bool_t nxt_http_route_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule); static nxt_bool_t nxt_http_route_pattern(nxt_http_request_t *r, nxt_http_route_pattern_t *pattern, u_char *start, size_t length); +static nxt_bool_t nxt_http_route_memcmp(u_char *start, u_char *test, + size_t length, nxt_bool_t case_sensitive); nxt_http_routes_t * @@ -407,8 +415,12 @@ nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp, { u_char *start; nxt_str_t test; + nxt_uint_t n, length; nxt_http_route_pattern_type_t type; + /* Suppress warning about uninitialized variable. */ + length = 0; + type = NXT_HTTP_ROUTE_PATTERN_EXACT; nxt_conf_get_string(cv, &test); @@ -448,37 +460,79 @@ nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp, } else if (test.start[test.length - 1] == '*') { test.length--; type = NXT_HTTP_ROUTE_PATTERN_BEGIN; + + } else { + length = test.length - 1; + + for (n = 1; n < length; n++) { + if (test.start[n] == '*') { + test.length = n; + type = NXT_HTTP_ROUTE_PATTERN_MIDDLE; + break; + } + } } } } pattern->type = type; pattern->min_length = test.length; - pattern->test.length = test.length; + pattern->length1 = test.length; - start = nxt_mp_nget(mp, test.length); + start = nxt_http_route_pattern_copy(mp, &test, pattern_case); if (nxt_slow_path(start == NULL)) { return NXT_ERROR; } - pattern->test.start = start; + pattern->start1 = start; + + if (type == NXT_HTTP_ROUTE_PATTERN_MIDDLE) { + length -= test.length; + pattern->length2 = length; + pattern->min_length += length; + + test.start = &test.start[test.length + 1]; + test.length = length; + + start = nxt_http_route_pattern_copy(mp, &test, pattern_case); + if (nxt_slow_path(start == NULL)) { + return NXT_ERROR; + } + + pattern->start2 = start; + } + + return NXT_OK; +} + + +static u_char * +nxt_http_route_pattern_copy(nxt_mp_t *mp, nxt_str_t *test, + nxt_http_route_pattern_case_t pattern_case) +{ + u_char *start; + + start = nxt_mp_nget(mp, test->length); + if (nxt_slow_path(start == NULL)) { + return start; + } switch (pattern_case) { case NXT_HTTP_ROUTE_PATTERN_UPCASE: - nxt_memcpy_upcase(start, test.start, test.length); + nxt_memcpy_upcase(start, test->start, test->length); break; case NXT_HTTP_ROUTE_PATTERN_LOWCASE: - nxt_memcpy_lowcase(start, test.start, test.length); + nxt_memcpy_lowcase(start, test->start, test->length); break; case NXT_HTTP_ROUTE_PATTERN_NOCASE: - nxt_memcpy(start, test.start, test.length); + nxt_memcpy(start, test->start, test->length); break; } - return NXT_OK; + return start; } @@ -805,18 +859,21 @@ static nxt_bool_t nxt_http_route_pattern(nxt_http_request_t *r, nxt_http_route_pattern_t *pattern, u_char *start, size_t length) { - nxt_str_t *test; + u_char *p, *end, *test; + size_t test_length; + nxt_bool_t ret; if (length < pattern->min_length) { return 0; } - test = &pattern->test; + test = pattern->start1; + test_length = pattern->length1; switch (pattern->type) { case NXT_HTTP_ROUTE_PATTERN_EXACT: - if (length != test->length) { + if (length != test_length) { return 0; } @@ -825,25 +882,52 @@ nxt_http_route_pattern(nxt_http_request_t *r, nxt_http_route_pattern_t *pattern, case NXT_HTTP_ROUTE_PATTERN_BEGIN: break; + case NXT_HTTP_ROUTE_PATTERN_MIDDLE: + ret = nxt_http_route_memcmp(start, test, test_length, + pattern->case_sensitive); + if (!ret) { + return ret; + } + + test = pattern->start2; + test_length = pattern->length2; + + /* Fall through. */ + case NXT_HTTP_ROUTE_PATTERN_END: - start += length - test->length; + start += length - test_length; break; case NXT_HTTP_ROUTE_PATTERN_SUBSTRING: + end = start + length; + if (pattern->case_sensitive) { - return (nxt_memstrn(start, start + length, - (char *) test->start, test->length) - != NULL); + p = nxt_memstrn(start, end, (char *) test, test_length); + + } else { + p = nxt_memcasestrn(start, end, (char *) test, test_length); } - return (nxt_memcasestrn(start, start + length, - (char *) test->start, test->length) - != NULL); + return (p != NULL); } - if (pattern->case_sensitive) { - return (nxt_memcmp(start, test->start, test->length) == 0); + return nxt_http_route_memcmp(start, test, test_length, + pattern->case_sensitive); +} + + +static nxt_bool_t +nxt_http_route_memcmp(u_char *start, u_char *test, size_t test_length, + nxt_bool_t case_sensitive) +{ + nxt_int_t n; + + if (case_sensitive) { + n = nxt_memcmp(start, test, test_length); + + } else { + n = nxt_memcasecmp(start, test, test_length); } - return (nxt_memcasecmp(start, test->start, test->length) == 0); + return (n == 0); } -- cgit From f0cc14d394ddad4d9dfd98f7fe925605eed1fa3d Mon Sep 17 00:00:00 2001 From: Valentin Bartenev Date: Fri, 12 Apr 2019 17:44:54 +0300 Subject: Simplified cycles in nxt_http_route_rule(). --- src/nxt_http_route.c | 64 ++++++++++++++++++++-------------------------------- 1 file changed, 24 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/src/nxt_http_route.c b/src/nxt_http_route.c index f1076b88..526f9472 100644 --- a/src/nxt_http_route.c +++ b/src/nxt_http_route.c @@ -539,20 +539,18 @@ nxt_http_route_pattern_copy(nxt_mp_t *mp, nxt_str_t *test, void nxt_http_routes_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) { - nxt_uint_t items; - nxt_http_route_t **route; + nxt_http_route_t **route, **end; nxt_http_routes_t *routes; routes = tmcf->router_conf->routes; if (routes != NULL) { - items = routes->items; route = &routes->route[0]; + end = route + routes->items; - while (items != 0) { + while (route < end) { nxt_http_route_resolve(task, tmcf, *route); route++; - items--; } } } @@ -562,17 +560,15 @@ static void nxt_http_route_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, nxt_http_route_t *route) { - nxt_uint_t items; - nxt_http_route_match_t **match; + nxt_http_route_match_t **match, **end; - items = route->items; match = &route->match[0]; + end = match + route->items; - while (items != 0) { + while (match < end) { nxt_http_pass_resolve(task, tmcf, &(*match)->pass); match++; - items--; } } @@ -615,11 +611,10 @@ nxt_http_pass_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, static nxt_http_route_t * nxt_http_route_find(nxt_http_routes_t *routes, nxt_str_t *name) { - nxt_uint_t items; - nxt_http_route_t **route; + nxt_http_route_t **route, **end; - items = routes->items; route = &routes->route[0]; + end = route + routes->items; do { if (nxt_strstr_eq(&(*route)->name, name)) { @@ -627,9 +622,8 @@ nxt_http_route_find(nxt_http_routes_t *routes, nxt_str_t *name) } route++; - items--; - } while (items != 0); + } while (route < end); return NULL; } @@ -681,20 +675,18 @@ nxt_http_pass_application(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, void nxt_http_routes_cleanup(nxt_task_t *task, nxt_http_routes_t *routes) { - nxt_uint_t items; - nxt_http_route_t **route; + nxt_http_route_t **route, **end; if (routes != NULL) { - items = routes->items; route = &routes->route[0]; + end = route + routes->items; do { nxt_http_route_cleanup(task, *route); route++; - items--; - } while (items != 0); + } while (route < end); } } @@ -702,19 +694,17 @@ nxt_http_routes_cleanup(nxt_task_t *task, nxt_http_routes_t *routes) static void nxt_http_route_cleanup(nxt_task_t *task, nxt_http_route_t *route) { - nxt_uint_t items; - nxt_http_route_match_t **match; + nxt_http_route_match_t **match, **end; - items = route->items; match = &route->match[0]; + end = match + route->items; do { nxt_http_pass_cleanup(task, &(*match)->pass); match++; - items--; - } while (items != 0); + } while (match < end); } @@ -731,23 +721,21 @@ static nxt_http_pass_t * nxt_http_route_pass(nxt_task_t *task, nxt_http_request_t *r, nxt_http_pass_t *start) { - nxt_uint_t items; nxt_http_pass_t *pass; nxt_http_route_t *route; - nxt_http_route_match_t **match; + nxt_http_route_match_t **match, **end; route = start->u.route; - items = route->items; match = &route->match[0]; + end = match + route->items; - while (items != 0) { + while (match < end) { pass = nxt_http_route_match(r, *match); if (pass != NULL) { return pass; } match++; - items--; } nxt_http_request_error(task, r, NXT_HTTP_NOT_FOUND); @@ -759,19 +747,17 @@ nxt_http_route_pass(nxt_task_t *task, nxt_http_request_t *r, static nxt_http_pass_t * nxt_http_route_match(nxt_http_request_t *r, nxt_http_route_match_t *match) { - nxt_uint_t items; - nxt_http_route_rule_t **rule; + nxt_http_route_rule_t **rule, **end; rule = &match->rule[0]; - items = match->items; + end = rule + match->items; - while (items != 0) { + while (rule < end) { if (!nxt_http_route_rule(r, *rule)) { return NULL; } rule++; - items--; } return &match->pass; @@ -785,10 +771,9 @@ nxt_http_route_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule) u_char *start; size_t length; nxt_str_t *s; - nxt_uint_t items; nxt_bool_t ret; nxt_http_field_t *f; - nxt_http_route_pattern_t *pattern; + nxt_http_route_pattern_t *pattern, *end; p = nxt_pointer_to(r, rule->offset); @@ -834,8 +819,8 @@ nxt_http_route_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule) } } - items = rule->items; pattern = &rule->pattern[0]; + end = pattern + rule->items; do { ret = nxt_http_route_pattern(r, pattern, start, length); @@ -847,9 +832,8 @@ nxt_http_route_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule) } pattern++; - items--; - } while (items != 0); + } while (pattern < end); return ret; } -- cgit From 5e1cf14565675ad1bbc983901a33ab6fe7e0c906 Mon Sep 17 00:00:00 2001 From: Valentin Bartenev Date: Fri, 12 Apr 2019 17:44:55 +0300 Subject: Controller: rejecting double wildcards. --- src/nxt_conf_validation.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nxt_conf_validation.c b/src/nxt_conf_validation.c index e2e1b89e..aedcc605 100644 --- a/src/nxt_conf_validation.c +++ b/src/nxt_conf_validation.c @@ -777,7 +777,12 @@ nxt_conf_vldt_match_pattern(nxt_conf_validation_t *vldt, case sw_side: if (i == last) { - break; + if (last - first != 1) { + break; + } + + return nxt_conf_vldt_error(vldt, "The \"match\" pattern must " + "not contain double \"*\" markers."); } /* Fall through. */ -- cgit From c6e96647a1fb71821a7e3e40b7b798da0f7c0e6b Mon Sep 17 00:00:00 2001 From: Max Romanov Date: Wed, 17 Apr 2019 19:15:41 +0300 Subject: Node.js: using low-case header names as key in req.headers. Node.js modules (body-parser, row-body) search low-cased names ('content-length', 'content-type' etc.) to properly assemble request body. This closes #246 issue on GitHub. --- src/nodejs/unit-http/unit.cpp | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/nodejs/unit-http/unit.cpp b/src/nodejs/unit-http/unit.cpp index ebde01ce..3f66189a 100644 --- a/src/nodejs/unit-http/unit.cpp +++ b/src/nodejs/unit-http/unit.cpp @@ -376,18 +376,31 @@ Unit::create_headers(nxt_unit_request_info_t *req, napi_value request) } +inline char +lowcase(char c) +{ + return (c >= 'A' && c <= 'Z') ? (c | 0x20) : c; +} + + inline void Unit::append_header(nxt_unit_field_t *f, napi_value headers, napi_value raw_headers, uint32_t idx) { - const char *name; - napi_value str, vstr; + char *name; + uint8_t i; + napi_value str, vstr; - name = (const char *) nxt_unit_sptr_get(&f->name); + name = (char *) nxt_unit_sptr_get(&f->name); - vstr = set_named_property(headers, name, f->value, f->value_length); str = create_string_latin1(name, f->name_length); + for (i = 0; i < f->name_length; i++) { + name[i] = lowcase(name[i]); + } + + vstr = set_named_property(headers, name, f->value, f->value_length); + set_element(raw_headers, idx * 2, str); set_element(raw_headers, idx * 2 + 1, vstr); } -- cgit From 1467d34d733fcbecb7cbc7289c3415cb14bf6603 Mon Sep 17 00:00:00 2001 From: Valentin Bartenev Date: Wed, 24 Apr 2019 20:31:00 +0300 Subject: Removed unused field from nxt_conf_op_s. --- src/nxt_conf.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/nxt_conf.c b/src/nxt_conf.c index 4c6d8839..08b0a029 100644 --- a/src/nxt_conf.c +++ b/src/nxt_conf.c @@ -87,7 +87,6 @@ struct nxt_conf_op_s { uint32_t index; uint32_t action; /* nxt_conf_op_action_t */ void *ctx; - nxt_conf_op_t *next; }; @@ -1015,7 +1014,7 @@ nxt_conf_copy_object(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst, break; } - op = op->next; + op = NULL; } } while (d != count); -- cgit From 30768b7b3c944425f4176fdf05946a684ba5a7ea Mon Sep 17 00:00:00 2001 From: Valentin Bartenev Date: Wed, 24 Apr 2019 20:31:00 +0300 Subject: Refactored nxt_conf_op_compile(). Now index is always initialized for create operations. The changes in nxt_conf_op_compile() simplify adding upcoming support of operations with arrays. No functional changes. --- src/nxt_conf.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/nxt_conf.c b/src/nxt_conf.c index 08b0a029..5ec86cd4 100644 --- a/src/nxt_conf.c +++ b/src/nxt_conf.c @@ -741,6 +741,7 @@ nxt_conf_op_compile(nxt_mp_t *mp, nxt_conf_op_t **ops, nxt_conf_value_t *root, { nxt_str_t token; nxt_conf_op_t *op, **parent; + nxt_conf_value_t *node; nxt_conf_path_parse_t parse; nxt_conf_object_member_t *member; @@ -761,22 +762,23 @@ nxt_conf_op_compile(nxt_mp_t *mp, nxt_conf_op_t **ops, nxt_conf_value_t *root, nxt_conf_path_next_token(&parse, &token); - root = nxt_conf_get_object_member(root, &token, &op->index); + node = nxt_conf_get_object_member(root, &token, &op->index); if (parse.last) { break; } - if (root == NULL) { + if (node == NULL) { return NXT_DECLINED; } op->action = NXT_CONF_OP_PASS; + root = node; } if (value == NULL) { - if (root == NULL) { + if (node == NULL) { return NXT_DECLINED; } @@ -785,7 +787,7 @@ nxt_conf_op_compile(nxt_mp_t *mp, nxt_conf_op_t **ops, nxt_conf_value_t *root, return NXT_OK; } - if (root == NULL) { + if (node == NULL) { member = nxt_mp_zget(mp, sizeof(nxt_conf_object_member_t)); if (nxt_slow_path(member == NULL)) { @@ -796,6 +798,7 @@ nxt_conf_op_compile(nxt_mp_t *mp, nxt_conf_op_t **ops, nxt_conf_value_t *root, member->value = *value; + op->index = root->u.object->count; op->action = NXT_CONF_OP_CREATE; op->ctx = member; @@ -938,9 +941,7 @@ nxt_conf_copy_object(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst, do { if (pass_op == NULL) { - index = (op == NULL || op->action == NXT_CONF_OP_CREATE) - ? src->u.object->count - : op->index; + index = (op == NULL) ? src->u.object->count : op->index; } while (s != index) { -- cgit From 4d35a7bbacb1013388491140964dab8ffab1d0ae Mon Sep 17 00:00:00 2001 From: Valentin Bartenev Date: Wed, 24 Apr 2019 20:31:00 +0300 Subject: Configuration: support for manipulations of array elements. Now PUT and DELETE operations also work on elements. This closes #242 issue on GitHub. --- src/nxt_conf.c | 170 +++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 141 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/nxt_conf.c b/src/nxt_conf.c index 5ec86cd4..fd6a62f5 100644 --- a/src/nxt_conf.c +++ b/src/nxt_conf.c @@ -112,6 +112,8 @@ static void nxt_conf_json_parse_error(nxt_conf_json_error_t *error, u_char *pos, static nxt_int_t nxt_conf_copy_value(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst, nxt_conf_value_t *src); +static nxt_int_t nxt_conf_copy_array(nxt_mp_t *mp, nxt_conf_op_t *op, + nxt_conf_value_t *dst, nxt_conf_value_t *src); static nxt_int_t nxt_conf_copy_object(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst, nxt_conf_value_t *src); @@ -740,6 +742,7 @@ nxt_conf_op_compile(nxt_mp_t *mp, nxt_conf_op_t **ops, nxt_conf_value_t *root, nxt_str_t *path, nxt_conf_value_t *value) { nxt_str_t token; + nxt_int_t index; nxt_conf_op_t *op, **parent; nxt_conf_value_t *node; nxt_conf_path_parse_t parse; @@ -762,7 +765,27 @@ nxt_conf_op_compile(nxt_mp_t *mp, nxt_conf_op_t **ops, nxt_conf_value_t *root, nxt_conf_path_next_token(&parse, &token); - node = nxt_conf_get_object_member(root, &token, &op->index); + switch (root->type) { + + case NXT_CONF_VALUE_OBJECT: + node = nxt_conf_get_object_member(root, &token, &op->index); + break; + + case NXT_CONF_VALUE_ARRAY: + index = nxt_int_parse(token.start, token.length); + + if (index < 0 || index > NXT_INT32_T_MAX) { + return NXT_DECLINED; + } + + op->index = index; + + node = nxt_conf_get_array_element(root, index); + break; + + default: + node = NULL; + } if (parse.last) { break; @@ -787,8 +810,23 @@ nxt_conf_op_compile(nxt_mp_t *mp, nxt_conf_op_t **ops, nxt_conf_value_t *root, return NXT_OK; } - if (node == NULL) { + if (node != NULL) { + op->action = NXT_CONF_OP_REPLACE; + op->ctx = value; + + return NXT_OK; + } + + op->action = NXT_CONF_OP_CREATE; + + if (root->type == NXT_CONF_VALUE_ARRAY) { + if (op->index > root->u.array->count) { + return NXT_DECLINED; + } + + op->ctx = value; + } else { member = nxt_mp_zget(mp, sizeof(nxt_conf_object_member_t)); if (nxt_slow_path(member == NULL)) { return NXT_ERROR; @@ -799,12 +837,7 @@ nxt_conf_op_compile(nxt_mp_t *mp, nxt_conf_op_t **ops, nxt_conf_value_t *root, member->value = *value; op->index = root->u.object->count; - op->action = NXT_CONF_OP_CREATE; op->ctx = member; - - } else { - op->action = NXT_CONF_OP_REPLACE; - op->ctx = value; } return NXT_OK; @@ -836,16 +869,13 @@ static nxt_int_t nxt_conf_copy_value(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst, nxt_conf_value_t *src) { - size_t size; - nxt_int_t rc; - nxt_uint_t n; - - if (op != NULL && src->type != NXT_CONF_VALUE_OBJECT) { + if (op != NULL + && src->type != NXT_CONF_VALUE_ARRAY + && src->type != NXT_CONF_VALUE_OBJECT) + { return NXT_ERROR; } - dst->type = src->type; - switch (src->type) { case NXT_CONF_VALUE_STRING: @@ -863,34 +893,116 @@ nxt_conf_copy_value(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst, break; case NXT_CONF_VALUE_ARRAY: + return nxt_conf_copy_array(mp, op, dst, src); - size = sizeof(nxt_conf_array_t) - + src->u.array->count * sizeof(nxt_conf_value_t); + case NXT_CONF_VALUE_OBJECT: + return nxt_conf_copy_object(mp, op, dst, src); - dst->u.array = nxt_mp_get(mp, size); - if (nxt_slow_path(dst->u.array == NULL)) { - return NXT_ERROR; + default: + dst->u = src->u; + } + + dst->type = src->type; + + return NXT_OK; +} + + +static nxt_int_t +nxt_conf_copy_array(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst, + nxt_conf_value_t *src) +{ + size_t size; + nxt_int_t rc; + nxt_uint_t s, d, count, index; + nxt_conf_op_t *pass_op; + nxt_conf_value_t *value; + + count = src->u.array->count; + + if (op != NULL) { + if (op->action == NXT_CONF_OP_CREATE) { + count++; + + } else if (op->action == NXT_CONF_OP_DELETE) { + count--; } + } - dst->u.array->count = src->u.array->count; + size = sizeof(nxt_conf_array_t) + count * sizeof(nxt_conf_value_t); - for (n = 0; n < src->u.array->count; n++) { - rc = nxt_conf_copy_value(mp, NULL, &dst->u.array->elements[n], - &src->u.array->elements[n]); + dst->u.array = nxt_mp_get(mp, size); + if (nxt_slow_path(dst->u.array == NULL)) { + return NXT_ERROR; + } + + dst->u.array->count = count; + + s = 0; + d = 0; + + pass_op = NULL; + /* + * This initialization is needed only to + * suppress a warning on GCC 4.8 and older. + */ + index = 0; + + do { + if (pass_op == NULL) { + index = (op == NULL) ? src->u.array->count : op->index; + } + + while (s != index) { + rc = nxt_conf_copy_value(mp, pass_op, &dst->u.array->elements[d], + &src->u.array->elements[s]); if (nxt_slow_path(rc != NXT_OK)) { return NXT_ERROR; } + + s++; + d++; } - break; + if (pass_op != NULL) { + pass_op = NULL; + continue; + } - case NXT_CONF_VALUE_OBJECT: - return nxt_conf_copy_object(mp, op, dst, src); + if (op != NULL) { + switch (op->action) { + case NXT_CONF_OP_PASS: + pass_op = op->ctx; + index++; + break; - default: - dst->u = src->u; - } + case NXT_CONF_OP_CREATE: + value = op->ctx; + dst->u.array->elements[d] = *value; + + d++; + break; + + case NXT_CONF_OP_REPLACE: + value = op->ctx; + dst->u.array->elements[d] = *value; + + s++; + d++; + break; + + case NXT_CONF_OP_DELETE: + s++; + break; + } + + op = NULL; + } + + } while (d != count); + + dst->type = src->type; return NXT_OK; } -- cgit From 6a6bc63c48501027f01d16fbd211eb4425c1a1e8 Mon Sep 17 00:00:00 2001 From: Valentin Bartenev Date: Wed, 24 Apr 2019 20:31:00 +0300 Subject: Configuration: support for POST operations on arrays. It allows to add an array element without specifying the index. --- src/nxt_conf.c | 47 ++++++++++++++++++++++++++++++++++++----------- src/nxt_conf.h | 13 +++++++++++-- src/nxt_controller.c | 34 +++++++++++++++++++++++++++------- 3 files changed, 74 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/nxt_conf.c b/src/nxt_conf.c index fd6a62f5..57870838 100644 --- a/src/nxt_conf.c +++ b/src/nxt_conf.c @@ -737,9 +737,9 @@ nxt_conf_array_qsort(nxt_conf_value_t *value, } -nxt_int_t +nxt_conf_op_ret_t nxt_conf_op_compile(nxt_mp_t *mp, nxt_conf_op_t **ops, nxt_conf_value_t *root, - nxt_str_t *path, nxt_conf_value_t *value) + nxt_str_t *path, nxt_conf_value_t *value, nxt_bool_t add) { nxt_str_t token; nxt_int_t index; @@ -757,7 +757,7 @@ nxt_conf_op_compile(nxt_mp_t *mp, nxt_conf_op_t **ops, nxt_conf_value_t *root, for ( ;; ) { op = nxt_mp_zget(mp, sizeof(nxt_conf_op_t)); if (nxt_slow_path(op == NULL)) { - return NXT_ERROR; + return NXT_CONF_OP_ERROR; } *parent = op; @@ -775,7 +775,7 @@ nxt_conf_op_compile(nxt_mp_t *mp, nxt_conf_op_t **ops, nxt_conf_value_t *root, index = nxt_int_parse(token.start, token.length); if (index < 0 || index > NXT_INT32_T_MAX) { - return NXT_DECLINED; + return NXT_CONF_OP_NOT_FOUND; } op->index = index; @@ -792,7 +792,7 @@ nxt_conf_op_compile(nxt_mp_t *mp, nxt_conf_op_t **ops, nxt_conf_value_t *root, } if (node == NULL) { - return NXT_DECLINED; + return NXT_CONF_OP_NOT_FOUND; } op->action = NXT_CONF_OP_PASS; @@ -802,26 +802,51 @@ nxt_conf_op_compile(nxt_mp_t *mp, nxt_conf_op_t **ops, nxt_conf_value_t *root, if (value == NULL) { if (node == NULL) { - return NXT_DECLINED; + return NXT_CONF_OP_NOT_FOUND; } op->action = NXT_CONF_OP_DELETE; - return NXT_OK; + return NXT_CONF_OP_OK; + } + + if (add) { + if (node == NULL) { + return NXT_CONF_OP_NOT_FOUND; + } + + if (node->type != NXT_CONF_VALUE_ARRAY) { + return NXT_CONF_OP_NOT_ALLOWED; + } + + op->action = NXT_CONF_OP_PASS; + + op = nxt_mp_zget(mp, sizeof(nxt_conf_op_t)); + if (nxt_slow_path(op == NULL)) { + return NXT_CONF_OP_ERROR; + } + + *parent = op; + + op->index = node->u.array->count; + op->action = NXT_CONF_OP_CREATE; + op->ctx = value; + + return NXT_CONF_OP_OK; } if (node != NULL) { op->action = NXT_CONF_OP_REPLACE; op->ctx = value; - return NXT_OK; + return NXT_CONF_OP_OK; } op->action = NXT_CONF_OP_CREATE; if (root->type == NXT_CONF_VALUE_ARRAY) { if (op->index > root->u.array->count) { - return NXT_DECLINED; + return NXT_CONF_OP_NOT_FOUND; } op->ctx = value; @@ -829,7 +854,7 @@ nxt_conf_op_compile(nxt_mp_t *mp, nxt_conf_op_t **ops, nxt_conf_value_t *root, } else { member = nxt_mp_zget(mp, sizeof(nxt_conf_object_member_t)); if (nxt_slow_path(member == NULL)) { - return NXT_ERROR; + return NXT_CONF_OP_ERROR; } nxt_conf_set_string(&member->name, &token); @@ -840,7 +865,7 @@ nxt_conf_op_compile(nxt_mp_t *mp, nxt_conf_op_t **ops, nxt_conf_value_t *root, op->ctx = member; } - return NXT_OK; + return NXT_CONF_OP_OK; } diff --git a/src/nxt_conf.h b/src/nxt_conf.h index 20ff3b1e..2435b0e2 100644 --- a/src/nxt_conf.h +++ b/src/nxt_conf.h @@ -20,6 +20,14 @@ typedef enum { } nxt_conf_type_t; +typedef enum { + NXT_CONF_OP_OK = 0, + NXT_CONF_OP_NOT_FOUND, + NXT_CONF_OP_NOT_ALLOWED, + NXT_CONF_OP_ERROR, +} nxt_conf_op_ret_t; + + typedef struct nxt_conf_value_s nxt_conf_value_t; typedef struct nxt_conf_op_s nxt_conf_op_t; @@ -80,8 +88,9 @@ NXT_EXPORT nxt_conf_value_t *nxt_conf_get_array_element(nxt_conf_value_t *value, NXT_EXPORT nxt_int_t nxt_conf_map_object(nxt_mp_t *mp, nxt_conf_value_t *value, nxt_conf_map_t *map, nxt_uint_t n, void *data); -nxt_int_t nxt_conf_op_compile(nxt_mp_t *mp, nxt_conf_op_t **ops, - nxt_conf_value_t *root, nxt_str_t *path, nxt_conf_value_t *value); +nxt_conf_op_ret_t nxt_conf_op_compile(nxt_mp_t *mp, nxt_conf_op_t **ops, + nxt_conf_value_t *root, nxt_str_t *path, nxt_conf_value_t *value, + nxt_bool_t add); nxt_conf_value_t *nxt_conf_clone(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *value); diff --git a/src/nxt_controller.c b/src/nxt_controller.c index d5534f49..49afbe46 100644 --- a/src/nxt_controller.c +++ b/src/nxt_controller.c @@ -930,6 +930,7 @@ nxt_controller_process_config(nxt_task_t *task, nxt_controller_request_t *req, nxt_mp_t *mp; nxt_int_t rc; nxt_conn_t *c; + nxt_bool_t post; nxt_buf_mem_t *mbuf; nxt_conf_op_t *ops; nxt_conf_value_t *value; @@ -958,7 +959,18 @@ nxt_controller_process_config(nxt_task_t *task, nxt_controller_request_t *req, return; } - if (nxt_str_eq(&req->parser.method, "PUT", 3)) { + if (nxt_str_eq(&req->parser.method, "POST", 4)) { + if (path->length == 1) { + goto not_allowed; + } + + post = 1; + + } else { + post = 0; + } + + if (post || nxt_str_eq(&req->parser.method, "PUT", 3)) { if (!nxt_queue_is_empty(&nxt_controller_waiting_requests)) { nxt_queue_insert_tail(&nxt_controller_waiting_requests, &req->link); @@ -1000,15 +1012,20 @@ nxt_controller_process_config(nxt_task_t *task, nxt_controller_request_t *req, if (path->length != 1) { rc = nxt_conf_op_compile(c->mem_pool, &ops, nxt_controller_conf.root, - path, value); + path, value, post); - if (rc != NXT_OK) { + if (rc != NXT_CONF_OP_OK) { nxt_mp_destroy(mp); - if (rc == NXT_DECLINED) { + switch (rc) { + case NXT_CONF_OP_NOT_FOUND: goto not_found; + + case NXT_CONF_OP_NOT_ALLOWED: + goto not_allowed; } + /* rc == NXT_CONF_OP_ERROR */ goto alloc_fail; } @@ -1080,13 +1097,14 @@ nxt_controller_process_config(nxt_task_t *task, nxt_controller_request_t *req, } else { rc = nxt_conf_op_compile(c->mem_pool, &ops, nxt_controller_conf.root, - path, NULL); + path, NULL, 0); if (rc != NXT_OK) { - if (rc == NXT_DECLINED) { + if (rc == NXT_CONF_OP_NOT_FOUND) { goto not_found; } + /* rc == NXT_CONF_OP_ERROR */ goto alloc_fail; } @@ -1145,8 +1163,10 @@ nxt_controller_process_config(nxt_task_t *task, nxt_controller_request_t *req, return; } +not_allowed: + resp.status = 405; - resp.title = (u_char *) "Invalid method."; + resp.title = (u_char *) "Method isn't allowed."; resp.offset = -1; nxt_controller_response(task, req, &resp); -- cgit From 6a2928b4bf3c57685b707c17eb0c147d68be1dd6 Mon Sep 17 00:00:00 2001 From: Max Romanov Date: Thu, 30 May 2019 15:02:07 +0300 Subject: Java: fixing request scheme using 'tls' flag. --- src/java/nginx/unit/Request.java | 2 +- src/java/nxt_jni_Request.c | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/java/nginx/unit/Request.java b/src/java/nginx/unit/Request.java index b46d3f59..3ba46f6c 100644 --- a/src/java/nginx/unit/Request.java +++ b/src/java/nginx/unit/Request.java @@ -920,7 +920,7 @@ public class Request implements HttpServletRequest, DynamicPathRequest @Override public String getScheme() { - log("getScheme"); + trace("getScheme"); return getScheme(req_ptr); } diff --git a/src/java/nxt_jni_Request.c b/src/java/nxt_jni_Request.c index a9fbe0e4..733290dd 100644 --- a/src/java/nxt_jni_Request.c +++ b/src/java/nxt_jni_Request.c @@ -542,7 +542,11 @@ nxt_java_Request_getRemotePort(JNIEnv *env, jclass cls, jlong req_ptr) static jstring JNICALL nxt_java_Request_getScheme(JNIEnv *env, jclass cls, jlong req_ptr) { - return (*env)->NewStringUTF(env, "http"); + nxt_unit_request_t *r; + + r = nxt_jlong2ptr(req_ptr); + + return (*env)->NewStringUTF(env, r->tls ? "https" : "http"); } -- cgit From 82415397346b7d8953b094f6dce867c1afdde420 Mon Sep 17 00:00:00 2001 From: Max Romanov Date: Thu, 30 May 2019 15:02:09 +0300 Subject: Java: fixing typo in context initialization. --- src/java/nxt_jni_Context.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/java/nxt_jni_Context.c b/src/java/nxt_jni_Context.c index 8f7adddf..589e1c5b 100644 --- a/src/java/nxt_jni_Context.c +++ b/src/java/nxt_jni_Context.c @@ -55,7 +55,7 @@ nxt_java_initContext(JNIEnv *env, jobject cl) } nxt_java_Context_stop = (*env)->GetMethodID(env, cls, "stop", "()V"); - if (nxt_java_Context_service == NULL) { + if (nxt_java_Context_stop == NULL) { nxt_unit_warn(NULL, "nginx.unit.Context.stop() not found"); goto failed; } -- cgit From f2aa190f60cc3b6e8b4eb09b044eaea1f4087a0a Mon Sep 17 00:00:00 2001 From: Igor Sysoev Date: Thu, 30 May 2019 15:33:51 +0300 Subject: Fixed segfault with empty rule array. --- src/nxt_http_route.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/nxt_http_route.c b/src/nxt_http_route.c index 526f9472..2a41d7fa 100644 --- a/src/nxt_http_route.c +++ b/src/nxt_http_route.c @@ -819,10 +819,11 @@ nxt_http_route_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule) } } + ret = 1; pattern = &rule->pattern[0]; end = pattern + rule->items; - do { + while (pattern < end) { ret = nxt_http_route_pattern(r, pattern, start, length); ret ^= pattern->negative; @@ -832,8 +833,7 @@ nxt_http_route_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule) } pattern++; - - } while (pattern < end); + } return ret; } -- cgit From 3aaebe4169f80707e495f1111b7ab9c2dcb79b6d Mon Sep 17 00:00:00 2001 From: Igor Sysoev Date: Thu, 30 May 2019 15:33:51 +0300 Subject: Fixed segfault with empty routes array. --- src/nxt_http_route.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/nxt_http_route.c b/src/nxt_http_route.c index 2a41d7fa..21e83ecb 100644 --- a/src/nxt_http_route.c +++ b/src/nxt_http_route.c @@ -616,14 +616,13 @@ nxt_http_route_find(nxt_http_routes_t *routes, nxt_str_t *name) route = &routes->route[0]; end = route + routes->items; - do { + while (route < end) { if (nxt_strstr_eq(&(*route)->name, name)) { return *route; } route++; - - } while (route < end); + } return NULL; } @@ -681,12 +680,11 @@ nxt_http_routes_cleanup(nxt_task_t *task, nxt_http_routes_t *routes) route = &routes->route[0]; end = route + routes->items; - do { + while (route < end) { nxt_http_route_cleanup(task, *route); route++; - - } while (route < end); + } } } @@ -699,12 +697,11 @@ nxt_http_route_cleanup(nxt_task_t *task, nxt_http_route_t *route) match = &route->match[0]; end = match + route->items; - do { + while (match < end) { nxt_http_pass_cleanup(task, &(*match)->pass); match++; - - } while (match < end); + } } -- cgit From 0ba7cfce7572070892bf54ed69b82a822e3ee0d4 Mon Sep 17 00:00:00 2001 From: Igor Sysoev Date: Thu, 30 May 2019 15:33:51 +0300 Subject: Added routing based on header fields. --- src/nxt_conf_validation.c | 68 +++++++- src/nxt_http_parse.c | 4 - src/nxt_http_parse.h | 5 + src/nxt_http_route.c | 399 +++++++++++++++++++++++++++++++++++++++------- 4 files changed, 409 insertions(+), 67 deletions(-) (limited to 'src') diff --git a/src/nxt_conf_validation.c b/src/nxt_conf_validation.c index aedcc605..bee82dd4 100644 --- a/src/nxt_conf_validation.c +++ b/src/nxt_conf_validation.c @@ -66,6 +66,12 @@ static nxt_int_t nxt_conf_vldt_match_patterns(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data); static nxt_int_t nxt_conf_vldt_match_pattern(nxt_conf_validation_t *vldt, nxt_conf_value_t *value); +static nxt_int_t nxt_conf_vldt_match_patterns_sets(nxt_conf_validation_t *vldt, + nxt_conf_value_t *value, void *data); +static nxt_int_t nxt_conf_vldt_match_patterns_set(nxt_conf_validation_t *vldt, + nxt_conf_value_t *value); +static nxt_int_t nxt_conf_vldt_match_patterns_set_member( + nxt_conf_validation_t *vldt, nxt_str_t *name, nxt_conf_value_t *value); static nxt_int_t nxt_conf_vldt_app_name(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data); static nxt_int_t nxt_conf_vldt_app(nxt_conf_validation_t *vldt, @@ -218,6 +224,21 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_match_members[] = { &nxt_conf_vldt_match_patterns, NULL }, + { nxt_string("arguments"), + NXT_CONF_VLDT_OBJECT | NXT_CONF_VLDT_ARRAY, + &nxt_conf_vldt_match_patterns_sets, + NULL }, + + { nxt_string("headers"), + NXT_CONF_VLDT_OBJECT | NXT_CONF_VLDT_ARRAY, + &nxt_conf_vldt_match_patterns_sets, + NULL }, + + { nxt_string("cookies"), + NXT_CONF_VLDT_OBJECT | NXT_CONF_VLDT_ARRAY, + &nxt_conf_vldt_match_patterns_sets, + NULL }, + NXT_CONF_VLDT_END }; @@ -748,8 +769,8 @@ nxt_conf_vldt_match_pattern(nxt_conf_validation_t *vldt, } state; if (nxt_conf_type(value) != NXT_CONF_STRING) { - return nxt_conf_vldt_error(vldt, - "The \"match\" patterns must be strings."); + return nxt_conf_vldt_error(vldt, "The \"match\" patterns for \"host\", " + "\"uri\", and \"method\" must be strings."); } nxt_conf_get_string(value, &pattern); @@ -798,6 +819,49 @@ nxt_conf_vldt_match_pattern(nxt_conf_validation_t *vldt, } +static nxt_int_t +nxt_conf_vldt_match_patterns_sets(nxt_conf_validation_t *vldt, + nxt_conf_value_t *value, void *data) +{ + if (nxt_conf_type(value) == NXT_CONF_ARRAY) { + return nxt_conf_vldt_array_iterator(vldt, value, + &nxt_conf_vldt_match_patterns_set); + } + + /* NXT_CONF_OBJECT */ + + return nxt_conf_vldt_match_patterns_set(vldt, value); +} + + +static nxt_int_t +nxt_conf_vldt_match_patterns_set(nxt_conf_validation_t *vldt, + nxt_conf_value_t *value) +{ + if (nxt_conf_type(value) != NXT_CONF_OBJECT) { + return nxt_conf_vldt_error(vldt, "The \"match\" patterns for " + "\"arguments\", \"cookies\", and " + "\"headers\" must be objects."); + } + + return nxt_conf_vldt_object_iterator(vldt, value, + &nxt_conf_vldt_match_patterns_set_member); +} + + +static nxt_int_t +nxt_conf_vldt_match_patterns_set_member(nxt_conf_validation_t *vldt, + nxt_str_t *name, nxt_conf_value_t *value) +{ + if (name->length == 0) { + return nxt_conf_vldt_error(vldt, "The \"match\" pattern objects must " + "not contain empty member names."); + } + + return nxt_conf_vldt_match_patterns(vldt, value, NULL); +} + + #if (NXT_TLS) static nxt_int_t diff --git a/src/nxt_http_parse.c b/src/nxt_http_parse.c index 64e4bf35..05df245e 100644 --- a/src/nxt_http_parse.c +++ b/src/nxt_http_parse.c @@ -34,10 +34,6 @@ static nxt_int_t nxt_http_field_hash_collision(nxt_lvlhsh_query_t *lhq, #define NXT_HTTP_FIELD_LVLHSH_SHIFT 5 -#define NXT_HTTP_FIELD_HASH_INIT 159406 -#define nxt_http_field_hash_char(h, c) (((h) << 4) + (h) + (c)) -#define nxt_http_field_hash_end(h) (((h) >> 16) ^ (h)) - typedef enum { NXT_HTTP_TARGET_SPACE = 1, /* \s */ diff --git a/src/nxt_http_parse.h b/src/nxt_http_parse.h index 0326d45c..6c629936 100644 --- a/src/nxt_http_parse.h +++ b/src/nxt_http_parse.h @@ -93,6 +93,11 @@ struct nxt_http_field_s { }; +#define NXT_HTTP_FIELD_HASH_INIT 159406U +#define nxt_http_field_hash_char(h, c) (((h) << 4) + (h) + (c)) +#define nxt_http_field_hash_end(h) (((h) >> 16) ^ (h)) + + nxt_int_t nxt_http_parse_request_init(nxt_http_request_parse_t *rp, nxt_mp_t *mp); nxt_int_t nxt_http_parse_request(nxt_http_request_parse_t *rp, diff --git a/src/nxt_http_route.c b/src/nxt_http_route.c index 21e83ecb..e3c3cd9f 100644 --- a/src/nxt_http_route.c +++ b/src/nxt_http_route.c @@ -9,9 +9,9 @@ typedef enum { - NXT_HTTP_ROUTE_STRING = 0, + NXT_HTTP_ROUTE_TABLE = 0, + NXT_HTTP_ROUTE_STRING, NXT_HTTP_ROUTE_STRING_PTR, - NXT_HTTP_ROUTE_FIELD, NXT_HTTP_ROUTE_HEADER, NXT_HTTP_ROUTE_ARGUMENT, NXT_HTTP_ROUTE_COOKIE, @@ -38,6 +38,7 @@ typedef struct { nxt_conf_value_t *host; nxt_conf_value_t *uri; nxt_conf_value_t *method; + nxt_conf_value_t *headers; } nxt_http_route_match_conf_t; @@ -56,17 +57,48 @@ typedef struct { typedef struct { - uintptr_t offset; - uint32_t items; + /* The object must be the first field. */ nxt_http_route_object_t object:8; + uint32_t items; + + union { + uintptr_t offset; + + struct { + u_char *start; + uint16_t hash; + uint16_t length; + } name; + } u; + nxt_http_route_pattern_t pattern[0]; } nxt_http_route_rule_t; typedef struct { uint32_t items; - nxt_http_pass_t pass; nxt_http_route_rule_t *rule[0]; +} nxt_http_route_ruleset_t; + + +typedef struct { + /* The object must be the first field. */ + nxt_http_route_object_t object:8; + uint32_t items; + nxt_http_route_ruleset_t *ruleset[0]; +} nxt_http_route_table_t; + + +typedef union { + nxt_http_route_rule_t *rule; + nxt_http_route_table_t *table; +} nxt_http_route_test_t; + + +typedef struct { + uint32_t items; + nxt_http_pass_t pass; + nxt_http_route_test_t test[0]; } nxt_http_route_match_t; @@ -87,9 +119,15 @@ static nxt_http_route_t *nxt_http_route_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv); static nxt_http_route_match_t *nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv); +static nxt_http_route_table_t *nxt_http_route_table_create(nxt_task_t *task, + nxt_mp_t *mp, nxt_conf_value_t *table_cv); +static nxt_http_route_ruleset_t *nxt_http_route_ruleset_create(nxt_task_t *task, + nxt_mp_t *mp, nxt_conf_value_t *ruleset_cv); +static nxt_http_route_rule_t *nxt_http_route_rule_header_create( + nxt_task_t *task, nxt_mp_t *mp, nxt_conf_value_t *rule_cv, nxt_str_t *name); static nxt_http_route_rule_t *nxt_http_route_rule_create(nxt_task_t *task, - nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv, - nxt_bool_t case_sensitive, nxt_http_route_pattern_case_t pattern_case); + nxt_mp_t *mp, nxt_conf_value_t *cv, nxt_bool_t case_sensitive, + nxt_http_route_pattern_case_t pattern_case); static int nxt_http_pattern_compare(const void *one, const void *two); static nxt_int_t nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp, nxt_conf_value_t *cv, nxt_http_route_pattern_t *pattern, @@ -109,8 +147,16 @@ static nxt_http_pass_t *nxt_http_route_pass(nxt_task_t *task, nxt_http_request_t *r, nxt_http_pass_t *start); static nxt_http_pass_t *nxt_http_route_match(nxt_http_request_t *r, nxt_http_route_match_t *match); +static nxt_bool_t nxt_http_route_table(nxt_http_request_t *r, + nxt_http_route_table_t *table); +static nxt_bool_t nxt_http_route_ruleset(nxt_http_request_t *r, + nxt_http_route_ruleset_t *ruleset); static nxt_bool_t nxt_http_route_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule); +static nxt_bool_t nxt_http_route_header(nxt_http_request_t *r, + nxt_http_route_rule_t *rule); +static nxt_bool_t nxt_http_route_test_rule(nxt_http_request_t *r, + nxt_http_route_rule_t *rule, u_char *start, size_t length); static nxt_bool_t nxt_http_route_pattern(nxt_http_request_t *r, nxt_http_route_pattern_t *pattern, u_char *start, size_t length); static nxt_bool_t nxt_http_route_memcmp(u_char *start, u_char *test, @@ -196,6 +242,12 @@ static nxt_conf_map_t nxt_http_route_match_conf[] = { NXT_CONF_MAP_PTR, offsetof(nxt_http_route_match_conf_t, method), }, + + { + nxt_string("headers"), + NXT_CONF_MAP_PTR, + offsetof(nxt_http_route_match_conf_t, headers), + }, }; @@ -241,10 +293,13 @@ nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, { size_t size; uint32_t n; + nxt_mp_t *mp; nxt_int_t ret; nxt_str_t pass, *string; nxt_conf_value_t *match_conf, *pass_conf; - nxt_http_route_rule_t *rule, **p; + nxt_http_route_test_t *test; + nxt_http_route_rule_t *rule; + nxt_http_route_table_t *table; nxt_http_route_match_t *match; nxt_http_route_match_conf_t mtcf; @@ -263,7 +318,9 @@ nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, n = (match_conf != NULL) ? nxt_conf_object_members_count(match_conf) : 0; size = sizeof(nxt_http_route_match_t) + n * sizeof(nxt_http_route_rule_t *); - match = nxt_mp_alloc(tmcf->router_conf->mem_pool, size); + mp = tmcf->router_conf->mem_pool; + + match = nxt_mp_alloc(mp, size); if (nxt_slow_path(match == NULL)) { return NULL; } @@ -272,7 +329,7 @@ nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, match->pass.handler = NULL; match->items = n; - string = nxt_str_dup(tmcf->router_conf->mem_pool, &match->pass.name, &pass); + string = nxt_str_dup(mp, &match->pass.name, &pass); if (nxt_slow_path(string == NULL)) { return NULL; } @@ -290,64 +347,204 @@ nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, return NULL; } - p = &match->rule[0]; + test = &match->test[0]; if (mtcf.host != NULL) { - rule = nxt_http_route_rule_create(task, tmcf, mtcf.host, 1, + rule = nxt_http_route_rule_create(task, mp, mtcf.host, 1, NXT_HTTP_ROUTE_PATTERN_LOWCASE); if (rule == NULL) { return NULL; } - rule->offset = offsetof(nxt_http_request_t, host); + rule->u.offset = offsetof(nxt_http_request_t, host); rule->object = NXT_HTTP_ROUTE_STRING; - *p++ = rule; + test->rule = rule; + test++; } if (mtcf.uri != NULL) { - rule = nxt_http_route_rule_create(task, tmcf, mtcf.uri, 1, + rule = nxt_http_route_rule_create(task, mp, mtcf.uri, 1, NXT_HTTP_ROUTE_PATTERN_NOCASE); if (rule == NULL) { return NULL; } - rule->offset = offsetof(nxt_http_request_t, path); + rule->u.offset = offsetof(nxt_http_request_t, path); rule->object = NXT_HTTP_ROUTE_STRING_PTR; - *p++ = rule; + test->rule = rule; + test++; } if (mtcf.method != NULL) { - rule = nxt_http_route_rule_create(task, tmcf, mtcf.method, 1, + rule = nxt_http_route_rule_create(task, mp, mtcf.method, 1, NXT_HTTP_ROUTE_PATTERN_UPCASE); if (rule == NULL) { return NULL; } - rule->offset = offsetof(nxt_http_request_t, method); + rule->u.offset = offsetof(nxt_http_request_t, method); rule->object = NXT_HTTP_ROUTE_STRING_PTR; - *p++ = rule; + test->rule = rule; + test++; + } + + if (mtcf.headers != NULL) { + table = nxt_http_route_table_create(task, mp, mtcf.headers); + if (table == NULL) { + return NULL; + } + + test->table = table; + test++; } return match; } +static nxt_http_route_table_t * +nxt_http_route_table_create(nxt_task_t *task, nxt_mp_t *mp, + nxt_conf_value_t *table_cv) +{ + size_t size; + uint32_t i, n; + nxt_bool_t array; + nxt_conf_value_t *ruleset_cv; + nxt_http_route_table_t *table; + nxt_http_route_ruleset_t *ruleset; + + array = (nxt_conf_type(table_cv) == NXT_CONF_ARRAY); + n = array ? nxt_conf_array_elements_count(table_cv) : 1; + size = sizeof(nxt_http_route_table_t) + + n * sizeof(nxt_http_route_ruleset_t *); + + table = nxt_mp_alloc(mp, size); + if (nxt_slow_path(table == NULL)) { + return NULL; + } + + table->items = n; + table->object = NXT_HTTP_ROUTE_TABLE; + + if (!array) { + ruleset = nxt_http_route_ruleset_create(task, mp, table_cv); + if (nxt_slow_path(ruleset == NULL)) { + return NULL; + } + + table->ruleset[0] = ruleset; + + return table; + } + + for (i = 0; i < n; i++) { + ruleset_cv = nxt_conf_get_array_element(table_cv, i); + + ruleset = nxt_http_route_ruleset_create(task, mp, ruleset_cv); + if (nxt_slow_path(ruleset == NULL)) { + return NULL; + } + + table->ruleset[i] = ruleset; + } + + return table; +} + + +static nxt_http_route_ruleset_t * +nxt_http_route_ruleset_create(nxt_task_t *task, nxt_mp_t *mp, + nxt_conf_value_t *ruleset_cv) +{ + size_t size; + uint32_t i, n, next; + nxt_str_t name; + nxt_conf_value_t *rule_cv; + nxt_http_route_rule_t *rule; + nxt_http_route_ruleset_t *ruleset; + + n = nxt_conf_object_members_count(ruleset_cv); + size = sizeof(nxt_http_route_ruleset_t) + + n * sizeof(nxt_http_route_rule_t *); + + ruleset = nxt_mp_alloc(mp, size); + if (nxt_slow_path(ruleset == NULL)) { + return NULL; + } + + ruleset->items = n; + + next = 0; + + for (i = 0; i < n; i++) { + rule_cv = nxt_conf_next_object_member(ruleset_cv, &name, &next); + + rule = nxt_http_route_rule_header_create(task, mp, rule_cv, &name); + if (nxt_slow_path(rule == NULL)) { + return NULL; + } + + ruleset->rule[i] = rule; + } + + return ruleset; +} + + static nxt_http_route_rule_t * -nxt_http_route_rule_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, +nxt_http_route_rule_header_create(nxt_task_t *task, nxt_mp_t *mp, + nxt_conf_value_t *rule_cv, nxt_str_t *name) +{ + u_char c, *p; + uint32_t hash; + nxt_uint_t i; + nxt_http_route_rule_t *rule; + + rule = nxt_http_route_rule_create(task, mp, rule_cv, 0, + NXT_HTTP_ROUTE_PATTERN_NOCASE); + if (nxt_slow_path(rule == NULL)) { + return NULL; + } + + rule->u.name.length = name->length; + + p = nxt_mp_nget(mp, name->length); + if (nxt_slow_path(p == NULL)) { + return NULL; + } + + rule->u.name.start = p; + rule->object = NXT_HTTP_ROUTE_HEADER; + + hash = NXT_HTTP_FIELD_HASH_INIT; + + for (i = 0; i < name->length; i++) { + c = name->start[i]; + *p++ = c; + + c = nxt_lowcase(c); + hash = nxt_http_field_hash_char(hash, c); + } + + rule->u.name.hash = nxt_http_field_hash_end(hash) & 0xFFFF; + + return rule; +} + + +static nxt_http_route_rule_t * +nxt_http_route_rule_create(nxt_task_t *task, nxt_mp_t *mp, nxt_conf_value_t *cv, nxt_bool_t case_sensitive, nxt_http_route_pattern_case_t pattern_case) { size_t size; uint32_t i, n; - nxt_mp_t *mp; nxt_int_t ret; nxt_bool_t string; nxt_conf_value_t *value; nxt_http_route_rule_t *rule; nxt_http_route_pattern_t *pattern; - mp = tmcf->router_conf->mem_pool; - string = (nxt_conf_type(cv) != NXT_CONF_ARRAY); n = string ? 1 : nxt_conf_array_elements_count(cv); size = sizeof(nxt_http_route_rule_t) + n * sizeof(nxt_http_route_pattern_t); @@ -543,6 +740,7 @@ nxt_http_routes_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) nxt_http_routes_t *routes; routes = tmcf->router_conf->routes; + if (routes != NULL) { route = &routes->route[0]; end = route + routes->items; @@ -743,78 +941,157 @@ nxt_http_route_pass(nxt_task_t *task, nxt_http_request_t *r, static nxt_http_pass_t * nxt_http_route_match(nxt_http_request_t *r, nxt_http_route_match_t *match) +{ + nxt_bool_t ret; + nxt_http_route_test_t *test, *end; + + test = &match->test[0]; + end = test + match->items; + + while (test < end) { + if (test->rule->object != NXT_HTTP_ROUTE_TABLE) { + ret = nxt_http_route_rule(r, test->rule); + + } else { + ret = nxt_http_route_table(r, test->table); + } + + if (!ret) { + return NULL; + } + + test++; + } + + return &match->pass; +} + + +static nxt_bool_t +nxt_http_route_table(nxt_http_request_t *r, nxt_http_route_table_t *table) +{ + nxt_bool_t ret; + nxt_http_route_ruleset_t **ruleset, **end; + + ret = 1; + ruleset = &table->ruleset[0]; + end = ruleset + table->items; + + while (ruleset < end) { + ret = nxt_http_route_ruleset(r, *ruleset); + + if (ret) { + return ret; + } + + ruleset++; + } + + return ret; +} + + +static nxt_bool_t +nxt_http_route_ruleset(nxt_http_request_t *r, nxt_http_route_ruleset_t *ruleset) { nxt_http_route_rule_t **rule, **end; - rule = &match->rule[0]; - end = rule + match->items; + rule = &ruleset->rule[0]; + end = rule + ruleset->items; while (rule < end) { if (!nxt_http_route_rule(r, *rule)) { - return NULL; + return 0; } rule++; } - return &match->pass; + return 1; } static nxt_bool_t nxt_http_route_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule) { - void *p, **pp; - u_char *start; - size_t length; - nxt_str_t *s; - nxt_bool_t ret; - nxt_http_field_t *f; - nxt_http_route_pattern_t *pattern, *end; + void *p, **pp; + u_char *start; + size_t length; + nxt_str_t *s; + + switch (rule->object) { - p = nxt_pointer_to(r, rule->offset); + case NXT_HTTP_ROUTE_HEADER: + return nxt_http_route_header(r, rule); + + case NXT_HTTP_ROUTE_ARGUMENT: + return 0; + + case NXT_HTTP_ROUTE_COOKIE: + return 0; + + default: + break; + } + + p = nxt_pointer_to(r, rule->u.offset); if (rule->object == NXT_HTTP_ROUTE_STRING) { s = p; - length = s->length; - start = s->start; } else { + /* NXT_HTTP_ROUTE_STRING_PTR */ pp = p; - p = *pp; + s = *pp; - if (p == NULL) { + if (s == NULL) { return 0; } + } - switch (rule->object) { + length = s->length; + start = s->start; - case NXT_HTTP_ROUTE_STRING_PTR: - s = p; - length = s->length; - start = s->start; - break; + return nxt_http_route_test_rule(r, rule, start, length); +} - case NXT_HTTP_ROUTE_FIELD: - f = p; - length = f->value_length; - start = f->value; - break; - case NXT_HTTP_ROUTE_HEADER: - return 0; +static nxt_bool_t +nxt_http_route_header(nxt_http_request_t *r, nxt_http_route_rule_t *rule) +{ + nxt_bool_t ret; + nxt_http_field_t *f; - case NXT_HTTP_ROUTE_ARGUMENT: - return 0; + ret = 0; - case NXT_HTTP_ROUTE_COOKIE: - return 0; + nxt_list_each(f, r->fields) { - default: - nxt_unreachable(); - return 0; + if (rule->u.name.hash != f->hash + || rule->u.name.length != f->name_length + || nxt_strncasecmp(rule->u.name.start, f->name, f->name_length) + != 0) + { + continue; } - } + + ret = nxt_http_route_test_rule(r, rule, f->value, f->value_length); + + if (!ret) { + return ret; + } + + } nxt_list_loop; + + return ret; +} + + +static nxt_bool_t +nxt_http_route_test_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule, + u_char *start, size_t length) +{ + nxt_bool_t ret; + nxt_http_route_pattern_t *pattern, *end; ret = 1; pattern = &rule->pattern[0]; -- cgit From 16273cf1c606a8dfc9934720b691f90312f9e2ab Mon Sep 17 00:00:00 2001 From: Igor Sysoev Date: Thu, 30 May 2019 15:33:51 +0300 Subject: Handling routing errors. --- src/nxt_http_request.c | 27 ++++++++++------------- src/nxt_http_route.c | 59 +++++++++++++++++++++++++++----------------------- src/nxt_router.h | 3 +++ 3 files changed, 47 insertions(+), 42 deletions(-) (limited to 'src') diff --git a/src/nxt_http_request.c b/src/nxt_http_request.c index 3ba7ffe7..1265c186 100644 --- a/src/nxt_http_request.c +++ b/src/nxt_http_request.c @@ -295,26 +295,23 @@ nxt_http_request_pass(nxt_task_t *task, void *obj, void *data) pass = r->conf->socket_conf->pass; - if (nxt_slow_path(pass == NULL)) { - goto fail; - } + if (nxt_fast_path(pass != NULL)) { - for ( ;; ) { - nxt_debug(task, "http request route: %V", &pass->name); + do { + nxt_debug(task, "http request route: %V", &pass->name); - pass = pass->handler(task, r, pass); - if (pass == NULL) { - break; - } + pass = pass->handler(task, r, pass); - if (nxt_slow_path(r->pass_count++ == 255)) { - goto fail; - } - } + if (pass == NULL) { + return; + } - return; + if (pass == NXT_HTTP_PASS_ERROR) { + break; + } -fail: + } while (r->pass_count++ < 255); + } nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); } diff --git a/src/nxt_http_route.c b/src/nxt_http_route.c index e3c3cd9f..512cc239 100644 --- a/src/nxt_http_route.c +++ b/src/nxt_http_route.c @@ -147,19 +147,19 @@ static nxt_http_pass_t *nxt_http_route_pass(nxt_task_t *task, nxt_http_request_t *r, nxt_http_pass_t *start); static nxt_http_pass_t *nxt_http_route_match(nxt_http_request_t *r, nxt_http_route_match_t *match); -static nxt_bool_t nxt_http_route_table(nxt_http_request_t *r, +static nxt_int_t nxt_http_route_table(nxt_http_request_t *r, nxt_http_route_table_t *table); -static nxt_bool_t nxt_http_route_ruleset(nxt_http_request_t *r, +static nxt_int_t nxt_http_route_ruleset(nxt_http_request_t *r, nxt_http_route_ruleset_t *ruleset); -static nxt_bool_t nxt_http_route_rule(nxt_http_request_t *r, +static nxt_int_t nxt_http_route_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule); -static nxt_bool_t nxt_http_route_header(nxt_http_request_t *r, +static nxt_int_t nxt_http_route_header(nxt_http_request_t *r, nxt_http_route_rule_t *rule); -static nxt_bool_t nxt_http_route_test_rule(nxt_http_request_t *r, +static nxt_int_t nxt_http_route_test_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule, u_char *start, size_t length); -static nxt_bool_t nxt_http_route_pattern(nxt_http_request_t *r, +static nxt_int_t nxt_http_route_pattern(nxt_http_request_t *r, nxt_http_route_pattern_t *pattern, u_char *start, size_t length); -static nxt_bool_t nxt_http_route_memcmp(u_char *start, u_char *test, +static nxt_int_t nxt_http_route_memcmp(u_char *start, u_char *test, size_t length, nxt_bool_t case_sensitive); @@ -942,7 +942,7 @@ nxt_http_route_pass(nxt_task_t *task, nxt_http_request_t *r, static nxt_http_pass_t * nxt_http_route_match(nxt_http_request_t *r, nxt_http_route_match_t *match) { - nxt_bool_t ret; + nxt_int_t ret; nxt_http_route_test_t *test, *end; test = &match->test[0]; @@ -956,8 +956,9 @@ nxt_http_route_match(nxt_http_request_t *r, nxt_http_route_match_t *match) ret = nxt_http_route_table(r, test->table); } - if (!ret) { - return NULL; + if (ret <= 0) { + /* 0 => NULL, -1 => NXT_HTTP_PASS_ERROR. */ + return (nxt_http_pass_t *) (intptr_t) ret; } test++; @@ -967,10 +968,10 @@ nxt_http_route_match(nxt_http_request_t *r, nxt_http_route_match_t *match) } -static nxt_bool_t +static nxt_int_t nxt_http_route_table(nxt_http_request_t *r, nxt_http_route_table_t *table) { - nxt_bool_t ret; + nxt_int_t ret; nxt_http_route_ruleset_t **ruleset, **end; ret = 1; @@ -980,7 +981,7 @@ nxt_http_route_table(nxt_http_request_t *r, nxt_http_route_table_t *table) while (ruleset < end) { ret = nxt_http_route_ruleset(r, *ruleset); - if (ret) { + if (ret != 0) { return ret; } @@ -991,17 +992,20 @@ nxt_http_route_table(nxt_http_request_t *r, nxt_http_route_table_t *table) } -static nxt_bool_t +static nxt_int_t nxt_http_route_ruleset(nxt_http_request_t *r, nxt_http_route_ruleset_t *ruleset) { + nxt_int_t ret; nxt_http_route_rule_t **rule, **end; rule = &ruleset->rule[0]; end = rule + ruleset->items; while (rule < end) { - if (!nxt_http_route_rule(r, *rule)) { - return 0; + ret = nxt_http_route_rule(r, *rule); + + if (ret <= 0) { + return ret; } rule++; @@ -1011,7 +1015,7 @@ nxt_http_route_ruleset(nxt_http_request_t *r, nxt_http_route_ruleset_t *ruleset) } -static nxt_bool_t +static nxt_int_t nxt_http_route_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule) { void *p, **pp; @@ -1056,10 +1060,10 @@ nxt_http_route_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule) } -static nxt_bool_t +static nxt_int_t nxt_http_route_header(nxt_http_request_t *r, nxt_http_route_rule_t *rule) { - nxt_bool_t ret; + nxt_int_t ret; nxt_http_field_t *f; ret = 0; @@ -1076,7 +1080,7 @@ nxt_http_route_header(nxt_http_request_t *r, nxt_http_route_rule_t *rule) ret = nxt_http_route_test_rule(r, rule, f->value, f->value_length); - if (!ret) { + if (ret == 0) { return ret; } @@ -1086,11 +1090,11 @@ nxt_http_route_header(nxt_http_request_t *r, nxt_http_route_rule_t *rule) } -static nxt_bool_t +static nxt_int_t nxt_http_route_test_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule, u_char *start, size_t length) { - nxt_bool_t ret; + nxt_int_t ret; nxt_http_route_pattern_t *pattern, *end; ret = 1; @@ -1100,6 +1104,7 @@ nxt_http_route_test_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule, while (pattern < end) { ret = nxt_http_route_pattern(r, pattern, start, length); + /* nxt_http_route_pattern() returns either 1 or 0. */ ret ^= pattern->negative; if (pattern->any == ret) { @@ -1113,13 +1118,13 @@ nxt_http_route_test_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule, } -static nxt_bool_t +static nxt_int_t nxt_http_route_pattern(nxt_http_request_t *r, nxt_http_route_pattern_t *pattern, u_char *start, size_t length) { - u_char *p, *end, *test; - size_t test_length; - nxt_bool_t ret; + u_char *p, *end, *test; + size_t test_length; + nxt_int_t ret; if (length < pattern->min_length) { return 0; @@ -1174,7 +1179,7 @@ nxt_http_route_pattern(nxt_http_request_t *r, nxt_http_route_pattern_t *pattern, } -static nxt_bool_t +static nxt_int_t nxt_http_route_memcmp(u_char *start, u_char *test, size_t test_length, nxt_bool_t case_sensitive) { diff --git a/src/nxt_router.h b/src/nxt_router.h index a876b9a4..d9fbfe05 100644 --- a/src/nxt_router.h +++ b/src/nxt_router.h @@ -21,6 +21,9 @@ typedef struct nxt_http_routes_s nxt_http_routes_t; typedef struct nxt_router_access_log_s nxt_router_access_log_t; +#define NXT_HTTP_PASS_ERROR ((nxt_http_pass_t *) -1) + + typedef struct { nxt_thread_spinlock_t lock; nxt_queue_t engines; -- cgit From 5fb3daa5af30bd6e57d5ca82df269a226f1e5813 Mon Sep 17 00:00:00 2001 From: Igor Sysoev Date: Thu, 30 May 2019 15:33:51 +0300 Subject: Added routing based on arguments. --- src/nxt_http.h | 1 + src/nxt_http_route.c | 223 +++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 209 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/nxt_http.h b/src/nxt_http.h index 00c13599..e788399f 100644 --- a/src/nxt_http.h +++ b/src/nxt_http.h @@ -121,6 +121,7 @@ struct nxt_http_request_s { nxt_str_t *path; nxt_str_t *args; + nxt_array_t *arguments; /* of nxt_http_name_value_t */ nxt_list_t *fields; nxt_http_field_t *content_type; nxt_http_field_t *content_length; diff --git a/src/nxt_http_route.c b/src/nxt_http_route.c index 512cc239..a2e1096d 100644 --- a/src/nxt_http_route.c +++ b/src/nxt_http_route.c @@ -39,6 +39,7 @@ typedef struct { nxt_conf_value_t *uri; nxt_conf_value_t *method; nxt_conf_value_t *headers; + nxt_conf_value_t *arguments; } nxt_http_route_match_conf_t; @@ -56,6 +57,15 @@ typedef struct { } nxt_http_route_pattern_t; +typedef struct { + uint16_t hash; + uint16_t name_length; + uint32_t value_length; + u_char *name; + u_char *value; +} nxt_http_name_value_t; + + typedef struct { /* The object must be the first field. */ nxt_http_route_object_t object:8; @@ -120,11 +130,14 @@ static nxt_http_route_t *nxt_http_route_create(nxt_task_t *task, static nxt_http_route_match_t *nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv); static nxt_http_route_table_t *nxt_http_route_table_create(nxt_task_t *task, - nxt_mp_t *mp, nxt_conf_value_t *table_cv); + nxt_mp_t *mp, nxt_conf_value_t *table_cv, nxt_http_route_object_t object, + nxt_bool_t case_sensitive); static nxt_http_route_ruleset_t *nxt_http_route_ruleset_create(nxt_task_t *task, - nxt_mp_t *mp, nxt_conf_value_t *ruleset_cv); -static nxt_http_route_rule_t *nxt_http_route_rule_header_create( - nxt_task_t *task, nxt_mp_t *mp, nxt_conf_value_t *rule_cv, nxt_str_t *name); + nxt_mp_t *mp, nxt_conf_value_t *ruleset_cv, nxt_http_route_object_t object, + nxt_bool_t case_sensitive); +static nxt_http_route_rule_t *nxt_http_route_rule_name_create(nxt_task_t *task, + nxt_mp_t *mp, nxt_conf_value_t *rule_cv, nxt_str_t *name, + nxt_bool_t case_sensitive); static nxt_http_route_rule_t *nxt_http_route_rule_create(nxt_task_t *task, nxt_mp_t *mp, nxt_conf_value_t *cv, nxt_bool_t case_sensitive, nxt_http_route_pattern_case_t pattern_case); @@ -155,6 +168,14 @@ static nxt_int_t nxt_http_route_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule); static nxt_int_t nxt_http_route_header(nxt_http_request_t *r, nxt_http_route_rule_t *rule); +static nxt_int_t nxt_http_route_arguments(nxt_http_request_t *r, + nxt_http_route_rule_t *rule); +static nxt_array_t *nxt_http_route_arguments_parse(nxt_http_request_t *r); +static nxt_http_name_value_t *nxt_http_route_argument(nxt_array_t *array, + u_char *name, size_t name_length, uint32_t hash, u_char *start, + u_char *end); +static nxt_int_t nxt_http_route_test_argument(nxt_http_request_t *r, + nxt_http_route_rule_t *rule, nxt_array_t *array); static nxt_int_t nxt_http_route_test_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule, u_char *start, size_t length); static nxt_int_t nxt_http_route_pattern(nxt_http_request_t *r, @@ -248,6 +269,12 @@ static nxt_conf_map_t nxt_http_route_match_conf[] = { NXT_CONF_MAP_PTR, offsetof(nxt_http_route_match_conf_t, headers), }, + + { + nxt_string("arguments"), + NXT_CONF_MAP_PTR, + offsetof(nxt_http_route_match_conf_t, arguments), + }, }; @@ -389,7 +416,19 @@ nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, } if (mtcf.headers != NULL) { - table = nxt_http_route_table_create(task, mp, mtcf.headers); + table = nxt_http_route_table_create(task, mp, mtcf.headers, + NXT_HTTP_ROUTE_HEADER, 0); + if (table == NULL) { + return NULL; + } + + test->table = table; + test++; + } + + if (mtcf.arguments != NULL) { + table = nxt_http_route_table_create(task, mp, mtcf.arguments, + NXT_HTTP_ROUTE_ARGUMENT, 1); if (table == NULL) { return NULL; } @@ -404,7 +443,8 @@ nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, static nxt_http_route_table_t * nxt_http_route_table_create(nxt_task_t *task, nxt_mp_t *mp, - nxt_conf_value_t *table_cv) + nxt_conf_value_t *table_cv, nxt_http_route_object_t object, + nxt_bool_t case_sensitive) { size_t size; uint32_t i, n; @@ -427,7 +467,8 @@ nxt_http_route_table_create(nxt_task_t *task, nxt_mp_t *mp, table->object = NXT_HTTP_ROUTE_TABLE; if (!array) { - ruleset = nxt_http_route_ruleset_create(task, mp, table_cv); + ruleset = nxt_http_route_ruleset_create(task, mp, table_cv, + object, case_sensitive); if (nxt_slow_path(ruleset == NULL)) { return NULL; } @@ -440,7 +481,8 @@ nxt_http_route_table_create(nxt_task_t *task, nxt_mp_t *mp, for (i = 0; i < n; i++) { ruleset_cv = nxt_conf_get_array_element(table_cv, i); - ruleset = nxt_http_route_ruleset_create(task, mp, ruleset_cv); + ruleset = nxt_http_route_ruleset_create(task, mp, ruleset_cv, + object, case_sensitive); if (nxt_slow_path(ruleset == NULL)) { return NULL; } @@ -454,7 +496,8 @@ nxt_http_route_table_create(nxt_task_t *task, nxt_mp_t *mp, static nxt_http_route_ruleset_t * nxt_http_route_ruleset_create(nxt_task_t *task, nxt_mp_t *mp, - nxt_conf_value_t *ruleset_cv) + nxt_conf_value_t *ruleset_cv, nxt_http_route_object_t object, + nxt_bool_t case_sensitive) { size_t size; uint32_t i, n, next; @@ -479,11 +522,13 @@ nxt_http_route_ruleset_create(nxt_task_t *task, nxt_mp_t *mp, for (i = 0; i < n; i++) { rule_cv = nxt_conf_next_object_member(ruleset_cv, &name, &next); - rule = nxt_http_route_rule_header_create(task, mp, rule_cv, &name); + rule = nxt_http_route_rule_name_create(task, mp, rule_cv, &name, + case_sensitive); if (nxt_slow_path(rule == NULL)) { return NULL; } + rule->object = object; ruleset->rule[i] = rule; } @@ -492,15 +537,15 @@ nxt_http_route_ruleset_create(nxt_task_t *task, nxt_mp_t *mp, static nxt_http_route_rule_t * -nxt_http_route_rule_header_create(nxt_task_t *task, nxt_mp_t *mp, - nxt_conf_value_t *rule_cv, nxt_str_t *name) +nxt_http_route_rule_name_create(nxt_task_t *task, nxt_mp_t *mp, + nxt_conf_value_t *rule_cv, nxt_str_t *name, nxt_bool_t case_sensitive) { u_char c, *p; uint32_t hash; nxt_uint_t i; nxt_http_route_rule_t *rule; - rule = nxt_http_route_rule_create(task, mp, rule_cv, 0, + rule = nxt_http_route_rule_create(task, mp, rule_cv, case_sensitive, NXT_HTTP_ROUTE_PATTERN_NOCASE); if (nxt_slow_path(rule == NULL)) { return NULL; @@ -514,7 +559,6 @@ nxt_http_route_rule_header_create(nxt_task_t *task, nxt_mp_t *mp, } rule->u.name.start = p; - rule->object = NXT_HTTP_ROUTE_HEADER; hash = NXT_HTTP_FIELD_HASH_INIT; @@ -1029,7 +1073,7 @@ nxt_http_route_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule) return nxt_http_route_header(r, rule); case NXT_HTTP_ROUTE_ARGUMENT: - return 0; + return nxt_http_route_arguments(r, rule); case NXT_HTTP_ROUTE_COOKIE: return 0; @@ -1090,6 +1134,155 @@ nxt_http_route_header(nxt_http_request_t *r, nxt_http_route_rule_t *rule) } +static nxt_int_t +nxt_http_route_arguments(nxt_http_request_t *r, nxt_http_route_rule_t *rule) +{ + nxt_array_t *arguments; + + if (r->args == NULL) { + return 0; + } + + arguments = nxt_http_route_arguments_parse(r); + if (nxt_slow_path(arguments == NULL)) { + return -1; + } + + return nxt_http_route_test_argument(r, rule, arguments); +} + + +static nxt_array_t * +nxt_http_route_arguments_parse(nxt_http_request_t *r) +{ + size_t name_length; + u_char c, *p, *start, *end, *name; + uint32_t hash; + nxt_bool_t valid; + nxt_array_t *args; + nxt_http_name_value_t *nv; + + if (r->arguments != NULL) { + return r->arguments; + } + + args = nxt_array_create(r->mem_pool, 2, sizeof(nxt_http_name_value_t)); + if (nxt_slow_path(args == NULL)) { + return NULL; + } + + hash = NXT_HTTP_FIELD_HASH_INIT; + valid = 1; + name = NULL; + name_length = 0; + + start = r->args->start; + end = start + r->args->length; + + for (p = start; p < end; p++) { + c = *p; + + if (c == '=') { + name_length = p - start; + name = start; + start = p + 1; + valid = (name_length != 0); + + } else if (c == '&') { + if (valid) { + nv = nxt_http_route_argument(args, name, name_length, hash, + start, p); + if (nxt_slow_path(nv == NULL)) { + return NULL; + } + } + + hash = NXT_HTTP_FIELD_HASH_INIT; + valid = 1; + name = NULL; + start = p + 1; + + } else if (name == NULL) { + hash = nxt_http_field_hash_char(hash, c); + } + } + + if (valid) { + nv = nxt_http_route_argument(args, name, name_length, hash, start, p); + if (nxt_slow_path(nv == NULL)) { + return NULL; + } + } + + r->arguments = args; + + return args; +} + + +static nxt_http_name_value_t * +nxt_http_route_argument(nxt_array_t *array, u_char *name, size_t name_length, + uint32_t hash, u_char *start, u_char *end) +{ + size_t length; + nxt_http_name_value_t *nv; + + nv = nxt_array_add(array); + if (nxt_slow_path(nv == NULL)) { + return NULL; + } + + nv->hash = nxt_http_field_hash_end(hash) & 0xFFFF; + + length = end - start; + + if (name == NULL) { + name_length = length; + name = start; + length = 0; + } + + nv->name_length = name_length; + nv->value_length = length; + nv->name = name; + nv->value = start; + + return nv; +} + + +static nxt_int_t +nxt_http_route_test_argument(nxt_http_request_t *r, + nxt_http_route_rule_t *rule, nxt_array_t *array) +{ + nxt_bool_t ret; + nxt_http_name_value_t *nv, *end; + + ret = 0; + + nv = array->elts; + end = nv + array->nelts; + + while (nv < end) { + + if (rule->u.name.hash == nv->hash + && rule->u.name.length == nv->name_length + && nxt_memcmp(rule->u.name.start, nv->name, nv->name_length) == 0) + { + ret = nxt_http_route_test_rule(r, rule, nv->value, + nv->value_length); + if (ret == 0) { + break; + } + } + + nv++; + } + + return ret; +} + + static nxt_int_t nxt_http_route_test_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule, u_char *start, size_t length) -- cgit From 6a775f58af430bd2e1f41556e9bb28b089a5e068 Mon Sep 17 00:00:00 2001 From: Igor Sysoev Date: Thu, 30 May 2019 15:33:51 +0300 Subject: Added routing based on cookies. --- src/nxt_http.h | 1 + src/nxt_http_route.c | 219 ++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 219 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nxt_http.h b/src/nxt_http.h index e788399f..835cf66d 100644 --- a/src/nxt_http.h +++ b/src/nxt_http.h @@ -122,6 +122,7 @@ struct nxt_http_request_s { nxt_str_t *args; nxt_array_t *arguments; /* of nxt_http_name_value_t */ + nxt_array_t *cookies; /* of nxt_http_name_value_t */ nxt_list_t *fields; nxt_http_field_t *content_type; nxt_http_field_t *content_length; diff --git a/src/nxt_http_route.c b/src/nxt_http_route.c index a2e1096d..d6749acb 100644 --- a/src/nxt_http_route.c +++ b/src/nxt_http_route.c @@ -40,6 +40,7 @@ typedef struct { nxt_conf_value_t *method; nxt_conf_value_t *headers; nxt_conf_value_t *arguments; + nxt_conf_value_t *cookies; } nxt_http_route_match_conf_t; @@ -66,6 +67,15 @@ typedef struct { } nxt_http_name_value_t; +typedef struct { + uint16_t hash; + uint16_t name_length; + uint32_t value_length; + u_char *name; + u_char *value; +} nxt_http_cookie_t; + + typedef struct { /* The object must be the first field. */ nxt_http_route_object_t object:8; @@ -125,6 +135,17 @@ struct nxt_http_routes_s { }; +#define NJS_COOKIE_HASH \ + (nxt_http_field_hash_end( \ + nxt_http_field_hash_char( \ + nxt_http_field_hash_char( \ + nxt_http_field_hash_char( \ + nxt_http_field_hash_char( \ + nxt_http_field_hash_char( \ + nxt_http_field_hash_char(NXT_HTTP_FIELD_HASH_INIT, \ + 'c'), 'o'), 'o'), 'k'), 'i'), 'e')) & 0xFFFF) + + static nxt_http_route_t *nxt_http_route_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv); static nxt_http_route_match_t *nxt_http_route_match_create(nxt_task_t *task, @@ -176,6 +197,15 @@ static nxt_http_name_value_t *nxt_http_route_argument(nxt_array_t *array, u_char *end); static nxt_int_t nxt_http_route_test_argument(nxt_http_request_t *r, nxt_http_route_rule_t *rule, nxt_array_t *array); +static nxt_int_t nxt_http_route_cookies(nxt_http_request_t *r, + nxt_http_route_rule_t *rule); +static nxt_array_t *nxt_http_route_cookies_parse(nxt_http_request_t *r); +static nxt_int_t nxt_http_route_cookie_parse(nxt_array_t *cookies, + u_char *start, u_char *end); +static nxt_http_name_value_t *nxt_http_route_cookie(nxt_array_t *array, + u_char *name, size_t name_length, u_char *start, u_char *end); +static nxt_int_t nxt_http_route_test_cookie(nxt_http_request_t *r, + nxt_http_route_rule_t *rule, nxt_array_t *array); static nxt_int_t nxt_http_route_test_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule, u_char *start, size_t length); static nxt_int_t nxt_http_route_pattern(nxt_http_request_t *r, @@ -275,6 +305,12 @@ static nxt_conf_map_t nxt_http_route_match_conf[] = { NXT_CONF_MAP_PTR, offsetof(nxt_http_route_match_conf_t, arguments), }, + + { + nxt_string("cookies"), + NXT_CONF_MAP_PTR, + offsetof(nxt_http_route_match_conf_t, cookies), + }, }; @@ -437,6 +473,17 @@ nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, test++; } + if (mtcf.cookies != NULL) { + table = nxt_http_route_table_create(task, mp, mtcf.cookies, + NXT_HTTP_ROUTE_COOKIE, 0); + if (table == NULL) { + return NULL; + } + + test->table = table; + test++; + } + return match; } @@ -1076,7 +1123,7 @@ nxt_http_route_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule) return nxt_http_route_arguments(r, rule); case NXT_HTTP_ROUTE_COOKIE: - return 0; + return nxt_http_route_cookies(r, rule); default: break; @@ -1283,6 +1330,176 @@ nxt_http_route_test_argument(nxt_http_request_t *r, } +static nxt_int_t +nxt_http_route_cookies(nxt_http_request_t *r, nxt_http_route_rule_t *rule) +{ + nxt_array_t *cookies; + + cookies = nxt_http_route_cookies_parse(r); + if (nxt_slow_path(cookies == NULL)) { + return -1; + } + + return nxt_http_route_test_cookie(r, rule, cookies); +} + + +static nxt_array_t * +nxt_http_route_cookies_parse(nxt_http_request_t *r) +{ + nxt_int_t ret; + nxt_array_t *cookies; + nxt_http_field_t *f; + + if (r->cookies != NULL) { + return r->cookies; + } + + cookies = nxt_array_create(r->mem_pool, 2, sizeof(nxt_http_name_value_t)); + if (nxt_slow_path(cookies == NULL)) { + return NULL; + } + + nxt_list_each(f, r->fields) { + + if (f->hash != NJS_COOKIE_HASH + || f->name_length != 6 + || nxt_strncasecmp(f->name, (u_char *) "Cookie", 6) != 0) + { + continue; + } + + ret = nxt_http_route_cookie_parse(cookies, f->value, + f->value + f->value_length); + if (ret != NXT_OK) { + return NULL; + } + + } nxt_list_loop; + + r->cookies = cookies; + + return cookies; +} + + +static nxt_int_t +nxt_http_route_cookie_parse(nxt_array_t *cookies, u_char *start, u_char *end) +{ + size_t name_length; + u_char c, *p, *name; + nxt_http_name_value_t *nv; + + name = NULL; + name_length = 0; + + for (p = start; p < end; p++) { + c = *p; + + if (c == '=') { + while (start[0] == ' ') { start++; } + + name_length = p - start; + + if (name_length != 0) { + name = start; + } + + start = p + 1; + + } else if (c == ';') { + if (name != NULL) { + nv = nxt_http_route_cookie(cookies, name, name_length, + start, p); + if (nxt_slow_path(nv == NULL)) { + return NXT_ERROR; + } + } + + name = NULL; + start = p + 1; + } + } + + if (name != NULL) { + nv = nxt_http_route_cookie(cookies, name, name_length, start, p); + if (nxt_slow_path(nv == NULL)) { + return NXT_ERROR; + } + } + + return NXT_OK; +} + + +static nxt_http_name_value_t * +nxt_http_route_cookie(nxt_array_t *array, u_char *name, size_t name_length, + u_char *start, u_char *end) +{ + u_char c, *p; + uint32_t hash; + nxt_http_name_value_t *nv; + + nv = nxt_array_add(array); + if (nxt_slow_path(nv == NULL)) { + return NULL; + } + + nv->name_length = name_length; + nv->name = name; + + hash = NXT_HTTP_FIELD_HASH_INIT; + + for (p = name; p < name + name_length; p++) { + c = *p; + c = nxt_lowcase(c); + hash = nxt_http_field_hash_char(hash, c); + } + + nv->hash = nxt_http_field_hash_end(hash) & 0xFFFF; + + while (start < end && end[-1] == ' ') { end--; } + + nv->value_length = end - start; + nv->value = start; + + return nv; +} + + +static nxt_int_t +nxt_http_route_test_cookie(nxt_http_request_t *r, + nxt_http_route_rule_t *rule, nxt_array_t *array) +{ + nxt_bool_t ret; + nxt_http_name_value_t *nv, *end; + + ret = 0; + + nv = array->elts; + end = nv + array->nelts; + + while (nv < end) { + + if (rule->u.name.hash == nv->hash + && rule->u.name.length == nv->name_length + && nxt_strncasecmp(rule->u.name.start, nv->name, nv->name_length) + == 0) + { + ret = nxt_http_route_test_rule(r, rule, nv->value, + nv->value_length); + if (ret == 0) { + break; + } + } + + nv++; + } + + return ret; +} + + static nxt_int_t nxt_http_route_test_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule, u_char *start, size_t length) -- cgit