xref: /unit/src/nxt_controller.c (revision 2207:c69f96ca4d5e)
1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) Valentin V. Bartenev
5  * Copyright (C) NGINX, Inc.
6  */
7 
8 #include <nxt_main.h>
9 #include <nxt_runtime.h>
10 #include <nxt_main_process.h>
11 #include <nxt_conf.h>
12 #include <nxt_status.h>
13 #include <nxt_cert.h>
14 
15 
16 typedef struct {
17     nxt_conf_value_t  *root;
18     nxt_mp_t          *pool;
19 } nxt_controller_conf_t;
20 
21 
22 typedef struct {
23     nxt_http_request_parse_t  parser;
24     size_t                    length;
25     nxt_controller_conf_t     conf;
26     nxt_conn_t                *conn;
27     nxt_queue_link_t          link;
28 } nxt_controller_request_t;
29 
30 
31 typedef struct {
32     nxt_uint_t        status;
33     nxt_conf_value_t  *conf;
34 
35     u_char            *title;
36     nxt_str_t         detail;
37     ssize_t           offset;
38     nxt_uint_t        line;
39     nxt_uint_t        column;
40 } nxt_controller_response_t;
41 
42 
43 static nxt_int_t nxt_controller_prefork(nxt_task_t *task,
44     nxt_process_t *process, nxt_mp_t *mp);
45 static nxt_int_t nxt_controller_file_read(nxt_task_t *task, const char *name,
46     nxt_str_t *str, nxt_mp_t *mp);
47 static nxt_int_t nxt_controller_start(nxt_task_t *task,
48     nxt_process_data_t *data);
49 static void nxt_controller_process_new_port_handler(nxt_task_t *task,
50     nxt_port_recv_msg_t *msg);
51 static void nxt_controller_send_current_conf(nxt_task_t *task);
52 static void nxt_controller_router_ready_handler(nxt_task_t *task,
53     nxt_port_recv_msg_t *msg);
54 static void nxt_controller_remove_pid_handler(nxt_task_t *task,
55     nxt_port_recv_msg_t *msg);
56 static nxt_int_t nxt_controller_conf_default(void);
57 static void nxt_controller_conf_init_handler(nxt_task_t *task,
58     nxt_port_recv_msg_t *msg, void *data);
59 static void nxt_controller_flush_requests(nxt_task_t *task);
60 static nxt_int_t nxt_controller_conf_send(nxt_task_t *task, nxt_mp_t *mp,
61     nxt_conf_value_t *conf, nxt_port_rpc_handler_t handler, void *data);
62 
63 static void nxt_controller_conn_init(nxt_task_t *task, void *obj, void *data);
64 static void nxt_controller_conn_read(nxt_task_t *task, void *obj, void *data);
65 static nxt_msec_t nxt_controller_conn_timeout_value(nxt_conn_t *c,
66     uintptr_t data);
67 static void nxt_controller_conn_read_error(nxt_task_t *task, void *obj,
68     void *data);
69 static void nxt_controller_conn_read_timeout(nxt_task_t *task, void *obj,
70     void *data);
71 static void nxt_controller_conn_body_read(nxt_task_t *task, void *obj,
72     void *data);
73 static void nxt_controller_conn_write(nxt_task_t *task, void *obj, void *data);
74 static void nxt_controller_conn_write_error(nxt_task_t *task, void *obj,
75     void *data);
76 static void nxt_controller_conn_write_timeout(nxt_task_t *task, void *obj,
77     void *data);
78 static void nxt_controller_conn_close(nxt_task_t *task, void *obj, void *data);
79 static void nxt_controller_conn_free(nxt_task_t *task, void *obj, void *data);
80 
81 static nxt_int_t nxt_controller_request_content_length(void *ctx,
82     nxt_http_field_t *field, uintptr_t data);
83 
84 static void nxt_controller_process_request(nxt_task_t *task,
85     nxt_controller_request_t *req);
86 static void nxt_controller_process_config(nxt_task_t *task,
87     nxt_controller_request_t *req, nxt_str_t *path);
88 static nxt_bool_t nxt_controller_check_postpone_request(nxt_task_t *task);
89 static void nxt_controller_process_status(nxt_task_t *task,
90     nxt_controller_request_t *req);
91 static void nxt_controller_status_handler(nxt_task_t *task,
92     nxt_port_recv_msg_t *msg, void *data);
93 static void nxt_controller_status_response(nxt_task_t *task,
94     nxt_controller_request_t *req, nxt_str_t *path);
95 #if (NXT_TLS)
96 static void nxt_controller_process_cert(nxt_task_t *task,
97     nxt_controller_request_t *req, nxt_str_t *path);
98 static void nxt_controller_process_cert_save(nxt_task_t *task,
99     nxt_port_recv_msg_t *msg, void *data);
100 static nxt_bool_t nxt_controller_cert_in_use(nxt_str_t *name);
101 static void nxt_controller_cert_cleanup(nxt_task_t *task, void *obj,
102     void *data);
103 #endif
104 static void nxt_controller_process_control(nxt_task_t *task,
105     nxt_controller_request_t *req, nxt_str_t *path);
106 static void nxt_controller_app_restart_handler(nxt_task_t *task,
107     nxt_port_recv_msg_t *msg, void *data);
108 static void nxt_controller_conf_handler(nxt_task_t *task,
109     nxt_port_recv_msg_t *msg, void *data);
110 static void nxt_controller_conf_store(nxt_task_t *task,
111     nxt_conf_value_t *conf);
112 static void nxt_controller_response(nxt_task_t *task,
113     nxt_controller_request_t *req, nxt_controller_response_t *resp);
114 static u_char *nxt_controller_date(u_char *buf, nxt_realtime_t *now,
115     struct tm *tm, size_t size, const char *format);
116 
117 
118 static nxt_http_field_proc_t  nxt_controller_request_fields[] = {
119     { nxt_string("Content-Length"),
120       &nxt_controller_request_content_length, 0 },
121 };
122 
123 static nxt_lvlhsh_t            nxt_controller_fields_hash;
124 
125 static nxt_uint_t              nxt_controller_listening;
126 static nxt_uint_t              nxt_controller_router_ready;
127 static nxt_controller_conf_t   nxt_controller_conf;
128 static nxt_queue_t             nxt_controller_waiting_requests;
129 static nxt_bool_t              nxt_controller_waiting_init_conf;
130 static nxt_conf_value_t        *nxt_controller_status;
131 
132 
133 static const nxt_event_conn_state_t  nxt_controller_conn_read_state;
134 static const nxt_event_conn_state_t  nxt_controller_conn_body_read_state;
135 static const nxt_event_conn_state_t  nxt_controller_conn_write_state;
136 static const nxt_event_conn_state_t  nxt_controller_conn_close_state;
137 
138 
139 static const nxt_port_handlers_t  nxt_controller_process_port_handlers = {
140     .quit           = nxt_signal_quit_handler,
141     .new_port       = nxt_controller_process_new_port_handler,
142     .change_file    = nxt_port_change_log_file_handler,
143     .mmap           = nxt_port_mmap_handler,
144     .process_ready  = nxt_controller_router_ready_handler,
145     .data           = nxt_port_data_handler,
146     .remove_pid     = nxt_controller_remove_pid_handler,
147     .rpc_ready      = nxt_port_rpc_handler,
148     .rpc_error      = nxt_port_rpc_handler,
149 };
150 
151 
152 const nxt_process_init_t  nxt_controller_process = {
153     .name           = "controller",
154     .type           = NXT_PROCESS_CONTROLLER,
155     .prefork        = nxt_controller_prefork,
156     .restart        = 1,
157     .setup          = nxt_process_core_setup,
158     .start          = nxt_controller_start,
159     .port_handlers  = &nxt_controller_process_port_handlers,
160     .signals        = nxt_process_signals,
161 };
162 
163 
164 static nxt_int_t
165 nxt_controller_prefork(nxt_task_t *task, nxt_process_t *process, nxt_mp_t *mp)
166 {
167     nxt_str_t              ver;
168     nxt_int_t              ret, num;
169     nxt_runtime_t          *rt;
170     nxt_controller_init_t  ctrl_init;
171 
172     nxt_log(task, NXT_LOG_INFO, "controller started");
173 
174     rt = task->thread->runtime;
175 
176     nxt_memzero(&ctrl_init, sizeof(nxt_controller_init_t));
177 
178     /*
179      * Since configuration version has only been introduced in 1.26,
180      * set the default version to 1.25.
181     */
182     nxt_conf_ver = 12500;
183 
184     ret = nxt_controller_file_read(task, rt->conf, &ctrl_init.conf, mp);
185     if (nxt_slow_path(ret == NXT_ERROR)) {
186         return NXT_ERROR;
187     }
188 
189     if (ret == NXT_OK) {
190         ret = nxt_controller_file_read(task, rt->ver, &ver, mp);
191         if (nxt_slow_path(ret == NXT_ERROR)) {
192             return NXT_ERROR;
193         }
194 
195         if (ret == NXT_OK) {
196             num = nxt_int_parse(ver.start, ver.length);
197 
198             if (nxt_slow_path(num < 0)) {
199                 nxt_alert(task, "failed to restore previous configuration: "
200                           "invalid version string \"%V\"", &ver);
201 
202                 nxt_str_null(&ctrl_init.conf);
203 
204             } else {
205                 nxt_conf_ver = num;
206             }
207         }
208     }
209 
210 #if (NXT_TLS)
211     ctrl_init.certs = nxt_cert_store_load(task, mp);
212 
213     nxt_mp_cleanup(mp, nxt_controller_cert_cleanup, task, ctrl_init.certs, rt);
214 #endif
215 
216     process->data.controller = ctrl_init;
217 
218     return NXT_OK;
219 }
220 
221 
222 static nxt_int_t
223 nxt_controller_file_read(nxt_task_t *task, const char *name, nxt_str_t *str,
224     nxt_mp_t *mp)
225 {
226     ssize_t          n;
227     nxt_int_t        ret;
228     nxt_file_t       file;
229     nxt_file_info_t  fi;
230 
231     nxt_memzero(&file, sizeof(nxt_file_t));
232 
233     file.name = (nxt_file_name_t *) name;
234 
235     ret = nxt_file_open(task, &file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 0);
236 
237     if (ret == NXT_OK) {
238         ret = nxt_file_info(&file, &fi);
239         if (nxt_slow_path(ret != NXT_OK)) {
240             goto fail;
241         }
242 
243         if (nxt_fast_path(nxt_is_file(&fi))) {
244             str->length = nxt_file_size(&fi);
245             str->start = nxt_mp_nget(mp, str->length);
246             if (nxt_slow_path(str->start == NULL)) {
247                 goto fail;
248             }
249 
250             n = nxt_file_read(&file, str->start, str->length, 0);
251             if (nxt_slow_path(n != (ssize_t) str->length)) {
252                 goto fail;
253             }
254 
255             nxt_file_close(task, &file);
256 
257             return NXT_OK;
258         }
259 
260         nxt_file_close(task, &file);
261     }
262 
263     return NXT_DECLINED;
264 
265 fail:
266 
267     nxt_file_close(task, &file);
268 
269     return NXT_ERROR;
270 }
271 
272 
273 #if (NXT_TLS)
274 
275 static void
276 nxt_controller_cert_cleanup(nxt_task_t *task, void *obj, void *data)
277 {
278     pid_t          main_pid;
279     nxt_array_t    *certs;
280     nxt_runtime_t  *rt;
281 
282     certs = obj;
283     rt = data;
284 
285     main_pid = rt->port_by_type[NXT_PROCESS_MAIN]->pid;
286 
287     if (nxt_pid == main_pid && certs != NULL) {
288         nxt_cert_store_release(certs);
289     }
290 }
291 
292 #endif
293 
294 
295 static nxt_int_t
296 nxt_controller_start(nxt_task_t *task, nxt_process_data_t *data)
297 {
298     nxt_mp_t               *mp;
299     nxt_int_t              ret;
300     nxt_str_t              *json;
301     nxt_conf_value_t       *conf;
302     nxt_conf_validation_t  vldt;
303     nxt_controller_init_t  *init;
304 
305     ret = nxt_http_fields_hash(&nxt_controller_fields_hash,
306                                nxt_controller_request_fields,
307                                nxt_nitems(nxt_controller_request_fields));
308 
309     if (nxt_slow_path(ret != NXT_OK)) {
310         return NXT_ERROR;
311     }
312 
313     nxt_queue_init(&nxt_controller_waiting_requests);
314 
315     init = &data->controller;
316 
317 #if (NXT_TLS)
318     if (init->certs != NULL) {
319         nxt_cert_info_init(task, init->certs);
320         nxt_cert_store_release(init->certs);
321     }
322 #endif
323 
324     json = &init->conf;
325 
326     if (json->start == NULL) {
327         return NXT_OK;
328     }
329 
330     mp = nxt_mp_create(1024, 128, 256, 32);
331     if (nxt_slow_path(mp == NULL)) {
332         return NXT_ERROR;
333     }
334 
335     conf = nxt_conf_json_parse_str(mp, json);
336     if (nxt_slow_path(conf == NULL)) {
337         nxt_alert(task, "failed to restore previous configuration: "
338                   "file is corrupted or not enough memory");
339 
340         nxt_mp_destroy(mp);
341         return NXT_OK;
342     }
343 
344     nxt_memzero(&vldt, sizeof(nxt_conf_validation_t));
345 
346     vldt.pool = nxt_mp_create(1024, 128, 256, 32);
347     if (nxt_slow_path(vldt.pool == NULL)) {
348         nxt_mp_destroy(mp);
349         return NXT_ERROR;
350     }
351 
352     vldt.conf = conf;
353     vldt.conf_pool = mp;
354     vldt.ver = nxt_conf_ver;
355 
356     ret = nxt_conf_validate(&vldt);
357 
358     if (nxt_slow_path(ret != NXT_OK)) {
359 
360         if (ret == NXT_DECLINED) {
361             nxt_alert(task, "the previous configuration is invalid: %V",
362                       &vldt.error);
363 
364             nxt_mp_destroy(vldt.pool);
365             nxt_mp_destroy(mp);
366 
367             return NXT_OK;
368         }
369 
370         /* ret == NXT_ERROR */
371 
372         return NXT_ERROR;
373     }
374 
375     nxt_mp_destroy(vldt.pool);
376 
377     nxt_controller_conf.root = conf;
378     nxt_controller_conf.pool = mp;
379 
380     return NXT_OK;
381 }
382 
383 
384 static void
385 nxt_controller_process_new_port_handler(nxt_task_t *task,
386     nxt_port_recv_msg_t *msg)
387 {
388     nxt_port_new_port_handler(task, msg);
389 
390     if (msg->u.new_port->type != NXT_PROCESS_ROUTER
391         || !nxt_controller_router_ready)
392     {
393         return;
394     }
395 
396     nxt_controller_send_current_conf(task);
397 }
398 
399 
400 static void
401 nxt_controller_send_current_conf(nxt_task_t *task)
402 {
403     nxt_int_t         rc;
404     nxt_runtime_t     *rt;
405     nxt_conf_value_t  *conf;
406 
407     conf = nxt_controller_conf.root;
408 
409     if (conf != NULL) {
410         rc = nxt_controller_conf_send(task, nxt_controller_conf.pool, conf,
411                                       nxt_controller_conf_init_handler, NULL);
412 
413         if (nxt_fast_path(rc == NXT_OK)) {
414             nxt_controller_waiting_init_conf = 1;
415 
416             return;
417         }
418 
419         nxt_mp_destroy(nxt_controller_conf.pool);
420 
421         if (nxt_slow_path(nxt_controller_conf_default() != NXT_OK)) {
422             nxt_abort();
423         }
424     }
425 
426     if (nxt_slow_path(nxt_controller_conf_default() != NXT_OK)) {
427         nxt_abort();
428     }
429 
430     rt = task->thread->runtime;
431 
432     if (nxt_slow_path(nxt_listen_event(task, rt->controller_socket) == NULL)) {
433         nxt_abort();
434     }
435 
436     nxt_controller_listening = 1;
437 
438     nxt_controller_flush_requests(task);
439 }
440 
441 
442 static void
443 nxt_controller_router_ready_handler(nxt_task_t *task,
444     nxt_port_recv_msg_t *msg)
445 {
446     nxt_port_t     *router_port;
447     nxt_runtime_t  *rt;
448 
449     rt = task->thread->runtime;
450 
451     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
452 
453     nxt_controller_router_ready = 1;
454 
455     if (router_port != NULL) {
456         nxt_controller_send_current_conf(task);
457     }
458 }
459 
460 
461 static void
462 nxt_controller_remove_pid_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
463 {
464     nxt_pid_t      pid;
465     nxt_process_t  *process;
466     nxt_runtime_t  *rt;
467 
468     rt = task->thread->runtime;
469 
470     nxt_assert(nxt_buf_used_size(msg->buf) == sizeof(pid));
471 
472     nxt_memcpy(&pid, msg->buf->mem.pos, sizeof(pid));
473 
474     process = nxt_runtime_process_find(rt, pid);
475     if (process != NULL && nxt_process_type(process) == NXT_PROCESS_ROUTER) {
476         nxt_controller_router_ready = 0;
477     }
478 
479     nxt_port_remove_pid_handler(task, msg);
480 }
481 
482 
483 static nxt_int_t
484 nxt_controller_conf_default(void)
485 {
486     nxt_mp_t          *mp;
487     nxt_conf_value_t  *conf;
488 
489     static const nxt_str_t json
490         = nxt_string("{ \"listeners\": {}, \"applications\": {} }");
491 
492     mp = nxt_mp_create(1024, 128, 256, 32);
493 
494     if (nxt_slow_path(mp == NULL)) {
495         return NXT_ERROR;
496     }
497 
498     conf = nxt_conf_json_parse_str(mp, &json);
499 
500     if (nxt_slow_path(conf == NULL)) {
501         return NXT_ERROR;
502     }
503 
504     nxt_controller_conf.root = conf;
505     nxt_controller_conf.pool = mp;
506 
507     return NXT_OK;
508 }
509 
510 
511 static void
512 nxt_controller_conf_init_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
513     void *data)
514 {
515     nxt_runtime_t  *rt;
516 
517     nxt_controller_waiting_init_conf = 0;
518 
519     if (msg->port_msg.type != NXT_PORT_MSG_RPC_READY) {
520         nxt_alert(task, "failed to apply previous configuration");
521 
522         nxt_mp_destroy(nxt_controller_conf.pool);
523 
524         if (nxt_slow_path(nxt_controller_conf_default() != NXT_OK)) {
525             nxt_abort();
526         }
527     }
528 
529     if (nxt_controller_listening == 0) {
530         rt = task->thread->runtime;
531 
532         if (nxt_slow_path(nxt_listen_event(task, rt->controller_socket)
533                           == NULL))
534         {
535             nxt_abort();
536         }
537 
538         nxt_controller_listening = 1;
539     }
540 
541     nxt_controller_flush_requests(task);
542 }
543 
544 
545 static void
546 nxt_controller_flush_requests(nxt_task_t *task)
547 {
548     nxt_queue_t               queue;
549     nxt_controller_request_t  *req;
550 
551     nxt_queue_init(&queue);
552     nxt_queue_add(&queue, &nxt_controller_waiting_requests);
553 
554     nxt_queue_init(&nxt_controller_waiting_requests);
555 
556     nxt_queue_each(req, &queue, nxt_controller_request_t, link) {
557         nxt_controller_process_request(task, req);
558     } nxt_queue_loop;
559 }
560 
561 
562 static nxt_int_t
563 nxt_controller_conf_send(nxt_task_t *task, nxt_mp_t *mp, nxt_conf_value_t *conf,
564     nxt_port_rpc_handler_t handler, void *data)
565 {
566     void           *mem;
567     u_char         *end;
568     size_t         size;
569     uint32_t       stream;
570     nxt_fd_t       fd;
571     nxt_int_t      rc;
572     nxt_buf_t      *b;
573     nxt_port_t     *router_port, *controller_port;
574     nxt_runtime_t  *rt;
575 
576     rt = task->thread->runtime;
577 
578     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
579 
580     nxt_assert(router_port != NULL);
581     nxt_assert(nxt_controller_router_ready);
582 
583     controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER];
584 
585     size = nxt_conf_json_length(conf, NULL);
586 
587     b = nxt_buf_mem_alloc(mp, sizeof(size_t), 0);
588     if (nxt_slow_path(b == NULL)) {
589         return NXT_ERROR;
590     }
591 
592     fd = nxt_shm_open(task, size);
593     if (nxt_slow_path(fd == -1)) {
594         return NXT_ERROR;
595     }
596 
597     mem = nxt_mem_mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
598     if (nxt_slow_path(mem == MAP_FAILED)) {
599         goto fail;
600     }
601 
602     end = nxt_conf_json_print(mem, conf, NULL);
603 
604     nxt_mem_munmap(mem, size);
605 
606     size = end - (u_char *) mem;
607 
608     b->mem.free = nxt_cpymem(b->mem.pos, &size, sizeof(size_t));
609 
610     stream = nxt_port_rpc_register_handler(task, controller_port,
611                                            handler, handler,
612                                            router_port->pid, data);
613     if (nxt_slow_path(stream == 0)) {
614         goto fail;
615     }
616 
617     rc = nxt_port_socket_write(task, router_port,
618                                NXT_PORT_MSG_DATA_LAST | NXT_PORT_MSG_CLOSE_FD,
619                                fd, stream, controller_port->id, b);
620 
621     if (nxt_slow_path(rc != NXT_OK)) {
622         nxt_port_rpc_cancel(task, controller_port, stream);
623 
624         goto fail;
625     }
626 
627     return NXT_OK;
628 
629 fail:
630 
631     nxt_fd_close(fd);
632 
633     return NXT_ERROR;
634 }
635 
636 
637 nxt_int_t
638 nxt_runtime_controller_socket(nxt_task_t *task, nxt_runtime_t *rt)
639 {
640     nxt_listen_socket_t  *ls;
641 
642     ls = nxt_mp_alloc(rt->mem_pool, sizeof(nxt_listen_socket_t));
643     if (ls == NULL) {
644         return NXT_ERROR;
645     }
646 
647     ls->sockaddr = rt->controller_listen;
648 
649     nxt_listen_socket_remote_size(ls);
650 
651     ls->socket = -1;
652     ls->backlog = NXT_LISTEN_BACKLOG;
653     ls->read_after_accept = 1;
654     ls->flags = NXT_NONBLOCK;
655 
656 #if 0
657     /* STUB */
658     wq = nxt_mp_zget(cf->mem_pool, sizeof(nxt_work_queue_t));
659     if (wq == NULL) {
660         return NXT_ERROR;
661     }
662     nxt_work_queue_name(wq, "listen");
663     /**/
664 
665     ls->work_queue = wq;
666 #endif
667     ls->handler = nxt_controller_conn_init;
668 
669 #if (NXT_HAVE_UNIX_DOMAIN)
670     if (ls->sockaddr->u.sockaddr.sa_family == AF_UNIX) {
671         const char *path = ls->sockaddr->u.sockaddr_un.sun_path;
672 
673         nxt_fs_mkdir_parent((const u_char *) path, 0755);
674     }
675 #endif
676 
677     if (nxt_listen_socket_create(task, rt->mem_pool, ls) != NXT_OK) {
678         return NXT_ERROR;
679     }
680 
681     rt->controller_socket = ls;
682 
683     return NXT_OK;
684 }
685 
686 
687 static void
688 nxt_controller_conn_init(nxt_task_t *task, void *obj, void *data)
689 {
690     nxt_buf_t                 *b;
691     nxt_conn_t                *c;
692     nxt_event_engine_t        *engine;
693     nxt_controller_request_t  *r;
694 
695     c = obj;
696 
697     nxt_debug(task, "controller conn init fd:%d", c->socket.fd);
698 
699     r = nxt_mp_zget(c->mem_pool, sizeof(nxt_controller_request_t));
700     if (nxt_slow_path(r == NULL)) {
701         nxt_controller_conn_free(task, c, NULL);
702         return;
703     }
704 
705     r->conn = c;
706 
707     if (nxt_slow_path(nxt_http_parse_request_init(&r->parser, c->mem_pool)
708                       != NXT_OK))
709     {
710         nxt_controller_conn_free(task, c, NULL);
711         return;
712     }
713 
714     r->parser.encoded_slashes = 1;
715 
716     b = nxt_buf_mem_alloc(c->mem_pool, 1024, 0);
717     if (nxt_slow_path(b == NULL)) {
718         nxt_controller_conn_free(task, c, NULL);
719         return;
720     }
721 
722     c->read = b;
723     c->socket.data = r;
724     c->socket.read_ready = 1;
725     c->read_state = &nxt_controller_conn_read_state;
726 
727     engine = task->thread->engine;
728     c->read_work_queue = &engine->read_work_queue;
729     c->write_work_queue = &engine->write_work_queue;
730 
731     nxt_conn_read(engine, c);
732 }
733 
734 
735 static const nxt_event_conn_state_t  nxt_controller_conn_read_state
736     nxt_aligned(64) =
737 {
738     .ready_handler = nxt_controller_conn_read,
739     .close_handler = nxt_controller_conn_close,
740     .error_handler = nxt_controller_conn_read_error,
741 
742     .timer_handler = nxt_controller_conn_read_timeout,
743     .timer_value = nxt_controller_conn_timeout_value,
744     .timer_data = 300 * 1000,
745 };
746 
747 
748 static void
749 nxt_controller_conn_read(nxt_task_t *task, void *obj, void *data)
750 {
751     size_t                    preread;
752     nxt_buf_t                 *b;
753     nxt_int_t                 rc;
754     nxt_conn_t                *c;
755     nxt_controller_request_t  *r;
756 
757     c = obj;
758     r = data;
759 
760     nxt_debug(task, "controller conn read");
761 
762     nxt_queue_remove(&c->link);
763     nxt_queue_self(&c->link);
764 
765     b = c->read;
766 
767     rc = nxt_http_parse_request(&r->parser, &b->mem);
768 
769     if (nxt_slow_path(rc != NXT_DONE)) {
770 
771         if (rc == NXT_AGAIN) {
772             if (nxt_buf_mem_free_size(&b->mem) == 0) {
773                 nxt_log(task, NXT_LOG_ERR, "too long request headers");
774                 nxt_controller_conn_close(task, c, r);
775                 return;
776             }
777 
778             nxt_conn_read(task->thread->engine, c);
779             return;
780         }
781 
782         /* rc == NXT_ERROR */
783 
784         nxt_log(task, NXT_LOG_ERR, "parsing error");
785 
786         nxt_controller_conn_close(task, c, r);
787         return;
788     }
789 
790     rc = nxt_http_fields_process(r->parser.fields, &nxt_controller_fields_hash,
791                                  r);
792 
793     if (nxt_slow_path(rc != NXT_OK)) {
794         nxt_controller_conn_close(task, c, r);
795         return;
796     }
797 
798     preread = nxt_buf_mem_used_size(&b->mem);
799 
800     nxt_debug(task, "controller request header parsing complete, "
801                     "body length: %uz, preread: %uz",
802                     r->length, preread);
803 
804     if (preread >= r->length) {
805         nxt_controller_process_request(task, r);
806         return;
807     }
808 
809     if (r->length - preread > (size_t) nxt_buf_mem_free_size(&b->mem)) {
810         b = nxt_buf_mem_alloc(c->mem_pool, r->length, 0);
811         if (nxt_slow_path(b == NULL)) {
812             nxt_controller_conn_free(task, c, NULL);
813             return;
814         }
815 
816         b->mem.free = nxt_cpymem(b->mem.free, c->read->mem.pos, preread);
817 
818         c->read = b;
819     }
820 
821     c->read_state = &nxt_controller_conn_body_read_state;
822 
823     nxt_conn_read(task->thread->engine, c);
824 }
825 
826 
827 static nxt_msec_t
828 nxt_controller_conn_timeout_value(nxt_conn_t *c, uintptr_t data)
829 {
830     return (nxt_msec_t) data;
831 }
832 
833 
834 static void
835 nxt_controller_conn_read_error(nxt_task_t *task, void *obj, void *data)
836 {
837     nxt_conn_t  *c;
838 
839     c = obj;
840 
841     nxt_debug(task, "controller conn read error");
842 
843     nxt_controller_conn_close(task, c, data);
844 }
845 
846 
847 static void
848 nxt_controller_conn_read_timeout(nxt_task_t *task, void *obj, void *data)
849 {
850     nxt_timer_t  *timer;
851     nxt_conn_t   *c;
852 
853     timer = obj;
854 
855     c = nxt_read_timer_conn(timer);
856     c->socket.timedout = 1;
857     c->socket.closed = 1;
858 
859     nxt_debug(task, "controller conn read timeout");
860 
861     nxt_controller_conn_close(task, c, data);
862 }
863 
864 
865 static const nxt_event_conn_state_t  nxt_controller_conn_body_read_state
866     nxt_aligned(64) =
867 {
868     .ready_handler = nxt_controller_conn_body_read,
869     .close_handler = nxt_controller_conn_close,
870     .error_handler = nxt_controller_conn_read_error,
871 
872     .timer_handler = nxt_controller_conn_read_timeout,
873     .timer_value = nxt_controller_conn_timeout_value,
874     .timer_data = 60 * 1000,
875     .timer_autoreset = 1,
876 };
877 
878 
879 static void
880 nxt_controller_conn_body_read(nxt_task_t *task, void *obj, void *data)
881 {
882     size_t                    read;
883     nxt_buf_t                 *b;
884     nxt_conn_t                *c;
885     nxt_controller_request_t  *r;
886 
887     c = obj;
888     r = data;
889     b = c->read;
890 
891     read = nxt_buf_mem_used_size(&b->mem);
892 
893     nxt_debug(task, "controller conn body read: %uz of %uz",
894               read, r->length);
895 
896     if (read >= r->length) {
897         nxt_controller_process_request(task, r);
898         return;
899     }
900 
901     nxt_conn_read(task->thread->engine, c);
902 }
903 
904 
905 static const nxt_event_conn_state_t  nxt_controller_conn_write_state
906     nxt_aligned(64) =
907 {
908     .ready_handler = nxt_controller_conn_write,
909     .error_handler = nxt_controller_conn_write_error,
910 
911     .timer_handler = nxt_controller_conn_write_timeout,
912     .timer_value = nxt_controller_conn_timeout_value,
913     .timer_data = 60 * 1000,
914     .timer_autoreset = 1,
915 };
916 
917 
918 static void
919 nxt_controller_conn_write(nxt_task_t *task, void *obj, void *data)
920 {
921     nxt_buf_t   *b;
922     nxt_conn_t  *c;
923 
924     c = obj;
925 
926     nxt_debug(task, "controller conn write");
927 
928     b = c->write;
929 
930     if (b->mem.pos != b->mem.free) {
931         nxt_conn_write(task->thread->engine, c);
932         return;
933     }
934 
935     nxt_debug(task, "controller conn write complete");
936 
937     nxt_controller_conn_close(task, c, data);
938 }
939 
940 
941 static void
942 nxt_controller_conn_write_error(nxt_task_t *task, void *obj, void *data)
943 {
944     nxt_conn_t  *c;
945 
946     c = obj;
947 
948     nxt_debug(task, "controller conn write error");
949 
950     nxt_controller_conn_close(task, c, data);
951 }
952 
953 
954 static void
955 nxt_controller_conn_write_timeout(nxt_task_t *task, void *obj, void *data)
956 {
957     nxt_conn_t   *c;
958     nxt_timer_t  *timer;
959 
960     timer = obj;
961 
962     c = nxt_write_timer_conn(timer);
963     c->socket.timedout = 1;
964     c->socket.closed = 1;
965 
966     nxt_debug(task, "controller conn write timeout");
967 
968     nxt_controller_conn_close(task, c, data);
969 }
970 
971 
972 static const nxt_event_conn_state_t  nxt_controller_conn_close_state
973     nxt_aligned(64) =
974 {
975     .ready_handler = nxt_controller_conn_free,
976 };
977 
978 
979 static void
980 nxt_controller_conn_close(nxt_task_t *task, void *obj, void *data)
981 {
982     nxt_conn_t  *c;
983 
984     c = obj;
985 
986     nxt_debug(task, "controller conn close");
987 
988     nxt_queue_remove(&c->link);
989 
990     c->write_state = &nxt_controller_conn_close_state;
991 
992     nxt_conn_close(task->thread->engine, c);
993 }
994 
995 
996 static void
997 nxt_controller_conn_free(nxt_task_t *task, void *obj, void *data)
998 {
999     nxt_conn_t  *c;
1000 
1001     c = obj;
1002 
1003     nxt_debug(task, "controller conn free");
1004 
1005     nxt_sockaddr_cache_free(task->thread->engine, c);
1006 
1007     nxt_conn_free(task, c);
1008 }
1009 
1010 
1011 static nxt_int_t
1012 nxt_controller_request_content_length(void *ctx, nxt_http_field_t *field,
1013     uintptr_t data)
1014 {
1015     off_t                     length;
1016     nxt_controller_request_t  *r;
1017 
1018     r = ctx;
1019 
1020     length = nxt_off_t_parse(field->value, field->value_length);
1021 
1022     if (nxt_fast_path(length >= 0)) {
1023 
1024         if (nxt_slow_path(length > NXT_SIZE_T_MAX)) {
1025             nxt_log_error(NXT_LOG_ERR, &r->conn->log,
1026                           "Content-Length is too big");
1027             return NXT_ERROR;
1028         }
1029 
1030         r->length = length;
1031         return NXT_OK;
1032     }
1033 
1034     nxt_log_error(NXT_LOG_ERR, &r->conn->log, "Content-Length is invalid");
1035 
1036     return NXT_ERROR;
1037 }
1038 
1039 
1040 static void
1041 nxt_controller_process_request(nxt_task_t *task, nxt_controller_request_t *req)
1042 {
1043     uint32_t                   i, count;
1044     nxt_str_t                  path;
1045     nxt_conn_t                 *c;
1046     nxt_conf_value_t           *value;
1047     nxt_controller_response_t  resp;
1048 #if (NXT_TLS)
1049     nxt_conf_value_t           *certs;
1050 
1051     static nxt_str_t certificates = nxt_string("certificates");
1052 #endif
1053     static nxt_str_t config = nxt_string("config");
1054     static nxt_str_t status = nxt_string("status");
1055 
1056     c = req->conn;
1057     path = req->parser.path;
1058 
1059     if (path.length > 1 && path.start[path.length - 1] == '/') {
1060         path.length--;
1061     }
1062 
1063     if (nxt_str_start(&path, "/config", 7)
1064         && (path.length == 7 || path.start[7] == '/'))
1065     {
1066         if (path.length == 7) {
1067             path.length = 1;
1068 
1069         } else {
1070             path.length -= 7;
1071             path.start += 7;
1072         }
1073 
1074         nxt_controller_process_config(task, req, &path);
1075         return;
1076     }
1077 
1078     nxt_memzero(&resp, sizeof(nxt_controller_response_t));
1079 
1080     if (nxt_str_start(&path, "/status", 7)
1081         && (path.length == 7 || path.start[7] == '/'))
1082     {
1083         if (!nxt_str_eq(&req->parser.method, "GET", 3)) {
1084             goto invalid_method;
1085         }
1086 
1087         if (nxt_controller_status == NULL) {
1088             nxt_controller_process_status(task, req);
1089             return;
1090         }
1091 
1092         if (path.length == 7) {
1093             path.length = 1;
1094 
1095         } else {
1096             path.length -= 7;
1097             path.start += 7;
1098         }
1099 
1100         nxt_controller_status_response(task, req, &path);
1101         return;
1102     }
1103 
1104 #if (NXT_TLS)
1105 
1106     if (nxt_str_start(&path, "/certificates", 13)
1107         && (path.length == 13 || path.start[13] == '/'))
1108     {
1109         if (path.length == 13) {
1110             path.length = 1;
1111 
1112         } else {
1113             path.length -= 13;
1114             path.start += 13;
1115         }
1116 
1117         nxt_controller_process_cert(task, req, &path);
1118         return;
1119     }
1120 
1121 #endif
1122 
1123     if (nxt_str_start(&path, "/control/", 9)) {
1124         path.length -= 9;
1125         path.start += 9;
1126 
1127         nxt_controller_process_control(task, req, &path);
1128         return;
1129     }
1130 
1131     if (path.length == 1 && path.start[0] == '/') {
1132 
1133         if (!nxt_str_eq(&req->parser.method, "GET", 3)) {
1134             goto invalid_method;
1135         }
1136 
1137         if (nxt_controller_status == NULL) {
1138             nxt_controller_process_status(task, req);
1139             return;
1140         }
1141 
1142         count = 2;
1143 #if (NXT_TLS)
1144         count++;
1145 #endif
1146 
1147         value = nxt_conf_create_object(c->mem_pool, count);
1148         if (nxt_slow_path(value == NULL)) {
1149             goto alloc_fail;
1150         }
1151 
1152         i = 0;
1153 
1154 #if (NXT_TLS)
1155         certs = nxt_cert_info_get_all(c->mem_pool);
1156         if (nxt_slow_path(certs == NULL)) {
1157             goto alloc_fail;
1158         }
1159 
1160         nxt_conf_set_member(value, &certificates, certs, i++);
1161 #endif
1162 
1163         nxt_conf_set_member(value, &config, nxt_controller_conf.root, i++);
1164         nxt_conf_set_member(value, &status, nxt_controller_status, i);
1165 
1166         resp.status = 200;
1167         resp.conf = value;
1168 
1169         nxt_controller_response(task, req, &resp);
1170         return;
1171     }
1172 
1173     resp.status = 404;
1174     resp.title = (u_char *) "Value doesn't exist.";
1175     resp.offset = -1;
1176 
1177     nxt_controller_response(task, req, &resp);
1178     return;
1179 
1180 invalid_method:
1181 
1182     resp.status = 405;
1183     resp.title = (u_char *) "Invalid method.";
1184     resp.offset = -1;
1185 
1186     nxt_controller_response(task, req, &resp);
1187     return;
1188 
1189 alloc_fail:
1190 
1191     resp.status = 500;
1192     resp.title = (u_char *) "Memory allocation failed.";
1193     resp.offset = -1;
1194 
1195     nxt_controller_response(task, req, &resp);
1196     return;
1197 }
1198 
1199 
1200 static void
1201 nxt_controller_process_config(nxt_task_t *task, nxt_controller_request_t *req,
1202     nxt_str_t *path)
1203 {
1204     nxt_mp_t                   *mp;
1205     nxt_int_t                  rc;
1206     nxt_conn_t                 *c;
1207     nxt_bool_t                 post;
1208     nxt_buf_mem_t              *mbuf;
1209     nxt_conf_op_t              *ops;
1210     nxt_conf_value_t           *value;
1211     nxt_conf_validation_t      vldt;
1212     nxt_conf_json_error_t      error;
1213     nxt_controller_response_t  resp;
1214 
1215     static const nxt_str_t empty_obj = nxt_string("{}");
1216 
1217     nxt_memzero(&resp, sizeof(nxt_controller_response_t));
1218 
1219     c = req->conn;
1220 
1221     if (nxt_str_eq(&req->parser.method, "GET", 3)) {
1222 
1223         value = nxt_conf_get_path(nxt_controller_conf.root, path);
1224 
1225         if (value == NULL) {
1226             goto not_found;
1227         }
1228 
1229         resp.status = 200;
1230         resp.conf = value;
1231 
1232         nxt_controller_response(task, req, &resp);
1233         return;
1234     }
1235 
1236     if (nxt_str_eq(&req->parser.method, "POST", 4)) {
1237         if (path->length == 1) {
1238             goto not_allowed;
1239         }
1240 
1241         post = 1;
1242 
1243     } else {
1244         post = 0;
1245     }
1246 
1247     if (post || nxt_str_eq(&req->parser.method, "PUT", 3)) {
1248 
1249         if (nxt_controller_check_postpone_request(task)) {
1250             nxt_queue_insert_tail(&nxt_controller_waiting_requests, &req->link);
1251             return;
1252         }
1253 
1254         mp = nxt_mp_create(1024, 128, 256, 32);
1255 
1256         if (nxt_slow_path(mp == NULL)) {
1257             goto alloc_fail;
1258         }
1259 
1260         mbuf = &c->read->mem;
1261 
1262         nxt_memzero(&error, sizeof(nxt_conf_json_error_t));
1263 
1264         /* Skip UTF-8 BOM. */
1265         if (nxt_buf_mem_used_size(mbuf) >= 3
1266             && nxt_memcmp(mbuf->pos, "\xEF\xBB\xBF", 3) == 0)
1267         {
1268             mbuf->pos += 3;
1269         }
1270 
1271         value = nxt_conf_json_parse(mp, mbuf->pos, mbuf->free, &error);
1272 
1273         if (value == NULL) {
1274             nxt_mp_destroy(mp);
1275 
1276             if (error.pos == NULL) {
1277                 goto alloc_fail;
1278             }
1279 
1280             resp.status = 400;
1281             resp.title = (u_char *) "Invalid JSON.";
1282             resp.detail.length = nxt_strlen(error.detail);
1283             resp.detail.start = error.detail;
1284             resp.offset = error.pos - mbuf->pos;
1285 
1286             nxt_conf_json_position(mbuf->pos, error.pos,
1287                                    &resp.line, &resp.column);
1288 
1289             nxt_controller_response(task, req, &resp);
1290             return;
1291         }
1292 
1293         if (path->length != 1) {
1294             rc = nxt_conf_op_compile(c->mem_pool, &ops,
1295                                      nxt_controller_conf.root,
1296                                      path, value, post);
1297 
1298             if (rc != NXT_CONF_OP_OK) {
1299                 nxt_mp_destroy(mp);
1300 
1301                 switch (rc) {
1302                 case NXT_CONF_OP_NOT_FOUND:
1303                     goto not_found;
1304 
1305                 case NXT_CONF_OP_NOT_ALLOWED:
1306                     goto not_allowed;
1307                 }
1308 
1309                 /* rc == NXT_CONF_OP_ERROR */
1310                 goto alloc_fail;
1311             }
1312 
1313             value = nxt_conf_clone(mp, ops, nxt_controller_conf.root);
1314 
1315             if (nxt_slow_path(value == NULL)) {
1316                 nxt_mp_destroy(mp);
1317                 goto alloc_fail;
1318             }
1319         }
1320 
1321         nxt_memzero(&vldt, sizeof(nxt_conf_validation_t));
1322 
1323         vldt.conf = value;
1324         vldt.pool = c->mem_pool;
1325         vldt.conf_pool = mp;
1326         vldt.ver = NXT_VERNUM;
1327 
1328         rc = nxt_conf_validate(&vldt);
1329 
1330         if (nxt_slow_path(rc != NXT_OK)) {
1331             nxt_mp_destroy(mp);
1332 
1333             if (rc == NXT_DECLINED) {
1334                 resp.detail = vldt.error;
1335                 goto invalid_conf;
1336             }
1337 
1338             /* rc == NXT_ERROR */
1339             goto alloc_fail;
1340         }
1341 
1342         rc = nxt_controller_conf_send(task, mp, value,
1343                                       nxt_controller_conf_handler, req);
1344 
1345         if (nxt_slow_path(rc != NXT_OK)) {
1346             nxt_mp_destroy(mp);
1347 
1348             /* rc == NXT_ERROR */
1349             goto alloc_fail;
1350         }
1351 
1352         req->conf.root = value;
1353         req->conf.pool = mp;
1354 
1355         nxt_queue_insert_head(&nxt_controller_waiting_requests, &req->link);
1356 
1357         return;
1358     }
1359 
1360     if (nxt_str_eq(&req->parser.method, "DELETE", 6)) {
1361 
1362         if (nxt_controller_check_postpone_request(task)) {
1363             nxt_queue_insert_tail(&nxt_controller_waiting_requests, &req->link);
1364             return;
1365         }
1366 
1367         if (path->length == 1) {
1368             mp = nxt_mp_create(1024, 128, 256, 32);
1369 
1370             if (nxt_slow_path(mp == NULL)) {
1371                 goto alloc_fail;
1372             }
1373 
1374             value = nxt_conf_json_parse_str(mp, &empty_obj);
1375 
1376         } else {
1377             rc = nxt_conf_op_compile(c->mem_pool, &ops,
1378                                      nxt_controller_conf.root,
1379                                      path, NULL, 0);
1380 
1381             if (rc != NXT_OK) {
1382                 if (rc == NXT_CONF_OP_NOT_FOUND) {
1383                     goto not_found;
1384                 }
1385 
1386                 /* rc == NXT_CONF_OP_ERROR */
1387                 goto alloc_fail;
1388             }
1389 
1390             mp = nxt_mp_create(1024, 128, 256, 32);
1391 
1392             if (nxt_slow_path(mp == NULL)) {
1393                 goto alloc_fail;
1394             }
1395 
1396             value = nxt_conf_clone(mp, ops, nxt_controller_conf.root);
1397         }
1398 
1399         if (nxt_slow_path(value == NULL)) {
1400             nxt_mp_destroy(mp);
1401             goto alloc_fail;
1402         }
1403 
1404         nxt_memzero(&vldt, sizeof(nxt_conf_validation_t));
1405 
1406         vldt.conf = value;
1407         vldt.pool = c->mem_pool;
1408         vldt.conf_pool = mp;
1409         vldt.ver = NXT_VERNUM;
1410 
1411         rc = nxt_conf_validate(&vldt);
1412 
1413         if (nxt_slow_path(rc != NXT_OK)) {
1414             nxt_mp_destroy(mp);
1415 
1416             if (rc == NXT_DECLINED) {
1417                 resp.detail = vldt.error;
1418                 goto invalid_conf;
1419             }
1420 
1421             /* rc == NXT_ERROR */
1422             goto alloc_fail;
1423         }
1424 
1425         rc = nxt_controller_conf_send(task, mp, value,
1426                                       nxt_controller_conf_handler, req);
1427 
1428         if (nxt_slow_path(rc != NXT_OK)) {
1429             nxt_mp_destroy(mp);
1430 
1431             /* rc == NXT_ERROR */
1432             goto alloc_fail;
1433         }
1434 
1435         req->conf.root = value;
1436         req->conf.pool = mp;
1437 
1438         nxt_queue_insert_head(&nxt_controller_waiting_requests, &req->link);
1439 
1440         return;
1441     }
1442 
1443 not_allowed:
1444 
1445     resp.status = 405;
1446     resp.title = (u_char *) "Method isn't allowed.";
1447     resp.offset = -1;
1448 
1449     nxt_controller_response(task, req, &resp);
1450     return;
1451 
1452 not_found:
1453 
1454     resp.status = 404;
1455     resp.title = (u_char *) "Value doesn't exist.";
1456     resp.offset = -1;
1457 
1458     nxt_controller_response(task, req, &resp);
1459     return;
1460 
1461 invalid_conf:
1462 
1463     resp.status = 400;
1464     resp.title = (u_char *) "Invalid configuration.";
1465     resp.offset = -1;
1466 
1467     nxt_controller_response(task, req, &resp);
1468     return;
1469 
1470 alloc_fail:
1471 
1472     resp.status = 500;
1473     resp.title = (u_char *) "Memory allocation failed.";
1474     resp.offset = -1;
1475 
1476     nxt_controller_response(task, req, &resp);
1477 }
1478 
1479 
1480 static nxt_bool_t
1481 nxt_controller_check_postpone_request(nxt_task_t *task)
1482 {
1483     nxt_port_t     *router_port;
1484     nxt_runtime_t  *rt;
1485 
1486     if (!nxt_queue_is_empty(&nxt_controller_waiting_requests)
1487         || nxt_controller_waiting_init_conf
1488         || !nxt_controller_router_ready)
1489     {
1490         return 1;
1491     }
1492 
1493     rt = task->thread->runtime;
1494 
1495     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
1496 
1497     return (router_port == NULL);
1498 }
1499 
1500 
1501 static void
1502 nxt_controller_process_status(nxt_task_t *task, nxt_controller_request_t *req)
1503 {
1504     uint32_t                   stream;
1505     nxt_int_t                  rc;
1506     nxt_port_t                 *router_port, *controller_port;
1507     nxt_runtime_t              *rt;
1508     nxt_controller_response_t  resp;
1509 
1510     if (nxt_controller_check_postpone_request(task)) {
1511         nxt_queue_insert_tail(&nxt_controller_waiting_requests, &req->link);
1512         return;
1513     }
1514 
1515     rt = task->thread->runtime;
1516 
1517     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
1518 
1519     nxt_assert(router_port != NULL);
1520     nxt_assert(nxt_controller_router_ready);
1521 
1522     controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER];
1523 
1524     stream = nxt_port_rpc_register_handler(task, controller_port,
1525                                            nxt_controller_status_handler,
1526                                            nxt_controller_status_handler,
1527                                            router_port->pid, req);
1528     if (nxt_slow_path(stream == 0)) {
1529         goto fail;
1530     }
1531 
1532     rc = nxt_port_socket_write(task, router_port, NXT_PORT_MSG_STATUS,
1533                                -1, stream, controller_port->id, NULL);
1534 
1535     if (nxt_slow_path(rc != NXT_OK)) {
1536         nxt_port_rpc_cancel(task, controller_port, stream);
1537 
1538         goto fail;
1539     }
1540 
1541     nxt_queue_insert_head(&nxt_controller_waiting_requests, &req->link);
1542     return;
1543 
1544 fail:
1545 
1546     nxt_memzero(&resp, sizeof(nxt_controller_response_t));
1547 
1548     resp.status = 500;
1549     resp.title = (u_char *) "Failed to get status.";
1550     resp.offset = -1;
1551 
1552     nxt_controller_response(task, req, &resp);
1553     return;
1554 }
1555 
1556 
1557 static void
1558 nxt_controller_status_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
1559     void *data)
1560 {
1561     nxt_conf_value_t           *status;
1562     nxt_controller_request_t   *req;
1563     nxt_controller_response_t  resp;
1564 
1565     nxt_debug(task, "controller status handler");
1566 
1567     req = data;
1568 
1569     if (msg->port_msg.type == NXT_PORT_MSG_RPC_READY) {
1570         status = nxt_status_get((nxt_status_report_t *) msg->buf->mem.pos,
1571                                 req->conn->mem_pool);
1572     } else {
1573         status = NULL;
1574     }
1575 
1576     if (status == NULL) {
1577         nxt_queue_remove(&req->link);
1578 
1579         nxt_memzero(&resp, sizeof(nxt_controller_response_t));
1580 
1581         resp.status = 500;
1582         resp.title = (u_char *) "Failed to get status.";
1583         resp.offset = -1;
1584 
1585         nxt_controller_response(task, req, &resp);
1586     }
1587 
1588     nxt_controller_status = status;
1589 
1590     nxt_controller_flush_requests(task);
1591 
1592     nxt_controller_status = NULL;
1593 }
1594 
1595 
1596 static void
1597 nxt_controller_status_response(nxt_task_t *task, nxt_controller_request_t *req,
1598     nxt_str_t *path)
1599 {
1600     nxt_conf_value_t           *status;
1601     nxt_controller_response_t  resp;
1602 
1603     status = nxt_conf_get_path(nxt_controller_status, path);
1604 
1605     nxt_memzero(&resp, sizeof(nxt_controller_response_t));
1606 
1607     if (status == NULL) {
1608         resp.status = 404;
1609         resp.title = (u_char *) "Invalid path.";
1610         resp.offset = -1;
1611 
1612         nxt_controller_response(task, req, &resp);
1613         return;
1614     }
1615 
1616     resp.status = 200;
1617     resp.conf = status;
1618 
1619     nxt_controller_response(task, req, &resp);
1620 }
1621 
1622 
1623 #if (NXT_TLS)
1624 
1625 static void
1626 nxt_controller_process_cert(nxt_task_t *task,
1627     nxt_controller_request_t *req, nxt_str_t *path)
1628 {
1629     u_char                     *p;
1630     nxt_str_t                  name;
1631     nxt_int_t                  ret;
1632     nxt_conn_t                 *c;
1633     nxt_cert_t                 *cert;
1634     nxt_conf_value_t           *value;
1635     nxt_controller_response_t  resp;
1636 
1637     name.length = path->length - 1;
1638     name.start = path->start + 1;
1639 
1640     p = nxt_memchr(name.start, '/', name.length);
1641 
1642     if (p != NULL) {
1643         name.length = p - name.start;
1644 
1645         path->length -= p - path->start;
1646         path->start = p;
1647 
1648     } else {
1649         path = NULL;
1650     }
1651 
1652     nxt_memzero(&resp, sizeof(nxt_controller_response_t));
1653 
1654     c = req->conn;
1655 
1656     if (nxt_str_eq(&req->parser.method, "GET", 3)) {
1657 
1658         if (name.length != 0) {
1659             value = nxt_cert_info_get(&name);
1660             if (value == NULL) {
1661                 goto cert_not_found;
1662             }
1663 
1664             if (path != NULL) {
1665                 value = nxt_conf_get_path(value, path);
1666                 if (value == NULL) {
1667                     goto not_found;
1668                 }
1669             }
1670 
1671         } else {
1672             value = nxt_cert_info_get_all(c->mem_pool);
1673             if (value == NULL) {
1674                 goto alloc_fail;
1675             }
1676         }
1677 
1678         resp.status = 200;
1679         resp.conf = value;
1680 
1681         nxt_controller_response(task, req, &resp);
1682         return;
1683     }
1684 
1685     if (name.length == 0 || path != NULL) {
1686         goto invalid_name;
1687     }
1688 
1689     if (nxt_str_eq(&req->parser.method, "PUT", 3)) {
1690         value = nxt_cert_info_get(&name);
1691         if (value != NULL) {
1692             goto exists_cert;
1693         }
1694 
1695         cert = nxt_cert_mem(task, &c->read->mem);
1696         if (cert == NULL) {
1697             goto invalid_cert;
1698         }
1699 
1700         ret = nxt_cert_info_save(&name, cert);
1701 
1702         nxt_cert_destroy(cert);
1703 
1704         if (nxt_slow_path(ret != NXT_OK)) {
1705             goto alloc_fail;
1706         }
1707 
1708         nxt_cert_store_get(task, &name, c->mem_pool,
1709                            nxt_controller_process_cert_save, req);
1710         return;
1711     }
1712 
1713     if (nxt_str_eq(&req->parser.method, "DELETE", 6)) {
1714 
1715         if (nxt_controller_cert_in_use(&name)) {
1716             goto cert_in_use;
1717         }
1718 
1719         if (nxt_cert_info_delete(&name) != NXT_OK) {
1720             goto cert_not_found;
1721         }
1722 
1723         nxt_cert_store_delete(task, &name, c->mem_pool);
1724 
1725         resp.status = 200;
1726         resp.title = (u_char *) "Certificate deleted.";
1727 
1728         nxt_controller_response(task, req, &resp);
1729         return;
1730     }
1731 
1732     resp.status = 405;
1733     resp.title = (u_char *) "Invalid method.";
1734     resp.offset = -1;
1735 
1736     nxt_controller_response(task, req, &resp);
1737     return;
1738 
1739 invalid_name:
1740 
1741     resp.status = 400;
1742     resp.title = (u_char *) "Invalid certificate name.";
1743     resp.offset = -1;
1744 
1745     nxt_controller_response(task, req, &resp);
1746     return;
1747 
1748 invalid_cert:
1749 
1750     resp.status = 400;
1751     resp.title = (u_char *) "Invalid certificate.";
1752     resp.offset = -1;
1753 
1754     nxt_controller_response(task, req, &resp);
1755     return;
1756 
1757 exists_cert:
1758 
1759     resp.status = 400;
1760     resp.title = (u_char *) "Certificate already exists.";
1761     resp.offset = -1;
1762 
1763     nxt_controller_response(task, req, &resp);
1764     return;
1765 
1766 cert_in_use:
1767 
1768     resp.status = 400;
1769     resp.title = (u_char *) "Certificate is used in the configuration.";
1770     resp.offset = -1;
1771 
1772     nxt_controller_response(task, req, &resp);
1773     return;
1774 
1775 cert_not_found:
1776 
1777     resp.status = 404;
1778     resp.title = (u_char *) "Certificate doesn't exist.";
1779     resp.offset = -1;
1780 
1781     nxt_controller_response(task, req, &resp);
1782     return;
1783 
1784 not_found:
1785 
1786     resp.status = 404;
1787     resp.title = (u_char *) "Invalid path.";
1788     resp.offset = -1;
1789 
1790     nxt_controller_response(task, req, &resp);
1791     return;
1792 
1793 alloc_fail:
1794 
1795     resp.status = 500;
1796     resp.title = (u_char *) "Memory allocation failed.";
1797     resp.offset = -1;
1798 
1799     nxt_controller_response(task, req, &resp);
1800     return;
1801 }
1802 
1803 
1804 static void
1805 nxt_controller_process_cert_save(nxt_task_t *task, nxt_port_recv_msg_t *msg,
1806     void *data)
1807 {
1808     nxt_conn_t                *c;
1809     nxt_buf_mem_t             *mbuf;
1810     nxt_controller_request_t  *req;
1811     nxt_controller_response_t  resp;
1812 
1813     req = data;
1814 
1815     nxt_memzero(&resp, sizeof(nxt_controller_response_t));
1816 
1817     if (msg == NULL || msg->port_msg.type == _NXT_PORT_MSG_RPC_ERROR) {
1818         resp.status = 500;
1819         resp.title = (u_char *) "Failed to store certificate.";
1820 
1821         nxt_controller_response(task, req, &resp);
1822         return;
1823     }
1824 
1825     c = req->conn;
1826 
1827     mbuf = &c->read->mem;
1828 
1829     nxt_fd_write(msg->fd[0], mbuf->pos, nxt_buf_mem_used_size(mbuf));
1830 
1831     nxt_fd_close(msg->fd[0]);
1832 
1833     nxt_memzero(&resp, sizeof(nxt_controller_response_t));
1834 
1835     resp.status = 200;
1836     resp.title = (u_char *) "Certificate chain uploaded.";
1837 
1838     nxt_controller_response(task, req, &resp);
1839 }
1840 
1841 
1842 static nxt_bool_t
1843 nxt_controller_cert_in_use(nxt_str_t *name)
1844 {
1845     uint32_t          next;
1846     nxt_str_t         str;
1847     nxt_conf_value_t  *listeners, *listener, *value;
1848 
1849     static nxt_str_t  listeners_path = nxt_string("/listeners");
1850     static nxt_str_t  certificate_path = nxt_string("/tls/certificate");
1851 
1852     listeners = nxt_conf_get_path(nxt_controller_conf.root, &listeners_path);
1853 
1854     if (listeners != NULL) {
1855         next = 0;
1856 
1857         for ( ;; ) {
1858             listener = nxt_conf_next_object_member(listeners, &str, &next);
1859             if (listener == NULL) {
1860                 break;
1861             }
1862 
1863             value = nxt_conf_get_path(listener, &certificate_path);
1864             if (value == NULL) {
1865                 continue;
1866             }
1867 
1868             nxt_conf_get_string(value, &str);
1869 
1870             if (nxt_strstr_eq(&str, name)) {
1871                 return 1;
1872             }
1873         }
1874     }
1875 
1876     return 0;
1877 }
1878 
1879 #endif
1880 
1881 
1882 static void
1883 nxt_controller_conf_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
1884     void *data)
1885 {
1886     nxt_controller_request_t   *req;
1887     nxt_controller_response_t  resp;
1888 
1889     req = data;
1890 
1891     nxt_debug(task, "controller conf ready: %*s",
1892               nxt_buf_mem_used_size(&msg->buf->mem), msg->buf->mem.pos);
1893 
1894     nxt_queue_remove(&req->link);
1895 
1896     nxt_memzero(&resp, sizeof(nxt_controller_response_t));
1897 
1898     if (msg->port_msg.type == NXT_PORT_MSG_RPC_READY) {
1899         nxt_mp_destroy(nxt_controller_conf.pool);
1900 
1901         nxt_controller_conf = req->conf;
1902 
1903         nxt_controller_conf_store(task, req->conf.root);
1904 
1905         resp.status = 200;
1906         resp.title = (u_char *) "Reconfiguration done.";
1907 
1908     } else {
1909         nxt_mp_destroy(req->conf.pool);
1910 
1911         resp.status = 500;
1912         resp.title = (u_char *) "Failed to apply new configuration.";
1913         resp.offset = -1;
1914     }
1915 
1916     nxt_controller_response(task, req, &resp);
1917 
1918     nxt_controller_flush_requests(task);
1919 }
1920 
1921 
1922 static void
1923 nxt_controller_process_control(nxt_task_t *task,
1924     nxt_controller_request_t *req, nxt_str_t *path)
1925 {
1926     uint32_t                   stream;
1927     nxt_buf_t                  *b;
1928     nxt_int_t                  rc;
1929     nxt_port_t                 *router_port, *controller_port;
1930     nxt_runtime_t              *rt;
1931     nxt_conf_value_t           *value;
1932     nxt_controller_response_t  resp;
1933 
1934     static nxt_str_t applications = nxt_string("applications");
1935 
1936     nxt_memzero(&resp, sizeof(nxt_controller_response_t));
1937 
1938     if (!nxt_str_eq(&req->parser.method, "GET", 3)) {
1939         goto not_allowed;
1940     }
1941 
1942     if (!nxt_str_start(path, "applications/", 13)
1943         || nxt_memcmp(path->start + path->length - 8, "/restart", 8) != 0)
1944     {
1945         goto not_found;
1946     }
1947 
1948     path->start += 13;
1949     path->length -= 13 + 8;
1950 
1951     if (nxt_controller_check_postpone_request(task)) {
1952         nxt_queue_insert_tail(&nxt_controller_waiting_requests, &req->link);
1953         return;
1954     }
1955 
1956     value = nxt_controller_conf.root;
1957     if (value == NULL) {
1958         goto not_found;
1959     }
1960 
1961     value = nxt_conf_get_object_member(value, &applications, NULL);
1962     if (value == NULL) {
1963         goto not_found;
1964     }
1965 
1966     value = nxt_conf_get_object_member(value, path, NULL);
1967     if (value == NULL) {
1968         goto not_found;
1969     }
1970 
1971     b = nxt_buf_mem_alloc(req->conn->mem_pool, path->length, 0);
1972     if (nxt_slow_path(b == NULL)) {
1973         goto alloc_fail;
1974     }
1975 
1976     b->mem.free = nxt_cpymem(b->mem.pos, path->start, path->length);
1977 
1978     rt = task->thread->runtime;
1979 
1980     controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER];
1981     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
1982 
1983     stream = nxt_port_rpc_register_handler(task, controller_port,
1984                                            nxt_controller_app_restart_handler,
1985                                            nxt_controller_app_restart_handler,
1986                                            router_port->pid, req);
1987     if (nxt_slow_path(stream == 0)) {
1988         goto alloc_fail;
1989     }
1990 
1991     rc = nxt_port_socket_write(task, router_port, NXT_PORT_MSG_APP_RESTART,
1992                                -1, stream, 0, b);
1993     if (nxt_slow_path(rc != NXT_OK)) {
1994         nxt_port_rpc_cancel(task, controller_port, stream);
1995 
1996         goto fail;
1997     }
1998 
1999     nxt_queue_insert_head(&nxt_controller_waiting_requests, &req->link);
2000 
2001     return;
2002 
2003 not_allowed:
2004 
2005     resp.status = 405;
2006     resp.title = (u_char *) "Method isn't allowed.";
2007     resp.offset = -1;
2008 
2009     nxt_controller_response(task, req, &resp);
2010     return;
2011 
2012 not_found:
2013 
2014     resp.status = 404;
2015     resp.title = (u_char *) "Value doesn't exist.";
2016     resp.offset = -1;
2017 
2018     nxt_controller_response(task, req, &resp);
2019     return;
2020 
2021 alloc_fail:
2022 
2023     resp.status = 500;
2024     resp.title = (u_char *) "Memory allocation failed.";
2025     resp.offset = -1;
2026 
2027     nxt_controller_response(task, req, &resp);
2028     return;
2029 
2030 fail:
2031 
2032     resp.status = 500;
2033     resp.title = (u_char *) "Send restart failed.";
2034     resp.offset = -1;
2035 
2036     nxt_controller_response(task, req, &resp);
2037 }
2038 
2039 
2040 static void
2041 nxt_controller_app_restart_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg,
2042     void *data)
2043 {
2044     nxt_controller_request_t   *req;
2045     nxt_controller_response_t  resp;
2046 
2047     req = data;
2048 
2049     nxt_debug(task, "controller app restart handler");
2050 
2051     nxt_queue_remove(&req->link);
2052 
2053     nxt_memzero(&resp, sizeof(nxt_controller_response_t));
2054 
2055     if (msg->port_msg.type == NXT_PORT_MSG_RPC_READY) {
2056         resp.status = 200;
2057         resp.title = (u_char *) "Ok";
2058 
2059     } else {
2060         resp.status = 500;
2061         resp.title = (u_char *) "Failed to restart app.";
2062         resp.offset = -1;
2063     }
2064 
2065     nxt_controller_response(task, req, &resp);
2066 
2067     nxt_controller_flush_requests(task);
2068 }
2069 
2070 
2071 static void
2072 nxt_controller_conf_store(nxt_task_t *task, nxt_conf_value_t *conf)
2073 {
2074     void           *mem;
2075     u_char         *end;
2076     size_t         size;
2077     nxt_fd_t       fd;
2078     nxt_buf_t      *b;
2079     nxt_port_t     *main_port;
2080     nxt_runtime_t  *rt;
2081 
2082     rt = task->thread->runtime;
2083 
2084     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
2085 
2086     size = nxt_conf_json_length(conf, NULL);
2087 
2088     fd = nxt_shm_open(task, size);
2089     if (nxt_slow_path(fd == -1)) {
2090         return;
2091     }
2092 
2093     mem = nxt_mem_mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
2094     if (nxt_slow_path(mem == MAP_FAILED)) {
2095         goto fail;
2096     }
2097 
2098     end = nxt_conf_json_print(mem, conf, NULL);
2099 
2100     nxt_mem_munmap(mem, size);
2101 
2102     size = end - (u_char *) mem;
2103 
2104     b = nxt_buf_mem_alloc(task->thread->engine->mem_pool, sizeof(size_t), 0);
2105     if (nxt_slow_path(b == NULL)) {
2106         goto fail;
2107     }
2108 
2109     b->mem.free = nxt_cpymem(b->mem.pos, &size, sizeof(size_t));
2110 
2111     (void) nxt_port_socket_write(task, main_port,
2112                                 NXT_PORT_MSG_CONF_STORE | NXT_PORT_MSG_CLOSE_FD,
2113                                  fd, 0, -1, b);
2114 
2115     return;
2116 
2117 fail:
2118 
2119     nxt_fd_close(fd);
2120 }
2121 
2122 
2123 static void
2124 nxt_controller_response(nxt_task_t *task, nxt_controller_request_t *req,
2125     nxt_controller_response_t *resp)
2126 {
2127     size_t                  size;
2128     nxt_str_t               status_line, str;
2129     nxt_buf_t               *b, *body;
2130     nxt_conn_t              *c;
2131     nxt_uint_t              n;
2132     nxt_conf_value_t        *value, *location;
2133     nxt_conf_json_pretty_t  pretty;
2134 
2135     static nxt_str_t  success_str = nxt_string("success");
2136     static nxt_str_t  error_str = nxt_string("error");
2137     static nxt_str_t  detail_str = nxt_string("detail");
2138     static nxt_str_t  location_str = nxt_string("location");
2139     static nxt_str_t  offset_str = nxt_string("offset");
2140     static nxt_str_t  line_str = nxt_string("line");
2141     static nxt_str_t  column_str = nxt_string("column");
2142 
2143     static nxt_time_string_t  date_cache = {
2144         (nxt_atomic_uint_t) -1,
2145         nxt_controller_date,
2146         "%s, %02d %s %4d %02d:%02d:%02d GMT",
2147         nxt_length("Wed, 31 Dec 1986 16:40:00 GMT"),
2148         NXT_THREAD_TIME_GMT,
2149         NXT_THREAD_TIME_SEC,
2150     };
2151 
2152     switch (resp->status) {
2153 
2154     case 200:
2155         nxt_str_set(&status_line, "200 OK");
2156         break;
2157 
2158     case 400:
2159         nxt_str_set(&status_line, "400 Bad Request");
2160         break;
2161 
2162     case 404:
2163         nxt_str_set(&status_line, "404 Not Found");
2164         break;
2165 
2166     case 405:
2167         nxt_str_set(&status_line, "405 Method Not Allowed");
2168         break;
2169 
2170     default:
2171         nxt_str_set(&status_line, "500 Internal Server Error");
2172         break;
2173     }
2174 
2175     c = req->conn;
2176     value = resp->conf;
2177 
2178     if (value == NULL) {
2179         n = 1
2180             + (resp->detail.length != 0)
2181             + (resp->status >= 400 && resp->offset != -1);
2182 
2183         value = nxt_conf_create_object(c->mem_pool, n);
2184 
2185         if (nxt_slow_path(value == NULL)) {
2186             nxt_controller_conn_close(task, c, req);
2187             return;
2188         }
2189 
2190         str.length = nxt_strlen(resp->title);
2191         str.start = resp->title;
2192 
2193         if (resp->status < 400) {
2194             nxt_conf_set_member_string(value, &success_str, &str, 0);
2195 
2196         } else {
2197             nxt_conf_set_member_string(value, &error_str, &str, 0);
2198         }
2199 
2200         n = 0;
2201 
2202         if (resp->detail.length != 0) {
2203             n++;
2204 
2205             nxt_conf_set_member_string(value, &detail_str, &resp->detail, n);
2206         }
2207 
2208         if (resp->status >= 400 && resp->offset != -1) {
2209             n++;
2210 
2211             location = nxt_conf_create_object(c->mem_pool,
2212                                               resp->line != 0 ? 3 : 1);
2213 
2214             nxt_conf_set_member(value, &location_str, location, n);
2215 
2216             nxt_conf_set_member_integer(location, &offset_str, resp->offset, 0);
2217 
2218             if (resp->line != 0) {
2219                 nxt_conf_set_member_integer(location, &line_str,
2220                                             resp->line, 1);
2221 
2222                 nxt_conf_set_member_integer(location, &column_str,
2223                                             resp->column, 2);
2224             }
2225         }
2226     }
2227 
2228     nxt_memzero(&pretty, sizeof(nxt_conf_json_pretty_t));
2229 
2230     size = nxt_conf_json_length(value, &pretty) + 2;
2231 
2232     body = nxt_buf_mem_alloc(c->mem_pool, size, 0);
2233     if (nxt_slow_path(body == NULL)) {
2234         nxt_controller_conn_close(task, c, req);
2235         return;
2236     }
2237 
2238     nxt_memzero(&pretty, sizeof(nxt_conf_json_pretty_t));
2239 
2240     body->mem.free = nxt_conf_json_print(body->mem.free, value, &pretty);
2241 
2242     body->mem.free = nxt_cpymem(body->mem.free, "\r\n", 2);
2243 
2244     size = nxt_length("HTTP/1.1 " "\r\n") + status_line.length
2245            + nxt_length("Server: " NXT_SERVER "\r\n")
2246            + nxt_length("Date: Wed, 31 Dec 1986 16:40:00 GMT\r\n")
2247            + nxt_length("Content-Type: application/json\r\n")
2248            + nxt_length("Content-Length: " "\r\n") + NXT_SIZE_T_LEN
2249            + nxt_length("Connection: close\r\n")
2250            + nxt_length("\r\n");
2251 
2252     b = nxt_buf_mem_alloc(c->mem_pool, size, 0);
2253     if (nxt_slow_path(b == NULL)) {
2254         nxt_controller_conn_close(task, c, req);
2255         return;
2256     }
2257 
2258     b->next = body;
2259 
2260     nxt_str_set(&str, "HTTP/1.1 ");
2261 
2262     b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length);
2263     b->mem.free = nxt_cpymem(b->mem.free, status_line.start,
2264                              status_line.length);
2265 
2266     nxt_str_set(&str, "\r\n"
2267                       "Server: " NXT_SERVER "\r\n"
2268                       "Date: ");
2269 
2270     b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length);
2271 
2272     b->mem.free = nxt_thread_time_string(task->thread, &date_cache,
2273                                          b->mem.free);
2274 
2275     nxt_str_set(&str, "\r\n"
2276                       "Content-Type: application/json\r\n"
2277                       "Content-Length: ");
2278 
2279     b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length);
2280 
2281     b->mem.free = nxt_sprintf(b->mem.free, b->mem.end, "%uz",
2282                               nxt_buf_mem_used_size(&body->mem));
2283 
2284     nxt_str_set(&str, "\r\n"
2285                       "Connection: close\r\n"
2286                       "\r\n");
2287 
2288     b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length);
2289 
2290     c->write = b;
2291     c->write_state = &nxt_controller_conn_write_state;
2292 
2293     nxt_conn_write(task->thread->engine, c);
2294 }
2295 
2296 
2297 static u_char *
2298 nxt_controller_date(u_char *buf, nxt_realtime_t *now, struct tm *tm,
2299     size_t size, const char *format)
2300 {
2301     static const char  *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri",
2302                                    "Sat" };
2303 
2304     static const char  *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
2305                                     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
2306 
2307     return nxt_sprintf(buf, buf + size, format,
2308                        week[tm->tm_wday], tm->tm_mday,
2309                        month[tm->tm_mon], tm->tm_year + 1900,
2310                        tm->tm_hour, tm->tm_min, tm->tm_sec);
2311 }
2312