xref: /unit/src/nxt_controller.c (revision 1926)
120Sigor@sysoev.ru 
220Sigor@sysoev.ru /*
320Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
420Sigor@sysoev.ru  * Copyright (C) Valentin V. Bartenev
520Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
620Sigor@sysoev.ru  */
720Sigor@sysoev.ru 
820Sigor@sysoev.ru #include <nxt_main.h>
920Sigor@sysoev.ru #include <nxt_runtime.h>
10240Sigor@sysoev.ru #include <nxt_main_process.h>
1129Svbart@nginx.com #include <nxt_conf.h>
12774Svbart@nginx.com #include <nxt_cert.h>
1320Sigor@sysoev.ru 
1420Sigor@sysoev.ru 
1527Svbart@nginx.com typedef struct {
16106Svbart@nginx.com     nxt_conf_value_t  *root;
17106Svbart@nginx.com     nxt_mp_t          *pool;
1844Svbart@nginx.com } nxt_controller_conf_t;
1944Svbart@nginx.com 
2044Svbart@nginx.com 
2144Svbart@nginx.com typedef struct {
2227Svbart@nginx.com     nxt_http_request_parse_t  parser;
2327Svbart@nginx.com     size_t                    length;
2444Svbart@nginx.com     nxt_controller_conf_t     conf;
25140Svbart@nginx.com     nxt_conn_t                *conn;
26140Svbart@nginx.com     nxt_queue_link_t          link;
2727Svbart@nginx.com } nxt_controller_request_t;
2827Svbart@nginx.com 
2927Svbart@nginx.com 
3044Svbart@nginx.com typedef struct {
31208Svbart@nginx.com     nxt_uint_t        status;
32106Svbart@nginx.com     nxt_conf_value_t  *conf;
33208Svbart@nginx.com 
34208Svbart@nginx.com     u_char            *title;
35357Svbart@nginx.com     nxt_str_t         detail;
36208Svbart@nginx.com     ssize_t           offset;
37208Svbart@nginx.com     nxt_uint_t        line;
38208Svbart@nginx.com     nxt_uint_t        column;
3944Svbart@nginx.com } nxt_controller_response_t;
4044Svbart@nginx.com 
4144Svbart@nginx.com 
421488St.nateldemoura@f5.com static nxt_int_t nxt_controller_prefork(nxt_task_t *task,
431488St.nateldemoura@f5.com     nxt_process_t *process, nxt_mp_t *mp);
441488St.nateldemoura@f5.com static nxt_int_t nxt_controller_start(nxt_task_t *task,
451488St.nateldemoura@f5.com     nxt_process_data_t *data);
46248Svbart@nginx.com static void nxt_controller_process_new_port_handler(nxt_task_t *task,
47248Svbart@nginx.com     nxt_port_recv_msg_t *msg);
48662Smax.romanov@nginx.com static void nxt_controller_send_current_conf(nxt_task_t *task);
49662Smax.romanov@nginx.com static void nxt_controller_router_ready_handler(nxt_task_t *task,
50662Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg);
511488St.nateldemoura@f5.com static void nxt_controller_remove_pid_handler(nxt_task_t *task,
521488St.nateldemoura@f5.com     nxt_port_recv_msg_t *msg);
53249Svbart@nginx.com static nxt_int_t nxt_controller_conf_default(void);
54249Svbart@nginx.com static void nxt_controller_conf_init_handler(nxt_task_t *task,
55249Svbart@nginx.com     nxt_port_recv_msg_t *msg, void *data);
561469Smax.romanov@nginx.com static void nxt_controller_flush_requests(nxt_task_t *task);
571526Smax.romanov@nginx.com static nxt_int_t nxt_controller_conf_send(nxt_task_t *task, nxt_mp_t *mp,
58249Svbart@nginx.com     nxt_conf_value_t *conf, nxt_port_rpc_handler_t handler, void *data);
59248Svbart@nginx.com 
6020Sigor@sysoev.ru static void nxt_controller_conn_init(nxt_task_t *task, void *obj, void *data);
6120Sigor@sysoev.ru static void nxt_controller_conn_read(nxt_task_t *task, void *obj, void *data);
6262Sigor@sysoev.ru static nxt_msec_t nxt_controller_conn_timeout_value(nxt_conn_t *c,
6320Sigor@sysoev.ru     uintptr_t data);
6420Sigor@sysoev.ru static void nxt_controller_conn_read_error(nxt_task_t *task, void *obj,
6520Sigor@sysoev.ru     void *data);
6620Sigor@sysoev.ru static void nxt_controller_conn_read_timeout(nxt_task_t *task, void *obj,
6720Sigor@sysoev.ru     void *data);
6827Svbart@nginx.com static void nxt_controller_conn_body_read(nxt_task_t *task, void *obj,
6927Svbart@nginx.com     void *data);
7027Svbart@nginx.com static void nxt_controller_conn_write(nxt_task_t *task, void *obj, void *data);
7127Svbart@nginx.com static void nxt_controller_conn_write_error(nxt_task_t *task, void *obj,
7227Svbart@nginx.com     void *data);
7327Svbart@nginx.com static void nxt_controller_conn_write_timeout(nxt_task_t *task, void *obj,
7427Svbart@nginx.com     void *data);
7520Sigor@sysoev.ru static void nxt_controller_conn_close(nxt_task_t *task, void *obj, void *data);
7620Sigor@sysoev.ru static void nxt_controller_conn_free(nxt_task_t *task, void *obj, void *data);
7720Sigor@sysoev.ru 
7827Svbart@nginx.com static nxt_int_t nxt_controller_request_content_length(void *ctx,
79417Svbart@nginx.com     nxt_http_field_t *field, uintptr_t data);
8027Svbart@nginx.com 
8127Svbart@nginx.com static void nxt_controller_process_request(nxt_task_t *task,
82140Svbart@nginx.com     nxt_controller_request_t *req);
83774Svbart@nginx.com static void nxt_controller_process_config(nxt_task_t *task,
84774Svbart@nginx.com     nxt_controller_request_t *req, nxt_str_t *path);
851470Smax.romanov@nginx.com static nxt_bool_t nxt_controller_check_postpone_request(nxt_task_t *task);
86774Svbart@nginx.com #if (NXT_TLS)
87774Svbart@nginx.com static void nxt_controller_process_cert(nxt_task_t *task,
88774Svbart@nginx.com     nxt_controller_request_t *req, nxt_str_t *path);
89774Svbart@nginx.com static void nxt_controller_process_cert_save(nxt_task_t *task,
90774Svbart@nginx.com     nxt_port_recv_msg_t *msg, void *data);
91774Svbart@nginx.com static nxt_bool_t nxt_controller_cert_in_use(nxt_str_t *name);
921488St.nateldemoura@f5.com static void nxt_controller_cert_cleanup(nxt_task_t *task, void *obj,
931488St.nateldemoura@f5.com     void *data);
94774Svbart@nginx.com #endif
95*1926Smax.romanov@nginx.com static void nxt_controller_process_control(nxt_task_t *task,
96*1926Smax.romanov@nginx.com     nxt_controller_request_t *req, nxt_str_t *path);
97*1926Smax.romanov@nginx.com static void nxt_controller_app_restart_handler(nxt_task_t *task,
98*1926Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg, void *data);
99238Svbart@nginx.com static void nxt_controller_conf_handler(nxt_task_t *task,
100238Svbart@nginx.com     nxt_port_recv_msg_t *msg, void *data);
101314Svbart@nginx.com static void nxt_controller_conf_store(nxt_task_t *task,
102314Svbart@nginx.com     nxt_conf_value_t *conf);
103140Svbart@nginx.com static void nxt_controller_response(nxt_task_t *task,
104140Svbart@nginx.com     nxt_controller_request_t *req, nxt_controller_response_t *resp);
105208Svbart@nginx.com static u_char *nxt_controller_date(u_char *buf, nxt_realtime_t *now,
106208Svbart@nginx.com     struct tm *tm, size_t size, const char *format);
10727Svbart@nginx.com 
10827Svbart@nginx.com 
109417Svbart@nginx.com static nxt_http_field_proc_t  nxt_controller_request_fields[] = {
11027Svbart@nginx.com     { nxt_string("Content-Length"),
11127Svbart@nginx.com       &nxt_controller_request_content_length, 0 },
11227Svbart@nginx.com };
11327Svbart@nginx.com 
114417Svbart@nginx.com static nxt_lvlhsh_t            nxt_controller_fields_hash;
11527Svbart@nginx.com 
116314Svbart@nginx.com static nxt_uint_t              nxt_controller_listening;
117662Smax.romanov@nginx.com static nxt_uint_t              nxt_controller_router_ready;
118238Svbart@nginx.com static nxt_controller_conf_t   nxt_controller_conf;
119238Svbart@nginx.com static nxt_queue_t             nxt_controller_waiting_requests;
1201469Smax.romanov@nginx.com static nxt_bool_t              nxt_controller_waiting_init_conf;
12127Svbart@nginx.com 
12220Sigor@sysoev.ru 
12320Sigor@sysoev.ru static const nxt_event_conn_state_t  nxt_controller_conn_read_state;
12427Svbart@nginx.com static const nxt_event_conn_state_t  nxt_controller_conn_body_read_state;
12527Svbart@nginx.com static const nxt_event_conn_state_t  nxt_controller_conn_write_state;
12620Sigor@sysoev.ru static const nxt_event_conn_state_t  nxt_controller_conn_close_state;
12720Sigor@sysoev.ru 
12820Sigor@sysoev.ru 
1291488St.nateldemoura@f5.com static const nxt_port_handlers_t  nxt_controller_process_port_handlers = {
1301488St.nateldemoura@f5.com     .quit           = nxt_signal_quit_handler,
131662Smax.romanov@nginx.com     .new_port       = nxt_controller_process_new_port_handler,
132662Smax.romanov@nginx.com     .change_file    = nxt_port_change_log_file_handler,
133662Smax.romanov@nginx.com     .mmap           = nxt_port_mmap_handler,
134662Smax.romanov@nginx.com     .process_ready  = nxt_controller_router_ready_handler,
135662Smax.romanov@nginx.com     .data           = nxt_port_data_handler,
1361488St.nateldemoura@f5.com     .remove_pid     = nxt_controller_remove_pid_handler,
137662Smax.romanov@nginx.com     .rpc_ready      = nxt_port_rpc_handler,
138662Smax.romanov@nginx.com     .rpc_error      = nxt_port_rpc_handler,
139248Svbart@nginx.com };
140248Svbart@nginx.com 
141248Svbart@nginx.com 
1421488St.nateldemoura@f5.com const nxt_process_init_t  nxt_controller_process = {
1431488St.nateldemoura@f5.com     .name           = "controller",
1441488St.nateldemoura@f5.com     .type           = NXT_PROCESS_CONTROLLER,
1451488St.nateldemoura@f5.com     .prefork        = nxt_controller_prefork,
1461488St.nateldemoura@f5.com     .restart        = 1,
1471488St.nateldemoura@f5.com     .setup          = nxt_process_core_setup,
1481488St.nateldemoura@f5.com     .start          = nxt_controller_start,
1491488St.nateldemoura@f5.com     .port_handlers  = &nxt_controller_process_port_handlers,
1501488St.nateldemoura@f5.com     .signals        = nxt_process_signals,
1511488St.nateldemoura@f5.com };
1521488St.nateldemoura@f5.com 
1531488St.nateldemoura@f5.com 
1541488St.nateldemoura@f5.com static nxt_int_t
1551488St.nateldemoura@f5.com nxt_controller_prefork(nxt_task_t *task, nxt_process_t *process, nxt_mp_t *mp)
1561488St.nateldemoura@f5.com {
1571488St.nateldemoura@f5.com     ssize_t                n;
1581488St.nateldemoura@f5.com     nxt_int_t              ret;
1591488St.nateldemoura@f5.com     nxt_str_t              *conf;
1601488St.nateldemoura@f5.com     nxt_file_t             file;
1611488St.nateldemoura@f5.com     nxt_runtime_t          *rt;
1621488St.nateldemoura@f5.com     nxt_file_info_t        fi;
1631488St.nateldemoura@f5.com     nxt_controller_init_t  ctrl_init;
1641488St.nateldemoura@f5.com 
1651488St.nateldemoura@f5.com     nxt_log(task, NXT_LOG_INFO, "controller started");
1661488St.nateldemoura@f5.com 
1671488St.nateldemoura@f5.com     rt = task->thread->runtime;
1681488St.nateldemoura@f5.com 
1691488St.nateldemoura@f5.com     nxt_memzero(&ctrl_init, sizeof(nxt_controller_init_t));
1701488St.nateldemoura@f5.com 
1711488St.nateldemoura@f5.com     conf = &ctrl_init.conf;
1721488St.nateldemoura@f5.com 
1731488St.nateldemoura@f5.com     nxt_memzero(&file, sizeof(nxt_file_t));
1741488St.nateldemoura@f5.com 
1751488St.nateldemoura@f5.com     file.name = (nxt_file_name_t *) rt->conf;
1761488St.nateldemoura@f5.com 
1771488St.nateldemoura@f5.com     ret = nxt_file_open(task, &file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 0);
1781488St.nateldemoura@f5.com 
1791488St.nateldemoura@f5.com     if (ret == NXT_OK) {
1801488St.nateldemoura@f5.com         ret = nxt_file_info(&file, &fi);
1811488St.nateldemoura@f5.com 
1821488St.nateldemoura@f5.com         if (nxt_fast_path(ret == NXT_OK && nxt_is_file(&fi))) {
1831488St.nateldemoura@f5.com             conf->length = nxt_file_size(&fi);
1841488St.nateldemoura@f5.com             conf->start = nxt_mp_alloc(mp, conf->length);
1851488St.nateldemoura@f5.com             if (nxt_slow_path(conf->start == NULL)) {
1861488St.nateldemoura@f5.com                 nxt_file_close(task, &file);
1871488St.nateldemoura@f5.com                 return NXT_ERROR;
1881488St.nateldemoura@f5.com             }
1891488St.nateldemoura@f5.com 
1901488St.nateldemoura@f5.com             n = nxt_file_read(&file, conf->start, conf->length, 0);
1911488St.nateldemoura@f5.com 
1921488St.nateldemoura@f5.com             if (nxt_slow_path(n != (ssize_t) conf->length)) {
1931488St.nateldemoura@f5.com                 conf->start = NULL;
1941488St.nateldemoura@f5.com                 conf->length = 0;
1951488St.nateldemoura@f5.com 
1961488St.nateldemoura@f5.com                 nxt_alert(task, "failed to restore previous configuration: "
1971488St.nateldemoura@f5.com                           "cannot read the file");
1981488St.nateldemoura@f5.com             }
1991488St.nateldemoura@f5.com         }
2001488St.nateldemoura@f5.com 
2011488St.nateldemoura@f5.com         nxt_file_close(task, &file);
2021488St.nateldemoura@f5.com     }
2031488St.nateldemoura@f5.com 
2041488St.nateldemoura@f5.com #if (NXT_TLS)
2051488St.nateldemoura@f5.com     ctrl_init.certs = nxt_cert_store_load(task, mp);
2061488St.nateldemoura@f5.com 
2071488St.nateldemoura@f5.com     nxt_mp_cleanup(mp, nxt_controller_cert_cleanup, task, ctrl_init.certs, rt);
2081488St.nateldemoura@f5.com #endif
2091488St.nateldemoura@f5.com 
2101488St.nateldemoura@f5.com     process->data.controller = ctrl_init;
2111488St.nateldemoura@f5.com 
2121488St.nateldemoura@f5.com     return NXT_OK;
2131488St.nateldemoura@f5.com }
2141488St.nateldemoura@f5.com 
2151488St.nateldemoura@f5.com 
2161488St.nateldemoura@f5.com #if (NXT_TLS)
2171488St.nateldemoura@f5.com 
2181488St.nateldemoura@f5.com static void
2191488St.nateldemoura@f5.com nxt_controller_cert_cleanup(nxt_task_t *task, void *obj, void *data)
2201488St.nateldemoura@f5.com {
2211488St.nateldemoura@f5.com     pid_t          main_pid;
2221488St.nateldemoura@f5.com     nxt_array_t    *certs;
2231488St.nateldemoura@f5.com     nxt_runtime_t  *rt;
2241488St.nateldemoura@f5.com 
2251488St.nateldemoura@f5.com     certs = obj;
2261488St.nateldemoura@f5.com     rt = data;
2271488St.nateldemoura@f5.com 
2281488St.nateldemoura@f5.com     main_pid = rt->port_by_type[NXT_PROCESS_MAIN]->pid;
2291488St.nateldemoura@f5.com 
2301488St.nateldemoura@f5.com     if (nxt_pid == main_pid && certs != NULL) {
2311488St.nateldemoura@f5.com         nxt_cert_store_release(certs);
2321488St.nateldemoura@f5.com     }
2331488St.nateldemoura@f5.com }
2341488St.nateldemoura@f5.com 
2351488St.nateldemoura@f5.com #endif
2361488St.nateldemoura@f5.com 
2371488St.nateldemoura@f5.com 
2381488St.nateldemoura@f5.com static nxt_int_t
2391488St.nateldemoura@f5.com nxt_controller_start(nxt_task_t *task, nxt_process_data_t *data)
24020Sigor@sysoev.ru {
241417Svbart@nginx.com     nxt_mp_t               *mp;
242417Svbart@nginx.com     nxt_int_t              ret;
243417Svbart@nginx.com     nxt_str_t              *json;
244417Svbart@nginx.com     nxt_conf_value_t       *conf;
245417Svbart@nginx.com     nxt_conf_validation_t  vldt;
246774Svbart@nginx.com     nxt_controller_init_t  *init;
24727Svbart@nginx.com 
2481459Smax.romanov@nginx.com     ret = nxt_http_fields_hash(&nxt_controller_fields_hash,
249417Svbart@nginx.com                                nxt_controller_request_fields,
250417Svbart@nginx.com                                nxt_nitems(nxt_controller_request_fields));
251417Svbart@nginx.com 
252417Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
25327Svbart@nginx.com         return NXT_ERROR;
25427Svbart@nginx.com     }
25527Svbart@nginx.com 
256248Svbart@nginx.com     nxt_queue_init(&nxt_controller_waiting_requests);
25727Svbart@nginx.com 
2581488St.nateldemoura@f5.com     init = &data->controller;
259774Svbart@nginx.com 
260774Svbart@nginx.com #if (NXT_TLS)
261774Svbart@nginx.com     if (init->certs != NULL) {
262774Svbart@nginx.com         nxt_cert_info_init(task, init->certs);
263774Svbart@nginx.com         nxt_cert_store_release(init->certs);
264774Svbart@nginx.com     }
265774Svbart@nginx.com #endif
266774Svbart@nginx.com 
267774Svbart@nginx.com     json = &init->conf;
268774Svbart@nginx.com 
269774Svbart@nginx.com     if (json->start == NULL) {
270314Svbart@nginx.com         return NXT_OK;
271314Svbart@nginx.com     }
272314Svbart@nginx.com 
273314Svbart@nginx.com     mp = nxt_mp_create(1024, 128, 256, 32);
274314Svbart@nginx.com     if (nxt_slow_path(mp == NULL)) {
275314Svbart@nginx.com         return NXT_ERROR;
276314Svbart@nginx.com     }
277314Svbart@nginx.com 
278314Svbart@nginx.com     conf = nxt_conf_json_parse_str(mp, json);
279314Svbart@nginx.com     if (nxt_slow_path(conf == NULL)) {
280564Svbart@nginx.com         nxt_alert(task, "failed to restore previous configuration: "
281564Svbart@nginx.com                   "file is corrupted or not enough memory");
282314Svbart@nginx.com 
283314Svbart@nginx.com         nxt_mp_destroy(mp);
284314Svbart@nginx.com         return NXT_OK;
285314Svbart@nginx.com     }
286314Svbart@nginx.com 
287357Svbart@nginx.com     nxt_memzero(&vldt, sizeof(nxt_conf_validation_t));
288314Svbart@nginx.com 
289357Svbart@nginx.com     vldt.pool = nxt_mp_create(1024, 128, 256, 32);
290357Svbart@nginx.com     if (nxt_slow_path(vldt.pool == NULL)) {
2911013Smax.romanov@nginx.com         nxt_mp_destroy(mp);
292357Svbart@nginx.com         return NXT_ERROR;
293314Svbart@nginx.com     }
294314Svbart@nginx.com 
295357Svbart@nginx.com     vldt.conf = conf;
296357Svbart@nginx.com 
297357Svbart@nginx.com     ret = nxt_conf_validate(&vldt);
298357Svbart@nginx.com 
299357Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
300357Svbart@nginx.com 
301357Svbart@nginx.com         if (ret == NXT_DECLINED) {
302564Svbart@nginx.com             nxt_alert(task, "the previous configuration is invalid: %V",
303564Svbart@nginx.com                       &vldt.error);
304357Svbart@nginx.com 
305357Svbart@nginx.com             nxt_mp_destroy(vldt.pool);
306357Svbart@nginx.com             nxt_mp_destroy(mp);
307357Svbart@nginx.com 
308357Svbart@nginx.com             return NXT_OK;
309357Svbart@nginx.com         }
310357Svbart@nginx.com 
311357Svbart@nginx.com         /* ret == NXT_ERROR */
312357Svbart@nginx.com 
313357Svbart@nginx.com         return NXT_ERROR;
314357Svbart@nginx.com     }
315357Svbart@nginx.com 
316357Svbart@nginx.com     nxt_mp_destroy(vldt.pool);
317314Svbart@nginx.com 
318314Svbart@nginx.com     nxt_controller_conf.root = conf;
319314Svbart@nginx.com     nxt_controller_conf.pool = mp;
320314Svbart@nginx.com 
321248Svbart@nginx.com     return NXT_OK;
322248Svbart@nginx.com }
323248Svbart@nginx.com 
324248Svbart@nginx.com 
325248Svbart@nginx.com static void
326248Svbart@nginx.com nxt_controller_process_new_port_handler(nxt_task_t *task,
327248Svbart@nginx.com     nxt_port_recv_msg_t *msg)
328248Svbart@nginx.com {
329662Smax.romanov@nginx.com     nxt_port_new_port_handler(task, msg);
330662Smax.romanov@nginx.com 
331662Smax.romanov@nginx.com     if (msg->u.new_port->type != NXT_PROCESS_ROUTER
332662Smax.romanov@nginx.com         || !nxt_controller_router_ready)
333662Smax.romanov@nginx.com     {
334662Smax.romanov@nginx.com         return;
335662Smax.romanov@nginx.com     }
336662Smax.romanov@nginx.com 
337662Smax.romanov@nginx.com     nxt_controller_send_current_conf(task);
338662Smax.romanov@nginx.com }
339662Smax.romanov@nginx.com 
340662Smax.romanov@nginx.com 
341662Smax.romanov@nginx.com static void
342662Smax.romanov@nginx.com nxt_controller_send_current_conf(nxt_task_t *task)
343662Smax.romanov@nginx.com {
344249Svbart@nginx.com     nxt_int_t         rc;
345248Svbart@nginx.com     nxt_runtime_t     *rt;
346248Svbart@nginx.com     nxt_conf_value_t  *conf;
347248Svbart@nginx.com 
348249Svbart@nginx.com     conf = nxt_controller_conf.root;
349249Svbart@nginx.com 
350249Svbart@nginx.com     if (conf != NULL) {
3511526Smax.romanov@nginx.com         rc = nxt_controller_conf_send(task, nxt_controller_conf.pool, conf,
352249Svbart@nginx.com                                       nxt_controller_conf_init_handler, NULL);
35344Svbart@nginx.com 
354249Svbart@nginx.com         if (nxt_fast_path(rc == NXT_OK)) {
3551469Smax.romanov@nginx.com             nxt_controller_waiting_init_conf = 1;
3561469Smax.romanov@nginx.com 
357249Svbart@nginx.com             return;
358249Svbart@nginx.com         }
359249Svbart@nginx.com 
360249Svbart@nginx.com         nxt_mp_destroy(nxt_controller_conf.pool);
361249Svbart@nginx.com 
362249Svbart@nginx.com         if (nxt_slow_path(nxt_controller_conf_default() != NXT_OK)) {
363249Svbart@nginx.com             nxt_abort();
364249Svbart@nginx.com         }
36544Svbart@nginx.com     }
36644Svbart@nginx.com 
367249Svbart@nginx.com     if (nxt_slow_path(nxt_controller_conf_default() != NXT_OK)) {
368248Svbart@nginx.com         nxt_abort();
36944Svbart@nginx.com     }
37044Svbart@nginx.com 
371248Svbart@nginx.com     rt = task->thread->runtime;
372140Svbart@nginx.com 
373248Svbart@nginx.com     if (nxt_slow_path(nxt_listen_event(task, rt->controller_socket) == NULL)) {
374248Svbart@nginx.com         nxt_abort();
375248Svbart@nginx.com     }
376314Svbart@nginx.com 
377314Svbart@nginx.com     nxt_controller_listening = 1;
3781470Smax.romanov@nginx.com 
3791470Smax.romanov@nginx.com     nxt_controller_flush_requests(task);
38020Sigor@sysoev.ru }
38120Sigor@sysoev.ru 
38220Sigor@sysoev.ru 
383662Smax.romanov@nginx.com static void
384662Smax.romanov@nginx.com nxt_controller_router_ready_handler(nxt_task_t *task,
385662Smax.romanov@nginx.com     nxt_port_recv_msg_t *msg)
386662Smax.romanov@nginx.com {
387662Smax.romanov@nginx.com     nxt_port_t     *router_port;
388662Smax.romanov@nginx.com     nxt_runtime_t  *rt;
389662Smax.romanov@nginx.com 
390662Smax.romanov@nginx.com     rt = task->thread->runtime;
391662Smax.romanov@nginx.com 
392662Smax.romanov@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
393662Smax.romanov@nginx.com 
394662Smax.romanov@nginx.com     nxt_controller_router_ready = 1;
395662Smax.romanov@nginx.com 
396662Smax.romanov@nginx.com     if (router_port != NULL) {
397662Smax.romanov@nginx.com         nxt_controller_send_current_conf(task);
398662Smax.romanov@nginx.com     }
399662Smax.romanov@nginx.com }
400662Smax.romanov@nginx.com 
401662Smax.romanov@nginx.com 
4021488St.nateldemoura@f5.com static void
4031488St.nateldemoura@f5.com nxt_controller_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
4041488St.nateldemoura@f5.com {
4051488St.nateldemoura@f5.com     nxt_pid_t      pid;
4061488St.nateldemoura@f5.com     nxt_process_t  *process;
4071488St.nateldemoura@f5.com     nxt_runtime_t  *rt;
4081488St.nateldemoura@f5.com 
4091488St.nateldemoura@f5.com     rt = task->thread->runtime;
4101488St.nateldemoura@f5.com 
4111488St.nateldemoura@f5.com     nxt_assert(nxt_buf_used_size(msg->buf) == sizeof(pid));
4121488St.nateldemoura@f5.com 
4131488St.nateldemoura@f5.com     nxt_memcpy(&pid, msg->buf->mem.pos, sizeof(pid));
4141488St.nateldemoura@f5.com 
4151488St.nateldemoura@f5.com     process = nxt_runtime_process_find(rt, pid);
4161488St.nateldemoura@f5.com     if (process != NULL && nxt_process_type(process) == NXT_PROCESS_ROUTER) {
4171488St.nateldemoura@f5.com         nxt_controller_router_ready = 0;
4181488St.nateldemoura@f5.com     }
4191488St.nateldemoura@f5.com 
4201488St.nateldemoura@f5.com     nxt_port_remove_pid_handler(task, msg);
4211488St.nateldemoura@f5.com }
4221488St.nateldemoura@f5.com 
4231488St.nateldemoura@f5.com 
424249Svbart@nginx.com static nxt_int_t
425249Svbart@nginx.com nxt_controller_conf_default(void)
426249Svbart@nginx.com {
427249Svbart@nginx.com     nxt_mp_t          *mp;
428249Svbart@nginx.com     nxt_conf_value_t  *conf;
429249Svbart@nginx.com 
430249Svbart@nginx.com     static const nxt_str_t json
431249Svbart@nginx.com         = nxt_string("{ \"listeners\": {}, \"applications\": {} }");
432249Svbart@nginx.com 
433249Svbart@nginx.com     mp = nxt_mp_create(1024, 128, 256, 32);
434249Svbart@nginx.com 
435249Svbart@nginx.com     if (nxt_slow_path(mp == NULL)) {
436249Svbart@nginx.com         return NXT_ERROR;
437249Svbart@nginx.com     }
438249Svbart@nginx.com 
439249Svbart@nginx.com     conf = nxt_conf_json_parse_str(mp, &json);
440249Svbart@nginx.com 
441249Svbart@nginx.com     if (nxt_slow_path(conf == NULL)) {
442249Svbart@nginx.com         return NXT_ERROR;
443249Svbart@nginx.com     }
444249Svbart@nginx.com 
445249Svbart@nginx.com     nxt_controller_conf.root = conf;
446249Svbart@nginx.com     nxt_controller_conf.pool = mp;
447249Svbart@nginx.com 
448249Svbart@nginx.com     return NXT_OK;
449249Svbart@nginx.com }
450249Svbart@nginx.com 
451249Svbart@nginx.com 
452249Svbart@nginx.com static void
453249Svbart@nginx.com nxt_controller_conf_init_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
454249Svbart@nginx.com     void *data)
455249Svbart@nginx.com {
456314Svbart@nginx.com     nxt_runtime_t  *rt;
457314Svbart@nginx.com 
4581469Smax.romanov@nginx.com     nxt_controller_waiting_init_conf = 0;
4591469Smax.romanov@nginx.com 
460249Svbart@nginx.com     if (msg->port_msg.type != NXT_PORT_MSG_RPC_READY) {
461564Svbart@nginx.com         nxt_alert(task, "failed to apply previous configuration");
462314Svbart@nginx.com 
463249Svbart@nginx.com         nxt_mp_destroy(nxt_controller_conf.pool);
464249Svbart@nginx.com 
465249Svbart@nginx.com         if (nxt_slow_path(nxt_controller_conf_default() != NXT_OK)) {
466249Svbart@nginx.com             nxt_abort();
467249Svbart@nginx.com         }
468249Svbart@nginx.com     }
469314Svbart@nginx.com 
470314Svbart@nginx.com     if (nxt_controller_listening == 0) {
471314Svbart@nginx.com         rt = task->thread->runtime;
472314Svbart@nginx.com 
473314Svbart@nginx.com         if (nxt_slow_path(nxt_listen_event(task, rt->controller_socket)
474314Svbart@nginx.com                           == NULL))
475314Svbart@nginx.com         {
476314Svbart@nginx.com             nxt_abort();
477314Svbart@nginx.com         }
478314Svbart@nginx.com 
479314Svbart@nginx.com         nxt_controller_listening = 1;
480314Svbart@nginx.com     }
4811469Smax.romanov@nginx.com 
4821469Smax.romanov@nginx.com     nxt_controller_flush_requests(task);
4831469Smax.romanov@nginx.com }
4841469Smax.romanov@nginx.com 
4851469Smax.romanov@nginx.com 
4861469Smax.romanov@nginx.com static void
4871469Smax.romanov@nginx.com nxt_controller_flush_requests(nxt_task_t *task)
4881469Smax.romanov@nginx.com {
4891469Smax.romanov@nginx.com     nxt_queue_t               queue;
4901469Smax.romanov@nginx.com     nxt_controller_request_t  *req;
4911469Smax.romanov@nginx.com 
4921469Smax.romanov@nginx.com     nxt_queue_init(&queue);
4931469Smax.romanov@nginx.com     nxt_queue_add(&queue, &nxt_controller_waiting_requests);
4941469Smax.romanov@nginx.com 
4951469Smax.romanov@nginx.com     nxt_queue_init(&nxt_controller_waiting_requests);
4961469Smax.romanov@nginx.com 
4971469Smax.romanov@nginx.com     nxt_queue_each(req, &queue, nxt_controller_request_t, link) {
4981469Smax.romanov@nginx.com         nxt_controller_process_request(task, req);
4991469Smax.romanov@nginx.com     } nxt_queue_loop;
500249Svbart@nginx.com }
501249Svbart@nginx.com 
502249Svbart@nginx.com 
503249Svbart@nginx.com static nxt_int_t
5041526Smax.romanov@nginx.com nxt_controller_conf_send(nxt_task_t *task, nxt_mp_t *mp, nxt_conf_value_t *conf,
505249Svbart@nginx.com     nxt_port_rpc_handler_t handler, void *data)
506249Svbart@nginx.com {
5071526Smax.romanov@nginx.com     void           *mem;
5081526Smax.romanov@nginx.com     u_char         *end;
509249Svbart@nginx.com     size_t         size;
510249Svbart@nginx.com     uint32_t       stream;
5111526Smax.romanov@nginx.com     nxt_fd_t       fd;
512249Svbart@nginx.com     nxt_int_t      rc;
513249Svbart@nginx.com     nxt_buf_t      *b;
514249Svbart@nginx.com     nxt_port_t     *router_port, *controller_port;
515249Svbart@nginx.com     nxt_runtime_t  *rt;
516249Svbart@nginx.com 
517249Svbart@nginx.com     rt = task->thread->runtime;
518249Svbart@nginx.com 
519249Svbart@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
520249Svbart@nginx.com 
5211470Smax.romanov@nginx.com     nxt_assert(router_port != NULL);
5221470Smax.romanov@nginx.com     nxt_assert(nxt_controller_router_ready);
523249Svbart@nginx.com 
524249Svbart@nginx.com     controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER];
525249Svbart@nginx.com 
526249Svbart@nginx.com     size = nxt_conf_json_length(conf, NULL);
527249Svbart@nginx.com 
5281526Smax.romanov@nginx.com     b = nxt_buf_mem_alloc(mp, sizeof(size_t), 0);
529379Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
530379Smax.romanov@nginx.com         return NXT_ERROR;
531379Smax.romanov@nginx.com     }
532249Svbart@nginx.com 
5331526Smax.romanov@nginx.com     fd = nxt_shm_open(task, size);
5341526Smax.romanov@nginx.com     if (nxt_slow_path(fd == -1)) {
5351526Smax.romanov@nginx.com         return NXT_ERROR;
5361526Smax.romanov@nginx.com     }
5371526Smax.romanov@nginx.com 
5381526Smax.romanov@nginx.com     mem = nxt_mem_mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
5391526Smax.romanov@nginx.com     if (nxt_slow_path(mem == MAP_FAILED)) {
5401526Smax.romanov@nginx.com         goto fail;
5411526Smax.romanov@nginx.com     }
5421526Smax.romanov@nginx.com 
5431526Smax.romanov@nginx.com     end = nxt_conf_json_print(mem, conf, NULL);
5441526Smax.romanov@nginx.com 
5451526Smax.romanov@nginx.com     nxt_mem_munmap(mem, size);
5461526Smax.romanov@nginx.com 
5471526Smax.romanov@nginx.com     size = end - (u_char *) mem;
5481526Smax.romanov@nginx.com 
5491526Smax.romanov@nginx.com     b->mem.free = nxt_cpymem(b->mem.pos, &size, sizeof(size_t));
550249Svbart@nginx.com 
551249Svbart@nginx.com     stream = nxt_port_rpc_register_handler(task, controller_port,
552249Svbart@nginx.com                                            handler, handler,
553249Svbart@nginx.com                                            router_port->pid, data);
554645Svbart@nginx.com     if (nxt_slow_path(stream == 0)) {
5551526Smax.romanov@nginx.com         goto fail;
556645Svbart@nginx.com     }
557645Svbart@nginx.com 
5581526Smax.romanov@nginx.com     rc = nxt_port_socket_write(task, router_port,
5591526Smax.romanov@nginx.com                                NXT_PORT_MSG_DATA_LAST | NXT_PORT_MSG_CLOSE_FD,
5601526Smax.romanov@nginx.com                                fd, stream, controller_port->id, b);
561249Svbart@nginx.com 
562249Svbart@nginx.com     if (nxt_slow_path(rc != NXT_OK)) {
563249Svbart@nginx.com         nxt_port_rpc_cancel(task, controller_port, stream);
5641526Smax.romanov@nginx.com 
5651526Smax.romanov@nginx.com         goto fail;
566249Svbart@nginx.com     }
567249Svbart@nginx.com 
568249Svbart@nginx.com     return NXT_OK;
5691526Smax.romanov@nginx.com 
5701526Smax.romanov@nginx.com fail:
5711526Smax.romanov@nginx.com 
5721526Smax.romanov@nginx.com     nxt_fd_close(fd);
5731526Smax.romanov@nginx.com 
5741526Smax.romanov@nginx.com     return NXT_ERROR;
575249Svbart@nginx.com }
576249Svbart@nginx.com 
577249Svbart@nginx.com 
57820Sigor@sysoev.ru nxt_int_t
57920Sigor@sysoev.ru nxt_runtime_controller_socket(nxt_task_t *task, nxt_runtime_t *rt)
58020Sigor@sysoev.ru {
58120Sigor@sysoev.ru     nxt_listen_socket_t  *ls;
58220Sigor@sysoev.ru 
58365Sigor@sysoev.ru     ls = nxt_mp_alloc(rt->mem_pool, sizeof(nxt_listen_socket_t));
58420Sigor@sysoev.ru     if (ls == NULL) {
58520Sigor@sysoev.ru         return NXT_ERROR;
58620Sigor@sysoev.ru     }
58720Sigor@sysoev.ru 
5881448Svbart@nginx.com     ls->sockaddr = rt->controller_listen;
58920Sigor@sysoev.ru 
590359Sigor@sysoev.ru     nxt_listen_socket_remote_size(ls);
59120Sigor@sysoev.ru 
59220Sigor@sysoev.ru     ls->socket = -1;
59320Sigor@sysoev.ru     ls->backlog = NXT_LISTEN_BACKLOG;
59420Sigor@sysoev.ru     ls->read_after_accept = 1;
59520Sigor@sysoev.ru     ls->flags = NXT_NONBLOCK;
59620Sigor@sysoev.ru 
59720Sigor@sysoev.ru #if 0
59820Sigor@sysoev.ru     /* STUB */
59965Sigor@sysoev.ru     wq = nxt_mp_zget(cf->mem_pool, sizeof(nxt_work_queue_t));
60020Sigor@sysoev.ru     if (wq == NULL) {
60120Sigor@sysoev.ru         return NXT_ERROR;
60220Sigor@sysoev.ru     }
60320Sigor@sysoev.ru     nxt_work_queue_name(wq, "listen");
60420Sigor@sysoev.ru     /**/
60520Sigor@sysoev.ru 
60620Sigor@sysoev.ru     ls->work_queue = wq;
60720Sigor@sysoev.ru #endif
60820Sigor@sysoev.ru     ls->handler = nxt_controller_conn_init;
60920Sigor@sysoev.ru 
6101451Svbart@nginx.com     if (nxt_listen_socket_create(task, rt->mem_pool, ls) != NXT_OK) {
61120Sigor@sysoev.ru         return NXT_ERROR;
61220Sigor@sysoev.ru     }
61320Sigor@sysoev.ru 
61420Sigor@sysoev.ru     rt->controller_socket = ls;
61520Sigor@sysoev.ru 
61620Sigor@sysoev.ru     return NXT_OK;
61720Sigor@sysoev.ru }
61820Sigor@sysoev.ru 
61920Sigor@sysoev.ru 
62020Sigor@sysoev.ru static void
62120Sigor@sysoev.ru nxt_controller_conn_init(nxt_task_t *task, void *obj, void *data)
62220Sigor@sysoev.ru {
62327Svbart@nginx.com     nxt_buf_t                 *b;
62462Sigor@sysoev.ru     nxt_conn_t                *c;
62527Svbart@nginx.com     nxt_event_engine_t        *engine;
62627Svbart@nginx.com     nxt_controller_request_t  *r;
62720Sigor@sysoev.ru 
62820Sigor@sysoev.ru     c = obj;
62920Sigor@sysoev.ru 
63020Sigor@sysoev.ru     nxt_debug(task, "controller conn init fd:%d", c->socket.fd);
63120Sigor@sysoev.ru 
63265Sigor@sysoev.ru     r = nxt_mp_zget(c->mem_pool, sizeof(nxt_controller_request_t));
63327Svbart@nginx.com     if (nxt_slow_path(r == NULL)) {
63427Svbart@nginx.com         nxt_controller_conn_free(task, c, NULL);
63527Svbart@nginx.com         return;
63627Svbart@nginx.com     }
63727Svbart@nginx.com 
638140Svbart@nginx.com     r->conn = c;
639140Svbart@nginx.com 
64060Svbart@nginx.com     if (nxt_slow_path(nxt_http_parse_request_init(&r->parser, c->mem_pool)
64160Svbart@nginx.com                       != NXT_OK))
64260Svbart@nginx.com     {
64360Svbart@nginx.com         nxt_controller_conn_free(task, c, NULL);
64460Svbart@nginx.com         return;
64560Svbart@nginx.com     }
64627Svbart@nginx.com 
6471167Svbart@nginx.com     r->parser.encoded_slashes = 1;
6481167Svbart@nginx.com 
64920Sigor@sysoev.ru     b = nxt_buf_mem_alloc(c->mem_pool, 1024, 0);
65020Sigor@sysoev.ru     if (nxt_slow_path(b == NULL)) {
65120Sigor@sysoev.ru         nxt_controller_conn_free(task, c, NULL);
65220Sigor@sysoev.ru         return;
65320Sigor@sysoev.ru     }
65420Sigor@sysoev.ru 
65520Sigor@sysoev.ru     c->read = b;
65627Svbart@nginx.com     c->socket.data = r;
65720Sigor@sysoev.ru     c->socket.read_ready = 1;
65820Sigor@sysoev.ru     c->read_state = &nxt_controller_conn_read_state;
65920Sigor@sysoev.ru 
66020Sigor@sysoev.ru     engine = task->thread->engine;
66120Sigor@sysoev.ru     c->read_work_queue = &engine->read_work_queue;
66227Svbart@nginx.com     c->write_work_queue = &engine->write_work_queue;
66320Sigor@sysoev.ru 
66462Sigor@sysoev.ru     nxt_conn_read(engine, c);
66520Sigor@sysoev.ru }
66620Sigor@sysoev.ru 
66720Sigor@sysoev.ru 
66820Sigor@sysoev.ru static const nxt_event_conn_state_t  nxt_controller_conn_read_state
66920Sigor@sysoev.ru     nxt_aligned(64) =
67020Sigor@sysoev.ru {
67156Sigor@sysoev.ru     .ready_handler = nxt_controller_conn_read,
67256Sigor@sysoev.ru     .close_handler = nxt_controller_conn_close,
67356Sigor@sysoev.ru     .error_handler = nxt_controller_conn_read_error,
67420Sigor@sysoev.ru 
67556Sigor@sysoev.ru     .timer_handler = nxt_controller_conn_read_timeout,
67656Sigor@sysoev.ru     .timer_value = nxt_controller_conn_timeout_value,
67756Sigor@sysoev.ru     .timer_data = 60 * 1000,
67820Sigor@sysoev.ru };
67920Sigor@sysoev.ru 
68020Sigor@sysoev.ru 
68120Sigor@sysoev.ru static void
68220Sigor@sysoev.ru nxt_controller_conn_read(nxt_task_t *task, void *obj, void *data)
68320Sigor@sysoev.ru {
68427Svbart@nginx.com     size_t                    preread;
68527Svbart@nginx.com     nxt_buf_t                 *b;
68627Svbart@nginx.com     nxt_int_t                 rc;
68762Sigor@sysoev.ru     nxt_conn_t                *c;
68827Svbart@nginx.com     nxt_controller_request_t  *r;
68920Sigor@sysoev.ru 
69020Sigor@sysoev.ru     c = obj;
69127Svbart@nginx.com     r = data;
69220Sigor@sysoev.ru 
69320Sigor@sysoev.ru     nxt_debug(task, "controller conn read");
69420Sigor@sysoev.ru 
69527Svbart@nginx.com     nxt_queue_remove(&c->link);
69627Svbart@nginx.com     nxt_queue_self(&c->link);
69727Svbart@nginx.com 
69827Svbart@nginx.com     b = c->read;
69927Svbart@nginx.com 
70027Svbart@nginx.com     rc = nxt_http_parse_request(&r->parser, &b->mem);
70127Svbart@nginx.com 
70227Svbart@nginx.com     if (nxt_slow_path(rc != NXT_DONE)) {
70327Svbart@nginx.com 
70427Svbart@nginx.com         if (rc == NXT_AGAIN) {
70527Svbart@nginx.com             if (nxt_buf_mem_free_size(&b->mem) == 0) {
70627Svbart@nginx.com                 nxt_log(task, NXT_LOG_ERR, "too long request headers");
70727Svbart@nginx.com                 nxt_controller_conn_close(task, c, r);
70827Svbart@nginx.com                 return;
70927Svbart@nginx.com             }
71027Svbart@nginx.com 
71162Sigor@sysoev.ru             nxt_conn_read(task->thread->engine, c);
71227Svbart@nginx.com             return;
71327Svbart@nginx.com         }
71427Svbart@nginx.com 
71527Svbart@nginx.com         /* rc == NXT_ERROR */
71627Svbart@nginx.com 
71727Svbart@nginx.com         nxt_log(task, NXT_LOG_ERR, "parsing error");
71827Svbart@nginx.com 
71927Svbart@nginx.com         nxt_controller_conn_close(task, c, r);
72027Svbart@nginx.com         return;
72127Svbart@nginx.com     }
72227Svbart@nginx.com 
723417Svbart@nginx.com     rc = nxt_http_fields_process(r->parser.fields, &nxt_controller_fields_hash,
724417Svbart@nginx.com                                  r);
72560Svbart@nginx.com 
72660Svbart@nginx.com     if (nxt_slow_path(rc != NXT_OK)) {
72760Svbart@nginx.com         nxt_controller_conn_close(task, c, r);
72860Svbart@nginx.com         return;
72960Svbart@nginx.com     }
73060Svbart@nginx.com 
73127Svbart@nginx.com     preread = nxt_buf_mem_used_size(&b->mem);
73227Svbart@nginx.com 
73327Svbart@nginx.com     nxt_debug(task, "controller request header parsing complete, "
734107Svbart@nginx.com                     "body length: %uz, preread: %uz",
73527Svbart@nginx.com                     r->length, preread);
73627Svbart@nginx.com 
73727Svbart@nginx.com     if (preread >= r->length) {
738140Svbart@nginx.com         nxt_controller_process_request(task, r);
73927Svbart@nginx.com         return;
74027Svbart@nginx.com     }
74127Svbart@nginx.com 
74227Svbart@nginx.com     if (r->length - preread > (size_t) nxt_buf_mem_free_size(&b->mem)) {
74327Svbart@nginx.com         b = nxt_buf_mem_alloc(c->mem_pool, r->length, 0);
74427Svbart@nginx.com         if (nxt_slow_path(b == NULL)) {
74527Svbart@nginx.com             nxt_controller_conn_free(task, c, NULL);
74627Svbart@nginx.com             return;
74727Svbart@nginx.com         }
74827Svbart@nginx.com 
74927Svbart@nginx.com         b->mem.free = nxt_cpymem(b->mem.free, c->read->mem.pos, preread);
75027Svbart@nginx.com 
75127Svbart@nginx.com         c->read = b;
75227Svbart@nginx.com     }
75327Svbart@nginx.com 
75427Svbart@nginx.com     c->read_state = &nxt_controller_conn_body_read_state;
75527Svbart@nginx.com 
75662Sigor@sysoev.ru     nxt_conn_read(task->thread->engine, c);
75720Sigor@sysoev.ru }
75820Sigor@sysoev.ru 
75920Sigor@sysoev.ru 
76020Sigor@sysoev.ru static nxt_msec_t
76162Sigor@sysoev.ru nxt_controller_conn_timeout_value(nxt_conn_t *c, uintptr_t data)
76220Sigor@sysoev.ru {
76320Sigor@sysoev.ru     return (nxt_msec_t) data;
76420Sigor@sysoev.ru }
76520Sigor@sysoev.ru 
76620Sigor@sysoev.ru 
76720Sigor@sysoev.ru static void
76820Sigor@sysoev.ru nxt_controller_conn_read_error(nxt_task_t *task, void *obj, void *data)
76920Sigor@sysoev.ru {
77062Sigor@sysoev.ru     nxt_conn_t  *c;
77120Sigor@sysoev.ru 
77220Sigor@sysoev.ru     c = obj;
77320Sigor@sysoev.ru 
77420Sigor@sysoev.ru     nxt_debug(task, "controller conn read error");
77520Sigor@sysoev.ru 
77627Svbart@nginx.com     nxt_controller_conn_close(task, c, data);
77720Sigor@sysoev.ru }
77820Sigor@sysoev.ru 
77920Sigor@sysoev.ru 
78020Sigor@sysoev.ru static void
78120Sigor@sysoev.ru nxt_controller_conn_read_timeout(nxt_task_t *task, void *obj, void *data)
78220Sigor@sysoev.ru {
78362Sigor@sysoev.ru     nxt_timer_t  *timer;
78462Sigor@sysoev.ru     nxt_conn_t   *c;
78520Sigor@sysoev.ru 
78662Sigor@sysoev.ru     timer = obj;
78720Sigor@sysoev.ru 
78862Sigor@sysoev.ru     c = nxt_read_timer_conn(timer);
78920Sigor@sysoev.ru     c->socket.timedout = 1;
79020Sigor@sysoev.ru     c->socket.closed = 1;
79120Sigor@sysoev.ru 
79220Sigor@sysoev.ru     nxt_debug(task, "controller conn read timeout");
79320Sigor@sysoev.ru 
79427Svbart@nginx.com     nxt_controller_conn_close(task, c, data);
79527Svbart@nginx.com }
79627Svbart@nginx.com 
79727Svbart@nginx.com 
79827Svbart@nginx.com static const nxt_event_conn_state_t  nxt_controller_conn_body_read_state
79927Svbart@nginx.com     nxt_aligned(64) =
80027Svbart@nginx.com {
80156Sigor@sysoev.ru     .ready_handler = nxt_controller_conn_body_read,
80256Sigor@sysoev.ru     .close_handler = nxt_controller_conn_close,
80356Sigor@sysoev.ru     .error_handler = nxt_controller_conn_read_error,
80427Svbart@nginx.com 
80556Sigor@sysoev.ru     .timer_handler = nxt_controller_conn_read_timeout,
80656Sigor@sysoev.ru     .timer_value = nxt_controller_conn_timeout_value,
80756Sigor@sysoev.ru     .timer_data = 60 * 1000,
80856Sigor@sysoev.ru     .timer_autoreset = 1,
80927Svbart@nginx.com };
81027Svbart@nginx.com 
81127Svbart@nginx.com 
81227Svbart@nginx.com static void
81327Svbart@nginx.com nxt_controller_conn_body_read(nxt_task_t *task, void *obj, void *data)
81427Svbart@nginx.com {
815107Svbart@nginx.com     size_t                    read;
816107Svbart@nginx.com     nxt_buf_t                 *b;
817107Svbart@nginx.com     nxt_conn_t                *c;
818107Svbart@nginx.com     nxt_controller_request_t  *r;
81927Svbart@nginx.com 
82027Svbart@nginx.com     c = obj;
821107Svbart@nginx.com     r = data;
82227Svbart@nginx.com     b = c->read;
82327Svbart@nginx.com 
824107Svbart@nginx.com     read = nxt_buf_mem_used_size(&b->mem);
82527Svbart@nginx.com 
826107Svbart@nginx.com     nxt_debug(task, "controller conn body read: %uz of %uz",
827107Svbart@nginx.com               read, r->length);
82827Svbart@nginx.com 
829107Svbart@nginx.com     if (read >= r->length) {
830140Svbart@nginx.com         nxt_controller_process_request(task, r);
83127Svbart@nginx.com         return;
83227Svbart@nginx.com     }
83327Svbart@nginx.com 
83462Sigor@sysoev.ru     nxt_conn_read(task->thread->engine, c);
83527Svbart@nginx.com }
83627Svbart@nginx.com 
83727Svbart@nginx.com 
83827Svbart@nginx.com static const nxt_event_conn_state_t  nxt_controller_conn_write_state
83927Svbart@nginx.com     nxt_aligned(64) =
84027Svbart@nginx.com {
84156Sigor@sysoev.ru     .ready_handler = nxt_controller_conn_write,
84256Sigor@sysoev.ru     .error_handler = nxt_controller_conn_write_error,
84327Svbart@nginx.com 
84456Sigor@sysoev.ru     .timer_handler = nxt_controller_conn_write_timeout,
84556Sigor@sysoev.ru     .timer_value = nxt_controller_conn_timeout_value,
84656Sigor@sysoev.ru     .timer_data = 60 * 1000,
84756Sigor@sysoev.ru     .timer_autoreset = 1,
84827Svbart@nginx.com };
84927Svbart@nginx.com 
85027Svbart@nginx.com 
85127Svbart@nginx.com static void
85227Svbart@nginx.com nxt_controller_conn_write(nxt_task_t *task, void *obj, void *data)
85327Svbart@nginx.com {
85462Sigor@sysoev.ru     nxt_buf_t   *b;
85562Sigor@sysoev.ru     nxt_conn_t  *c;
85627Svbart@nginx.com 
85727Svbart@nginx.com     c = obj;
85827Svbart@nginx.com 
85927Svbart@nginx.com     nxt_debug(task, "controller conn write");
86027Svbart@nginx.com 
86127Svbart@nginx.com     b = c->write;
86227Svbart@nginx.com 
86327Svbart@nginx.com     if (b->mem.pos != b->mem.free) {
86462Sigor@sysoev.ru         nxt_conn_write(task->thread->engine, c);
86527Svbart@nginx.com         return;
86627Svbart@nginx.com     }
86727Svbart@nginx.com 
86827Svbart@nginx.com     nxt_debug(task, "controller conn write complete");
86927Svbart@nginx.com 
87027Svbart@nginx.com     nxt_controller_conn_close(task, c, data);
87127Svbart@nginx.com }
87227Svbart@nginx.com 
87327Svbart@nginx.com 
87427Svbart@nginx.com static void
87527Svbart@nginx.com nxt_controller_conn_write_error(nxt_task_t *task, void *obj, void *data)
87627Svbart@nginx.com {
87762Sigor@sysoev.ru     nxt_conn_t  *c;
87827Svbart@nginx.com 
87927Svbart@nginx.com     c = obj;
88027Svbart@nginx.com 
88127Svbart@nginx.com     nxt_debug(task, "controller conn write error");
88227Svbart@nginx.com 
88327Svbart@nginx.com     nxt_controller_conn_close(task, c, data);
88427Svbart@nginx.com }
88527Svbart@nginx.com 
88627Svbart@nginx.com 
88727Svbart@nginx.com static void
88827Svbart@nginx.com nxt_controller_conn_write_timeout(nxt_task_t *task, void *obj, void *data)
88927Svbart@nginx.com {
89062Sigor@sysoev.ru     nxt_conn_t   *c;
89162Sigor@sysoev.ru     nxt_timer_t  *timer;
89227Svbart@nginx.com 
89362Sigor@sysoev.ru     timer = obj;
89427Svbart@nginx.com 
89562Sigor@sysoev.ru     c = nxt_write_timer_conn(timer);
89627Svbart@nginx.com     c->socket.timedout = 1;
89727Svbart@nginx.com     c->socket.closed = 1;
89827Svbart@nginx.com 
89927Svbart@nginx.com     nxt_debug(task, "controller conn write timeout");
90027Svbart@nginx.com 
90127Svbart@nginx.com     nxt_controller_conn_close(task, c, data);
90220Sigor@sysoev.ru }
90320Sigor@sysoev.ru 
90420Sigor@sysoev.ru 
90520Sigor@sysoev.ru static const nxt_event_conn_state_t  nxt_controller_conn_close_state
90620Sigor@sysoev.ru     nxt_aligned(64) =
90720Sigor@sysoev.ru {
90856Sigor@sysoev.ru     .ready_handler = nxt_controller_conn_free,
90920Sigor@sysoev.ru };
91020Sigor@sysoev.ru 
91120Sigor@sysoev.ru 
91220Sigor@sysoev.ru static void
91320Sigor@sysoev.ru nxt_controller_conn_close(nxt_task_t *task, void *obj, void *data)
91420Sigor@sysoev.ru {
91562Sigor@sysoev.ru     nxt_conn_t  *c;
91620Sigor@sysoev.ru 
91720Sigor@sysoev.ru     c = obj;
91820Sigor@sysoev.ru 
91920Sigor@sysoev.ru     nxt_debug(task, "controller conn close");
92020Sigor@sysoev.ru 
92127Svbart@nginx.com     nxt_queue_remove(&c->link);
92227Svbart@nginx.com 
92320Sigor@sysoev.ru     c->write_state = &nxt_controller_conn_close_state;
92420Sigor@sysoev.ru 
92562Sigor@sysoev.ru     nxt_conn_close(task->thread->engine, c);
92620Sigor@sysoev.ru }
92720Sigor@sysoev.ru 
92820Sigor@sysoev.ru 
92920Sigor@sysoev.ru static void
93020Sigor@sysoev.ru nxt_controller_conn_free(nxt_task_t *task, void *obj, void *data)
93120Sigor@sysoev.ru {
93262Sigor@sysoev.ru     nxt_conn_t  *c;
93320Sigor@sysoev.ru 
93420Sigor@sysoev.ru     c = obj;
93520Sigor@sysoev.ru 
93620Sigor@sysoev.ru     nxt_debug(task, "controller conn free");
93720Sigor@sysoev.ru 
938337Sigor@sysoev.ru     nxt_sockaddr_cache_free(task->thread->engine, c);
939337Sigor@sysoev.ru 
940386Sigor@sysoev.ru     nxt_conn_free(task, c);
94120Sigor@sysoev.ru }
94227Svbart@nginx.com 
94327Svbart@nginx.com 
94427Svbart@nginx.com static nxt_int_t
94560Svbart@nginx.com nxt_controller_request_content_length(void *ctx, nxt_http_field_t *field,
946417Svbart@nginx.com     uintptr_t data)
94727Svbart@nginx.com {
94827Svbart@nginx.com     off_t                     length;
94927Svbart@nginx.com     nxt_controller_request_t  *r;
95027Svbart@nginx.com 
95127Svbart@nginx.com     r = ctx;
95227Svbart@nginx.com 
953417Svbart@nginx.com     length = nxt_off_t_parse(field->value, field->value_length);
95427Svbart@nginx.com 
955710Svbart@nginx.com     if (nxt_fast_path(length >= 0)) {
956107Svbart@nginx.com 
957107Svbart@nginx.com         if (nxt_slow_path(length > NXT_SIZE_T_MAX)) {
958417Svbart@nginx.com             nxt_log_error(NXT_LOG_ERR, &r->conn->log,
959417Svbart@nginx.com                           "Content-Length is too big");
960107Svbart@nginx.com             return NXT_ERROR;
961107Svbart@nginx.com         }
96227Svbart@nginx.com 
96327Svbart@nginx.com         r->length = length;
96427Svbart@nginx.com         return NXT_OK;
96527Svbart@nginx.com     }
96627Svbart@nginx.com 
967417Svbart@nginx.com     nxt_log_error(NXT_LOG_ERR, &r->conn->log, "Content-Length is invalid");
96827Svbart@nginx.com 
96927Svbart@nginx.com     return NXT_ERROR;
97027Svbart@nginx.com }
97127Svbart@nginx.com 
97227Svbart@nginx.com 
97327Svbart@nginx.com static void
974140Svbart@nginx.com nxt_controller_process_request(nxt_task_t *task, nxt_controller_request_t *req)
97527Svbart@nginx.com {
976774Svbart@nginx.com     uint32_t                   i, count;
977774Svbart@nginx.com     nxt_str_t                  path;
978774Svbart@nginx.com     nxt_conn_t                 *c;
979774Svbart@nginx.com     nxt_conf_value_t           *value;
980774Svbart@nginx.com     nxt_controller_response_t  resp;
981774Svbart@nginx.com #if (NXT_TLS)
982774Svbart@nginx.com     nxt_conf_value_t           *certs;
983774Svbart@nginx.com 
984774Svbart@nginx.com     static nxt_str_t certificates = nxt_string("certificates");
985774Svbart@nginx.com #endif
986774Svbart@nginx.com     static nxt_str_t config = nxt_string("config");
987774Svbart@nginx.com 
988774Svbart@nginx.com     c = req->conn;
989774Svbart@nginx.com     path = req->parser.path;
990774Svbart@nginx.com 
991774Svbart@nginx.com     if (path.length > 1 && path.start[path.length - 1] == '/') {
992774Svbart@nginx.com         path.length--;
993774Svbart@nginx.com     }
994774Svbart@nginx.com 
995774Svbart@nginx.com     if (nxt_str_start(&path, "/config", 7)
996774Svbart@nginx.com         && (path.length == 7 || path.start[7] == '/'))
997774Svbart@nginx.com     {
998774Svbart@nginx.com         if (path.length == 7) {
999774Svbart@nginx.com             path.length = 1;
1000774Svbart@nginx.com 
1001774Svbart@nginx.com         } else {
1002774Svbart@nginx.com             path.length -= 7;
1003774Svbart@nginx.com             path.start += 7;
1004774Svbart@nginx.com         }
1005774Svbart@nginx.com 
1006774Svbart@nginx.com         nxt_controller_process_config(task, req, &path);
1007774Svbart@nginx.com         return;
1008774Svbart@nginx.com     }
1009774Svbart@nginx.com 
1010774Svbart@nginx.com #if (NXT_TLS)
1011774Svbart@nginx.com 
1012774Svbart@nginx.com     if (nxt_str_start(&path, "/certificates", 13)
1013774Svbart@nginx.com         && (path.length == 13 || path.start[13] == '/'))
1014774Svbart@nginx.com     {
1015774Svbart@nginx.com         if (path.length == 13) {
1016774Svbart@nginx.com             path.length = 1;
1017774Svbart@nginx.com 
1018774Svbart@nginx.com         } else {
1019774Svbart@nginx.com             path.length -= 13;
1020774Svbart@nginx.com             path.start += 13;
1021774Svbart@nginx.com         }
1022774Svbart@nginx.com 
1023774Svbart@nginx.com         nxt_controller_process_cert(task, req, &path);
1024774Svbart@nginx.com         return;
1025774Svbart@nginx.com     }
1026774Svbart@nginx.com 
1027774Svbart@nginx.com #endif
1028774Svbart@nginx.com 
1029*1926Smax.romanov@nginx.com     if (nxt_str_start(&path, "/control/", 9)) {
1030*1926Smax.romanov@nginx.com         path.length -= 9;
1031*1926Smax.romanov@nginx.com         path.start += 9;
1032*1926Smax.romanov@nginx.com 
1033*1926Smax.romanov@nginx.com         nxt_controller_process_control(task, req, &path);
1034*1926Smax.romanov@nginx.com         return;
1035*1926Smax.romanov@nginx.com     }
1036*1926Smax.romanov@nginx.com 
1037774Svbart@nginx.com     nxt_memzero(&resp, sizeof(nxt_controller_response_t));
1038774Svbart@nginx.com 
1039774Svbart@nginx.com     if (path.length == 1 && path.start[0] == '/') {
1040774Svbart@nginx.com 
1041774Svbart@nginx.com         if (!nxt_str_eq(&req->parser.method, "GET", 3)) {
1042774Svbart@nginx.com             goto invalid_method;
1043774Svbart@nginx.com         }
1044774Svbart@nginx.com 
1045774Svbart@nginx.com         count = 1;
1046774Svbart@nginx.com #if (NXT_TLS)
1047774Svbart@nginx.com         count++;
1048774Svbart@nginx.com #endif
1049774Svbart@nginx.com 
1050774Svbart@nginx.com         value = nxt_conf_create_object(c->mem_pool, count);
1051774Svbart@nginx.com         if (nxt_slow_path(value == NULL)) {
1052774Svbart@nginx.com             goto alloc_fail;
1053774Svbart@nginx.com         }
1054774Svbart@nginx.com 
1055774Svbart@nginx.com         i = 0;
1056774Svbart@nginx.com 
1057774Svbart@nginx.com #if (NXT_TLS)
1058774Svbart@nginx.com         certs = nxt_cert_info_get_all(c->mem_pool);
1059774Svbart@nginx.com         if (nxt_slow_path(certs == NULL)) {
1060774Svbart@nginx.com             goto alloc_fail;
1061774Svbart@nginx.com         }
1062774Svbart@nginx.com 
1063774Svbart@nginx.com         nxt_conf_set_member(value, &certificates, certs, i++);
1064774Svbart@nginx.com #endif
1065774Svbart@nginx.com 
1066774Svbart@nginx.com         nxt_conf_set_member(value, &config, nxt_controller_conf.root, i);
1067774Svbart@nginx.com 
1068774Svbart@nginx.com         resp.status = 200;
1069774Svbart@nginx.com         resp.conf = value;
1070774Svbart@nginx.com 
1071774Svbart@nginx.com         nxt_controller_response(task, req, &resp);
1072774Svbart@nginx.com         return;
1073774Svbart@nginx.com     }
1074774Svbart@nginx.com 
1075774Svbart@nginx.com     resp.status = 404;
1076774Svbart@nginx.com     resp.title = (u_char *) "Value doesn't exist.";
1077774Svbart@nginx.com     resp.offset = -1;
1078774Svbart@nginx.com 
1079774Svbart@nginx.com     nxt_controller_response(task, req, &resp);
1080774Svbart@nginx.com     return;
1081774Svbart@nginx.com 
1082774Svbart@nginx.com invalid_method:
1083774Svbart@nginx.com 
1084774Svbart@nginx.com     resp.status = 405;
1085774Svbart@nginx.com     resp.title = (u_char *) "Invalid method.";
1086774Svbart@nginx.com     resp.offset = -1;
1087774Svbart@nginx.com 
1088774Svbart@nginx.com     nxt_controller_response(task, req, &resp);
1089774Svbart@nginx.com     return;
1090774Svbart@nginx.com 
1091774Svbart@nginx.com alloc_fail:
1092774Svbart@nginx.com 
1093774Svbart@nginx.com     resp.status = 500;
1094774Svbart@nginx.com     resp.title = (u_char *) "Memory allocation failed.";
1095774Svbart@nginx.com     resp.offset = -1;
1096774Svbart@nginx.com 
1097774Svbart@nginx.com     nxt_controller_response(task, req, &resp);
1098774Svbart@nginx.com     return;
1099774Svbart@nginx.com }
1100774Svbart@nginx.com 
1101774Svbart@nginx.com 
1102774Svbart@nginx.com static void
1103774Svbart@nginx.com nxt_controller_process_config(nxt_task_t *task, nxt_controller_request_t *req,
1104774Svbart@nginx.com     nxt_str_t *path)
1105774Svbart@nginx.com {
110665Sigor@sysoev.ru     nxt_mp_t                   *mp;
110751Svbart@nginx.com     nxt_int_t                  rc;
1108140Svbart@nginx.com     nxt_conn_t                 *c;
11091049Svbart@nginx.com     nxt_bool_t                 post;
111051Svbart@nginx.com     nxt_buf_mem_t              *mbuf;
1111106Svbart@nginx.com     nxt_conf_op_t              *ops;
1112106Svbart@nginx.com     nxt_conf_value_t           *value;
1113357Svbart@nginx.com     nxt_conf_validation_t      vldt;
1114208Svbart@nginx.com     nxt_conf_json_error_t      error;
111544Svbart@nginx.com     nxt_controller_response_t  resp;
111644Svbart@nginx.com 
111751Svbart@nginx.com     static const nxt_str_t empty_obj = nxt_string("{}");
111851Svbart@nginx.com 
1119774Svbart@nginx.com     nxt_memzero(&resp, sizeof(nxt_controller_response_t));
1120632Svbart@nginx.com 
1121774Svbart@nginx.com     c = req->conn;
112244Svbart@nginx.com 
112344Svbart@nginx.com     if (nxt_str_eq(&req->parser.method, "GET", 3)) {
112446Svbart@nginx.com 
1125774Svbart@nginx.com         value = nxt_conf_get_path(nxt_controller_conf.root, path);
112651Svbart@nginx.com 
112751Svbart@nginx.com         if (value == NULL) {
1128208Svbart@nginx.com             goto not_found;
112951Svbart@nginx.com         }
113051Svbart@nginx.com 
1131208Svbart@nginx.com         resp.status = 200;
1132106Svbart@nginx.com         resp.conf = value;
113346Svbart@nginx.com 
1134208Svbart@nginx.com         nxt_controller_response(task, req, &resp);
1135208Svbart@nginx.com         return;
113651Svbart@nginx.com     }
113751Svbart@nginx.com 
11381049Svbart@nginx.com     if (nxt_str_eq(&req->parser.method, "POST", 4)) {
11391049Svbart@nginx.com         if (path->length == 1) {
11401049Svbart@nginx.com             goto not_allowed;
11411049Svbart@nginx.com         }
11421049Svbart@nginx.com 
11431049Svbart@nginx.com         post = 1;
11441049Svbart@nginx.com 
11451049Svbart@nginx.com     } else {
11461049Svbart@nginx.com         post = 0;
11471049Svbart@nginx.com     }
11481049Svbart@nginx.com 
11491049Svbart@nginx.com     if (post || nxt_str_eq(&req->parser.method, "PUT", 3)) {
115046Svbart@nginx.com 
11511470Smax.romanov@nginx.com         if (nxt_controller_check_postpone_request(task)) {
1152238Svbart@nginx.com             nxt_queue_insert_tail(&nxt_controller_waiting_requests, &req->link);
1153238Svbart@nginx.com             return;
1154238Svbart@nginx.com         }
1155238Svbart@nginx.com 
115665Sigor@sysoev.ru         mp = nxt_mp_create(1024, 128, 256, 32);
115751Svbart@nginx.com 
115851Svbart@nginx.com         if (nxt_slow_path(mp == NULL)) {
1159208Svbart@nginx.com             goto alloc_fail;
116046Svbart@nginx.com         }
116146Svbart@nginx.com 
116251Svbart@nginx.com         mbuf = &c->read->mem;
116351Svbart@nginx.com 
1164208Svbart@nginx.com         nxt_memzero(&error, sizeof(nxt_conf_json_error_t));
1165208Svbart@nginx.com 
11661364Svbart@nginx.com         /* Skip UTF-8 BOM. */
11671364Svbart@nginx.com         if (nxt_buf_mem_used_size(mbuf) >= 3
11681364Svbart@nginx.com             && nxt_memcmp(mbuf->pos, "\xEF\xBB\xBF", 3) == 0)
11691364Svbart@nginx.com         {
11701364Svbart@nginx.com             mbuf->pos += 3;
11711364Svbart@nginx.com         }
11721364Svbart@nginx.com 
1173208Svbart@nginx.com         value = nxt_conf_json_parse(mp, mbuf->pos, mbuf->free, &error);
117451Svbart@nginx.com 
117551Svbart@nginx.com         if (value == NULL) {
117665Sigor@sysoev.ru             nxt_mp_destroy(mp);
1177208Svbart@nginx.com 
1178208Svbart@nginx.com             if (error.pos == NULL) {
1179208Svbart@nginx.com                 goto alloc_fail;
1180208Svbart@nginx.com             }
1181208Svbart@nginx.com 
1182208Svbart@nginx.com             resp.status = 400;
1183208Svbart@nginx.com             resp.title = (u_char *) "Invalid JSON.";
1184357Svbart@nginx.com             resp.detail.length = nxt_strlen(error.detail);
1185357Svbart@nginx.com             resp.detail.start = error.detail;
1186208Svbart@nginx.com             resp.offset = error.pos - mbuf->pos;
1187208Svbart@nginx.com 
1188208Svbart@nginx.com             nxt_conf_json_position(mbuf->pos, error.pos,
1189208Svbart@nginx.com                                    &resp.line, &resp.column);
1190208Svbart@nginx.com 
1191208Svbart@nginx.com             nxt_controller_response(task, req, &resp);
1192208Svbart@nginx.com             return;
119351Svbart@nginx.com         }
119451Svbart@nginx.com 
1195774Svbart@nginx.com         if (path->length != 1) {
1196106Svbart@nginx.com             rc = nxt_conf_op_compile(c->mem_pool, &ops,
1197106Svbart@nginx.com                                      nxt_controller_conf.root,
11981049Svbart@nginx.com                                      path, value, post);
119946Svbart@nginx.com 
12001049Svbart@nginx.com             if (rc != NXT_CONF_OP_OK) {
1201619Svbart@nginx.com                 nxt_mp_destroy(mp);
1202619Svbart@nginx.com 
12031049Svbart@nginx.com                 switch (rc) {
12041049Svbart@nginx.com                 case NXT_CONF_OP_NOT_FOUND:
1205208Svbart@nginx.com                     goto not_found;
12061049Svbart@nginx.com 
12071049Svbart@nginx.com                 case NXT_CONF_OP_NOT_ALLOWED:
12081049Svbart@nginx.com                     goto not_allowed;
120951Svbart@nginx.com                 }
121046Svbart@nginx.com 
12111049Svbart@nginx.com                 /* rc == NXT_CONF_OP_ERROR */
1212208Svbart@nginx.com                 goto alloc_fail;
121351Svbart@nginx.com             }
121451Svbart@nginx.com 
1215106Svbart@nginx.com             value = nxt_conf_clone(mp, ops, nxt_controller_conf.root);
121651Svbart@nginx.com 
121751Svbart@nginx.com             if (nxt_slow_path(value == NULL)) {
121865Sigor@sysoev.ru                 nxt_mp_destroy(mp);
1219208Svbart@nginx.com                 goto alloc_fail;
122051Svbart@nginx.com             }
122146Svbart@nginx.com         }
122244Svbart@nginx.com 
1223357Svbart@nginx.com         nxt_memzero(&vldt, sizeof(nxt_conf_validation_t));
1224357Svbart@nginx.com 
1225357Svbart@nginx.com         vldt.conf = value;
1226357Svbart@nginx.com         vldt.pool = c->mem_pool;
1227357Svbart@nginx.com 
1228357Svbart@nginx.com         rc = nxt_conf_validate(&vldt);
1229357Svbart@nginx.com 
1230357Svbart@nginx.com         if (nxt_slow_path(rc != NXT_OK)) {
1231121Svbart@nginx.com             nxt_mp_destroy(mp);
1232357Svbart@nginx.com 
1233357Svbart@nginx.com             if (rc == NXT_DECLINED) {
1234357Svbart@nginx.com                 resp.detail = vldt.error;
1235357Svbart@nginx.com                 goto invalid_conf;
1236357Svbart@nginx.com             }
1237357Svbart@nginx.com 
1238357Svbart@nginx.com             /* rc == NXT_ERROR */
1239357Svbart@nginx.com             goto alloc_fail;
1240116Svbart@nginx.com         }
1241116Svbart@nginx.com 
12421526Smax.romanov@nginx.com         rc = nxt_controller_conf_send(task, mp, value,
1243249Svbart@nginx.com                                       nxt_controller_conf_handler, req);
1244247Svbart@nginx.com 
1245247Svbart@nginx.com         if (nxt_slow_path(rc != NXT_OK)) {
1246121Svbart@nginx.com             nxt_mp_destroy(mp);
1247247Svbart@nginx.com 
1248247Svbart@nginx.com             /* rc == NXT_ERROR */
1249208Svbart@nginx.com             goto alloc_fail;
1250121Svbart@nginx.com         }
1251121Svbart@nginx.com 
1252249Svbart@nginx.com         req->conf.root = value;
1253249Svbart@nginx.com         req->conf.pool = mp;
1254249Svbart@nginx.com 
1255249Svbart@nginx.com         nxt_queue_insert_head(&nxt_controller_waiting_requests, &req->link);
1256249Svbart@nginx.com 
1257140Svbart@nginx.com         return;
125851Svbart@nginx.com     }
125927Svbart@nginx.com 
126051Svbart@nginx.com     if (nxt_str_eq(&req->parser.method, "DELETE", 6)) {
126151Svbart@nginx.com 
12621470Smax.romanov@nginx.com         if (nxt_controller_check_postpone_request(task)) {
1263238Svbart@nginx.com             nxt_queue_insert_tail(&nxt_controller_waiting_requests, &req->link);
1264238Svbart@nginx.com             return;
1265238Svbart@nginx.com         }
1266238Svbart@nginx.com 
1267774Svbart@nginx.com         if (path->length == 1) {
126865Sigor@sysoev.ru             mp = nxt_mp_create(1024, 128, 256, 32);
126944Svbart@nginx.com 
127051Svbart@nginx.com             if (nxt_slow_path(mp == NULL)) {
1271208Svbart@nginx.com                 goto alloc_fail;
127251Svbart@nginx.com             }
127351Svbart@nginx.com 
1274106Svbart@nginx.com             value = nxt_conf_json_parse_str(mp, &empty_obj);
127527Svbart@nginx.com 
127644Svbart@nginx.com         } else {
1277106Svbart@nginx.com             rc = nxt_conf_op_compile(c->mem_pool, &ops,
1278106Svbart@nginx.com                                      nxt_controller_conf.root,
12791049Svbart@nginx.com                                      path, NULL, 0);
128051Svbart@nginx.com 
128151Svbart@nginx.com             if (rc != NXT_OK) {
12821049Svbart@nginx.com                 if (rc == NXT_CONF_OP_NOT_FOUND) {
1283208Svbart@nginx.com                     goto not_found;
128451Svbart@nginx.com                 }
128551Svbart@nginx.com 
12861049Svbart@nginx.com                 /* rc == NXT_CONF_OP_ERROR */
1287208Svbart@nginx.com                 goto alloc_fail;
128851Svbart@nginx.com             }
128951Svbart@nginx.com 
129065Sigor@sysoev.ru             mp = nxt_mp_create(1024, 128, 256, 32);
129151Svbart@nginx.com 
129251Svbart@nginx.com             if (nxt_slow_path(mp == NULL)) {
1293208Svbart@nginx.com                 goto alloc_fail;
129451Svbart@nginx.com             }
129551Svbart@nginx.com 
1296106Svbart@nginx.com             value = nxt_conf_clone(mp, ops, nxt_controller_conf.root);
129751Svbart@nginx.com         }
129851Svbart@nginx.com 
129951Svbart@nginx.com         if (nxt_slow_path(value == NULL)) {
130065Sigor@sysoev.ru             nxt_mp_destroy(mp);
1301208Svbart@nginx.com             goto alloc_fail;
130244Svbart@nginx.com         }
130344Svbart@nginx.com 
1304357Svbart@nginx.com         nxt_memzero(&vldt, sizeof(nxt_conf_validation_t));
1305357Svbart@nginx.com 
1306357Svbart@nginx.com         vldt.conf = value;
1307357Svbart@nginx.com         vldt.pool = c->mem_pool;
1308357Svbart@nginx.com 
1309357Svbart@nginx.com         rc = nxt_conf_validate(&vldt);
1310357Svbart@nginx.com 
1311357Svbart@nginx.com         if (nxt_slow_path(rc != NXT_OK)) {
1312121Svbart@nginx.com             nxt_mp_destroy(mp);
1313357Svbart@nginx.com 
1314357Svbart@nginx.com             if (rc == NXT_DECLINED) {
1315357Svbart@nginx.com                 resp.detail = vldt.error;
1316357Svbart@nginx.com                 goto invalid_conf;
1317357Svbart@nginx.com             }
1318357Svbart@nginx.com 
1319357Svbart@nginx.com             /* rc == NXT_ERROR */
1320357Svbart@nginx.com             goto alloc_fail;
1321116Svbart@nginx.com         }
1322116Svbart@nginx.com 
13231526Smax.romanov@nginx.com         rc = nxt_controller_conf_send(task, mp, value,
1324249Svbart@nginx.com                                       nxt_controller_conf_handler, req);
1325247Svbart@nginx.com 
1326247Svbart@nginx.com         if (nxt_slow_path(rc != NXT_OK)) {
1327121Svbart@nginx.com             nxt_mp_destroy(mp);
1328247Svbart@nginx.com 
1329247Svbart@nginx.com             /* rc == NXT_ERROR */
1330208Svbart@nginx.com             goto alloc_fail;
1331121Svbart@nginx.com         }
1332121Svbart@nginx.com 
1333249Svbart@nginx.com         req->conf.root = value;
1334249Svbart@nginx.com         req->conf.pool = mp;
1335249Svbart@nginx.com 
1336249Svbart@nginx.com         nxt_queue_insert_head(&nxt_controller_waiting_requests, &req->link);
1337249Svbart@nginx.com 
1338140Svbart@nginx.com         return;
133951Svbart@nginx.com     }
134051Svbart@nginx.com 
13411049Svbart@nginx.com not_allowed:
13421049Svbart@nginx.com 
1343208Svbart@nginx.com     resp.status = 405;
13441049Svbart@nginx.com     resp.title = (u_char *) "Method isn't allowed.";
1345208Svbart@nginx.com     resp.offset = -1;
134651Svbart@nginx.com 
1347208Svbart@nginx.com     nxt_controller_response(task, req, &resp);
1348208Svbart@nginx.com     return;
134951Svbart@nginx.com 
1350208Svbart@nginx.com not_found:
1351208Svbart@nginx.com 
1352208Svbart@nginx.com     resp.status = 404;
1353208Svbart@nginx.com     resp.title = (u_char *) "Value doesn't exist.";
1354208Svbart@nginx.com     resp.offset = -1;
1355208Svbart@nginx.com 
1356208Svbart@nginx.com     nxt_controller_response(task, req, &resp);
1357208Svbart@nginx.com     return;
1358208Svbart@nginx.com 
1359208Svbart@nginx.com invalid_conf:
1360208Svbart@nginx.com 
1361208Svbart@nginx.com     resp.status = 400;
1362208Svbart@nginx.com     resp.title = (u_char *) "Invalid configuration.";
1363208Svbart@nginx.com     resp.offset = -1;
1364208Svbart@nginx.com 
1365208Svbart@nginx.com     nxt_controller_response(task, req, &resp);
1366208Svbart@nginx.com     return;
1367247Svbart@nginx.com 
1368247Svbart@nginx.com alloc_fail:
1369247Svbart@nginx.com 
1370247Svbart@nginx.com     resp.status = 500;
1371247Svbart@nginx.com     resp.title = (u_char *) "Memory allocation failed.";
1372247Svbart@nginx.com     resp.offset = -1;
1373247Svbart@nginx.com 
1374247Svbart@nginx.com     nxt_controller_response(task, req, &resp);
13751470Smax.romanov@nginx.com }
13761470Smax.romanov@nginx.com 
1377247Svbart@nginx.com 
13781470Smax.romanov@nginx.com static nxt_bool_t
13791470Smax.romanov@nginx.com nxt_controller_check_postpone_request(nxt_task_t *task)
13801470Smax.romanov@nginx.com {
13811470Smax.romanov@nginx.com     nxt_port_t     *router_port;
13821470Smax.romanov@nginx.com     nxt_runtime_t  *rt;
1383247Svbart@nginx.com 
13841470Smax.romanov@nginx.com     if (!nxt_queue_is_empty(&nxt_controller_waiting_requests)
13851470Smax.romanov@nginx.com         || nxt_controller_waiting_init_conf
13861470Smax.romanov@nginx.com         || !nxt_controller_router_ready)
13871470Smax.romanov@nginx.com     {
13881470Smax.romanov@nginx.com         return 1;
13891470Smax.romanov@nginx.com     }
1390247Svbart@nginx.com 
13911470Smax.romanov@nginx.com     rt = task->thread->runtime;
13921470Smax.romanov@nginx.com 
13931470Smax.romanov@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
13941470Smax.romanov@nginx.com 
13951470Smax.romanov@nginx.com     return (router_port == NULL);
139627Svbart@nginx.com }
139727Svbart@nginx.com 
139827Svbart@nginx.com 
1399774Svbart@nginx.com #if (NXT_TLS)
1400774Svbart@nginx.com 
1401774Svbart@nginx.com static void
1402774Svbart@nginx.com nxt_controller_process_cert(nxt_task_t *task,
1403774Svbart@nginx.com     nxt_controller_request_t *req, nxt_str_t *path)
1404774Svbart@nginx.com {
1405774Svbart@nginx.com     u_char                     *p;
1406774Svbart@nginx.com     nxt_str_t                  name;
1407774Svbart@nginx.com     nxt_int_t                  ret;
1408774Svbart@nginx.com     nxt_conn_t                 *c;
1409774Svbart@nginx.com     nxt_cert_t                 *cert;
1410774Svbart@nginx.com     nxt_conf_value_t           *value;
1411774Svbart@nginx.com     nxt_controller_response_t  resp;
1412774Svbart@nginx.com 
1413774Svbart@nginx.com     name.length = path->length - 1;
1414774Svbart@nginx.com     name.start = path->start + 1;
1415774Svbart@nginx.com 
1416774Svbart@nginx.com     p = nxt_memchr(name.start, '/', name.length);
1417774Svbart@nginx.com 
1418774Svbart@nginx.com     if (p != NULL) {
1419774Svbart@nginx.com         name.length = p - name.start;
1420774Svbart@nginx.com 
1421774Svbart@nginx.com         path->length -= p - path->start;
1422774Svbart@nginx.com         path->start = p;
1423774Svbart@nginx.com 
1424774Svbart@nginx.com     } else {
1425774Svbart@nginx.com         path = NULL;
1426774Svbart@nginx.com     }
1427774Svbart@nginx.com 
1428774Svbart@nginx.com     nxt_memzero(&resp, sizeof(nxt_controller_response_t));
1429774Svbart@nginx.com 
1430774Svbart@nginx.com     c = req->conn;
1431774Svbart@nginx.com 
1432774Svbart@nginx.com     if (nxt_str_eq(&req->parser.method, "GET", 3)) {
1433774Svbart@nginx.com 
1434774Svbart@nginx.com         if (name.length != 0) {
1435774Svbart@nginx.com             value = nxt_cert_info_get(&name);
1436774Svbart@nginx.com             if (value == NULL) {
1437774Svbart@nginx.com                 goto cert_not_found;
1438774Svbart@nginx.com             }
1439774Svbart@nginx.com 
1440774Svbart@nginx.com             if (path != NULL) {
1441774Svbart@nginx.com                 value = nxt_conf_get_path(value, path);
1442774Svbart@nginx.com                 if (value == NULL) {
1443774Svbart@nginx.com                     goto not_found;
1444774Svbart@nginx.com                 }
1445774Svbart@nginx.com             }
1446774Svbart@nginx.com 
1447774Svbart@nginx.com         } else {
1448774Svbart@nginx.com             value = nxt_cert_info_get_all(c->mem_pool);
1449774Svbart@nginx.com             if (value == NULL) {
1450774Svbart@nginx.com                 goto alloc_fail;
1451774Svbart@nginx.com             }
1452774Svbart@nginx.com         }
1453774Svbart@nginx.com 
1454774Svbart@nginx.com         resp.status = 200;
1455774Svbart@nginx.com         resp.conf = value;
1456774Svbart@nginx.com 
1457774Svbart@nginx.com         nxt_controller_response(task, req, &resp);
1458774Svbart@nginx.com         return;
1459774Svbart@nginx.com     }
1460774Svbart@nginx.com 
1461774Svbart@nginx.com     if (name.length == 0 || path != NULL) {
1462774Svbart@nginx.com         goto invalid_name;
1463774Svbart@nginx.com     }
1464774Svbart@nginx.com 
1465774Svbart@nginx.com     if (nxt_str_eq(&req->parser.method, "PUT", 3)) {
1466774Svbart@nginx.com         value = nxt_cert_info_get(&name);
1467774Svbart@nginx.com         if (value != NULL) {
1468774Svbart@nginx.com             goto exists_cert;
1469774Svbart@nginx.com         }
1470774Svbart@nginx.com 
1471774Svbart@nginx.com         cert = nxt_cert_mem(task, &c->read->mem);
1472774Svbart@nginx.com         if (cert == NULL) {
1473774Svbart@nginx.com             goto invalid_cert;
1474774Svbart@nginx.com         }
1475774Svbart@nginx.com 
1476774Svbart@nginx.com         ret = nxt_cert_info_save(&name, cert);
1477774Svbart@nginx.com 
1478774Svbart@nginx.com         nxt_cert_destroy(cert);
1479774Svbart@nginx.com 
1480774Svbart@nginx.com         if (nxt_slow_path(ret != NXT_OK)) {
1481774Svbart@nginx.com             goto alloc_fail;
1482774Svbart@nginx.com         }
1483774Svbart@nginx.com 
1484774Svbart@nginx.com         nxt_cert_store_get(task, &name, c->mem_pool,
1485774Svbart@nginx.com                            nxt_controller_process_cert_save, req);
1486774Svbart@nginx.com         return;
1487774Svbart@nginx.com     }
1488774Svbart@nginx.com 
1489774Svbart@nginx.com     if (nxt_str_eq(&req->parser.method, "DELETE", 6)) {
1490774Svbart@nginx.com 
1491774Svbart@nginx.com         if (nxt_controller_cert_in_use(&name)) {
1492774Svbart@nginx.com             goto cert_in_use;
1493774Svbart@nginx.com         }
1494774Svbart@nginx.com 
1495774Svbart@nginx.com         if (nxt_cert_info_delete(&name) != NXT_OK) {
1496774Svbart@nginx.com             goto cert_not_found;
1497774Svbart@nginx.com         }
1498774Svbart@nginx.com 
1499774Svbart@nginx.com         nxt_cert_store_delete(task, &name, c->mem_pool);
1500774Svbart@nginx.com 
1501774Svbart@nginx.com         resp.status = 200;
1502774Svbart@nginx.com         resp.title = (u_char *) "Certificate deleted.";
1503774Svbart@nginx.com 
1504774Svbart@nginx.com         nxt_controller_response(task, req, &resp);
1505774Svbart@nginx.com         return;
1506774Svbart@nginx.com     }
1507774Svbart@nginx.com 
1508774Svbart@nginx.com     resp.status = 405;
1509774Svbart@nginx.com     resp.title = (u_char *) "Invalid method.";
1510774Svbart@nginx.com     resp.offset = -1;
1511774Svbart@nginx.com 
1512774Svbart@nginx.com     nxt_controller_response(task, req, &resp);
1513774Svbart@nginx.com     return;
1514774Svbart@nginx.com 
1515774Svbart@nginx.com invalid_name:
1516774Svbart@nginx.com 
1517774Svbart@nginx.com     resp.status = 400;
1518774Svbart@nginx.com     resp.title = (u_char *) "Invalid certificate name.";
1519774Svbart@nginx.com     resp.offset = -1;
1520774Svbart@nginx.com 
1521774Svbart@nginx.com     nxt_controller_response(task, req, &resp);
1522774Svbart@nginx.com     return;
1523774Svbart@nginx.com 
1524774Svbart@nginx.com invalid_cert:
1525774Svbart@nginx.com 
1526774Svbart@nginx.com     resp.status = 400;
1527774Svbart@nginx.com     resp.title = (u_char *) "Invalid certificate.";
1528774Svbart@nginx.com     resp.offset = -1;
1529774Svbart@nginx.com 
1530774Svbart@nginx.com     nxt_controller_response(task, req, &resp);
1531774Svbart@nginx.com     return;
1532774Svbart@nginx.com 
1533774Svbart@nginx.com exists_cert:
1534774Svbart@nginx.com 
1535774Svbart@nginx.com     resp.status = 400;
1536774Svbart@nginx.com     resp.title = (u_char *) "Certificate already exists.";
1537774Svbart@nginx.com     resp.offset = -1;
1538774Svbart@nginx.com 
1539774Svbart@nginx.com     nxt_controller_response(task, req, &resp);
1540774Svbart@nginx.com     return;
1541774Svbart@nginx.com 
1542774Svbart@nginx.com cert_in_use:
1543774Svbart@nginx.com 
1544774Svbart@nginx.com     resp.status = 400;
1545774Svbart@nginx.com     resp.title = (u_char *) "Certificate is used in the configuration.";
1546774Svbart@nginx.com     resp.offset = -1;
1547774Svbart@nginx.com 
1548774Svbart@nginx.com     nxt_controller_response(task, req, &resp);
1549774Svbart@nginx.com     return;
1550774Svbart@nginx.com 
1551774Svbart@nginx.com cert_not_found:
1552774Svbart@nginx.com 
1553774Svbart@nginx.com     resp.status = 404;
1554774Svbart@nginx.com     resp.title = (u_char *) "Certificate doesn't exist.";
1555774Svbart@nginx.com     resp.offset = -1;
1556774Svbart@nginx.com 
1557774Svbart@nginx.com     nxt_controller_response(task, req, &resp);
1558774Svbart@nginx.com     return;
1559774Svbart@nginx.com 
1560774Svbart@nginx.com not_found:
1561774Svbart@nginx.com 
1562774Svbart@nginx.com     resp.status = 404;
1563774Svbart@nginx.com     resp.title = (u_char *) "Invalid path.";
1564774Svbart@nginx.com     resp.offset = -1;
1565774Svbart@nginx.com 
1566774Svbart@nginx.com     nxt_controller_response(task, req, &resp);
1567774Svbart@nginx.com     return;
1568774Svbart@nginx.com 
1569774Svbart@nginx.com alloc_fail:
1570774Svbart@nginx.com 
1571774Svbart@nginx.com     resp.status = 500;
1572774Svbart@nginx.com     resp.title = (u_char *) "Memory allocation failed.";
1573774Svbart@nginx.com     resp.offset = -1;
1574774Svbart@nginx.com 
1575774Svbart@nginx.com     nxt_controller_response(task, req, &resp);
1576774Svbart@nginx.com     return;
1577774Svbart@nginx.com }
1578774Svbart@nginx.com 
1579774Svbart@nginx.com 
1580774Svbart@nginx.com static void
1581774Svbart@nginx.com nxt_controller_process_cert_save(nxt_task_t *task, nxt_port_recv_msg_t *msg,
1582774Svbart@nginx.com     void *data)
1583774Svbart@nginx.com {
1584774Svbart@nginx.com     nxt_conn_t                *c;
1585774Svbart@nginx.com     nxt_buf_mem_t             *mbuf;
1586774Svbart@nginx.com     nxt_controller_request_t  *req;
1587774Svbart@nginx.com     nxt_controller_response_t  resp;
1588774Svbart@nginx.com 
1589774Svbart@nginx.com     req = data;
1590774Svbart@nginx.com 
1591774Svbart@nginx.com     nxt_memzero(&resp, sizeof(nxt_controller_response_t));
1592774Svbart@nginx.com 
1593774Svbart@nginx.com     if (msg == NULL || msg->port_msg.type == _NXT_PORT_MSG_RPC_ERROR) {
1594774Svbart@nginx.com         resp.status = 500;
1595774Svbart@nginx.com         resp.title = (u_char *) "Failed to store certificate.";
1596774Svbart@nginx.com 
1597774Svbart@nginx.com         nxt_controller_response(task, req, &resp);
1598774Svbart@nginx.com         return;
1599774Svbart@nginx.com     }
1600774Svbart@nginx.com 
1601774Svbart@nginx.com     c = req->conn;
1602774Svbart@nginx.com 
1603774Svbart@nginx.com     mbuf = &c->read->mem;
1604774Svbart@nginx.com 
16051558Smax.romanov@nginx.com     nxt_fd_write(msg->fd[0], mbuf->pos, nxt_buf_mem_used_size(mbuf));
16061558Smax.romanov@nginx.com 
16071558Smax.romanov@nginx.com     nxt_fd_close(msg->fd[0]);
1608774Svbart@nginx.com 
1609774Svbart@nginx.com     nxt_memzero(&resp, sizeof(nxt_controller_response_t));
1610774Svbart@nginx.com 
1611774Svbart@nginx.com     resp.status = 200;
1612774Svbart@nginx.com     resp.title = (u_char *) "Certificate chain uploaded.";
1613774Svbart@nginx.com 
1614774Svbart@nginx.com     nxt_controller_response(task, req, &resp);
1615774Svbart@nginx.com }
1616774Svbart@nginx.com 
1617774Svbart@nginx.com 
1618774Svbart@nginx.com static nxt_bool_t
1619774Svbart@nginx.com nxt_controller_cert_in_use(nxt_str_t *name)
1620774Svbart@nginx.com {
1621774Svbart@nginx.com     uint32_t          next;
1622774Svbart@nginx.com     nxt_str_t         str;
1623774Svbart@nginx.com     nxt_conf_value_t  *listeners, *listener, *value;
1624774Svbart@nginx.com 
1625774Svbart@nginx.com     static nxt_str_t  listeners_path = nxt_string("/listeners");
1626774Svbart@nginx.com     static nxt_str_t  certificate_path = nxt_string("/tls/certificate");
1627774Svbart@nginx.com 
1628774Svbart@nginx.com     listeners = nxt_conf_get_path(nxt_controller_conf.root, &listeners_path);
1629774Svbart@nginx.com 
1630774Svbart@nginx.com     if (listeners != NULL) {
1631774Svbart@nginx.com         next = 0;
1632774Svbart@nginx.com 
1633774Svbart@nginx.com         for ( ;; ) {
1634774Svbart@nginx.com             listener = nxt_conf_next_object_member(listeners, &str, &next);
1635774Svbart@nginx.com             if (listener == NULL) {
1636774Svbart@nginx.com                 break;
1637774Svbart@nginx.com             }
1638774Svbart@nginx.com 
1639774Svbart@nginx.com             value = nxt_conf_get_path(listener, &certificate_path);
1640774Svbart@nginx.com             if (value == NULL) {
1641774Svbart@nginx.com                 continue;
1642774Svbart@nginx.com             }
1643774Svbart@nginx.com 
1644774Svbart@nginx.com             nxt_conf_get_string(value, &str);
1645774Svbart@nginx.com 
1646774Svbart@nginx.com             if (nxt_strstr_eq(&str, name)) {
1647774Svbart@nginx.com                 return 1;
1648774Svbart@nginx.com             }
1649774Svbart@nginx.com         }
1650774Svbart@nginx.com     }
1651774Svbart@nginx.com 
1652774Svbart@nginx.com     return 0;
1653774Svbart@nginx.com }
1654774Svbart@nginx.com 
1655774Svbart@nginx.com #endif
1656774Svbart@nginx.com 
1657774Svbart@nginx.com 
1658193Smax.romanov@nginx.com static void
1659193Smax.romanov@nginx.com nxt_controller_conf_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
1660193Smax.romanov@nginx.com     void *data)
1661140Svbart@nginx.com {
1662140Svbart@nginx.com     nxt_controller_request_t   *req;
1663140Svbart@nginx.com     nxt_controller_response_t  resp;
1664140Svbart@nginx.com 
1665238Svbart@nginx.com     req = data;
1666238Svbart@nginx.com 
1667201Svbart@nginx.com     nxt_debug(task, "controller conf ready: %*s",
1668201Svbart@nginx.com               nxt_buf_mem_used_size(&msg->buf->mem), msg->buf->mem.pos);
1669140Svbart@nginx.com 
1670238Svbart@nginx.com     nxt_queue_remove(&req->link);
1671140Svbart@nginx.com 
1672238Svbart@nginx.com     nxt_memzero(&resp, sizeof(nxt_controller_response_t));
1673140Svbart@nginx.com 
1674193Smax.romanov@nginx.com     if (msg->port_msg.type == NXT_PORT_MSG_RPC_READY) {
1675140Svbart@nginx.com         nxt_mp_destroy(nxt_controller_conf.pool);
1676140Svbart@nginx.com 
1677140Svbart@nginx.com         nxt_controller_conf = req->conf;
1678140Svbart@nginx.com 
1679314Svbart@nginx.com         nxt_controller_conf_store(task, req->conf.root);
1680314Svbart@nginx.com 
1681208Svbart@nginx.com         resp.status = 200;
1682208Svbart@nginx.com         resp.title = (u_char *) "Reconfiguration done.";
1683140Svbart@nginx.com 
1684140Svbart@nginx.com     } else {
1685140Svbart@nginx.com         nxt_mp_destroy(req->conf.pool);
1686140Svbart@nginx.com 
1687208Svbart@nginx.com         resp.status = 500;
1688208Svbart@nginx.com         resp.title = (u_char *) "Failed to apply new configuration.";
1689208Svbart@nginx.com         resp.offset = -1;
1690140Svbart@nginx.com     }
1691140Svbart@nginx.com 
1692140Svbart@nginx.com     nxt_controller_response(task, req, &resp);
1693140Svbart@nginx.com 
16941469Smax.romanov@nginx.com     nxt_controller_flush_requests(task);
1695121Svbart@nginx.com }
1696121Svbart@nginx.com 
1697121Svbart@nginx.com 
1698140Svbart@nginx.com static void
1699*1926Smax.romanov@nginx.com nxt_controller_process_control(nxt_task_t *task,
1700*1926Smax.romanov@nginx.com     nxt_controller_request_t *req, nxt_str_t *path)
1701*1926Smax.romanov@nginx.com {
1702*1926Smax.romanov@nginx.com     uint32_t                   stream;
1703*1926Smax.romanov@nginx.com     nxt_buf_t                  *b;
1704*1926Smax.romanov@nginx.com     nxt_int_t                  rc;
1705*1926Smax.romanov@nginx.com     nxt_port_t                 *router_port, *controller_port;
1706*1926Smax.romanov@nginx.com     nxt_runtime_t              *rt;
1707*1926Smax.romanov@nginx.com     nxt_conf_value_t           *value;
1708*1926Smax.romanov@nginx.com     nxt_controller_response_t  resp;
1709*1926Smax.romanov@nginx.com 
1710*1926Smax.romanov@nginx.com     static nxt_str_t applications = nxt_string("applications");
1711*1926Smax.romanov@nginx.com 
1712*1926Smax.romanov@nginx.com     nxt_memzero(&resp, sizeof(nxt_controller_response_t));
1713*1926Smax.romanov@nginx.com 
1714*1926Smax.romanov@nginx.com     if (!nxt_str_eq(&req->parser.method, "GET", 3)) {
1715*1926Smax.romanov@nginx.com         goto not_allowed;
1716*1926Smax.romanov@nginx.com     }
1717*1926Smax.romanov@nginx.com 
1718*1926Smax.romanov@nginx.com     if (!nxt_str_start(path, "applications/", 13)
1719*1926Smax.romanov@nginx.com         || nxt_memcmp(path->start + path->length - 8, "/restart", 8) != 0)
1720*1926Smax.romanov@nginx.com     {
1721*1926Smax.romanov@nginx.com         goto not_found;
1722*1926Smax.romanov@nginx.com     }
1723*1926Smax.romanov@nginx.com 
1724*1926Smax.romanov@nginx.com     path->start += 13;
1725*1926Smax.romanov@nginx.com     path->length -= 13 + 8;
1726*1926Smax.romanov@nginx.com 
1727*1926Smax.romanov@nginx.com     if (nxt_controller_check_postpone_request(task)) {
1728*1926Smax.romanov@nginx.com         nxt_queue_insert_tail(&nxt_controller_waiting_requests, &req->link);
1729*1926Smax.romanov@nginx.com         return;
1730*1926Smax.romanov@nginx.com     }
1731*1926Smax.romanov@nginx.com 
1732*1926Smax.romanov@nginx.com     value = nxt_controller_conf.root;
1733*1926Smax.romanov@nginx.com     if (value == NULL) {
1734*1926Smax.romanov@nginx.com         goto not_found;
1735*1926Smax.romanov@nginx.com     }
1736*1926Smax.romanov@nginx.com 
1737*1926Smax.romanov@nginx.com     value = nxt_conf_get_object_member(value, &applications, NULL);
1738*1926Smax.romanov@nginx.com     if (value == NULL) {
1739*1926Smax.romanov@nginx.com         goto not_found;
1740*1926Smax.romanov@nginx.com     }
1741*1926Smax.romanov@nginx.com 
1742*1926Smax.romanov@nginx.com     value = nxt_conf_get_object_member(value, path, NULL);
1743*1926Smax.romanov@nginx.com     if (value == NULL) {
1744*1926Smax.romanov@nginx.com         goto not_found;
1745*1926Smax.romanov@nginx.com     }
1746*1926Smax.romanov@nginx.com 
1747*1926Smax.romanov@nginx.com     b = nxt_buf_mem_alloc(req->conn->mem_pool, path->length, 0);
1748*1926Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
1749*1926Smax.romanov@nginx.com         goto alloc_fail;
1750*1926Smax.romanov@nginx.com     }
1751*1926Smax.romanov@nginx.com 
1752*1926Smax.romanov@nginx.com     b->mem.free = nxt_cpymem(b->mem.pos, path->start, path->length);
1753*1926Smax.romanov@nginx.com 
1754*1926Smax.romanov@nginx.com     rt = task->thread->runtime;
1755*1926Smax.romanov@nginx.com 
1756*1926Smax.romanov@nginx.com     controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER];
1757*1926Smax.romanov@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
1758*1926Smax.romanov@nginx.com 
1759*1926Smax.romanov@nginx.com     stream = nxt_port_rpc_register_handler(task, controller_port,
1760*1926Smax.romanov@nginx.com                                            nxt_controller_app_restart_handler,
1761*1926Smax.romanov@nginx.com                                            nxt_controller_app_restart_handler,
1762*1926Smax.romanov@nginx.com                                            router_port->pid, req);
1763*1926Smax.romanov@nginx.com     if (nxt_slow_path(stream == 0)) {
1764*1926Smax.romanov@nginx.com         goto alloc_fail;
1765*1926Smax.romanov@nginx.com     }
1766*1926Smax.romanov@nginx.com 
1767*1926Smax.romanov@nginx.com     rc = nxt_port_socket_write(task, router_port, NXT_PORT_MSG_APP_RESTART,
1768*1926Smax.romanov@nginx.com                                -1, stream, 0, b);
1769*1926Smax.romanov@nginx.com     if (nxt_slow_path(rc != NXT_OK)) {
1770*1926Smax.romanov@nginx.com         nxt_port_rpc_cancel(task, controller_port, stream);
1771*1926Smax.romanov@nginx.com 
1772*1926Smax.romanov@nginx.com         goto fail;
1773*1926Smax.romanov@nginx.com     }
1774*1926Smax.romanov@nginx.com 
1775*1926Smax.romanov@nginx.com     nxt_queue_insert_head(&nxt_controller_waiting_requests, &req->link);
1776*1926Smax.romanov@nginx.com 
1777*1926Smax.romanov@nginx.com     return;
1778*1926Smax.romanov@nginx.com 
1779*1926Smax.romanov@nginx.com not_allowed:
1780*1926Smax.romanov@nginx.com 
1781*1926Smax.romanov@nginx.com     resp.status = 405;
1782*1926Smax.romanov@nginx.com     resp.title = (u_char *) "Method isn't allowed.";
1783*1926Smax.romanov@nginx.com     resp.offset = -1;
1784*1926Smax.romanov@nginx.com 
1785*1926Smax.romanov@nginx.com     nxt_controller_response(task, req, &resp);
1786*1926Smax.romanov@nginx.com     return;
1787*1926Smax.romanov@nginx.com 
1788*1926Smax.romanov@nginx.com not_found:
1789*1926Smax.romanov@nginx.com 
1790*1926Smax.romanov@nginx.com     resp.status = 404;
1791*1926Smax.romanov@nginx.com     resp.title = (u_char *) "Value doesn't exist.";
1792*1926Smax.romanov@nginx.com     resp.offset = -1;
1793*1926Smax.romanov@nginx.com 
1794*1926Smax.romanov@nginx.com     nxt_controller_response(task, req, &resp);
1795*1926Smax.romanov@nginx.com     return;
1796*1926Smax.romanov@nginx.com 
1797*1926Smax.romanov@nginx.com alloc_fail:
1798*1926Smax.romanov@nginx.com 
1799*1926Smax.romanov@nginx.com     resp.status = 500;
1800*1926Smax.romanov@nginx.com     resp.title = (u_char *) "Memory allocation failed.";
1801*1926Smax.romanov@nginx.com     resp.offset = -1;
1802*1926Smax.romanov@nginx.com 
1803*1926Smax.romanov@nginx.com     nxt_controller_response(task, req, &resp);
1804*1926Smax.romanov@nginx.com     return;
1805*1926Smax.romanov@nginx.com 
1806*1926Smax.romanov@nginx.com fail:
1807*1926Smax.romanov@nginx.com 
1808*1926Smax.romanov@nginx.com     resp.status = 500;
1809*1926Smax.romanov@nginx.com     resp.title = (u_char *) "Send restart failed.";
1810*1926Smax.romanov@nginx.com     resp.offset = -1;
1811*1926Smax.romanov@nginx.com 
1812*1926Smax.romanov@nginx.com     nxt_controller_response(task, req, &resp);
1813*1926Smax.romanov@nginx.com }
1814*1926Smax.romanov@nginx.com 
1815*1926Smax.romanov@nginx.com 
1816*1926Smax.romanov@nginx.com static void
1817*1926Smax.romanov@nginx.com nxt_controller_app_restart_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
1818*1926Smax.romanov@nginx.com     void *data)
1819*1926Smax.romanov@nginx.com {
1820*1926Smax.romanov@nginx.com     nxt_controller_request_t   *req;
1821*1926Smax.romanov@nginx.com     nxt_controller_response_t  resp;
1822*1926Smax.romanov@nginx.com 
1823*1926Smax.romanov@nginx.com     req = data;
1824*1926Smax.romanov@nginx.com 
1825*1926Smax.romanov@nginx.com     nxt_debug(task, "controller app restart handler");
1826*1926Smax.romanov@nginx.com 
1827*1926Smax.romanov@nginx.com     nxt_queue_remove(&req->link);
1828*1926Smax.romanov@nginx.com 
1829*1926Smax.romanov@nginx.com     nxt_memzero(&resp, sizeof(nxt_controller_response_t));
1830*1926Smax.romanov@nginx.com 
1831*1926Smax.romanov@nginx.com     if (msg->port_msg.type == NXT_PORT_MSG_RPC_READY) {
1832*1926Smax.romanov@nginx.com         resp.status = 200;
1833*1926Smax.romanov@nginx.com         resp.title = (u_char *) "Ok";
1834*1926Smax.romanov@nginx.com 
1835*1926Smax.romanov@nginx.com     } else {
1836*1926Smax.romanov@nginx.com         resp.status = 500;
1837*1926Smax.romanov@nginx.com         resp.title = (u_char *) "Failed to restart app.";
1838*1926Smax.romanov@nginx.com         resp.offset = -1;
1839*1926Smax.romanov@nginx.com     }
1840*1926Smax.romanov@nginx.com 
1841*1926Smax.romanov@nginx.com     nxt_controller_response(task, req, &resp);
1842*1926Smax.romanov@nginx.com 
1843*1926Smax.romanov@nginx.com     nxt_controller_flush_requests(task);
1844*1926Smax.romanov@nginx.com }
1845*1926Smax.romanov@nginx.com 
1846*1926Smax.romanov@nginx.com 
1847*1926Smax.romanov@nginx.com static void
1848314Svbart@nginx.com nxt_controller_conf_store(nxt_task_t *task, nxt_conf_value_t *conf)
1849314Svbart@nginx.com {
18501787Smax.romanov@nginx.com     void           *mem;
18511787Smax.romanov@nginx.com     u_char         *end;
1852314Svbart@nginx.com     size_t         size;
18531787Smax.romanov@nginx.com     nxt_fd_t       fd;
1854314Svbart@nginx.com     nxt_buf_t      *b;
1855314Svbart@nginx.com     nxt_port_t     *main_port;
1856314Svbart@nginx.com     nxt_runtime_t  *rt;
1857314Svbart@nginx.com 
1858314Svbart@nginx.com     rt = task->thread->runtime;
1859314Svbart@nginx.com 
1860314Svbart@nginx.com     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
1861314Svbart@nginx.com 
1862314Svbart@nginx.com     size = nxt_conf_json_length(conf, NULL);
1863314Svbart@nginx.com 
18641787Smax.romanov@nginx.com     fd = nxt_shm_open(task, size);
18651787Smax.romanov@nginx.com     if (nxt_slow_path(fd == -1)) {
18661787Smax.romanov@nginx.com         return;
18671787Smax.romanov@nginx.com     }
18681787Smax.romanov@nginx.com 
18691787Smax.romanov@nginx.com     mem = nxt_mem_mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
18701787Smax.romanov@nginx.com     if (nxt_slow_path(mem == MAP_FAILED)) {
18711787Smax.romanov@nginx.com         goto fail;
1872314Svbart@nginx.com     }
18731787Smax.romanov@nginx.com 
18741787Smax.romanov@nginx.com     end = nxt_conf_json_print(mem, conf, NULL);
18751787Smax.romanov@nginx.com 
18761787Smax.romanov@nginx.com     nxt_mem_munmap(mem, size);
18771787Smax.romanov@nginx.com 
18781787Smax.romanov@nginx.com     size = end - (u_char *) mem;
18791787Smax.romanov@nginx.com 
18801787Smax.romanov@nginx.com     b = nxt_buf_mem_alloc(task->thread->engine->mem_pool, sizeof(size_t), 0);
18811787Smax.romanov@nginx.com     if (nxt_slow_path(b == NULL)) {
18821787Smax.romanov@nginx.com         goto fail;
18831787Smax.romanov@nginx.com     }
18841787Smax.romanov@nginx.com 
18851787Smax.romanov@nginx.com     b->mem.free = nxt_cpymem(b->mem.pos, &size, sizeof(size_t));
18861787Smax.romanov@nginx.com 
18871787Smax.romanov@nginx.com     (void) nxt_port_socket_write(task, main_port,
18881787Smax.romanov@nginx.com                                 NXT_PORT_MSG_CONF_STORE | NXT_PORT_MSG_CLOSE_FD,
18891787Smax.romanov@nginx.com                                  fd, 0, -1, b);
18901787Smax.romanov@nginx.com 
18911787Smax.romanov@nginx.com     return;
18921787Smax.romanov@nginx.com 
18931787Smax.romanov@nginx.com fail:
18941787Smax.romanov@nginx.com 
18951787Smax.romanov@nginx.com     nxt_fd_close(fd);
1896314Svbart@nginx.com }
1897314Svbart@nginx.com 
1898314Svbart@nginx.com 
1899314Svbart@nginx.com static void
1900140Svbart@nginx.com nxt_controller_response(nxt_task_t *task, nxt_controller_request_t *req,
190144Svbart@nginx.com     nxt_controller_response_t *resp)
190233Svbart@nginx.com {
1903208Svbart@nginx.com     size_t                  size;
1904208Svbart@nginx.com     nxt_str_t               status_line, str;
1905208Svbart@nginx.com     nxt_buf_t               *b, *body;
1906208Svbart@nginx.com     nxt_conn_t              *c;
1907208Svbart@nginx.com     nxt_uint_t              n;
1908208Svbart@nginx.com     nxt_conf_value_t        *value, *location;
1909208Svbart@nginx.com     nxt_conf_json_pretty_t  pretty;
1910208Svbart@nginx.com 
1911208Svbart@nginx.com     static nxt_str_t  success_str = nxt_string("success");
1912208Svbart@nginx.com     static nxt_str_t  error_str = nxt_string("error");
1913208Svbart@nginx.com     static nxt_str_t  detail_str = nxt_string("detail");
1914208Svbart@nginx.com     static nxt_str_t  location_str = nxt_string("location");
1915208Svbart@nginx.com     static nxt_str_t  offset_str = nxt_string("offset");
1916208Svbart@nginx.com     static nxt_str_t  line_str = nxt_string("line");
1917208Svbart@nginx.com     static nxt_str_t  column_str = nxt_string("column");
1918208Svbart@nginx.com 
1919208Svbart@nginx.com     static nxt_time_string_t  date_cache = {
1920208Svbart@nginx.com         (nxt_atomic_uint_t) -1,
1921208Svbart@nginx.com         nxt_controller_date,
1922208Svbart@nginx.com         "%s, %02d %s %4d %02d:%02d:%02d GMT",
1923703Svbart@nginx.com         nxt_length("Wed, 31 Dec 1986 16:40:00 GMT"),
1924208Svbart@nginx.com         NXT_THREAD_TIME_GMT,
1925208Svbart@nginx.com         NXT_THREAD_TIME_SEC,
1926208Svbart@nginx.com     };
1927208Svbart@nginx.com 
1928208Svbart@nginx.com     switch (resp->status) {
1929208Svbart@nginx.com 
1930208Svbart@nginx.com     case 200:
1931208Svbart@nginx.com         nxt_str_set(&status_line, "200 OK");
1932208Svbart@nginx.com         break;
1933208Svbart@nginx.com 
1934208Svbart@nginx.com     case 400:
1935208Svbart@nginx.com         nxt_str_set(&status_line, "400 Bad Request");
1936208Svbart@nginx.com         break;
1937208Svbart@nginx.com 
1938208Svbart@nginx.com     case 404:
1939208Svbart@nginx.com         nxt_str_set(&status_line, "404 Not Found");
1940208Svbart@nginx.com         break;
1941208Svbart@nginx.com 
1942208Svbart@nginx.com     case 405:
1943208Svbart@nginx.com         nxt_str_set(&status_line, "405 Method Not Allowed");
1944208Svbart@nginx.com         break;
1945208Svbart@nginx.com 
1946209Svbart@nginx.com     default:
1947208Svbart@nginx.com         nxt_str_set(&status_line, "500 Internal Server Error");
1948208Svbart@nginx.com         break;
1949208Svbart@nginx.com     }
1950140Svbart@nginx.com 
1951140Svbart@nginx.com     c = req->conn;
1952208Svbart@nginx.com     value = resp->conf;
195333Svbart@nginx.com 
1954208Svbart@nginx.com     if (value == NULL) {
1955208Svbart@nginx.com         n = 1
1956357Svbart@nginx.com             + (resp->detail.length != 0)
1957208Svbart@nginx.com             + (resp->status >= 400 && resp->offset != -1);
1958208Svbart@nginx.com 
1959208Svbart@nginx.com         value = nxt_conf_create_object(c->mem_pool, n);
1960208Svbart@nginx.com 
1961208Svbart@nginx.com         if (nxt_slow_path(value == NULL)) {
1962208Svbart@nginx.com             nxt_controller_conn_close(task, c, req);
1963208Svbart@nginx.com             return;
1964208Svbart@nginx.com         }
1965208Svbart@nginx.com 
1966208Svbart@nginx.com         str.length = nxt_strlen(resp->title);
1967208Svbart@nginx.com         str.start = resp->title;
1968208Svbart@nginx.com 
1969208Svbart@nginx.com         if (resp->status < 400) {
1970208Svbart@nginx.com             nxt_conf_set_member_string(value, &success_str, &str, 0);
1971208Svbart@nginx.com 
1972208Svbart@nginx.com         } else {
1973208Svbart@nginx.com             nxt_conf_set_member_string(value, &error_str, &str, 0);
1974208Svbart@nginx.com         }
1975208Svbart@nginx.com 
1976208Svbart@nginx.com         n = 0;
1977208Svbart@nginx.com 
1978357Svbart@nginx.com         if (resp->detail.length != 0) {
1979208Svbart@nginx.com             n++;
1980208Svbart@nginx.com 
1981357Svbart@nginx.com             nxt_conf_set_member_string(value, &detail_str, &resp->detail, n);
1982208Svbart@nginx.com         }
1983208Svbart@nginx.com 
1984208Svbart@nginx.com         if (resp->status >= 400 && resp->offset != -1) {
1985208Svbart@nginx.com             n++;
1986208Svbart@nginx.com 
1987208Svbart@nginx.com             location = nxt_conf_create_object(c->mem_pool,
1988208Svbart@nginx.com                                               resp->line != 0 ? 3 : 1);
1989208Svbart@nginx.com 
1990208Svbart@nginx.com             nxt_conf_set_member(value, &location_str, location, n);
1991208Svbart@nginx.com 
1992208Svbart@nginx.com             nxt_conf_set_member_integer(location, &offset_str, resp->offset, 0);
1993208Svbart@nginx.com 
1994208Svbart@nginx.com             if (resp->line != 0) {
1995208Svbart@nginx.com                 nxt_conf_set_member_integer(location, &line_str,
1996208Svbart@nginx.com                                             resp->line, 1);
1997208Svbart@nginx.com 
1998208Svbart@nginx.com                 nxt_conf_set_member_integer(location, &column_str,
1999208Svbart@nginx.com                                             resp->column, 2);
2000208Svbart@nginx.com             }
2001208Svbart@nginx.com         }
2002208Svbart@nginx.com     }
2003208Svbart@nginx.com 
2004208Svbart@nginx.com     nxt_memzero(&pretty, sizeof(nxt_conf_json_pretty_t));
2005208Svbart@nginx.com 
2006208Svbart@nginx.com     size = nxt_conf_json_length(value, &pretty) + 2;
2007208Svbart@nginx.com 
2008208Svbart@nginx.com     body = nxt_buf_mem_alloc(c->mem_pool, size, 0);
2009208Svbart@nginx.com     if (nxt_slow_path(body == NULL)) {
2010208Svbart@nginx.com         nxt_controller_conn_close(task, c, req);
2011208Svbart@nginx.com         return;
2012208Svbart@nginx.com     }
2013208Svbart@nginx.com 
2014208Svbart@nginx.com     nxt_memzero(&pretty, sizeof(nxt_conf_json_pretty_t));
2015208Svbart@nginx.com 
2016208Svbart@nginx.com     body->mem.free = nxt_conf_json_print(body->mem.free, value, &pretty);
2017208Svbart@nginx.com 
2018208Svbart@nginx.com     body->mem.free = nxt_cpymem(body->mem.free, "\r\n", 2);
2019208Svbart@nginx.com 
2020703Svbart@nginx.com     size = nxt_length("HTTP/1.1 " "\r\n") + status_line.length
2021703Svbart@nginx.com            + nxt_length("Server: " NXT_SERVER "\r\n")
2022703Svbart@nginx.com            + nxt_length("Date: Wed, 31 Dec 1986 16:40:00 GMT\r\n")
2023703Svbart@nginx.com            + nxt_length("Content-Type: application/json\r\n")
2024703Svbart@nginx.com            + nxt_length("Content-Length: " "\r\n") + NXT_SIZE_T_LEN
2025703Svbart@nginx.com            + nxt_length("Connection: close\r\n")
2026703Svbart@nginx.com            + nxt_length("\r\n");
202733Svbart@nginx.com 
202844Svbart@nginx.com     b = nxt_buf_mem_alloc(c->mem_pool, size, 0);
202933Svbart@nginx.com     if (nxt_slow_path(b == NULL)) {
2030140Svbart@nginx.com         nxt_controller_conn_close(task, c, req);
2031140Svbart@nginx.com         return;
203233Svbart@nginx.com     }
203333Svbart@nginx.com 
2034208Svbart@nginx.com     b->next = body;
2035208Svbart@nginx.com 
2036208Svbart@nginx.com     nxt_str_set(&str, "HTTP/1.1 ");
203744Svbart@nginx.com 
2038208Svbart@nginx.com     b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length);
2039208Svbart@nginx.com     b->mem.free = nxt_cpymem(b->mem.free, status_line.start,
2040208Svbart@nginx.com                              status_line.length);
2041208Svbart@nginx.com 
2042208Svbart@nginx.com     nxt_str_set(&str, "\r\n"
2043673Svbart@nginx.com                       "Server: " NXT_SERVER "\r\n"
2044208Svbart@nginx.com                       "Date: ");
2045208Svbart@nginx.com 
2046208Svbart@nginx.com     b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length);
204744Svbart@nginx.com 
2048208Svbart@nginx.com     b->mem.free = nxt_thread_time_string(task->thread, &date_cache,
2049208Svbart@nginx.com                                          b->mem.free);
2050208Svbart@nginx.com 
2051208Svbart@nginx.com     nxt_str_set(&str, "\r\n"
2052208Svbart@nginx.com                       "Content-Type: application/json\r\n"
2053208Svbart@nginx.com                       "Content-Length: ");
2054208Svbart@nginx.com 
2055208Svbart@nginx.com     b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length);
205645Svbart@nginx.com 
2057208Svbart@nginx.com     b->mem.free = nxt_sprintf(b->mem.free, b->mem.end, "%uz",
2058208Svbart@nginx.com                               nxt_buf_mem_used_size(&body->mem));
2059208Svbart@nginx.com 
2060208Svbart@nginx.com     nxt_str_set(&str, "\r\n"
2061208Svbart@nginx.com                       "Connection: close\r\n"
2062208Svbart@nginx.com                       "\r\n");
2063208Svbart@nginx.com 
2064208Svbart@nginx.com     b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length);
206533Svbart@nginx.com 
206633Svbart@nginx.com     c->write = b;
206744Svbart@nginx.com     c->write_state = &nxt_controller_conn_write_state;
206833Svbart@nginx.com 
206962Sigor@sysoev.ru     nxt_conn_write(task->thread->engine, c);
207033Svbart@nginx.com }
207145Svbart@nginx.com 
207245Svbart@nginx.com 
2073208Svbart@nginx.com static u_char *
2074208Svbart@nginx.com nxt_controller_date(u_char *buf, nxt_realtime_t *now, struct tm *tm,
2075208Svbart@nginx.com     size_t size, const char *format)
207645Svbart@nginx.com {
2077208Svbart@nginx.com     static const char  *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri",
2078208Svbart@nginx.com                                    "Sat" };
207945Svbart@nginx.com 
2080208Svbart@nginx.com     static const char  *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
2081208Svbart@nginx.com                                     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
208245Svbart@nginx.com 
2083208Svbart@nginx.com     return nxt_sprintf(buf, buf + size, format,
2084208Svbart@nginx.com                        week[tm->tm_wday], tm->tm_mday,
2085208Svbart@nginx.com                        month[tm->tm_mon], tm->tm_year + 1900,
2086208Svbart@nginx.com                        tm->tm_hour, tm->tm_min, tm->tm_sec);
208745Svbart@nginx.com }
2088