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