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}
|