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