120Sigor@sysoev.ru 220Sigor@sysoev.ru /* 320Sigor@sysoev.ru * Copyright (C) Igor Sysoev 420Sigor@sysoev.ru * Copyright (C) Valentin V. Bartenev 520Sigor@sysoev.ru * Copyright (C) NGINX, Inc. 620Sigor@sysoev.ru */ 720Sigor@sysoev.ru 820Sigor@sysoev.ru #include <nxt_main.h> 920Sigor@sysoev.ru #include <nxt_runtime.h> 10240Sigor@sysoev.ru #include <nxt_main_process.h> 1129Svbart@nginx.com #include <nxt_conf.h> 1220Sigor@sysoev.ru 1320Sigor@sysoev.ru 1427Svbart@nginx.com typedef struct { 15106Svbart@nginx.com nxt_conf_value_t *root; 16106Svbart@nginx.com nxt_mp_t *pool; 1744Svbart@nginx.com } nxt_controller_conf_t; 1844Svbart@nginx.com 1944Svbart@nginx.com 2044Svbart@nginx.com typedef struct { 2127Svbart@nginx.com nxt_http_request_parse_t parser; 2227Svbart@nginx.com size_t length; 2344Svbart@nginx.com nxt_controller_conf_t conf; 24140Svbart@nginx.com nxt_conn_t *conn; 25140Svbart@nginx.com nxt_queue_link_t link; 2627Svbart@nginx.com } nxt_controller_request_t; 2727Svbart@nginx.com 2827Svbart@nginx.com 2944Svbart@nginx.com typedef struct { 30208Svbart@nginx.com nxt_uint_t status; 31106Svbart@nginx.com nxt_conf_value_t *conf; 32208Svbart@nginx.com 33208Svbart@nginx.com u_char *title; 34357Svbart@nginx.com nxt_str_t detail; 35208Svbart@nginx.com ssize_t offset; 36208Svbart@nginx.com nxt_uint_t line; 37208Svbart@nginx.com nxt_uint_t column; 3844Svbart@nginx.com } nxt_controller_response_t; 3944Svbart@nginx.com 4044Svbart@nginx.com 41248Svbart@nginx.com static void nxt_controller_process_new_port_handler(nxt_task_t *task, 42248Svbart@nginx.com nxt_port_recv_msg_t *msg); 43249Svbart@nginx.com static nxt_int_t nxt_controller_conf_default(void); 44249Svbart@nginx.com static void nxt_controller_conf_init_handler(nxt_task_t *task, 45249Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 46249Svbart@nginx.com static nxt_int_t nxt_controller_conf_send(nxt_task_t *task, 47249Svbart@nginx.com nxt_conf_value_t *conf, nxt_port_rpc_handler_t handler, void *data); 48248Svbart@nginx.com 4920Sigor@sysoev.ru static void nxt_controller_conn_init(nxt_task_t *task, void *obj, void *data); 5020Sigor@sysoev.ru static void nxt_controller_conn_read(nxt_task_t *task, void *obj, void *data); 5162Sigor@sysoev.ru static nxt_msec_t nxt_controller_conn_timeout_value(nxt_conn_t *c, 5220Sigor@sysoev.ru uintptr_t data); 5320Sigor@sysoev.ru static void nxt_controller_conn_read_error(nxt_task_t *task, void *obj, 5420Sigor@sysoev.ru void *data); 5520Sigor@sysoev.ru static void nxt_controller_conn_read_timeout(nxt_task_t *task, void *obj, 5620Sigor@sysoev.ru void *data); 5727Svbart@nginx.com static void nxt_controller_conn_body_read(nxt_task_t *task, void *obj, 5827Svbart@nginx.com void *data); 5927Svbart@nginx.com static void nxt_controller_conn_write(nxt_task_t *task, void *obj, void *data); 6027Svbart@nginx.com static void nxt_controller_conn_write_error(nxt_task_t *task, void *obj, 6127Svbart@nginx.com void *data); 6227Svbart@nginx.com static void nxt_controller_conn_write_timeout(nxt_task_t *task, void *obj, 6327Svbart@nginx.com void *data); 6420Sigor@sysoev.ru static void nxt_controller_conn_close(nxt_task_t *task, void *obj, void *data); 6520Sigor@sysoev.ru static void nxt_controller_conn_free(nxt_task_t *task, void *obj, void *data); 6620Sigor@sysoev.ru 6727Svbart@nginx.com static nxt_int_t nxt_controller_request_content_length(void *ctx, 6867Svbart@nginx.com nxt_http_field_t *field, nxt_log_t *log); 6927Svbart@nginx.com 7027Svbart@nginx.com static void nxt_controller_process_request(nxt_task_t *task, 71140Svbart@nginx.com nxt_controller_request_t *req); 72238Svbart@nginx.com static void nxt_controller_conf_handler(nxt_task_t *task, 73238Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 74314Svbart@nginx.com static void nxt_controller_conf_store(nxt_task_t *task, 75314Svbart@nginx.com nxt_conf_value_t *conf); 76140Svbart@nginx.com static void nxt_controller_response(nxt_task_t *task, 77140Svbart@nginx.com nxt_controller_request_t *req, nxt_controller_response_t *resp); 78208Svbart@nginx.com static u_char *nxt_controller_date(u_char *buf, nxt_realtime_t *now, 79208Svbart@nginx.com struct tm *tm, size_t size, const char *format); 8027Svbart@nginx.com 8127Svbart@nginx.com 8260Svbart@nginx.com static nxt_http_fields_hash_entry_t nxt_controller_request_fields[] = { 8327Svbart@nginx.com { nxt_string("Content-Length"), 8427Svbart@nginx.com &nxt_controller_request_content_length, 0 }, 8527Svbart@nginx.com 8627Svbart@nginx.com { nxt_null_string, NULL, 0 } 8727Svbart@nginx.com }; 8827Svbart@nginx.com 8960Svbart@nginx.com static nxt_http_fields_hash_t *nxt_controller_fields_hash; 9027Svbart@nginx.com 91314Svbart@nginx.com static nxt_uint_t nxt_controller_listening; 92238Svbart@nginx.com static nxt_controller_conf_t nxt_controller_conf; 93238Svbart@nginx.com static nxt_queue_t nxt_controller_waiting_requests; 9427Svbart@nginx.com 9520Sigor@sysoev.ru 9620Sigor@sysoev.ru static const nxt_event_conn_state_t nxt_controller_conn_read_state; 9727Svbart@nginx.com static const nxt_event_conn_state_t nxt_controller_conn_body_read_state; 9827Svbart@nginx.com static const nxt_event_conn_state_t nxt_controller_conn_write_state; 9920Sigor@sysoev.ru static const nxt_event_conn_state_t nxt_controller_conn_close_state; 10020Sigor@sysoev.ru 10120Sigor@sysoev.ru 102320Smax.romanov@nginx.com nxt_port_handlers_t nxt_controller_process_port_handlers = { 103320Smax.romanov@nginx.com .quit = nxt_worker_process_quit_handler, 104320Smax.romanov@nginx.com .new_port = nxt_controller_process_new_port_handler, 105320Smax.romanov@nginx.com .change_file = nxt_port_change_log_file_handler, 106320Smax.romanov@nginx.com .mmap = nxt_port_mmap_handler, 107320Smax.romanov@nginx.com .data = nxt_port_data_handler, 108320Smax.romanov@nginx.com .remove_pid = nxt_port_remove_pid_handler, 109320Smax.romanov@nginx.com .rpc_ready = nxt_port_rpc_handler, 110320Smax.romanov@nginx.com .rpc_error = nxt_port_rpc_handler, 111248Svbart@nginx.com }; 112248Svbart@nginx.com 113248Svbart@nginx.com 11420Sigor@sysoev.ru nxt_int_t 115141Smax.romanov@nginx.com nxt_controller_start(nxt_task_t *task, void *data) 11620Sigor@sysoev.ru { 117314Svbart@nginx.com nxt_mp_t *mp; 118357Svbart@nginx.com nxt_int_t ret; 119314Svbart@nginx.com nxt_str_t *json; 120141Smax.romanov@nginx.com nxt_runtime_t *rt; 121314Svbart@nginx.com nxt_conf_value_t *conf; 122337Sigor@sysoev.ru nxt_event_engine_t *engine; 123357Svbart@nginx.com nxt_conf_validation_t vldt; 12427Svbart@nginx.com nxt_http_fields_hash_t *hash; 12527Svbart@nginx.com 126141Smax.romanov@nginx.com rt = task->thread->runtime; 127141Smax.romanov@nginx.com 128337Sigor@sysoev.ru engine = task->thread->engine; 129337Sigor@sysoev.ru 130337Sigor@sysoev.ru engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64); 131337Sigor@sysoev.ru if (nxt_slow_path(engine->mem_pool == NULL)) { 132337Sigor@sysoev.ru return NXT_ERROR; 133337Sigor@sysoev.ru } 134337Sigor@sysoev.ru 13560Svbart@nginx.com hash = nxt_http_fields_hash_create(nxt_controller_request_fields, 13660Svbart@nginx.com rt->mem_pool); 13727Svbart@nginx.com if (nxt_slow_path(hash == NULL)) { 13827Svbart@nginx.com return NXT_ERROR; 13927Svbart@nginx.com } 14027Svbart@nginx.com 14160Svbart@nginx.com nxt_controller_fields_hash = hash; 142248Svbart@nginx.com nxt_queue_init(&nxt_controller_waiting_requests); 14327Svbart@nginx.com 144314Svbart@nginx.com json = data; 145314Svbart@nginx.com 146314Svbart@nginx.com if (json->length == 0) { 147314Svbart@nginx.com return NXT_OK; 148314Svbart@nginx.com } 149314Svbart@nginx.com 150314Svbart@nginx.com mp = nxt_mp_create(1024, 128, 256, 32); 151314Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 152314Svbart@nginx.com return NXT_ERROR; 153314Svbart@nginx.com } 154314Svbart@nginx.com 155314Svbart@nginx.com conf = nxt_conf_json_parse_str(mp, json); 156314Svbart@nginx.com nxt_free(json->start); 157314Svbart@nginx.com 158314Svbart@nginx.com if (nxt_slow_path(conf == NULL)) { 159314Svbart@nginx.com nxt_log(task, NXT_LOG_ALERT, 160314Svbart@nginx.com "failed to restore previous configuration: " 161314Svbart@nginx.com "file is corrupted or not enough memory"); 162314Svbart@nginx.com 163314Svbart@nginx.com nxt_mp_destroy(mp); 164314Svbart@nginx.com return NXT_OK; 165314Svbart@nginx.com } 166314Svbart@nginx.com 167357Svbart@nginx.com nxt_memzero(&vldt, sizeof(nxt_conf_validation_t)); 168314Svbart@nginx.com 169357Svbart@nginx.com vldt.pool = nxt_mp_create(1024, 128, 256, 32); 170357Svbart@nginx.com if (nxt_slow_path(vldt.pool == NULL)) { 171357Svbart@nginx.com return NXT_ERROR; 172314Svbart@nginx.com } 173314Svbart@nginx.com 174357Svbart@nginx.com vldt.conf = conf; 175357Svbart@nginx.com 176357Svbart@nginx.com ret = nxt_conf_validate(&vldt); 177357Svbart@nginx.com 178357Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 179357Svbart@nginx.com 180357Svbart@nginx.com if (ret == NXT_DECLINED) { 181357Svbart@nginx.com nxt_log(task, NXT_LOG_ALERT, 182357Svbart@nginx.com "the previous configuration is invalid: %V", &vldt.error); 183357Svbart@nginx.com 184357Svbart@nginx.com nxt_mp_destroy(vldt.pool); 185357Svbart@nginx.com nxt_mp_destroy(mp); 186357Svbart@nginx.com 187357Svbart@nginx.com return NXT_OK; 188357Svbart@nginx.com } 189357Svbart@nginx.com 190357Svbart@nginx.com /* ret == NXT_ERROR */ 191357Svbart@nginx.com 192357Svbart@nginx.com return NXT_ERROR; 193357Svbart@nginx.com } 194357Svbart@nginx.com 195357Svbart@nginx.com nxt_mp_destroy(vldt.pool); 196314Svbart@nginx.com 197314Svbart@nginx.com nxt_controller_conf.root = conf; 198314Svbart@nginx.com nxt_controller_conf.pool = mp; 199314Svbart@nginx.com 200248Svbart@nginx.com return NXT_OK; 201248Svbart@nginx.com } 202248Svbart@nginx.com 203248Svbart@nginx.com 204248Svbart@nginx.com static void 205248Svbart@nginx.com nxt_controller_process_new_port_handler(nxt_task_t *task, 206248Svbart@nginx.com nxt_port_recv_msg_t *msg) 207248Svbart@nginx.com { 208249Svbart@nginx.com nxt_int_t rc; 209248Svbart@nginx.com nxt_runtime_t *rt; 210248Svbart@nginx.com nxt_conf_value_t *conf; 211248Svbart@nginx.com 212248Svbart@nginx.com nxt_port_new_port_handler(task, msg); 213248Svbart@nginx.com 214347Smax.romanov@nginx.com if (msg->u.new_port->type != NXT_PROCESS_ROUTER) { 215248Svbart@nginx.com return; 21620Sigor@sysoev.ru } 21720Sigor@sysoev.ru 218249Svbart@nginx.com conf = nxt_controller_conf.root; 219249Svbart@nginx.com 220249Svbart@nginx.com if (conf != NULL) { 221249Svbart@nginx.com rc = nxt_controller_conf_send(task, conf, 222249Svbart@nginx.com nxt_controller_conf_init_handler, NULL); 22344Svbart@nginx.com 224249Svbart@nginx.com if (nxt_fast_path(rc == NXT_OK)) { 225249Svbart@nginx.com return; 226249Svbart@nginx.com } 227249Svbart@nginx.com 228249Svbart@nginx.com nxt_mp_destroy(nxt_controller_conf.pool); 229249Svbart@nginx.com 230249Svbart@nginx.com if (nxt_slow_path(nxt_controller_conf_default() != NXT_OK)) { 231249Svbart@nginx.com nxt_abort(); 232249Svbart@nginx.com } 23344Svbart@nginx.com } 23444Svbart@nginx.com 235249Svbart@nginx.com if (nxt_slow_path(nxt_controller_conf_default() != NXT_OK)) { 236248Svbart@nginx.com nxt_abort(); 23744Svbart@nginx.com } 23844Svbart@nginx.com 239248Svbart@nginx.com rt = task->thread->runtime; 240140Svbart@nginx.com 241248Svbart@nginx.com if (nxt_slow_path(nxt_listen_event(task, rt->controller_socket) == NULL)) { 242248Svbart@nginx.com nxt_abort(); 243248Svbart@nginx.com } 244314Svbart@nginx.com 245314Svbart@nginx.com nxt_controller_listening = 1; 24620Sigor@sysoev.ru } 24720Sigor@sysoev.ru 24820Sigor@sysoev.ru 249249Svbart@nginx.com static nxt_int_t 250249Svbart@nginx.com nxt_controller_conf_default(void) 251249Svbart@nginx.com { 252249Svbart@nginx.com nxt_mp_t *mp; 253249Svbart@nginx.com nxt_conf_value_t *conf; 254249Svbart@nginx.com 255249Svbart@nginx.com static const nxt_str_t json 256249Svbart@nginx.com = nxt_string("{ \"listeners\": {}, \"applications\": {} }"); 257249Svbart@nginx.com 258249Svbart@nginx.com mp = nxt_mp_create(1024, 128, 256, 32); 259249Svbart@nginx.com 260249Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 261249Svbart@nginx.com return NXT_ERROR; 262249Svbart@nginx.com } 263249Svbart@nginx.com 264249Svbart@nginx.com conf = nxt_conf_json_parse_str(mp, &json); 265249Svbart@nginx.com 266249Svbart@nginx.com if (nxt_slow_path(conf == NULL)) { 267249Svbart@nginx.com return NXT_ERROR; 268249Svbart@nginx.com } 269249Svbart@nginx.com 270249Svbart@nginx.com nxt_controller_conf.root = conf; 271249Svbart@nginx.com nxt_controller_conf.pool = mp; 272249Svbart@nginx.com 273249Svbart@nginx.com return NXT_OK; 274249Svbart@nginx.com } 275249Svbart@nginx.com 276249Svbart@nginx.com 277249Svbart@nginx.com static void 278249Svbart@nginx.com nxt_controller_conf_init_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 279249Svbart@nginx.com void *data) 280249Svbart@nginx.com { 281314Svbart@nginx.com nxt_runtime_t *rt; 282314Svbart@nginx.com 283249Svbart@nginx.com if (msg->port_msg.type != NXT_PORT_MSG_RPC_READY) { 284314Svbart@nginx.com nxt_log(task, NXT_LOG_ALERT, "failed to apply previous configuration"); 285314Svbart@nginx.com 286249Svbart@nginx.com nxt_mp_destroy(nxt_controller_conf.pool); 287249Svbart@nginx.com 288249Svbart@nginx.com if (nxt_slow_path(nxt_controller_conf_default() != NXT_OK)) { 289249Svbart@nginx.com nxt_abort(); 290249Svbart@nginx.com } 291249Svbart@nginx.com } 292314Svbart@nginx.com 293314Svbart@nginx.com if (nxt_controller_listening == 0) { 294314Svbart@nginx.com rt = task->thread->runtime; 295314Svbart@nginx.com 296314Svbart@nginx.com if (nxt_slow_path(nxt_listen_event(task, rt->controller_socket) 297314Svbart@nginx.com == NULL)) 298314Svbart@nginx.com { 299314Svbart@nginx.com nxt_abort(); 300314Svbart@nginx.com } 301314Svbart@nginx.com 302314Svbart@nginx.com nxt_controller_listening = 1; 303314Svbart@nginx.com } 304249Svbart@nginx.com } 305249Svbart@nginx.com 306249Svbart@nginx.com 307249Svbart@nginx.com static nxt_int_t 308249Svbart@nginx.com nxt_controller_conf_send(nxt_task_t *task, nxt_conf_value_t *conf, 309249Svbart@nginx.com nxt_port_rpc_handler_t handler, void *data) 310249Svbart@nginx.com { 311249Svbart@nginx.com size_t size; 312249Svbart@nginx.com uint32_t stream; 313249Svbart@nginx.com nxt_int_t rc; 314249Svbart@nginx.com nxt_buf_t *b; 315249Svbart@nginx.com nxt_port_t *router_port, *controller_port; 316249Svbart@nginx.com nxt_runtime_t *rt; 317249Svbart@nginx.com 318249Svbart@nginx.com rt = task->thread->runtime; 319249Svbart@nginx.com 320249Svbart@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 321249Svbart@nginx.com 322249Svbart@nginx.com if (nxt_slow_path(router_port == NULL)) { 323249Svbart@nginx.com return NXT_DECLINED; 324249Svbart@nginx.com } 325249Svbart@nginx.com 326249Svbart@nginx.com controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER]; 327249Svbart@nginx.com 328249Svbart@nginx.com size = nxt_conf_json_length(conf, NULL); 329249Svbart@nginx.com 330249Svbart@nginx.com b = nxt_port_mmap_get_buf(task, router_port, size); 331379Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 332379Smax.romanov@nginx.com return NXT_ERROR; 333379Smax.romanov@nginx.com } 334249Svbart@nginx.com 335249Svbart@nginx.com b->mem.free = nxt_conf_json_print(b->mem.free, conf, NULL); 336249Svbart@nginx.com 337249Svbart@nginx.com stream = nxt_port_rpc_register_handler(task, controller_port, 338249Svbart@nginx.com handler, handler, 339249Svbart@nginx.com router_port->pid, data); 340249Svbart@nginx.com 341249Svbart@nginx.com rc = nxt_port_socket_write(task, router_port, NXT_PORT_MSG_DATA_LAST, -1, 342249Svbart@nginx.com stream, controller_port->id, b); 343249Svbart@nginx.com 344249Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 345249Svbart@nginx.com nxt_port_rpc_cancel(task, controller_port, stream); 346249Svbart@nginx.com return NXT_ERROR; 347249Svbart@nginx.com } 348249Svbart@nginx.com 349249Svbart@nginx.com return NXT_OK; 350249Svbart@nginx.com } 351249Svbart@nginx.com 352249Svbart@nginx.com 35320Sigor@sysoev.ru nxt_int_t 35420Sigor@sysoev.ru nxt_runtime_controller_socket(nxt_task_t *task, nxt_runtime_t *rt) 35520Sigor@sysoev.ru { 35620Sigor@sysoev.ru nxt_sockaddr_t *sa; 35720Sigor@sysoev.ru nxt_listen_socket_t *ls; 35820Sigor@sysoev.ru 35920Sigor@sysoev.ru sa = rt->controller_listen; 36020Sigor@sysoev.ru 36165Sigor@sysoev.ru ls = nxt_mp_alloc(rt->mem_pool, sizeof(nxt_listen_socket_t)); 36220Sigor@sysoev.ru if (ls == NULL) { 36320Sigor@sysoev.ru return NXT_ERROR; 36420Sigor@sysoev.ru } 36520Sigor@sysoev.ru 36620Sigor@sysoev.ru ls->sockaddr = nxt_sockaddr_create(rt->mem_pool, &sa->u.sockaddr, 36720Sigor@sysoev.ru sa->socklen, sa->length); 36820Sigor@sysoev.ru if (ls->sockaddr == NULL) { 36920Sigor@sysoev.ru return NXT_ERROR; 37020Sigor@sysoev.ru } 37120Sigor@sysoev.ru 37220Sigor@sysoev.ru ls->sockaddr->type = sa->type; 373312Sigor@sysoev.ru nxt_sockaddr_text(ls->sockaddr); 37420Sigor@sysoev.ru 375359Sigor@sysoev.ru nxt_listen_socket_remote_size(ls); 37620Sigor@sysoev.ru 37720Sigor@sysoev.ru ls->socket = -1; 37820Sigor@sysoev.ru ls->backlog = NXT_LISTEN_BACKLOG; 37920Sigor@sysoev.ru ls->read_after_accept = 1; 38020Sigor@sysoev.ru ls->flags = NXT_NONBLOCK; 38120Sigor@sysoev.ru 38220Sigor@sysoev.ru #if 0 38320Sigor@sysoev.ru /* STUB */ 38465Sigor@sysoev.ru wq = nxt_mp_zget(cf->mem_pool, sizeof(nxt_work_queue_t)); 38520Sigor@sysoev.ru if (wq == NULL) { 38620Sigor@sysoev.ru return NXT_ERROR; 38720Sigor@sysoev.ru } 38820Sigor@sysoev.ru nxt_work_queue_name(wq, "listen"); 38920Sigor@sysoev.ru /**/ 39020Sigor@sysoev.ru 39120Sigor@sysoev.ru ls->work_queue = wq; 39220Sigor@sysoev.ru #endif 39320Sigor@sysoev.ru ls->handler = nxt_controller_conn_init; 39420Sigor@sysoev.ru 39520Sigor@sysoev.ru if (nxt_listen_socket_create(task, ls, 0) != NXT_OK) { 39620Sigor@sysoev.ru return NXT_ERROR; 39720Sigor@sysoev.ru } 39820Sigor@sysoev.ru 39920Sigor@sysoev.ru rt->controller_socket = ls; 40020Sigor@sysoev.ru 40120Sigor@sysoev.ru return NXT_OK; 40220Sigor@sysoev.ru } 40320Sigor@sysoev.ru 40420Sigor@sysoev.ru 40520Sigor@sysoev.ru static void 40620Sigor@sysoev.ru nxt_controller_conn_init(nxt_task_t *task, void *obj, void *data) 40720Sigor@sysoev.ru { 40827Svbart@nginx.com nxt_buf_t *b; 40962Sigor@sysoev.ru nxt_conn_t *c; 41027Svbart@nginx.com nxt_event_engine_t *engine; 41127Svbart@nginx.com nxt_controller_request_t *r; 41220Sigor@sysoev.ru 41320Sigor@sysoev.ru c = obj; 41420Sigor@sysoev.ru 41520Sigor@sysoev.ru nxt_debug(task, "controller conn init fd:%d", c->socket.fd); 41620Sigor@sysoev.ru 41765Sigor@sysoev.ru r = nxt_mp_zget(c->mem_pool, sizeof(nxt_controller_request_t)); 41827Svbart@nginx.com if (nxt_slow_path(r == NULL)) { 41927Svbart@nginx.com nxt_controller_conn_free(task, c, NULL); 42027Svbart@nginx.com return; 42127Svbart@nginx.com } 42227Svbart@nginx.com 423140Svbart@nginx.com r->conn = c; 424140Svbart@nginx.com 42560Svbart@nginx.com if (nxt_slow_path(nxt_http_parse_request_init(&r->parser, c->mem_pool) 42660Svbart@nginx.com != NXT_OK)) 42760Svbart@nginx.com { 42860Svbart@nginx.com nxt_controller_conn_free(task, c, NULL); 42960Svbart@nginx.com return; 43060Svbart@nginx.com } 43127Svbart@nginx.com 43267Svbart@nginx.com r->parser.fields_hash = nxt_controller_fields_hash; 43367Svbart@nginx.com 43420Sigor@sysoev.ru b = nxt_buf_mem_alloc(c->mem_pool, 1024, 0); 43520Sigor@sysoev.ru if (nxt_slow_path(b == NULL)) { 43620Sigor@sysoev.ru nxt_controller_conn_free(task, c, NULL); 43720Sigor@sysoev.ru return; 43820Sigor@sysoev.ru } 43920Sigor@sysoev.ru 44020Sigor@sysoev.ru c->read = b; 44127Svbart@nginx.com c->socket.data = r; 44220Sigor@sysoev.ru c->socket.read_ready = 1; 44320Sigor@sysoev.ru c->read_state = &nxt_controller_conn_read_state; 44420Sigor@sysoev.ru 44520Sigor@sysoev.ru engine = task->thread->engine; 44620Sigor@sysoev.ru c->read_work_queue = &engine->read_work_queue; 44727Svbart@nginx.com c->write_work_queue = &engine->write_work_queue; 44820Sigor@sysoev.ru 44962Sigor@sysoev.ru nxt_conn_read(engine, c); 45020Sigor@sysoev.ru } 45120Sigor@sysoev.ru 45220Sigor@sysoev.ru 45320Sigor@sysoev.ru static const nxt_event_conn_state_t nxt_controller_conn_read_state 45420Sigor@sysoev.ru nxt_aligned(64) = 45520Sigor@sysoev.ru { 45656Sigor@sysoev.ru .ready_handler = nxt_controller_conn_read, 45756Sigor@sysoev.ru .close_handler = nxt_controller_conn_close, 45856Sigor@sysoev.ru .error_handler = nxt_controller_conn_read_error, 45920Sigor@sysoev.ru 46056Sigor@sysoev.ru .timer_handler = nxt_controller_conn_read_timeout, 46156Sigor@sysoev.ru .timer_value = nxt_controller_conn_timeout_value, 46256Sigor@sysoev.ru .timer_data = 60 * 1000, 46320Sigor@sysoev.ru }; 46420Sigor@sysoev.ru 46520Sigor@sysoev.ru 46620Sigor@sysoev.ru static void 46720Sigor@sysoev.ru nxt_controller_conn_read(nxt_task_t *task, void *obj, void *data) 46820Sigor@sysoev.ru { 46927Svbart@nginx.com size_t preread; 47027Svbart@nginx.com nxt_buf_t *b; 47127Svbart@nginx.com nxt_int_t rc; 47262Sigor@sysoev.ru nxt_conn_t *c; 47327Svbart@nginx.com nxt_controller_request_t *r; 47420Sigor@sysoev.ru 47520Sigor@sysoev.ru c = obj; 47627Svbart@nginx.com r = data; 47720Sigor@sysoev.ru 47820Sigor@sysoev.ru nxt_debug(task, "controller conn read"); 47920Sigor@sysoev.ru 48027Svbart@nginx.com nxt_queue_remove(&c->link); 48127Svbart@nginx.com nxt_queue_self(&c->link); 48227Svbart@nginx.com 48327Svbart@nginx.com b = c->read; 48427Svbart@nginx.com 48527Svbart@nginx.com rc = nxt_http_parse_request(&r->parser, &b->mem); 48627Svbart@nginx.com 48727Svbart@nginx.com if (nxt_slow_path(rc != NXT_DONE)) { 48827Svbart@nginx.com 48927Svbart@nginx.com if (rc == NXT_AGAIN) { 49027Svbart@nginx.com if (nxt_buf_mem_free_size(&b->mem) == 0) { 49127Svbart@nginx.com nxt_log(task, NXT_LOG_ERR, "too long request headers"); 49227Svbart@nginx.com nxt_controller_conn_close(task, c, r); 49327Svbart@nginx.com return; 49427Svbart@nginx.com } 49527Svbart@nginx.com 49662Sigor@sysoev.ru nxt_conn_read(task->thread->engine, c); 49727Svbart@nginx.com return; 49827Svbart@nginx.com } 49927Svbart@nginx.com 50027Svbart@nginx.com /* rc == NXT_ERROR */ 50127Svbart@nginx.com 50227Svbart@nginx.com nxt_log(task, NXT_LOG_ERR, "parsing error"); 50327Svbart@nginx.com 50427Svbart@nginx.com nxt_controller_conn_close(task, c, r); 50527Svbart@nginx.com return; 50627Svbart@nginx.com } 50727Svbart@nginx.com 50867Svbart@nginx.com rc = nxt_http_fields_process(r->parser.fields, r, task->log); 50960Svbart@nginx.com 51060Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 51160Svbart@nginx.com nxt_controller_conn_close(task, c, r); 51260Svbart@nginx.com return; 51360Svbart@nginx.com } 51460Svbart@nginx.com 51527Svbart@nginx.com preread = nxt_buf_mem_used_size(&b->mem); 51627Svbart@nginx.com 51727Svbart@nginx.com nxt_debug(task, "controller request header parsing complete, " 518107Svbart@nginx.com "body length: %uz, preread: %uz", 51927Svbart@nginx.com r->length, preread); 52027Svbart@nginx.com 52127Svbart@nginx.com if (preread >= r->length) { 522140Svbart@nginx.com nxt_controller_process_request(task, r); 52327Svbart@nginx.com return; 52427Svbart@nginx.com } 52527Svbart@nginx.com 52627Svbart@nginx.com if (r->length - preread > (size_t) nxt_buf_mem_free_size(&b->mem)) { 52727Svbart@nginx.com b = nxt_buf_mem_alloc(c->mem_pool, r->length, 0); 52827Svbart@nginx.com if (nxt_slow_path(b == NULL)) { 52927Svbart@nginx.com nxt_controller_conn_free(task, c, NULL); 53027Svbart@nginx.com return; 53127Svbart@nginx.com } 53227Svbart@nginx.com 53327Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, c->read->mem.pos, preread); 53427Svbart@nginx.com 53527Svbart@nginx.com c->read = b; 53627Svbart@nginx.com } 53727Svbart@nginx.com 53827Svbart@nginx.com c->read_state = &nxt_controller_conn_body_read_state; 53927Svbart@nginx.com 54062Sigor@sysoev.ru nxt_conn_read(task->thread->engine, c); 54120Sigor@sysoev.ru } 54220Sigor@sysoev.ru 54320Sigor@sysoev.ru 54420Sigor@sysoev.ru static nxt_msec_t 54562Sigor@sysoev.ru nxt_controller_conn_timeout_value(nxt_conn_t *c, uintptr_t data) 54620Sigor@sysoev.ru { 54720Sigor@sysoev.ru return (nxt_msec_t) data; 54820Sigor@sysoev.ru } 54920Sigor@sysoev.ru 55020Sigor@sysoev.ru 55120Sigor@sysoev.ru static void 55220Sigor@sysoev.ru nxt_controller_conn_read_error(nxt_task_t *task, void *obj, void *data) 55320Sigor@sysoev.ru { 55462Sigor@sysoev.ru nxt_conn_t *c; 55520Sigor@sysoev.ru 55620Sigor@sysoev.ru c = obj; 55720Sigor@sysoev.ru 55820Sigor@sysoev.ru nxt_debug(task, "controller conn read error"); 55920Sigor@sysoev.ru 56027Svbart@nginx.com nxt_controller_conn_close(task, c, data); 56120Sigor@sysoev.ru } 56220Sigor@sysoev.ru 56320Sigor@sysoev.ru 56420Sigor@sysoev.ru static void 56520Sigor@sysoev.ru nxt_controller_conn_read_timeout(nxt_task_t *task, void *obj, void *data) 56620Sigor@sysoev.ru { 56762Sigor@sysoev.ru nxt_timer_t *timer; 56862Sigor@sysoev.ru nxt_conn_t *c; 56920Sigor@sysoev.ru 57062Sigor@sysoev.ru timer = obj; 57120Sigor@sysoev.ru 57262Sigor@sysoev.ru c = nxt_read_timer_conn(timer); 57320Sigor@sysoev.ru c->socket.timedout = 1; 57420Sigor@sysoev.ru c->socket.closed = 1; 57520Sigor@sysoev.ru 57620Sigor@sysoev.ru nxt_debug(task, "controller conn read timeout"); 57720Sigor@sysoev.ru 57827Svbart@nginx.com nxt_controller_conn_close(task, c, data); 57927Svbart@nginx.com } 58027Svbart@nginx.com 58127Svbart@nginx.com 58227Svbart@nginx.com static const nxt_event_conn_state_t nxt_controller_conn_body_read_state 58327Svbart@nginx.com nxt_aligned(64) = 58427Svbart@nginx.com { 58556Sigor@sysoev.ru .ready_handler = nxt_controller_conn_body_read, 58656Sigor@sysoev.ru .close_handler = nxt_controller_conn_close, 58756Sigor@sysoev.ru .error_handler = nxt_controller_conn_read_error, 58827Svbart@nginx.com 58956Sigor@sysoev.ru .timer_handler = nxt_controller_conn_read_timeout, 59056Sigor@sysoev.ru .timer_value = nxt_controller_conn_timeout_value, 59156Sigor@sysoev.ru .timer_data = 60 * 1000, 59256Sigor@sysoev.ru .timer_autoreset = 1, 59327Svbart@nginx.com }; 59427Svbart@nginx.com 59527Svbart@nginx.com 59627Svbart@nginx.com static void 59727Svbart@nginx.com nxt_controller_conn_body_read(nxt_task_t *task, void *obj, void *data) 59827Svbart@nginx.com { 599107Svbart@nginx.com size_t read; 600107Svbart@nginx.com nxt_buf_t *b; 601107Svbart@nginx.com nxt_conn_t *c; 602107Svbart@nginx.com nxt_controller_request_t *r; 60327Svbart@nginx.com 60427Svbart@nginx.com c = obj; 605107Svbart@nginx.com r = data; 60627Svbart@nginx.com b = c->read; 60727Svbart@nginx.com 608107Svbart@nginx.com read = nxt_buf_mem_used_size(&b->mem); 60927Svbart@nginx.com 610107Svbart@nginx.com nxt_debug(task, "controller conn body read: %uz of %uz", 611107Svbart@nginx.com read, r->length); 61227Svbart@nginx.com 613107Svbart@nginx.com if (read >= r->length) { 614140Svbart@nginx.com nxt_controller_process_request(task, r); 61527Svbart@nginx.com return; 61627Svbart@nginx.com } 61727Svbart@nginx.com 61862Sigor@sysoev.ru nxt_conn_read(task->thread->engine, c); 61927Svbart@nginx.com } 62027Svbart@nginx.com 62127Svbart@nginx.com 62227Svbart@nginx.com static const nxt_event_conn_state_t nxt_controller_conn_write_state 62327Svbart@nginx.com nxt_aligned(64) = 62427Svbart@nginx.com { 62556Sigor@sysoev.ru .ready_handler = nxt_controller_conn_write, 62656Sigor@sysoev.ru .error_handler = nxt_controller_conn_write_error, 62727Svbart@nginx.com 62856Sigor@sysoev.ru .timer_handler = nxt_controller_conn_write_timeout, 62956Sigor@sysoev.ru .timer_value = nxt_controller_conn_timeout_value, 63056Sigor@sysoev.ru .timer_data = 60 * 1000, 63156Sigor@sysoev.ru .timer_autoreset = 1, 63227Svbart@nginx.com }; 63327Svbart@nginx.com 63427Svbart@nginx.com 63527Svbart@nginx.com static void 63627Svbart@nginx.com nxt_controller_conn_write(nxt_task_t *task, void *obj, void *data) 63727Svbart@nginx.com { 63862Sigor@sysoev.ru nxt_buf_t *b; 63962Sigor@sysoev.ru nxt_conn_t *c; 64027Svbart@nginx.com 64127Svbart@nginx.com c = obj; 64227Svbart@nginx.com 64327Svbart@nginx.com nxt_debug(task, "controller conn write"); 64427Svbart@nginx.com 64527Svbart@nginx.com b = c->write; 64627Svbart@nginx.com 64727Svbart@nginx.com if (b->mem.pos != b->mem.free) { 64862Sigor@sysoev.ru nxt_conn_write(task->thread->engine, c); 64927Svbart@nginx.com return; 65027Svbart@nginx.com } 65127Svbart@nginx.com 65227Svbart@nginx.com nxt_debug(task, "controller conn write complete"); 65327Svbart@nginx.com 65427Svbart@nginx.com nxt_controller_conn_close(task, c, data); 65527Svbart@nginx.com } 65627Svbart@nginx.com 65727Svbart@nginx.com 65827Svbart@nginx.com static void 65927Svbart@nginx.com nxt_controller_conn_write_error(nxt_task_t *task, void *obj, void *data) 66027Svbart@nginx.com { 66162Sigor@sysoev.ru nxt_conn_t *c; 66227Svbart@nginx.com 66327Svbart@nginx.com c = obj; 66427Svbart@nginx.com 66527Svbart@nginx.com nxt_debug(task, "controller conn write error"); 66627Svbart@nginx.com 66727Svbart@nginx.com nxt_controller_conn_close(task, c, data); 66827Svbart@nginx.com } 66927Svbart@nginx.com 67027Svbart@nginx.com 67127Svbart@nginx.com static void 67227Svbart@nginx.com nxt_controller_conn_write_timeout(nxt_task_t *task, void *obj, void *data) 67327Svbart@nginx.com { 67462Sigor@sysoev.ru nxt_conn_t *c; 67562Sigor@sysoev.ru nxt_timer_t *timer; 67627Svbart@nginx.com 67762Sigor@sysoev.ru timer = obj; 67827Svbart@nginx.com 67962Sigor@sysoev.ru c = nxt_write_timer_conn(timer); 68027Svbart@nginx.com c->socket.timedout = 1; 68127Svbart@nginx.com c->socket.closed = 1; 68227Svbart@nginx.com 68327Svbart@nginx.com nxt_debug(task, "controller conn write timeout"); 68427Svbart@nginx.com 68527Svbart@nginx.com nxt_controller_conn_close(task, c, data); 68620Sigor@sysoev.ru } 68720Sigor@sysoev.ru 68820Sigor@sysoev.ru 68920Sigor@sysoev.ru static const nxt_event_conn_state_t nxt_controller_conn_close_state 69020Sigor@sysoev.ru nxt_aligned(64) = 69120Sigor@sysoev.ru { 69256Sigor@sysoev.ru .ready_handler = nxt_controller_conn_free, 69320Sigor@sysoev.ru }; 69420Sigor@sysoev.ru 69520Sigor@sysoev.ru 69620Sigor@sysoev.ru static void 69720Sigor@sysoev.ru nxt_controller_conn_close(nxt_task_t *task, void *obj, void *data) 69820Sigor@sysoev.ru { 69962Sigor@sysoev.ru nxt_conn_t *c; 70020Sigor@sysoev.ru 70120Sigor@sysoev.ru c = obj; 70220Sigor@sysoev.ru 70320Sigor@sysoev.ru nxt_debug(task, "controller conn close"); 70420Sigor@sysoev.ru 70527Svbart@nginx.com nxt_queue_remove(&c->link); 70627Svbart@nginx.com 70720Sigor@sysoev.ru c->write_state = &nxt_controller_conn_close_state; 70820Sigor@sysoev.ru 70962Sigor@sysoev.ru nxt_conn_close(task->thread->engine, c); 71020Sigor@sysoev.ru } 71120Sigor@sysoev.ru 71220Sigor@sysoev.ru 71320Sigor@sysoev.ru static void 71420Sigor@sysoev.ru nxt_controller_conn_free(nxt_task_t *task, void *obj, void *data) 71520Sigor@sysoev.ru { 71662Sigor@sysoev.ru nxt_conn_t *c; 71720Sigor@sysoev.ru 71820Sigor@sysoev.ru c = obj; 71920Sigor@sysoev.ru 72020Sigor@sysoev.ru nxt_debug(task, "controller conn free"); 72120Sigor@sysoev.ru 722337Sigor@sysoev.ru nxt_sockaddr_cache_free(task->thread->engine, c); 723337Sigor@sysoev.ru 724*386Sigor@sysoev.ru nxt_conn_free(task, c); 72520Sigor@sysoev.ru } 72627Svbart@nginx.com 72727Svbart@nginx.com 72827Svbart@nginx.com static nxt_int_t 72960Svbart@nginx.com nxt_controller_request_content_length(void *ctx, nxt_http_field_t *field, 73067Svbart@nginx.com nxt_log_t *log) 73127Svbart@nginx.com { 73227Svbart@nginx.com off_t length; 73327Svbart@nginx.com nxt_controller_request_t *r; 73427Svbart@nginx.com 73527Svbart@nginx.com r = ctx; 73627Svbart@nginx.com 73760Svbart@nginx.com length = nxt_off_t_parse(field->value.start, field->value.length); 73827Svbart@nginx.com 73927Svbart@nginx.com if (nxt_fast_path(length > 0)) { 740107Svbart@nginx.com 741107Svbart@nginx.com if (nxt_slow_path(length > NXT_SIZE_T_MAX)) { 742107Svbart@nginx.com nxt_log_error(NXT_LOG_ERR, log, "Content-Length is too big"); 743107Svbart@nginx.com return NXT_ERROR; 744107Svbart@nginx.com } 74527Svbart@nginx.com 74627Svbart@nginx.com r->length = length; 74727Svbart@nginx.com return NXT_OK; 74827Svbart@nginx.com } 74927Svbart@nginx.com 75060Svbart@nginx.com nxt_log_error(NXT_LOG_ERR, log, "Content-Length is invalid"); 75127Svbart@nginx.com 75227Svbart@nginx.com return NXT_ERROR; 75327Svbart@nginx.com } 75427Svbart@nginx.com 75527Svbart@nginx.com 75627Svbart@nginx.com static void 757140Svbart@nginx.com nxt_controller_process_request(nxt_task_t *task, nxt_controller_request_t *req) 75827Svbart@nginx.com { 75965Sigor@sysoev.ru nxt_mp_t *mp; 76051Svbart@nginx.com nxt_int_t rc; 76146Svbart@nginx.com nxt_str_t path; 762140Svbart@nginx.com nxt_conn_t *c; 76351Svbart@nginx.com nxt_buf_mem_t *mbuf; 764106Svbart@nginx.com nxt_conf_op_t *ops; 765106Svbart@nginx.com nxt_conf_value_t *value; 766357Svbart@nginx.com nxt_conf_validation_t vldt; 767208Svbart@nginx.com nxt_conf_json_error_t error; 76844Svbart@nginx.com nxt_controller_response_t resp; 76944Svbart@nginx.com 77051Svbart@nginx.com static const nxt_str_t empty_obj = nxt_string("{}"); 77151Svbart@nginx.com 772140Svbart@nginx.com c = req->conn; 773112Smax.romanov@nginx.com path = req->parser.path; 77451Svbart@nginx.com 77551Svbart@nginx.com if (path.length > 1 && path.start[path.length - 1] == '/') { 77651Svbart@nginx.com path.length--; 77751Svbart@nginx.com } 77851Svbart@nginx.com 77944Svbart@nginx.com nxt_memzero(&resp, sizeof(nxt_controller_response_t)); 78044Svbart@nginx.com 78144Svbart@nginx.com if (nxt_str_eq(&req->parser.method, "GET", 3)) { 78246Svbart@nginx.com 783106Svbart@nginx.com value = nxt_conf_get_path(nxt_controller_conf.root, &path); 78451Svbart@nginx.com 78551Svbart@nginx.com if (value == NULL) { 786208Svbart@nginx.com goto not_found; 78751Svbart@nginx.com } 78851Svbart@nginx.com 789208Svbart@nginx.com resp.status = 200; 790106Svbart@nginx.com resp.conf = value; 79146Svbart@nginx.com 792208Svbart@nginx.com nxt_controller_response(task, req, &resp); 793208Svbart@nginx.com return; 79451Svbart@nginx.com } 79551Svbart@nginx.com 79651Svbart@nginx.com if (nxt_str_eq(&req->parser.method, "PUT", 3)) { 79746Svbart@nginx.com 798238Svbart@nginx.com if (!nxt_queue_is_empty(&nxt_controller_waiting_requests)) { 799238Svbart@nginx.com nxt_queue_insert_tail(&nxt_controller_waiting_requests, &req->link); 800238Svbart@nginx.com return; 801238Svbart@nginx.com } 802238Svbart@nginx.com 80365Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 80451Svbart@nginx.com 80551Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 806208Svbart@nginx.com goto alloc_fail; 80746Svbart@nginx.com } 80846Svbart@nginx.com 80951Svbart@nginx.com mbuf = &c->read->mem; 81051Svbart@nginx.com 811208Svbart@nginx.com nxt_memzero(&error, sizeof(nxt_conf_json_error_t)); 812208Svbart@nginx.com 813208Svbart@nginx.com value = nxt_conf_json_parse(mp, mbuf->pos, mbuf->free, &error); 81451Svbart@nginx.com 81551Svbart@nginx.com if (value == NULL) { 81665Sigor@sysoev.ru nxt_mp_destroy(mp); 817208Svbart@nginx.com 818208Svbart@nginx.com if (error.pos == NULL) { 819208Svbart@nginx.com goto alloc_fail; 820208Svbart@nginx.com } 821208Svbart@nginx.com 822208Svbart@nginx.com resp.status = 400; 823208Svbart@nginx.com resp.title = (u_char *) "Invalid JSON."; 824357Svbart@nginx.com resp.detail.length = nxt_strlen(error.detail); 825357Svbart@nginx.com resp.detail.start = error.detail; 826208Svbart@nginx.com resp.offset = error.pos - mbuf->pos; 827208Svbart@nginx.com 828208Svbart@nginx.com nxt_conf_json_position(mbuf->pos, error.pos, 829208Svbart@nginx.com &resp.line, &resp.column); 830208Svbart@nginx.com 831208Svbart@nginx.com nxt_controller_response(task, req, &resp); 832208Svbart@nginx.com return; 83351Svbart@nginx.com } 83451Svbart@nginx.com 83551Svbart@nginx.com if (path.length != 1) { 836106Svbart@nginx.com rc = nxt_conf_op_compile(c->mem_pool, &ops, 837106Svbart@nginx.com nxt_controller_conf.root, 838106Svbart@nginx.com &path, value); 83946Svbart@nginx.com 84051Svbart@nginx.com if (rc != NXT_OK) { 84151Svbart@nginx.com if (rc == NXT_DECLINED) { 842208Svbart@nginx.com goto not_found; 84351Svbart@nginx.com } 84446Svbart@nginx.com 845208Svbart@nginx.com goto alloc_fail; 84651Svbart@nginx.com } 84751Svbart@nginx.com 848106Svbart@nginx.com value = nxt_conf_clone(mp, ops, nxt_controller_conf.root); 84951Svbart@nginx.com 85051Svbart@nginx.com if (nxt_slow_path(value == NULL)) { 85165Sigor@sysoev.ru nxt_mp_destroy(mp); 852208Svbart@nginx.com goto alloc_fail; 85351Svbart@nginx.com } 85446Svbart@nginx.com } 85544Svbart@nginx.com 856357Svbart@nginx.com nxt_memzero(&vldt, sizeof(nxt_conf_validation_t)); 857357Svbart@nginx.com 858357Svbart@nginx.com vldt.conf = value; 859357Svbart@nginx.com vldt.pool = c->mem_pool; 860357Svbart@nginx.com 861357Svbart@nginx.com rc = nxt_conf_validate(&vldt); 862357Svbart@nginx.com 863357Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 864121Svbart@nginx.com nxt_mp_destroy(mp); 865357Svbart@nginx.com 866357Svbart@nginx.com if (rc == NXT_DECLINED) { 867357Svbart@nginx.com resp.detail = vldt.error; 868357Svbart@nginx.com goto invalid_conf; 869357Svbart@nginx.com } 870357Svbart@nginx.com 871357Svbart@nginx.com /* rc == NXT_ERROR */ 872357Svbart@nginx.com goto alloc_fail; 873116Svbart@nginx.com } 874116Svbart@nginx.com 875249Svbart@nginx.com rc = nxt_controller_conf_send(task, value, 876249Svbart@nginx.com nxt_controller_conf_handler, req); 877247Svbart@nginx.com 878247Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 879121Svbart@nginx.com nxt_mp_destroy(mp); 880247Svbart@nginx.com 881247Svbart@nginx.com if (rc == NXT_DECLINED) { 882247Svbart@nginx.com goto no_router; 883247Svbart@nginx.com } 884247Svbart@nginx.com 885247Svbart@nginx.com /* rc == NXT_ERROR */ 886208Svbart@nginx.com goto alloc_fail; 887121Svbart@nginx.com } 888121Svbart@nginx.com 889249Svbart@nginx.com req->conf.root = value; 890249Svbart@nginx.com req->conf.pool = mp; 891249Svbart@nginx.com 892249Svbart@nginx.com nxt_queue_insert_head(&nxt_controller_waiting_requests, &req->link); 893249Svbart@nginx.com 894140Svbart@nginx.com return; 89551Svbart@nginx.com } 89627Svbart@nginx.com 89751Svbart@nginx.com if (nxt_str_eq(&req->parser.method, "DELETE", 6)) { 89851Svbart@nginx.com 899238Svbart@nginx.com if (!nxt_queue_is_empty(&nxt_controller_waiting_requests)) { 900238Svbart@nginx.com nxt_queue_insert_tail(&nxt_controller_waiting_requests, &req->link); 901238Svbart@nginx.com return; 902238Svbart@nginx.com } 903238Svbart@nginx.com 90451Svbart@nginx.com if (path.length == 1) { 90565Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 90644Svbart@nginx.com 90751Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 908208Svbart@nginx.com goto alloc_fail; 90951Svbart@nginx.com } 91051Svbart@nginx.com 911106Svbart@nginx.com value = nxt_conf_json_parse_str(mp, &empty_obj); 91227Svbart@nginx.com 91344Svbart@nginx.com } else { 914106Svbart@nginx.com rc = nxt_conf_op_compile(c->mem_pool, &ops, 915106Svbart@nginx.com nxt_controller_conf.root, 916106Svbart@nginx.com &path, NULL); 91751Svbart@nginx.com 91851Svbart@nginx.com if (rc != NXT_OK) { 91951Svbart@nginx.com if (rc == NXT_DECLINED) { 920208Svbart@nginx.com goto not_found; 92151Svbart@nginx.com } 92251Svbart@nginx.com 923208Svbart@nginx.com goto alloc_fail; 92451Svbart@nginx.com } 92551Svbart@nginx.com 92665Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 92751Svbart@nginx.com 92851Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 929208Svbart@nginx.com goto alloc_fail; 93051Svbart@nginx.com } 93151Svbart@nginx.com 932106Svbart@nginx.com value = nxt_conf_clone(mp, ops, nxt_controller_conf.root); 93351Svbart@nginx.com } 93451Svbart@nginx.com 93551Svbart@nginx.com if (nxt_slow_path(value == NULL)) { 93665Sigor@sysoev.ru nxt_mp_destroy(mp); 937208Svbart@nginx.com goto alloc_fail; 93844Svbart@nginx.com } 93944Svbart@nginx.com 940357Svbart@nginx.com nxt_memzero(&vldt, sizeof(nxt_conf_validation_t)); 941357Svbart@nginx.com 942357Svbart@nginx.com vldt.conf = value; 943357Svbart@nginx.com vldt.pool = c->mem_pool; 944357Svbart@nginx.com 945357Svbart@nginx.com rc = nxt_conf_validate(&vldt); 946357Svbart@nginx.com 947357Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 948121Svbart@nginx.com nxt_mp_destroy(mp); 949357Svbart@nginx.com 950357Svbart@nginx.com if (rc == NXT_DECLINED) { 951357Svbart@nginx.com resp.detail = vldt.error; 952357Svbart@nginx.com goto invalid_conf; 953357Svbart@nginx.com } 954357Svbart@nginx.com 955357Svbart@nginx.com /* rc == NXT_ERROR */ 956357Svbart@nginx.com goto alloc_fail; 957116Svbart@nginx.com } 958116Svbart@nginx.com 959249Svbart@nginx.com rc = nxt_controller_conf_send(task, value, 960249Svbart@nginx.com nxt_controller_conf_handler, req); 961247Svbart@nginx.com 962247Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 963121Svbart@nginx.com nxt_mp_destroy(mp); 964247Svbart@nginx.com 965247Svbart@nginx.com if (rc == NXT_DECLINED) { 966247Svbart@nginx.com goto no_router; 967247Svbart@nginx.com } 968247Svbart@nginx.com 969247Svbart@nginx.com /* rc == NXT_ERROR */ 970208Svbart@nginx.com goto alloc_fail; 971121Svbart@nginx.com } 972121Svbart@nginx.com 973249Svbart@nginx.com req->conf.root = value; 974249Svbart@nginx.com req->conf.pool = mp; 975249Svbart@nginx.com 976249Svbart@nginx.com nxt_queue_insert_head(&nxt_controller_waiting_requests, &req->link); 977249Svbart@nginx.com 978140Svbart@nginx.com return; 97951Svbart@nginx.com } 98051Svbart@nginx.com 981208Svbart@nginx.com resp.status = 405; 982208Svbart@nginx.com resp.title = (u_char *) "Invalid method."; 983208Svbart@nginx.com resp.offset = -1; 98451Svbart@nginx.com 985208Svbart@nginx.com nxt_controller_response(task, req, &resp); 986208Svbart@nginx.com return; 98751Svbart@nginx.com 988208Svbart@nginx.com not_found: 989208Svbart@nginx.com 990208Svbart@nginx.com resp.status = 404; 991208Svbart@nginx.com resp.title = (u_char *) "Value doesn't exist."; 992208Svbart@nginx.com resp.offset = -1; 993208Svbart@nginx.com 994208Svbart@nginx.com nxt_controller_response(task, req, &resp); 995208Svbart@nginx.com return; 996208Svbart@nginx.com 997208Svbart@nginx.com invalid_conf: 998208Svbart@nginx.com 999208Svbart@nginx.com resp.status = 400; 1000208Svbart@nginx.com resp.title = (u_char *) "Invalid configuration."; 1001208Svbart@nginx.com resp.offset = -1; 1002208Svbart@nginx.com 1003208Svbart@nginx.com nxt_controller_response(task, req, &resp); 1004208Svbart@nginx.com return; 1005247Svbart@nginx.com 1006247Svbart@nginx.com alloc_fail: 1007247Svbart@nginx.com 1008247Svbart@nginx.com resp.status = 500; 1009247Svbart@nginx.com resp.title = (u_char *) "Memory allocation failed."; 1010247Svbart@nginx.com resp.offset = -1; 1011247Svbart@nginx.com 1012247Svbart@nginx.com nxt_controller_response(task, req, &resp); 1013247Svbart@nginx.com return; 1014247Svbart@nginx.com 1015247Svbart@nginx.com no_router: 1016247Svbart@nginx.com 1017247Svbart@nginx.com resp.status = 500; 1018247Svbart@nginx.com resp.title = (u_char *) "Router process isn't available."; 1019247Svbart@nginx.com resp.offset = -1; 1020247Svbart@nginx.com 1021247Svbart@nginx.com nxt_controller_response(task, req, &resp); 1022247Svbart@nginx.com return; 102327Svbart@nginx.com } 102427Svbart@nginx.com 102527Svbart@nginx.com 1026193Smax.romanov@nginx.com static void 1027193Smax.romanov@nginx.com nxt_controller_conf_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 1028193Smax.romanov@nginx.com void *data) 1029140Svbart@nginx.com { 1030238Svbart@nginx.com nxt_queue_t queue; 1031140Svbart@nginx.com nxt_controller_request_t *req; 1032140Svbart@nginx.com nxt_controller_response_t resp; 1033140Svbart@nginx.com 1034238Svbart@nginx.com req = data; 1035238Svbart@nginx.com 1036201Svbart@nginx.com nxt_debug(task, "controller conf ready: %*s", 1037201Svbart@nginx.com nxt_buf_mem_used_size(&msg->buf->mem), msg->buf->mem.pos); 1038140Svbart@nginx.com 1039238Svbart@nginx.com nxt_queue_remove(&req->link); 1040140Svbart@nginx.com 1041238Svbart@nginx.com nxt_memzero(&resp, sizeof(nxt_controller_response_t)); 1042140Svbart@nginx.com 1043193Smax.romanov@nginx.com if (msg->