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