summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorAndrei Belov <defan@nginx.com>2021-08-19 18:17:12 +0300
committerAndrei Belov <defan@nginx.com>2021-08-19 18:17:12 +0300
commitdb442f1be7e713e6a219621ff97a51046590dbd6 (patch)
tree913734275bc890ec175e51fcb0f36b01a3c52c24 /src
parenta1d2ced6fc2317d36bc917c5d0ac339bc647dc34 (diff)
parent13c0025dfa6e041563d0ad5dd81679b44522694c (diff)
downloadunit-db442f1be7e713e6a219621ff97a51046590dbd6.tar.gz
unit-db442f1be7e713e6a219621ff97a51046590dbd6.tar.bz2
Merged with the default branch.1.25.0-1
Diffstat (limited to 'src')
-rw-r--r--src/nxt_application.h1
-rw-r--r--src/nxt_buf.c2
-rw-r--r--src/nxt_buf.h6
-rw-r--r--src/nxt_conf_validation.c174
-rw-r--r--src/nxt_controller.c161
-rw-r--r--src/nxt_event_engine.c3
-rwxr-xr-xsrc/nxt_h1proto.c1
-rw-r--r--src/nxt_http.h73
-rw-r--r--src/nxt_http_chunk_parse.c1
-rw-r--r--src/nxt_http_proxy.c19
-rw-r--r--src/nxt_http_request.c154
-rw-r--r--src/nxt_http_return.c83
-rw-r--r--src/nxt_http_route.c246
-rw-r--r--src/nxt_http_route_addr.c19
-rw-r--r--src/nxt_http_static.c219
-rw-r--r--src/nxt_isolation.c4
-rw-r--r--src/nxt_log.h22
-rw-r--r--src/nxt_main_process.c7
-rw-r--r--src/nxt_openssl.c367
-rw-r--r--src/nxt_port.h3
-rw-r--r--src/nxt_port_socket.c56
-rw-r--r--src/nxt_router.c449
-rw-r--r--src/nxt_router.h11
-rw-r--r--src/nxt_sockaddr.c160
-rw-r--r--src/nxt_sockaddr.h3
-rw-r--r--src/nxt_tls.h36
-rw-r--r--src/nxt_upstream.c4
-rw-r--r--src/python/nxt_python.c8
-rw-r--r--src/python/nxt_python.h2
-rw-r--r--src/python/nxt_python_asgi.c28
-rw-r--r--src/python/nxt_python_asgi_http.c132
-rw-r--r--src/python/nxt_python_wsgi.c4
-rw-r--r--src/ruby/nxt_ruby.c155
33 files changed, 2013 insertions, 600 deletions
diff --git a/src/nxt_application.h b/src/nxt_application.h
index 45e7fa48..6fbdc4be 100644
--- a/src/nxt_application.h
+++ b/src/nxt_application.h
@@ -74,6 +74,7 @@ typedef struct {
typedef struct {
nxt_str_t script;
uint32_t threads;
+ nxt_str_t hooks;
} nxt_ruby_app_conf_t;
diff --git a/src/nxt_buf.c b/src/nxt_buf.c
index 83be0fac..cbde069e 100644
--- a/src/nxt_buf.c
+++ b/src/nxt_buf.c
@@ -201,7 +201,6 @@ nxt_buf_completion(nxt_task_t *task, void *obj, void *data)
nxt_buf_t *b, *next, *parent;
b = obj;
- parent = data;
nxt_debug(task, "buf completion: %p %p", b, b->mem.start);
@@ -275,7 +274,6 @@ nxt_buf_ts_completion(nxt_task_t *task, void *obj, void *data)
nxt_buf_t *b, *next, *parent;
b = obj;
- parent = data;
if (nxt_buf_ts_handle(task, obj, data)) {
return;
diff --git a/src/nxt_buf.h b/src/nxt_buf.h
index 25e8499a..5121d659 100644
--- a/src/nxt_buf.h
+++ b/src/nxt_buf.h
@@ -288,4 +288,10 @@ nxt_buf_cpystr(nxt_buf_t *b, const nxt_str_t *str)
}
+nxt_inline void
+nxt_buf_dummy_completion(nxt_task_t *task, void *obj, void *data)
+{
+}
+
+
#endif /* _NXT_BUF_H_INCLIDED_ */
diff --git a/src/nxt_conf_validation.c b/src/nxt_conf_validation.c
index 06ae2847..a53fff74 100644
--- a/src/nxt_conf_validation.c
+++ b/src/nxt_conf_validation.c
@@ -95,6 +95,16 @@ static nxt_int_t nxt_conf_vldt_object_conf_commands(nxt_conf_validation_t *vldt,
#endif
static nxt_int_t nxt_conf_vldt_certificate_element(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value);
+static nxt_int_t nxt_conf_vldt_tls_cache_size(nxt_conf_validation_t *vldt,
+ nxt_conf_value_t *value, void *data);
+static nxt_int_t nxt_conf_vldt_tls_timeout(nxt_conf_validation_t *vldt,
+ nxt_conf_value_t *value, void *data);
+#if (NXT_HAVE_OPENSSL_TLSEXT)
+static nxt_int_t nxt_conf_vldt_ticket_key(nxt_conf_validation_t *vldt,
+ nxt_conf_value_t *value, void *data);
+static nxt_int_t nxt_conf_vldt_ticket_key_element(nxt_conf_validation_t *vldt,
+ nxt_conf_value_t *value);
+#endif
#endif
static nxt_int_t nxt_conf_vldt_action(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value, void *data);
@@ -204,8 +214,10 @@ 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_client_ip_members[];
#if (NXT_TLS)
static nxt_conf_vldt_object_t nxt_conf_vldt_tls_members[];
+static nxt_conf_vldt_object_t nxt_conf_vldt_session_members[];
#endif
static nxt_conf_vldt_object_t nxt_conf_vldt_match_members[];
static nxt_conf_vldt_object_t nxt_conf_vldt_python_target_members[];
@@ -346,6 +358,11 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_listener_members[] = {
.name = nxt_string("application"),
.type = NXT_CONF_VLDT_STRING,
.validator = nxt_conf_vldt_app_name,
+ }, {
+ .name = nxt_string("client_ip"),
+ .type = NXT_CONF_VLDT_OBJECT,
+ .validator = nxt_conf_vldt_object,
+ .u.members = nxt_conf_vldt_client_ip_members
},
#if (NXT_TLS)
@@ -361,6 +378,25 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_listener_members[] = {
};
+static nxt_conf_vldt_object_t nxt_conf_vldt_client_ip_members[] = {
+ {
+ .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("header"),
+ .type = NXT_CONF_VLDT_STRING,
+ .flags = NXT_CONF_VLDT_REQUIRED
+ }, {
+ .name = nxt_string("recursive"),
+ .type = NXT_CONF_VLDT_BOOLEAN,
+ },
+
+ NXT_CONF_VLDT_END
+};
+
+
#if (NXT_TLS)
static nxt_conf_vldt_object_t nxt_conf_vldt_tls_members[] = {
@@ -378,11 +414,132 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_tls_members[] = {
.validator = nxt_conf_vldt_unsupported,
.u.string = "conf_commands",
#endif
+ }, {
+ .name = nxt_string("session"),
+ .type = NXT_CONF_VLDT_OBJECT,
+ .validator = nxt_conf_vldt_object,
+ .u.members = nxt_conf_vldt_session_members,
+ },
+
+ NXT_CONF_VLDT_END
+};
+
+
+static nxt_conf_vldt_object_t nxt_conf_vldt_session_members[] = {
+ {
+ .name = nxt_string("cache_size"),
+ .type = NXT_CONF_VLDT_INTEGER,
+ .validator = nxt_conf_vldt_tls_cache_size,
+ }, {
+ .name = nxt_string("timeout"),
+ .type = NXT_CONF_VLDT_INTEGER,
+ .validator = nxt_conf_vldt_tls_timeout,
+ }, {
+ .name = nxt_string("tickets"),
+ .type = NXT_CONF_VLDT_STRING
+ | NXT_CONF_VLDT_ARRAY
+ | NXT_CONF_VLDT_BOOLEAN,
+#if (NXT_HAVE_OPENSSL_TLSEXT)
+ .validator = nxt_conf_vldt_ticket_key,
+#else
+ .validator = nxt_conf_vldt_unsupported,
+ .u.string = "tickets",
+#endif
},
NXT_CONF_VLDT_END
};
+
+static nxt_int_t
+nxt_conf_vldt_tls_cache_size(nxt_conf_validation_t *vldt,
+ nxt_conf_value_t *value, void *data)
+{
+ int64_t cache_size;
+
+ cache_size = nxt_conf_get_number(value);
+
+ if (cache_size < 0) {
+ return nxt_conf_vldt_error(vldt, "The \"cache_size\" number must not "
+ "be negative.");
+ }
+
+ return NXT_OK;
+}
+
+
+static nxt_int_t
+nxt_conf_vldt_tls_timeout(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
+ void *data)
+{
+ int64_t timeout;
+
+ timeout = nxt_conf_get_number(value);
+
+ if (timeout <= 0) {
+ return nxt_conf_vldt_error(vldt, "The \"timeout\" number must be "
+ "greater than zero.");
+ }
+
+ return NXT_OK;
+}
+
+#endif
+
+#if (NXT_HAVE_OPENSSL_TLSEXT)
+
+static nxt_int_t
+nxt_conf_vldt_ticket_key(nxt_conf_validation_t *vldt, nxt_conf_value_t *value,
+ void *data)
+{
+ if (nxt_conf_type(value) == NXT_CONF_BOOLEAN) {
+ return NXT_OK;
+ }
+
+ if (nxt_conf_type(value) == NXT_CONF_ARRAY) {
+ return nxt_conf_vldt_array_iterator(vldt, value,
+ &nxt_conf_vldt_ticket_key_element);
+ }
+
+ /* NXT_CONF_STRING */
+
+ return nxt_conf_vldt_ticket_key_element(vldt, value);
+}
+
+
+static nxt_int_t
+nxt_conf_vldt_ticket_key_element(nxt_conf_validation_t *vldt,
+ nxt_conf_value_t *value)
+{
+ nxt_str_t key;
+ nxt_int_t ret;
+
+ if (nxt_conf_type(value) != NXT_CONF_STRING) {
+ return nxt_conf_vldt_error(vldt, "The \"key\" array must "
+ "contain only string values.");
+ }
+
+ nxt_conf_get_string(value, &key);
+
+ ret = nxt_openssl_base64_decode(NULL, 0, key.start, key.length);
+ if (nxt_slow_path(ret == NXT_ERROR)) {
+ return NXT_ERROR;
+ }
+
+ if (ret == NXT_DECLINED) {
+ return nxt_conf_vldt_error(vldt, "Invalid Base64 format for the ticket "
+ "key \"%V\".", &key);
+ }
+
+ if (ret != 48 && ret != 80) {
+ return nxt_conf_vldt_error(vldt, "Invalid length %d of the ticket "
+ "key \"%V\". Must be 48 or 80 bytes.",
+ ret, &key);
+ }
+
+ return NXT_OK;
+}
+
#endif
@@ -732,6 +889,9 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_ruby_members[] = {
.name = nxt_string("threads"),
.type = NXT_CONF_VLDT_INTEGER,
.validator = nxt_conf_vldt_threads,
+ }, {
+ .name = nxt_string("hooks"),
+ .type = NXT_CONF_VLDT_STRING
},
NXT_CONF_VLDT_NEXT(nxt_conf_vldt_common_members)
@@ -1215,7 +1375,7 @@ static nxt_int_t
nxt_conf_vldt_mtypes_extension(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value)
{
- nxt_str_t ext, *dup_type;
+ nxt_str_t exten, *dup_type;
nxt_conf_vldt_mtypes_ctx_t *ctx;
ctx = vldt->ctx;
@@ -1225,24 +1385,24 @@ nxt_conf_vldt_mtypes_extension(nxt_conf_validation_t *vldt,
"contain only strings.", ctx->type);
}
- nxt_conf_get_string(value, &ext);
+ nxt_conf_get_string(value, &exten);
- if (ext.length == 0) {
+ if (exten.length == 0) {
return nxt_conf_vldt_error(vldt, "An empty file extension for "
"the \"%V\" MIME type.", ctx->type);
}
- dup_type = nxt_http_static_mtypes_hash_find(&ctx->hash, &ext);
+ dup_type = nxt_http_static_mtype_get(&ctx->hash, &exten);
if (dup_type->length != 0) {
return nxt_conf_vldt_error(vldt, "The \"%V\" file extension has been "
"declared for \"%V\" and \"%V\" "
"MIME types at the same time.",
- &ext, dup_type, ctx->type);
+ &exten, dup_type, ctx->type);
}
- return nxt_http_static_mtypes_hash_add(ctx->pool, &ctx->hash,
- &ext, ctx->type);
+ return nxt_http_static_mtypes_hash_add(ctx->pool, &ctx->hash, &exten,
+ ctx->type);
}
diff --git a/src/nxt_controller.c b/src/nxt_controller.c
index 772d10c8..779a625d 100644
--- a/src/nxt_controller.c
+++ b/src/nxt_controller.c
@@ -92,6 +92,10 @@ static nxt_bool_t nxt_controller_cert_in_use(nxt_str_t *name);
static void nxt_controller_cert_cleanup(nxt_task_t *task, void *obj,
void *data);
#endif
+static void nxt_controller_process_control(nxt_task_t *task,
+ nxt_controller_request_t *req, nxt_str_t *path);
+static void nxt_controller_app_restart_handler(nxt_task_t *task,
+ nxt_port_recv_msg_t *msg, void *data);
static void nxt_controller_conf_handler(nxt_task_t *task,
nxt_port_recv_msg_t *msg, void *data);
static void nxt_controller_conf_store(nxt_task_t *task,
@@ -1022,6 +1026,14 @@ nxt_controller_process_request(nxt_task_t *task, nxt_controller_request_t *req)
#endif
+ if (nxt_str_start(&path, "/control/", 9)) {
+ path.length -= 9;
+ path.start += 9;
+
+ nxt_controller_process_control(task, req, &path);
+ return;
+ }
+
nxt_memzero(&resp, sizeof(nxt_controller_response_t));
if (path.length == 1 && path.start[0] == '/') {
@@ -1684,6 +1696,155 @@ nxt_controller_conf_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
static void
+nxt_controller_process_control(nxt_task_t *task,
+ nxt_controller_request_t *req, nxt_str_t *path)
+{
+ uint32_t stream;
+ nxt_buf_t *b;
+ nxt_int_t rc;
+ nxt_port_t *router_port, *controller_port;
+ nxt_runtime_t *rt;
+ nxt_conf_value_t *value;
+ nxt_controller_response_t resp;
+
+ static nxt_str_t applications = nxt_string("applications");
+
+ nxt_memzero(&resp, sizeof(nxt_controller_response_t));
+
+ if (!nxt_str_eq(&req->parser.method, "GET", 3)) {
+ goto not_allowed;
+ }
+
+ if (!nxt_str_start(path, "applications/", 13)
+ || nxt_memcmp(path->start + path->length - 8, "/restart", 8) != 0)
+ {
+ goto not_found;
+ }
+
+ path->start += 13;
+ path->length -= 13 + 8;
+
+ if (nxt_controller_check_postpone_request(task)) {
+ nxt_queue_insert_tail(&nxt_controller_waiting_requests, &req->link);
+ return;
+ }
+
+ value = nxt_controller_conf.root;
+ if (value == NULL) {
+ goto not_found;
+ }
+
+ value = nxt_conf_get_object_member(value, &applications, NULL);
+ if (value == NULL) {
+ goto not_found;
+ }
+
+ value = nxt_conf_get_object_member(value, path, NULL);
+ if (value == NULL) {
+ goto not_found;
+ }
+
+ b = nxt_buf_mem_alloc(req->conn->mem_pool, path->length, 0);
+ if (nxt_slow_path(b == NULL)) {
+ goto alloc_fail;
+ }
+
+ b->mem.free = nxt_cpymem(b->mem.pos, path->start, path->length);
+
+ rt = task->thread->runtime;
+
+ controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER];
+ router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
+
+ stream = nxt_port_rpc_register_handler(task, controller_port,
+ nxt_controller_app_restart_handler,
+ nxt_controller_app_restart_handler,
+ router_port->pid, req);
+ if (nxt_slow_path(stream == 0)) {
+ goto alloc_fail;
+ }
+
+ rc = nxt_port_socket_write(task, router_port, NXT_PORT_MSG_APP_RESTART,
+ -1, stream, 0, b);
+ 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;
+
+not_allowed:
+
+ resp.status = 405;
+ resp.title = (u_char *) "Method isn't allowed.";
+ resp.offset = -1;
+
+ nxt_controller_response(task, req, &resp);
+ return;
+
+not_found:
+
+ resp.status = 404;
+ resp.title = (u_char *) "Value doesn't exist.";
+ resp.offset = -1;
+
+ nxt_controller_response(task, req, &resp);
+ return;
+
+alloc_fail:
+
+ resp.status = 500;
+ resp.title = (u_char *) "Memory allocation failed.";
+ resp.offset = -1;
+
+ nxt_controller_response(task, req, &resp);
+ return;
+
+fail:
+
+ resp.status = 500;
+ resp.title = (u_char *) "Send restart failed.";
+ resp.offset = -1;
+
+ nxt_controller_response(task, req, &resp);
+}
+
+
+static void
+nxt_controller_app_restart_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
+ void *data)
+{
+ nxt_controller_request_t *req;
+ nxt_controller_response_t resp;
+
+ req = data;
+
+ nxt_debug(task, "controller app restart handler");
+
+ nxt_queue_remove(&req->link);
+
+ nxt_memzero(&resp, sizeof(nxt_controller_response_t));
+
+ if (msg->port_msg.type == NXT_PORT_MSG_RPC_READY) {
+ resp.status = 200;
+ resp.title = (u_char *) "Ok";
+
+ } else {
+ resp.status = 500;
+ resp.title = (u_char *) "Failed to restart app.";
+ resp.offset = -1;
+ }
+
+ nxt_controller_response(task, req, &resp);
+
+ nxt_controller_flush_requests(task);
+}
+
+
+static void
nxt_controller_conf_store(nxt_task_t *task, nxt_conf_value_t *conf)
{
void *mem;
diff --git a/src/nxt_event_engine.c b/src/nxt_event_engine.c
index 4384d3b1..78c79bb1 100644
--- a/src/nxt_event_engine.c
+++ b/src/nxt_event_engine.c
@@ -720,11 +720,10 @@ nxt_event_engine_buf_mem_free(nxt_event_engine_t *engine, nxt_buf_t *b)
void
nxt_event_engine_buf_mem_completion(nxt_task_t *task, void *obj, void *data)
{
- nxt_event_engine_t *engine;
nxt_buf_t *b, *next, *parent;
+ nxt_event_engine_t *engine;
b = obj;
- parent = data;
nxt_debug(task, "buf completion: %p %p", b, b->mem.start);
diff --git a/src/nxt_h1proto.c b/src/nxt_h1proto.c
index d3da6942..b683cb22 100755
--- a/src/nxt_h1proto.c
+++ b/src/nxt_h1proto.c
@@ -955,7 +955,6 @@ nxt_h1p_request_body_read(nxt_task_t *task, nxt_http_request_t *r)
} else {
size = nxt_min(body_buffer_size, size);
b->mem.free = nxt_cpymem(b->mem.free, in->mem.pos, size);
- body_buffer_size -= size;
}
in->mem.pos += size;
diff --git a/src/nxt_http.h b/src/nxt_http.h
index f82d837e..3bc2fd61 100644
--- a/src/nxt_http.h
+++ b/src/nxt_http.h
@@ -197,8 +197,23 @@ struct nxt_http_request_s {
};
-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_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;
+
+
+typedef struct {
+ nxt_conf_value_t *pass;
+ nxt_conf_value_t *ret;
+ nxt_str_t location;
+ nxt_conf_value_t *proxy;
+ nxt_conf_value_t *share;
+ nxt_str_t chroot;
+ nxt_conf_value_t *follow_symlinks;
+ nxt_conf_value_t *traverse_mounts;
+ nxt_conf_value_t *types;
+ nxt_conf_value_t *fallback;
+} nxt_http_action_conf_t;
struct nxt_http_action_s {
@@ -206,26 +221,15 @@ struct nxt_http_action_s {
nxt_http_request_t *r,
nxt_http_action_t *action);
union {
+ void *conf;
nxt_http_route_t *route;
nxt_upstream_t *upstream;
uint32_t upstream_number;
- nxt_http_status_t return_code;
nxt_var_t *var;
-
- struct {
- nxt_app_t *application;
- nxt_int_t target;
- } app;
-
- struct {
- nxt_str_t chroot;
- nxt_uint_t resolve;
- nxt_http_route_rule_t *types;
- nxt_http_action_t *fallback;
- } share;
} u;
nxt_str_t name;
+ nxt_http_action_t *fallback;
};
@@ -251,6 +255,14 @@ typedef struct {
} nxt_http_proto_table_t;
+struct nxt_http_client_ip_s {
+ nxt_http_route_addr_rule_t *source;
+ nxt_str_t *header;
+ uint32_t header_hash;
+ uint8_t recursive; /* 1 bit */
+};
+
+
#define NXT_HTTP_DATE_LEN nxt_length("Wed, 31 Dec 1986 16:40:00 GMT")
nxt_inline u_char *
@@ -308,27 +320,34 @@ nxt_int_t nxt_http_pass_segments(nxt_mp_t *mp, nxt_str_t *pass,
nxt_str_t *segments, nxt_uint_t n);
nxt_http_action_t *nxt_http_pass_application(nxt_task_t *task,
nxt_router_conf_t *rtcf, nxt_str_t *name);
+nxt_http_route_addr_rule_t *nxt_http_route_addr_rule_create(
+ nxt_task_t *task, nxt_mp_t *mp, nxt_conf_value_t *cv);
+nxt_int_t nxt_http_route_addr_rule(nxt_http_request_t *r,
+ nxt_http_route_addr_rule_t *addr_rule, nxt_sockaddr_t *sockaddr);
+nxt_http_route_rule_t *nxt_http_route_types_rule_create(nxt_task_t *task,
+ nxt_mp_t *mp, nxt_conf_value_t *types);
nxt_int_t nxt_http_route_test_rule(nxt_http_request_t *r,
nxt_http_route_rule_t *rule, u_char *start, size_t length);
+nxt_int_t nxt_http_action_init(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
+ nxt_conf_value_t *cv, nxt_http_action_t *action);
+void nxt_http_request_action(nxt_task_t *task, nxt_http_request_t *r,
+ nxt_http_action_t *action);
+
nxt_int_t nxt_upstreams_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
nxt_conf_value_t *conf);
nxt_int_t nxt_upstreams_joint_create(nxt_router_temp_conf_t *tmcf,
nxt_upstream_t ***upstream_joint);
-void nxt_http_request_action(nxt_task_t *task, nxt_http_request_t *r,
- nxt_http_action_t *action);
-
-nxt_http_action_t *nxt_http_return_handler(nxt_task_t *task,
- nxt_http_request_t *r, nxt_http_action_t *action);
+nxt_int_t nxt_http_return_init(nxt_mp_t *mp, nxt_http_action_t *action,
+ nxt_http_action_conf_t *acf);
-nxt_http_action_t *nxt_http_static_handler(nxt_task_t *task,
- nxt_http_request_t *r, nxt_http_action_t *action);
+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 *extension, nxt_str_t *type);
-nxt_str_t *nxt_http_static_mtypes_hash_find(nxt_lvlhsh_t *hash,
- nxt_str_t *extension);
+ nxt_str_t *exten, nxt_str_t *type);
+nxt_str_t *nxt_http_static_mtype_get(nxt_lvlhsh_t *hash, 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);
@@ -337,8 +356,8 @@ nxt_int_t nxt_upstream_find(nxt_upstreams_t *upstreams, nxt_str_t *name,
nxt_http_action_t *nxt_upstream_proxy_handler(nxt_task_t *task,
nxt_http_request_t *r, nxt_upstream_t *upstream);
-
-nxt_int_t nxt_http_proxy_create(nxt_mp_t *mp, nxt_http_action_t *action);
+nxt_int_t nxt_http_proxy_init(nxt_mp_t *mp, nxt_http_action_t *action,
+ nxt_http_action_conf_t *acf);
nxt_int_t nxt_http_proxy_date(void *ctx, nxt_http_field_t *field,
uintptr_t data);
nxt_int_t nxt_http_proxy_content_length(void *ctx, nxt_http_field_t *field,
diff --git a/src/nxt_http_chunk_parse.c b/src/nxt_http_chunk_parse.c
index be3a2023..deab116d 100644
--- a/src/nxt_http_chunk_parse.c
+++ b/src/nxt_http_chunk_parse.c
@@ -253,7 +253,6 @@ nxt_http_chunk_buf_completion(nxt_task_t *task, void *obj, void *data)
nxt_buf_t *b, *next, *parent;
b = obj;
- parent = data;
nxt_debug(task, "buf completion: %p %p", b, b->mem.start);
diff --git a/src/nxt_http_proxy.c b/src/nxt_http_proxy.c
index 338d9fce..6aa3aabb 100644
--- a/src/nxt_http_proxy.c
+++ b/src/nxt_http_proxy.c
@@ -21,7 +21,7 @@ static void nxt_http_proxy_upstream_ready(nxt_task_t *task,
nxt_upstream_server_t *us);
static void nxt_http_proxy_upstream_error(nxt_task_t *task,
nxt_upstream_server_t *us);
-static nxt_http_action_t *nxt_http_proxy_handler(nxt_task_t *task,
+static nxt_http_action_t *nxt_http_proxy(nxt_task_t *task,
nxt_http_request_t *r, nxt_http_action_t *action);
static void nxt_http_proxy_header_send(nxt_task_t *task, void *obj, void *data);
static void nxt_http_proxy_header_sent(nxt_task_t *task, void *obj, void *data);
@@ -50,7 +50,8 @@ static const nxt_upstream_peer_state_t nxt_upstream_proxy_state = {
nxt_int_t
-nxt_http_proxy_create(nxt_mp_t *mp, nxt_http_action_t *action)
+nxt_http_proxy_init(nxt_mp_t *mp, nxt_http_action_t *action,
+ nxt_http_action_conf_t *acf)
{
nxt_str_t name;
nxt_sockaddr_t *sa;
@@ -58,7 +59,7 @@ nxt_http_proxy_create(nxt_mp_t *mp, nxt_http_action_t *action)
nxt_upstream_proxy_t *proxy;
sa = NULL;
- name = action->name;
+ nxt_conf_get_string(acf->proxy, &name);
if (nxt_str_start(&name, "http://", 7)) {
name.length -= 7;
@@ -92,7 +93,7 @@ nxt_http_proxy_create(nxt_mp_t *mp, nxt_http_action_t *action)
up->type.proxy = proxy;
action->u.upstream = up;
- action->handler = nxt_http_proxy_handler;
+ action->handler = nxt_http_proxy;
}
return NXT_OK;
@@ -100,10 +101,16 @@ nxt_http_proxy_create(nxt_mp_t *mp, nxt_http_action_t *action)
static nxt_http_action_t *
-nxt_http_proxy_handler(nxt_task_t *task, nxt_http_request_t *r,
+nxt_http_proxy(nxt_task_t *task, nxt_http_request_t *r,
nxt_http_action_t *action)
{
- return nxt_upstream_proxy_handler(task, r, action->u.upstream);
+ nxt_upstream_t *u;
+
+ u = action->u.upstream;
+
+ nxt_debug(task, "http proxy: \"%V\"", &u->name);
+
+ return nxt_upstream_proxy_handler(task, r, u);
}
diff --git a/src/nxt_http_request.c b/src/nxt_http_request.c
index 779cfcf8..b71b25d9 100644
--- a/src/nxt_http_request.c
+++ b/src/nxt_http_request.c
@@ -10,6 +10,10 @@
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_sockaddr_t *nxt_http_request_client_ip_sockaddr(
+ nxt_http_request_t *r, u_char *start, size_t len);
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);
@@ -272,16 +276,162 @@ static const nxt_http_request_state_t nxt_http_request_init_state
static void
nxt_http_request_start(nxt_task_t *task, void *obj, void *data)
{
+ nxt_int_t ret;
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);
+ }
+
nxt_http_request_read_body(task, r);
}
+static nxt_int_t
+nxt_http_request_client_ip(nxt_task_t *task, nxt_http_request_t *r)
+{
+ 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;
+
+ 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);
+ if (ret <= 0) {
+ return NXT_OK;
+ }
+
+ header = client_ip->header;
+
+ fields_arr = nxt_array_create(r->mem_pool, 2, sizeof(nxt_http_field_t *));
+ if (nxt_slow_path(fields_arr == NULL)) {
+ return NXT_ERROR;
+ }
+
+ nxt_list_each(f, r->fields) {
+ if (f->hash == client_ip->header_hash
+ && f->name_length == client_ip->header->length
+ && f->value_length > 0
+ && nxt_memcasecmp(f->name, header->start, header->length) == 0)
+ {
+ fields = nxt_array_add(fields_arr);
+ if (nxt_slow_path(fields == NULL)) {
+ return NXT_ERROR;
+ }
+
+ *fields = f;
+ }
+ } nxt_list_loop;
+
+ prev_sa = r->remote;
+ fields = (nxt_http_field_t **) fields_arr->elts;
+
+ i = fields_arr->nelts;
+
+ while (i-- > 0) {
+ f = fields[i];
+ start = f->value;
+ len = f->value_length;
+
+ do {
+ for (p = start + len - 1; p > start; p--, len--) {
+ if (*p != ' ' && *p != ',') {
+ break;
+ }
+ }
+
+ for (/* void */; p > start; p--) {
+ if (*p == ' ' || *p == ',') {
+ p++;
+ break;
+ }
+ }
+
+ sa = nxt_http_request_client_ip_sockaddr(r, p, len - (p - start));
+ if (nxt_slow_path(sa == NULL)) {
+ if (prev_sa != NULL) {
+ r->remote = prev_sa;
+ }
+
+ return NXT_OK;
+ }
+
+ if (!client_ip->recursive) {
+ r->remote = sa;
+
+ return NXT_OK;
+ }
+
+ ret = nxt_http_route_addr_rule(r, client_ip->source, sa);
+ if (ret <= 0 || (i == 0 && p == start)) {
+ r->remote = sa;
+
+ return NXT_OK;
+ }
+
+ prev_sa = sa;
+ len = p - 1 - start;
+
+ } while (len > 0);
+ }
+
+ return NXT_OK;
+}
+
+
+static nxt_sockaddr_t *
+nxt_http_request_client_ip_sockaddr(nxt_http_request_t *r, u_char *start,
+ size_t len)
+{
+ nxt_str_t addr;
+ nxt_sockaddr_t *sa;
+
+ addr.start = start;
+ addr.length = len;
+
+ sa = nxt_sockaddr_parse_optport(r->mem_pool, &addr);
+ if (nxt_slow_path(sa == NULL)) {
+ return NULL;
+ }
+
+ switch (sa->u.sockaddr.sa_family) {
+ case AF_INET:
+ if (sa->u.sockaddr_in.sin_addr.s_addr == INADDR_ANY) {
+ return NULL;
+ }
+
+ break;
+
+#if (NXT_INET6)
+ case AF_INET6:
+ if (IN6_IS_ADDR_UNSPECIFIED(&sa->u.sockaddr_in6.sin6_addr)) {
+ return NULL;
+ }
+
+ break;
+#endif /* NXT_INET6 */
+
+ default:
+ return NULL;
+ }
+
+ return sa;
+}
+
+
static const nxt_http_request_state_t nxt_http_request_body_state
nxt_aligned(64) =
{
@@ -348,9 +498,7 @@ nxt_http_application_handler(nxt_task_t *task, nxt_http_request_t *r,
nxt_str_set(&r->server_name, "localhost");
}
- r->app_target = action->u.app.target;
-
- nxt_router_process_http_request(task, r, action->u.app.application);
+ nxt_router_process_http_request(task, r, action);
return NULL;
}
diff --git a/src/nxt_http_return.c b/src/nxt_http_return.c
index c466cc25..18fd490d 100644
--- a/src/nxt_http_return.c
+++ b/src/nxt_http_return.c
@@ -7,29 +7,90 @@
#include <nxt_http.h>
+typedef struct {
+ nxt_http_status_t status;
+ nxt_str_t location;
+} nxt_http_return_conf_t;
+
+
+static nxt_http_action_t *nxt_http_return(nxt_task_t *task,
+ nxt_http_request_t *r, nxt_http_action_t *action);
+
+
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_action_conf_t *acf)
+{
+ nxt_str_t *loc;
+ nxt_uint_t encode;
+ nxt_http_return_conf_t *conf;
+
+ conf = nxt_mp_zget(mp, sizeof(nxt_http_return_conf_t));
+ if (nxt_slow_path(conf == NULL)) {
+ return NXT_ERROR;
+ }
+
+ action->handler = nxt_http_return;
+ action->u.conf = conf;
+
+ conf->status = nxt_conf_get_number(acf->ret);
+
+ if (acf->location.length > 0) {
+ if (nxt_is_complex_uri_encoded(acf->location.start,
+ acf->location.length))
+ {
+ loc = nxt_str_dup(mp, &conf->location, &acf->location);
+ if (nxt_slow_path(loc == NULL)) {
+ return NXT_ERROR;
+ }
+
+ } else {
+ loc = &conf->location;
+
+ encode = nxt_encode_complex_uri(NULL, acf->location.start,
+ acf->location.length);
+ loc->length = acf->location.length + encode * 2;
+
+ loc->start = nxt_mp_nget(mp, loc->length);
+ if (nxt_slow_path(loc->start == NULL)) {
+ return NXT_ERROR;
+ }
+
+ nxt_encode_complex_uri(loc->start, acf->location.start,
+ acf->location.length);
+ }
+ }
+
+ return NXT_OK;
+}
+
+
nxt_http_action_t *
-nxt_http_return_handler(nxt_task_t *task, nxt_http_request_t *r,
+nxt_http_return(nxt_task_t *task, nxt_http_request_t *r,
nxt_http_action_t *action)
{
- nxt_http_field_t *field;
- nxt_http_status_t status;
+ nxt_http_field_t *field;
+ nxt_http_return_conf_t *conf;
+
+ conf = action->u.conf;
- status = action->u.return_code;
+ nxt_debug(task, "http return: %d (loc: \"%V\")",
+ conf->status, &conf->location);
- if (status >= NXT_HTTP_BAD_REQUEST
- && status <= NXT_HTTP_SERVER_ERROR_MAX)
+ if (conf->status >= NXT_HTTP_BAD_REQUEST
+ && conf->status <= NXT_HTTP_SERVER_ERROR_MAX)
{
- nxt_http_request_error(task, r, status);
+ nxt_http_request_error(task, r, conf->status);
return NULL;
}
- r->status = status;
+ r->status = conf->status;
r->resp.content_length_n = 0;
- if (action->name.length > 0) {
+ if (conf->location.length > 0) {
field = nxt_list_zero_add(r->resp.fields);
if (nxt_slow_path(field == NULL)) {
nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
@@ -38,8 +99,8 @@ nxt_http_return_handler(nxt_task_t *task, nxt_http_request_t *r,
nxt_http_field_name_set(field, "Location");
- field->value = action->name.start;
- field->value_length = action->name.length;
+ field->value = conf->location.start;
+ field->value_length = conf->location.length;
}
r->state = &nxt_http_return_send_state;
diff --git a/src/nxt_http_route.c b/src/nxt_http_route.c
index 15b85544..cff69f96 100644
--- a/src/nxt_http_route.c
+++ b/src/nxt_http_route.c
@@ -47,20 +47,6 @@ typedef enum {
typedef struct {
- nxt_conf_value_t *pass;
- nxt_conf_value_t *ret;
- nxt_str_t location;
- nxt_conf_value_t *proxy;
- nxt_conf_value_t *share;
- nxt_str_t chroot;
- nxt_conf_value_t *follow_symlinks;
- nxt_conf_value_t *traverse_mounts;
- nxt_conf_value_t *types;
- nxt_conf_value_t *fallback;
-} nxt_http_route_action_conf_t;
-
-
-typedef struct {
nxt_conf_value_t *host;
nxt_conf_value_t *uri;
nxt_conf_value_t *method;
@@ -149,12 +135,12 @@ typedef struct {
} nxt_http_route_table_t;
-typedef struct {
+struct nxt_http_route_addr_rule_s {
/* The object must be the first field. */
nxt_http_route_object_t object:8;
uint32_t items;
nxt_http_route_addr_pattern_t addr_pattern[0];
-} nxt_http_route_addr_rule_t;
+};
typedef union {
@@ -199,9 +185,6 @@ static nxt_http_route_t *nxt_http_route_create(nxt_task_t *task,
nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv);
static nxt_http_route_match_t *nxt_http_route_match_create(nxt_task_t *task,
nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv);
-static nxt_int_t nxt_http_route_action_create(nxt_task_t *task,
- nxt_router_temp_conf_t *tmcf, nxt_conf_value_t *cv,
- nxt_http_action_t *action);
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);
@@ -211,8 +194,6 @@ static nxt_http_route_ruleset_t *nxt_http_route_ruleset_create(nxt_task_t *task,
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);
-static nxt_http_route_addr_rule_t *nxt_http_route_addr_rule_create(
- nxt_task_t *task, nxt_mp_t *mp, nxt_conf_value_t *cv);
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,
@@ -254,8 +235,6 @@ static nxt_int_t nxt_http_route_table(nxt_http_request_t *r,
nxt_http_route_table_t *table);
static nxt_int_t nxt_http_route_ruleset(nxt_http_request_t *r,
nxt_http_route_ruleset_t *ruleset);
-static nxt_int_t nxt_http_route_addr_rule(nxt_http_request_t *r,
- nxt_http_route_addr_rule_t *addr_rule, nxt_sockaddr_t *sockaddr);
static nxt_int_t nxt_http_route_rule(nxt_http_request_t *r,
nxt_http_route_rule_t *rule);
static nxt_int_t nxt_http_route_header(nxt_http_request_t *r,
@@ -476,7 +455,7 @@ nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
return NULL;
}
- ret = nxt_http_route_action_create(task, tmcf, action_conf, &match->action);
+ ret = nxt_http_action_init(task, tmcf, action_conf, &match->action);
if (nxt_slow_path(ret != NXT_OK)) {
return NULL;
}
@@ -617,77 +596,69 @@ static nxt_conf_map_t nxt_http_route_action_conf[] = {
{
nxt_string("pass"),
NXT_CONF_MAP_PTR,
- offsetof(nxt_http_route_action_conf_t, pass)
+ offsetof(nxt_http_action_conf_t, pass)
},
{
nxt_string("return"),
NXT_CONF_MAP_PTR,
- offsetof(nxt_http_route_action_conf_t, ret)
+ offsetof(nxt_http_action_conf_t, ret)
},
{
nxt_string("location"),
NXT_CONF_MAP_STR,
- offsetof(nxt_http_route_action_conf_t, location)
+ offsetof(nxt_http_action_conf_t, location)
},
{
nxt_string("proxy"),
NXT_CONF_MAP_PTR,
- offsetof(nxt_http_route_action_conf_t, proxy)
+ offsetof(nxt_http_action_conf_t, proxy)
},
{
nxt_string("share"),
NXT_CONF_MAP_PTR,
- offsetof(nxt_http_route_action_conf_t, share)
+ offsetof(nxt_http_action_conf_t, share)
},
{
nxt_string("chroot"),
NXT_CONF_MAP_STR,
- offsetof(nxt_http_route_action_conf_t, chroot)
+ offsetof(nxt_http_action_conf_t, chroot)
},
{
nxt_string("follow_symlinks"),
NXT_CONF_MAP_PTR,
- offsetof(nxt_http_route_action_conf_t, follow_symlinks)
+ offsetof(nxt_http_action_conf_t, follow_symlinks)
},
{
nxt_string("traverse_mounts"),
NXT_CONF_MAP_PTR,
- offsetof(nxt_http_route_action_conf_t, traverse_mounts)
+ offsetof(nxt_http_action_conf_t, traverse_mounts)
},
{
nxt_string("types"),
NXT_CONF_MAP_PTR,
- offsetof(nxt_http_route_action_conf_t, types)
+ offsetof(nxt_http_action_conf_t, types)
},
{
nxt_string("fallback"),
NXT_CONF_MAP_PTR,
- offsetof(nxt_http_route_action_conf_t, fallback)
+ offsetof(nxt_http_action_conf_t, fallback)
},
};
-static nxt_int_t
-nxt_http_route_action_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
+nxt_int_t
+nxt_http_action_init(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
nxt_conf_value_t *cv, nxt_http_action_t *action)
{
-#if (NXT_HAVE_OPENAT2)
- u_char *p;
- uint8_t slash;
- nxt_str_t *chroot;
-#endif
- nxt_mp_t *mp;
- nxt_int_t ret;
- nxt_str_t name, *string;
- nxt_uint_t encode;
- nxt_conf_value_t *conf;
- nxt_http_route_rule_t *rule;
- nxt_http_route_action_conf_t accf;
+ nxt_mp_t *mp;
+ nxt_int_t ret;
+ nxt_str_t name, *string;
+ nxt_http_action_conf_t acf;
- nxt_memzero(&accf, sizeof(accf));
+ nxt_memzero(&acf, sizeof(acf));
ret = nxt_conf_map_object(tmcf->mem_pool, cv, nxt_http_route_action_conf,
- nxt_nitems(nxt_http_route_action_conf), &accf);
+ nxt_nitems(nxt_http_route_action_conf), &acf);
if (ret != NXT_OK) {
return ret;
}
@@ -696,126 +667,25 @@ nxt_http_route_action_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
mp = tmcf->router_conf->mem_pool;
- if (accf.ret != NULL) {
- action->handler = nxt_http_return_handler;
- action->u.return_code = nxt_conf_get_number(accf.ret);
-
- if (accf.location.length > 0) {
- if (nxt_is_complex_uri_encoded(accf.location.start,
- accf.location.length))
- {
- string = nxt_str_dup(mp, &action->name, &accf.location);
- if (nxt_slow_path(string == NULL)) {
- return NXT_ERROR;
- }
-
- } else {
- string = &action->name;
-
- encode = nxt_encode_complex_uri(NULL, accf.location.start,
- accf.location.length);
- string->length = accf.location.length + encode * 2;
-
- string->start = nxt_mp_nget(mp, string->length);
- if (nxt_slow_path(string->start == NULL)) {
- return NXT_ERROR;
- }
-
- nxt_encode_complex_uri(string->start, accf.location.start,
- accf.location.length);
- }
- }
-
- return NXT_OK;
+ if (acf.ret != NULL) {
+ return nxt_http_return_init(mp, action, &acf);
}
- if (accf.share != NULL) {
- conf = accf.share;
-
- } else if (accf.proxy != NULL) {
- conf = accf.proxy;
+ if (acf.share != NULL) {
+ return nxt_http_static_init(task, tmcf, action, &acf);
+ }
- } else {
- conf = accf.pass;
+ if (acf.proxy != NULL) {
+ return nxt_http_proxy_init(mp, action, &acf);
}
- nxt_conf_get_string(conf, &name);
+ nxt_conf_get_string(acf.pass, &name);
string = nxt_str_dup(mp, &action->name, &name);
if (nxt_slow_path(string == NULL)) {
return NXT_ERROR;
}
- if (accf.share != NULL) {
- action->handler = nxt_http_static_handler;
-
-#if (NXT_HAVE_OPENAT2)
- string = &accf.chroot;
- chroot = &action->u.share.chroot;
-
- if (string->length > 0) {
- action->u.share.resolve |= RESOLVE_IN_ROOT;
-
- slash = (string->start[string->length - 1] != '/');
-
- chroot->length = string->length + (slash ? 1 : 0);
-
- chroot->start = nxt_mp_alloc(mp, chroot->length + 1);
- if (nxt_slow_path(chroot->start == NULL)) {
- return NXT_ERROR;
- }
-
- p = nxt_cpymem(chroot->start, string->start, string->length);
-
- if (slash) {
- *p++ = '/';
- }
-
- *p = '\0';
- }
-
- if (accf.follow_symlinks != NULL
- && !nxt_conf_get_boolean(accf.follow_symlinks))
- {
- action->u.share.resolve |= RESOLVE_NO_SYMLINKS;
- }
-
- if (accf.traverse_mounts != NULL
- && !nxt_conf_get_boolean(accf.traverse_mounts))
- {
- action->u.share.resolve |= RESOLVE_NO_XDEV;
- }
-#endif
-
- if (accf.types != NULL) {
- rule = nxt_http_route_rule_create(task, mp, accf.types, 0,
- NXT_HTTP_ROUTE_PATTERN_LOWCASE,
- NXT_HTTP_ROUTE_ENCODING_NONE);
- if (nxt_slow_path(rule == NULL)) {
- return NXT_ERROR;
- }
-
- action->u.share.types = rule;
- }
-
- if (accf.fallback != NULL) {
- action->u.share.fallback = nxt_mp_alloc(mp,
- sizeof(nxt_http_action_t));
- if (nxt_slow_path(action->u.share.fallback == NULL)) {
- return NXT_ERROR;
- }
-
- return nxt_http_route_action_create(task, tmcf, accf.fallback,
- action->u.share.fallback);
- }
-
- return NXT_OK;
- }
-
- if (accf.proxy != NULL) {
- return nxt_http_proxy_create(mp, action);
- }
-
return NXT_OK;
}
@@ -1066,7 +936,7 @@ nxt_http_route_rule_create(nxt_task_t *task, nxt_mp_t *mp,
}
-static nxt_http_route_addr_rule_t *
+nxt_http_route_addr_rule_t *
nxt_http_route_addr_rule_create(nxt_task_t *task, nxt_mp_t *mp,
nxt_conf_value_t *cv)
{
@@ -1119,6 +989,16 @@ nxt_http_route_addr_rule_create(nxt_task_t *task, nxt_mp_t *mp,
}
+nxt_http_route_rule_t *
+nxt_http_route_types_rule_create(nxt_task_t *task, nxt_mp_t *mp,
+ nxt_conf_value_t *types)
+{
+ return nxt_http_route_rule_create(task, mp, types, 0,
+ NXT_HTTP_ROUTE_PATTERN_LOWCASE,
+ NXT_HTTP_ROUTE_ENCODING_NONE);
+}
+
+
static int
nxt_http_pattern_compare(const void *one, const void *two)
{
@@ -1491,15 +1371,12 @@ static nxt_int_t
nxt_http_action_resolve(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
nxt_http_action_t *action)
{
- nxt_var_t *var;
nxt_int_t ret;
+ nxt_var_t *var;
if (action->handler != NULL) {
- if (action->handler == nxt_http_static_handler
- && action->u.share.fallback != NULL)
- {
- return nxt_http_action_resolve(task, tmcf,
- action->u.share.fallback);
+ if (action->fallback != NULL) {
+ return nxt_http_action_resolve(task, tmcf, action->fallback);
}
return NXT_OK;
@@ -1601,9 +1478,7 @@ static nxt_int_t
nxt_http_pass_find(nxt_task_t *task, nxt_mp_t *mp, nxt_router_conf_t *rtcf,
nxt_http_action_t *action)
{
- nxt_str_t *targets;
nxt_int_t ret;
- nxt_uint_t i;
nxt_str_t segments[3];
ret = nxt_http_pass_segments(mp, &action->name, segments, 3);
@@ -1612,24 +1487,8 @@ nxt_http_pass_find(nxt_task_t *task, nxt_mp_t *mp, nxt_router_conf_t *rtcf,
}
if (nxt_str_eq(&segments[0], "applications", 12)) {
- ret = nxt_router_listener_application(rtcf, &segments[1], action);
-
- if (ret != NXT_OK) {
- return ret;
- }
-
- if (segments[2].length != 0) {
- targets = action->u.app.application->targets;
-
- for (i = 0; !nxt_strstr_eq(&segments[2], &targets[i]); i++);
-
- action->u.app.target = i;
-
- } else {
- action->u.app.target = 0;
- }
-
- return NXT_OK;
+ return nxt_router_application_init(rtcf, &segments[1], &segments[2],
+ action);
}
if (segments[2].length == 0) {
@@ -1704,6 +1563,10 @@ nxt_http_route_find(nxt_http_routes_t *routes, nxt_str_t *name,
{
nxt_http_route_t **route, **end;
+ if (routes == NULL) {
+ return NXT_DECLINED;
+ }
+
route = &routes->route[0];
end = route + routes->items;
@@ -1762,9 +1625,7 @@ nxt_http_pass_application(nxt_task_t *task, nxt_router_conf_t *rtcf,
action->name = *name;
- (void) nxt_router_listener_application(rtcf, name, action);
-
- action->u.app.target = 0;
+ (void) nxt_router_application_init(rtcf, name, NULL, action);
return action;
}
@@ -2062,7 +1923,7 @@ nxt_http_route_addr_pattern_match(nxt_http_route_addr_pattern_t *p,
}
-static nxt_int_t
+nxt_int_t
nxt_http_route_addr_rule(nxt_http_request_t *r,
nxt_http_route_addr_rule_t *addr_rule, nxt_sockaddr_t *sa)
{
@@ -2071,6 +1932,11 @@ nxt_http_route_addr_rule(nxt_http_request_t *r,
nxt_http_route_addr_pattern_t *p;
n = addr_rule->items;
+
+ if (n == 0) {
+ return 0;
+ }
+
p = &addr_rule->addr_pattern[0] - 1;
do {
diff --git a/src/nxt_http_route_addr.c b/src/nxt_http_route_addr.c
index 6d4955ed..2907a902 100644
--- a/src/nxt_http_route_addr.c
+++ b/src/nxt_http_route_addr.c
@@ -8,7 +8,6 @@
#include <nxt_http_route_addr.h>
-static nxt_bool_t nxt_str_looks_like_ipv6(const nxt_str_t *str);
#if (NXT_INET6)
static nxt_bool_t nxt_valid_ipv6_blocks(u_char *c, size_t len);
#endif
@@ -57,7 +56,7 @@ nxt_http_route_addr_pattern_parse(nxt_mp_t *mp,
goto parse_port;
}
- if (nxt_str_looks_like_ipv6(&addr)) {
+ if (nxt_inet6_probe(&addr)) {
#if (NXT_INET6)
u_char *end;
uint8_t i;
@@ -304,22 +303,6 @@ parse_port:
}
-static nxt_bool_t
-nxt_str_looks_like_ipv6(const nxt_str_t *str)
-{
- u_char *colon, *end;
-
- colon = nxt_memchr(str->start, ':', str->length);
-
- if (colon != NULL) {
- end = str->start + str->length;
- colon = nxt_memchr(colon + 1, ':', end - (colon + 1));
- }
-
- return (colon != NULL);
-}
-
-
#if (NXT_INET6)
static nxt_bool_t
diff --git a/src/nxt_http_static.c b/src/nxt_http_static.c
index c8b73fac..9b79a666 100644
--- a/src/nxt_http_static.c
+++ b/src/nxt_http_static.c
@@ -7,12 +7,22 @@
#include <nxt_http.h>
+typedef struct {
+ nxt_str_t share;
+ nxt_str_t chroot;
+ nxt_uint_t resolve;
+ nxt_http_route_rule_t *types;
+} nxt_http_static_conf_t;
+
+
#define NXT_HTTP_STATIC_BUF_COUNT 2
#define NXT_HTTP_STATIC_BUF_SIZE (128 * 1024)
+static nxt_http_action_t *nxt_http_static(nxt_task_t *task,
+ nxt_http_request_t *r, nxt_http_action_t *action);
static void nxt_http_static_extract_extension(nxt_str_t *path,
- nxt_str_t *extension);
+ nxt_str_t *exten);
static void nxt_http_static_body_handler(nxt_task_t *task, void *obj,
void *data);
static void nxt_http_static_buf_completion(nxt_task_t *task, void *obj,
@@ -27,30 +37,122 @@ static void nxt_http_static_mtypes_hash_free(void *data, void *p);
static const nxt_http_request_state_t nxt_http_static_send_state;
-nxt_http_action_t *
-nxt_http_static_handler(nxt_task_t *task, nxt_http_request_t *r,
+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_mp_t *mp;
+ nxt_str_t *str, value;
+ nxt_http_static_conf_t *conf;
+
+ mp = tmcf->router_conf->mem_pool;
+
+ conf = nxt_mp_zget(mp, sizeof(nxt_http_static_conf_t));
+ if (nxt_slow_path(conf == NULL)) {
+ return NXT_ERROR;
+ }
+
+ action->handler = nxt_http_static;
+ action->u.conf = conf;
+
+ nxt_conf_get_string(acf->share, &value);
+
+ str = nxt_str_dup(mp, &conf->share, &value);
+ if (nxt_slow_path(str == NULL)) {
+ return NXT_ERROR;
+ }
+
+#if (NXT_HAVE_OPENAT2)
+ if (acf->chroot.length > 0) {
+ u_char *p;
+ nxt_str_t slash;
+
+ if (acf->chroot.start[acf->chroot.length - 1] != '/') {
+ nxt_str_set(&slash, "/");
+
+ } else {
+ nxt_str_set(&slash, "");
+ }
+
+ value.length = acf->chroot.length + slash.length;
+
+ value.start = nxt_mp_alloc(mp, value.length + 1);
+ if (nxt_slow_path(value.start == NULL)) {
+ return NXT_ERROR;
+ }
+
+ p = value.start;
+ p = nxt_cpymem(p, acf->chroot.start, acf->chroot.length);
+ p = nxt_cpymem(p, slash.start, slash.length);
+ *p = '\0';
+
+ conf->chroot = value;
+ conf->resolve |= RESOLVE_IN_ROOT;
+ }
+
+ if (acf->follow_symlinks != NULL
+ && !nxt_conf_get_boolean(acf->follow_symlinks))
+ {
+ conf->resolve |= RESOLVE_NO_SYMLINKS;
+ }
+
+ if (acf->traverse_mounts != NULL
+ && !nxt_conf_get_boolean(acf->traverse_mounts))
+ {
+ conf->resolve |= RESOLVE_NO_XDEV;
+ }
+#endif
+
+ if (acf->types != NULL) {
+ conf->types = nxt_http_route_types_rule_create(task, mp, acf->types);
+ if (nxt_slow_path(conf->types == NULL)) {
+ return NXT_ERROR;
+ }
+ }
+
+ if (acf->fallback != NULL) {
+ action->fallback = nxt_mp_alloc(mp, sizeof(nxt_http_action_t));
+ if (nxt_slow_path(action->fallback == NULL)) {
+ return NXT_ERROR;
+ }
+
+ return nxt_http_action_init(task, tmcf, acf->fallback,
+ action->fallback);
+ }
+
+ return NXT_OK;
+}
+
+
+static nxt_http_action_t *
+nxt_http_static(nxt_task_t *task, nxt_http_request_t *r,
nxt_http_action_t *action)
{
- size_t length, encode;
- u_char *p, *fname;
- struct tm tm;
- nxt_buf_t *fb;
- nxt_int_t ret;
- nxt_str_t index, extension, *mtype, *chroot;
- nxt_uint_t level;
- nxt_bool_t need_body;
- nxt_file_t *f, file;
- nxt_file_info_t fi;
- nxt_http_field_t *field;
- nxt_http_status_t status;
- nxt_router_conf_t *rtcf;
- nxt_work_handler_t body_handler;
+ size_t length, encode;
+ u_char *p, *fname;
+ struct tm tm;
+ nxt_buf_t *fb;
+ nxt_int_t ret;
+ nxt_str_t index, exten, *mtype, *chroot;
+ nxt_uint_t level;
+ nxt_bool_t need_body;
+ nxt_file_t *f, file;
+ nxt_file_info_t fi;
+ nxt_http_field_t *field;
+ nxt_http_status_t status;
+ nxt_router_conf_t *rtcf;
+ nxt_work_handler_t body_handler;
+ nxt_http_static_conf_t *conf;
+
+ conf = action->u.conf;
+
+ nxt_debug(task, "http static: \"%V\"", &conf->share);
if (nxt_slow_path(!nxt_str_eq(r->method, "GET", 3))) {
if (!nxt_str_eq(r->method, "HEAD", 4)) {
- if (action->u.share.fallback != NULL) {
- return action->u.share.fallback;
+ if (action->fallback != NULL) {
+ return action->fallback;
}
nxt_http_request_error(task, r, NXT_HTTP_METHOD_NOT_ALLOWED);
@@ -66,11 +168,11 @@ nxt_http_static_handler(nxt_task_t *task, nxt_http_request_t *r,
if (r->path->start[r->path->length - 1] == '/') {
/* TODO: dynamic index setting. */
nxt_str_set(&index, "index.html");
- nxt_str_set(&extension, ".html");
+ nxt_str_set(&exten, ".html");
} else {
nxt_str_set(&index, "");
- nxt_str_null(&extension);
+ nxt_str_null(&exten);
}
f = NULL;
@@ -79,20 +181,19 @@ nxt_http_static_handler(nxt_task_t *task, nxt_http_request_t *r,
mtype = NULL;
- if (action->u.share.types != NULL && extension.start == NULL) {
- nxt_http_static_extract_extension(r->path, &extension);
- mtype = nxt_http_static_mtypes_hash_find(&rtcf->mtypes_hash,
- &extension);
+ if (conf->types != NULL && exten.start == NULL) {
+ nxt_http_static_extract_extension(r->path, &exten);
+ mtype = nxt_http_static_mtype_get(&rtcf->mtypes_hash, &exten);
- ret = nxt_http_route_test_rule(r, action->u.share.types,
- mtype->start, mtype->length);
+ ret = nxt_http_route_test_rule(r, conf->types, mtype->start,
+ mtype->length);
if (nxt_slow_path(ret == NXT_ERROR)) {
goto fail;
}
if (ret == 0) {
- if (action->u.share.fallback != NULL) {
- return action->u.share.fallback;
+ if (action->fallback != NULL) {
+ return action->fallback;
}
nxt_http_request_error(task, r, NXT_HTTP_FORBIDDEN);
@@ -100,7 +201,7 @@ nxt_http_static_handler(nxt_task_t *task, nxt_http_request_t *r,
}
}
- length = action->name.length + r->path->length + index.length;
+ length = conf->share.length + r->path->length + index.length;
fname = nxt_mp_nget(r->mem_pool, length + 1);
if (nxt_slow_path(fname == NULL)) {
@@ -108,7 +209,7 @@ nxt_http_static_handler(nxt_task_t *task, nxt_http_request_t *r,
}
p = fname;
- p = nxt_cpymem(p, action->name.start, action->name.length);
+ p = nxt_cpymem(p, conf->share.start, conf->share.length);
p = nxt_cpymem(p, r->path->start, r->path->length);
p = nxt_cpymem(p, index.start, index.length);
*p = '\0';
@@ -117,11 +218,10 @@ nxt_http_static_handler(nxt_task_t *task, nxt_http_request_t *r,
file.name = fname;
- chroot = &action->u.share.chroot;
+ chroot = &conf->chroot;
#if (NXT_HAVE_OPENAT2)
-
- if (action->u.share.resolve != 0) {
+ if (conf->resolve != 0) {
if (chroot->length > 0) {
file.name = chroot->start;
@@ -156,8 +256,7 @@ nxt_http_static_handler(nxt_task_t *task, nxt_http_request_t *r,
file.name = fname;
ret = nxt_file_openat2(task, &file, NXT_FILE_RDONLY,
- NXT_FILE_OPEN, 0, af.fd,
- action->u.share.resolve);
+ NXT_FILE_OPEN, 0, af.fd, conf->resolve);
if (af.fd != AT_FDCWD) {
nxt_file_close(task, &af);
@@ -169,9 +268,7 @@ nxt_http_static_handler(nxt_task_t *task, nxt_http_request_t *r,
}
#else
-
ret = nxt_file_open(task, &file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 0);
-
#endif
if (nxt_slow_path(ret != NXT_OK)) {
@@ -211,8 +308,8 @@ nxt_http_static_handler(nxt_task_t *task, nxt_http_request_t *r,
break;
}
- if (level == NXT_LOG_ERR && action->u.share.fallback != NULL) {
- return action->u.share.fallback;
+ if (level == NXT_LOG_ERR && action->fallback != NULL) {
+ return action->fallback;
}
if (status != NXT_HTTP_NOT_FOUND) {
@@ -283,13 +380,12 @@ nxt_http_static_handler(nxt_task_t *task, nxt_http_request_t *r,
nxt_file_size(&fi))
- p;
- if (extension.start == NULL) {
- nxt_http_static_extract_extension(r->path, &extension);
+ if (exten.start == NULL) {
+ nxt_http_static_extract_extension(r->path, &exten);
}
if (mtype == NULL) {
- mtype = nxt_http_static_mtypes_hash_find(&rtcf->mtypes_hash,
- &extension);
+ mtype = nxt_http_static_mtype_get(&rtcf->mtypes_hash, &exten);
}
if (mtype->length != 0) {
@@ -328,8 +424,8 @@ nxt_http_static_handler(nxt_task_t *task, nxt_http_request_t *r,
nxt_file_close(task, f);
if (nxt_slow_path(!nxt_is_dir(&fi))) {
- if (action->u.share.fallback != NULL) {
- return action->u.share.fallback;
+ if (action->fallback != NULL) {
+ return action->fallback;
}
nxt_log(task, NXT_LOG_ERR, "\"%FN\" is not a regular file",
@@ -401,7 +497,7 @@ fail:
static void
-nxt_http_static_extract_extension(nxt_str_t *path, nxt_str_t *extension)
+nxt_http_static_extract_extension(nxt_str_t *path, nxt_str_t *exten)
{
u_char ch, *p, *end;
@@ -419,8 +515,8 @@ nxt_http_static_extract_extension(nxt_str_t *path, nxt_str_t *extension)
p++;
/* Fall through. */
case '.':
- extension->length = end - p;
- extension->start = p;
+ exten->length = end - p;
+ exten->start = p;
return;
}
}
@@ -571,13 +667,13 @@ clean:
nxt_int_t
nxt_http_static_mtypes_init(nxt_mp_t *mp, nxt_lvlhsh_t *hash)
{
- nxt_str_t *type, extension;
+ nxt_str_t *type, exten;
nxt_int_t ret;
nxt_uint_t i;
static const struct {
nxt_str_t type;
- const char *extension;
+ const char *exten;
} default_types[] = {
{ nxt_string("text/html"), ".html" },
@@ -644,10 +740,10 @@ nxt_http_static_mtypes_init(nxt_mp_t *mp, nxt_lvlhsh_t *hash)
for (i = 0; i < nxt_nitems(default_types); i++) {
type = (nxt_str_t *) &default_types[i].type;
- extension.start = (u_char *) default_types[i].extension;
- extension.length = nxt_strlen(extension.start);
+ exten.start = (u_char *) default_types[i].exten;
+ exten.length = nxt_strlen(exten.start);
- ret = nxt_http_static_mtypes_hash_add(mp, hash, &extension, type);
+ ret = nxt_http_static_mtypes_hash_add(mp, hash, &exten, type);
if (nxt_slow_path(ret != NXT_OK)) {
return NXT_ERROR;
}
@@ -668,14 +764,14 @@ static const nxt_lvlhsh_proto_t nxt_http_static_mtypes_hash_proto
typedef struct {
- nxt_str_t extension;
+ nxt_str_t exten;
nxt_str_t *type;
} nxt_http_static_mtype_t;
nxt_int_t
nxt_http_static_mtypes_hash_add(nxt_mp_t *mp, nxt_lvlhsh_t *hash,
- nxt_str_t *extension, nxt_str_t *type)
+ nxt_str_t *exten, nxt_str_t *type)
{
nxt_lvlhsh_query_t lhq;
nxt_http_static_mtype_t *mtype;
@@ -685,10 +781,10 @@ nxt_http_static_mtypes_hash_add(nxt_mp_t *mp, nxt_lvlhsh_t *hash,
return NXT_ERROR;
}
- mtype->extension = *extension;
+ mtype->exten = *exten;
mtype->type = type;
- lhq.key = *extension;
+ lhq.key = *exten;
lhq.key_hash = nxt_djb_hash_lowcase(lhq.key.start, lhq.key.length);
lhq.replace = 1;
lhq.value = mtype;
@@ -700,14 +796,14 @@ nxt_http_static_mtypes_hash_add(nxt_mp_t *mp, nxt_lvlhsh_t *hash,
nxt_str_t *
-nxt_http_static_mtypes_hash_find(nxt_lvlhsh_t *hash, nxt_str_t *extension)
+nxt_http_static_mtype_get(nxt_lvlhsh_t *hash, nxt_str_t *exten)
{
nxt_lvlhsh_query_t lhq;
nxt_http_static_mtype_t *mtype;
static nxt_str_t empty = nxt_string("");
- lhq.key = *extension;
+ lhq.key = *exten;
lhq.key_hash = nxt_djb_hash_lowcase(lhq.key.start, lhq.key.length);
lhq.proto = &nxt_http_static_mtypes_hash_proto;
@@ -727,8 +823,7 @@ nxt_http_static_mtypes_hash_test(nxt_lvlhsh_query_t *lhq, void *data)
mtype = data;
- return nxt_strcasestr_eq(&lhq->key, &mtype->extension) ? NXT_OK
- : NXT_DECLINED;
+ return nxt_strcasestr_eq(&lhq->key, &mtype->exten) ? NXT_OK : NXT_DECLINED;
}
diff --git a/src/nxt_isolation.c b/src/nxt_isolation.c
index cab0074b..e3cb1f22 100644
--- a/src/nxt_isolation.c
+++ b/src/nxt_isolation.c
@@ -126,10 +126,10 @@ nxt_isolation_main_prefork(nxt_task_t *task, nxt_process_t *process,
return ret;
}
- has_mnt = 0;
-
#if (NXT_HAVE_CLONE_NEWNS)
has_mnt = nxt_is_clone_flag_set(process->isolation.clone.flags, NEWNS);
+#else
+ has_mnt = 0;
#endif
if (process->user_cred->uid == 0 && !has_mnt) {
diff --git a/src/nxt_log.h b/src/nxt_log.h
index 48742721..0cf10b5c 100644
--- a/src/nxt_log.h
+++ b/src/nxt_log.h
@@ -48,29 +48,29 @@ nxt_log_level_enough(log, level) \
#define nxt_alert(task, ...) \
do { \
- nxt_log_t *log = (task)->log; \
+ nxt_log_t *_log = (task)->log; \
\
- log->handler(NXT_LOG_ALERT, log, __VA_ARGS__); \
+ _log->handler(NXT_LOG_ALERT, _log, __VA_ARGS__); \
} while (0)
#define nxt_log(task, _level, ...) \
do { \
- nxt_log_t *log = (task)->log; \
+ nxt_log_t *_log = (task)->log; \
nxt_uint_t _level_ = (_level); \
\
- if (nxt_slow_path(log->level >= _level_)) { \
- log->handler(_level_, log, __VA_ARGS__); \
+ if (nxt_slow_path(_log->level >= _level_)) { \
+ _log->handler(_level_, _log, __VA_ARGS__); \
} \
} while (0)
#define nxt_trace(task, ...) \
do { \
- nxt_log_t *log = (task)->log; \
+ nxt_log_t *_log = (task)->log; \
\
- if (nxt_slow_path(log->level >= NXT_LOG_NOTICE || nxt_trace)) { \
- log->handler(NXT_LOG_NOTICE, log, __VA_ARGS__); \
+ if (nxt_slow_path(_log->level >= NXT_LOG_NOTICE || nxt_trace)) { \
+ _log->handler(NXT_LOG_NOTICE, _log, __VA_ARGS__); \
} \
} while (0)
@@ -99,10 +99,10 @@ nxt_log_error(_level, _log, ...) \
#define nxt_debug(task, ...) \
do { \
- nxt_log_t *log = (task)->log; \
+ nxt_log_t *_log = (task)->log; \
\
- if (nxt_slow_path(log->level == NXT_LOG_DEBUG || nxt_debug)) { \
- log->handler(NXT_LOG_DEBUG, log, __VA_ARGS__); \
+ if (nxt_slow_path(_log->level == NXT_LOG_DEBUG || nxt_debug)) { \
+ _log->handler(NXT_LOG_DEBUG, _log, __VA_ARGS__); \
} \
} while (0)
diff --git a/src/nxt_main_process.c b/src/nxt_main_process.c
index 00f336f6..16c6a297 100644
--- a/src/nxt_main_process.c
+++ b/src/nxt_main_process.c
@@ -271,6 +271,11 @@ static nxt_conf_map_t nxt_ruby_app_conf[] = {
NXT_CONF_MAP_INT32,
offsetof(nxt_common_app_conf_t, u.ruby.threads),
},
+ {
+ nxt_string("hooks"),
+ NXT_CONF_MAP_STR,
+ offsetof(nxt_common_app_conf_t, u.ruby.hooks),
+ }
};
@@ -342,8 +347,6 @@ nxt_port_main_start_process_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
nxt_process_init_t *init;
nxt_common_app_conf_t *app_conf;
- ret = NXT_ERROR;
-
rt = task->thread->runtime;
process = nxt_main_process_new(task, rt);
diff --git a/src/nxt_openssl.c b/src/nxt_openssl.c
index 2fd5d1bf..273ca7f4 100644
--- a/src/nxt_openssl.c
+++ b/src/nxt_openssl.c
@@ -11,6 +11,8 @@
#include <openssl/err.h>
#include <openssl/rand.h>
#include <openssl/x509v3.h>
+#include <openssl/bio.h>
+#include <openssl/evp.h>
typedef struct {
@@ -42,15 +44,22 @@ static void nxt_openssl_lock(int mode, int type, const char *file, int line);
static unsigned long nxt_openssl_thread_id(void);
static void nxt_openssl_locks_free(void);
#endif
-static nxt_int_t nxt_openssl_server_init(nxt_task_t *task,
- nxt_tls_conf_t *conf, nxt_mp_t *mp, nxt_conf_value_t *conf_cmds,
- nxt_bool_t last);
+static nxt_int_t nxt_openssl_server_init(nxt_task_t *task, nxt_mp_t *mp,
+ nxt_tls_init_t *tls_init, nxt_bool_t last);
static nxt_int_t nxt_openssl_chain_file(nxt_task_t *task, SSL_CTX *ctx,
nxt_tls_conf_t *conf, nxt_mp_t *mp, nxt_bool_t single);
#if (NXT_HAVE_OPENSSL_CONF_CMD)
static nxt_int_t nxt_ssl_conf_commands(nxt_task_t *task, SSL_CTX *ctx,
nxt_conf_value_t *value, nxt_mp_t *mp);
#endif
+#if (NXT_HAVE_OPENSSL_TLSEXT)
+static nxt_int_t nxt_tls_ticket_keys(nxt_task_t *task, SSL_CTX *ctx,
+ nxt_tls_init_t *tls_init, nxt_mp_t *mp);
+static int nxt_tls_ticket_key_callback(SSL *s, unsigned char *name,
+ unsigned char *iv, EVP_CIPHER_CTX *ectx,HMAC_CTX *hctx, int enc);
+#endif
+static void nxt_ssl_session_cache(SSL_CTX *ctx, size_t cache_size,
+ time_t timeout);
static nxt_uint_t nxt_openssl_cert_get_names(nxt_task_t *task, X509 *cert,
nxt_tls_conf_t *conf, nxt_mp_t *mp);
static nxt_int_t nxt_openssl_bundle_hash_test(nxt_lvlhsh_query_t *lhq,
@@ -265,11 +274,12 @@ nxt_openssl_locks_free(void)
static nxt_int_t
-nxt_openssl_server_init(nxt_task_t *task, nxt_tls_conf_t *conf,
- nxt_mp_t *mp, nxt_conf_value_t *conf_cmds, nxt_bool_t last)
+nxt_openssl_server_init(nxt_task_t *task, nxt_mp_t *mp,
+ nxt_tls_init_t *tls_init, nxt_bool_t last)
{
SSL_CTX *ctx;
const char *ciphers, *ca_certificate;
+ nxt_tls_conf_t *conf;
STACK_OF(X509_NAME) *list;
nxt_tls_bundle_conf_t *bundle;
@@ -279,6 +289,8 @@ nxt_openssl_server_init(nxt_task_t *task, nxt_tls_conf_t *conf,
return NXT_ERROR;
}
+ conf = tls_init->conf;
+
bundle = conf->bundle;
nxt_assert(bundle != NULL);
@@ -337,13 +349,21 @@ nxt_openssl_server_init(nxt_task_t *task, nxt_tls_conf_t *conf,
}
#if (NXT_HAVE_OPENSSL_CONF_CMD)
- if (conf_cmds != NULL
- && nxt_ssl_conf_commands(task, ctx, conf_cmds, mp) != NXT_OK)
+ if (tls_init->conf_cmds != NULL
+ && nxt_ssl_conf_commands(task, ctx, tls_init->conf_cmds, mp) != NXT_OK)
{
goto fail;
}
#endif
+ nxt_ssl_session_cache(ctx, tls_init->cache_size, tls_init->timeout);
+
+#if (NXT_HAVE_OPENSSL_TLSEXT)
+ if (nxt_tls_ticket_keys(task, ctx, tls_init, mp) != NXT_OK) {
+ goto fail;
+ }
+#endif
+
SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
if (conf->ca_certificate != NULL) {
@@ -581,6 +601,257 @@ fail:
#endif
+#if (NXT_HAVE_OPENSSL_TLSEXT)
+
+static nxt_int_t
+nxt_tls_ticket_keys(nxt_task_t *task, SSL_CTX *ctx, nxt_tls_init_t *tls_init,
+ nxt_mp_t *mp)
+{
+ uint32_t i;
+ nxt_int_t ret;
+ nxt_str_t value;
+ nxt_uint_t count;
+ nxt_conf_value_t *member, *tickets_conf;
+ nxt_tls_ticket_t *ticket;
+ nxt_tls_tickets_t *tickets;
+ u_char buf[80];
+
+ tickets_conf = tls_init->tickets_conf;
+
+ if (tickets_conf == NULL) {
+ goto no_ticket;
+ }
+
+ if (nxt_conf_type(tickets_conf) == NXT_CONF_BOOLEAN) {
+ if (nxt_conf_get_boolean(tickets_conf) == 0) {
+ goto no_ticket;
+ }
+
+ return NXT_OK;
+ }
+
+ if (nxt_conf_type(tickets_conf) == NXT_CONF_ARRAY) {
+ count = nxt_conf_array_elements_count(tickets_conf);
+
+ if (count == 0) {
+ goto no_ticket;
+ }
+
+ } else {
+ /* nxt_conf_type(tickets_conf) == NXT_CONF_STRING */
+ count = 1;
+ }
+
+#ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB
+
+ tickets = nxt_mp_get(mp, sizeof(nxt_tls_tickets_t)
+ + count * sizeof(nxt_tls_ticket_t));
+ if (nxt_slow_path(tickets == NULL)) {
+ return NXT_ERROR;
+ }
+
+ tickets->count = count;
+ tls_init->conf->tickets = tickets;
+ i = 0;
+
+ do {
+ ticket = &tickets->tickets[i];
+
+ i++;
+
+ if (nxt_conf_type(tickets_conf) == NXT_CONF_ARRAY) {
+ member = nxt_conf_get_array_element(tickets_conf, count - i);
+ if (member == NULL) {
+ break;
+ }
+
+ } else {
+ /* nxt_conf_type(tickets_conf) == NXT_CONF_STRING */
+ member = tickets_conf;
+ }
+
+ nxt_conf_get_string(member, &value);
+
+ ret = nxt_openssl_base64_decode(buf, 80, value.start, value.length);
+ if (nxt_slow_path(ret == NXT_ERROR)) {
+ return NXT_ERROR;
+ }
+
+ if (ret == 48) {
+ ticket->aes128 = 1;
+ nxt_memcpy(ticket->aes_key, buf + 16, 16);
+ nxt_memcpy(ticket->hmac_key, buf + 32, 16);
+
+ } else {
+ ticket->aes128 = 0;
+ nxt_memcpy(ticket->hmac_key, buf + 16, 32);
+ nxt_memcpy(ticket->aes_key, buf + 48, 32);
+ }
+
+ nxt_memcpy(ticket->name, buf, 16);
+ } while (i < count);
+
+ if (SSL_CTX_set_tlsext_ticket_key_cb(ctx, nxt_tls_ticket_key_callback)
+ == 0)
+ {
+ nxt_openssl_log_error(task, NXT_LOG_ALERT,
+ "Unit was built with Session Tickets support, however, "
+ "now it is linked dynamically to an OpenSSL library "
+ "which has no tlsext support, therefore Session Tickets "
+ "are not available");
+
+ return NXT_ERROR;
+ }
+
+ return NXT_OK;
+
+#else
+ nxt_alert(task, "Setting custom session ticket keys is not supported with "
+ "this version of OpenSSL library");
+
+ return NXT_ERROR;
+
+#endif
+
+no_ticket:
+
+ SSL_CTX_set_options(ctx, SSL_OP_NO_TICKET);
+
+ return NXT_OK;
+}
+
+
+#ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB
+
+static int
+nxt_tls_ticket_key_callback(SSL *s, unsigned char *name, unsigned char *iv,
+ EVP_CIPHER_CTX *ectx, HMAC_CTX *hctx, int enc)
+{
+ size_t size;
+ nxt_uint_t i;
+ nxt_conn_t *c;
+ const EVP_MD *digest;
+ const EVP_CIPHER *cipher;
+ nxt_tls_ticket_t *ticket;
+ nxt_openssl_conn_t *tls;
+
+ c = SSL_get_ex_data(s, nxt_openssl_connection_index);
+
+ if (nxt_slow_path(c == NULL)) {
+ nxt_thread_log_alert("SSL_get_ex_data() failed");
+ return -1;
+ }
+
+ tls = c->u.tls;
+ ticket = tls->conf->tickets->tickets;
+
+#ifdef OPENSSL_NO_SHA256
+ digest = EVP_sha1();
+#else
+ digest = EVP_sha256();
+#endif
+
+ if (enc == 1) {
+ /* encrypt session ticket */
+
+ nxt_debug(c->socket.task, "TLS session ticket encrypt");
+
+ if (ticket[0].aes128 == 1) {
+ cipher = EVP_aes_128_cbc();
+ size = 16;
+
+ } else {
+ cipher = EVP_aes_256_cbc();
+ size = 32;
+ }
+
+ if (RAND_bytes(iv, EVP_CIPHER_iv_length(cipher)) != 1) {
+ nxt_openssl_log_error(c->socket.task, NXT_LOG_ALERT,
+ "RAND_bytes() failed");
+ return -1;
+ }
+
+ if (EVP_EncryptInit_ex(ectx, cipher, NULL, ticket[0].aes_key, iv)
+ != 1)
+ {
+ nxt_openssl_log_error(c->socket.task, NXT_LOG_ALERT,
+ "EVP_EncryptInit_ex() failed");
+ return -1;
+ }
+
+ if (HMAC_Init_ex(hctx, ticket[0].hmac_key, size, digest, NULL) != 1) {
+ nxt_openssl_log_error(c->socket.task, NXT_LOG_ALERT,
+ "HMAC_Init_ex() failed");
+ return -1;
+ }
+
+ nxt_memcpy(name, ticket[0].name, 16);
+
+ return 1;
+
+ } else {
+ /* decrypt session ticket */
+
+ for (i = 0; i < tls->conf->tickets->count; i++) {
+ if (nxt_memcmp(name, ticket[i].name, 16) == 0) {
+ goto found;
+ }
+ }
+
+ nxt_debug(c->socket.task, "TLS session ticket decrypt, key not found");
+
+ return 0;
+
+ found:
+
+ nxt_debug(c->socket.task,
+ "TLS session ticket decrypt, key number: \"%d\"", i);
+
+ if (ticket[i].aes128 == 1) {
+ cipher = EVP_aes_128_cbc();
+ size = 16;
+
+ } else {
+ cipher = EVP_aes_256_cbc();
+ size = 32;
+ }
+
+ if (EVP_DecryptInit_ex(ectx, cipher, NULL, ticket[i].aes_key, iv) != 1) {
+ nxt_openssl_log_error(c->socket.task, NXT_LOG_ALERT,
+ "EVP_DecryptInit_ex() failed");
+ return -1;
+ }
+
+ if (HMAC_Init_ex(hctx, ticket[i].hmac_key, size, digest, NULL) != 1) {
+ nxt_openssl_log_error(c->socket.task, NXT_LOG_ALERT,
+ "HMAC_Init_ex() failed");
+ return -1;
+ }
+
+ return (i == 0) ? 1 : 2 /* renew */;
+ }
+}
+
+#endif /* SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB */
+
+#endif /* NXT_HAVE_OPENSSL_TLSEXT */
+
+
+static void
+nxt_ssl_session_cache(SSL_CTX *ctx, size_t cache_size, time_t timeout)
+{
+ if (cache_size == 0) {
+ SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
+ return;
+ }
+
+ SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER);
+
+ SSL_CTX_sess_set_cache_size(ctx, cache_size);
+
+ SSL_CTX_set_timeout(ctx, (long) timeout);
+}
+
static nxt_uint_t
nxt_openssl_cert_get_names(nxt_task_t *task, X509 *cert, nxt_tls_conf_t *conf,
@@ -782,15 +1053,15 @@ nxt_openssl_servername(SSL *s, int *ad, void *arg)
}
servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name);
- if (nxt_slow_path(servername == NULL)) {
- nxt_log(c->socket.task, NXT_LOG_ALERT, "SSL_get_servername() returned "
- "NULL in server name callback");
- return SSL_TLSEXT_ERR_ALERT_FATAL;
+
+ if (servername == NULL) {
+ nxt_debug(c->socket.task, "SSL_get_servername(): NULL");
+ goto done;
}
str.length = nxt_strlen(servername);
if (str.length == 0) {
- nxt_debug(c->socket.task, "client sent zero-length server name");
+ nxt_debug(c->socket.task, "SSL_get_servername(): \"\" is empty");
goto done;
}
@@ -882,6 +1153,11 @@ nxt_openssl_server_free(nxt_task_t *task, nxt_tls_conf_t *conf)
bundle = bundle->next;
} while (bundle != NULL);
+ if (conf->tickets) {
+ nxt_memzero(conf->tickets->tickets,
+ conf->tickets->count * sizeof(nxt_tls_ticket_t));
+ }
+
#if (OPENSSL_VERSION_NUMBER >= 0x1010100fL \
&& OPENSSL_VERSION_NUMBER < 0x1010101fL)
RAND_keep_random_devices_open(0);
@@ -1543,3 +1819,70 @@ nxt_openssl_copy_error(u_char *p, u_char *end)
return p;
}
+
+
+nxt_int_t
+nxt_openssl_base64_decode(u_char *d, size_t dlen, const u_char *s, size_t slen)
+{
+ BIO *bio, *b64;
+ nxt_int_t count, ret;
+ u_char buf[128];
+
+ b64 = BIO_new(BIO_f_base64());
+ if (nxt_slow_path(b64 == NULL)) {
+ goto error;
+ }
+
+ bio = BIO_new_mem_buf(s, slen);
+ if (nxt_slow_path(bio == NULL)) {
+ goto error;
+ }
+
+ bio = BIO_push(b64, bio);
+
+ BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
+
+ count = 0;
+
+ if (d == NULL) {
+
+ for ( ;; ) {
+ ret = BIO_read(bio, buf, 128);
+
+ if (ret < 0) {
+ goto invalid;
+ }
+
+ count += ret;
+
+ if (ret != 128) {
+ break;
+ }
+ }
+
+ } else {
+ count = BIO_read(bio, d, dlen);
+
+ if (count < 0) {
+ goto invalid;
+ }
+ }
+
+ BIO_free_all(bio);
+
+ return count;
+
+error:
+
+ BIO_vfree(b64);
+ ERR_clear_error();
+
+ return NXT_ERROR;
+
+invalid:
+
+ BIO_free_all(bio);
+ ERR_clear_error();
+
+ return NXT_DECLINED;
+}
diff --git a/src/nxt_port.h b/src/nxt_port.h
index 5ece3bfa..a0bc2512 100644
--- a/src/nxt_port.h
+++ b/src/nxt_port.h
@@ -50,6 +50,7 @@ struct nxt_port_handlers_s {
/* Various data. */
nxt_port_handler_t data;
+ nxt_port_handler_t app_restart;
nxt_port_handler_t oosm;
nxt_port_handler_t shm_ack;
@@ -100,6 +101,7 @@ typedef enum {
_NXT_PORT_MSG_WEBSOCKET = nxt_port_handler_idx(websocket_frame),
_NXT_PORT_MSG_DATA = nxt_port_handler_idx(data),
+ _NXT_PORT_MSG_APP_RESTART = nxt_port_handler_idx(app_restart),
_NXT_PORT_MSG_OOSM = nxt_port_handler_idx(oosm),
_NXT_PORT_MSG_SHM_ACK = nxt_port_handler_idx(shm_ack),
@@ -139,6 +141,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_OOSM = nxt_msg_last(_NXT_PORT_MSG_OOSM),
NXT_PORT_MSG_SHM_ACK = nxt_msg_last(_NXT_PORT_MSG_SHM_ACK),
diff --git a/src/nxt_port_socket.c b/src/nxt_port_socket.c
index 3cf2e79a..ba1b7081 100644
--- a/src/nxt_port_socket.c
+++ b/src/nxt_port_socket.c
@@ -21,6 +21,7 @@ static nxt_int_t 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);
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);
static nxt_buf_t *nxt_port_buf_completion(nxt_task_t *task,
nxt_work_queue_t *wq, nxt_buf_t *b, size_t sent, nxt_bool_t mmap_mode);
static nxt_port_send_msg_t *nxt_port_msg_insert_tail(nxt_port_t *port,
@@ -449,19 +450,7 @@ next_fragment:
goto fail;
}
- if (msg->close_fd) {
- if (msg->fd[0] != -1) {
- nxt_fd_close(msg->fd[0]);
-
- msg->fd[0] = -1;
- }
-
- if (msg->fd[1] != -1) {
- nxt_fd_close(msg->fd[1]);
-
- msg->fd[1] = -1;
- }
- }
+ nxt_port_msg_close_fd(msg);
msg->buf = nxt_port_buf_completion(task, wq, msg->buf, plain_size,
m == NXT_PORT_METHOD_MMAP);
@@ -524,6 +513,12 @@ next_fragment:
} else {
if (nxt_slow_path(n == NXT_ERROR)) {
+ if (msg->link.next == NULL) {
+ nxt_port_msg_close_fd(msg);
+
+ nxt_port_release_send_msg(msg);
+ }
+
goto fail;
}
@@ -591,6 +586,27 @@ nxt_port_msg_first(nxt_port_t *port)
}
+nxt_inline void
+nxt_port_msg_close_fd(nxt_port_send_msg_t *msg)
+{
+ if (!msg->close_fd) {
+ return;
+ }
+
+ if (msg->fd[0] != -1) {
+ nxt_fd_close(msg->fd[0]);
+
+ msg->fd[0] = -1;
+ }
+
+ if (msg->fd[1] != -1) {
+ nxt_fd_close(msg->fd[1]);
+
+ msg->fd[1] = -1;
+ }
+}
+
+
static nxt_buf_t *
nxt_port_buf_completion(nxt_task_t *task, nxt_work_queue_t *wq, nxt_buf_t *b,
size_t sent, nxt_bool_t mmap_mode)
@@ -1315,19 +1331,7 @@ nxt_port_error_handler(nxt_task_t *task, void *obj, void *data)
nxt_queue_each(msg, &port->messages, nxt_port_send_msg_t, link) {
- if (msg->close_fd) {
- if (msg->fd[0] != -1) {
- nxt_fd_close(msg->fd[0]);
-
- msg->fd[0] = -1;
- }
-
- if (msg->fd[1] != -1) {
- nxt_fd_close(msg->fd[1]);
-
- msg->fd[1] = -1;
- }
- }
+ nxt_port_msg_close_fd(msg);
for (b = msg->buf; b != NULL; b = next) {
next = b->next;
diff --git a/src/nxt_router.c b/src/nxt_router.c
index 015ae226..39d375f8 100644
--- a/src/nxt_router.c
+++ b/src/nxt_router.c
@@ -18,6 +18,8 @@
#include <nxt_app_queue.h>
#include <nxt_port_queue.h>
+#define NXT_SHARED_PORT_ID 0xFFFFu
+
typedef struct {
nxt_str_t type;
uint32_t processes;
@@ -44,10 +46,10 @@ typedef struct {
nxt_str_t name;
nxt_socket_conf_t *socket_conf;
nxt_router_temp_conf_t *temp_conf;
- nxt_conf_value_t *conf_cmds;
+ nxt_tls_init_t *tls_init;
nxt_bool_t last;
- nxt_queue_link_t link; /* for nxt_socket_conf_t.tls */
+ nxt_queue_link_t link; /* for nxt_socket_conf_t.tls */
} nxt_router_tlssock_t;
#endif
@@ -67,6 +69,12 @@ typedef struct {
} nxt_app_rpc_t;
+typedef struct {
+ nxt_app_joint_t *app_joint;
+ uint32_t generation;
+} nxt_app_joint_rpc_t;
+
+
static nxt_int_t nxt_router_prefork(nxt_task_t *task, nxt_process_t *process,
nxt_mp_t *mp);
static nxt_int_t nxt_router_start(nxt_task_t *task, nxt_process_data_t *data);
@@ -79,6 +87,8 @@ static void nxt_router_new_port_handler(nxt_task_t *task,
nxt_port_recv_msg_t *msg);
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,
nxt_port_recv_msg_t *msg);
static void nxt_router_access_log_reopen_handler(nxt_task_t *task,
@@ -97,6 +107,9 @@ 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_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);
@@ -123,8 +136,8 @@ static void nxt_router_listen_socket_error(nxt_task_t *task,
static void nxt_router_tls_rpc_handler(nxt_task_t *task,
nxt_port_recv_msg_t *msg, void *data);
static nxt_int_t nxt_router_conf_tls_insert(nxt_router_temp_conf_t *tmcf,
- nxt_conf_value_t *value, nxt_socket_conf_t *skcf,
- nxt_conf_value_t * conf_cmds);
+ nxt_conf_value_t *value, nxt_socket_conf_t *skcf, nxt_tls_init_t *tls_init,
+ nxt_bool_t last);
#endif
static void nxt_router_app_rpc_create(nxt_task_t *task,
nxt_router_temp_conf_t *tmcf, nxt_app_t *app);
@@ -224,8 +237,6 @@ static void nxt_router_http_request_error(nxt_task_t *task, void *obj,
static void nxt_router_http_request_done(nxt_task_t *task, void *obj,
void *data);
-static void nxt_router_dummy_buf_completion(nxt_task_t *task, void *obj,
- void *data);
static void nxt_router_app_prepare_request(nxt_task_t *task,
nxt_request_rpc_data_t *req_rpc_data);
static nxt_buf_t *nxt_router_prepare_msg(nxt_task_t *task,
@@ -281,6 +292,7 @@ static const nxt_port_handlers_t nxt_router_process_port_handlers = {
.mmap = nxt_port_mmap_handler,
.get_mmap = nxt_router_get_mmap_handler,
.data = nxt_router_conf_data_handler,
+ .app_restart = nxt_router_app_restart_handler,
.remove_pid = nxt_router_remove_pid_handler,
.access_log = nxt_router_access_log_reopen_handler,
.rpc_ready = nxt_port_rpc_handler,
@@ -379,14 +391,15 @@ static void
nxt_router_start_app_process_handler(nxt_task_t *task, nxt_port_t *port,
void *data)
{
- size_t size;
- uint32_t stream;
- nxt_mp_t *mp;
- nxt_int_t ret;
- nxt_app_t *app;
- nxt_buf_t *b;
- nxt_port_t *main_port;
- nxt_runtime_t *rt;
+ size_t size;
+ uint32_t stream;
+ nxt_mp_t *mp;
+ nxt_int_t ret;
+ nxt_app_t *app;
+ nxt_buf_t *b;
+ nxt_port_t *main_port;
+ nxt_runtime_t *rt;
+ nxt_app_joint_rpc_t *app_joint_rpc;
app = data;
@@ -407,30 +420,29 @@ nxt_router_start_app_process_handler(nxt_task_t *task, nxt_port_t *port,
*b->mem.free++ = '\0';
nxt_buf_cpystr(b, &app->conf);
- nxt_router_app_joint_use(task, app->joint, 1);
-
- stream = nxt_port_rpc_register_handler(task, port,
- nxt_router_app_port_ready,
- nxt_router_app_port_error,
- -1, app->joint);
-
- if (nxt_slow_path(stream == 0)) {
- nxt_router_app_joint_use(task, app->joint, -1);
-
+ app_joint_rpc = nxt_port_rpc_register_handler_ex(task, port,
+ nxt_router_app_port_ready,
+ nxt_router_app_port_error,
+ sizeof(nxt_app_joint_rpc_t));
+ if (nxt_slow_path(app_joint_rpc == NULL)) {
goto failed;
}
+ stream = nxt_port_rpc_ex_stream(app_joint_rpc);
+
ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_START_PROCESS,
-1, stream, port->id, b);
-
if (nxt_slow_path(ret != NXT_OK)) {
nxt_port_rpc_cancel(task, port, stream);
- nxt_router_app_joint_use(task, app->joint, -1);
-
goto failed;
}
+ app_joint_rpc->app_joint = app->joint;
+ app_joint_rpc->generation = app->generation;
+
+ nxt_router_app_joint_use(task, app->joint, 1);
+
nxt_router_app_use(task, app, -1);
return;
@@ -504,6 +516,7 @@ nxt_router_msg_cancel(nxt_task_t *task, nxt_request_rpc_data_t *req_rpc_data)
{
nxt_buf_t *b, *next;
nxt_bool_t cancelled;
+ nxt_port_t *app_port;
nxt_msg_info_t *msg_info;
msg_info = &req_rpc_data->msg_info;
@@ -512,13 +525,20 @@ nxt_router_msg_cancel(nxt_task_t *task, nxt_request_rpc_data_t *req_rpc_data)
return 0;
}
- cancelled = nxt_app_queue_cancel(req_rpc_data->app->shared_port->queue,
- msg_info->tracking_cookie,
- req_rpc_data->stream);
+ app_port = req_rpc_data->app_port;
+
+ if (app_port != NULL && app_port->id == NXT_SHARED_PORT_ID) {
+ cancelled = nxt_app_queue_cancel(app_port->queue,
+ msg_info->tracking_cookie,
+ req_rpc_data->stream);
- if (cancelled) {
- nxt_debug(task, "stream #%uD: cancelled by router",
- req_rpc_data->stream);
+ if (cancelled) {
+ nxt_debug(task, "stream #%uD: cancelled by router",
+ req_rpc_data->stream);
+ }
+
+ } else {
+ cancelled = 0;
}
for (b = msg_info->buf; b != NULL; b = next) {
@@ -680,18 +700,20 @@ nxt_router_new_port_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
nxt_assert(main_app_port != NULL);
app = main_app_port->app;
- nxt_assert(app != NULL);
- nxt_thread_mutex_lock(&app->mutex);
+ if (nxt_fast_path(app != NULL)) {
+ nxt_thread_mutex_lock(&app->mutex);
- /* TODO here should be find-and-add code because there can be
- port waiters in port_hash */
- nxt_port_hash_add(&app->port_hash, port);
- app->port_hash_count++;
+ /* TODO here should be find-and-add code because there can be
+ port waiters in port_hash */
+ nxt_port_hash_add(&app->port_hash, port);
+ app->port_hash_count++;
- nxt_thread_mutex_unlock(&app->mutex);
+ nxt_thread_mutex_unlock(&app->mutex);
+
+ port->app = app;
+ }
- port->app = app;
port->main_app_port = main_app_port;
nxt_port_socket_write(task, port, NXT_PORT_MSG_PORT_ACK, -1, 0, 0, NULL);
@@ -792,6 +814,90 @@ cleanup:
static void
+nxt_router_app_restart_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
+{
+ nxt_app_t *app;
+ nxt_int_t ret;
+ nxt_str_t app_name;
+ nxt_port_t *port, *reply_port, *shared_port, *old_shared_port;
+ nxt_port_msg_type_t reply;
+
+ reply_port = nxt_runtime_port_find(task->thread->runtime,
+ msg->port_msg.pid,
+ msg->port_msg.reply_port);
+ if (nxt_slow_path(reply_port == NULL)) {
+ nxt_alert(task, "app_restart_handler: reply port not found");
+ return;
+ }
+
+ app_name.length = nxt_buf_mem_used_size(&msg->buf->mem);
+ app_name.start = msg->buf->mem.pos;
+
+ nxt_debug(task, "app_restart_handler: %V", &app_name);
+
+ app = nxt_router_app_find(&nxt_router->apps, &app_name);
+
+ if (nxt_fast_path(app != NULL)) {
+ shared_port = nxt_port_new(task, NXT_SHARED_PORT_ID, nxt_pid,
+ NXT_PROCESS_APP);
+ if (nxt_slow_path(shared_port == NULL)) {
+ goto fail;
+ }
+
+ ret = nxt_port_socket_init(task, shared_port, 0);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ nxt_port_use(task, shared_port, -1);
+ goto fail;
+ }
+
+ ret = nxt_router_app_queue_init(task, shared_port);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ nxt_port_write_close(shared_port);
+ nxt_port_read_close(shared_port);
+ nxt_port_use(task, shared_port, -1);
+ goto fail;
+ }
+
+ nxt_port_write_enable(task, shared_port);
+
+ nxt_thread_mutex_lock(&app->mutex);
+
+ nxt_queue_each(port, &app->ports, nxt_port_t, app_link) {
+
+ (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1,
+ 0, 0, NULL);
+
+ } nxt_queue_loop;
+
+ app->generation++;
+
+ shared_port->app = app;
+
+ old_shared_port = app->shared_port;
+ old_shared_port->app = NULL;
+
+ app->shared_port = shared_port;
+
+ nxt_thread_mutex_unlock(&app->mutex);
+
+ nxt_port_close(task, old_shared_port);
+ nxt_port_use(task, old_shared_port, -1);
+
+ reply = NXT_PORT_MSG_RPC_READY_LAST;
+
+ } else {
+
+fail:
+
+ reply = NXT_PORT_MSG_RPC_ERROR;
+ }
+
+ nxt_port_socket_write(task, reply_port, reply, -1, msg->port_msg.stream,
+ 0, NULL);
+}
+
+
+static void
nxt_router_app_process_remove_pid(nxt_task_t *task, nxt_port_t *port,
void *data)
{
@@ -956,8 +1062,6 @@ nxt_router_conf_apply(nxt_task_t *task, void *obj, void *data)
tls = nxt_queue_link_data(qlk, nxt_router_tlssock_t, link);
- tls->last = nxt_queue_is_empty(&tmcf->tls);
-
nxt_cert_store_get(task, &tls->name, tmcf->mem_pool,
nxt_router_tls_rpc_handler, tls);
return;
@@ -1341,12 +1445,13 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
nxt_router_t *router;
nxt_app_joint_t *app_joint;
#if (NXT_TLS)
- nxt_conf_value_t *certificate, *conf_cmds;
+ nxt_tls_init_t *tls_init;
+ nxt_conf_value_t *certificate;
#endif
nxt_conf_value_t *conf, *http, *value, *websocket;
nxt_conf_value_t *applications, *application;
nxt_conf_value_t *listeners, *listener;
- nxt_conf_value_t *routes_conf, *static_conf;
+ nxt_conf_value_t *routes_conf, *static_conf, *client_ip_conf;
nxt_socket_conf_t *skcf;
nxt_http_routes_t *routes;
nxt_event_engine_t *engine;
@@ -1363,9 +1468,13 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
#if (NXT_TLS)
static nxt_str_t certificate_path = nxt_string("/tls/certificate");
static nxt_str_t conf_commands_path = nxt_string("/tls/conf_commands");
+ static nxt_str_t conf_cache_path = nxt_string("/tls/session/cache_size");
+ static nxt_str_t conf_timeout_path = nxt_string("/tls/session/timeout");
+ static nxt_str_t conf_tickets = nxt_string("/tls/session/tickets");
#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 client_ip_path = nxt_string("/client_ip");
conf = nxt_conf_json_parse(tmcf->mem_pool, start, end, NULL);
if (conf == NULL) {
@@ -1604,7 +1713,7 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
app_joint->free_app_work.task = &engine->task;
app_joint->free_app_work.obj = app_joint;
- port = nxt_port_new(task, (nxt_port_id_t) -1, nxt_pid,
+ port = nxt_port_new(task, NXT_SHARED_PORT_ID, nxt_pid,
NXT_PROCESS_APP);
if (nxt_slow_path(port == NULL)) {
return NXT_ERROR;
@@ -1737,11 +1846,40 @@ 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;
+ }
+
#if (NXT_TLS)
certificate = nxt_conf_get_path(listener, &certificate_path);
if (certificate != NULL) {
- conf_cmds = nxt_conf_get_path(listener, &conf_commands_path);
+ tls_init = nxt_mp_get(tmcf->mem_pool, sizeof(nxt_tls_init_t));
+ if (nxt_slow_path(tls_init == NULL)) {
+ return NXT_ERROR;
+ }
+
+ tls_init->cache_size = 0;
+ tls_init->timeout = 300;
+
+ value = nxt_conf_get_path(listener, &conf_cache_path);
+ if (value != NULL) {
+ tls_init->cache_size = nxt_conf_get_number(value);
+ }
+
+ value = nxt_conf_get_path(listener, &conf_timeout_path);
+ if (value != NULL) {
+ tls_init->timeout = nxt_conf_get_number(value);
+ }
+
+ tls_init->conf_cmds = nxt_conf_get_path(listener,
+ &conf_commands_path);
+
+ tls_init->tickets_conf = nxt_conf_get_path(listener,
+ &conf_tickets);
if (nxt_conf_type(certificate) == NXT_CONF_ARRAY) {
n = nxt_conf_array_elements_count(certificate);
@@ -1752,7 +1890,7 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
nxt_assert(value != NULL);
ret = nxt_router_conf_tls_insert(tmcf, value, skcf,
- conf_cmds);
+ tls_init, i == 0);
if (nxt_slow_path(ret != NXT_OK)) {
goto fail;
}
@@ -1761,7 +1899,7 @@ nxt_router_conf_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
} else {
/* NXT_CONF_STRING */
ret = nxt_router_conf_tls_insert(tmcf, certificate, skcf,
- conf_cmds);
+ tls_init, 1);
if (nxt_slow_path(ret != NXT_OK)) {
goto fail;
}
@@ -1856,7 +1994,7 @@ fail:
static nxt_int_t
nxt_router_conf_tls_insert(nxt_router_temp_conf_t *tmcf,
nxt_conf_value_t *value, nxt_socket_conf_t *skcf,
- nxt_conf_value_t *conf_cmds)
+ nxt_tls_init_t *tls_init, nxt_bool_t last)
{
nxt_router_tlssock_t *tls;
@@ -1865,9 +2003,10 @@ nxt_router_conf_tls_insert(nxt_router_temp_conf_t *tmcf,
return NXT_ERROR;
}
+ tls->tls_init = tls_init;
tls->socket_conf = skcf;
- tls->conf_cmds = conf_cmds;
tls->temp_conf = tmcf;
+ tls->last = last;
nxt_conf_get_string(value, &tls->name);
nxt_queue_insert_tail(&tmcf->tls, &tls->link);
@@ -1884,7 +2023,7 @@ nxt_router_conf_process_static(nxt_task_t *task, nxt_router_conf_t *rtcf,
{
uint32_t next, i;
nxt_mp_t *mp;
- nxt_str_t *type, extension, str;
+ nxt_str_t *type, exten, str;
nxt_int_t ret;
nxt_uint_t exts;
nxt_conf_value_t *mtypes_conf, *ext_conf, *value;
@@ -1922,12 +2061,12 @@ nxt_router_conf_process_static(nxt_task_t *task, nxt_router_conf_t *rtcf,
if (nxt_conf_type(ext_conf) == NXT_CONF_STRING) {
nxt_conf_get_string(ext_conf, &str);
- if (nxt_slow_path(nxt_str_dup(mp, &extension, &str) == NULL)) {
+ if (nxt_slow_path(nxt_str_dup(mp, &exten, &str) == NULL)) {
return NXT_ERROR;
}
ret = nxt_http_static_mtypes_hash_add(mp, &rtcf->mtypes_hash,
- &extension, type);
+ &exten, type);
if (nxt_slow_path(ret != NXT_OK)) {
return NXT_ERROR;
}
@@ -1942,12 +2081,12 @@ nxt_router_conf_process_static(nxt_task_t *task, nxt_router_conf_t *rtcf,
nxt_conf_get_string(value, &str);
- if (nxt_slow_path(nxt_str_dup(mp, &extension, &str) == NULL)) {
+ if (nxt_slow_path(nxt_str_dup(mp, &exten, &str) == NULL)) {
return NXT_ERROR;
}
ret = nxt_http_static_mtypes_hash_add(mp, &rtcf->mtypes_hash,
- &extension, type);
+ &exten, type);
if (nxt_slow_path(ret != NXT_OK)) {
return NXT_ERROR;
}
@@ -1959,6 +2098,79 @@ 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)
+{
+ 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_http_route_addr_rule_t *source;
+
+ static nxt_str_t header_path = nxt_string("/header");
+ 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;
+
+ return NXT_OK;
+ }
+
+ mp = tmcf->router_conf->mem_pool;
+
+ 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;
+ }
+
+ client_ip = nxt_mp_zget(mp, sizeof(nxt_http_client_ip_t));
+ if (nxt_slow_path(client_ip == NULL)) {
+ return NXT_ERROR;
+ }
+
+ source = nxt_http_route_addr_rule_create(task, mp, source_conf);
+ if (nxt_slow_path(source == NULL)) {
+ return NXT_ERROR;
+ }
+
+ client_ip->source = source;
+
+ nxt_conf_get_string(header_conf, &header);
+
+ if (recursive_conf != NULL) {
+ client_ip->recursive = nxt_conf_get_boolean(recursive_conf);
+ }
+
+ client_ip->header = nxt_str_dup(mp, NULL, &header);
+ if (nxt_slow_path(client_ip->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];
+ 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;
+
+ return NXT_OK;
+}
+
+
static nxt_app_t *
nxt_router_app_find(nxt_queue_t *queue, nxt_str_t *name)
{
@@ -2135,21 +2347,46 @@ nxt_router_apps_hash_use(nxt_task_t *task, nxt_router_conf_t *rtcf, int i)
}
+typedef struct {
+ nxt_app_t *app;
+ nxt_int_t target;
+} nxt_http_app_conf_t;
+
nxt_int_t
-nxt_router_listener_application(nxt_router_conf_t *rtcf, nxt_str_t *name,
- nxt_http_action_t *action)
+nxt_router_application_init(nxt_router_conf_t *rtcf, nxt_str_t *name,
+ nxt_str_t *target, nxt_http_action_t *action)
{
- nxt_app_t *app;
+ nxt_app_t *app;
+ nxt_str_t *targets;
+ nxt_uint_t i;
+ nxt_http_app_conf_t *conf;
app = nxt_router_apps_hash_get(rtcf, name);
-
if (app == NULL) {
return NXT_DECLINED;
}
- action->u.app.application = app;
+ conf = nxt_mp_get(rtcf->mem_pool, sizeof(nxt_http_app_conf_t));
+ if (nxt_slow_path(conf == NULL)) {
+ return NXT_ERROR;
+ }
+
action->handler = nxt_http_application_handler;
+ action->u.conf = conf;
+
+ conf->app = app;
+
+ if (target != NULL && target->length != 0) {
+ targets = app->targets;
+
+ for (i = 0; !nxt_strstr_eq(target, &targets[i]); i++);
+
+ conf->target = i;
+
+ } else {
+ conf->target = 0;
+ }
return NXT_OK;
}
@@ -2297,7 +2534,7 @@ nxt_router_listen_socket_rpc_create(nxt_task_t *task,
goto fail;
}
- b->completion_handler = nxt_router_dummy_buf_completion;
+ b->completion_handler = nxt_buf_dummy_completion;
b->mem.free = nxt_cpymem(b->mem.free, skcf->listen->sockaddr, size);
@@ -2466,6 +2703,8 @@ nxt_router_tls_rpc_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
tlscf = tls->socket_conf->tls;
}
+ tls->tls_init->conf = tlscf;
+
bundle = nxt_mp_get(mp, sizeof(nxt_tls_bundle_conf_t));
if (nxt_slow_path(bundle == NULL)) {
goto fail;
@@ -2479,8 +2718,8 @@ nxt_router_tls_rpc_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
bundle->next = tlscf->bundle;
tlscf->bundle = bundle;
- ret = task->thread->runtime->tls->server_init(task, tlscf, mp,
- tls->conf_cmds, tls->last);
+ ret = task->thread->runtime->tls->server_init(task, mp, tls->tls_init,
+ tls->last);
if (nxt_slow_path(ret != NXT_OK)) {
goto fail;
}
@@ -2526,7 +2765,7 @@ nxt_router_app_rpc_create(nxt_task_t *task,
goto fail;
}
- b->completion_handler = nxt_router_dummy_buf_completion;
+ b->completion_handler = nxt_buf_dummy_completion;
nxt_buf_cpystr(b, &app->name);
*b->mem.free++ = '\0';
@@ -3555,7 +3794,7 @@ nxt_router_access_log_open(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
goto fail;
}
- b->completion_handler = nxt_router_dummy_buf_completion;
+ b->completion_handler = nxt_buf_dummy_completion;
nxt_buf_cpystr(b, &access_log->path);
*b->mem.free++ = '\0';
@@ -4183,11 +4422,16 @@ static void
nxt_router_app_port_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
void *data)
{
- nxt_app_t *app;
- nxt_port_t *port;
- nxt_app_joint_t *app_joint;
+ nxt_app_t *app;
+ nxt_bool_t start_process;
+ nxt_port_t *port;
+ nxt_app_joint_t *app_joint;
+ nxt_app_joint_rpc_t *app_joint_rpc;
+
+ nxt_assert(data != NULL);
- app_joint = data;
+ app_joint_rpc = data;
+ app_joint = app_joint_rpc->app_joint;
port = msg->u.new_port;
nxt_assert(app_joint != NULL);
@@ -4207,14 +4451,37 @@ nxt_router_app_port_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
return;
}
- port->app = app;
- port->main_app_port = port;
-
nxt_thread_mutex_lock(&app->mutex);
nxt_assert(app->pending_processes != 0);
app->pending_processes--;
+
+ if (nxt_slow_path(app->generation != app_joint_rpc->generation)) {
+ nxt_debug(task, "new port ready for restarted app, send QUIT");
+
+ start_process = !task->thread->engine->shutdown
+ && nxt_router_app_can_start(app)
+ && nxt_router_app_need_start(app);
+
+ if (start_process) {
+ app->pending_processes++;
+ }
+
+ nxt_thread_mutex_unlock(&app->mutex);
+
+ nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT, -1, 0, 0, NULL);
+
+ if (start_process) {
+ nxt_router_start_app_process(task, app);
+ }
+
+ return;
+ }
+
+ port->app = app;
+ port->main_app_port = port;
+
app->processes++;
nxt_port_hash_add(&app->port_hash, port);
app->port_hash_count++;
@@ -4268,12 +4535,16 @@ static void
nxt_router_app_port_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
void *data)
{
- nxt_app_t *app;
- nxt_app_joint_t *app_joint;
- nxt_queue_link_t *link;
- nxt_http_request_t *r;
+ nxt_app_t *app;
+ nxt_app_joint_t *app_joint;
+ nxt_queue_link_t *link;
+ nxt_http_request_t *r;
+ nxt_app_joint_rpc_t *app_joint_rpc;
+
+ nxt_assert(data != NULL);
- app_joint = data;
+ app_joint_rpc = data;
+ app_joint = app_joint_rpc->app_joint;
nxt_assert(app_joint != NULL);
@@ -4440,7 +4711,7 @@ nxt_router_app_port_release(nxt_task_t *task, nxt_port_t *port,
port->pid, port->id,
(int) inc_use, (int) got_response);
- if (port == app->shared_port) {
+ if (port->id == NXT_SHARED_PORT_ID) {
nxt_thread_mutex_lock(&app->mutex);
app->active_requests -= got_response + dec_requests;
@@ -4810,6 +5081,8 @@ nxt_router_free_app(nxt_task_t *task, void *obj, void *data)
app->shared_port->app = NULL;
nxt_port_close(task, app->shared_port);
nxt_port_use(task, app->shared_port, -1);
+
+ app->shared_port = NULL;
}
nxt_thread_mutex_destroy(&app->mutex);
@@ -4876,13 +5149,17 @@ nxt_router_app_port_get(nxt_task_t *task, nxt_app_t *app,
void
nxt_router_process_http_request(nxt_task_t *task, nxt_http_request_t *r,
- nxt_app_t *app)
+ nxt_http_action_t *action)
{
nxt_event_engine_t *engine;
+ nxt_http_app_conf_t *conf;
nxt_request_rpc_data_t *req_rpc_data;
+ conf = action->u.conf;
engine = task->thread->engine;
+ r->app_target = conf->target;
+
req_rpc_data = nxt_port_rpc_register_handler_ex(task, engine->port,
nxt_router_response_ready_handler,
nxt_router_response_error_handler,
@@ -4913,11 +5190,11 @@ nxt_router_process_http_request(nxt_task_t *task, nxt_http_request_t *r,
r->err_work.obj = r;
req_rpc_data->stream = nxt_port_rpc_ex_stream(req_rpc_data);
- req_rpc_data->app = app;
+ req_rpc_data->app = conf->app;
req_rpc_data->msg_info.body_fd = -1;
req_rpc_data->rpc_cancel = 1;
- nxt_router_app_use(task, app, 1);
+ nxt_router_app_use(task, conf->app, 1);
req_rpc_data->request = r;
r->req_rpc_data = req_rpc_data;
@@ -4926,7 +5203,7 @@ nxt_router_process_http_request(nxt_task_t *task, nxt_http_request_t *r,
r->last->completion_handler = nxt_router_http_request_done;
}
- nxt_router_app_port_get(task, app, req_rpc_data);
+ nxt_router_app_port_get(task, conf->app, req_rpc_data);
nxt_router_app_prepare_request(task, req_rpc_data);
}
@@ -4968,12 +5245,6 @@ nxt_router_http_request_done(nxt_task_t *task, void *obj, void *data)
static void
-nxt_router_dummy_buf_completion(nxt_task_t *task, void *obj, void *data)
-{
-}
-
-
-static void
nxt_router_app_prepare_request(nxt_task_t *task,
nxt_request_rpc_data_t *req_rpc_data)
{
diff --git a/src/nxt_router.h b/src/nxt_router.h
index b1ccdf51..fc068b53 100644
--- a/src/nxt_router.h
+++ b/src/nxt_router.h
@@ -18,6 +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_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;
@@ -125,6 +126,8 @@ struct nxt_app_s {
uint32_t max_pending_processes;
uint32_t max_requests;
+ uint32_t generation;
+
nxt_msec_t timeout;
nxt_msec_t idle_timeout;
@@ -193,6 +196,8 @@ typedef struct {
uint8_t discard_unsafe_fields; /* 1 bit */
+ nxt_http_client_ip_t *client_ip;
+
#if (NXT_TLS)
nxt_tls_conf_t *tls;
#endif
@@ -223,10 +228,10 @@ struct nxt_router_access_log_s {
void nxt_router_process_http_request(nxt_task_t *task, nxt_http_request_t *r,
- nxt_app_t *app);
+ nxt_http_action_t *action);
void nxt_router_app_port_close(nxt_task_t *task, nxt_port_t *port);
-nxt_int_t nxt_router_listener_application(nxt_router_conf_t *rtcf,
- nxt_str_t *name, nxt_http_action_t *action);
+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_release(nxt_task_t *task, nxt_socket_conf_joint_t *joint);
diff --git a/src/nxt_sockaddr.c b/src/nxt_sockaddr.c
index af696a6b..730428e4 100644
--- a/src/nxt_sockaddr.c
+++ b/src/nxt_sockaddr.c
@@ -525,9 +525,9 @@ nxt_inet6_ntop(u_char *addr, u_char *buf, u_char *end)
return buf;
}
- zero_start = 8;
+ zero_start = 16;
zero_groups = 0;
- last_zero_start = 8;
+ last_zero_start = 16;
last_zero_groups = 0;
for (i = 0; i < 16; i += 2) {
@@ -605,10 +605,35 @@ nxt_sockaddr_parse(nxt_mp_t *mp, nxt_str_t *addr)
{
nxt_sockaddr_t *sa;
+ sa = nxt_sockaddr_parse_optport(mp, addr);
+
+ if (sa != NULL
+ && sa->u.sockaddr.sa_family != AF_UNIX
+ && nxt_sockaddr_port_number(sa) == 0)
+ {
+ nxt_thread_log_error(NXT_LOG_ERR,
+ "The address \"%V\" must specify a port.", addr);
+ return NULL;
+ }
+
+ return sa;
+}
+
+
+nxt_sockaddr_t *
+nxt_sockaddr_parse_optport(nxt_mp_t *mp, nxt_str_t *addr)
+{
+ nxt_sockaddr_t *sa;
+
+ if (addr->length == 0) {
+ nxt_thread_log_error(NXT_LOG_ERR, "socket address cannot be empty");
+ return NULL;
+ }
+
if (addr->length > 6 && nxt_memcmp(addr->start, "unix:", 5) == 0) {
sa = nxt_sockaddr_unix_parse(mp, addr);
- } else if (addr->length != 0 && addr->start[0] == '[') {
+ } else if (addr->start[0] == '[' || nxt_inet6_probe(addr)) {
sa = nxt_sockaddr_inet6_parse(mp, addr);
} else {
@@ -703,44 +728,60 @@ nxt_sockaddr_inet6_parse(nxt_mp_t *mp, nxt_str_t *addr)
nxt_int_t ret, port;
nxt_sockaddr_t *sa;
- length = addr->length - 1;
- start = addr->start + 1;
+ if (addr->start[0] == '[') {
+ length = addr->length - 1;
+ start = addr->start + 1;
- end = nxt_memchr(start, ']', length);
-
- if (end != NULL) {
- sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in6),
- NXT_INET6_ADDR_STR_LEN);
- if (nxt_slow_path(sa == NULL)) {
+ end = nxt_memchr(start, ']', length);
+ if (nxt_slow_path(end == NULL)) {
return NULL;
}
- ret = nxt_inet6_addr(&sa->u.sockaddr_in6.sin6_addr, start, end - start);
+ p = end + 1;
+
+ } else {
+ length = addr->length;
+ start = addr->start;
+ end = addr->start + addr->length;
+ p = NULL;
+ }
- if (nxt_fast_path(ret == NXT_OK)) {
- p = end + 1;
- length = (start + length) - p;
+ port = 0;
- if (length > 2 && *p == ':') {
- port = nxt_int_parse(p + 1, length - 1);
+ if (p != NULL) {
+ length = (start + length) - p;
- if (port > 0 && port < 65536) {
- sa->u.sockaddr_in6.sin6_port = htons((in_port_t) port);
- sa->u.sockaddr_in6.sin6_family = AF_INET6;
+ if (length < 2 || *p != ':') {
+ nxt_thread_log_error(NXT_LOG_ERR, "invalid IPv6 address in \"%V\"",
+ addr);
+ return NULL;
+ }
- return sa;
- }
- }
+ port = nxt_int_parse(p + 1, length - 1);
+ if (port < 1 || port > 65535) {
nxt_thread_log_error(NXT_LOG_ERR, "invalid port in \"%V\"", addr);
-
return NULL;
}
}
- nxt_thread_log_error(NXT_LOG_ERR, "invalid IPv6 address in \"%V\"", addr);
+ sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in6),
+ NXT_INET6_ADDR_STR_LEN);
+ if (nxt_slow_path(sa == NULL)) {
+ return NULL;
+ }
- return NULL;
+ ret = nxt_inet6_addr(&sa->u.sockaddr_in6.sin6_addr, start, end - start);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ nxt_thread_log_error(NXT_LOG_ERR, "invalid IPv6 address in \"%V\"",
+ addr);
+ return NULL;
+ }
+
+ sa->u.sockaddr_in6.sin6_family = AF_INET6;
+ sa->u.sockaddr_in6.sin6_port = htons((in_port_t) port);
+
+ return sa;
#else /* !(NXT_INET6) */
@@ -763,41 +804,48 @@ nxt_sockaddr_inet_parse(nxt_mp_t *mp, nxt_str_t *addr)
p = nxt_memchr(addr->start, ':', addr->length);
- if (nxt_fast_path(p != NULL)) {
- inaddr = INADDR_ANY;
+ if (p == NULL) {
+ length = addr->length;
+
+ } else {
length = p - addr->start;
+ }
- if (length != 1 || addr->start[0] != '*') {
- inaddr = nxt_inet_addr(addr->start, length);
+ inaddr = INADDR_ANY;
- if (nxt_slow_path(inaddr == INADDR_NONE)) {
- nxt_thread_log_error(NXT_LOG_ERR, "invalid address \"%V\"",
- addr);
- return NULL;
- }
+ if (length != 1 || addr->start[0] != '*') {
+ inaddr = nxt_inet_addr(addr->start, length);
+ if (nxt_slow_path(inaddr == INADDR_NONE)) {
+ nxt_thread_log_error(NXT_LOG_ERR, "invalid address \"%V\"", addr);
+ return NULL;
}
+ }
+
+ port = 0;
+ if (p != NULL) {
p++;
length = (addr->start + addr->length) - p;
- port = nxt_int_parse(p, length);
-
- if (port > 0 && port < 65536) {
- sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in),
- NXT_INET_ADDR_STR_LEN);
- if (nxt_fast_path(sa != NULL)) {
- sa->u.sockaddr_in.sin_family = AF_INET;
- sa->u.sockaddr_in.sin_port = htons((in_port_t) port);
- sa->u.sockaddr_in.sin_addr.s_addr = inaddr;
- }
+ port = nxt_int_parse(p, length);
- return sa;
+ if (port < 1 || port > 65535) {
+ nxt_thread_log_error(NXT_LOG_ERR, "invalid port in \"%V\"", addr);
+ return NULL;
}
}
- nxt_thread_log_error(NXT_LOG_ERR, "invalid port in \"%V\"", addr);
+ sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in),
+ NXT_INET_ADDR_STR_LEN);
+ if (nxt_slow_path(sa == NULL)) {
+ return NULL;
+ }
- return NULL;
+ sa->u.sockaddr_in.sin_family = AF_INET;
+ sa->u.sockaddr_in.sin_addr.s_addr = inaddr;
+ sa->u.sockaddr_in.sin_port = htons((in_port_t) port);
+
+ return sa;
}
@@ -1320,3 +1368,19 @@ nxt_inet6_addr(struct in6_addr *in6_addr, u_char *buf, size_t length)
}
#endif
+
+
+nxt_bool_t
+nxt_inet6_probe(nxt_str_t *str)
+{
+ u_char *colon, *end;
+
+ colon = nxt_memchr(str->start, ':', str->length);
+
+ if (colon != NULL) {
+ end = str->start + str->length;
+ colon = nxt_memchr(colon + 1, ':', end - (colon + 1));
+ }
+
+ return (colon != NULL);
+}
diff --git a/src/nxt_sockaddr.h b/src/nxt_sockaddr.h
index aa4da5d2..a8f1b393 100644
--- a/src/nxt_sockaddr.h
+++ b/src/nxt_sockaddr.h
@@ -91,12 +91,15 @@ NXT_EXPORT nxt_bool_t nxt_sockaddr_cmp(nxt_sockaddr_t *sa1,
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,
size_t len);
#endif
+NXT_EXPORT nxt_bool_t nxt_inet6_probe(nxt_str_t *addr);
#define NXT_INET_ADDR_STR_LEN nxt_length("255.255.255.255:65535")
diff --git a/src/nxt_tls.h b/src/nxt_tls.h
index 63c49ee4..eeb4e7ba 100644
--- a/src/nxt_tls.h
+++ b/src/nxt_tls.h
@@ -28,14 +28,16 @@
typedef struct nxt_tls_conf_s nxt_tls_conf_t;
typedef struct nxt_tls_bundle_conf_s nxt_tls_bundle_conf_t;
+typedef struct nxt_tls_init_s nxt_tls_init_t;
+typedef struct nxt_tls_ticket_s nxt_tls_ticket_t;
+typedef struct nxt_tls_tickets_s nxt_tls_tickets_t;
typedef struct {
nxt_int_t (*library_init)(nxt_task_t *task);
void (*library_free)(nxt_task_t *task);
- nxt_int_t (*server_init)(nxt_task_t *task,
- nxt_tls_conf_t *conf, nxt_mp_t *mp,
- nxt_conf_value_t *conf_cmds,
+ nxt_int_t (*server_init)(nxt_task_t *task, nxt_mp_t *mp,
+ nxt_tls_init_t *tls_init,
nxt_bool_t last);
void (*server_free)(nxt_task_t *task,
nxt_tls_conf_t *conf);
@@ -63,6 +65,8 @@ struct nxt_tls_conf_s {
nxt_tls_bundle_conf_t *bundle;
nxt_lvlhsh_t bundle_hash;
+ nxt_tls_tickets_t *tickets;
+
void (*conn_init)(nxt_task_t *task,
nxt_tls_conf_t *conf, nxt_conn_t *c);
@@ -78,12 +82,38 @@ struct nxt_tls_conf_s {
};
+struct nxt_tls_init_s {
+ size_t cache_size;
+ nxt_time_t timeout;
+ nxt_conf_value_t *conf_cmds;
+ nxt_conf_value_t *tickets_conf;
+
+ nxt_tls_conf_t *conf;
+};
+
+
+struct nxt_tls_ticket_s {
+ uint8_t aes128;
+ u_char name[16];
+ u_char hmac_key[32];
+ u_char aes_key[32];
+};
+
+
+struct nxt_tls_tickets_s {
+ nxt_uint_t count;
+ nxt_tls_ticket_t tickets[];
+};
+
+
#if (NXT_HAVE_OPENSSL)
extern const nxt_tls_lib_t nxt_openssl_lib;
void nxt_cdecl nxt_openssl_log_error(nxt_task_t *task, nxt_uint_t level,
const char *fmt, ...);
u_char *nxt_openssl_copy_error(u_char *p, u_char *end);
+nxt_int_t nxt_openssl_base64_decode(u_char *d, size_t dlen, const u_char *s,
+ size_t slen);
#endif
#if (NXT_HAVE_GNUTLS)
diff --git a/src/nxt_upstream.c b/src/nxt_upstream.c
index 9f81b286..de9b1d49 100644
--- a/src/nxt_upstream.c
+++ b/src/nxt_upstream.c
@@ -78,6 +78,10 @@ nxt_upstream_find(nxt_upstreams_t *upstreams, nxt_str_t *name,
uint32_t i, n;
nxt_upstream_t *upstream;
+ if (upstreams == NULL) {
+ return NXT_DECLINED;
+ }
+
upstream = &upstreams->upstream[0];
n = upstreams->items;
diff --git a/src/python/nxt_python.c b/src/python/nxt_python.c
index 588a147a..abb04194 100644
--- a/src/python/nxt_python.c
+++ b/src/python/nxt_python.c
@@ -264,7 +264,7 @@ nxt_python_start(nxt_task_t *task, nxt_process_data_t *data)
goto fail;
}
- rc = nxt_py_proto.ctx_data_alloc(&python_init.ctx_data);
+ rc = nxt_py_proto.ctx_data_alloc(&python_init.ctx_data, 1);
if (nxt_slow_path(rc != NXT_UNIT_OK)) {
goto fail;
}
@@ -364,13 +364,13 @@ nxt_python_set_target(nxt_task_t *task, nxt_python_target_t *target,
obj = PyDict_GetItemString(PyModule_GetDict(module), callable);
if (nxt_slow_path(obj == NULL)) {
nxt_alert(task, "Python failed to get \"%s\" from module \"%s\"",
- callable, module);
+ callable, module_name);
goto fail;
}
if (nxt_slow_path(PyCallable_Check(obj) == 0)) {
nxt_alert(task, "\"%s\" in module \"%s\" is not a callable object",
- callable, module);
+ callable, module_name);
goto fail;
}
@@ -504,7 +504,7 @@ nxt_python_init_threads(nxt_python_app_conf_t *c)
for (i = 0; i < c->threads - 1; i++) {
ti = &nxt_py_threads[i];
- res = nxt_py_proto.ctx_data_alloc(&ti->ctx_data);
+ res = nxt_py_proto.ctx_data_alloc(&ti->ctx_data, 0);
if (nxt_slow_path(res != NXT_UNIT_OK)) {
return NXT_UNIT_ERROR;
}
diff --git a/src/python/nxt_python.h b/src/python/nxt_python.h
index a5c1d9a6..e4eac9dc 100644
--- a/src/python/nxt_python.h
+++ b/src/python/nxt_python.h
@@ -60,7 +60,7 @@ typedef struct {
typedef struct {
- int (*ctx_data_alloc)(void **pdata);
+ int (*ctx_data_alloc)(void **pdata, int main);
void (*ctx_data_free)(void *data);
int (*startup)(void *data);
int (*run)(nxt_unit_ctx_t *ctx);
diff --git a/src/python/nxt_python_asgi.c b/src/python/nxt_python_asgi.c
index 1d220678..26003805 100644
--- a/src/python/nxt_python_asgi.c
+++ b/src/python/nxt_python_asgi.c
@@ -17,7 +17,7 @@
static PyObject *nxt_python_asgi_get_func(PyObject *obj);
-static int nxt_python_asgi_ctx_data_alloc(void **pdata);
+static int nxt_python_asgi_ctx_data_alloc(void **pdata, int main);
static void nxt_python_asgi_ctx_data_free(void *data);
static int nxt_python_asgi_startup(void *data);
static int nxt_python_asgi_run(nxt_unit_ctx_t *ctx);
@@ -194,10 +194,11 @@ nxt_python_asgi_init(nxt_unit_init_t *init, nxt_python_proto_t *proto)
static int
-nxt_python_asgi_ctx_data_alloc(void **pdata)
+nxt_python_asgi_ctx_data_alloc(void **pdata, int main)
{
uint32_t i;
- PyObject *asyncio, *loop, *new_event_loop, *obj;
+ PyObject *asyncio, *loop, *event_loop, *obj;
+ const char *event_loop_func;
nxt_py_asgi_ctx_data_t *ctx_data;
ctx_data = nxt_unit_malloc(NULL, sizeof(nxt_py_asgi_ctx_data_t));
@@ -232,23 +233,28 @@ nxt_python_asgi_ctx_data_alloc(void **pdata)
goto fail;
}
- new_event_loop = PyDict_GetItemString(PyModule_GetDict(asyncio),
- "new_event_loop");
- if (nxt_slow_path(new_event_loop == NULL)) {
+ event_loop_func = main ? "get_event_loop" : "new_event_loop";
+
+ event_loop = PyDict_GetItemString(PyModule_GetDict(asyncio),
+ event_loop_func);
+ if (nxt_slow_path(event_loop == NULL)) {
nxt_unit_alert(NULL,
- "Python failed to get 'new_event_loop' from module 'asyncio'");
+ "Python failed to get '%s' from module 'asyncio'",
+ event_loop_func);
goto fail;
}
- if (nxt_slow_path(PyCallable_Check(new_event_loop) == 0)) {
+ if (nxt_slow_path(PyCallable_Check(event_loop) == 0)) {
nxt_unit_alert(NULL,
- "'asyncio.new_event_loop' is not a callable object");
+ "'asyncio.%s' is not a callable object",
+ event_loop_func);
goto fail;
}
- loop = PyObject_CallObject(new_event_loop, NULL);
+ loop = PyObject_CallObject(event_loop, NULL);
if (nxt_slow_path(loop == NULL)) {
- nxt_unit_alert(NULL, "Python failed to call 'asyncio.new_event_loop'");
+ nxt_unit_alert(NULL, "Python failed to call 'asyncio.%s'",
+ event_loop_func);
goto fail;
}
diff --git a/src/python/nxt_python_asgi_http.c b/src/python/nxt_python_asgi_http.c
index d88c4b00..c4a77d53 100644
--- a/src/python/nxt_python_asgi_http.c
+++ b/src/python/nxt_python_asgi_http.c
@@ -23,10 +23,11 @@ typedef struct {
PyObject *send_future;
uint64_t content_length;
uint64_t bytes_sent;
- int complete;
- int closed;
PyObject *send_body;
Py_ssize_t send_body_off;
+ uint8_t complete;
+ uint8_t closed;
+ uint8_t empty_body_received;
} nxt_py_asgi_http_t;
@@ -37,6 +38,9 @@ static PyObject *nxt_py_asgi_http_response_start(nxt_py_asgi_http_t *http,
PyObject *dict);
static PyObject *nxt_py_asgi_http_response_body(nxt_py_asgi_http_t *http,
PyObject *dict);
+static void nxt_py_asgi_http_emit_disconnect(nxt_py_asgi_http_t *http);
+static void nxt_py_asgi_http_set_result(nxt_py_asgi_http_t *http,
+ PyObject *future, PyObject *msg);
static PyObject *nxt_py_asgi_http_done(PyObject *self, PyObject *future);
@@ -94,10 +98,11 @@ nxt_py_asgi_http_create(nxt_unit_request_info_t *req)
http->send_future = NULL;
http->content_length = -1;
http->bytes_sent = 0;
- http->complete = 0;
- http->closed = 0;
http->send_body = NULL;
http->send_body_off = 0;
+ http->complete = 0;
+ http->closed = 0;
+ http->empty_body_received = 0;
}
return (PyObject *) http;
@@ -117,7 +122,7 @@ nxt_py_asgi_http_receive(PyObject *self, PyObject *none)
nxt_unit_req_debug(req, "asgi_http_receive");
- if (nxt_slow_path(http->closed || nxt_unit_response_is_sent(req))) {
+ if (nxt_slow_path(http->closed || http->complete )) {
msg = nxt_py_asgi_new_msg(req, nxt_py_http_disconnect_str);
} else {
@@ -171,6 +176,14 @@ nxt_py_asgi_http_read_msg(nxt_py_asgi_http_t *http)
size = nxt_py_asgi_http_body_buf_size;
}
+ if (size == 0) {
+ if (http->empty_body_received) {
+ Py_RETURN_NONE;
+ }
+
+ http->empty_body_received = 1;
+ }
+
if (size > 0) {
body = PyBytes_FromStringAndSize(NULL, size);
if (nxt_slow_path(body == NULL)) {
@@ -442,6 +455,8 @@ nxt_py_asgi_http_response_body(nxt_py_asgi_http_t *http, PyObject *dict)
if (more_body == NULL || more_body == Py_False) {
http->complete = 1;
+
+ nxt_py_asgi_http_emit_disconnect(http);
}
Py_INCREF(http);
@@ -449,10 +464,67 @@ nxt_py_asgi_http_response_body(nxt_py_asgi_http_t *http, PyObject *dict)
}
+static void
+nxt_py_asgi_http_emit_disconnect(nxt_py_asgi_http_t *http)
+{
+ PyObject *msg, *future;
+
+ if (http->receive_future == NULL) {
+ return;
+ }
+
+ msg = nxt_py_asgi_new_msg(http->req, nxt_py_http_disconnect_str);
+ if (nxt_slow_path(msg == NULL)) {
+ return;
+ }
+
+ if (msg == Py_None) {
+ Py_DECREF(msg);
+ return;
+ }
+
+ future = http->receive_future;
+ http->receive_future = NULL;
+
+ nxt_py_asgi_http_set_result(http, future, msg);
+
+ Py_DECREF(msg);
+}
+
+
+static void
+nxt_py_asgi_http_set_result(nxt_py_asgi_http_t *http, PyObject *future,
+ PyObject *msg)
+{
+ PyObject *res;
+
+ res = PyObject_CallMethodObjArgs(future, nxt_py_done_str, NULL);
+ if (nxt_slow_path(res == NULL)) {
+ nxt_unit_req_alert(http->req, "'done' call failed");
+ nxt_python_print_exception();
+ }
+
+ if (nxt_fast_path(res == Py_False)) {
+ res = PyObject_CallMethodObjArgs(future, nxt_py_set_result_str, msg,
+ NULL);
+ if (nxt_slow_path(res == NULL)) {
+ nxt_unit_req_alert(http->req, "'set_result' call failed");
+ nxt_python_print_exception();
+ }
+
+ } else {
+ res = NULL;
+ }
+
+ Py_XDECREF(res);
+ Py_DECREF(future);
+}
+
+
void
nxt_py_asgi_http_data_handler(nxt_unit_request_info_t *req)
{
- PyObject *msg, *future, *res;
+ PyObject *msg, *future;
nxt_py_asgi_http_t *http;
http = req->data;
@@ -476,14 +548,7 @@ nxt_py_asgi_http_data_handler(nxt_unit_request_info_t *req)
future = http->receive_future;
http->receive_future = NULL;
- res = PyObject_CallMethodObjArgs(future, nxt_py_set_result_str, msg, NULL);
- if (nxt_slow_path(res == NULL)) {
- nxt_unit_req_alert(req, "'set_result' call failed");
- nxt_python_print_exception();
- }
-
- Py_XDECREF(res);
- Py_DECREF(future);
+ nxt_py_asgi_http_set_result(http, future, msg);
Py_DECREF(msg);
}
@@ -527,15 +592,7 @@ nxt_py_asgi_http_drain(nxt_queue_link_t *lnk)
future = http->send_future;
http->send_future = NULL;
- res = PyObject_CallMethodObjArgs(future, nxt_py_set_result_str, Py_None,
- NULL);
- if (nxt_slow_path(res == NULL)) {
- nxt_unit_req_alert(http->req, "'set_result' call failed");
- nxt_python_print_exception();
- }
-
- Py_XDECREF(res);
- Py_DECREF(future);
+ nxt_py_asgi_http_set_result(http, future, Py_None);
return NXT_UNIT_OK;
@@ -573,7 +630,6 @@ fail:
void
nxt_py_asgi_http_close_handler(nxt_unit_request_info_t *req)
{
- PyObject *msg, *future, *res;
nxt_py_asgi_http_t *http;
http = req->data;
@@ -582,33 +638,7 @@ nxt_py_asgi_http_close_handler(nxt_unit_request_info_t *req)
http->closed = 1;
- if (http->receive_future == NULL) {
- return;
- }
-
- msg = nxt_py_asgi_new_msg(req, nxt_py_http_disconnect_str);
- if (nxt_slow_path(msg == NULL)) {
- return;
- }
-
- if (msg == Py_None) {
- Py_DECREF(msg);
- return;
- }
-
- future = http->receive_future;
- http->receive_future = NULL;
-
- res = PyObject_CallMethodObjArgs(future, nxt_py_set_result_str, msg, NULL);
- if (nxt_slow_path(res == NULL)) {
- nxt_unit_req_alert(req, "'set_result' call failed");
- nxt_python_print_exception();
- }
-
- Py_XDECREF(res);
- Py_DECREF(future);
-
- Py_DECREF(msg);
+ nxt_py_asgi_http_emit_disconnect(http);
}
diff --git a/src/python/nxt_python_wsgi.c b/src/python/nxt_python_wsgi.c
index b80d10fa..87dcfaa2 100644
--- a/src/python/nxt_python_wsgi.c
+++ b/src/python/nxt_python_wsgi.c
@@ -51,7 +51,7 @@ typedef struct {
} nxt_python_ctx_t;
-static int nxt_python_wsgi_ctx_data_alloc(void **pdata);
+static int nxt_python_wsgi_ctx_data_alloc(void **pdata, int main);
static void nxt_python_wsgi_ctx_data_free(void *data);
static int nxt_python_wsgi_run(nxt_unit_ctx_t *ctx);
static void nxt_python_wsgi_done(void);
@@ -210,7 +210,7 @@ fail:
static int
-nxt_python_wsgi_ctx_data_alloc(void **pdata)
+nxt_python_wsgi_ctx_data_alloc(void **pdata, int main)
{
nxt_python_ctx_t *pctx;
diff --git a/src/ruby/nxt_ruby.c b/src/ruby/nxt_ruby.c
index ca14af5b..522869b5 100644
--- a/src/ruby/nxt_ruby.c
+++ b/src/ruby/nxt_ruby.c
@@ -29,6 +29,11 @@ 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_hook_procs_load(VALUE path);
+static VALUE nxt_ruby_hook_register(VALUE arg);
+static VALUE nxt_ruby_hook_call(VALUE name);
+
static VALUE nxt_ruby_rack_init(nxt_ruby_rack_init_t *rack_init);
static VALUE nxt_ruby_require_rubygems(VALUE arg);
@@ -78,6 +83,7 @@ static uint32_t compat[] = {
NXT_VERNUM, NXT_DEBUG,
};
+static VALUE nxt_ruby_hook_procs;
static VALUE nxt_ruby_rackup;
static VALUE nxt_ruby_call;
@@ -115,6 +121,10 @@ static VALUE nxt_rb_server_addr_str;
static VALUE nxt_rb_server_name_str;
static VALUE nxt_rb_server_port_str;
static VALUE nxt_rb_server_protocol_str;
+static VALUE nxt_rb_on_worker_boot;
+static VALUE nxt_rb_on_worker_shutdown;
+static VALUE nxt_rb_on_thread_boot;
+static VALUE nxt_rb_on_thread_shutdown;
static nxt_ruby_string_t nxt_rb_strings[] = {
{ nxt_string("80"), &nxt_rb_80_str },
@@ -132,6 +142,10 @@ static nxt_ruby_string_t nxt_rb_strings[] = {
{ nxt_string("SERVER_NAME"), &nxt_rb_server_name_str },
{ nxt_string("SERVER_PORT"), &nxt_rb_server_port_str },
{ nxt_string("SERVER_PROTOCOL"), &nxt_rb_server_protocol_str },
+ { nxt_string("on_worker_boot"), &nxt_rb_on_worker_boot },
+ { nxt_string("on_worker_shutdown"), &nxt_rb_on_worker_shutdown },
+ { nxt_string("on_thread_boot"), &nxt_rb_on_thread_boot },
+ { nxt_string("on_thread_shutdown"), &nxt_rb_on_thread_shutdown },
{ nxt_null_string, NULL },
};
@@ -183,11 +197,70 @@ nxt_ruby_done_strings(void)
}
+static VALUE
+nxt_ruby_hook_procs_load(VALUE path)
+{
+ VALUE module, file, file_obj;
+
+ module = rb_define_module("Unit");
+
+ nxt_ruby_hook_procs = rb_hash_new();
+
+ rb_gc_register_address(&nxt_ruby_hook_procs);
+
+ rb_define_module_function(module, "on_worker_boot",
+ &nxt_ruby_hook_register, 0);
+ rb_define_module_function(module, "on_worker_shutdown",
+ &nxt_ruby_hook_register, 0);
+ rb_define_module_function(module, "on_thread_boot",
+ &nxt_ruby_hook_register, 0);
+ rb_define_module_function(module, "on_thread_shutdown",
+ &nxt_ruby_hook_register, 0);
+
+ file = rb_const_get(rb_cObject, rb_intern("File"));
+ file_obj = rb_funcall(file, rb_intern("read"), 1, path);
+
+ return rb_funcall(module, rb_intern("module_eval"), 3, file_obj, path,
+ INT2NUM(1));
+}
+
+
+static VALUE
+nxt_ruby_hook_register(VALUE arg)
+{
+ VALUE kernel, callee, callee_str;
+
+ rb_need_block();
+
+ kernel = rb_const_get(rb_cObject, rb_intern("Kernel"));
+ callee = rb_funcall(kernel, rb_intern("__callee__"), 0);
+ callee_str = rb_funcall(callee, rb_intern("to_s"), 0);
+
+ rb_hash_aset(nxt_ruby_hook_procs, callee_str, rb_block_proc());
+
+ return Qnil;
+}
+
+
+static VALUE
+nxt_ruby_hook_call(VALUE name)
+{
+ VALUE proc;
+
+ proc = rb_hash_lookup(nxt_ruby_hook_procs, name);
+ if (proc == Qnil) {
+ return Qnil;
+ }
+
+ return rb_funcall(proc, rb_intern("call"), 0);
+}
+
+
static nxt_int_t
nxt_ruby_start(nxt_task_t *task, nxt_process_data_t *data)
{
int state, rc;
- VALUE res;
+ VALUE res, path;
nxt_ruby_ctx_t ruby_ctx;
nxt_unit_ctx_t *unit_ctx;
nxt_unit_init_t ruby_unit_init;
@@ -231,6 +304,29 @@ nxt_ruby_start(nxt_task_t *task, nxt_process_data_t *data)
}
nxt_ruby_call = Qnil;
+ nxt_ruby_hook_procs = Qnil;
+
+ if (c->hooks.start != NULL) {
+ path = rb_str_new((const char *) c->hooks.start,
+ (long) c->hooks.length);
+
+ rb_protect(nxt_ruby_hook_procs_load, path, &state);
+ rb_str_free(path);
+ if (nxt_slow_path(state != 0)) {
+ nxt_ruby_exception_log(NULL, NXT_LOG_ALERT,
+ "Failed to setup hooks");
+ return NXT_ERROR;
+ }
+ }
+
+ if (nxt_ruby_hook_procs != Qnil) {
+ rb_protect(nxt_ruby_hook_call, nxt_rb_on_worker_boot, &state);
+ if (nxt_slow_path(state != 0)) {
+ nxt_ruby_exception_log(NULL, NXT_LOG_ERR,
+ "Failed to call on_worker_boot()");
+ return NXT_ERROR;
+ }
+ }
nxt_ruby_rackup = nxt_ruby_rack_init(&rack_init);
if (nxt_slow_path(nxt_ruby_rackup == Qnil)) {
@@ -274,11 +370,35 @@ nxt_ruby_start(nxt_task_t *task, nxt_process_data_t *data)
goto fail;
}
+ if (nxt_ruby_hook_procs != Qnil) {
+ rb_protect(nxt_ruby_hook_call, nxt_rb_on_thread_boot, &state);
+ if (nxt_slow_path(state != 0)) {
+ nxt_ruby_exception_log(NULL, NXT_LOG_ERR,
+ "Failed to call on_thread_boot()");
+ }
+ }
+
rc = (intptr_t) rb_thread_call_without_gvl(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);
+ if (nxt_slow_path(state != 0)) {
+ nxt_ruby_exception_log(NULL, NXT_LOG_ERR,
+ "Failed to call on_thread_shutdown()");
+ }
+ }
+
nxt_ruby_join_threads(unit_ctx, c);
+ if (nxt_ruby_hook_procs != Qnil) {
+ rb_protect(nxt_ruby_hook_call, nxt_rb_on_worker_shutdown, &state);
+ if (nxt_slow_path(state != 0)) {
+ nxt_ruby_exception_log(NULL, NXT_LOG_ERR,
+ "Failed to call on_worker_shutdown()");
+ }
+ }
+
nxt_unit_done(unit_ctx);
nxt_ruby_ctx_done(&ruby_ctx);
@@ -1069,14 +1189,18 @@ nxt_ruby_exception_log(nxt_unit_request_info_t *req, uint32_t level,
return;
}
+ eclass = rb_class_name(rb_class_of(err));
+
+ msg = rb_funcall(err, rb_intern("message"), 0);
ary = rb_funcall(err, rb_intern("backtrace"), 0);
- if (nxt_slow_path(RARRAY_LEN(ary) == 0)) {
+
+ if (RARRAY_LEN(ary) == 0) {
+ nxt_unit_req_log(req, level, "Ruby: %s (%s)", RSTRING_PTR(msg),
+ RSTRING_PTR(eclass));
+
return;
}
- eclass = rb_class_name(rb_class_of(err));
- msg = rb_funcall(err, rb_intern("message"), 0);
-
nxt_unit_req_log(req, level, "Ruby: %s: %s (%s)",
RSTRING_PTR(RARRAY_PTR(ary)[0]),
RSTRING_PTR(msg), RSTRING_PTR(eclass));
@@ -1116,6 +1240,10 @@ nxt_ruby_atexit(void)
rb_gc_unregister_address(&nxt_ruby_call);
}
+ if (nxt_ruby_hook_procs != Qnil) {
+ rb_gc_unregister_address(&nxt_ruby_hook_procs);
+ }
+
nxt_ruby_done_strings();
ruby_cleanup(0);
@@ -1178,6 +1306,7 @@ nxt_ruby_thread_create_gvl(void *rctx)
static VALUE
nxt_ruby_thread_func(VALUE arg)
{
+ int state;
nxt_unit_ctx_t *ctx;
nxt_ruby_ctx_t *rctx;
@@ -1190,9 +1319,25 @@ nxt_ruby_thread_func(VALUE arg)
goto fail;
}
+ if (nxt_ruby_hook_procs != Qnil) {
+ rb_protect(nxt_ruby_hook_call, nxt_rb_on_thread_boot, &state);
+ if (nxt_slow_path(state != 0)) {
+ nxt_ruby_exception_log(NULL, NXT_LOG_ERR,
+ "Failed to call on_thread_boot()");
+ }
+ }
+
(void) rb_thread_call_without_gvl(nxt_ruby_unit_run, ctx,
nxt_ruby_ubf, ctx);
+ if (nxt_ruby_hook_procs != Qnil) {
+ rb_protect(nxt_ruby_hook_call, nxt_rb_on_thread_shutdown, &state);
+ if (nxt_slow_path(state != 0)) {
+ nxt_ruby_exception_log(NULL, NXT_LOG_ERR,
+ "Failed to call on_thread_shutdown()");
+ }
+ }
+
nxt_unit_done(ctx);
fail: