diff options
Diffstat (limited to 'src')
57 files changed, 2476 insertions, 1890 deletions
diff --git a/src/nxt_application.c b/src/nxt_application.c index 594574b1..556f1ffb 100644 --- a/src/nxt_application.c +++ b/src/nxt_application.c @@ -23,6 +23,13 @@ #endif +#ifdef WCOREDUMP +#define NXT_WCOREDUMP(s) WCOREDUMP(s) +#else +#define NXT_WCOREDUMP(s) 0 +#endif + + typedef struct { nxt_app_type_t type; nxt_str_t version; @@ -636,6 +643,8 @@ nxt_proto_start_process_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) process->data.app = nxt_app_conf; process->stream = msg->port_msg.stream; + init->siblings = &nxt_proto_children; + ret = nxt_process_start(task, process); if (nxt_slow_path(ret == NXT_ERROR)) { nxt_process_use(task, process, -1); @@ -711,15 +720,19 @@ nxt_proto_process_created_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) nxt_debug(task, "app process %PI (aka %PI) is created", isolated_pid, pid); - nxt_runtime_process_remove(task->thread->runtime, process); - process->pid = pid; - nxt_runtime_process_add(task, process); - } else { nxt_debug(task, "app process %PI is created", isolated_pid); } + + if (!process->registered) { + nxt_assert(!nxt_queue_is_empty(&process->ports)); + + nxt_runtime_process_add(task, process); + + nxt_port_use(task, nxt_process_port_first(process), -1); + } } @@ -753,7 +766,11 @@ nxt_proto_sigchld_handler(nxt_task_t *task, void *obj, void *data) int status; nxt_err_t err; nxt_pid_t pid; + nxt_port_t *port; nxt_process_t *process; + nxt_runtime_t *rt; + + rt = task->thread->runtime; nxt_debug(task, "proto sigchld handler signo:%d (%s)", (int) (uintptr_t) obj, data); @@ -783,32 +800,58 @@ nxt_proto_sigchld_handler(nxt_task_t *task, void *obj, void *data) return; } + process = nxt_proto_process_remove(task, pid); + if (WTERMSIG(status)) { -#ifdef WCOREDUMP - nxt_alert(task, "app process (isolated %PI) exited on signal %d%s", - pid, WTERMSIG(status), - WCOREDUMP(status) ? " (core dumped)" : ""); -#else - nxt_alert(task, "app process (isolated %PI) exited on signal %d", - pid, WTERMSIG(status)); -#endif + if (rt->is_pid_isolated) { + nxt_alert(task, "app process %PI (isolated %PI) " + "exited on signal %d%s", + process != NULL ? process->pid : 0, + pid, WTERMSIG(status), + NXT_WCOREDUMP(status) ? " (core dumped)" : ""); + + } else { + nxt_alert(task, "app process %PI exited on signal %d%s", + pid, WTERMSIG(status), + NXT_WCOREDUMP(status) ? " (core dumped)" : ""); + } } else { - nxt_trace(task, "app process (isolated %PI) exited with code %d", - pid, WEXITSTATUS(status)); + if (rt->is_pid_isolated) { + nxt_trace(task, "app process %PI (isolated %PI) " + "exited with code %d", + process != NULL ? process->pid : 0, + pid, WEXITSTATUS(status)); + + } else { + nxt_trace(task, "app process %PI exited with code %d", + pid, WEXITSTATUS(status)); + } } - process = nxt_proto_process_remove(task, pid); if (process == NULL) { continue; } + if (process->registered) { + port = NULL; + + } else { + nxt_assert(!nxt_queue_is_empty(&process->ports)); + + port = nxt_process_port_first(process); + } + if (process->state != NXT_PROCESS_STATE_CREATING) { nxt_port_remove_notify_others(task, process); } nxt_process_close_ports(task, process); + if (port != NULL) { + nxt_port_use(task, port, -1); + } + if (nxt_proto_exiting && nxt_queue_is_empty(&nxt_proto_children)) { nxt_process_quit(task, 0); return; @@ -1122,7 +1165,7 @@ nxt_proto_process_add(nxt_task_t *task, nxt_process_t *process) break; default: - nxt_debug(task, "process (isolated %PI) failed to add", + nxt_alert(task, "process (isolated %PI) failed to add", process->isolated_pid); break; } diff --git a/src/nxt_clone.c b/src/nxt_clone.c index aa952a54..a9b39ac1 100644 --- a/src/nxt_clone.c +++ b/src/nxt_clone.c @@ -14,9 +14,9 @@ pid_t nxt_clone(nxt_int_t flags) { #if defined(__s390x__) || defined(__s390__) || defined(__CRIS__) - return syscall(__NR_clone, NULL, flags); + return syscall(SYS_clone, NULL, flags); #else - return syscall(__NR_clone, flags, NULL); + return syscall(SYS_clone, flags, NULL); #endif } diff --git a/src/nxt_conf.c b/src/nxt_conf.c index 79e776a0..c6312f3d 100644 --- a/src/nxt_conf.c +++ b/src/nxt_conf.c @@ -102,7 +102,7 @@ typedef struct { static nxt_int_t nxt_conf_path_next_token(nxt_conf_path_parse_t *parse, nxt_str_t *token); -static u_char *nxt_conf_json_skip_space(u_char *start, u_char *end); +static u_char *nxt_conf_json_skip_space(u_char *start, const u_char *end); static u_char *nxt_conf_json_parse_value(nxt_mp_t *mp, nxt_conf_value_t *value, u_char *start, u_char *end, nxt_conf_json_error_t *error); static u_char *nxt_conf_json_parse_object(nxt_mp_t *mp, nxt_conf_value_t *value, @@ -266,7 +266,7 @@ nxt_conf_create_object(nxt_mp_t *mp, nxt_uint_t count) void nxt_conf_set_member(nxt_conf_value_t *object, nxt_str_t *name, - nxt_conf_value_t *value, uint32_t index) + const nxt_conf_value_t *value, uint32_t index) { nxt_conf_object_member_t *member; @@ -278,6 +278,20 @@ nxt_conf_set_member(nxt_conf_value_t *object, nxt_str_t *name, } +nxt_int_t +nxt_conf_set_member_dup(nxt_conf_value_t *object, nxt_mp_t *mp, nxt_str_t *name, + nxt_conf_value_t *value, uint32_t index) +{ + nxt_conf_object_member_t *member; + + member = &object->u.object->members[index]; + + member->value = *value; + + return nxt_conf_set_string_dup(&member->name, mp, name); +} + + void nxt_conf_set_member_string(nxt_conf_value_t *object, nxt_str_t *name, nxt_str_t *value, uint32_t index) @@ -367,7 +381,7 @@ nxt_conf_create_array(nxt_mp_t *mp, nxt_uint_t count) void nxt_conf_set_element(nxt_conf_value_t *array, nxt_uint_t index, - nxt_conf_value_t *value) + const nxt_conf_value_t *value) { array->u.array->elements[index] = *value; } @@ -1271,7 +1285,7 @@ nxt_conf_json_parse(nxt_mp_t *mp, u_char *start, u_char *end, static u_char * -nxt_conf_json_skip_space(u_char *start, u_char *end) +nxt_conf_json_skip_space(u_char *start, const u_char *end) { u_char *p, ch; @@ -2605,7 +2619,7 @@ nxt_conf_json_escape(u_char *dst, u_char *src, size_t size) void -nxt_conf_json_position(u_char *start, u_char *pos, nxt_uint_t *line, +nxt_conf_json_position(u_char *start, const u_char *pos, nxt_uint_t *line, nxt_uint_t *column) { u_char *p; diff --git a/src/nxt_conf.h b/src/nxt_conf.h index cfbc5991..c8a276c0 100644 --- a/src/nxt_conf.h +++ b/src/nxt_conf.h @@ -72,6 +72,7 @@ typedef struct { nxt_mp_t *pool; nxt_str_t error; void *ctx; + nxt_array_t *var_fields; /* of nxt_var_field_t */ nxt_mp_t *conf_pool; nxt_uint_t ver; } nxt_conf_validation_t; @@ -109,7 +110,7 @@ size_t nxt_conf_json_length(nxt_conf_value_t *value, nxt_conf_json_pretty_t *pretty); u_char *nxt_conf_json_print(u_char *p, nxt_conf_value_t *value, nxt_conf_json_pretty_t *pretty); -void nxt_conf_json_position(u_char *start, u_char *pos, nxt_uint_t *line, +void nxt_conf_json_position(u_char *start, const u_char *pos, nxt_uint_t *line, nxt_uint_t *column); nxt_int_t nxt_conf_validate(nxt_conf_validation_t *vldt); @@ -125,7 +126,9 @@ NXT_EXPORT uint8_t nxt_conf_get_boolean(nxt_conf_value_t *value); NXT_EXPORT nxt_uint_t nxt_conf_object_members_count(nxt_conf_value_t *value); nxt_conf_value_t *nxt_conf_create_object(nxt_mp_t *mp, nxt_uint_t count); void nxt_conf_set_member(nxt_conf_value_t *object, nxt_str_t *name, - nxt_conf_value_t *value, uint32_t index); + const nxt_conf_value_t *value, uint32_t index); +nxt_int_t nxt_conf_set_member_dup(nxt_conf_value_t *object, nxt_mp_t *mp, + nxt_str_t *name, nxt_conf_value_t *value, uint32_t index); void nxt_conf_set_member_string(nxt_conf_value_t *object, nxt_str_t *name, nxt_str_t *value, uint32_t index); nxt_int_t nxt_conf_set_member_string_dup(nxt_conf_value_t *object, nxt_mp_t *mp, @@ -137,7 +140,7 @@ void nxt_conf_set_member_null(nxt_conf_value_t *object, nxt_str_t *name, nxt_conf_value_t *nxt_conf_create_array(nxt_mp_t *mp, nxt_uint_t count); void nxt_conf_set_element(nxt_conf_value_t *array, nxt_uint_t index, - nxt_conf_value_t *value); + const nxt_conf_value_t *value); nxt_int_t nxt_conf_set_element_string_dup(nxt_conf_value_t *array, nxt_mp_t *mp, nxt_uint_t index, nxt_str_t *value); NXT_EXPORT nxt_uint_t nxt_conf_array_elements_count(nxt_conf_value_t *value); diff --git a/src/nxt_conf_validation.c b/src/nxt_conf_validation.c index ee7ebe44..fe6c22e5 100644 --- a/src/nxt_conf_validation.c +++ b/src/nxt_conf_validation.c @@ -166,6 +166,8 @@ static nxt_int_t nxt_conf_vldt_match_addr(nxt_conf_validation_t *vldt, 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_forwarded(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, nxt_str_t *name, nxt_conf_value_t *value); static nxt_int_t nxt_conf_vldt_object(nxt_conf_validation_t *vldt, @@ -200,6 +202,8 @@ static nxt_int_t nxt_conf_vldt_server(nxt_conf_validation_t *vldt, nxt_str_t *name, nxt_conf_value_t *value); static nxt_int_t nxt_conf_vldt_server_weight(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data); +static nxt_int_t nxt_conf_vldt_access_log(nxt_conf_validation_t *vldt, + nxt_conf_value_t *value, void *data); static nxt_int_t nxt_conf_vldt_isolation(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data); @@ -220,6 +224,7 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_setting_members[]; static nxt_conf_vldt_object_t nxt_conf_vldt_http_members[]; static nxt_conf_vldt_object_t nxt_conf_vldt_websocket_members[]; static nxt_conf_vldt_object_t nxt_conf_vldt_static_members[]; +static nxt_conf_vldt_object_t nxt_conf_vldt_forwarded_members[]; static nxt_conf_vldt_object_t nxt_conf_vldt_client_ip_members[]; #if (NXT_TLS) static nxt_conf_vldt_object_t nxt_conf_vldt_tls_members[]; @@ -238,6 +243,7 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_app_namespaces_members[]; #if (NXT_HAVE_ISOLATION_ROOTFS) static nxt_conf_vldt_object_t nxt_conf_vldt_app_automount_members[]; #endif +static nxt_conf_vldt_object_t nxt_conf_vldt_access_log_members[]; static nxt_conf_vldt_object_t nxt_conf_vldt_root_members[] = { @@ -267,7 +273,8 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_root_members[] = { .u.object = nxt_conf_vldt_upstream, }, { .name = nxt_string("access_log"), - .type = NXT_CONF_VLDT_STRING, + .type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_OBJECT, + .validator = nxt_conf_vldt_access_log, }, NXT_CONF_VLDT_END @@ -366,6 +373,10 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_listener_members[] = { .type = NXT_CONF_VLDT_STRING, .validator = nxt_conf_vldt_app_name, }, { + .name = nxt_string("forwarded"), + .type = NXT_CONF_VLDT_OBJECT, + .validator = nxt_conf_vldt_forwarded, + }, { .name = nxt_string("client_ip"), .type = NXT_CONF_VLDT_OBJECT, .validator = nxt_conf_vldt_object, @@ -385,6 +396,27 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_listener_members[] = { }; +static nxt_conf_vldt_object_t nxt_conf_vldt_forwarded_members[] = { + { + .name = nxt_string("client_ip"), + .type = NXT_CONF_VLDT_STRING, + }, { + .name = nxt_string("protocol"), + .type = NXT_CONF_VLDT_STRING, + }, { + .name = nxt_string("source"), + .type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, + .validator = nxt_conf_vldt_match_addrs, + .flags = NXT_CONF_VLDT_REQUIRED + }, { + .name = nxt_string("recursive"), + .type = NXT_CONF_VLDT_BOOLEAN, + }, + + NXT_CONF_VLDT_END +}; + + static nxt_conf_vldt_object_t nxt_conf_vldt_client_ip_members[] = { { .name = nxt_string("source"), @@ -1177,11 +1209,29 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_upstream_server_members[] = { }; +static nxt_conf_vldt_object_t nxt_conf_vldt_access_log_members[] = { + { + .name = nxt_string("path"), + .type = NXT_CONF_VLDT_STRING, + }, { + .name = nxt_string("format"), + .type = NXT_CONF_VLDT_STRING, + }, + + NXT_CONF_VLDT_END +}; + + nxt_int_t nxt_conf_validate(nxt_conf_validation_t *vldt) { nxt_int_t ret; + vldt->var_fields = nxt_array_create(vldt->pool, 4, sizeof(nxt_var_field_t)); + if (nxt_slow_path(vldt->var_fields == NULL)) { + return NXT_ERROR; + } + ret = nxt_conf_vldt_type(vldt, NULL, vldt->conf, NXT_CONF_VLDT_OBJECT); if (ret != NXT_OK) { return ret; @@ -1314,7 +1364,7 @@ nxt_conf_vldt_var(nxt_conf_validation_t *vldt, nxt_str_t *name, { u_char error[NXT_MAX_ERROR_STR]; - if (nxt_var_test(value, error) != NXT_OK) { + if (nxt_var_test(value, vldt->var_fields, error) != NXT_OK) { return nxt_conf_vldt_error(vldt, "%s in the \"%V\" value.", error, name); } @@ -1430,9 +1480,14 @@ nxt_conf_vldt_listener(nxt_conf_validation_t *vldt, nxt_str_t *name, nxt_conf_value_t *value) { nxt_int_t ret; + nxt_str_t str; nxt_sockaddr_t *sa; - sa = nxt_sockaddr_parse(vldt->pool, name); + if (nxt_slow_path(nxt_str_dup(vldt->pool, &str, name) == NULL)) { + return NXT_ERROR; + } + + sa = nxt_sockaddr_parse(vldt->pool, &str); if (nxt_slow_path(sa == NULL)) { return nxt_conf_vldt_error(vldt, "The listener address \"%V\" is invalid.", @@ -2124,6 +2179,11 @@ nxt_conf_vldt_match_addr(nxt_conf_validation_t *vldt, return nxt_conf_vldt_error(vldt, "The \"address\" does not support " "IPv6 with your configuration."); + case NXT_ADDR_PATTERN_NO_UNIX_ERROR: + return nxt_conf_vldt_error(vldt, "The \"address\" does not support " + "UNIX domain sockets with your " + "configuration."); + default: return nxt_conf_vldt_error(vldt, "The \"address\" has an unknown " "format."); @@ -2318,6 +2378,28 @@ error: static nxt_int_t +nxt_conf_vldt_forwarded(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, + void *data) +{ + nxt_conf_value_t *client_ip, *protocol; + + static nxt_str_t client_ip_str = nxt_string("client_ip"); + static nxt_str_t protocol_str = nxt_string("protocol"); + + client_ip = nxt_conf_get_object_member(value, &client_ip_str, NULL); + protocol = nxt_conf_get_object_member(value, &protocol_str, NULL); + + if (client_ip == NULL && protocol == NULL) { + return nxt_conf_vldt_error(vldt, "The \"forwarded\" object must have " + "either \"client_ip\" or \"protocol\" " + "option set."); + } + + return nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_forwarded_members); +} + + +static nxt_int_t nxt_conf_vldt_app(nxt_conf_validation_t *vldt, nxt_str_t *name, nxt_conf_value_t *value) { @@ -3030,3 +3112,65 @@ nxt_conf_vldt_server_weight(nxt_conf_validation_t *vldt, return NXT_OK; } + + +typedef struct { + nxt_str_t path; + nxt_str_t format; +} nxt_conf_vldt_access_log_conf_t; + + +static nxt_conf_map_t nxt_conf_vldt_access_log_map[] = { + { + nxt_string("path"), + NXT_CONF_MAP_STR, + offsetof(nxt_conf_vldt_access_log_conf_t, path), + }, + + { + nxt_string("format"), + NXT_CONF_MAP_STR, + offsetof(nxt_conf_vldt_access_log_conf_t, format), + }, +}; + + +static nxt_int_t +nxt_conf_vldt_access_log(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, + void *data) +{ + nxt_int_t ret; + nxt_conf_vldt_access_log_conf_t conf; + + static nxt_str_t format_str = nxt_string("format"); + + if (nxt_conf_type(value) == NXT_CONF_STRING) { + return NXT_OK; + } + + ret = nxt_conf_vldt_object(vldt, value, nxt_conf_vldt_access_log_members); + if (ret != NXT_OK) { + return ret; + } + + nxt_memzero(&conf, sizeof(nxt_conf_vldt_access_log_conf_t)); + + ret = nxt_conf_map_object(vldt->pool, value, + nxt_conf_vldt_access_log_map, + nxt_nitems(nxt_conf_vldt_access_log_map), + &conf); + if (ret != NXT_OK) { + return ret; + } + + if (conf.path.length == 0) { + return nxt_conf_vldt_error(vldt, + "The \"path\" string must not be empty."); + } + + if (nxt_is_var(&conf.format)) { + return nxt_conf_vldt_var(vldt, &format_str, &conf.format); + } + + return NXT_OK; +} diff --git a/src/nxt_conn.h b/src/nxt_conn.h index a443601f..8a703e9a 100644 --- a/src/nxt_conn.h +++ b/src/nxt_conn.h @@ -160,6 +160,7 @@ struct nxt_conn_s { uint8_t block_read; /* 1 bit */ uint8_t block_write; /* 1 bit */ uint8_t delayed; /* 1 bit */ + uint8_t idle; /* 1 bit */ #define NXT_CONN_SENDFILE_OFF 0 #define NXT_CONN_SENDFILE_ON 1 @@ -294,6 +295,28 @@ NXT_EXPORT void nxt_event_conn_job_sendfile(nxt_task_t *task, } while (0) +#define nxt_conn_idle(engine, c) \ + do { \ + nxt_event_engine_t *e = engine; \ + \ + nxt_queue_insert_head(&e->idle_connections, &c->link); \ + \ + c->idle = 1; \ + e->idle_conns_cnt++; \ + } while (0) + + +#define nxt_conn_active(engine, c) \ + do { \ + nxt_event_engine_t *e = engine; \ + \ + nxt_queue_remove(&c->link); \ + \ + c->idle = 0; \ + e->idle_conns_cnt--; \ + } while (0) + + extern nxt_conn_io_t nxt_unix_conn_io; diff --git a/src/nxt_conn_accept.c b/src/nxt_conn_accept.c index 77c44c58..720c7b64 100644 --- a/src/nxt_conn_accept.c +++ b/src/nxt_conn_accept.c @@ -187,7 +187,8 @@ nxt_conn_io_accept(nxt_task_t *task, void *obj, void *data) void nxt_conn_accept(nxt_task_t *task, nxt_listen_event_t *lev, nxt_conn_t *c) { - nxt_conn_t *next; + nxt_conn_t *next; + nxt_event_engine_t *engine; nxt_sockaddr_text(c->remote); @@ -195,7 +196,11 @@ nxt_conn_accept(nxt_task_t *task, nxt_listen_event_t *lev, nxt_conn_t *c) (size_t) c->remote->address_length, nxt_sockaddr_address(c->remote)); - nxt_queue_insert_head(&task->thread->engine->idle_connections, &c->link); + engine = task->thread->engine; + + engine->accepted_conns_cnt++; + + nxt_conn_idle(engine, c); c->listen = lev; lev->count++; diff --git a/src/nxt_conn_close.c b/src/nxt_conn_close.c index 7c130309..92bd8d1b 100644 --- a/src/nxt_conn_close.c +++ b/src/nxt_conn_close.c @@ -119,6 +119,8 @@ nxt_conn_close_handler(nxt_task_t *task, void *obj, void *data) nxt_socket_close(task, c->socket.fd); c->socket.fd = -1; + engine->closed_conns_cnt++; + if (timers_pending == 0) { nxt_work_queue_add(&engine->fast_work_queue, c->write_state->ready_handler, @@ -137,8 +139,9 @@ nxt_conn_close_handler(nxt_task_t *task, void *obj, void *data) static void nxt_conn_close_timer_handler(nxt_task_t *task, void *obj, void *data) { - nxt_conn_t *c; - nxt_timer_t *timer; + nxt_conn_t *c; + nxt_timer_t *timer; + nxt_event_engine_t *engine; timer = obj; @@ -146,13 +149,16 @@ nxt_conn_close_timer_handler(nxt_task_t *task, void *obj, void *data) nxt_debug(task, "conn close timer handler fd:%d", c->socket.fd); + engine = task->thread->engine; + if (c->socket.fd != -1) { nxt_socket_close(task, c->socket.fd); c->socket.fd = -1; + + engine->closed_conns_cnt++; } - nxt_work_queue_add(&task->thread->engine->fast_work_queue, - c->write_state->ready_handler, + nxt_work_queue_add(&engine->fast_work_queue, c->write_state->ready_handler, task, c, c->socket.data); } diff --git a/src/nxt_controller.c b/src/nxt_controller.c index 7510d6f0..09168821 100644 --- a/src/nxt_controller.c +++ b/src/nxt_controller.c @@ -9,6 +9,7 @@ #include <nxt_runtime.h> #include <nxt_main_process.h> #include <nxt_conf.h> +#include <nxt_status.h> #include <nxt_cert.h> @@ -85,6 +86,12 @@ static void nxt_controller_process_request(nxt_task_t *task, static void nxt_controller_process_config(nxt_task_t *task, nxt_controller_request_t *req, nxt_str_t *path); static nxt_bool_t nxt_controller_check_postpone_request(nxt_task_t *task); +static void nxt_controller_process_status(nxt_task_t *task, + nxt_controller_request_t *req); +static void nxt_controller_status_handler(nxt_task_t *task, + nxt_port_recv_msg_t *msg, void *data); +static void nxt_controller_status_response(nxt_task_t *task, + nxt_controller_request_t *req, nxt_str_t *path); #if (NXT_TLS) static void nxt_controller_process_cert(nxt_task_t *task, nxt_controller_request_t *req, nxt_str_t *path); @@ -120,6 +127,7 @@ static nxt_uint_t nxt_controller_router_ready; static nxt_controller_conf_t nxt_controller_conf; static nxt_queue_t nxt_controller_waiting_requests; static nxt_bool_t nxt_controller_waiting_init_conf; +static nxt_conf_value_t *nxt_controller_status; static const nxt_event_conn_state_t nxt_controller_conn_read_state; @@ -725,7 +733,7 @@ static const nxt_event_conn_state_t nxt_controller_conn_read_state .timer_handler = nxt_controller_conn_read_timeout, .timer_value = nxt_controller_conn_timeout_value, - .timer_data = 60 * 1000, + .timer_data = 300 * 1000, }; @@ -1035,6 +1043,7 @@ nxt_controller_process_request(nxt_task_t *task, nxt_controller_request_t *req) static nxt_str_t certificates = nxt_string("certificates"); #endif static nxt_str_t config = nxt_string("config"); + static nxt_str_t status = nxt_string("status"); c = req->conn; path = req->parser.path; @@ -1058,6 +1067,32 @@ nxt_controller_process_request(nxt_task_t *task, nxt_controller_request_t *req) return; } + nxt_memzero(&resp, sizeof(nxt_controller_response_t)); + + if (nxt_str_start(&path, "/status", 7) + && (path.length == 7 || path.start[7] == '/')) + { + if (!nxt_str_eq(&req->parser.method, "GET", 3)) { + goto invalid_method; + } + + if (nxt_controller_status == NULL) { + nxt_controller_process_status(task, req); + return; + } + + if (path.length == 7) { + path.length = 1; + + } else { + path.length -= 7; + path.start += 7; + } + + nxt_controller_status_response(task, req, &path); + return; + } + #if (NXT_TLS) if (nxt_str_start(&path, "/certificates", 13) @@ -1085,15 +1120,18 @@ nxt_controller_process_request(nxt_task_t *task, nxt_controller_request_t *req) return; } - nxt_memzero(&resp, sizeof(nxt_controller_response_t)); - if (path.length == 1 && path.start[0] == '/') { if (!nxt_str_eq(&req->parser.method, "GET", 3)) { goto invalid_method; } - count = 1; + if (nxt_controller_status == NULL) { + nxt_controller_process_status(task, req); + return; + } + + count = 2; #if (NXT_TLS) count++; #endif @@ -1114,7 +1152,8 @@ nxt_controller_process_request(nxt_task_t *task, nxt_controller_request_t *req) nxt_conf_set_member(value, &certificates, certs, i++); #endif - nxt_conf_set_member(value, &config, nxt_controller_conf.root, i); + nxt_conf_set_member(value, &config, nxt_controller_conf.root, i++); + nxt_conf_set_member(value, &status, nxt_controller_status, i); resp.status = 200; resp.conf = value; @@ -1451,6 +1490,128 @@ nxt_controller_check_postpone_request(nxt_task_t *task) } +static void +nxt_controller_process_status(nxt_task_t *task, nxt_controller_request_t *req) +{ + uint32_t stream; + nxt_int_t rc; + nxt_port_t *router_port, *controller_port; + nxt_runtime_t *rt; + nxt_controller_response_t resp; + + if (nxt_controller_check_postpone_request(task)) { + nxt_queue_insert_tail(&nxt_controller_waiting_requests, &req->link); + return; + } + + rt = task->thread->runtime; + + router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; + + nxt_assert(router_port != NULL); + nxt_assert(nxt_controller_router_ready); + + controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER]; + + stream = nxt_port_rpc_register_handler(task, controller_port, + nxt_controller_status_handler, + nxt_controller_status_handler, + router_port->pid, req); + if (nxt_slow_path(stream == 0)) { + goto fail; + } + + rc = nxt_port_socket_write(task, router_port, NXT_PORT_MSG_STATUS, + -1, stream, controller_port->id, NULL); + + if (nxt_slow_path(rc != NXT_OK)) { + nxt_port_rpc_cancel(task, controller_port, stream); + + goto fail; + } + + nxt_queue_insert_head(&nxt_controller_waiting_requests, &req->link); + return; + +fail: + + nxt_memzero(&resp, sizeof(nxt_controller_response_t)); + + resp.status = 500; + resp.title = (u_char *) "Failed to get status."; + resp.offset = -1; + + nxt_controller_response(task, req, &resp); + return; +} + + +static void +nxt_controller_status_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, + void *data) +{ + nxt_conf_value_t *status; + nxt_controller_request_t *req; + nxt_controller_response_t resp; + + nxt_debug(task, "controller status handler"); + + req = data; + + if (msg->port_msg.type == NXT_PORT_MSG_RPC_READY) { + status = nxt_status_get((nxt_status_report_t *) msg->buf->mem.pos, + req->conn->mem_pool); + } else { + status = NULL; + } + + if (status == NULL) { + nxt_queue_remove(&req->link); + + nxt_memzero(&resp, sizeof(nxt_controller_response_t)); + + resp.status = 500; + resp.title = (u_char *) "Failed to get status."; + resp.offset = -1; + + nxt_controller_response(task, req, &resp); + } + + nxt_controller_status = status; + + nxt_controller_flush_requests(task); + + nxt_controller_status = NULL; +} + + +static void +nxt_controller_status_response(nxt_task_t *task, nxt_controller_request_t *req, + nxt_str_t *path) +{ + nxt_conf_value_t *status; + nxt_controller_response_t resp; + + status = nxt_conf_get_path(nxt_controller_status, path); + + nxt_memzero(&resp, sizeof(nxt_controller_response_t)); + + if (status == NULL) { + resp.status = 404; + resp.title = (u_char *) "Invalid path."; + resp.offset = -1; + + nxt_controller_response(task, req, &resp); + return; + } + + resp.status = 200; + resp.conf = status; + + nxt_controller_response(task, req, &resp); +} + + #if (NXT_TLS) static void diff --git a/src/nxt_event_engine.h b/src/nxt_event_engine.h index 91cfc0aa..291ea749 100644 --- a/src/nxt_event_engine.h +++ b/src/nxt_event_engine.h @@ -483,6 +483,11 @@ struct nxt_event_engine_s { nxt_queue_t idle_connections; nxt_array_t *mem_cache; + nxt_atomic_uint_t accepted_conns_cnt; + nxt_atomic_uint_t idle_conns_cnt; + nxt_atomic_uint_t closed_conns_cnt; + nxt_atomic_uint_t requests_cnt; + nxt_queue_link_t link; // STUB: router link nxt_queue_link_t link0; diff --git a/src/nxt_h1proto.c b/src/nxt_h1proto.c index d3340774..852b4866 100644 --- a/src/nxt_h1proto.c +++ b/src/nxt_h1proto.c @@ -478,7 +478,7 @@ nxt_h1p_conn_request_init(nxt_task_t *task, void *obj, void *data) nxt_debug(task, "h1p conn request init"); - nxt_queue_remove(&c->link); + nxt_conn_active(task->thread->engine, c); r = nxt_http_request_create(task); @@ -490,7 +490,7 @@ nxt_h1p_conn_request_init(nxt_task_t *task, void *obj, void *data) r->remote = c->remote; #if (NXT_TLS) - r->tls = c->u.tls; + r->tls = (c->u.tls != NULL); #endif r->task = c->task; @@ -1739,7 +1739,7 @@ nxt_h1p_conn_close(nxt_task_t *task, void *obj, void *data) nxt_debug(task, "h1p conn close"); - nxt_queue_remove(&c->link); + nxt_conn_active(task->thread->engine, c); nxt_h1p_shutdown(task, c); } @@ -1754,7 +1754,7 @@ nxt_h1p_conn_error(nxt_task_t *task, void *obj, void *data) nxt_debug(task, "h1p conn error"); - nxt_queue_remove(&c->link); + nxt_conn_active(task->thread->engine, c); nxt_h1p_shutdown(task, c); } @@ -1801,7 +1801,8 @@ nxt_h1p_keepalive(nxt_task_t *task, nxt_h1proto_t *h1p, nxt_conn_t *c) c->sent = 0; engine = task->thread->engine; - nxt_queue_insert_head(&engine->idle_connections, &c->link); + + nxt_conn_idle(engine, c); if (in == NULL) { c->read_state = &nxt_h1p_keepalive_state; @@ -1855,7 +1856,7 @@ nxt_h1p_idle_close(nxt_task_t *task, void *obj, void *data) nxt_debug(task, "h1p idle close"); - nxt_queue_remove(&c->link); + nxt_conn_active(task->thread->engine, c); nxt_h1p_idle_response(task, c); } @@ -1874,7 +1875,7 @@ nxt_h1p_idle_timeout(nxt_task_t *task, void *obj, void *data) c = nxt_read_timer_conn(timer); c->block_read = 1; - nxt_queue_remove(&c->link); + nxt_conn_active(task->thread->engine, c); nxt_h1p_idle_response(task, c); } diff --git a/src/nxt_http.h b/src/nxt_http.h index d299fdd4..c2e85840 100644 --- a/src/nxt_http.h +++ b/src/nxt_http.h @@ -162,7 +162,6 @@ struct nxt_http_request_s { nxt_sockaddr_t *remote; nxt_sockaddr_t *local; - void *tls; nxt_task_t task; nxt_timer_t timer; @@ -190,6 +189,7 @@ struct nxt_http_request_s { uint8_t pass_count; /* 8 bits */ uint8_t app_target; nxt_http_protocol_t protocol:8; /* 2 bits */ + uint8_t tls; /* 1 bit */ uint8_t logged; /* 1 bit */ uint8_t header_sent; /* 1 bit */ uint8_t inconsistent; /* 1 bit */ @@ -207,6 +207,13 @@ typedef struct { } nxt_http_name_value_t; +typedef enum { + NXT_HTTP_URI_ENCODING_NONE = 0, + NXT_HTTP_URI_ENCODING, + NXT_HTTP_URI_ENCODING_PLUS +} nxt_http_uri_encoding_t; + + typedef struct nxt_http_route_s nxt_http_route_t; typedef struct nxt_http_route_rule_s nxt_http_route_rule_t; typedef struct nxt_http_route_addr_rule_s nxt_http_route_addr_rule_t; @@ -266,10 +273,16 @@ typedef struct { } nxt_http_proto_table_t; -struct nxt_http_client_ip_s { - nxt_http_route_addr_rule_t *source; +typedef struct { nxt_str_t *header; uint32_t header_hash; +} nxt_http_forward_header_t; + + +struct nxt_http_forward_s { + nxt_http_forward_header_t client_ip; + nxt_http_forward_header_t protocol; + nxt_http_route_addr_rule_t *source; uint8_t recursive; /* 1 bit */ }; @@ -324,6 +337,12 @@ nxt_int_t nxt_http_request_content_length(void *ctx, nxt_http_field_t *field, nxt_array_t *nxt_http_arguments_parse(nxt_http_request_t *r); nxt_array_t *nxt_http_cookies_parse(nxt_http_request_t *r); +int64_t nxt_http_field_hash(nxt_mp_t *mp, nxt_str_t *name, + nxt_bool_t case_sensitive, uint8_t encoding); +int64_t nxt_http_argument_hash(nxt_mp_t *mp, nxt_str_t *name); +int64_t nxt_http_header_hash(nxt_mp_t *mp, nxt_str_t *name); +int64_t nxt_http_cookie_hash(nxt_mp_t *mp, nxt_str_t *name); + nxt_http_routes_t *nxt_http_routes_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *routes_conf); nxt_http_action_t *nxt_http_action_create(nxt_task_t *task, @@ -353,15 +372,16 @@ nxt_int_t nxt_upstreams_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, nxt_int_t nxt_upstreams_joint_create(nxt_router_temp_conf_t *tmcf, nxt_upstream_t ***upstream_joint); -nxt_int_t nxt_http_return_init(nxt_mp_t *mp, nxt_http_action_t *action, - nxt_http_action_conf_t *acf); +nxt_int_t nxt_http_return_init(nxt_router_conf_t *rtcf, + nxt_http_action_t *action, nxt_http_action_conf_t *acf); nxt_int_t nxt_http_static_init(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, nxt_http_action_t *action, nxt_http_action_conf_t *acf); nxt_int_t nxt_http_static_mtypes_init(nxt_mp_t *mp, nxt_lvlhsh_t *hash); nxt_int_t nxt_http_static_mtypes_hash_add(nxt_mp_t *mp, nxt_lvlhsh_t *hash, - nxt_str_t *exten, nxt_str_t *type); -nxt_str_t *nxt_http_static_mtype_get(nxt_lvlhsh_t *hash, nxt_str_t *exten); + const nxt_str_t *exten, nxt_str_t *type); +nxt_str_t *nxt_http_static_mtype_get(nxt_lvlhsh_t *hash, + const nxt_str_t *exten); nxt_http_action_t *nxt_http_application_handler(nxt_task_t *task, nxt_http_request_t *r, nxt_http_action_t *action); diff --git a/src/nxt_http_parse.c b/src/nxt_http_parse.c index 1ab6cc90..1bb4291f 100644 --- a/src/nxt_http_parse.c +++ b/src/nxt_http_parse.c @@ -8,16 +8,16 @@ static nxt_int_t nxt_http_parse_unusual_target(nxt_http_request_parse_t *rp, - u_char **pos, u_char *end); + u_char **pos, const u_char *end); static nxt_int_t nxt_http_parse_request_line(nxt_http_request_parse_t *rp, - u_char **pos, u_char *end); + u_char **pos, const u_char *end); static nxt_int_t nxt_http_parse_field_name(nxt_http_request_parse_t *rp, - u_char **pos, u_char *end); + u_char **pos, const u_char *end); static nxt_int_t nxt_http_parse_field_value(nxt_http_request_parse_t *rp, - u_char **pos, u_char *end); -static u_char *nxt_http_lookup_field_end(u_char *p, u_char *end); + u_char **pos, const u_char *end); +static u_char *nxt_http_lookup_field_end(u_char *p, const u_char *end); static nxt_int_t nxt_http_parse_field_end(nxt_http_request_parse_t *rp, - u_char **pos, u_char *end); + u_char **pos, const u_char *end); static nxt_int_t nxt_http_parse_complex_target(nxt_http_request_parse_t *rp); @@ -62,7 +62,7 @@ static const uint8_t nxt_http_target_chars[256] nxt_aligned(64) = { nxt_inline nxt_http_target_traps_e -nxt_http_parse_target(u_char **pos, u_char *end) +nxt_http_parse_target(u_char **pos, const u_char *end) { u_char *p; nxt_uint_t trap; @@ -158,7 +158,7 @@ nxt_http_parse_fields(nxt_http_request_parse_t *rp, nxt_buf_mem_t *b) static nxt_int_t nxt_http_parse_request_line(nxt_http_request_parse_t *rp, u_char **pos, - u_char *end) + const u_char *end) { u_char *p, ch, *after_slash, *args; nxt_int_t rc; @@ -479,7 +479,7 @@ space_after_target: static nxt_int_t nxt_http_parse_unusual_target(nxt_http_request_parse_t *rp, u_char **pos, - u_char *end) + const u_char *end) { u_char *p, ch; @@ -517,7 +517,7 @@ nxt_http_parse_unusual_target(nxt_http_request_parse_t *rp, u_char **pos, static nxt_int_t nxt_http_parse_field_name(nxt_http_request_parse_t *rp, u_char **pos, - u_char *end) + const u_char *end) { u_char *p, c; size_t len; @@ -624,7 +624,7 @@ name_end: static nxt_int_t nxt_http_parse_field_value(nxt_http_request_parse_t *rp, u_char **pos, - u_char *end) + const u_char *end) { u_char *p, *start, ch; size_t len; @@ -704,7 +704,7 @@ nxt_http_parse_field_value(nxt_http_request_parse_t *rp, u_char **pos, static u_char * -nxt_http_lookup_field_end(u_char *p, u_char *end) +nxt_http_lookup_field_end(u_char *p, const u_char *end) { while (nxt_fast_path(end - p >= 16)) { @@ -771,7 +771,7 @@ nxt_http_lookup_field_end(u_char *p, u_char *end) static nxt_int_t nxt_http_parse_field_end(nxt_http_request_parse_t *rp, u_char **pos, - u_char *end) + const u_char *end) { u_char *p; nxt_http_field_t *field; diff --git a/src/nxt_http_parse.h b/src/nxt_http_parse.h index 3cd9bd15..2b714464 100644 --- a/src/nxt_http_parse.h +++ b/src/nxt_http_parse.h @@ -35,7 +35,7 @@ typedef union { struct nxt_http_request_parse_s { nxt_int_t (*handler)(nxt_http_request_parse_t *rp, - u_char **pos, u_char *end); + u_char **pos, const u_char *end); nxt_str_t method; diff --git a/src/nxt_http_request.c b/src/nxt_http_request.c index 04a6f7f3..943ad82d 100644 --- a/src/nxt_http_request.c +++ b/src/nxt_http_request.c @@ -10,10 +10,14 @@ 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 nxt_int_t nxt_http_request_client_ip(nxt_task_t *task, - nxt_http_request_t *r); +static nxt_int_t nxt_http_request_forward(nxt_task_t *task, + nxt_http_request_t *r, nxt_http_forward_t *forward); +static void nxt_http_request_forward_client_ip(nxt_http_request_t *r, + nxt_http_forward_t *forward, nxt_array_t *fields); static nxt_sockaddr_t *nxt_http_request_client_ip_sockaddr( nxt_http_request_t *r, u_char *start, size_t len); +static void nxt_http_request_forward_protocol(nxt_http_request_t *r, + nxt_http_field_t *field); static void nxt_http_request_ready(nxt_task_t *task, void *obj, void *data); static void nxt_http_request_proto_info(nxt_task_t *task, nxt_http_request_t *r); @@ -26,11 +30,11 @@ static u_char *nxt_http_date_cache_handler(u_char *buf, nxt_realtime_t *now, static nxt_http_name_value_t *nxt_http_argument(nxt_array_t *array, u_char *name, size_t name_length, uint32_t hash, u_char *start, - u_char *end); + const u_char *end); static nxt_int_t nxt_http_cookie_parse(nxt_array_t *cookies, u_char *start, - u_char *end); + const u_char *end); static nxt_http_name_value_t *nxt_http_cookie(nxt_array_t *array, u_char *name, - size_t name_length, u_char *start, u_char *end); + size_t name_length, u_char *start, const u_char *end); #define NXT_HTTP_COOKIE_HASH \ @@ -274,6 +278,8 @@ nxt_http_request_create(nxt_task_t *task) r->resp.content_length_n = -1; r->state = &nxt_http_request_init_state; + task->thread->engine->requests_cnt++; + return r; fail: @@ -296,74 +302,125 @@ static void nxt_http_request_start(nxt_task_t *task, void *obj, void *data) { nxt_int_t ret; + nxt_socket_conf_t *skcf; nxt_http_request_t *r; r = obj; r->state = &nxt_http_request_body_state; - ret = nxt_http_request_client_ip(task, r); - if (nxt_slow_path(ret != NXT_OK)) { - nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); + skcf = r->conf->socket_conf; + + if (skcf->forwarded != NULL) { + ret = nxt_http_request_forward(task, r, skcf->forwarded); + if (nxt_slow_path(ret != NXT_OK)) { + goto fail; + } + } + + if (skcf->client_ip != NULL) { + ret = nxt_http_request_forward(task, r, skcf->client_ip); + if (nxt_slow_path(ret != NXT_OK)) { + goto fail; + } } nxt_http_request_read_body(task, r); + + return; + +fail: + nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); } static nxt_int_t -nxt_http_request_client_ip(nxt_task_t *task, nxt_http_request_t *r) +nxt_http_request_forward(nxt_task_t *task, nxt_http_request_t *r, + nxt_http_forward_t *forward) { - u_char *start, *p; - nxt_int_t ret, i, len; - nxt_str_t *header; - nxt_array_t *fields_arr; /* of nxt_http_field_t * */ - nxt_sockaddr_t *sa, *prev_sa; - nxt_http_field_t *f, **fields; - nxt_http_client_ip_t *client_ip; + nxt_int_t ret; + nxt_array_t *client_ip_fields; + nxt_http_field_t *f, **fields, *protocol_field; + nxt_http_forward_header_t *client_ip, *protocol; - client_ip = r->conf->socket_conf->client_ip; - - if (client_ip == NULL) { - return NXT_OK; - } - - ret = nxt_http_route_addr_rule(r, client_ip->source, r->remote); + ret = nxt_http_route_addr_rule(r, forward->source, r->remote); if (ret <= 0) { return NXT_OK; } - header = client_ip->header; + client_ip = &forward->client_ip; + protocol = &forward->protocol; + + if (client_ip->header != NULL) { + client_ip_fields = nxt_array_create(r->mem_pool, 1, + sizeof(nxt_http_field_t *)); + if (nxt_slow_path(client_ip_fields == NULL)) { + return NXT_ERROR; + } - fields_arr = nxt_array_create(r->mem_pool, 2, sizeof(nxt_http_field_t *)); - if (nxt_slow_path(fields_arr == NULL)) { - return NXT_ERROR; + } else { + client_ip_fields = NULL; } + protocol_field = NULL; + nxt_list_each(f, r->fields) { - if (f->hash == client_ip->header_hash - && f->name_length == client_ip->header->length + if (client_ip_fields != NULL + && f->hash == client_ip->header_hash && f->value_length > 0 - && nxt_memcasecmp(f->name, header->start, header->length) == 0) + && f->name_length == client_ip->header->length + && nxt_memcasecmp(f->name, client_ip->header->start, + client_ip->header->length) == 0) { - fields = nxt_array_add(fields_arr); + fields = nxt_array_add(client_ip_fields); if (nxt_slow_path(fields == NULL)) { return NXT_ERROR; } *fields = f; } + + if (protocol->header != NULL + && protocol_field == NULL + && f->hash == protocol->header_hash + && f->value_length > 0 + && f->name_length == protocol->header->length + && nxt_memcasecmp(f->name, protocol->header->start, + protocol->header->length) == 0) + { + protocol_field = f; + } } nxt_list_loop; + if (client_ip_fields != NULL) { + nxt_http_request_forward_client_ip(r, forward, client_ip_fields); + } + + if (protocol_field != NULL) { + nxt_http_request_forward_protocol(r, protocol_field); + } + + return NXT_OK; +} + + +static void +nxt_http_request_forward_client_ip(nxt_http_request_t *r, + nxt_http_forward_t *forward, nxt_array_t *fields) +{ + u_char *start, *p; + nxt_int_t ret, i, len; + nxt_sockaddr_t *sa, *prev_sa; + nxt_http_field_t **f; + prev_sa = r->remote; - fields = (nxt_http_field_t **) fields_arr->elts; + f = (nxt_http_field_t **) fields->elts; - i = fields_arr->nelts; + i = fields->nelts; while (i-- > 0) { - f = fields[i]; - start = f->value; - len = f->value_length; + start = f[i]->value; + len = f[i]->value_length; do { for (p = start + len - 1; p > start; p--, len--) { @@ -385,20 +442,18 @@ nxt_http_request_client_ip(nxt_task_t *task, nxt_http_request_t *r) r->remote = prev_sa; } - return NXT_OK; + return; } - if (!client_ip->recursive) { + if (!forward->recursive) { r->remote = sa; - - return NXT_OK; + return; } - ret = nxt_http_route_addr_rule(r, client_ip->source, sa); + ret = nxt_http_route_addr_rule(r, forward->source, sa); if (ret <= 0 || (i == 0 && p == start)) { r->remote = sa; - - return NXT_OK; + return; } prev_sa = sa; @@ -406,8 +461,6 @@ nxt_http_request_client_ip(nxt_task_t *task, nxt_http_request_t *r) } while (len > 0); } - - return NXT_OK; } @@ -451,6 +504,28 @@ nxt_http_request_client_ip_sockaddr(nxt_http_request_t *r, u_char *start, } +static void +nxt_http_request_forward_protocol(nxt_http_request_t *r, + nxt_http_field_t *field) +{ + if (field->value_length == 4) { + if (nxt_memcasecmp(field->value, "http", 4) == 0) { + r->tls = 0; + } + + } else if (field->value_length == 5) { + if (nxt_memcasecmp(field->value, "https", 5) == 0) { + r->tls = 1; + } + + } else if (field->value_length == 2) { + if (nxt_memcasecmp(field->value, "on", 2) == 0) { + r->tls = 1; + } + } +} + + static const nxt_http_request_state_t nxt_http_request_body_state nxt_aligned(64) = { @@ -718,6 +793,7 @@ nxt_http_request_error_handler(nxt_task_t *task, void *obj, void *data) void nxt_http_request_close_handler(nxt_task_t *task, void *obj, void *data) { + nxt_var_t *log_format; nxt_http_proto_t proto; nxt_http_request_t *r; nxt_http_protocol_t protocol; @@ -727,20 +803,22 @@ nxt_http_request_close_handler(nxt_task_t *task, void *obj, void *data) r = obj; proto.any = data; - nxt_debug(task, "http request close handler"); - conf = r->conf; if (!r->logged) { r->logged = 1; access_log = conf->socket_conf->router_conf->access_log; + log_format = conf->socket_conf->router_conf->log_format; if (access_log != NULL) { - access_log->handler(task, r, access_log); + access_log->handler(task, r, access_log, log_format); + return; } } + nxt_debug(task, "http request close handler"); + r->proto.any = NULL; if (r->body != NULL && nxt_buf_is_file(r->body) @@ -876,7 +954,7 @@ nxt_http_arguments_parse(nxt_http_request_t *r) static nxt_http_name_value_t * nxt_http_argument(nxt_array_t *array, u_char *name, size_t name_length, - uint32_t hash, u_char *start, u_char *end) + uint32_t hash, u_char *start, const u_char *end) { size_t length; nxt_http_name_value_t *nv; @@ -945,7 +1023,7 @@ nxt_http_cookies_parse(nxt_http_request_t *r) static nxt_int_t -nxt_http_cookie_parse(nxt_array_t *cookies, u_char *start, u_char *end) +nxt_http_cookie_parse(nxt_array_t *cookies, u_char *start, const u_char *end) { size_t name_length; u_char c, *p, *name; @@ -994,7 +1072,7 @@ nxt_http_cookie_parse(nxt_array_t *cookies, u_char *start, u_char *end) static nxt_http_name_value_t * nxt_http_cookie(nxt_array_t *array, u_char *name, size_t name_length, - u_char *start, u_char *end) + u_char *start, const u_char *end) { u_char c, *p; uint32_t hash; @@ -1024,3 +1102,140 @@ nxt_http_cookie(nxt_array_t *array, u_char *name, size_t name_length, return nv; } + + +int64_t +nxt_http_field_hash(nxt_mp_t *mp, nxt_str_t *name, nxt_bool_t case_sensitive, + uint8_t encoding) +{ + u_char c, *p, *src, *start, *end, plus; + uint8_t d0, d1; + uint32_t hash; + nxt_str_t str; + nxt_uint_t i; + + str.length = name->length; + + str.start = nxt_mp_nget(mp, str.length); + if (nxt_slow_path(str.start == NULL)) { + return -1; + } + + p = str.start; + + hash = NXT_HTTP_FIELD_HASH_INIT; + + if (encoding == NXT_HTTP_URI_ENCODING_NONE) { + for (i = 0; i < name->length; i++) { + c = name->start[i]; + *p++ = c; + + c = case_sensitive ? c : nxt_lowcase(c); + hash = nxt_http_field_hash_char(hash, c); + } + + goto end; + } + + plus = (encoding == NXT_HTTP_URI_ENCODING_PLUS) ? ' ' : '+'; + + start = name->start; + end = start + name->length; + + for (src = start; src < end; src++) { + c = *src; + + switch (c) { + case '%': + if (nxt_slow_path(end - src <= 2)) { + return -1; + } + + d0 = nxt_hex2int[src[1]]; + d1 = nxt_hex2int[src[2]]; + src += 2; + + if (nxt_slow_path((d0 | d1) >= 16)) { + return -1; + } + + c = (d0 << 4) + d1; + *p++ = c; + break; + + case '+': + c = plus; + *p++ = c; + break; + + default: + *p++ = c; + break; + } + + c = case_sensitive ? c : nxt_lowcase(c); + hash = nxt_http_field_hash_char(hash, c); + } + + str.length = p - str.start; + +end: + + *name = str; + + return nxt_http_field_hash_end(hash) & 0xFFFF; +} + + +int64_t +nxt_http_argument_hash(nxt_mp_t *mp, nxt_str_t *name) +{ + return nxt_http_field_hash(mp, name, 1, NXT_HTTP_URI_ENCODING_PLUS); +} + + +int64_t +nxt_http_header_hash(nxt_mp_t *mp, nxt_str_t *name) +{ + u_char c, *p; + uint32_t i, hash; + nxt_str_t str; + + str.length = name->length; + + str.start = nxt_mp_nget(mp, str.length); + if (nxt_slow_path(str.start == NULL)) { + return -1; + } + + p = str.start; + hash = NXT_HTTP_FIELD_HASH_INIT; + + for (i = 0; i < name->length; i++) { + c = name->start[i]; + + if (c >= 'A' && c <= 'Z') { + *p = c | 0x20; + + } else if (c == '_') { + *p = '-'; + + } else { + *p = c; + } + + hash = nxt_http_field_hash_char(hash, *p); + p++; + } + + *name = str; + + return nxt_http_field_hash_end(hash) & 0xFFFF; +} + + +int64_t +nxt_http_cookie_hash(nxt_mp_t *mp, nxt_str_t *name) +{ + return nxt_http_field_hash(mp, name, 1, NXT_HTTP_URI_ENCODING_NONE); +} diff --git a/src/nxt_http_return.c b/src/nxt_http_return.c index 82c91568..9f3c4fc5 100644 --- a/src/nxt_http_return.c +++ b/src/nxt_http_return.c @@ -32,12 +32,15 @@ static const nxt_http_request_state_t nxt_http_return_send_state; nxt_int_t -nxt_http_return_init(nxt_mp_t *mp, nxt_http_action_t *action, +nxt_http_return_init(nxt_router_conf_t *rtcf, nxt_http_action_t *action, nxt_http_action_conf_t *acf) { + nxt_mp_t *mp; nxt_str_t str; nxt_http_return_conf_t *conf; + mp = rtcf->mem_pool; + conf = nxt_mp_zget(mp, sizeof(nxt_http_return_conf_t)); if (nxt_slow_path(conf == NULL)) { return NXT_ERROR; @@ -54,7 +57,7 @@ nxt_http_return_init(nxt_mp_t *mp, nxt_http_action_t *action, nxt_conf_get_string(acf->location, &str); - conf->location = nxt_var_compile(&str, mp, 0); + conf->location = nxt_var_compile(&str, mp, rtcf->var_fields, 0); if (nxt_slow_path(conf->location == NULL)) { return NXT_ERROR; } diff --git a/src/nxt_http_route.c b/src/nxt_http_route.c index 9200dc52..cdc9077f 100644 --- a/src/nxt_http_route.c +++ b/src/nxt_http_route.c @@ -40,13 +40,6 @@ typedef enum { } nxt_http_route_pattern_case_t; -typedef enum { - NXT_HTTP_ROUTE_ENCODING_NONE = 0, - NXT_HTTP_ROUTE_ENCODING_URI, - NXT_HTTP_ROUTE_ENCODING_URI_PLUS -} nxt_http_route_encoding_t; - - typedef struct { nxt_conf_value_t *host; nxt_conf_value_t *uri; @@ -169,29 +162,29 @@ 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_http_route_object_t object, - nxt_bool_t case_sensitive, nxt_http_route_encoding_t encoding); + nxt_bool_t case_sensitive, nxt_http_uri_encoding_t encoding); 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_http_route_object_t object, - nxt_bool_t case_sensitive, nxt_http_route_encoding_t encoding); + nxt_bool_t case_sensitive, nxt_http_uri_encoding_t encoding); 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, nxt_http_route_encoding_t encoding); + nxt_bool_t case_sensitive, nxt_http_uri_encoding_t encoding); 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, - nxt_http_route_encoding_t encoding); + nxt_http_uri_encoding_t encoding); static int nxt_http_pattern_compare(const void *one, const void *two); static int nxt_http_addr_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, - nxt_http_route_encoding_t encoding); + nxt_http_uri_encoding_t encoding); static nxt_int_t nxt_http_route_decode_str(nxt_str_t *str, - nxt_http_route_encoding_t encoding); + nxt_http_uri_encoding_t encoding); static nxt_int_t nxt_http_route_pattern_slice(nxt_array_t *slices, nxt_str_t *test, nxt_http_route_pattern_type_t type, - nxt_http_route_encoding_t encoding, + nxt_http_uri_encoding_t encoding, nxt_http_route_pattern_case_t pattern_case); static nxt_int_t nxt_http_route_resolve(nxt_task_t *task, @@ -457,7 +450,7 @@ nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, if (mtcf.scheme != NULL) { rule = nxt_http_route_rule_create(task, mp, mtcf.scheme, 1, NXT_HTTP_ROUTE_PATTERN_NOCASE, - NXT_HTTP_ROUTE_ENCODING_NONE); + NXT_HTTP_URI_ENCODING_NONE); if (rule == NULL) { return NULL; } @@ -470,7 +463,7 @@ nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, if (mtcf.host != NULL) { rule = nxt_http_route_rule_create(task, mp, mtcf.host, 1, NXT_HTTP_ROUTE_PATTERN_LOWCASE, - NXT_HTTP_ROUTE_ENCODING_NONE); + NXT_HTTP_URI_ENCODING_NONE); if (rule == NULL) { return NULL; } @@ -484,7 +477,7 @@ nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, if (mtcf.uri != NULL) { rule = nxt_http_route_rule_create(task, mp, mtcf.uri, 1, NXT_HTTP_ROUTE_PATTERN_NOCASE, - NXT_HTTP_ROUTE_ENCODING_URI); + NXT_HTTP_URI_ENCODING); if (rule == NULL) { return NULL; } @@ -498,7 +491,7 @@ nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, if (mtcf.method != NULL) { rule = nxt_http_route_rule_create(task, mp, mtcf.method, 1, NXT_HTTP_ROUTE_PATTERN_UPCASE, - NXT_HTTP_ROUTE_ENCODING_NONE); + NXT_HTTP_URI_ENCODING_NONE); if (rule == NULL) { return NULL; } @@ -512,7 +505,7 @@ 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, NXT_HTTP_ROUTE_HEADER, 0, - NXT_HTTP_ROUTE_ENCODING_NONE); + NXT_HTTP_URI_ENCODING_NONE); if (table == NULL) { return NULL; } @@ -524,7 +517,7 @@ nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, if (mtcf.arguments != NULL) { table = nxt_http_route_table_create(task, mp, mtcf.arguments, NXT_HTTP_ROUTE_ARGUMENT, 1, - NXT_HTTP_ROUTE_ENCODING_URI_PLUS); + NXT_HTTP_URI_ENCODING_PLUS); if (table == NULL) { return NULL; } @@ -536,7 +529,7 @@ nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, if (mtcf.cookies != NULL) { table = nxt_http_route_table_create(task, mp, mtcf.cookies, NXT_HTTP_ROUTE_COOKIE, 1, - NXT_HTTP_ROUTE_ENCODING_NONE); + NXT_HTTP_URI_ENCODING_NONE); if (table == NULL) { return NULL; } @@ -548,7 +541,7 @@ nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, if (mtcf.query != NULL) { rule = nxt_http_route_rule_create(task, mp, mtcf.query, 1, NXT_HTTP_ROUTE_PATTERN_NOCASE, - NXT_HTTP_ROUTE_ENCODING_URI_PLUS); + NXT_HTTP_URI_ENCODING_PLUS); if (rule == NULL) { return NULL; } @@ -650,6 +643,7 @@ nxt_http_action_init(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, nxt_mp_t *mp; nxt_int_t ret; nxt_str_t pass; + nxt_router_conf_t *rtcf; nxt_http_action_conf_t acf; nxt_memzero(&acf, sizeof(acf)); @@ -662,10 +656,11 @@ nxt_http_action_init(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, nxt_memzero(action, sizeof(nxt_http_action_t)); - mp = tmcf->router_conf->mem_pool; + rtcf = tmcf->router_conf; + mp = rtcf->mem_pool; if (acf.ret != NULL) { - return nxt_http_return_init(mp, action, &acf); + return nxt_http_return_init(rtcf, action, &acf); } if (acf.share != NULL) { @@ -678,7 +673,7 @@ nxt_http_action_init(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, nxt_conf_get_string(acf.pass, &pass); - action->u.var = nxt_var_compile(&pass, mp, 0); + action->u.var = nxt_var_compile(&pass, mp, rtcf->var_fields, 0); if (nxt_slow_path(action->u.var == NULL)) { return NXT_ERROR; } @@ -690,7 +685,7 @@ nxt_http_action_init(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_http_route_object_t object, - nxt_bool_t case_sensitive, nxt_http_route_encoding_t encoding) + nxt_bool_t case_sensitive, nxt_http_uri_encoding_t encoding) { size_t size; uint32_t i, n; @@ -729,7 +724,7 @@ 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_http_route_object_t object, - nxt_bool_t case_sensitive, nxt_http_route_encoding_t encoding) + nxt_bool_t case_sensitive, nxt_http_uri_encoding_t encoding) { size_t size; uint32_t i, n, next; @@ -777,12 +772,9 @@ nxt_http_route_ruleset_create(nxt_task_t *task, nxt_mp_t *mp, 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, - nxt_http_route_encoding_t encoding) + nxt_http_uri_encoding_t encoding) { - u_char c, *p, *src, *start, *end, plus; - uint8_t d0, d1; - uint32_t hash; - nxt_uint_t i; + int64_t hash; nxt_http_route_rule_t *rule; rule = nxt_http_route_rule_create(task, mp, rule_cv, case_sensitive, @@ -792,73 +784,14 @@ nxt_http_route_rule_name_create(nxt_task_t *task, nxt_mp_t *mp, return NULL; } - rule->u.name.length = name->length; - - p = nxt_mp_nget(mp, name->length); - if (nxt_slow_path(p == NULL)) { + hash = nxt_http_field_hash(mp, name, case_sensitive, encoding); + if (nxt_slow_path(hash == -1)) { return NULL; } - hash = NXT_HTTP_FIELD_HASH_INIT; - rule->u.name.start = p; - - if (encoding == NXT_HTTP_ROUTE_ENCODING_NONE) { - for (i = 0; i < name->length; i++) { - c = name->start[i]; - *p++ = c; - - c = case_sensitive ? c : nxt_lowcase(c); - hash = nxt_http_field_hash_char(hash, c); - } - - goto end; - } - - plus = (encoding == NXT_HTTP_ROUTE_ENCODING_URI_PLUS) ? ' ' : '+'; - - start = name->start; - end = start + name->length; - - for (src = start; src < end; src++) { - c = *src; - - switch (c) { - case '%': - if (nxt_slow_path(end - src <= 2)) { - return NULL; - } - - d0 = nxt_hex2int[src[1]]; - d1 = nxt_hex2int[src[2]]; - src += 2; - - if (nxt_slow_path((d0 | d1) >= 16)) { - return NULL; - } - - c = (d0 << 4) + d1; - *p++ = c; - break; - - case '+': - c = plus; - *p++ = c; - break; - - default: - *p++ = c; - break; - } - - c = case_sensitive ? c : nxt_lowcase(c); - hash = nxt_http_field_hash_char(hash, c); - } - - rule->u.name.length = p - rule->u.name.start; - -end: - - rule->u.name.hash = nxt_http_field_hash_end(hash) & 0xFFFF; + rule->u.name.hash = hash; + rule->u.name.start = name->start; + rule->u.name.length = name->length; return rule; } @@ -868,7 +801,7 @@ 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, - nxt_http_route_encoding_t encoding) + nxt_http_uri_encoding_t encoding) { size_t size; uint32_t i, n; @@ -953,7 +886,7 @@ nxt_http_route_types_rule_create(nxt_task_t *task, nxt_mp_t *mp, { return nxt_http_route_rule_create(task, mp, types, 0, NXT_HTTP_ROUTE_PATTERN_LOWCASE, - NXT_HTTP_ROUTE_ENCODING_NONE); + NXT_HTTP_URI_ENCODING_NONE); } @@ -992,7 +925,7 @@ 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, - nxt_http_route_encoding_t encoding) + nxt_http_uri_encoding_t encoding) { u_char c, *p, *end; nxt_str_t test, tmp; @@ -1188,15 +1121,15 @@ nxt_http_route_pattern_create(nxt_task_t *task, nxt_mp_t *mp, static nxt_int_t -nxt_http_route_decode_str(nxt_str_t *str, nxt_http_route_encoding_t encoding) +nxt_http_route_decode_str(nxt_str_t *str, nxt_http_uri_encoding_t encoding) { u_char *start, *end; switch (encoding) { - case NXT_HTTP_ROUTE_ENCODING_NONE: + case NXT_HTTP_URI_ENCODING_NONE: break; - case NXT_HTTP_ROUTE_ENCODING_URI: + case NXT_HTTP_URI_ENCODING: start = str->start; end = nxt_decode_uri(start, start, str->length); @@ -1207,7 +1140,7 @@ nxt_http_route_decode_str(nxt_str_t *str, nxt_http_route_encoding_t encoding) str->length = end - start; break; - case NXT_HTTP_ROUTE_ENCODING_URI_PLUS: + case NXT_HTTP_URI_ENCODING_PLUS: start = str->start; end = nxt_decode_uri_plus(start, start, str->length); @@ -1228,9 +1161,8 @@ nxt_http_route_decode_str(nxt_str_t *str, nxt_http_route_encoding_t encoding) static nxt_int_t nxt_http_route_pattern_slice(nxt_array_t *slices, - nxt_str_t *test, - nxt_http_route_pattern_type_t type, - nxt_http_route_encoding_t encoding, + nxt_str_t *test, nxt_http_route_pattern_type_t type, + nxt_http_uri_encoding_t encoding, nxt_http_route_pattern_case_t pattern_case) { u_char *start; @@ -1554,16 +1486,18 @@ nxt_http_action_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, { nxt_mp_t *mp; nxt_int_t ret; + nxt_router_conf_t *rtcf; nxt_http_action_t *action; - mp = tmcf->router_conf->mem_pool; + rtcf = tmcf->router_conf; + mp = rtcf->mem_pool; action = nxt_mp_alloc(mp, sizeof(nxt_http_action_t)); if (nxt_slow_path(action == NULL)) { return NULL; } - action->u.var = nxt_var_compile(pass, mp, 0); + action->u.var = nxt_var_compile(pass, mp, rtcf->var_fields, 0); if (nxt_slow_path(action->u.var == NULL)) { return NULL; } @@ -1884,6 +1818,13 @@ nxt_http_route_addr_pattern_match(nxt_http_route_addr_pattern_t *p, break; #endif +#if (NXT_HAVE_UNIX_DOMAIN) + case AF_UNIX: + + match = (base->addr_family == AF_UNIX); + break; +#endif + default: match = 0; break; @@ -2019,14 +1960,13 @@ nxt_http_route_test_argument(nxt_http_request_t *r, static nxt_int_t nxt_http_route_scheme(nxt_http_request_t *r, nxt_http_route_rule_t *rule) { - nxt_bool_t tls, https; + nxt_bool_t https; nxt_http_route_pattern_slice_t *pattern_slice; pattern_slice = rule->pattern[0].u.pattern_slices->elts; https = (pattern_slice->length == nxt_length("https")); - tls = (r->tls != NULL); - return (tls == https); + return (r->tls == https); } diff --git a/src/nxt_http_route_addr.c b/src/nxt_http_route_addr.c index 2907a902..34455af4 100644 --- a/src/nxt_http_route_addr.c +++ b/src/nxt_http_route_addr.c @@ -41,6 +41,16 @@ nxt_http_route_addr_pattern_parse(nxt_mp_t *mp, base->negative = 0; } + if (nxt_str_eq(&addr, "unix", 4)) { +#if (NXT_HAVE_UNIX_DOMAIN) + base->addr_family = AF_UNIX; + + return NXT_OK; +#else + return NXT_ADDR_PATTERN_NO_UNIX_ERROR; +#endif + } + if (nxt_slow_path(addr.length < 2)) { return NXT_ADDR_PATTERN_LENGTH_ERROR; } @@ -233,7 +243,7 @@ nxt_http_route_addr_pattern_parse(nxt_mp_t *mp, } addr.length = delim - addr.start; - inet->end = htonl(0xFFFFFFFF & (0xFFFFFFFF << (32 - cidr_prefix))); + inet->end = htonl(0xFFFFFFFF & (0xFFFFFFFFULL << (32 - cidr_prefix))); inet->start = nxt_inet_addr(addr.start, addr.length) & inet->end; if (nxt_slow_path(inet->start == INADDR_NONE)) { diff --git a/src/nxt_http_route_addr.h b/src/nxt_http_route_addr.h index 3b1e1da3..2deda6f8 100644 --- a/src/nxt_http_route_addr.h +++ b/src/nxt_http_route_addr.h @@ -26,6 +26,7 @@ enum { NXT_ADDR_PATTERN_RANGE_OVERLAP_ERROR, NXT_ADDR_PATTERN_CIDR_ERROR, NXT_ADDR_PATTERN_NO_IPv6_ERROR, + NXT_ADDR_PATTERN_NO_UNIX_ERROR, }; diff --git a/src/nxt_http_static.c b/src/nxt_http_static.c index 61dd0cb3..0507e038 100644 --- a/src/nxt_http_static.c +++ b/src/nxt_http_static.c @@ -79,9 +79,11 @@ nxt_http_static_init(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, nxt_str_t str, *ret; nxt_var_t *var; nxt_conf_value_t *cv; + nxt_router_conf_t *rtcf; nxt_http_static_conf_t *conf; - mp = tmcf->router_conf->mem_pool; + rtcf = tmcf->router_conf; + mp = rtcf->mem_pool; conf = nxt_mp_zget(mp, sizeof(nxt_http_static_conf_t)); if (nxt_slow_path(conf == NULL)) { @@ -102,7 +104,7 @@ nxt_http_static_init(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, cv = nxt_conf_get_array_element_or_itself(acf->share, i); nxt_conf_get_string(cv, &str); - var = nxt_var_compile(&str, mp, 1); + var = nxt_var_compile(&str, mp, rtcf->var_fields, NXT_VAR_STRZ); if (nxt_slow_path(var == NULL)) { return NXT_ERROR; } @@ -128,7 +130,8 @@ nxt_http_static_init(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, nxt_str_t chr, shr; nxt_bool_t is_const; - conf->chroot = nxt_var_compile(&acf->chroot, mp, 1); + conf->chroot = nxt_var_compile(&acf->chroot, mp, rtcf->var_fields, + NXT_VAR_STRZ); if (nxt_slow_path(conf->chroot == NULL)) { return NXT_ERROR; } @@ -756,9 +759,7 @@ nxt_http_static_extract_extension(nxt_str_t *path, nxt_str_t *exten) end = path->start + path->length; p = end; - for ( ;; ) { - /* There's always '/' in the beginning of the request path. */ - + while (p > path->start) { p--; ch = *p; @@ -767,11 +768,14 @@ nxt_http_static_extract_extension(nxt_str_t *path, nxt_str_t *exten) p++; /* Fall through. */ case '.': - exten->length = end - p; - exten->start = p; - return; + goto extension; } } + +extension: + + exten->length = end - p; + exten->start = p; } @@ -1023,7 +1027,7 @@ typedef struct { nxt_int_t nxt_http_static_mtypes_hash_add(nxt_mp_t *mp, nxt_lvlhsh_t *hash, - nxt_str_t *exten, nxt_str_t *type) + const nxt_str_t *exten, nxt_str_t *type) { nxt_lvlhsh_query_t lhq; nxt_http_static_mtype_t *mtype; @@ -1048,7 +1052,7 @@ nxt_http_static_mtypes_hash_add(nxt_mp_t *mp, nxt_lvlhsh_t *hash, nxt_str_t * -nxt_http_static_mtype_get(nxt_lvlhsh_t *hash, nxt_str_t *exten) +nxt_http_static_mtype_get(nxt_lvlhsh_t *hash, const nxt_str_t *exten) { nxt_lvlhsh_query_t lhq; nxt_http_static_mtype_t *mtype; diff --git a/src/nxt_http_variables.c b/src/nxt_http_variables.c index b765e177..5a632b24 100644 --- a/src/nxt_http_variables.c +++ b/src/nxt_http_variables.c @@ -7,32 +7,90 @@ #include <nxt_http.h> -static nxt_int_t nxt_http_var_method(nxt_task_t *task, nxt_var_query_t *query, - nxt_str_t *str, void *ctx); -static nxt_int_t nxt_http_var_request_uri(nxt_task_t *task, - nxt_var_query_t *query, nxt_str_t *str, void *ctx); -static nxt_int_t nxt_http_var_uri(nxt_task_t *task, nxt_var_query_t *query, - nxt_str_t *str, void *ctx); -static nxt_int_t nxt_http_var_host(nxt_task_t *task, nxt_var_query_t *query, - nxt_str_t *str, void *ctx); +static nxt_int_t nxt_http_var_dollar(nxt_task_t *task, nxt_str_t *str, + void *ctx, uint16_t field); +static nxt_int_t nxt_http_var_method(nxt_task_t *task, nxt_str_t *str, + void *ctx, uint16_t field); +static nxt_int_t nxt_http_var_request_uri(nxt_task_t *task, nxt_str_t *str, + void *ctx, uint16_t field); +static nxt_int_t nxt_http_var_uri(nxt_task_t *task, nxt_str_t *str, void *ctx, + uint16_t field); +static nxt_int_t nxt_http_var_host(nxt_task_t *task, nxt_str_t *str, void *ctx, + uint16_t field); +static nxt_int_t nxt_http_var_remote_addr(nxt_task_t *task, nxt_str_t *str, + void *ctx, uint16_t field); +static nxt_int_t nxt_http_var_time_local(nxt_task_t *task, nxt_str_t *str, + void *ctx, uint16_t field); +static u_char *nxt_http_log_date(u_char *buf, nxt_realtime_t *now, + struct tm *tm, size_t size, const char *format); +static nxt_int_t nxt_http_var_request_line(nxt_task_t *task, nxt_str_t *str, + void *ctx, uint16_t field); +static nxt_int_t nxt_http_var_status(nxt_task_t *task, nxt_str_t *str, + void *ctx, uint16_t field); +static nxt_int_t nxt_http_var_body_bytes_sent(nxt_task_t *task, nxt_str_t *str, + void *ctx, uint16_t field); +static nxt_int_t nxt_http_var_referer(nxt_task_t *task, nxt_str_t *str, + void *ctx, uint16_t field); +static nxt_int_t nxt_http_var_user_agent(nxt_task_t *task, nxt_str_t *str, + void *ctx, uint16_t field); +static nxt_int_t nxt_http_var_arg(nxt_task_t *task, nxt_str_t *str, void *ctx, + uint16_t field); +static nxt_int_t nxt_http_var_header(nxt_task_t *task, nxt_str_t *str, + void *ctx, uint16_t field); +static nxt_int_t nxt_http_var_cookie(nxt_task_t *task, nxt_str_t *str, + void *ctx, uint16_t field); static nxt_var_decl_t nxt_http_vars[] = { - { nxt_string("method"), - &nxt_http_var_method, - 0 }, - - { nxt_string("request_uri"), - &nxt_http_var_request_uri, - 0 }, - - { nxt_string("uri"), - &nxt_http_var_uri, - 0 }, - - { nxt_string("host"), - &nxt_http_var_host, - 0 }, + { + .name = nxt_string("dollar"), + .handler = nxt_http_var_dollar, + }, { + .name = nxt_string("method"), + .handler = nxt_http_var_method, + }, { + .name = nxt_string("request_uri"), + .handler = nxt_http_var_request_uri, + }, { + .name = nxt_string("uri"), + .handler = nxt_http_var_uri, + }, { + .name = nxt_string("host"), + .handler = nxt_http_var_host, + }, { + .name = nxt_string("remote_addr"), + .handler = nxt_http_var_remote_addr, + }, { + .name = nxt_string("time_local"), + .handler = nxt_http_var_time_local, + }, { + .name = nxt_string("request_line"), + .handler = nxt_http_var_request_line, + }, { + .name = nxt_string("status"), + .handler = nxt_http_var_status, + }, { + .name = nxt_string("body_bytes_sent"), + .handler = nxt_http_var_body_bytes_sent, + }, { + .name = nxt_string("header_referer"), + .handler = nxt_http_var_referer, + }, { + .name = nxt_string("header_user_agent"), + .handler = nxt_http_var_user_agent, + }, { + .name = nxt_string("arg"), + .handler = nxt_http_var_arg, + .field_hash = nxt_http_argument_hash, + }, { + .name = nxt_string("header"), + .handler = nxt_http_var_header, + .field_hash = nxt_http_header_hash, + }, { + .name = nxt_string("cookie"), + .handler = nxt_http_var_cookie, + .field_hash = nxt_http_cookie_hash, + }, }; @@ -44,8 +102,16 @@ nxt_http_register_variables(void) static nxt_int_t -nxt_http_var_method(nxt_task_t *task, nxt_var_query_t *query, nxt_str_t *str, - void *ctx) +nxt_http_var_dollar(nxt_task_t *task, nxt_str_t *str, void *ctx, uint16_t field) +{ + nxt_str_set(str, "$"); + + return NXT_OK; +} + + +static nxt_int_t +nxt_http_var_method(nxt_task_t *task, nxt_str_t *str, void *ctx, uint16_t field) { nxt_http_request_t *r; @@ -58,8 +124,8 @@ nxt_http_var_method(nxt_task_t *task, nxt_var_query_t *query, nxt_str_t *str, static nxt_int_t -nxt_http_var_request_uri(nxt_task_t *task, nxt_var_query_t *query, - nxt_str_t *str, void *ctx) +nxt_http_var_request_uri(nxt_task_t *task, nxt_str_t *str, void *ctx, + uint16_t field) { nxt_http_request_t *r; @@ -72,8 +138,7 @@ nxt_http_var_request_uri(nxt_task_t *task, nxt_var_query_t *query, static nxt_int_t -nxt_http_var_uri(nxt_task_t *task, nxt_var_query_t *query, nxt_str_t *str, - void *ctx) +nxt_http_var_uri(nxt_task_t *task, nxt_str_t *str, void *ctx, uint16_t field) { nxt_http_request_t *r; @@ -86,8 +151,7 @@ nxt_http_var_uri(nxt_task_t *task, nxt_var_query_t *query, nxt_str_t *str, static nxt_int_t -nxt_http_var_host(nxt_task_t *task, nxt_var_query_t *query, nxt_str_t *str, - void *ctx) +nxt_http_var_host(nxt_task_t *task, nxt_str_t *str, void *ctx, uint16_t field) { nxt_http_request_t *r; @@ -97,3 +161,323 @@ nxt_http_var_host(nxt_task_t *task, nxt_var_query_t *query, nxt_str_t *str, return NXT_OK; } + + +static nxt_int_t +nxt_http_var_remote_addr(nxt_task_t *task, nxt_str_t *str, void *ctx, + uint16_t field) +{ + nxt_http_request_t *r; + + r = ctx; + + str->length = r->remote->address_length; + str->start = nxt_sockaddr_address(r->remote); + + return NXT_OK; +} + + +static nxt_int_t +nxt_http_var_time_local(nxt_task_t *task, nxt_str_t *str, void *ctx, + uint16_t field) +{ + nxt_http_request_t *r; + + static nxt_time_string_t date_cache = { + (nxt_atomic_uint_t) -1, + nxt_http_log_date, + "%02d/%s/%4d:%02d:%02d:%02d %c%02d%02d", + nxt_length("31/Dec/1986:19:40:00 +0300"), + NXT_THREAD_TIME_LOCAL, + NXT_THREAD_TIME_SEC, + }; + + r = ctx; + + str->length = date_cache.size; + + str->start = nxt_mp_nget(r->mem_pool, str->length); + if (nxt_slow_path(str->start == NULL)) { + return NXT_ERROR; + } + + str->length = nxt_thread_time_string(task->thread, &date_cache, str->start) + - str->start; + + return NXT_OK; +} + + +static u_char * +nxt_http_log_date(u_char *buf, nxt_realtime_t *now, struct tm *tm, + size_t size, const char *format) +{ + u_char sign; + time_t gmtoff; + + static const char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + + gmtoff = nxt_timezone(tm) / 60; + + if (gmtoff < 0) { + gmtoff = -gmtoff; + sign = '-'; + + } else { + sign = '+'; + } + + return nxt_sprintf(buf, buf + size, format, + tm->tm_mday, month[tm->tm_mon], tm->tm_year + 1900, + tm->tm_hour, tm->tm_min, tm->tm_sec, + sign, gmtoff / 60, gmtoff % 60); +} + + +static nxt_int_t +nxt_http_var_request_line(nxt_task_t *task, nxt_str_t *str, void *ctx, + uint16_t field) +{ + size_t length; + u_char *p, *start; + nxt_http_request_t *r; + + r = ctx; + + length = r->method->length + 1 + r->target.length + 1 + r->version.length; + + start = nxt_mp_nget(r->mem_pool, length); + if (nxt_slow_path(start == NULL)) { + return NXT_ERROR; + } + + p = start; + + if (r->method->length != 0) { + p = nxt_cpymem(p, r->method->start, r->method->length); + + if (r->target.length != 0) { + *p++ = ' '; + p = nxt_cpymem(p, r->target.start, r->target.length); + + if (r->version.length != 0) { + *p++ = ' '; + p = nxt_cpymem(p, r->version.start, r->version.length); + } + } + + } else { + *p++ = '-'; + } + + str->start = start; + str->length = p - start; + + return NXT_OK; +} + + +static nxt_int_t +nxt_http_var_body_bytes_sent(nxt_task_t *task, nxt_str_t *str, void *ctx, + uint16_t field) +{ + nxt_off_t bytes; + nxt_http_request_t *r; + + r = ctx; + + str->start = nxt_mp_nget(r->mem_pool, NXT_OFF_T_LEN); + if (nxt_slow_path(str->start == NULL)) { + return NXT_ERROR; + } + + bytes = nxt_http_proto[r->protocol].body_bytes_sent(task, r->proto); + + str->length = nxt_sprintf(str->start, str->start + NXT_OFF_T_LEN, "%O", + bytes) - str->start; + + return NXT_OK; +} + + +static nxt_int_t +nxt_http_var_status(nxt_task_t *task, nxt_str_t *str, void *ctx, uint16_t field) +{ + nxt_http_request_t *r; + + r = ctx; + + str->start = nxt_mp_nget(r->mem_pool, 3); + if (nxt_slow_path(str->start == NULL)) { + return NXT_ERROR; + } + + str->length = nxt_sprintf(str->start, str->start + 3, "%03d", r->status) + - str->start; + + return NXT_OK; +} + + +static nxt_int_t +nxt_http_var_referer(nxt_task_t *task, nxt_str_t *str, void *ctx, + uint16_t field) +{ + nxt_http_request_t *r; + + r = ctx; + + if (r->referer != NULL) { + str->start = r->referer->value; + str->length = r->referer->value_length; + + } else { + nxt_str_null(str); + } + + return NXT_OK; +} + + +static nxt_int_t +nxt_http_var_user_agent(nxt_task_t *task, nxt_str_t *str, void *ctx, + uint16_t field) +{ + nxt_http_request_t *r; + + r = ctx; + + if (r->user_agent != NULL) { + str->start = r->user_agent->value; + str->length = r->user_agent->value_length; + + } else { + nxt_str_null(str); + } + + return NXT_OK; +} + + +static nxt_int_t +nxt_http_var_arg(nxt_task_t *task, nxt_str_t *str, void *ctx, uint16_t field) +{ + nxt_array_t *args; + nxt_var_field_t *vf; + nxt_router_conf_t *rtcf; + nxt_http_request_t *r; + nxt_http_name_value_t *nv, *start; + + r = ctx; + + rtcf = r->conf->socket_conf->router_conf; + + vf = nxt_var_field_get(rtcf->var_fields, field); + + args = nxt_http_arguments_parse(r); + if (nxt_slow_path(args == NULL)) { + return NXT_ERROR; + } + + start = args->elts; + nv = start + args->nelts - 1; + + while (nv >= start) { + + if (vf->hash == nv->hash + && vf->name.length == nv->name_length + && nxt_memcmp(vf->name.start, nv->name, nv->name_length) == 0) + { + str->start = nv->value; + str->length = nv->value_length; + + return NXT_OK; + } + + nv--; + } + + nxt_str_null(str); + + return NXT_OK; +} + + +static nxt_int_t +nxt_http_var_header(nxt_task_t *task, nxt_str_t *str, void *ctx, uint16_t field) +{ + nxt_var_field_t *vf; + nxt_http_field_t *f; + nxt_router_conf_t *rtcf; + nxt_http_request_t *r; + + r = ctx; + + rtcf = r->conf->socket_conf->router_conf; + + vf = nxt_var_field_get(rtcf->var_fields, field); + + nxt_list_each(f, r->fields) { + + if (vf->hash == f->hash + && vf->name.length == f->name_length + && nxt_strncasecmp(vf->name.start, f->name, f->name_length) == 0) + { + str->start = f->value; + str->length = f->value_length; + + return NXT_OK; + } + + } nxt_list_loop; + + nxt_str_null(str); + + return NXT_OK; +} + + +static nxt_int_t +nxt_http_var_cookie(nxt_task_t *task, nxt_str_t *str, void *ctx, uint16_t field) +{ + nxt_array_t *cookies; + nxt_var_field_t *vf; + nxt_router_conf_t *rtcf; + nxt_http_request_t *r; + nxt_http_name_value_t *nv, *end; + + r = ctx; + + rtcf = r->conf->socket_conf->router_conf; + + vf = nxt_var_field_get(rtcf->var_fields, field); + + cookies = nxt_http_cookies_parse(r); + if (nxt_slow_path(cookies == NULL)) { + return NXT_ERROR; + } + + nv = cookies->elts; + end = nv + cookies->nelts; + + while (nv < end) { + + if (vf->hash == nv->hash + && vf->name.length == nv->name_length + && nxt_memcmp(vf->name.start, nv->name, nv->name_length) == 0) + { + str->start = nv->value; + str->length = nv->value_length; + + return NXT_OK; + } + + nv++; + } + + nxt_str_null(str); + + return NXT_OK; +} diff --git a/src/nxt_isolation.c b/src/nxt_isolation.c index e3cb1f22..796da4c6 100644 --- a/src/nxt_isolation.c +++ b/src/nxt_isolation.c @@ -7,7 +7,7 @@ #include <nxt_process.h> #include <nxt_isolation.h> -#if (NXT_HAVE_PIVOT_ROOT) +#if (NXT_HAVE_MNTENT_H) #include <mntent.h> #endif @@ -45,7 +45,7 @@ static int nxt_cdecl nxt_isolation_mount_compare(const void *v1, const void *v2); static void nxt_isolation_unmount_all(nxt_task_t *task, nxt_process_t *process); -#if (NXT_HAVE_PIVOT_ROOT) && (NXT_HAVE_CLONE_NEWNS) +#if (NXT_HAVE_LINUX_PIVOT_ROOT) && (NXT_HAVE_CLONE_NEWNS) static nxt_int_t nxt_isolation_pivot_root(nxt_task_t *task, const char *rootfs); static nxt_int_t nxt_isolation_make_private_mount(nxt_task_t *task, const char *rootfs); @@ -752,7 +752,7 @@ undo: } -#if (NXT_HAVE_PIVOT_ROOT) && (NXT_HAVE_CLONE_NEWNS) +#if (NXT_HAVE_LINUX_PIVOT_ROOT) && (NXT_HAVE_CLONE_NEWNS) nxt_int_t nxt_isolation_change_root(nxt_task_t *task, nxt_process_t *process) @@ -1003,11 +1003,11 @@ fail: nxt_inline int nxt_pivot_root(const char *new_root, const char *old_root) { - return syscall(__NR_pivot_root, new_root, old_root); + return syscall(SYS_pivot_root, new_root, old_root); } -#else /* !(NXT_HAVE_PIVOT_ROOT) || !(NXT_HAVE_CLONE_NEWNS) */ +#else /* !(NXT_HAVE_LINUX_PIVOT_ROOT) || !(NXT_HAVE_CLONE_NEWNS) */ nxt_int_t diff --git a/src/nxt_isolation.h b/src/nxt_isolation.h index 88a5f9e1..b1bfc33c 100644 --- a/src/nxt_isolation.h +++ b/src/nxt_isolation.h @@ -2,8 +2,8 @@ * Copyright (C) NGINX, Inc. */ -#ifndef _NXT_ISOLATION_H_ -#define _NXT_ISOLATION_H_ +#ifndef _NXT_ISOLATION_H_INCLUDED_ +#define _NXT_ISOLATION_H_INCLUDED_ nxt_int_t nxt_isolation_main_prefork(nxt_task_t *task, nxt_process_t *process, @@ -15,4 +15,4 @@ nxt_int_t nxt_isolation_prepare_rootfs(nxt_task_t *task, nxt_int_t nxt_isolation_change_root(nxt_task_t *task, nxt_process_t *process); #endif -#endif /* _NXT_ISOLATION_H_ */ +#endif /* _NXT_ISOLATION_H_INCLUDED_ */ diff --git a/src/nxt_job_resolve.c b/src/nxt_job_resolve.c deleted file mode 100644 index 0f1fb9aa..00000000 --- a/src/nxt_job_resolve.c +++ /dev/null @@ -1,132 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#include <nxt_main.h> - - -void -nxt_job_resolve(nxt_job_resolve_t *jbr) -{ - int err; - u_char *host; - size_t length; - nxt_mp_t *mp; - nxt_uint_t n; - nxt_sockaddr_t *sa; - struct addrinfo hint, *res, *r; - nxt_work_handler_t handler; - - #define NXT_BUFSIZE 64 - u_char buf[NXT_BUFSIZE]; - - handler = jbr->error_handler; - res = NULL; - - length = jbr->name.length + 1; - - if (nxt_fast_path(length <= NXT_BUFSIZE)) { - host = buf; - - } else { - host = nxt_mp_alloc(jbr->job.mem_pool, length); - if (nxt_slow_path(host == NULL)) { - goto fail; - } - } - - nxt_cpystrn(host, jbr->name.start, length); - - nxt_memzero(&hint, sizeof(struct addrinfo)); - hint.ai_socktype = SOCK_STREAM; - - err = getaddrinfo((char *) host, NULL, &hint, &res); - - if (err != 0) { - nxt_thread_log_error(jbr->log_level, - "getaddrinfo(\"%s\") failed (%d: %s)", - host, err, gai_strerror(err)); - goto fail; - } - - n = 0; - for (r = res; r != NULL; r = r->ai_next) { - - switch (r->ai_addr->sa_family) { -#if (NXT_INET6) - case AF_INET6: -#endif - case AF_INET: - n++; - break; - - default: - break; - } - } - - jbr->count = n; - mp = jbr->job.mem_pool; - - jbr->sockaddrs = nxt_mp_alloc(mp, n * sizeof(nxt_sockaddr_t *)); - if (nxt_slow_path(jbr->sockaddrs == NULL)) { - goto fail; - } - - n = 0; - for (r = res; r != NULL; r = r->ai_next) { - - switch (r->ai_addr->sa_family) { -#if (NXT_INET6) - case AF_INET6: - length = NXT_INET6_ADDR_STR_LEN; - break; -#endif - case AF_INET: - length = NXT_INET_ADDR_STR_LEN; - break; - - default: - continue; - } - - sa = nxt_sockaddr_create(mp, r->ai_addr, r->ai_addrlen, length); - if (nxt_slow_path(sa == NULL)) { - goto fail; - } - - jbr->sockaddrs[n++] = sa; - - if (jbr->port != 0) { - - switch (sa->u.sockaddr.sa_family) { - case AF_INET: - sa->u.sockaddr_in.sin_port = jbr->port; - break; -#if (NXT_INET6) - case AF_INET6: - sa->u.sockaddr_in6.sin6_port = jbr->port; - break; -#endif - default: - break; - } - } - } - - handler = jbr->ready_handler; - -fail: - - if (nxt_fast_path(res != NULL)) { - freeaddrinfo(res); - } - - if (host != buf) { - nxt_mp_free(jbr->job.mem_pool, host); - } - - nxt_job_return(jbr->job.task, &jbr->job, handler); -} diff --git a/src/nxt_job_resolve.h b/src/nxt_job_resolve.h deleted file mode 100644 index fef55b99..00000000 --- a/src/nxt_job_resolve.h +++ /dev/null @@ -1,29 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - * Copyright (C) NGINX, Inc. - */ - -#ifndef _NXT_JOB_RESOLVE_H_INCLUDED_ -#define _NXT_JOB_RESOLVE_H_INCLUDED_ - - -typedef struct { - nxt_job_t job; - nxt_str_t name; - - uint32_t log_level; /* 4 bits */ - in_port_t port; - uint16_t count; - - nxt_sockaddr_t **sockaddrs; - - nxt_work_handler_t ready_handler; - nxt_work_handler_t error_handler; -} nxt_job_resolve_t; - - -void nxt_job_resolve(nxt_job_resolve_t *jbr); - - -#endif /* _NXT_JOB_RESOLVE_H_INCLUDED_ */ diff --git a/src/nxt_main.h b/src/nxt_main.h index 7f812568..dca4b6dc 100644 --- a/src/nxt_main.h +++ b/src/nxt_main.h @@ -146,7 +146,6 @@ typedef void (*nxt_event_conn_handler_t)(nxt_thread_t *thr, nxt_conn_t *c); #include <nxt_job_file.h> #include <nxt_buf_filter.h> -#include <nxt_job_resolve.h> #include <nxt_sockaddr.h> #include <nxt_cache.h> diff --git a/src/nxt_main_process.c b/src/nxt_main_process.c index 03761a10..39a8e112 100644 --- a/src/nxt_main_process.c +++ b/src/nxt_main_process.c @@ -1187,7 +1187,9 @@ nxt_main_listening_socket(nxt_sockaddr_t *sa, nxt_listening_socket_t *ls) #if (NXT_HAVE_UNIX_DOMAIN) - if (sa->u.sockaddr.sa_family == AF_UNIX) { + if (sa->u.sockaddr.sa_family == AF_UNIX + && sa->u.sockaddr_un.sun_path[0] != '\0') + { char *filename; mode_t access; diff --git a/src/nxt_mp.c b/src/nxt_mp.c index d0de2c0e..2bd8cdee 100644 --- a/src/nxt_mp.c +++ b/src/nxt_mp.c @@ -155,7 +155,7 @@ static void *nxt_mp_alloc_large(nxt_mp_t *mp, size_t alignment, size_t size, nxt_bool_t freeable); static intptr_t nxt_mp_rbtree_compare(nxt_rbtree_node_t *node1, nxt_rbtree_node_t *node2); -static nxt_mp_block_t *nxt_mp_find_block(nxt_rbtree_t *tree, u_char *p); +static nxt_mp_block_t *nxt_mp_find_block(nxt_rbtree_t *tree, const u_char *p); static const char *nxt_mp_chunk_free(nxt_mp_t *mp, nxt_mp_block_t *cluster, u_char *p); @@ -830,7 +830,7 @@ nxt_mp_free(nxt_mp_t *mp, void *p) static nxt_mp_block_t * -nxt_mp_find_block(nxt_rbtree_t *tree, u_char *p) +nxt_mp_find_block(nxt_rbtree_t *tree, const u_char *p) { nxt_mp_block_t *block; nxt_rbtree_node_t *node, *sentinel; diff --git a/src/nxt_nncq.h b/src/nxt_nncq.h index 20e7ecff..6c9ab326 100644 --- a/src/nxt_nncq.h +++ b/src/nxt_nncq.h @@ -85,7 +85,7 @@ nxt_nncq_empty(nxt_nncq_t const volatile *q) } -static void +static inline void nxt_nncq_init(nxt_nncq_t volatile *q) { q->head = NXT_NNCQ_SIZE; @@ -94,7 +94,7 @@ nxt_nncq_init(nxt_nncq_t volatile *q) } -static void +static inline void nxt_nncq_enqueue(nxt_nncq_t volatile *q, nxt_nncq_atomic_t val) { nxt_nncq_cycle_t e_cycle, t_cycle; @@ -128,7 +128,7 @@ nxt_nncq_enqueue(nxt_nncq_t volatile *q, nxt_nncq_atomic_t val) } -static nxt_nncq_atomic_t +static inline nxt_nncq_atomic_t nxt_nncq_dequeue(nxt_nncq_t volatile *q) { nxt_nncq_cycle_t e_cycle, h_cycle; diff --git a/src/nxt_nvbcq.h b/src/nxt_nvbcq.h index 2b019dcc..e164615b 100644 --- a/src/nxt_nvbcq.h +++ b/src/nxt_nvbcq.h @@ -64,7 +64,7 @@ nxt_nvbcq_empty(nxt_nvbcq_t const volatile *q) } -static void +static inline void nxt_nvbcq_init(nxt_nvbcq_t volatile *q) { nxt_nvbcq_atomic_t i; @@ -79,7 +79,7 @@ nxt_nvbcq_init(nxt_nvbcq_t volatile *q) } -static void +static inline void nxt_nvbcq_enqueue(nxt_nvbcq_t volatile *q, nxt_nvbcq_atomic_t val) { nxt_nvbcq_atomic_t t, h, i; @@ -110,7 +110,7 @@ nxt_nvbcq_enqueue(nxt_nvbcq_t volatile *q, nxt_nvbcq_atomic_t val) } -static nxt_nvbcq_atomic_t +static inline nxt_nvbcq_atomic_t nxt_nvbcq_dequeue(nxt_nvbcq_t volatile *q) { nxt_nvbcq_atomic_t h, t, i, e; diff --git a/src/nxt_port.h b/src/nxt_port.h index 3b66edfd..3a8da5ad 100644 --- a/src/nxt_port.h +++ b/src/nxt_port.h @@ -53,6 +53,9 @@ struct nxt_port_handlers_s { nxt_port_handler_t data; nxt_port_handler_t app_restart; + /* Status report. */ + nxt_port_handler_t status; + nxt_port_handler_t oosm; nxt_port_handler_t shm_ack; nxt_port_handler_t read_queue; @@ -104,6 +107,7 @@ typedef enum { _NXT_PORT_MSG_DATA = nxt_port_handler_idx(data), _NXT_PORT_MSG_APP_RESTART = nxt_port_handler_idx(app_restart), + _NXT_PORT_MSG_STATUS = nxt_port_handler_idx(status), _NXT_PORT_MSG_OOSM = nxt_port_handler_idx(oosm), _NXT_PORT_MSG_SHM_ACK = nxt_port_handler_idx(shm_ack), @@ -145,6 +149,7 @@ typedef enum { NXT_PORT_MSG_DATA = _NXT_PORT_MSG_DATA, NXT_PORT_MSG_DATA_LAST = nxt_msg_last(_NXT_PORT_MSG_DATA), NXT_PORT_MSG_APP_RESTART = nxt_msg_last(_NXT_PORT_MSG_APP_RESTART), + NXT_PORT_MSG_STATUS = nxt_msg_last(_NXT_PORT_MSG_STATUS), NXT_PORT_MSG_OOSM = nxt_msg_last(_NXT_PORT_MSG_OOSM), NXT_PORT_MSG_SHM_ACK = nxt_msg_last(_NXT_PORT_MSG_SHM_ACK), @@ -174,9 +179,6 @@ typedef struct { /* More Fragments followed. */ uint8_t mf; /* 1 bit */ - - /* Message delivery tracking enabled, next chunk is tracking msg. */ - uint8_t tracking; /* 1 bit */ } nxt_port_msg_t; @@ -186,7 +188,6 @@ typedef struct { size_t share; nxt_fd_t fd[2]; nxt_port_msg_t port_msg; - uint32_t tracking_msg[2]; uint8_t close_fd; /* 1 bit */ uint8_t allocated; /* 1 bit */ } nxt_port_send_msg_t; diff --git a/src/nxt_port_memory.c b/src/nxt_port_memory.c index e799f860..0a4a6c53 100644 --- a/src/nxt_port_memory.c +++ b/src/nxt_port_memory.c @@ -539,137 +539,6 @@ nxt_port_get_port_incoming_mmap(nxt_task_t *task, nxt_pid_t spid, uint32_t id) } -nxt_int_t -nxt_port_mmap_get_tracking(nxt_task_t *task, nxt_port_mmaps_t *mmaps, - nxt_port_mmap_tracking_t *tracking, uint32_t stream) -{ - nxt_chunk_id_t c; - nxt_port_mmap_header_t *hdr; - nxt_port_mmap_handler_t *mmap_handler; - - nxt_debug(task, "request tracking for stream #%uD", stream); - - mmap_handler = nxt_port_mmap_get(task, mmaps, &c, 1, 1); - if (nxt_slow_path(mmap_handler == NULL)) { - return NXT_ERROR; - } - - nxt_port_mmap_handler_use(mmap_handler, 1); - - hdr = mmap_handler->hdr; - - tracking->mmap_handler = mmap_handler; - tracking->tracking = hdr->tracking + c; - - *tracking->tracking = stream; - - nxt_debug(task, "outgoing tracking allocation: %PI->%PI,%d,%d", - hdr->src_pid, hdr->dst_pid, hdr->id, c); - - return NXT_OK; -} - - -nxt_bool_t -nxt_port_mmap_tracking_cancel(nxt_task_t *task, - nxt_port_mmap_tracking_t *tracking, uint32_t stream) -{ - nxt_bool_t res; - nxt_chunk_id_t c; - nxt_port_mmap_header_t *hdr; - nxt_port_mmap_handler_t *mmap_handler; - - mmap_handler = tracking->mmap_handler; - - if (nxt_slow_path(mmap_handler == NULL)) { - return 0; - } - - hdr = mmap_handler->hdr; - - res = nxt_atomic_cmp_set(tracking->tracking, stream, 0); - - nxt_debug(task, "%s tracking for stream #%uD", - (res ? "cancelled" : "failed to cancel"), stream); - - if (!res) { - c = tracking->tracking - hdr->tracking; - nxt_port_mmap_set_chunk_free(hdr->free_tracking_map, c); - } - - nxt_port_mmap_handler_use(mmap_handler, -1); - - return res; -} - - -nxt_int_t -nxt_port_mmap_tracking_write(uint32_t *buf, nxt_port_mmap_tracking_t *t) -{ - nxt_port_mmap_handler_t *mmap_handler; - - mmap_handler = t->mmap_handler; - -#if (NXT_DEBUG) - { - nxt_atomic_t *tracking; - - tracking = mmap_handler->hdr->tracking; - - nxt_assert(t->tracking >= tracking); - nxt_assert(t->tracking < tracking + PORT_MMAP_CHUNK_COUNT); - } -#endif - - buf[0] = mmap_handler->hdr->id; - buf[1] = t->tracking - mmap_handler->hdr->tracking; - - return NXT_OK; -} - -nxt_bool_t -nxt_port_mmap_tracking_read(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - nxt_buf_t *b; - nxt_bool_t res; - nxt_chunk_id_t c; - nxt_port_mmap_header_t *hdr; - nxt_port_mmap_handler_t *mmap_handler; - nxt_port_mmap_tracking_msg_t *tracking_msg; - - b = msg->buf; - - if (nxt_buf_used_size(b) < (int) sizeof(nxt_port_mmap_tracking_msg_t)) { - nxt_debug(task, "too small message %O", nxt_buf_used_size(b)); - return 0; - } - - tracking_msg = (nxt_port_mmap_tracking_msg_t *) b->mem.pos; - - b->mem.pos += sizeof(nxt_port_mmap_tracking_msg_t); - mmap_handler = nxt_port_get_port_incoming_mmap(task, msg->port_msg.pid, - tracking_msg->mmap_id); - - if (nxt_slow_path(mmap_handler == NULL)) { - return 0; - } - - hdr = mmap_handler->hdr; - - c = tracking_msg->tracking_id; - res = nxt_atomic_cmp_set(hdr->tracking + c, msg->port_msg.stream, 0); - - nxt_debug(task, "tracking for stream #%uD %s", msg->port_msg.stream, - (res ? "received" : "already cancelled")); - - if (!res) { - nxt_port_mmap_set_chunk_free(hdr->free_tracking_map, c); - } - - return res; -} - - nxt_buf_t * nxt_port_mmap_get_buf(nxt_task_t *task, nxt_port_mmaps_t *mmaps, size_t size) { diff --git a/src/nxt_port_memory.h b/src/nxt_port_memory.h index a2cdf5dd..f1e70964 100644 --- a/src/nxt_port_memory.h +++ b/src/nxt_port_memory.h @@ -15,27 +15,6 @@ typedef struct nxt_port_mmap_handler_s nxt_port_mmap_handler_t; void nxt_port_mmaps_destroy(nxt_port_mmaps_t *port_mmaps, nxt_bool_t free_elts); -typedef struct nxt_port_mmap_tracking_s nxt_port_mmap_tracking_t; - -struct nxt_port_mmap_tracking_s { - void *mmap_handler; - nxt_atomic_t *tracking; -}; - -nxt_int_t -nxt_port_mmap_get_tracking(nxt_task_t *task, nxt_port_mmaps_t *mmaps, - nxt_port_mmap_tracking_t *tracking, uint32_t stream); - -nxt_bool_t -nxt_port_mmap_tracking_cancel(nxt_task_t *task, - nxt_port_mmap_tracking_t *tracking, uint32_t stream); - -nxt_int_t -nxt_port_mmap_tracking_write(uint32_t *buf, nxt_port_mmap_tracking_t *t); - -nxt_bool_t -nxt_port_mmap_tracking_read(nxt_task_t *task, nxt_port_recv_msg_t *msg); - /* * Allocates nxt_but_t structure from task's thread engine mem_pool, assigns * this buf 'mem' pointers to first available shared mem bucket(s). 'size' diff --git a/src/nxt_port_memory_int.h b/src/nxt_port_memory_int.h index d2524ee4..21a05b10 100644 --- a/src/nxt_port_memory_int.h +++ b/src/nxt_port_memory_int.h @@ -84,13 +84,6 @@ struct nxt_port_mmap_msg_s { }; -typedef struct nxt_port_mmap_tracking_msg_s nxt_port_mmap_tracking_msg_t; - -struct nxt_port_mmap_tracking_msg_s { - uint32_t mmap_id; /* Mmap index in nxt_process_t.outgoing. */ - nxt_chunk_id_t tracking_id; /* Tracking index. */ -}; - nxt_inline nxt_bool_t nxt_port_mmap_get_free_chunk(nxt_free_map_t *m, nxt_chunk_id_t *c); @@ -107,7 +100,7 @@ nxt_inline void nxt_port_mmap_set_chunk_free(nxt_free_map_t *m, nxt_chunk_id_t c); nxt_inline nxt_chunk_id_t -nxt_port_mmap_chunk_id(nxt_port_mmap_header_t *hdr, u_char *p) +nxt_port_mmap_chunk_id(nxt_port_mmap_header_t *hdr, const u_char *p) { u_char *mm_start; diff --git a/src/nxt_port_rpc.c b/src/nxt_port_rpc.c index 0cac5cbb..28590933 100644 --- a/src/nxt_port_rpc.c +++ b/src/nxt_port_rpc.c @@ -512,7 +512,6 @@ nxt_port_rpc_close(nxt_task_t *task, nxt_port_t *port) msg.port_msg.mmap = 0; msg.port_msg.nf = 0; msg.port_msg.mf = 0; - msg.port_msg.tracking = 0; msg.size = 0; msg.cancelled = 0; msg.u.data = NULL; diff --git a/src/nxt_port_socket.c b/src/nxt_port_socket.c index 2a51dfb6..5752d5ab 100644 --- a/src/nxt_port_socket.c +++ b/src/nxt_port_socket.c @@ -19,7 +19,7 @@ static uint8_t nxt_port_enqueue_buf(nxt_task_t *task, nxt_port_msg_t *pm, void *qbuf, nxt_buf_t *b); static nxt_int_t nxt_port_msg_chk_insert(nxt_task_t *task, nxt_port_t *port, nxt_port_send_msg_t *msg); -static nxt_port_send_msg_t *nxt_port_msg_alloc(nxt_port_send_msg_t *m); +static nxt_port_send_msg_t *nxt_port_msg_alloc(const nxt_port_send_msg_t *m); static void nxt_port_write_handler(nxt_task_t *task, void *obj, void *data); static nxt_port_send_msg_t *nxt_port_msg_first(nxt_port_t *port); nxt_inline void nxt_port_msg_close_fd(nxt_port_send_msg_t *msg); @@ -332,7 +332,7 @@ nxt_port_msg_chk_insert(nxt_task_t *task, nxt_port_t *port, static nxt_port_send_msg_t * -nxt_port_msg_alloc(nxt_port_send_msg_t *m) +nxt_port_msg_alloc(const nxt_port_send_msg_t *m) { nxt_port_send_msg_t *msg; diff --git a/src/nxt_process.c b/src/nxt_process.c index 82e66a99..738a03bf 100644 --- a/src/nxt_process.c +++ b/src/nxt_process.c @@ -296,6 +296,16 @@ nxt_process_child_fixup(nxt_task_t *task, nxt_process_t *process) } nxt_runtime_process_loop; + if (init->siblings != NULL) { + nxt_queue_each(p, init->siblings, nxt_process_t, link) { + + nxt_debug(task, "remove sibling process %PI", p->pid); + + nxt_process_close_ports(task, p); + + } nxt_queue_loop; + } + return NXT_OK; } @@ -303,8 +313,9 @@ nxt_process_child_fixup(nxt_task_t *task, nxt_process_t *process) static nxt_pid_t nxt_process_create(nxt_task_t *task, nxt_process_t *process) { - nxt_int_t ret; - nxt_pid_t pid; + nxt_int_t ret; + nxt_pid_t pid; + nxt_runtime_t *rt; #if (NXT_HAVE_CLONE) pid = nxt_clone(SIGCHLD | process->isolation.clone.flags); @@ -352,7 +363,20 @@ nxt_process_create(nxt_task_t *task, nxt_process_t *process) process->pid = pid; process->isolated_pid = pid; - nxt_runtime_process_add(task, process); + rt = task->thread->runtime; + + if (rt->is_pid_isolated) { + /* + * Do not register process in runtime with isolated pid. + * Only global pid can be the key to avoid clash. + */ + nxt_assert(!nxt_queue_is_empty(&process->ports)); + + nxt_port_use(task, nxt_process_port_first(process), 1); + + } else { + nxt_runtime_process_add(task, process); + } return pid; } @@ -798,8 +822,6 @@ nxt_process_send_ready(nxt_task_t *task, nxt_process_t *process) } -#if (NXT_HAVE_POSIX_SPAWN) - /* * Linux glibc 2.2 posix_spawn() is implemented via fork()/execve(). * Linux glibc 2.4 posix_spawn() without file actions and spawn @@ -834,52 +856,6 @@ nxt_process_execute(nxt_task_t *task, char *name, char **argv, char **envp) return pid; } -#else - -nxt_pid_t -nxt_process_execute(nxt_task_t *task, char *name, char **argv, char **envp) -{ - nxt_pid_t pid; - - /* - * vfork() is better than fork() because: - * it is faster several times; - * its execution time does not depend on private memory mapping size; - * it has lesser chances to fail due to the ENOMEM error. - */ - - pid = vfork(); - - switch (pid) { - - case -1: - nxt_alert(task, "vfork() failed while executing \"%s\" %E", - name, nxt_errno); - break; - - case 0: - /* A child. */ - nxt_debug(task, "execve(\"%s\")", name); - - (void) execve(name, argv, envp); - - nxt_alert(task, "execve(\"%s\") failed %E", name, nxt_errno); - - exit(1); - nxt_unreachable(); - break; - - default: - /* A parent. */ - nxt_debug(task, "vfork(): %PI", pid); - break; - } - - return pid; -} - -#endif - nxt_int_t nxt_process_daemon(nxt_task_t *task) @@ -1008,6 +984,8 @@ nxt_process_close_ports(nxt_task_t *task, nxt_process_t *process) { nxt_port_t *port; + nxt_process_use(task, process, 1); + nxt_process_port_each(process, port) { nxt_port_close(task, port); @@ -1015,6 +993,8 @@ nxt_process_close_ports(nxt_task_t *task, nxt_process_t *process) nxt_runtime_port_remove(task, port); } nxt_process_port_loop; + + nxt_process_use(task, process, -1); } diff --git a/src/nxt_process.h b/src/nxt_process.h index 694f457e..15fd4e7f 100644 --- a/src/nxt_process.h +++ b/src/nxt_process.h @@ -19,7 +19,7 @@ * fork(2) calls. As we use clone(2) for container, it returns the wrong pid. */ #define nxt_getpid() \ - syscall(__NR_getpid) + syscall(SYS_getpid) #else #define nxt_getpid() \ getpid() @@ -148,6 +148,8 @@ typedef struct { const nxt_port_handlers_t *port_handlers; const nxt_sig_event_t *signals; + + nxt_queue_t *siblings; } nxt_process_init_t; diff --git a/src/nxt_router.c b/src/nxt_router.c index 3a32a363..f02bf3f2 100644 --- a/src/nxt_router.c +++ b/src/nxt_router.c @@ -7,6 +7,7 @@ #include <nxt_router.h> #include <nxt_conf.h> +#include <nxt_status.h> #if (NXT_TLS) #include <nxt_cert.h> #endif @@ -90,17 +91,14 @@ static void nxt_router_conf_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg); static void nxt_router_app_restart_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg); -static void nxt_router_remove_pid_handler(nxt_task_t *task, +static void nxt_router_status_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg); -static void nxt_router_access_log_reopen_handler(nxt_task_t *task, +static void nxt_router_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg); static nxt_router_temp_conf_t *nxt_router_temp_conf(nxt_task_t *task); -static void nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data); static void nxt_router_conf_ready(nxt_task_t *task, nxt_router_temp_conf_t *tmcf); -static void nxt_router_conf_error(nxt_task_t *task, - nxt_router_temp_conf_t *tmcf); static void nxt_router_conf_send(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, nxt_port_msg_type_t type); @@ -108,9 +106,10 @@ static nxt_int_t nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, u_char *start, u_char *end); static nxt_int_t nxt_router_conf_process_static(nxt_task_t *task, nxt_router_conf_t *rtcf, nxt_conf_value_t *conf); -static nxt_int_t nxt_router_conf_process_client_ip(nxt_task_t *task, - nxt_router_temp_conf_t *tmcf, nxt_socket_conf_t *skcf, - nxt_conf_value_t *conf); +static nxt_http_forward_t *nxt_router_conf_forward(nxt_task_t *task, + nxt_mp_t *mp, nxt_conf_value_t *conf); +static nxt_int_t nxt_router_conf_forward_header(nxt_mp_t *mp, + nxt_conf_value_t *conf, nxt_http_forward_header_t *fh); static nxt_app_t *nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name); static nxt_int_t nxt_router_apps_hash_test(nxt_lvlhsh_query_t *lhq, void *data); @@ -200,27 +199,6 @@ static void nxt_router_req_headers_ack_handler(nxt_task_t *task, static void nxt_router_listen_socket_release(nxt_task_t *task, nxt_socket_conf_t *skcf); -static void nxt_router_access_log_writer(nxt_task_t *task, - nxt_http_request_t *r, nxt_router_access_log_t *access_log); -static u_char *nxt_router_access_log_date(u_char *buf, nxt_realtime_t *now, - struct tm *tm, size_t size, const char *format); -static void nxt_router_access_log_open(nxt_task_t *task, - nxt_router_temp_conf_t *tmcf); -static void nxt_router_access_log_ready(nxt_task_t *task, - nxt_port_recv_msg_t *msg, void *data); -static void nxt_router_access_log_error(nxt_task_t *task, - nxt_port_recv_msg_t *msg, void *data); -static void nxt_router_access_log_use(nxt_thread_spinlock_t *lock, - nxt_router_access_log_t *access_log); -static void nxt_router_access_log_release(nxt_task_t *task, - nxt_thread_spinlock_t *lock, nxt_router_access_log_t *access_log); -static void nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj, - void *data); -static void nxt_router_access_log_reopen_ready(nxt_task_t *task, - nxt_port_recv_msg_t *msg, void *data); -static void nxt_router_access_log_reopen_error(nxt_task_t *task, - nxt_port_recv_msg_t *msg, void *data); - static void nxt_router_app_port_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data); static void nxt_router_app_port_error(nxt_task_t *task, @@ -270,7 +248,7 @@ static void nxt_router_get_mmap_handler(nxt_task_t *task, extern const nxt_http_request_state_t nxt_http_websocket; -static nxt_router_t *nxt_router; +nxt_router_t *nxt_router; static const nxt_str_t http_prefix = nxt_string("HTTP_"); static const nxt_str_t empty_prefix = nxt_string(""); @@ -294,6 +272,7 @@ static const nxt_port_handlers_t nxt_router_process_port_handlers = { .get_mmap = nxt_router_get_mmap_handler, .data = nxt_router_conf_data_handler, .app_restart = nxt_router_app_restart_handler, + .status = nxt_router_status_handler, .remove_pid = nxt_router_remove_pid_handler, .access_log = nxt_router_access_log_reopen_handler, .rpc_ready = nxt_port_rpc_handler, @@ -944,6 +923,84 @@ fail: static void +nxt_router_status_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) +{ + u_char *p; + size_t alloc; + nxt_app_t *app; + nxt_buf_t *b; + nxt_uint_t type; + nxt_port_t *port; + nxt_status_app_t *app_stat; + nxt_event_engine_t *engine; + nxt_status_report_t *report; + + port = nxt_runtime_port_find(task->thread->runtime, + msg->port_msg.pid, + msg->port_msg.reply_port); + if (nxt_slow_path(port == NULL)) { + nxt_alert(task, "nxt_router_status_handler(): reply port not found"); + return; + } + + alloc = sizeof(nxt_status_report_t); + + nxt_queue_each(app, &nxt_router->apps, nxt_app_t, link) { + + alloc += sizeof(nxt_status_app_t) + app->name.length; + + } nxt_queue_loop; + + b = nxt_buf_mem_alloc(port->mem_pool, alloc, 0); + if (nxt_slow_path(b == NULL)) { + type = NXT_PORT_MSG_RPC_ERROR; + goto fail; + } + + report = (nxt_status_report_t *) b->mem.free; + b->mem.free = b->mem.end; + + nxt_memzero(report, sizeof(nxt_status_report_t)); + + nxt_queue_each(engine, &nxt_router->engines, nxt_event_engine_t, link0) { + + report->accepted_conns += engine->accepted_conns_cnt; + report->idle_conns += engine->idle_conns_cnt; + report->closed_conns += engine->closed_conns_cnt; + report->requests += engine->requests_cnt; + + } nxt_queue_loop; + + report->apps_count = 0; + app_stat = report->apps; + p = b->mem.end; + + nxt_queue_each(app, &nxt_router->apps, nxt_app_t, link) { + p -= app->name.length; + + nxt_memcpy(p, app->name.start, app->name.length); + + app_stat->name.length = app->name.length; + app_stat->name.start = (u_char *) (p - b->mem.pos); + + app_stat->active_requests = app->active_requests; + app_stat->pending_processes = app->pending_processes; + app_stat->processes = app->processes; + app_stat->idle_processes = app->idle_processes; + + report->apps_count++; + app_stat++; + } nxt_queue_loop; + + type = NXT_PORT_MSG_RPC_READY_LAST; + +fail: + + nxt_port_socket_write(task, port, type, -1, msg->port_msg.stream, 0, b); +} + + +static void nxt_router_app_process_remove_pid(nxt_task_t *task, nxt_port_t *port, void *data) { @@ -1003,6 +1060,11 @@ nxt_router_temp_conf(nxt_task_t *task) rtcf->mem_pool = mp; + rtcf->var_fields = nxt_array_create(mp, 4, sizeof(nxt_var_field_t)); + if (nxt_slow_path(rtcf->var_fields == NULL)) { + goto fail; + } + tmp = nxt_mp_create(1024, 128, 256, 32); if (nxt_slow_path(tmp == NULL)) { goto fail; @@ -1069,7 +1131,7 @@ nxt_router_app_need_start(nxt_app_t *app) } -static void +void nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data) { nxt_int_t ret; @@ -1225,11 +1287,10 @@ nxt_router_conf_ready(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) } -static void +void nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) { nxt_app_t *app; - nxt_queue_t new_socket_confs; nxt_socket_t s; nxt_router_t *router; nxt_queue_link_t *qlk; @@ -1252,11 +1313,6 @@ nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) nxt_free(skcf->listen); } - nxt_queue_init(&new_socket_confs); - nxt_queue_add(&new_socket_confs, &updating_sockets); - nxt_queue_add(&new_socket_confs, &pending_sockets); - nxt_queue_add(&new_socket_confs, &creating_sockets); - rtcf = tmcf->router_conf; nxt_queue_each(app, &tmcf->apps, nxt_app_t, link) { @@ -1483,7 +1539,7 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, nxt_mp_t *mp, *app_mp; uint32_t next, next_target; nxt_int_t ret; - nxt_str_t name, path, target; + nxt_str_t name, target; nxt_app_t *app, *prev; nxt_str_t *t, *s, *targets; nxt_uint_t n, i; @@ -1494,16 +1550,15 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, nxt_tls_init_t *tls_init; nxt_conf_value_t *certificate; #endif - nxt_conf_value_t *conf, *http, *value, *websocket; + nxt_conf_value_t *root, *conf, *http, *value, *websocket; nxt_conf_value_t *applications, *application; nxt_conf_value_t *listeners, *listener; - nxt_conf_value_t *routes_conf, *static_conf, *client_ip_conf; nxt_socket_conf_t *skcf; + nxt_router_conf_t *rtcf; nxt_http_routes_t *routes; nxt_event_engine_t *engine; nxt_app_lang_module_t *lang; nxt_router_app_conf_t apcf; - nxt_router_access_log_t *access_log; nxt_router_listener_conf_t lscf; static nxt_str_t http_path = nxt_string("/settings/http"); @@ -1520,37 +1575,39 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, #endif static nxt_str_t static_path = nxt_string("/settings/http/static"); static nxt_str_t websocket_path = nxt_string("/settings/http/websocket"); + static nxt_str_t forwarded_path = nxt_string("/forwarded"); static nxt_str_t client_ip_path = nxt_string("/client_ip"); - conf = nxt_conf_json_parse(tmcf->mem_pool, start, end, NULL); - if (conf == NULL) { + root = nxt_conf_json_parse(tmcf->mem_pool, start, end, NULL); + if (root == NULL) { nxt_alert(task, "configuration parsing error"); return NXT_ERROR; } - mp = tmcf->router_conf->mem_pool; + rtcf = tmcf->router_conf; + mp = rtcf->mem_pool; - ret = nxt_conf_map_object(mp, conf, nxt_router_conf, - nxt_nitems(nxt_router_conf), tmcf->router_conf); + ret = nxt_conf_map_object(mp, root, nxt_router_conf, + nxt_nitems(nxt_router_conf), rtcf); if (ret != NXT_OK) { nxt_alert(task, "root map error"); return NXT_ERROR; } - if (tmcf->router_conf->threads == 0) { - tmcf->router_conf->threads = nxt_ncpu; + if (rtcf->threads == 0) { + rtcf->threads = nxt_ncpu; } - static_conf = nxt_conf_get_path(conf, &static_path); + conf = nxt_conf_get_path(root, &static_path); - ret = nxt_router_conf_process_static(task, tmcf->router_conf, static_conf); + ret = nxt_router_conf_process_static(task, rtcf, conf); if (nxt_slow_path(ret != NXT_OK)) { return NXT_ERROR; } - router = tmcf->router_conf->router; + router = rtcf->router; - applications = nxt_conf_get_path(conf, &applications_path); + applications = nxt_conf_get_path(root, &applications_path); if (applications != NULL) { next = 0; @@ -1599,7 +1656,7 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, nxt_queue_remove(&prev->link); nxt_queue_insert_tail(&tmcf->previous, &prev->link); - ret = nxt_router_apps_hash_add(tmcf->router_conf, prev); + ret = nxt_router_apps_hash_add(rtcf, prev); if (nxt_slow_path(ret != NXT_OK)) { goto fail; } @@ -1734,7 +1791,7 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, nxt_queue_insert_tail(&tmcf->apps, &app->link); - ret = nxt_router_apps_hash_add(tmcf->router_conf, app); + ret = nxt_router_apps_hash_add(rtcf, app); if (nxt_slow_path(ret != NXT_OK)) { goto app_fail; } @@ -1785,21 +1842,22 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, } } - routes_conf = nxt_conf_get_path(conf, &routes_path); - if (nxt_fast_path(routes_conf != NULL)) { - routes = nxt_http_routes_create(task, tmcf, routes_conf); + conf = nxt_conf_get_path(root, &routes_path); + if (nxt_fast_path(conf != NULL)) { + routes = nxt_http_routes_create(task, tmcf, conf); if (nxt_slow_path(routes == NULL)) { return NXT_ERROR; } - tmcf->router_conf->routes = routes; + + rtcf->routes = routes; } - ret = nxt_upstreams_create(task, tmcf, conf); + ret = nxt_upstreams_create(task, tmcf, root); if (nxt_slow_path(ret != NXT_OK)) { return ret; } - http = nxt_conf_get_path(conf, &http_path); + http = nxt_conf_get_path(root, &http_path); #if 0 if (http == NULL) { nxt_alert(task, "no \"http\" block"); @@ -1807,9 +1865,9 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, } #endif - websocket = nxt_conf_get_path(conf, &websocket_path); + websocket = nxt_conf_get_path(root, &websocket_path); - listeners = nxt_conf_get_path(conf, &listeners_path); + listeners = nxt_conf_get_path(root, &listeners_path); if (listeners != NULL) { next = 0; @@ -1889,11 +1947,22 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, t->length = nxt_strlen(t->start); } - client_ip_conf = nxt_conf_get_path(listener, &client_ip_path); - ret = nxt_router_conf_process_client_ip(task, tmcf, skcf, - client_ip_conf); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; + conf = nxt_conf_get_path(listener, &forwarded_path); + + if (conf != NULL) { + skcf->forwarded = nxt_router_conf_forward(task, mp, conf); + if (nxt_slow_path(skcf->forwarded == NULL)) { + return NXT_ERROR; + } + } + + conf = nxt_conf_get_path(listener, &client_ip_path); + + if (conf != NULL) { + skcf->client_ip = nxt_router_conf_forward(task, mp, conf); + if (nxt_slow_path(skcf->client_ip == NULL)) { + return NXT_ERROR; + } } #if (NXT_TLS) @@ -1941,7 +2010,7 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, #endif skcf->listen->handler = nxt_http_conn_init; - skcf->router_conf = tmcf->router_conf; + skcf->router_conf = rtcf; skcf->router_conf->count++; if (lscf.pass.length != 0) { @@ -1949,8 +2018,7 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, /* COMPATIBILITY: listener application. */ } else if (lscf.application.length > 0) { - skcf->action = nxt_http_pass_application(task, - tmcf->router_conf, + skcf->action = nxt_http_pass_application(task, rtcf, &lscf.application); } @@ -1965,36 +2033,13 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, goto fail; } - value = nxt_conf_get_path(conf, &access_log_path); + value = nxt_conf_get_path(root, &access_log_path); if (value != NULL) { - nxt_conf_get_string(value, &path); - - access_log = router->access_log; - - if (access_log != NULL && nxt_strstr_eq(&path, &access_log->path)) { - nxt_router_access_log_use(&router->lock, access_log); - - } else { - access_log = nxt_malloc(sizeof(nxt_router_access_log_t) - + path.length); - if (access_log == NULL) { - nxt_alert(task, "failed to allocate access log structure"); - goto fail; - } - - access_log->fd = -1; - access_log->handler = &nxt_router_access_log_writer; - access_log->count = 1; - - access_log->path.length = path.length; - access_log->path.start = (u_char *) access_log - + sizeof(nxt_router_access_log_t); - - nxt_memcpy(access_log->path.start, path.start, path.length); + ret = nxt_router_access_log_create(task, rtcf, value); + if (nxt_slow_path(ret != NXT_OK)) { + goto fail; } - - tmcf->router_conf->access_log = access_log; } nxt_queue_add(&deleting_sockets, &router->sockets); @@ -2129,74 +2174,103 @@ nxt_router_conf_process_static(nxt_task_t *task, nxt_router_conf_t *rtcf, } -static nxt_int_t -nxt_router_conf_process_client_ip(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, - nxt_socket_conf_t *skcf, nxt_conf_value_t *conf) +static nxt_http_forward_t * +nxt_router_conf_forward(nxt_task_t *task, nxt_mp_t *mp, nxt_conf_value_t *conf) { - char c; - size_t i; - nxt_mp_t *mp; - uint32_t hash; - nxt_str_t header; - nxt_conf_value_t *source_conf, *header_conf, *recursive_conf; - nxt_http_client_ip_t *client_ip; + nxt_int_t ret; + nxt_conf_value_t *header_conf, *client_ip_conf, *protocol_conf; + nxt_conf_value_t *source_conf, *recursive_conf; + nxt_http_forward_t *forward; nxt_http_route_addr_rule_t *source; static nxt_str_t header_path = nxt_string("/header"); + static nxt_str_t client_ip_path = nxt_string("/client_ip"); + static nxt_str_t protocol_path = nxt_string("/protocol"); static nxt_str_t source_path = nxt_string("/source"); static nxt_str_t recursive_path = nxt_string("/recursive"); - if (conf == NULL) { - skcf->client_ip = NULL; + header_conf = nxt_conf_get_path(conf, &header_path); - return NXT_OK; - } + if (header_conf != NULL) { + client_ip_conf = nxt_conf_get_path(conf, &header_path); + protocol_conf = NULL; - mp = tmcf->router_conf->mem_pool; + } else { + client_ip_conf = nxt_conf_get_path(conf, &client_ip_path); + protocol_conf = nxt_conf_get_path(conf, &protocol_path); + } source_conf = nxt_conf_get_path(conf, &source_path); - header_conf = nxt_conf_get_path(conf, &header_path); recursive_conf = nxt_conf_get_path(conf, &recursive_path); - if (source_conf == NULL || header_conf == NULL) { - return NXT_ERROR; + if (source_conf == NULL + || (protocol_conf == NULL && client_ip_conf == NULL)) + { + return NULL; } - client_ip = nxt_mp_zget(mp, sizeof(nxt_http_client_ip_t)); - if (nxt_slow_path(client_ip == NULL)) { - return NXT_ERROR; + forward = nxt_mp_zget(mp, sizeof(nxt_http_forward_t)); + if (nxt_slow_path(forward == NULL)) { + return NULL; } source = nxt_http_route_addr_rule_create(task, mp, source_conf); if (nxt_slow_path(source == NULL)) { - return NXT_ERROR; + return NULL; } - client_ip->source = source; - - nxt_conf_get_string(header_conf, &header); + forward->source = source; if (recursive_conf != NULL) { - client_ip->recursive = nxt_conf_get_boolean(recursive_conf); + forward->recursive = nxt_conf_get_boolean(recursive_conf); } - client_ip->header = nxt_str_dup(mp, NULL, &header); - if (nxt_slow_path(client_ip->header == NULL)) { + if (client_ip_conf != NULL) { + ret = nxt_router_conf_forward_header(mp, client_ip_conf, + &forward->client_ip); + if (nxt_slow_path(ret != NXT_OK)) { + return NULL; + } + } + + if (protocol_conf != NULL) { + ret = nxt_router_conf_forward_header(mp, protocol_conf, + &forward->protocol); + if (nxt_slow_path(ret != NXT_OK)) { + return NULL; + } + } + + return forward; +} + + +static nxt_int_t +nxt_router_conf_forward_header(nxt_mp_t *mp, nxt_conf_value_t *conf, + nxt_http_forward_header_t *fh) +{ + char c; + size_t i; + uint32_t hash; + nxt_str_t header; + + nxt_conf_get_string(conf, &header); + + fh->header = nxt_str_dup(mp, NULL, &header); + if (nxt_slow_path(fh->header == NULL)) { return NXT_ERROR; } hash = NXT_HTTP_FIELD_HASH_INIT; - for (i = 0; i < client_ip->header->length; i++) { - c = client_ip->header->start[i]; + for (i = 0; i < fh->header->length; i++) { + c = fh->header->start[i]; hash = nxt_http_field_hash_char(hash, nxt_lowcase(c)); } hash = nxt_http_field_hash_end(hash) & 0xFFFF; - client_ip->header_hash = hash; - - skcf->client_ip = client_ip; + fh->header_hash = hash; return NXT_OK; } @@ -3719,384 +3793,6 @@ nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint) static void -nxt_router_access_log_writer(nxt_task_t *task, nxt_http_request_t *r, - nxt_router_access_log_t *access_log) -{ - size_t size; - u_char *buf, *p; - nxt_off_t bytes; - - static nxt_time_string_t date_cache = { - (nxt_atomic_uint_t) -1, - nxt_router_access_log_date, - "%02d/%s/%4d:%02d:%02d:%02d %c%02d%02d", - nxt_length("31/Dec/1986:19:40:00 +0300"), - NXT_THREAD_TIME_LOCAL, - NXT_THREAD_TIME_SEC, - }; - - size = r->remote->address_length - + 6 /* ' - - [' */ - + date_cache.size - + 3 /* '] "' */ - + r->method->length - + 1 /* space */ - + r->target.length - + 1 /* space */ - + r->version.length - + 2 /* '" ' */ - + 3 /* status */ - + 1 /* space */ - + NXT_OFF_T_LEN - + 2 /* ' "' */ - + (r->referer != NULL ? r->referer->value_length : 1) - + 3 /* '" "' */ - + (r->user_agent != NULL ? r->user_agent->value_length : 1) - + 2 /* '"\n' */ - ; - - buf = nxt_mp_nget(r->mem_pool, size); - if (nxt_slow_path(buf == NULL)) { - return; - } - - p = nxt_cpymem(buf, nxt_sockaddr_address(r->remote), - r->remote->address_length); - - p = nxt_cpymem(p, " - - [", 6); - - p = nxt_thread_time_string(task->thread, &date_cache, p); - - p = nxt_cpymem(p, "] \"", 3); - - if (r->method->length != 0) { - p = nxt_cpymem(p, r->method->start, r->method->length); - - if (r->target.length != 0) { - *p++ = ' '; - p = nxt_cpymem(p, r->target.start, r->target.length); - - if (r->version.length != 0) { - *p++ = ' '; - p = nxt_cpymem(p, r->version.start, r->version.length); - } - } - - } else { - *p++ = '-'; - } - - p = nxt_cpymem(p, "\" ", 2); - - p = nxt_sprintf(p, p + 3, "%03d", r->status); - - *p++ = ' '; - - bytes = nxt_http_proto[r->protocol].body_bytes_sent(task, r->proto); - - p = nxt_sprintf(p, p + NXT_OFF_T_LEN, "%O", bytes); - - p = nxt_cpymem(p, " \"", 2); - - if (r->referer != NULL) { - p = nxt_cpymem(p, r->referer->value, r->referer->value_length); - - } else { - *p++ = '-'; - } - - p = nxt_cpymem(p, "\" \"", 3); - - if (r->user_agent != NULL) { - p = nxt_cpymem(p, r->user_agent->value, r->user_agent->value_length); - - } else { - *p++ = '-'; - } - - p = nxt_cpymem(p, "\"\n", 2); - - nxt_fd_write(access_log->fd, buf, p - buf); -} - - -static u_char * -nxt_router_access_log_date(u_char *buf, nxt_realtime_t *now, struct tm *tm, - size_t size, const char *format) -{ - u_char sign; - time_t gmtoff; - - static const char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; - - gmtoff = nxt_timezone(tm) / 60; - - if (gmtoff < 0) { - gmtoff = -gmtoff; - sign = '-'; - - } else { - sign = '+'; - } - - return nxt_sprintf(buf, buf + size, format, - tm->tm_mday, month[tm->tm_mon], tm->tm_year + 1900, - tm->tm_hour, tm->tm_min, tm->tm_sec, - sign, gmtoff / 60, gmtoff % 60); -} - - -static void -nxt_router_access_log_open(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) -{ - uint32_t stream; - nxt_int_t ret; - nxt_buf_t *b; - nxt_port_t *main_port, *router_port; - nxt_runtime_t *rt; - nxt_router_access_log_t *access_log; - - access_log = tmcf->router_conf->access_log; - - b = nxt_buf_mem_alloc(tmcf->mem_pool, access_log->path.length + 1, 0); - if (nxt_slow_path(b == NULL)) { - goto fail; - } - - b->completion_handler = nxt_buf_dummy_completion; - - nxt_buf_cpystr(b, &access_log->path); - *b->mem.free++ = '\0'; - - rt = task->thread->runtime; - main_port = rt->port_by_type[NXT_PROCESS_MAIN]; - router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; - - stream = nxt_port_rpc_register_handler(task, router_port, - nxt_router_access_log_ready, - nxt_router_access_log_error, - -1, tmcf); - if (nxt_slow_path(stream == 0)) { - goto fail; - } - - ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1, - stream, router_port->id, b); - - if (nxt_slow_path(ret != NXT_OK)) { - nxt_port_rpc_cancel(task, router_port, stream); - goto fail; - } - - return; - -fail: - - nxt_router_conf_error(task, tmcf); -} - - -static void -nxt_router_access_log_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, - void *data) -{ - nxt_router_temp_conf_t *tmcf; - nxt_router_access_log_t *access_log; - - tmcf = data; - - access_log = tmcf->router_conf->access_log; - - access_log->fd = msg->fd[0]; - - nxt_work_queue_add(&task->thread->engine->fast_work_queue, - nxt_router_conf_apply, task, tmcf, NULL); -} - - -static void -nxt_router_access_log_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, - void *data) -{ - nxt_router_temp_conf_t *tmcf; - - tmcf = data; - - nxt_router_conf_error(task, tmcf); -} - - -static void -nxt_router_access_log_use(nxt_thread_spinlock_t *lock, - nxt_router_access_log_t *access_log) -{ - if (access_log == NULL) { - return; - } - - nxt_thread_spin_lock(lock); - - access_log->count++; - - nxt_thread_spin_unlock(lock); -} - - -static void -nxt_router_access_log_release(nxt_task_t *task, nxt_thread_spinlock_t *lock, - nxt_router_access_log_t *access_log) -{ - if (access_log == NULL) { - return; - } - - nxt_thread_spin_lock(lock); - - if (--access_log->count != 0) { - access_log = NULL; - } - - nxt_thread_spin_unlock(lock); - - if (access_log != NULL) { - - if (access_log->fd != -1) { - nxt_fd_close(access_log->fd); - } - - nxt_free(access_log); - } -} - - -typedef struct { - nxt_mp_t *mem_pool; - nxt_router_access_log_t *access_log; -} nxt_router_access_log_reopen_t; - - -static void -nxt_router_access_log_reopen_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) -{ - nxt_mp_t *mp; - uint32_t stream; - nxt_int_t ret; - nxt_buf_t *b; - nxt_port_t *main_port, *router_port; - nxt_runtime_t *rt; - nxt_router_access_log_t *access_log; - nxt_router_access_log_reopen_t *reopen; - - access_log = nxt_router->access_log; - - if (access_log == NULL) { - return; - } - - mp = nxt_mp_create(1024, 128, 256, 32); - if (nxt_slow_path(mp == NULL)) { - return; - } - - reopen = nxt_mp_get(mp, sizeof(nxt_router_access_log_reopen_t)); - if (nxt_slow_path(reopen == NULL)) { - goto fail; - } - - reopen->mem_pool = mp; - reopen->access_log = access_log; - - b = nxt_buf_mem_alloc(mp, access_log->path.length + 1, 0); - if (nxt_slow_path(b == NULL)) { - goto fail; - } - - b->completion_handler = nxt_router_access_log_reopen_completion; - - nxt_buf_cpystr(b, &access_log->path); - *b->mem.free++ = '\0'; - - rt = task->thread->runtime; - main_port = rt->port_by_type[NXT_PROCESS_MAIN]; - router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; - - stream = nxt_port_rpc_register_handler(task, router_port, - nxt_router_access_log_reopen_ready, - nxt_router_access_log_reopen_error, - -1, reopen); - if (nxt_slow_path(stream == 0)) { - goto fail; - } - - ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1, - stream, router_port->id, b); - - if (nxt_slow_path(ret != NXT_OK)) { - nxt_port_rpc_cancel(task, router_port, stream); - goto fail; - } - - nxt_mp_retain(mp); - - return; - -fail: - - nxt_mp_destroy(mp); -} - - -static void -nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj, void *data) -{ - nxt_mp_t *mp; - nxt_buf_t *b; - - b = obj; - mp = b->data; - - nxt_mp_release(mp); -} - - -static void -nxt_router_access_log_reopen_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, - void *data) -{ - nxt_router_access_log_t *access_log; - nxt_router_access_log_reopen_t *reopen; - - reopen = data; - - access_log = reopen->access_log; - - if (access_log == nxt_router->access_log) { - - if (nxt_slow_path(dup2(msg->fd[0], access_log->fd) == -1)) { - nxt_alert(task, "dup2(%FD, %FD) failed %E", - msg->fd[0], access_log->fd, nxt_errno); - } - } - - nxt_fd_close(msg->fd[0]); - nxt_mp_release(reopen->mem_pool); -} - - -static void -nxt_router_access_log_reopen_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, - void *data) -{ - nxt_router_access_log_reopen_t *reopen; - - reopen = data; - - nxt_mp_release(reopen->mem_pool); -} - - -static void nxt_router_thread_exit_handler(nxt_task_t *task, void *obj, void *data) { nxt_port_t *port; @@ -5390,7 +5086,6 @@ nxt_router_app_prepare_request(nxt_task_t *task, msg.pm.mmap = 1; msg.pm.nf = 0; msg.pm.mf = 0; - msg.pm.tracking = 0; nxt_port_mmap_handler_t *mmap_handler = buf->parent; nxt_port_mmap_header_t *hdr = mmap_handler->hdr; @@ -5559,7 +5254,7 @@ 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->tls = r->tls; req->websocket_handshake = r->websocket_handshake; req->server_name_length = r->server_name.length; diff --git a/src/nxt_router.h b/src/nxt_router.h index 7e337d27..a6add219 100644 --- a/src/nxt_router.h +++ b/src/nxt_router.h @@ -18,7 +18,7 @@ typedef struct nxt_http_request_s nxt_http_request_t; typedef struct nxt_http_action_s nxt_http_action_t; typedef struct nxt_http_routes_s nxt_http_routes_t; -typedef struct nxt_http_client_ip_s nxt_http_client_ip_t; +typedef struct nxt_http_forward_s nxt_http_forward_t; typedef struct nxt_upstream_s nxt_upstream_t; typedef struct nxt_upstreams_s nxt_upstreams_t; typedef struct nxt_router_access_log_s nxt_router_access_log_t; @@ -43,6 +43,7 @@ typedef struct { uint32_t threads; nxt_mp_t *mem_pool; + nxt_array_t *var_fields; /* of nxt_var_field_t */ nxt_router_t *router; nxt_http_routes_t *routes; @@ -52,6 +53,7 @@ typedef struct { nxt_lvlhsh_t apps_hash; nxt_router_access_log_t *access_log; + nxt_var_t *log_format; } nxt_router_conf_t; @@ -197,7 +199,8 @@ typedef struct { uint8_t discard_unsafe_fields; /* 1 bit */ - nxt_http_client_ip_t *client_ip; + nxt_http_forward_t *forwarded; + nxt_http_forward_t *client_ip; #if (NXT_TLS) nxt_tls_conf_t *tls; @@ -221,7 +224,8 @@ typedef struct { struct nxt_router_access_log_s { void (*handler)(nxt_task_t *task, nxt_http_request_t *r, - nxt_router_access_log_t *access_log); + nxt_router_access_log_t *access_log, + nxt_var_t *format); nxt_fd_t fd; nxt_str_t path; uint32_t count; @@ -235,7 +239,23 @@ nxt_int_t nxt_router_application_init(nxt_router_conf_t *rtcf, nxt_str_t *name, nxt_str_t *target, nxt_http_action_t *action); void nxt_router_listen_event_release(nxt_task_t *task, nxt_listen_event_t *lev, nxt_socket_conf_joint_t *joint); + +void nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data); +void nxt_router_conf_error(nxt_task_t *task, nxt_router_temp_conf_t *tmcf); void nxt_router_conf_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint); +nxt_int_t nxt_router_access_log_create(nxt_task_t *task, + nxt_router_conf_t *rtcf, nxt_conf_value_t *value); +void nxt_router_access_log_open(nxt_task_t *task, nxt_router_temp_conf_t *tmcf); +void nxt_router_access_log_use(nxt_thread_spinlock_t *lock, + nxt_router_access_log_t *access_log); +void nxt_router_access_log_release(nxt_task_t *task, + nxt_thread_spinlock_t *lock, nxt_router_access_log_t *access_log); +void nxt_router_access_log_reopen_handler(nxt_task_t *task, + nxt_port_recv_msg_t *msg); + + +extern nxt_router_t *nxt_router; + #endif /* _NXT_ROUTER_H_INCLUDED_ */ diff --git a/src/nxt_router_access_log.c b/src/nxt_router_access_log.c new file mode 100644 index 00000000..dc2a6687 --- /dev/null +++ b/src/nxt_router_access_log.c @@ -0,0 +1,442 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Valentin V. Bartenev + * Copyright (C) NGINX, Inc. + */ + +#include <nxt_router.h> +#include <nxt_conf.h> +#include <nxt_http.h> + + +typedef struct { + nxt_str_t path; + nxt_str_t format; +} nxt_router_access_log_conf_t; + + +typedef struct { + nxt_str_t text; + nxt_router_access_log_t *access_log; +} nxt_router_access_log_ctx_t; + + +static void nxt_router_access_log_writer(nxt_task_t *task, + nxt_http_request_t *r, nxt_router_access_log_t *access_log, + nxt_var_t *format); +static void nxt_router_access_log_write_ready(nxt_task_t *task, void *obj, + void *data); +static void nxt_router_access_log_write_error(nxt_task_t *task, void *obj, + void *data); +static void nxt_router_access_log_ready(nxt_task_t *task, + nxt_port_recv_msg_t *msg, void *data); +static void nxt_router_access_log_error(nxt_task_t *task, + nxt_port_recv_msg_t *msg, void *data); +static void nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj, + void *data); +static void nxt_router_access_log_reopen_ready(nxt_task_t *task, + nxt_port_recv_msg_t *msg, void *data); +static void nxt_router_access_log_reopen_error(nxt_task_t *task, + nxt_port_recv_msg_t *msg, void *data); + + +static nxt_conf_map_t nxt_router_access_log_conf[] = { + { + nxt_string("path"), + NXT_CONF_MAP_STR, + offsetof(nxt_router_access_log_conf_t, path), + }, + + { + nxt_string("format"), + NXT_CONF_MAP_STR, + offsetof(nxt_router_access_log_conf_t, format), + }, +}; + + +nxt_int_t +nxt_router_access_log_create(nxt_task_t *task, nxt_router_conf_t *rtcf, + nxt_conf_value_t *value) +{ + u_char *p; + nxt_int_t ret; + nxt_str_t str; + nxt_var_t *format; + nxt_router_t *router; + nxt_router_access_log_t *access_log; + nxt_router_access_log_conf_t alcf; + + static nxt_str_t log_format_str = nxt_string("$remote_addr - - " + "[$time_local] \"$request_line\" $status $body_bytes_sent " + "\"$header_referer\" \"$header_user_agent\""); + + alcf.format = log_format_str; + + if (nxt_conf_type(value) == NXT_CONF_STRING) { + nxt_conf_get_string(value, &alcf.path); + + } else { + ret = nxt_conf_map_object(rtcf->mem_pool, value, + nxt_router_access_log_conf, + nxt_nitems(nxt_router_access_log_conf), + &alcf); + if (ret != NXT_OK) { + nxt_alert(task, "access log map error"); + return NXT_ERROR; + } + } + + router = nxt_router; + + access_log = router->access_log; + + if (access_log != NULL && nxt_strstr_eq(&alcf.path, &access_log->path)) { + nxt_router_access_log_use(&router->lock, access_log); + + } else { + access_log = nxt_malloc(sizeof(nxt_router_access_log_t) + + alcf.path.length); + if (access_log == NULL) { + nxt_alert(task, "failed to allocate access log structure"); + return NXT_ERROR; + } + + access_log->fd = -1; + access_log->handler = &nxt_router_access_log_writer; + access_log->count = 1; + + access_log->path.length = alcf.path.length; + access_log->path.start = (u_char *) access_log + + sizeof(nxt_router_access_log_t); + + nxt_memcpy(access_log->path.start, alcf.path.start, alcf.path.length); + } + + str.length = alcf.format.length + 1; + + str.start = nxt_malloc(str.length); + if (str.start == NULL) { + nxt_alert(task, "failed to allocate log format structure"); + return NXT_ERROR; + } + + p = nxt_cpymem(str.start, alcf.format.start, alcf.format.length); + *p = '\n'; + + format = nxt_var_compile(&str, rtcf->mem_pool, rtcf->var_fields, + NXT_VAR_LOGGING); + if (nxt_slow_path(format == NULL)) { + return NXT_ERROR; + } + + rtcf->access_log = access_log; + rtcf->log_format = format; + + return NXT_OK; +} + + +static void +nxt_router_access_log_writer(nxt_task_t *task, nxt_http_request_t *r, + nxt_router_access_log_t *access_log, nxt_var_t *format) +{ + nxt_int_t ret; + nxt_router_access_log_ctx_t *ctx; + + ctx = nxt_mp_get(r->mem_pool, sizeof(nxt_router_access_log_ctx_t)); + if (nxt_slow_path(ctx == NULL)) { + return; + } + + ctx->access_log = access_log; + + if (nxt_var_is_const(format)) { + nxt_var_raw(format, &ctx->text); + + nxt_router_access_log_write_ready(task, r, ctx); + + } else { + ret = nxt_var_query_init(&r->var_query, r, r->mem_pool); + if (nxt_slow_path(ret != NXT_OK)) { + return; + } + + nxt_var_query(task, r->var_query, format, &ctx->text); + nxt_var_query_resolve(task, r->var_query, ctx, + nxt_router_access_log_write_ready, + nxt_router_access_log_write_error); + } +} + + +static void +nxt_router_access_log_write_ready(nxt_task_t *task, void *obj, void *data) +{ + nxt_http_request_t *r; + nxt_router_access_log_ctx_t *ctx; + + r = obj; + ctx = data; + + nxt_fd_write(ctx->access_log->fd, ctx->text.start, ctx->text.length); + + nxt_http_request_close_handler(task, r, r->proto.any); +} + + +static void +nxt_router_access_log_write_error(nxt_task_t *task, void *obj, void *data) +{ + +} + + +void +nxt_router_access_log_open(nxt_task_t *task, nxt_router_temp_conf_t *tmcf) +{ + uint32_t stream; + nxt_int_t ret; + nxt_buf_t *b; + nxt_port_t *main_port, *router_port; + nxt_runtime_t *rt; + nxt_router_access_log_t *access_log; + + access_log = tmcf->router_conf->access_log; + + b = nxt_buf_mem_alloc(tmcf->mem_pool, access_log->path.length + 1, 0); + if (nxt_slow_path(b == NULL)) { + goto fail; + } + + b->completion_handler = nxt_buf_dummy_completion; + + nxt_buf_cpystr(b, &access_log->path); + *b->mem.free++ = '\0'; + + rt = task->thread->runtime; + main_port = rt->port_by_type[NXT_PROCESS_MAIN]; + router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; + + stream = nxt_port_rpc_register_handler(task, router_port, + nxt_router_access_log_ready, + nxt_router_access_log_error, + -1, tmcf); + if (nxt_slow_path(stream == 0)) { + goto fail; + } + + ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1, + stream, router_port->id, b); + + if (nxt_slow_path(ret != NXT_OK)) { + nxt_port_rpc_cancel(task, router_port, stream); + goto fail; + } + + return; + +fail: + + nxt_router_conf_error(task, tmcf); +} + + +static void +nxt_router_access_log_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, + void *data) +{ + nxt_router_temp_conf_t *tmcf; + nxt_router_access_log_t *access_log; + + tmcf = data; + + access_log = tmcf->router_conf->access_log; + + access_log->fd = msg->fd[0]; + + nxt_work_queue_add(&task->thread->engine->fast_work_queue, + nxt_router_conf_apply, task, tmcf, NULL); +} + + +static void +nxt_router_access_log_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, + void *data) +{ + nxt_router_temp_conf_t *tmcf; + + tmcf = data; + + nxt_router_conf_error(task, tmcf); +} + + +void +nxt_router_access_log_use(nxt_thread_spinlock_t *lock, + nxt_router_access_log_t *access_log) +{ + if (access_log == NULL) { + return; + } + + nxt_thread_spin_lock(lock); + + access_log->count++; + + nxt_thread_spin_unlock(lock); +} + + +void +nxt_router_access_log_release(nxt_task_t *task, nxt_thread_spinlock_t *lock, + nxt_router_access_log_t *access_log) +{ + if (access_log == NULL) { + return; + } + + nxt_thread_spin_lock(lock); + + if (--access_log->count != 0) { + access_log = NULL; + } + + nxt_thread_spin_unlock(lock); + + if (access_log != NULL) { + + if (access_log->fd != -1) { + nxt_fd_close(access_log->fd); + } + + nxt_free(access_log); + } +} + + +typedef struct { + nxt_mp_t *mem_pool; + nxt_router_access_log_t *access_log; +} nxt_router_access_log_reopen_t; + + +void +nxt_router_access_log_reopen_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg) +{ + nxt_mp_t *mp; + uint32_t stream; + nxt_int_t ret; + nxt_buf_t *b; + nxt_port_t *main_port, *router_port; + nxt_runtime_t *rt; + nxt_router_access_log_t *access_log; + nxt_router_access_log_reopen_t *reopen; + + access_log = nxt_router->access_log; + + if (access_log == NULL) { + return; + } + + mp = nxt_mp_create(1024, 128, 256, 32); + if (nxt_slow_path(mp == NULL)) { + return; + } + + reopen = nxt_mp_get(mp, sizeof(nxt_router_access_log_reopen_t)); + if (nxt_slow_path(reopen == NULL)) { + goto fail; + } + + reopen->mem_pool = mp; + reopen->access_log = access_log; + + b = nxt_buf_mem_alloc(mp, access_log->path.length + 1, 0); + if (nxt_slow_path(b == NULL)) { + goto fail; + } + + b->completion_handler = nxt_router_access_log_reopen_completion; + + nxt_buf_cpystr(b, &access_log->path); + *b->mem.free++ = '\0'; + + rt = task->thread->runtime; + main_port = rt->port_by_type[NXT_PROCESS_MAIN]; + router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; + + stream = nxt_port_rpc_register_handler(task, router_port, + nxt_router_access_log_reopen_ready, + nxt_router_access_log_reopen_error, + -1, reopen); + if (nxt_slow_path(stream == 0)) { + goto fail; + } + + ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1, + stream, router_port->id, b); + + if (nxt_slow_path(ret != NXT_OK)) { + nxt_port_rpc_cancel(task, router_port, stream); + goto fail; + } + + nxt_mp_retain(mp); + + return; + +fail: + + nxt_mp_destroy(mp); +} + + +static void +nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj, void *data) +{ + nxt_mp_t *mp; + nxt_buf_t *b; + + b = obj; + mp = b->data; + + nxt_mp_release(mp); +} + + +static void +nxt_router_access_log_reopen_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg, + void *data) +{ + nxt_router_access_log_t *access_log; + nxt_router_access_log_reopen_t *reopen; + + reopen = data; + + access_log = reopen->access_log; + + if (access_log == nxt_router->access_log) { + + if (nxt_slow_path(dup2(msg->fd[0], access_log->fd) == -1)) { + nxt_alert(task, "dup2(%FD, %FD) failed %E", + msg->fd[0], access_log->fd, nxt_errno); + } + } + + nxt_fd_close(msg->fd[0]); + nxt_mp_release(reopen->mem_pool); +} + + +static void +nxt_router_access_log_reopen_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, + void *data) +{ + nxt_router_access_log_reopen_t *reopen; + + reopen = data; + + nxt_mp_release(reopen->mem_pool); +} diff --git a/src/nxt_runtime.c b/src/nxt_runtime.c index 46955f1c..d9c9f2ef 100644 --- a/src/nxt_runtime.c +++ b/src/nxt_runtime.c @@ -1408,6 +1408,7 @@ nxt_runtime_process_release(nxt_runtime_t *rt, nxt_process_t *process) nxt_assert(process->use_count == 0); nxt_assert(process->registered == 0); + nxt_assert(nxt_queue_is_empty(&process->ports)); nxt_port_mmaps_destroy(&process->incoming, 1); @@ -1579,11 +1580,11 @@ nxt_runtime_process_add(nxt_task_t *task, nxt_process_t *process) process->registered = 1; - nxt_thread_log_debug("process %PI added", process->pid); + nxt_debug(task, "process %PI added", process->pid); break; default: - nxt_thread_log_debug("process %PI failed to add", process->pid); + nxt_alert(task, "process %PI failed to add", process->pid); break; } @@ -1597,6 +1598,8 @@ nxt_runtime_process_remove(nxt_runtime_t *rt, nxt_process_t *process) nxt_pid_t pid; nxt_lvlhsh_query_t lhq; + nxt_assert(process->registered != 0); + pid = process->pid; nxt_runtime_process_lhq_pid(&lhq, &pid); @@ -1608,9 +1611,9 @@ nxt_runtime_process_remove(nxt_runtime_t *rt, nxt_process_t *process) switch (nxt_lvlhsh_delete(&rt->processes, &lhq)) { case NXT_OK: - rt->nprocesses--; + nxt_assert(lhq.value == process); - process = lhq.value; + rt->nprocesses--; process->registered = 0; @@ -1618,7 +1621,7 @@ nxt_runtime_process_remove(nxt_runtime_t *rt, nxt_process_t *process) break; default: - nxt_thread_log_debug("process %PI remove failed", pid); + nxt_thread_log_alert("process %PI remove failed", pid); break; } diff --git a/src/nxt_sockaddr.c b/src/nxt_sockaddr.c index 730428e4..86c3335e 100644 --- a/src/nxt_sockaddr.c +++ b/src/nxt_sockaddr.c @@ -15,10 +15,6 @@ static nxt_sockaddr_t *nxt_sockaddr_unix_parse(nxt_mp_t *mp, nxt_str_t *addr); static nxt_sockaddr_t *nxt_sockaddr_inet6_parse(nxt_mp_t *mp, nxt_str_t *addr); static nxt_sockaddr_t *nxt_sockaddr_inet_parse(nxt_mp_t *mp, nxt_str_t *addr); -static nxt_int_t nxt_job_sockaddr_unix_parse(nxt_job_sockaddr_parse_t *jbs); -static nxt_int_t nxt_job_sockaddr_inet6_parse(nxt_job_sockaddr_parse_t *jbs); -static nxt_int_t nxt_job_sockaddr_inet_parse(nxt_job_sockaddr_parse_t *jbs); - nxt_sockaddr_t * nxt_sockaddr_cache_alloc(nxt_event_engine_t *engine, nxt_listen_socket_t *ls) @@ -208,8 +204,8 @@ nxt_getsockname(nxt_task_t *task, nxt_mp_t *mp, nxt_socket_t s) #if (NXT_HAVE_UNIX_DOMAIN) case AF_UNIX: length = nxt_length("unix:") + socklen; -#endif break; +#endif case AF_INET: length = NXT_INET_ADDR_STR_LEN; @@ -433,82 +429,6 @@ nxt_sockaddr_cmp(nxt_sockaddr_t *sa1, nxt_sockaddr_t *sa2) } -size_t -nxt_sockaddr_ntop(nxt_sockaddr_t *sa, u_char *buf, u_char *end, nxt_bool_t port) -{ - u_char *p; - - switch (sa->u.sockaddr.sa_family) { - - case AF_INET: - p = (u_char *) &sa->u.sockaddr_in.sin_addr; - - if (port) { - p = nxt_sprintf(buf, end, "%ud.%ud.%ud.%ud:%d", - p[0], p[1], p[2], p[3], - ntohs(sa->u.sockaddr_in.sin_port)); - } else { - p = nxt_sprintf(buf, end, "%ud.%ud.%ud.%ud", - p[0], p[1], p[2], p[3]); - } - - return p - buf; - -#if (NXT_INET6) - - case AF_INET6: - p = buf; - - if (port) { - *p++ = '['; - } - - p = nxt_inet6_ntop(sa->u.sockaddr_in6.sin6_addr.s6_addr, p, end); - - if (port) { - p = nxt_sprintf(p, end, "]:%d", - ntohs(sa->u.sockaddr_in6.sin6_port)); - } - - return p - buf; -#endif - -#if (NXT_HAVE_UNIX_DOMAIN) - - case AF_UNIX: - -#if (NXT_LINUX) - - p = (u_char *) sa->u.sockaddr_un.sun_path; - - if (p[0] == '\0') { - size_t length; - - /* Linux abstract socket address has no trailing zero. */ - - length = sa->socklen - offsetof(struct sockaddr_un, sun_path) - 1; - p = nxt_sprintf(buf, end, "unix:\\0%*s", length, p + 1); - - } else { - p = nxt_sprintf(buf, end, "unix:%s", p); - } - -#else /* !(NXT_LINUX) */ - - p = nxt_sprintf(buf, end, "unix:%s", sa->u.sockaddr_un.sun_path); - -#endif - - return p - buf; - -#endif /* NXT_HAVE_UNIX_DOMAIN */ - - default: - return 0; - } -} - - #if (NXT_INET6) static u_char * @@ -681,8 +601,6 @@ nxt_sockaddr_unix_parse(nxt_mp_t *mp, nxt_str_t *addr) socklen = offsetof(struct sockaddr_un, sun_path) + length + 1; -#if (NXT_LINUX) - /* * Linux unix(7): * @@ -695,9 +613,12 @@ nxt_sockaddr_unix_parse(nxt_mp_t *mp, nxt_str_t *addr) if (path[0] == '@') { path[0] = '\0'; socklen--; - } - +#if !(NXT_LINUX) + nxt_thread_log_error(NXT_LOG_ERR, + "abstract unix domain sockets are not supported"); + return NULL; #endif + } sa = nxt_sockaddr_alloc(mp, socklen, addr->length); @@ -849,338 +770,6 @@ nxt_sockaddr_inet_parse(nxt_mp_t *mp, nxt_str_t *addr) } -void -nxt_job_sockaddr_parse(nxt_job_sockaddr_parse_t *jbs) -{ - u_char *p; - size_t length; - nxt_int_t ret; - nxt_work_handler_t handler; - - nxt_job_set_name(&jbs->resolve.job, "job sockaddr parse"); - - length = jbs->addr.length; - p = jbs->addr.start; - - if (length > 6 && nxt_memcmp(p, "unix:", 5) == 0) { - ret = nxt_job_sockaddr_unix_parse(jbs); - - } else if (length != 0 && *p == '[') { - ret = nxt_job_sockaddr_inet6_parse(jbs); - - } else { - ret = nxt_job_sockaddr_inet_parse(jbs); - } - - switch (ret) { - - case NXT_OK: - handler = jbs->resolve.ready_handler; - break; - - case NXT_ERROR: - handler = jbs->resolve.error_handler; - break; - - default: /* NXT_AGAIN */ - return; - } - - nxt_job_return(jbs->resolve.job.task, &jbs->resolve.job, handler); -} - - -static nxt_int_t -nxt_job_sockaddr_unix_parse(nxt_job_sockaddr_parse_t *jbs) -{ -#if (NXT_HAVE_UNIX_DOMAIN) - size_t length, socklen; - u_char *path; - nxt_mp_t *mp; - nxt_sockaddr_t *sa; - - /* - * Actual sockaddr_un length can be lesser or even larger than defined - * struct sockaddr_un length (see comment in nxt_socket.h). So - * limit maximum Unix domain socket address length by defined sun_path[] - * length because some OSes accept addresses twice larger than defined - * struct sockaddr_un. Also reserve space for a trailing zero to avoid - * ambiguity, since many OSes accept Unix domain socket addresses - * without a trailing zero. - */ - const size_t max_len = sizeof(struct sockaddr_un) - - offsetof(struct sockaddr_un, sun_path) - 1; - - /* cutting "unix:" */ - length = jbs->addr.length - 5; - path = jbs->addr.start + 5; - - if (length > max_len) { - nxt_thread_log_error(jbs->resolve.log_level, - "unix domain socket \"%V\" name is too long", - &jbs->addr); - return NXT_ERROR; - } - - socklen = offsetof(struct sockaddr_un, sun_path) + length + 1; - -#if (NXT_LINUX) - - /* - * Linux unix(7): - * - * abstract: an abstract socket address is distinguished by the fact - * that sun_path[0] is a null byte ('\0'). The socket's address in - * this namespace is given by the additional bytes in sun_path that - * are covered by the specified length of the address structure. - * (Null bytes in the name have no special significance.) - */ - if (path[0] == '\0') { - socklen--; - } - -#endif - - mp = jbs->resolve.job.mem_pool; - - jbs->resolve.sockaddrs = nxt_mp_alloc(mp, sizeof(void *)); - - if (nxt_fast_path(jbs->resolve.sockaddrs != NULL)) { - sa = nxt_sockaddr_alloc(mp, socklen, jbs->addr.length); - - if (nxt_fast_path(sa != NULL)) { - jbs->resolve.count = 1; - jbs->resolve.sockaddrs[0] = sa; - - sa->u.sockaddr_un.sun_family = AF_UNIX; - nxt_memcpy(sa->u.sockaddr_un.sun_path, path, length); - - return NXT_OK; - } - } - - return NXT_ERROR; - -#else /* !(NXT_HAVE_UNIX_DOMAIN) */ - - nxt_thread_log_error(jbs->resolve.log_level, - "unix domain socket \"%V\" is not supported", - &jbs->addr); - return NXT_ERROR; - -#endif -} - - -static nxt_int_t -nxt_job_sockaddr_inet6_parse(nxt_job_sockaddr_parse_t *jbs) -{ -#if (NXT_INET6) - u_char *p, *addr, *addr_end; - size_t length; - nxt_mp_t *mp; - nxt_int_t port; - nxt_sockaddr_t *sa; - struct in6_addr *in6_addr; - - length = jbs->addr.length - 1; - addr = jbs->addr.start + 1; - - addr_end = nxt_memchr(addr, ']', length); - - if (addr_end == NULL) { - goto invalid_address; - } - - mp = jbs->resolve.job.mem_pool; - - jbs->resolve.sockaddrs = nxt_mp_alloc(mp, sizeof(void *)); - - if (nxt_slow_path(jbs->resolve.sockaddrs == NULL)) { - return NXT_ERROR; - } - - sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in6), - NXT_INET6_ADDR_STR_LEN); - - if (nxt_slow_path(sa == NULL)) { - return NXT_ERROR; - } - - jbs->resolve.count = 1; - jbs->resolve.sockaddrs[0] = sa; - - in6_addr = &sa->u.sockaddr_in6.sin6_addr; - - if (nxt_inet6_addr(in6_addr, addr, addr_end - addr) != NXT_OK) { - goto invalid_address; - } - - p = addr_end + 1; - length = (addr + length) - p; - - if (length == 0) { - jbs->no_port = 1; - port = jbs->resolve.port; - goto found; - } - - if (*p == ':') { - port = nxt_int_parse(p + 1, length - 1); - - if (port >= 1 && port <= 65535) { - port = htons((in_port_t) port); - goto found; - } - } - - nxt_thread_log_error(jbs->resolve.log_level, - "invalid port in \"%V\"", &jbs->addr); - - return NXT_ERROR; - -found: - - sa->u.sockaddr_in6.sin6_family = AF_INET6; - sa->u.sockaddr_in6.sin6_port = (in_port_t) port; - - if (IN6_IS_ADDR_UNSPECIFIED(in6_addr)) { - jbs->wildcard = 1; - } - - return NXT_OK; - -invalid_address: - - nxt_thread_log_error(jbs->resolve.log_level, - "invalid IPv6 address in \"%V\"", &jbs->addr); - return NXT_ERROR; - -#else - - nxt_thread_log_error(jbs->resolve.log_level, - "IPv6 socket \"%V\" is not supported", &jbs->addr); - return NXT_ERROR; - -#endif -} - - -static nxt_int_t -nxt_job_sockaddr_inet_parse(nxt_job_sockaddr_parse_t *jbs) -{ - u_char *p, *host; - size_t length; - nxt_mp_t *mp; - nxt_int_t port; - in_addr_t addr; - nxt_sockaddr_t *sa; - - addr = INADDR_ANY; - - length = jbs->addr.length; - host = jbs->addr.start; - - p = nxt_memchr(host, ':', length); - - if (p == NULL) { - - /* single value port, address, or host name */ - - port = nxt_int_parse(host, length); - - if (port > 0) { - if (port < 1 || port > 65535) { - goto invalid_port; - } - - /* "*:XX" */ - port = htons((in_port_t) port); - jbs->resolve.port = (in_port_t) port; - - } else { - jbs->no_port = 1; - - addr = nxt_inet_addr(host, length); - - if (addr == INADDR_NONE) { - jbs->resolve.name.length = length; - jbs->resolve.name.start = host; - - nxt_job_resolve(&jbs->resolve); - return NXT_AGAIN; - } - - /* "x.x.x.x" */ - port = jbs->resolve.port; - } - - } else { - - /* x.x.x.x:XX or host:XX */ - - p++; - length = (host + length) - p; - port = nxt_int_parse(p, length); - - if (port < 1 || port > 65535) { - goto invalid_port; - } - - port = htons((in_port_t) port); - - length = (p - 1) - host; - - if (length != 1 || host[0] != '*') { - addr = nxt_inet_addr(host, length); - - if (addr == INADDR_NONE) { - jbs->resolve.name.length = length; - jbs->resolve.name.start = host; - jbs->resolve.port = (in_port_t) port; - - nxt_job_resolve(&jbs->resolve); - return NXT_AGAIN; - } - - /* "x.x.x.x:XX" */ - } - } - - mp = jbs->resolve.job.mem_pool; - - jbs->resolve.sockaddrs = nxt_mp_alloc(mp, sizeof(void *)); - if (nxt_slow_path(jbs->resolve.sockaddrs == NULL)) { - return NXT_ERROR; - } - - sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in), - NXT_INET_ADDR_STR_LEN); - - if (nxt_fast_path(sa != NULL)) { - jbs->resolve.count = 1; - jbs->resolve.sockaddrs[0] = sa; - - jbs->wildcard = (addr == INADDR_ANY); - - sa->u.sockaddr_in.sin_family = AF_INET; - sa->u.sockaddr_in.sin_port = (in_port_t) port; - sa->u.sockaddr_in.sin_addr.s_addr = addr; - - return NXT_OK; - } - - return NXT_ERROR; - -invalid_port: - - nxt_thread_log_error(jbs->resolve.log_level, - "invalid port in \"%V\"", &jbs->addr); - - return NXT_ERROR; -} - - in_addr_t nxt_inet_addr(u_char *buf, size_t length) { diff --git a/src/nxt_sockaddr.h b/src/nxt_sockaddr.h index a8f1b393..0f96f6dd 100644 --- a/src/nxt_sockaddr.h +++ b/src/nxt_sockaddr.h @@ -58,15 +58,6 @@ struct nxt_sockaddr_s { }; -typedef struct { - nxt_job_resolve_t resolve; - nxt_str_t addr; - - uint8_t wildcard; /* 1 bit */ - uint8_t no_port; /* 1 bit */ -} nxt_job_sockaddr_parse_t; - - nxt_sockaddr_t *nxt_sockaddr_cache_alloc(nxt_event_engine_t *engine, nxt_listen_socket_t *ls); void nxt_sockaddr_cache_free(nxt_event_engine_t *engine, nxt_conn_t *c); @@ -88,12 +79,9 @@ NXT_EXPORT void nxt_sockaddr_text(nxt_sockaddr_t *sa); NXT_EXPORT uint32_t nxt_sockaddr_port_number(nxt_sockaddr_t *sa); NXT_EXPORT nxt_bool_t nxt_sockaddr_cmp(nxt_sockaddr_t *sa1, nxt_sockaddr_t *sa2); -NXT_EXPORT size_t nxt_sockaddr_ntop(nxt_sockaddr_t *sa, u_char *buf, - u_char *end, nxt_bool_t port); NXT_EXPORT nxt_sockaddr_t *nxt_sockaddr_parse(nxt_mp_t *mp, nxt_str_t *addr); NXT_EXPORT nxt_sockaddr_t *nxt_sockaddr_parse_optport(nxt_mp_t *mp, nxt_str_t *addr); -NXT_EXPORT void nxt_job_sockaddr_parse(nxt_job_sockaddr_parse_t *jbs); NXT_EXPORT in_addr_t nxt_inet_addr(u_char *buf, size_t len); #if (NXT_INET6) NXT_EXPORT nxt_int_t nxt_inet6_addr(struct in6_addr *in6_addr, u_char *buf, diff --git a/src/nxt_status.c b/src/nxt_status.c new file mode 100644 index 00000000..f8002e86 --- /dev/null +++ b/src/nxt_status.c @@ -0,0 +1,105 @@ + +/* + * Copyright (C) NGINX, Inc. + */ + +#include <nxt_main.h> +#include <nxt_conf.h> +#include <nxt_status.h> + + +nxt_conf_value_t * +nxt_status_get(nxt_status_report_t *report, nxt_mp_t *mp) +{ + size_t i; + nxt_str_t name; + nxt_int_t ret; + nxt_status_app_t *app; + nxt_conf_value_t *status, *obj, *apps, *app_obj; + + static nxt_str_t conns_str = nxt_string("connections"); + static nxt_str_t acc_str = nxt_string("accepted"); + static nxt_str_t active_str = nxt_string("active"); + static nxt_str_t idle_str = nxt_string("idle"); + static nxt_str_t closed_str = nxt_string("closed"); + static nxt_str_t reqs_str = nxt_string("requests"); + static nxt_str_t total_str = nxt_string("total"); + static nxt_str_t apps_str = nxt_string("applications"); + static nxt_str_t procs_str = nxt_string("processes"); + static nxt_str_t run_str = nxt_string("running"); + static nxt_str_t start_str = nxt_string("starting"); + + status = nxt_conf_create_object(mp, 3); + if (nxt_slow_path(status == NULL)) { + return NULL; + } + + obj = nxt_conf_create_object(mp, 4); + if (nxt_slow_path(obj == NULL)) { + return NULL; + } + + nxt_conf_set_member(status, &conns_str, obj, 0); + + nxt_conf_set_member_integer(obj, &acc_str, report->accepted_conns, 0); + nxt_conf_set_member_integer(obj, &active_str, report->accepted_conns + - report->closed_conns + - report->idle_conns, 1); + nxt_conf_set_member_integer(obj, &idle_str, report->idle_conns, 2); + nxt_conf_set_member_integer(obj, &closed_str, report->closed_conns, 3); + + obj = nxt_conf_create_object(mp, 1); + if (nxt_slow_path(obj == NULL)) { + return NULL; + } + + nxt_conf_set_member(status, &reqs_str, obj, 1); + + nxt_conf_set_member_integer(obj, &total_str, report->requests, 0); + + apps = nxt_conf_create_object(mp, report->apps_count); + if (nxt_slow_path(apps == NULL)) { + return NULL; + } + + nxt_conf_set_member(status, &apps_str, apps, 2); + + for (i = 0; i < report->apps_count; i++) { + app = &report->apps[i]; + + app_obj = nxt_conf_create_object(mp, 2); + if (nxt_slow_path(app_obj == NULL)) { + return NULL; + } + + name.length = app->name.length; + name.start = nxt_pointer_to(report, (uintptr_t) app->name.start); + + ret = nxt_conf_set_member_dup(apps, mp, &name, app_obj, i); + if (nxt_slow_path(ret != NXT_OK)) { + return NULL; + } + + obj = nxt_conf_create_object(mp, 3); + if (nxt_slow_path(obj == NULL)) { + return NULL; + } + + nxt_conf_set_member(app_obj, &procs_str, obj, 0); + + nxt_conf_set_member_integer(obj, &run_str, app->processes, 0); + nxt_conf_set_member_integer(obj, &start_str, app->pending_processes, 1); + nxt_conf_set_member_integer(obj, &idle_str, app->idle_processes, 2); + + obj = nxt_conf_create_object(mp, 1); + if (nxt_slow_path(obj == NULL)) { + return NULL; + } + + nxt_conf_set_member(app_obj, &reqs_str, obj, 1); + + nxt_conf_set_member_integer(obj, &active_str, app->active_requests, 0); + } + + return status; +} diff --git a/src/nxt_status.h b/src/nxt_status.h new file mode 100644 index 00000000..a99ac7d0 --- /dev/null +++ b/src/nxt_status.h @@ -0,0 +1,33 @@ + +/* + * Copyright (C) NGINX, Inc. + */ + +#ifndef _NXT_STATUS_H_INCLUDED_ +#define _NXT_STATUS_H_INCLUDED_ + + +typedef struct { + nxt_str_t name; + uint32_t active_requests; + uint32_t pending_processes; + uint32_t processes; + uint32_t idle_processes; +} nxt_status_app_t; + + +typedef struct { + uint64_t accepted_conns; + uint64_t idle_conns; + uint64_t closed_conns; + uint64_t requests; + + size_t apps_count; + nxt_status_app_t apps[]; +} nxt_status_report_t; + + +nxt_conf_value_t *nxt_status_get(nxt_status_report_t *report, nxt_mp_t *mp); + + +#endif /* _NXT_STATUS_H_INCLUDED_ */ diff --git a/src/nxt_string.c b/src/nxt_string.c index b7aef79e..4d89c23c 100644 --- a/src/nxt_string.c +++ b/src/nxt_string.c @@ -338,7 +338,7 @@ nxt_rmemstrn(const u_char *s, const u_char *end, const char *ss, size_t length) size_t -nxt_str_strip(u_char *start, u_char *end) +nxt_str_strip(const u_char *start, u_char *end) { u_char *p; diff --git a/src/nxt_string.h b/src/nxt_string.h index 80cdbb59..a8673c61 100644 --- a/src/nxt_string.h +++ b/src/nxt_string.h @@ -96,7 +96,7 @@ NXT_EXPORT u_char *nxt_memcasestrn(const u_char *s, const u_char *end, const char *ss, size_t length); NXT_EXPORT u_char *nxt_rmemstrn(const u_char *s, const u_char *end, const char *ss, size_t length); -NXT_EXPORT size_t nxt_str_strip(u_char *start, u_char *end); +NXT_EXPORT size_t nxt_str_strip(const u_char *start, u_char *end); typedef struct { diff --git a/src/nxt_time_parse.c b/src/nxt_time_parse.c index 94c43289..63620b09 100644 --- a/src/nxt_time_parse.c +++ b/src/nxt_time_parse.c @@ -22,7 +22,7 @@ nxt_time_parse(const u_char *p, size_t len) nxt_uint_t year, days; const u_char *end; - static nxt_int_t mday[12] = { + static const nxt_int_t mday[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; diff --git a/src/nxt_unit.c b/src/nxt_unit.c index 32bb07ab..e5cb0b58 100644 --- a/src/nxt_unit.c +++ b/src/nxt_unit.c @@ -196,7 +196,8 @@ static int nxt_unit_request_hash_add(nxt_unit_ctx_t *ctx, static nxt_unit_request_info_t *nxt_unit_request_hash_find( nxt_unit_ctx_t *ctx, uint32_t stream, int remove); -static char * nxt_unit_snprint_prefix(char *p, char *end, pid_t pid, int level); +static char * nxt_unit_snprint_prefix(char *p, const char *end, pid_t pid, + int level); static void *nxt_unit_lvlhsh_alloc(void *data, size_t size); static void nxt_unit_lvlhsh_free(void *data, void *p); static int nxt_unit_memcasecmp(const void *p1, const void *p2, size_t length); @@ -584,9 +585,14 @@ fail: static nxt_unit_impl_t * nxt_unit_create(nxt_unit_init_t *init) { - int rc; - nxt_unit_impl_t *lib; - nxt_unit_callbacks_t *cb; + int rc; + nxt_unit_impl_t *lib; + + if (nxt_slow_path(init->callbacks.request_handler == NULL)) { + nxt_unit_alert(NULL, "request_handler is NULL"); + + return NULL; + } lib = nxt_unit_malloc(NULL, sizeof(nxt_unit_impl_t) + init->request_data_size); @@ -629,15 +635,6 @@ nxt_unit_create(nxt_unit_init_t *init) goto fail; } - cb = &lib->callbacks; - - if (cb->request_handler == NULL) { - nxt_unit_alert(NULL, "request_handler is NULL"); - - pthread_mutex_destroy(&lib->mutex); - goto fail; - } - nxt_unit_mmaps_init(&lib->incoming); nxt_unit_mmaps_init(&lib->outgoing); @@ -942,7 +939,6 @@ nxt_unit_ready(nxt_unit_ctx_t *ctx, int ready_fd, uint32_t stream, int queue_fd) msg.mmap = 0; msg.nf = 0; msg.mf = 0; - msg.tracking = 0; nxt_socket_msg_oob_init(&oob, fds); @@ -2644,7 +2640,6 @@ nxt_unit_mmap_buf_send(nxt_unit_request_info_t *req, m.msg.mmap = hdr != NULL && m.mmap_msg.size > 0; m.msg.nf = 0; m.msg.mf = 0; - m.msg.tracking = 0; rc = NXT_UNIT_ERROR; @@ -3077,7 +3072,6 @@ nxt_unit_request_read(nxt_unit_request_info_t *req, void *dst, size_t size) } req->content_length -= res; - size -= res; dst = nxt_pointer_to(dst, res); @@ -3296,7 +3290,6 @@ skip_response_send: msg.mmap = 0; msg.nf = 0; msg.mf = 0; - msg.tracking = 0; (void) nxt_unit_port_send(req->ctx, req->response_port, &msg, sizeof(msg), NULL); @@ -3619,7 +3612,6 @@ nxt_unit_send_oosm(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port) msg.mmap = 0; msg.nf = 0; msg.mf = 0; - msg.tracking = 0; res = nxt_unit_port_send(ctx, lib->router_port, &msg, sizeof(msg), NULL); if (nxt_slow_path(res != sizeof(msg))) { @@ -3816,13 +3808,12 @@ static int nxt_unit_shm_open(nxt_unit_ctx_t *ctx, size_t size) { int fd; - nxt_unit_impl_t *lib; - - lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); #if (NXT_HAVE_MEMFD_CREATE || NXT_HAVE_SHM_OPEN) char name[64]; + nxt_unit_impl_t *lib; + lib = nxt_container_of(ctx->unit, nxt_unit_impl_t, unit); snprintf(name, sizeof(name), NXT_SHM_PREFIX "unit.%d.%p", lib->pid, (void *) (uintptr_t) pthread_self()); #endif @@ -3905,7 +3896,6 @@ nxt_unit_send_mmap(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port, int fd) msg.mmap = 0; msg.nf = 0; msg.mf = 0; - msg.tracking = 0; nxt_socket_msg_oob_init(&oob, fds); @@ -4390,7 +4380,6 @@ nxt_unit_send_shm_ack(nxt_unit_ctx_t *ctx, pid_t pid) msg.mmap = 0; msg.nf = 0; msg.mf = 0; - msg.tracking = 0; res = nxt_unit_port_send(ctx, lib->router_port, &msg, sizeof(msg), NULL); if (nxt_slow_path(res != sizeof(msg))) { @@ -5356,7 +5345,6 @@ nxt_unit_send_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *dst, m.msg.mmap = 0; m.msg.nf = 0; m.msg.mf = 0; - m.msg.tracking = 0; m.new_port.id = port->id.id; m.new_port.pid = port->id.pid; @@ -6673,7 +6661,7 @@ static const char * nxt_unit_log_levels[] = { static char * -nxt_unit_snprint_prefix(char *p, char *end, pid_t pid, int level) +nxt_unit_snprint_prefix(char *p, const char *end, pid_t pid, int level) { struct tm tm; struct timespec ts; diff --git a/src/nxt_unix.h b/src/nxt_unix.h index d8eaabc3..6bc6be5e 100644 --- a/src/nxt_unix.h +++ b/src/nxt_unix.h @@ -156,9 +156,7 @@ #include <setjmp.h> #include <sched.h> #include <signal.h> -#if (NXT_HAVE_POSIX_SPAWN) #include <spawn.h> -#endif #include <stdarg.h> #include <stddef.h> /* offsetof() */ #include <stdio.h> diff --git a/src/nxt_var.c b/src/nxt_var.c index 0a722d17..f55a2d30 100644 --- a/src/nxt_var.c +++ b/src/nxt_var.c @@ -9,7 +9,7 @@ struct nxt_var_s { size_t length; nxt_uint_t vars; - uint8_t strz; /* 1 bit */ + nxt_var_flags_t flags; u_char data[]; /* @@ -26,19 +26,12 @@ typedef struct { } nxt_var_sub_t; -typedef struct { - nxt_var_t *var; - nxt_str_t *value; -} nxt_var_value_t; - - struct nxt_var_query_s { - nxt_array_t values; /* of nxt_var_value_t */ - nxt_array_t parts; /* of nxt_str_t * */ + nxt_mp_t *pool; nxt_lvlhsh_t cache; - nxt_str_t *spare; + nxt_uint_t waiting; nxt_uint_t failed; /* 1 bit */ @@ -59,16 +52,18 @@ struct nxt_var_query_s { static nxt_int_t nxt_var_hash_test(nxt_lvlhsh_query_t *lhq, void *data); static nxt_var_decl_t *nxt_var_hash_find(nxt_str_t *name); +static nxt_var_decl_t *nxt_var_decl_get(nxt_str_t *name, nxt_array_t *fields, + uint32_t *index); +static nxt_var_field_t *nxt_var_field_add(nxt_array_t *fields, nxt_str_t *name, + uint32_t hash); + static nxt_int_t nxt_var_cache_test(nxt_lvlhsh_query_t *lhq, void *data); -static nxt_str_t *nxt_var_cache_find(nxt_lvlhsh_t *lh, uint32_t index); -static nxt_int_t nxt_var_cache_add(nxt_lvlhsh_t *lh, uint32_t index, - nxt_str_t *value, nxt_mp_t *mp); +static nxt_str_t *nxt_var_cache_value(nxt_task_t *task, nxt_var_query_t *query, + uint32_t index); static u_char *nxt_var_next_part(u_char *start, size_t length, nxt_str_t *part, nxt_bool_t *is_var); -static void nxt_var_query_finish(nxt_task_t *task, nxt_var_query_t *query); - static const nxt_lvlhsh_proto_t nxt_var_hash_proto nxt_aligned(64) = { NXT_LVLHSH_DEFAULT, @@ -91,21 +86,6 @@ static uint32_t nxt_var_count; static nxt_var_handler_t *nxt_var_index; -void -nxt_var_raw(nxt_var_t *var, nxt_str_t *str) -{ - str->length = var->length; - str->start = nxt_var_raw_start(var); -} - - -nxt_bool_t -nxt_var_is_const(nxt_var_t *var) -{ - return (var->vars == 0); -} - - static nxt_int_t nxt_var_hash_test(nxt_lvlhsh_query_t *lhq, void *data) { @@ -134,46 +114,166 @@ nxt_var_hash_find(nxt_str_t *name) } -static nxt_int_t -nxt_var_cache_test(nxt_lvlhsh_query_t *lhq, void *data) +static nxt_var_decl_t * +nxt_var_decl_get(nxt_str_t *name, nxt_array_t *fields, uint32_t *index) { - return NXT_OK; + u_char *p, *end; + int64_t hash; + uint16_t field; + nxt_str_t str; + nxt_var_decl_t *decl; + nxt_var_field_t *f; + + f = NULL; + field = 0; + decl = nxt_var_hash_find(name); + + if (decl == NULL) { + p = name->start; + end = p + name->length; + + while (p < end) { + if (*p++ == '_') { + break; + } + } + + if (p == end) { + return NULL; + } + + str.start = name->start; + str.length = p - 1 - name->start; + + decl = nxt_var_hash_find(&str); + + if (decl != NULL) { + str.start = p; + str.length = end - p; + + hash = decl->field_hash(fields->mem_pool, &str); + if (nxt_slow_path(hash == -1)) { + return NULL; + } + + f = nxt_var_field_add(fields, &str, (uint32_t) hash); + if (nxt_slow_path(f == NULL)) { + return NULL; + } + + field = f->index; + } + } + + if (decl != NULL) { + if (decl->field_hash != NULL && f == NULL) { + return NULL; + } + + if (index != NULL) { + *index = (decl->index << 16) | field; + } + } + + return decl; } -static nxt_str_t * -nxt_var_cache_find(nxt_lvlhsh_t *lh, uint32_t index) +static nxt_var_field_t * +nxt_var_field_add(nxt_array_t *fields, nxt_str_t *name, uint32_t hash) { - nxt_lvlhsh_query_t lhq; + nxt_uint_t i; + nxt_var_field_t *field; - lhq.key_hash = nxt_murmur_hash2_uint32(&index); - lhq.key.length = sizeof(uint32_t); - lhq.key.start = (u_char *) &index; - lhq.proto = &nxt_var_cache_proto; + field = fields->elts; - if (nxt_lvlhsh_find(lh, &lhq) != NXT_OK) { + for (i = 0; i < fields->nelts; i++) { + if (field[i].hash == hash + && nxt_strstr_eq(&field[i].name, name)) + { + return field; + } + } + + field = nxt_array_add(fields); + if (nxt_slow_path(field == NULL)) { return NULL; } - return lhq.value; + field->name = *name; + field->hash = hash; + field->index = fields->nelts - 1; + + return field; +} + + +nxt_var_field_t * +nxt_var_field_get(nxt_array_t *fields, uint16_t index) +{ + nxt_uint_t nfields; + nxt_var_field_t *field; + + field = fields->elts; + nfields = fields->nelts; + + if (nfields > 0 && index <= nfields) { + return &field[index]; + } + + return NULL; } static nxt_int_t -nxt_var_cache_add(nxt_lvlhsh_t *lh, uint32_t index, nxt_str_t *value, - nxt_mp_t *mp) +nxt_var_cache_test(nxt_lvlhsh_query_t *lhq, void *data) { + return NXT_OK; +} + + +static nxt_str_t * +nxt_var_cache_value(nxt_task_t *task, nxt_var_query_t *query, uint32_t index) +{ + nxt_int_t ret; + nxt_str_t *value; nxt_lvlhsh_query_t lhq; + value = query->spare; + + if (value == NULL) { + value = nxt_mp_zget(query->pool, sizeof(nxt_str_t)); + if (nxt_slow_path(value == NULL)) { + return NULL; + } + + query->spare = value; + } + lhq.key_hash = nxt_murmur_hash2_uint32(&index); lhq.replace = 0; lhq.key.length = sizeof(uint32_t); lhq.key.start = (u_char *) &index; lhq.value = value; lhq.proto = &nxt_var_cache_proto; - lhq.pool = mp; + lhq.pool = query->pool; - return nxt_lvlhsh_insert(lh, &lhq); + ret = nxt_lvlhsh_insert(&query->cache, &lhq); + if (nxt_slow_path(ret == NXT_ERROR)) { + return NULL; + } + + if (ret == NXT_OK) { + ret = nxt_var_index[index >> 16](task, value, query->ctx, + index & 0xffff); + if (nxt_slow_path(ret != NXT_OK)) { + return NULL; + } + + query->spare = NULL; + } + + return lhq.value; } @@ -230,10 +330,13 @@ nxt_var_index_init(void) nxt_var_t * -nxt_var_compile(nxt_str_t *str, nxt_mp_t *mp, nxt_bool_t strz) +nxt_var_compile(nxt_str_t *str, nxt_mp_t *mp, nxt_array_t *fields, + nxt_var_flags_t flags) { u_char *p, *end, *next, *src; size_t size; + uint32_t index; + nxt_bool_t strz; nxt_var_t *var; nxt_str_t part; nxt_uint_t n; @@ -241,6 +344,8 @@ nxt_var_compile(nxt_str_t *str, nxt_mp_t *mp, nxt_bool_t strz) nxt_var_sub_t *subs; nxt_var_decl_t *decl; + strz = (flags & NXT_VAR_STRZ) != 0; + n = 0; p = str->start; @@ -266,7 +371,7 @@ nxt_var_compile(nxt_str_t *str, nxt_mp_t *mp, nxt_bool_t strz) var->length = str->length; var->vars = n; - var->strz = strz; + var->flags = flags; subs = nxt_var_subs(var); src = nxt_var_raw_start(var); @@ -284,12 +389,12 @@ nxt_var_compile(nxt_str_t *str, nxt_mp_t *mp, nxt_bool_t strz) next = nxt_var_next_part(p, end - p, &part, &is_var); if (is_var) { - decl = nxt_var_hash_find(&part); + decl = nxt_var_decl_get(&part, fields, &index); if (nxt_slow_path(decl == NULL)) { return NULL; } - subs[n].index = decl->index; + subs[n].index = index; subs[n].length = next - p; subs[n].position = p - str->start; @@ -304,7 +409,7 @@ nxt_var_compile(nxt_str_t *str, nxt_mp_t *mp, nxt_bool_t strz) nxt_int_t -nxt_var_test(nxt_str_t *str, u_char *error) +nxt_var_test(nxt_str_t *str, nxt_array_t *fields, u_char *error) { u_char *p, *end, *next; nxt_str_t part; @@ -325,7 +430,7 @@ nxt_var_test(nxt_str_t *str, u_char *error) } if (is_var) { - decl = nxt_var_hash_find(&part); + decl = nxt_var_decl_get(&part, fields, NULL); if (decl == NULL) { nxt_sprintf(error, error + NXT_MAX_ERROR_STR, @@ -420,6 +525,21 @@ nxt_var_next_part(u_char *start, size_t length, nxt_str_t *part, } +inline void +nxt_var_raw(nxt_var_t *var, nxt_str_t *str) +{ + str->length = var->length; + str->start = nxt_var_raw_start(var); +} + + +inline nxt_bool_t +nxt_var_is_const(nxt_var_t *var) +{ + return (var->vars == 0); +} + + nxt_int_t nxt_var_query_init(nxt_var_query_t **query_p, void *ctx, nxt_mp_t *mp) { @@ -432,14 +552,9 @@ nxt_var_query_init(nxt_var_query_t **query_p, void *ctx, nxt_mp_t *mp) if (nxt_slow_path(query == NULL)) { return NXT_ERROR; } - - nxt_array_init(&query->values, mp, sizeof(nxt_var_value_t)); - nxt_array_init(&query->parts, mp, sizeof(nxt_str_t *)); - - } else { - nxt_array_reset(&query->values); } + query->pool = mp; query->ctx = ctx; *query_p = query; @@ -452,13 +567,13 @@ void nxt_var_query(nxt_task_t *task, nxt_var_query_t *query, nxt_var_t *var, nxt_str_t *str) { - uint32_t index; - nxt_mp_t *mp; - nxt_str_t *value; - nxt_int_t ret; - nxt_uint_t i; - nxt_var_sub_t *subs; - nxt_var_value_t *val; + u_char *p, *src; + size_t length, last, next; + nxt_str_t *value, **part; + nxt_uint_t i; + nxt_bool_t strz, logging; + nxt_array_t parts; + nxt_var_sub_t *subs; if (nxt_var_is_const(var)) { nxt_var_raw(var, str); @@ -469,53 +584,74 @@ nxt_var_query(nxt_task_t *task, nxt_var_query_t *query, nxt_var_t *var, return; } - mp = query->values.mem_pool; + nxt_memzero(&parts, sizeof(nxt_array_t)); + nxt_array_init(&parts, query->pool, sizeof(nxt_str_t *)); + + strz = (var->flags & NXT_VAR_STRZ) != 0; + logging = (var->flags & NXT_VAR_LOGGING) != 0; + subs = nxt_var_subs(var); - value = query->spare; - for (i = 0; i < var->vars; i++) { + length = var->length; - if (value == NULL) { - value = nxt_mp_zget(mp, sizeof(nxt_str_t)); - if (nxt_slow_path(value == NULL)) { - goto fail; - } + for (i = 0; i < var->vars; i++) { + value = nxt_var_cache_value(task, query, subs[i].index); + if (nxt_slow_path(value == NULL)) { + goto fail; } - index = subs[i].index; + part = nxt_array_add(&parts); + if (nxt_slow_path(part == NULL)) { + goto fail; + } - ret = nxt_var_cache_add(&query->cache, index, value, mp); + *part = value; - if (ret != NXT_OK) { - if (nxt_slow_path(ret == NXT_ERROR)) { - goto fail; - } + length += value->length - subs[i].length; - continue; /* NXT_DECLINED */ + if (logging && value->start == NULL) { + length += 1; } + } - ret = nxt_var_index[index](task, query, value, query->ctx); + p = nxt_mp_nget(query->pool, length + strz); + if (nxt_slow_path(p == NULL)) { + goto fail; + } - value = NULL; + str->length = length; + str->start = p; - if (ret != NXT_OK) { - if (nxt_slow_path(ret != NXT_AGAIN)) { - goto fail; - } + part = parts.elts; + src = nxt_var_raw_start(var); + + last = 0; - query->waiting++; + for (i = 0; i < var->vars; i++) { + next = subs[i].position; + + if (next != last) { + p = nxt_cpymem(p, &src[last], next - last); } + + p = nxt_cpymem(p, part[i]->start, part[i]->length); + + if (logging && part[i]->start == NULL) { + *p++ = '-'; + } + + last = next + subs[i].length; } - query->spare = value; + if (last != var->length) { + p = nxt_cpymem(p, &src[last], var->length - last); + } - val = nxt_array_add(&query->values); - if (nxt_slow_path(val == NULL)) { - goto fail; + if (strz) { + *p = '\0'; } - val->var = var; - val->value = str; + nxt_debug(task, "var: \"%*s\" -> \"%V\"", length, src, str); return; @@ -534,7 +670,9 @@ nxt_var_query_resolve(nxt_task_t *task, nxt_var_query_t *query, void *data, query->error = error; if (query->waiting == 0) { - nxt_var_query_finish(task, query); + nxt_work_queue_add(&task->thread->engine->fast_work_queue, + query->failed ? query->error : query->ready, + task, query->ctx, query->data); } } @@ -546,94 +684,8 @@ nxt_var_query_handle(nxt_task_t *task, nxt_var_query_t *query, query->failed |= failed; if (--query->waiting == 0) { - nxt_var_query_finish(task, query); - } -} - - -static void -nxt_var_query_finish(nxt_task_t *task, nxt_var_query_t *query) -{ - u_char *p, *src; - size_t length, last, next; - nxt_str_t *str, **part; - nxt_var_t *var; - nxt_uint_t i, j; - nxt_var_sub_t *subs; - nxt_var_value_t *val; - - if (query->failed) { - goto done; + nxt_work_queue_add(&task->thread->engine->fast_work_queue, + query->failed ? query->error : query->ready, + task, query->ctx, query->data); } - - val = query->values.elts; - - for (i = 0; i < query->values.nelts; i++) { - var = val[i].var; - - subs = nxt_var_subs(var); - length = var->length; - - for (j = 0; j < var->vars; j++) { - str = nxt_var_cache_find(&query->cache, subs[j].index); - - nxt_assert(str != NULL); - - part = nxt_array_add(&query->parts); - - if (nxt_slow_path(part == NULL)) { - query->failed = 1; - goto done; - } - - *part = str; - - length += str->length - subs[j].length; - } - - p = nxt_mp_nget(query->values.mem_pool, length + var->strz); - if (nxt_slow_path(p == NULL)) { - query->failed = 1; - goto done; - } - - val[i].value->length = length; - val[i].value->start = p; - - part = query->parts.elts; - src = nxt_var_raw_start(var); - - last = 0; - - for (j = 0; j < var->vars; j++) { - next = subs[j].position; - - if (next != last) { - p = nxt_cpymem(p, &src[last], next - last); - } - - p = nxt_cpymem(p, part[j]->start, part[j]->length); - - last = next + subs[j].length; - } - - if (last != var->length) { - p = nxt_cpymem(p, &src[last], var->length - last); - } - - if (var->strz) { - *p = '\0'; - } - - nxt_array_reset(&query->parts); - - nxt_debug(task, "var: \"%*s\" -> \"%V\"", var->length, src, - val[i].value); - } - -done: - - nxt_work_queue_add(&task->thread->engine->fast_work_queue, - query->failed ? query->error : query->ready, - task, query->ctx, query->data); } diff --git a/src/nxt_var.h b/src/nxt_var.h index 3b7d0c28..cc7ff502 100644 --- a/src/nxt_var.h +++ b/src/nxt_var.h @@ -12,17 +12,32 @@ typedef struct nxt_var_query_s nxt_var_query_t; typedef nxt_int_t (*nxt_var_handler_t)(nxt_task_t *task, - nxt_var_query_t *query, nxt_str_t *str, - void *ctx); + void *ctx, uint16_t field); + +typedef int64_t (*nxt_var_field_hash_t)(nxt_mp_t *mp, nxt_str_t *str); typedef struct { - nxt_str_t name; - nxt_var_handler_t handler; - uint32_t index; + nxt_str_t name; + nxt_var_handler_t handler; + nxt_var_field_hash_t field_hash; + uint32_t index; } nxt_var_decl_t; +typedef struct { + nxt_str_t name; + uint16_t hash; + uint32_t index; +} nxt_var_field_t; + + +typedef enum { + NXT_VAR_STRZ = 1 << 0, + NXT_VAR_LOGGING = 1 << 1, +} nxt_var_flags_t; + + nxt_inline nxt_bool_t nxt_is_var(nxt_str_t *str) { @@ -30,13 +45,17 @@ nxt_is_var(nxt_str_t *str) } -void nxt_var_raw(nxt_var_t *var, nxt_str_t *str); -nxt_bool_t nxt_var_is_const(nxt_var_t *var); - nxt_int_t nxt_var_register(nxt_var_decl_t *decl, size_t n); nxt_int_t nxt_var_index_init(void); -nxt_var_t *nxt_var_compile(nxt_str_t *str, nxt_mp_t *mp, nxt_bool_t strz); -nxt_int_t nxt_var_test(nxt_str_t *str, u_char *error); + +nxt_var_field_t *nxt_var_field_get(nxt_array_t *fields, uint16_t index); + +nxt_var_t *nxt_var_compile(nxt_str_t *str, nxt_mp_t *mp, nxt_array_t *fields, + nxt_var_flags_t flags); +nxt_int_t nxt_var_test(nxt_str_t *str, nxt_array_t *fields, u_char *error); + +nxt_bool_t nxt_var_is_const(nxt_var_t *var); +void nxt_var_raw(nxt_var_t *var, nxt_str_t *str); nxt_int_t nxt_var_query_init(nxt_var_query_t **query_p, void *ctx, nxt_mp_t *mp); diff --git a/src/nxt_websocket_accept.c b/src/nxt_websocket_accept.c index 05cbcb56..0e2cef58 100644 --- a/src/nxt_websocket_accept.c +++ b/src/nxt_websocket_accept.c @@ -11,8 +11,8 @@ static void nxt_websocket_base64_encode(u_char *d, const uint8_t *s, size_t len) { - u_char c0, c1, c2; - static u_char basis[] = + u_char c0, c1, c2; + static const u_char basis[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; while (len > 2) { diff --git a/src/python/nxt_python_asgi.c b/src/python/nxt_python_asgi.c index 91af8f4b..4ad0857d 100644 --- a/src/python/nxt_python_asgi.c +++ b/src/python/nxt_python_asgi.c @@ -30,6 +30,8 @@ static void nxt_py_asgi_close_handler(nxt_unit_request_info_t *req); static PyObject *nxt_py_asgi_create_http_scope(nxt_unit_request_info_t *req); static PyObject *nxt_py_asgi_create_address(nxt_unit_sptr_t *sptr, uint8_t len, uint16_t port); +static PyObject *nxt_py_asgi_create_ip_address(nxt_unit_sptr_t *sptr, + uint8_t len, uint16_t port); static PyObject *nxt_py_asgi_create_header(nxt_unit_field_t *f); static PyObject *nxt_py_asgi_create_subprotocols(nxt_unit_field_t *f); @@ -736,6 +738,48 @@ fail: static PyObject * nxt_py_asgi_create_address(nxt_unit_sptr_t *sptr, uint8_t len, uint16_t port) { + size_t prefix_len; + nxt_str_t addr; + PyObject *pair, *v; + + addr.length = len; + addr.start = nxt_unit_sptr_get(sptr); + + prefix_len = nxt_length("unix:"); + if (!nxt_str_start(&addr, "unix:", prefix_len)) { + return nxt_py_asgi_create_ip_address(sptr, len, port); + } + +#if NXT_HAVE_UNIX_DOMAIN + pair = PyTuple_New(2); + if (nxt_slow_path(pair == NULL)) { + return NULL; + } + + addr.start += prefix_len; + addr.length -= prefix_len; + + v = PyString_FromStringAndSize((const char *) addr.start, addr.length); + if (nxt_slow_path(v == NULL)) { + Py_DECREF(pair); + + return NULL; + } + + PyTuple_SET_ITEM(pair, 0, v); + PyTuple_SET_ITEM(pair, 1, Py_None); + + return pair; + +#else + return NULL; +#endif +} + + +static PyObject * +nxt_py_asgi_create_ip_address(nxt_unit_sptr_t *sptr, uint8_t len, uint16_t port) +{ char *p, *s; PyObject *pair, *v; diff --git a/src/ruby/nxt_ruby.c b/src/ruby/nxt_ruby.c index 8f4afd35..f316d8a5 100644 --- a/src/ruby/nxt_ruby.c +++ b/src/ruby/nxt_ruby.c @@ -29,7 +29,6 @@ typedef struct { static nxt_int_t nxt_ruby_start(nxt_task_t *task, nxt_process_data_t *data); static VALUE nxt_ruby_init_basic(VALUE arg); -static VALUE nxt_ruby_script_basename(nxt_str_t *script); static VALUE nxt_ruby_hook_procs_load(VALUE path); static VALUE nxt_ruby_hook_register(VALUE arg); @@ -50,7 +49,7 @@ static void *nxt_ruby_thread_create_gvl(void *rctx); static VALUE nxt_ruby_thread_func(VALUE arg); static void *nxt_ruby_unit_run(void *ctx); static void nxt_ruby_ubf(void *ctx); -static int nxt_ruby_init_threads(VALUE script, nxt_ruby_app_conf_t *c); +static int nxt_ruby_init_threads(nxt_ruby_app_conf_t *c); static void nxt_ruby_join_threads(nxt_unit_ctx_t *ctx, nxt_ruby_app_conf_t *c); @@ -261,7 +260,7 @@ static nxt_int_t nxt_ruby_start(nxt_task_t *task, nxt_process_data_t *data) { int state, rc; - VALUE res, path, script; + VALUE res, path; nxt_ruby_ctx_t ruby_ctx; nxt_unit_ctx_t *unit_ctx; nxt_unit_init_t ruby_unit_init; @@ -271,6 +270,8 @@ nxt_ruby_start(nxt_task_t *task, nxt_process_data_t *data) static char *argv[2] = { (char *) "NGINX_Unit", (char *) "-e0" }; + signal(SIGINT, SIG_IGN); + conf = data->app; c = &conf->u.ruby; @@ -283,10 +284,7 @@ nxt_ruby_start(nxt_task_t *task, nxt_process_data_t *data) ruby_options(2, argv); ruby_script("NGINX_Unit"); - script = nxt_ruby_script_basename(&c->script); - ruby_ctx.env = Qnil; - ruby_ctx.script = script; ruby_ctx.io_input = Qnil; ruby_ctx.io_error = Qnil; ruby_ctx.thread = Qnil; @@ -356,7 +354,7 @@ nxt_ruby_start(nxt_task_t *task, nxt_process_data_t *data) goto fail; } - rc = nxt_ruby_init_threads(script, c); + rc = nxt_ruby_init_threads(c); if (nxt_slow_path(rc == NXT_UNIT_ERROR)) { goto fail; } @@ -381,8 +379,8 @@ nxt_ruby_start(nxt_task_t *task, nxt_process_data_t *data) } } - rc = (intptr_t) rb_thread_call_without_gvl(nxt_ruby_unit_run, unit_ctx, - nxt_ruby_ubf, unit_ctx); + rc = (intptr_t) rb_thread_call_without_gvl2(nxt_ruby_unit_run, unit_ctx, + nxt_ruby_ubf, unit_ctx); if (nxt_ruby_hook_procs != Qnil) { rb_protect(nxt_ruby_hook_call, nxt_rb_on_thread_shutdown, &state); @@ -425,37 +423,6 @@ fail: static VALUE -nxt_ruby_script_basename(nxt_str_t *script) -{ - size_t len; - u_char *p, *last; - - last = NULL; - p = script->start + script->length; - - while (p > script->start) { - - if (p[-1] == '/') { - last = p; - break; - } - - p--; - } - - if (last != NULL) { - len = script->length - (last - script->start); - - } else { - last = script->start; - len = script->length; - } - - return rb_str_new((const char *) last, len); -} - - -static VALUE nxt_ruby_init_basic(VALUE arg) { int state; @@ -598,7 +565,7 @@ nxt_ruby_rack_env_create(VALUE arg) rb_ary_push(version, UINT2NUM(NXT_RUBY_RACK_API_VERSION_MAJOR)); rb_ary_push(version, UINT2NUM(NXT_RUBY_RACK_API_VERSION_MINOR)); - rb_hash_aset(hash_env, rb_str_new2("SCRIPT_NAME"), rctx->script); + rb_hash_aset(hash_env, rb_str_new2("SCRIPT_NAME"), rb_str_new("", 0)); rb_hash_aset(hash_env, rb_str_new2("rack.version"), version); rb_hash_aset(hash_env, rb_str_new2("rack.input"), rctx->io_input); rb_hash_aset(hash_env, rb_str_new2("rack.errors"), rctx->io_error); @@ -1393,7 +1360,7 @@ nxt_ruby_ubf(void *ctx) static int -nxt_ruby_init_threads(VALUE script, nxt_ruby_app_conf_t *c) +nxt_ruby_init_threads(nxt_ruby_app_conf_t *c) { int state; uint32_t i; @@ -1415,7 +1382,6 @@ nxt_ruby_init_threads(VALUE script, nxt_ruby_app_conf_t *c) rctx = &nxt_ruby_ctxs[i]; rctx->env = Qnil; - rctx->script = script; rctx->io_input = Qnil; rctx->io_error = Qnil; rctx->thread = Qnil; diff --git a/src/ruby/nxt_ruby.h b/src/ruby/nxt_ruby.h index 3bdd567a..26430021 100644 --- a/src/ruby/nxt_ruby.h +++ b/src/ruby/nxt_ruby.h @@ -22,7 +22,6 @@ typedef struct { VALUE env; - VALUE script; VALUE io_input; VALUE io_error; VALUE thread; |