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, 68417Svbart@nginx.com nxt_http_field_t *field, uintptr_t data); 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 82417Svbart@nginx.com static nxt_http_field_proc_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 87417Svbart@nginx.com static nxt_lvlhsh_t nxt_controller_fields_hash; 8827Svbart@nginx.com 89314Svbart@nginx.com static nxt_uint_t nxt_controller_listening; 90238Svbart@nginx.com static nxt_controller_conf_t nxt_controller_conf; 91238Svbart@nginx.com static nxt_queue_t nxt_controller_waiting_requests; 9227Svbart@nginx.com 9320Sigor@sysoev.ru 9420Sigor@sysoev.ru static const nxt_event_conn_state_t nxt_controller_conn_read_state; 9527Svbart@nginx.com static const nxt_event_conn_state_t nxt_controller_conn_body_read_state; 9627Svbart@nginx.com static const nxt_event_conn_state_t nxt_controller_conn_write_state; 9720Sigor@sysoev.ru static const nxt_event_conn_state_t nxt_controller_conn_close_state; 9820Sigor@sysoev.ru 9920Sigor@sysoev.ru 100320Smax.romanov@nginx.com nxt_port_handlers_t nxt_controller_process_port_handlers = { 101320Smax.romanov@nginx.com .quit = nxt_worker_process_quit_handler, 102320Smax.romanov@nginx.com .new_port = nxt_controller_process_new_port_handler, 103320Smax.romanov@nginx.com .change_file = nxt_port_change_log_file_handler, 104320Smax.romanov@nginx.com .mmap = nxt_port_mmap_handler, 105320Smax.romanov@nginx.com .data = nxt_port_data_handler, 106320Smax.romanov@nginx.com .remove_pid = nxt_port_remove_pid_handler, 107320Smax.romanov@nginx.com .rpc_ready = nxt_port_rpc_handler, 108320Smax.romanov@nginx.com .rpc_error = nxt_port_rpc_handler, 109248Svbart@nginx.com }; 110248Svbart@nginx.com 111248Svbart@nginx.com 11220Sigor@sysoev.ru nxt_int_t 113141Smax.romanov@nginx.com nxt_controller_start(nxt_task_t *task, void *data) 11420Sigor@sysoev.ru { 115417Svbart@nginx.com nxt_mp_t *mp; 116417Svbart@nginx.com nxt_int_t ret; 117417Svbart@nginx.com nxt_str_t *json; 118417Svbart@nginx.com nxt_runtime_t *rt; 119417Svbart@nginx.com nxt_conf_value_t *conf; 120417Svbart@nginx.com nxt_event_engine_t *engine; 121417Svbart@nginx.com nxt_conf_validation_t vldt; 12227Svbart@nginx.com 123141Smax.romanov@nginx.com rt = task->thread->runtime; 124141Smax.romanov@nginx.com 125337Sigor@sysoev.ru engine = task->thread->engine; 126337Sigor@sysoev.ru 127337Sigor@sysoev.ru engine->mem_pool = nxt_mp_create(4096, 128, 1024, 64); 128337Sigor@sysoev.ru if (nxt_slow_path(engine->mem_pool == NULL)) { 129337Sigor@sysoev.ru return NXT_ERROR; 130337Sigor@sysoev.ru } 131337Sigor@sysoev.ru 132417Svbart@nginx.com ret = nxt_http_fields_hash(&nxt_controller_fields_hash, rt->mem_pool, 133417Svbart@nginx.com nxt_controller_request_fields, 134417Svbart@nginx.com nxt_nitems(nxt_controller_request_fields)); 135417Svbart@nginx.com 136417Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 13727Svbart@nginx.com return NXT_ERROR; 13827Svbart@nginx.com } 13927Svbart@nginx.com 140248Svbart@nginx.com nxt_queue_init(&nxt_controller_waiting_requests); 14127Svbart@nginx.com 142314Svbart@nginx.com json = data; 143314Svbart@nginx.com 144314Svbart@nginx.com if (json->length == 0) { 145314Svbart@nginx.com return NXT_OK; 146314Svbart@nginx.com } 147314Svbart@nginx.com 148314Svbart@nginx.com mp = nxt_mp_create(1024, 128, 256, 32); 149314Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 150314Svbart@nginx.com return NXT_ERROR; 151314Svbart@nginx.com } 152314Svbart@nginx.com 153314Svbart@nginx.com conf = nxt_conf_json_parse_str(mp, json); 154314Svbart@nginx.com nxt_free(json->start); 155314Svbart@nginx.com 156314Svbart@nginx.com if (nxt_slow_path(conf == NULL)) { 157564Svbart@nginx.com nxt_alert(task, "failed to restore previous configuration: " 158564Svbart@nginx.com "file is corrupted or not enough memory"); 159314Svbart@nginx.com 160314Svbart@nginx.com nxt_mp_destroy(mp); 161314Svbart@nginx.com return NXT_OK; 162314Svbart@nginx.com } 163314Svbart@nginx.com 164357Svbart@nginx.com nxt_memzero(&vldt, sizeof(nxt_conf_validation_t)); 165314Svbart@nginx.com 166357Svbart@nginx.com vldt.pool = nxt_mp_create(1024, 128, 256, 32); 167357Svbart@nginx.com if (nxt_slow_path(vldt.pool == NULL)) { 168357Svbart@nginx.com return NXT_ERROR; 169314Svbart@nginx.com } 170314Svbart@nginx.com 171357Svbart@nginx.com vldt.conf = conf; 172357Svbart@nginx.com 173357Svbart@nginx.com ret = nxt_conf_validate(&vldt); 174357Svbart@nginx.com 175357Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 176357Svbart@nginx.com 177357Svbart@nginx.com if (ret == NXT_DECLINED) { 178564Svbart@nginx.com nxt_alert(task, "the previous configuration is invalid: %V", 179564Svbart@nginx.com &vldt.error); 180357Svbart@nginx.com 181357Svbart@nginx.com nxt_mp_destroy(vldt.pool); 182357Svbart@nginx.com nxt_mp_destroy(mp); 183357Svbart@nginx.com 184357Svbart@nginx.com return NXT_OK; 185357Svbart@nginx.com } 186357Svbart@nginx.com 187357Svbart@nginx.com /* ret == NXT_ERROR */ 188357Svbart@nginx.com 189357Svbart@nginx.com return NXT_ERROR; 190357Svbart@nginx.com } 191357Svbart@nginx.com 192357Svbart@nginx.com nxt_mp_destroy(vldt.pool); 193314Svbart@nginx.com 194314Svbart@nginx.com nxt_controller_conf.root = conf; 195314Svbart@nginx.com nxt_controller_conf.pool = mp; 196314Svbart@nginx.com 197248Svbart@nginx.com return NXT_OK; 198248Svbart@nginx.com } 199248Svbart@nginx.com 200248Svbart@nginx.com 201248Svbart@nginx.com static void 202248Svbart@nginx.com nxt_controller_process_new_port_handler(nxt_task_t *task, 203248Svbart@nginx.com nxt_port_recv_msg_t *msg) 204248Svbart@nginx.com { 205249Svbart@nginx.com nxt_int_t rc; 206248Svbart@nginx.com nxt_runtime_t *rt; 207248Svbart@nginx.com nxt_conf_value_t *conf; 208248Svbart@nginx.com 209248Svbart@nginx.com nxt_port_new_port_handler(task, msg); 210248Svbart@nginx.com 211347Smax.romanov@nginx.com if (msg->u.new_port->type != NXT_PROCESS_ROUTER) { 212248Svbart@nginx.com return; 21320Sigor@sysoev.ru } 21420Sigor@sysoev.ru 215249Svbart@nginx.com conf = nxt_controller_conf.root; 216249Svbart@nginx.com 217249Svbart@nginx.com if (conf != NULL) { 218249Svbart@nginx.com rc = nxt_controller_conf_send(task, conf, 219249Svbart@nginx.com nxt_controller_conf_init_handler, NULL); 22044Svbart@nginx.com 221249Svbart@nginx.com if (nxt_fast_path(rc == NXT_OK)) { 222249Svbart@nginx.com return; 223249Svbart@nginx.com } 224249Svbart@nginx.com 225249Svbart@nginx.com nxt_mp_destroy(nxt_controller_conf.pool); 226249Svbart@nginx.com 227249Svbart@nginx.com if (nxt_slow_path(nxt_controller_conf_default() != NXT_OK)) { 228249Svbart@nginx.com nxt_abort(); 229249Svbart@nginx.com } 23044Svbart@nginx.com } 23144Svbart@nginx.com 232249Svbart@nginx.com if (nxt_slow_path(nxt_controller_conf_default() != NXT_OK)) { 233248Svbart@nginx.com nxt_abort(); 23444Svbart@nginx.com } 23544Svbart@nginx.com 236248Svbart@nginx.com rt = task->thread->runtime; 237140Svbart@nginx.com 238248Svbart@nginx.com if (nxt_slow_path(nxt_listen_event(task, rt->controller_socket) == NULL)) { 239248Svbart@nginx.com nxt_abort(); 240248Svbart@nginx.com } 241314Svbart@nginx.com 242314Svbart@nginx.com nxt_controller_listening = 1; 24320Sigor@sysoev.ru } 24420Sigor@sysoev.ru 24520Sigor@sysoev.ru 246249Svbart@nginx.com static nxt_int_t 247249Svbart@nginx.com nxt_controller_conf_default(void) 248249Svbart@nginx.com { 249249Svbart@nginx.com nxt_mp_t *mp; 250249Svbart@nginx.com nxt_conf_value_t *conf; 251249Svbart@nginx.com 252249Svbart@nginx.com static const nxt_str_t json 253249Svbart@nginx.com = nxt_string("{ \"listeners\": {}, \"applications\": {} }"); 254249Svbart@nginx.com 255249Svbart@nginx.com mp = nxt_mp_create(1024, 128, 256, 32); 256249Svbart@nginx.com 257249Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 258249Svbart@nginx.com return NXT_ERROR; 259249Svbart@nginx.com } 260249Svbart@nginx.com 261249Svbart@nginx.com conf = nxt_conf_json_parse_str(mp, &json); 262249Svbart@nginx.com 263249Svbart@nginx.com if (nxt_slow_path(conf == NULL)) { 264249Svbart@nginx.com return NXT_ERROR; 265249Svbart@nginx.com } 266249Svbart@nginx.com 267249Svbart@nginx.com nxt_controller_conf.root = conf; 268249Svbart@nginx.com nxt_controller_conf.pool = mp; 269249Svbart@nginx.com 270249Svbart@nginx.com return NXT_OK; 271249Svbart@nginx.com } 272249Svbart@nginx.com 273249Svbart@nginx.com 274249Svbart@nginx.com static void 275249Svbart@nginx.com nxt_controller_conf_init_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 276249Svbart@nginx.com void *data) 277249Svbart@nginx.com { 278314Svbart@nginx.com nxt_runtime_t *rt; 279314Svbart@nginx.com 280249Svbart@nginx.com if (msg->port_msg.type != NXT_PORT_MSG_RPC_READY) { 281564Svbart@nginx.com nxt_alert(task, "failed to apply previous configuration"); 282314Svbart@nginx.com 283249Svbart@nginx.com nxt_mp_destroy(nxt_controller_conf.pool); 284249Svbart@nginx.com 285249Svbart@nginx.com if (nxt_slow_path(nxt_controller_conf_default() != NXT_OK)) { 286249Svbart@nginx.com nxt_abort(); 287249Svbart@nginx.com } 288249Svbart@nginx.com } 289314Svbart@nginx.com 290314Svbart@nginx.com if (nxt_controller_listening == 0) { 291314Svbart@nginx.com rt = task->thread->runtime; 292314Svbart@nginx.com 293314Svbart@nginx.com if (nxt_slow_path(nxt_listen_event(task, rt->controller_socket) 294314Svbart@nginx.com == NULL)) 295314Svbart@nginx.com { 296314Svbart@nginx.com nxt_abort(); 297314Svbart@nginx.com } 298314Svbart@nginx.com 299314Svbart@nginx.com nxt_controller_listening = 1; 300314Svbart@nginx.com } 301249Svbart@nginx.com } 302249Svbart@nginx.com 303249Svbart@nginx.com 304249Svbart@nginx.com static nxt_int_t 305249Svbart@nginx.com nxt_controller_conf_send(nxt_task_t *task, nxt_conf_value_t *conf, 306249Svbart@nginx.com nxt_port_rpc_handler_t handler, void *data) 307249Svbart@nginx.com { 308249Svbart@nginx.com size_t size; 309249Svbart@nginx.com uint32_t stream; 310249Svbart@nginx.com nxt_int_t rc; 311249Svbart@nginx.com nxt_buf_t *b; 312249Svbart@nginx.com nxt_port_t *router_port, *controller_port; 313249Svbart@nginx.com nxt_runtime_t *rt; 314249Svbart@nginx.com 315249Svbart@nginx.com rt = task->thread->runtime; 316249Svbart@nginx.com 317249Svbart@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 318249Svbart@nginx.com 319249Svbart@nginx.com if (nxt_slow_path(router_port == NULL)) { 320249Svbart@nginx.com return NXT_DECLINED; 321249Svbart@nginx.com } 322249Svbart@nginx.com 323249Svbart@nginx.com controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER]; 324249Svbart@nginx.com 325249Svbart@nginx.com size = nxt_conf_json_length(conf, NULL); 326249Svbart@nginx.com 327249Svbart@nginx.com b = nxt_port_mmap_get_buf(task, router_port, size); 328379Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 329379Smax.romanov@nginx.com return NXT_ERROR; 330379Smax.romanov@nginx.com } 331249Svbart@nginx.com 332249Svbart@nginx.com b->mem.free = nxt_conf_json_print(b->mem.free, conf, NULL); 333249Svbart@nginx.com 334249Svbart@nginx.com stream = nxt_port_rpc_register_handler(task, controller_port, 335249Svbart@nginx.com handler, handler, 336249Svbart@nginx.com router_port->pid, data); 337249Svbart@nginx.com 338249Svbart@nginx.com rc = nxt_port_socket_write(task, router_port, NXT_PORT_MSG_DATA_LAST, -1, 339249Svbart@nginx.com stream, controller_port->id, b); 340249Svbart@nginx.com 341249Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 342249Svbart@nginx.com nxt_port_rpc_cancel(task, controller_port, stream); 343249Svbart@nginx.com return NXT_ERROR; 344249Svbart@nginx.com } 345249Svbart@nginx.com 346249Svbart@nginx.com return NXT_OK; 347249Svbart@nginx.com } 348249Svbart@nginx.com 349249Svbart@nginx.com 35020Sigor@sysoev.ru nxt_int_t 35120Sigor@sysoev.ru nxt_runtime_controller_socket(nxt_task_t *task, nxt_runtime_t *rt) 35220Sigor@sysoev.ru { 35320Sigor@sysoev.ru nxt_sockaddr_t *sa; 35420Sigor@sysoev.ru nxt_listen_socket_t *ls; 35520Sigor@sysoev.ru 35620Sigor@sysoev.ru sa = rt->controller_listen; 35720Sigor@sysoev.ru 35865Sigor@sysoev.ru ls = nxt_mp_alloc(rt->mem_pool, sizeof(nxt_listen_socket_t)); 35920Sigor@sysoev.ru if (ls == NULL) { 36020Sigor@sysoev.ru return NXT_ERROR; 36120Sigor@sysoev.ru } 36220Sigor@sysoev.ru 36320Sigor@sysoev.ru ls->sockaddr = nxt_sockaddr_create(rt->mem_pool, &sa->u.sockaddr, 36420Sigor@sysoev.ru sa->socklen, sa->length); 36520Sigor@sysoev.ru if (ls->sockaddr == NULL) { 36620Sigor@sysoev.ru return NXT_ERROR; 36720Sigor@sysoev.ru } 36820Sigor@sysoev.ru 36920Sigor@sysoev.ru ls->sockaddr->type = sa->type; 370312Sigor@sysoev.ru nxt_sockaddr_text(ls->sockaddr); 37120Sigor@sysoev.ru 372359Sigor@sysoev.ru nxt_listen_socket_remote_size(ls); 37320Sigor@sysoev.ru 37420Sigor@sysoev.ru ls->socket = -1; 37520Sigor@sysoev.ru ls->backlog = NXT_LISTEN_BACKLOG; 37620Sigor@sysoev.ru ls->read_after_accept = 1; 37720Sigor@sysoev.ru ls->flags = NXT_NONBLOCK; 37820Sigor@sysoev.ru 37920Sigor@sysoev.ru #if 0 38020Sigor@sysoev.ru /* STUB */ 38165Sigor@sysoev.ru wq = nxt_mp_zget(cf->mem_pool, sizeof(nxt_work_queue_t)); 38220Sigor@sysoev.ru if (wq == NULL) { 38320Sigor@sysoev.ru return NXT_ERROR; 38420Sigor@sysoev.ru } 38520Sigor@sysoev.ru nxt_work_queue_name(wq, "listen"); 38620Sigor@sysoev.ru /**/ 38720Sigor@sysoev.ru 38820Sigor@sysoev.ru ls->work_queue = wq; 38920Sigor@sysoev.ru #endif 39020Sigor@sysoev.ru ls->handler = nxt_controller_conn_init; 39120Sigor@sysoev.ru 39220Sigor@sysoev.ru if (nxt_listen_socket_create(task, ls, 0) != NXT_OK) { 39320Sigor@sysoev.ru return NXT_ERROR; 39420Sigor@sysoev.ru } 39520Sigor@sysoev.ru 39620Sigor@sysoev.ru rt->controller_socket = ls; 39720Sigor@sysoev.ru 39820Sigor@sysoev.ru return NXT_OK; 39920Sigor@sysoev.ru } 40020Sigor@sysoev.ru 40120Sigor@sysoev.ru 40220Sigor@sysoev.ru static void 40320Sigor@sysoev.ru nxt_controller_conn_init(nxt_task_t *task, void *obj, void *data) 40420Sigor@sysoev.ru { 40527Svbart@nginx.com nxt_buf_t *b; 40662Sigor@sysoev.ru nxt_conn_t *c; 40727Svbart@nginx.com nxt_event_engine_t *engine; 40827Svbart@nginx.com nxt_controller_request_t *r; 40920Sigor@sysoev.ru 41020Sigor@sysoev.ru c = obj; 41120Sigor@sysoev.ru 41220Sigor@sysoev.ru nxt_debug(task, "controller conn init fd:%d", c->socket.fd); 41320Sigor@sysoev.ru 41465Sigor@sysoev.ru r = nxt_mp_zget(c->mem_pool, sizeof(nxt_controller_request_t)); 41527Svbart@nginx.com if (nxt_slow_path(r == NULL)) { 41627Svbart@nginx.com nxt_controller_conn_free(task, c, NULL); 41727Svbart@nginx.com return; 41827Svbart@nginx.com } 41927Svbart@nginx.com 420140Svbart@nginx.com r->conn = c; 421140Svbart@nginx.com 42260Svbart@nginx.com if (nxt_slow_path(nxt_http_parse_request_init(&r->parser, c->mem_pool) 42360Svbart@nginx.com != NXT_OK)) 42460Svbart@nginx.com { 42560Svbart@nginx.com nxt_controller_conn_free(task, c, NULL); 42660Svbart@nginx.com return; 42760Svbart@nginx.com } 42827Svbart@nginx.com 42920Sigor@sysoev.ru b = nxt_buf_mem_alloc(c->mem_pool, 1024, 0); 43020Sigor@sysoev.ru if (nxt_slow_path(b == NULL)) { 43120Sigor@sysoev.ru nxt_controller_conn_free(task, c, NULL); 43220Sigor@sysoev.ru return; 43320Sigor@sysoev.ru } 43420Sigor@sysoev.ru 43520Sigor@sysoev.ru c->read = b; 43627Svbart@nginx.com c->socket.data = r; 43720Sigor@sysoev.ru c->socket.read_ready = 1; 43820Sigor@sysoev.ru c->read_state = &nxt_controller_conn_read_state; 43920Sigor@sysoev.ru 44020Sigor@sysoev.ru engine = task->thread->engine; 44120Sigor@sysoev.ru c->read_work_queue = &engine->read_work_queue; 44227Svbart@nginx.com c->write_work_queue = &engine->write_work_queue; 44320Sigor@sysoev.ru 44462Sigor@sysoev.ru nxt_conn_read(engine, c); 44520Sigor@sysoev.ru } 44620Sigor@sysoev.ru 44720Sigor@sysoev.ru 44820Sigor@sysoev.ru static const nxt_event_conn_state_t nxt_controller_conn_read_state 44920Sigor@sysoev.ru nxt_aligned(64) = 45020Sigor@sysoev.ru { 45156Sigor@sysoev.ru .ready_handler = nxt_controller_conn_read, 45256Sigor@sysoev.ru .close_handler = nxt_controller_conn_close, 45356Sigor@sysoev.ru .error_handler = nxt_controller_conn_read_error, 45420Sigor@sysoev.ru 45556Sigor@sysoev.ru .timer_handler = nxt_controller_conn_read_timeout, 45656Sigor@sysoev.ru .timer_value = nxt_controller_conn_timeout_value, 45756Sigor@sysoev.ru .timer_data = 60 * 1000, 45820Sigor@sysoev.ru }; 45920Sigor@sysoev.ru 46020Sigor@sysoev.ru 46120Sigor@sysoev.ru static void 46220Sigor@sysoev.ru nxt_controller_conn_read(nxt_task_t *task, void *obj, void *data) 46320Sigor@sysoev.ru { 46427Svbart@nginx.com size_t preread; 46527Svbart@nginx.com nxt_buf_t *b; 46627Svbart@nginx.com nxt_int_t rc; 46762Sigor@sysoev.ru nxt_conn_t *c; 46827Svbart@nginx.com nxt_controller_request_t *r; 46920Sigor@sysoev.ru 47020Sigor@sysoev.ru c = obj; 47127Svbart@nginx.com r = data; 47220Sigor@sysoev.ru 47320Sigor@sysoev.ru nxt_debug(task, "controller conn read"); 47420Sigor@sysoev.ru 47527Svbart@nginx.com nxt_queue_remove(&c->link); 47627Svbart@nginx.com nxt_queue_self(&c->link); 47727Svbart@nginx.com 47827Svbart@nginx.com b = c->read; 47927Svbart@nginx.com 48027Svbart@nginx.com rc = nxt_http_parse_request(&r->parser, &b->mem); 48127Svbart@nginx.com 48227Svbart@nginx.com if (nxt_slow_path(rc != NXT_DONE)) { 48327Svbart@nginx.com 48427Svbart@nginx.com if (rc == NXT_AGAIN) { 48527Svbart@nginx.com if (nxt_buf_mem_free_size(&b->mem) == 0) { 48627Svbart@nginx.com nxt_log(task, NXT_LOG_ERR, "too long request headers"); 48727Svbart@nginx.com nxt_controller_conn_close(task, c, r); 48827Svbart@nginx.com return; 48927Svbart@nginx.com } 49027Svbart@nginx.com 49162Sigor@sysoev.ru nxt_conn_read(task->thread->engine, c); 49227Svbart@nginx.com return; 49327Svbart@nginx.com } 49427Svbart@nginx.com 49527Svbart@nginx.com /* rc == NXT_ERROR */ 49627Svbart@nginx.com 49727Svbart@nginx.com nxt_log(task, NXT_LOG_ERR, "parsing error"); 49827Svbart@nginx.com 49927Svbart@nginx.com nxt_controller_conn_close(task, c, r); 50027Svbart@nginx.com return; 50127Svbart@nginx.com } 50227Svbart@nginx.com 503417Svbart@nginx.com rc = nxt_http_fields_process(r->parser.fields, &nxt_controller_fields_hash, 504417Svbart@nginx.com r); 50560Svbart@nginx.com 50660Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 50760Svbart@nginx.com nxt_controller_conn_close(task, c, r); 50860Svbart@nginx.com return; 50960Svbart@nginx.com } 51060Svbart@nginx.com 51127Svbart@nginx.com preread = nxt_buf_mem_used_size(&b->mem); 51227Svbart@nginx.com 51327Svbart@nginx.com nxt_debug(task, "controller request header parsing complete, " 514107Svbart@nginx.com "body length: %uz, preread: %uz", 51527Svbart@nginx.com r->length, preread); 51627Svbart@nginx.com 51727Svbart@nginx.com if (preread >= r->length) { 518140Svbart@nginx.com nxt_controller_process_request(task, r); 51927Svbart@nginx.com return; 52027Svbart@nginx.com } 52127Svbart@nginx.com 52227Svbart@nginx.com if (r->length - preread > (size_t) nxt_buf_mem_free_size(&b->mem)) { 52327Svbart@nginx.com b = nxt_buf_mem_alloc(c->mem_pool, r->length, 0); 52427Svbart@nginx.com if (nxt_slow_path(b == NULL)) { 52527Svbart@nginx.com nxt_controller_conn_free(task, c, NULL); 52627Svbart@nginx.com return; 52727Svbart@nginx.com } 52827Svbart@nginx.com 52927Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, c->read->mem.pos, preread); 53027Svbart@nginx.com 53127Svbart@nginx.com c->read = b; 53227Svbart@nginx.com } 53327Svbart@nginx.com 53427Svbart@nginx.com c->read_state = &nxt_controller_conn_body_read_state; 53527Svbart@nginx.com 53662Sigor@sysoev.ru nxt_conn_read(task->thread->engine, c); 53720Sigor@sysoev.ru } 53820Sigor@sysoev.ru 53920Sigor@sysoev.ru 54020Sigor@sysoev.ru static nxt_msec_t 54162Sigor@sysoev.ru nxt_controller_conn_timeout_value(nxt_conn_t *c, uintptr_t data) 54220Sigor@sysoev.ru { 54320Sigor@sysoev.ru return (nxt_msec_t) data; 54420Sigor@sysoev.ru } 54520Sigor@sysoev.ru 54620Sigor@sysoev.ru 54720Sigor@sysoev.ru static void 54820Sigor@sysoev.ru nxt_controller_conn_read_error(nxt_task_t *task, void *obj, void *data) 54920Sigor@sysoev.ru { 55062Sigor@sysoev.ru nxt_conn_t *c; 55120Sigor@sysoev.ru 55220Sigor@sysoev.ru c = obj; 55320Sigor@sysoev.ru 55420Sigor@sysoev.ru nxt_debug(task, "controller conn read error"); 55520Sigor@sysoev.ru 55627Svbart@nginx.com nxt_controller_conn_close(task, c, data); 55720Sigor@sysoev.ru } 55820Sigor@sysoev.ru 55920Sigor@sysoev.ru 56020Sigor@sysoev.ru static void 56120Sigor@sysoev.ru nxt_controller_conn_read_timeout(nxt_task_t *task, void *obj, void *data) 56220Sigor@sysoev.ru { 56362Sigor@sysoev.ru nxt_timer_t *timer; 56462Sigor@sysoev.ru nxt_conn_t *c; 56520Sigor@sysoev.ru 56662Sigor@sysoev.ru timer = obj; 56720Sigor@sysoev.ru 56862Sigor@sysoev.ru c = nxt_read_timer_conn(timer); 56920Sigor@sysoev.ru c->socket.timedout = 1; 57020Sigor@sysoev.ru c->socket.closed = 1; 57120Sigor@sysoev.ru 57220Sigor@sysoev.ru nxt_debug(task, "controller conn read timeout"); 57320Sigor@sysoev.ru 57427Svbart@nginx.com nxt_controller_conn_close(task, c, data); 57527Svbart@nginx.com } 57627Svbart@nginx.com 57727Svbart@nginx.com 57827Svbart@nginx.com static const nxt_event_conn_state_t nxt_controller_conn_body_read_state 57927Svbart@nginx.com nxt_aligned(64) = 58027Svbart@nginx.com { 58156Sigor@sysoev.ru .ready_handler = nxt_controller_conn_body_read, 58256Sigor@sysoev.ru .close_handler = nxt_controller_conn_close, 58356Sigor@sysoev.ru .error_handler = nxt_controller_conn_read_error, 58427Svbart@nginx.com 58556Sigor@sysoev.ru .timer_handler = nxt_controller_conn_read_timeout, 58656Sigor@sysoev.ru .timer_value = nxt_controller_conn_timeout_value, 58756Sigor@sysoev.ru .timer_data = 60 * 1000, 58856Sigor@sysoev.ru .timer_autoreset = 1, 58927Svbart@nginx.com }; 59027Svbart@nginx.com 59127Svbart@nginx.com 59227Svbart@nginx.com static void 59327Svbart@nginx.com nxt_controller_conn_body_read(nxt_task_t *task, void *obj, void *data) 59427Svbart@nginx.com { 595107Svbart@nginx.com size_t read; 596107Svbart@nginx.com nxt_buf_t *b; 597107Svbart@nginx.com nxt_conn_t *c; 598107Svbart@nginx.com nxt_controller_request_t *r; 59927Svbart@nginx.com 60027Svbart@nginx.com c = obj; 601107Svbart@nginx.com r = data; 60227Svbart@nginx.com b = c->read; 60327Svbart@nginx.com 604107Svbart@nginx.com read = nxt_buf_mem_used_size(&b->mem); 60527Svbart@nginx.com 606107Svbart@nginx.com nxt_debug(task, "controller conn body read: %uz of %uz", 607107Svbart@nginx.com read, r->length); 60827Svbart@nginx.com 609107Svbart@nginx.com if (read >= r->length) { 610140Svbart@nginx.com nxt_controller_process_request(task, r); 61127Svbart@nginx.com return; 61227Svbart@nginx.com } 61327Svbart@nginx.com 61462Sigor@sysoev.ru nxt_conn_read(task->thread->engine, c); 61527Svbart@nginx.com } 61627Svbart@nginx.com 61727Svbart@nginx.com 61827Svbart@nginx.com static const nxt_event_conn_state_t nxt_controller_conn_write_state 61927Svbart@nginx.com nxt_aligned(64) = 62027Svbart@nginx.com { 62156Sigor@sysoev.ru .ready_handler = nxt_controller_conn_write, 62256Sigor@sysoev.ru .error_handler = nxt_controller_conn_write_error, 62327Svbart@nginx.com 62456Sigor@sysoev.ru .timer_handler = nxt_controller_conn_write_timeout, 62556Sigor@sysoev.ru .timer_value = nxt_controller_conn_timeout_value, 62656Sigor@sysoev.ru .timer_data = 60 * 1000, 62756Sigor@sysoev.ru .timer_autoreset = 1, 62827Svbart@nginx.com }; 62927Svbart@nginx.com 63027Svbart@nginx.com 63127Svbart@nginx.com static void 63227Svbart@nginx.com nxt_controller_conn_write(nxt_task_t *task, void *obj, void *data) 63327Svbart@nginx.com { 63462Sigor@sysoev.ru nxt_buf_t *b; 63562Sigor@sysoev.ru nxt_conn_t *c; 63627Svbart@nginx.com 63727Svbart@nginx.com c = obj; 63827Svbart@nginx.com 63927Svbart@nginx.com nxt_debug(task, "controller conn write"); 64027Svbart@nginx.com 64127Svbart@nginx.com b = c->write; 64227Svbart@nginx.com 64327Svbart@nginx.com if (b->mem.pos != b->mem.free) { 64462Sigor@sysoev.ru nxt_conn_write(task->thread->engine, c); 64527Svbart@nginx.com return; 64627Svbart@nginx.com } 64727Svbart@nginx.com 64827Svbart@nginx.com nxt_debug(task, "controller conn write complete"); 64927Svbart@nginx.com 65027Svbart@nginx.com nxt_controller_conn_close(task, c, data); 65127Svbart@nginx.com } 65227Svbart@nginx.com 65327Svbart@nginx.com 65427Svbart@nginx.com static void 65527Svbart@nginx.com nxt_controller_conn_write_error(nxt_task_t *task, void *obj, void *data) 65627Svbart@nginx.com { 65762Sigor@sysoev.ru nxt_conn_t *c; 65827Svbart@nginx.com 65927Svbart@nginx.com c = obj; 66027Svbart@nginx.com 66127Svbart@nginx.com nxt_debug(task, "controller conn write error"); 66227Svbart@nginx.com 66327Svbart@nginx.com nxt_controller_conn_close(task, c, data); 66427Svbart@nginx.com } 66527Svbart@nginx.com 66627Svbart@nginx.com 66727Svbart@nginx.com static void 66827Svbart@nginx.com nxt_controller_conn_write_timeout(nxt_task_t *task, void *obj, void *data) 66927Svbart@nginx.com { 67062Sigor@sysoev.ru nxt_conn_t *c; 67162Sigor@sysoev.ru nxt_timer_t *timer; 67227Svbart@nginx.com 67362Sigor@sysoev.ru timer = obj; 67427Svbart@nginx.com 67562Sigor@sysoev.ru c = nxt_write_timer_conn(timer); 67627Svbart@nginx.com c->socket.timedout = 1; 67727Svbart@nginx.com c->socket.closed = 1; 67827Svbart@nginx.com 67927Svbart@nginx.com nxt_debug(task, "controller conn write timeout"); 68027Svbart@nginx.com 68127Svbart@nginx.com nxt_controller_conn_close(task, c, data); 68220Sigor@sysoev.ru } 68320Sigor@sysoev.ru 68420Sigor@sysoev.ru 68520Sigor@sysoev.ru static const nxt_event_conn_state_t nxt_controller_conn_close_state 68620Sigor@sysoev.ru nxt_aligned(64) = 68720Sigor@sysoev.ru { 68856Sigor@sysoev.ru .ready_handler = nxt_controller_conn_free, 68920Sigor@sysoev.ru }; 69020Sigor@sysoev.ru 69120Sigor@sysoev.ru 69220Sigor@sysoev.ru static void 69320Sigor@sysoev.ru nxt_controller_conn_close(nxt_task_t *task, void *obj, void *data) 69420Sigor@sysoev.ru { 69562Sigor@sysoev.ru nxt_conn_t *c; 69620Sigor@sysoev.ru 69720Sigor@sysoev.ru c = obj; 69820Sigor@sysoev.ru 69920Sigor@sysoev.ru nxt_debug(task, "controller conn close"); 70020Sigor@sysoev.ru 70127Svbart@nginx.com nxt_queue_remove(&c->link); 70227Svbart@nginx.com 70320Sigor@sysoev.ru c->write_state = &nxt_controller_conn_close_state; 70420Sigor@sysoev.ru 70562Sigor@sysoev.ru nxt_conn_close(task->thread->engine, c); 70620Sigor@sysoev.ru } 70720Sigor@sysoev.ru 70820Sigor@sysoev.ru 70920Sigor@sysoev.ru static void 71020Sigor@sysoev.ru nxt_controller_conn_free(nxt_task_t *task, void *obj, void *data) 71120Sigor@sysoev.ru { 71262Sigor@sysoev.ru nxt_conn_t *c; 71320Sigor@sysoev.ru 71420Sigor@sysoev.ru c = obj; 71520Sigor@sysoev.ru 71620Sigor@sysoev.ru nxt_debug(task, "controller conn free"); 71720Sigor@sysoev.ru 718337Sigor@sysoev.ru nxt_sockaddr_cache_free(task->thread->engine, c); 719337Sigor@sysoev.ru 720386Sigor@sysoev.ru nxt_conn_free(task, c); 72120Sigor@sysoev.ru } 72227Svbart@nginx.com 72327Svbart@nginx.com 72427Svbart@nginx.com static nxt_int_t 72560Svbart@nginx.com nxt_controller_request_content_length(void *ctx, nxt_http_field_t *field, 726417Svbart@nginx.com uintptr_t data) 72727Svbart@nginx.com { 72827Svbart@nginx.com off_t length; 72927Svbart@nginx.com nxt_controller_request_t *r; 73027Svbart@nginx.com 73127Svbart@nginx.com r = ctx; 73227Svbart@nginx.com 733417Svbart@nginx.com length = nxt_off_t_parse(field->value, field->value_length); 73427Svbart@nginx.com 73527Svbart@nginx.com if (nxt_fast_path(length > 0)) { 736107Svbart@nginx.com 737107Svbart@nginx.com if (nxt_slow_path(length > NXT_SIZE_T_MAX)) { 738417Svbart@nginx.com nxt_log_error(NXT_LOG_ERR, &r->conn->log, 739417Svbart@nginx.com "Content-Length is too big"); 740107Svbart@nginx.com return NXT_ERROR; 741107Svbart@nginx.com } 74227Svbart@nginx.com 74327Svbart@nginx.com r->length = length; 74427Svbart@nginx.com return NXT_OK; 74527Svbart@nginx.com } 74627Svbart@nginx.com 747417Svbart@nginx.com nxt_log_error(NXT_LOG_ERR, &r->conn->log, "Content-Length is invalid"); 74827Svbart@nginx.com 74927Svbart@nginx.com return NXT_ERROR; 75027Svbart@nginx.com } 75127Svbart@nginx.com 75227Svbart@nginx.com 75327Svbart@nginx.com static void 754140Svbart@nginx.com nxt_controller_process_request(nxt_task_t *task, nxt_controller_request_t *req) 75527Svbart@nginx.com { 75665Sigor@sysoev.ru nxt_mp_t *mp; 75751Svbart@nginx.com nxt_int_t rc; 75846Svbart@nginx.com nxt_str_t path; 759140Svbart@nginx.com nxt_conn_t *c; 76051Svbart@nginx.com nxt_buf_mem_t *mbuf; 761106Svbart@nginx.com nxt_conf_op_t *ops; 762106Svbart@nginx.com nxt_conf_value_t *value; 763357Svbart@nginx.com nxt_conf_validation_t vldt; 764208Svbart@nginx.com nxt_conf_json_error_t error; 76544Svbart@nginx.com nxt_controller_response_t resp; 76644Svbart@nginx.com 76751Svbart@nginx.com static const nxt_str_t empty_obj = nxt_string("{}"); 76851Svbart@nginx.com 769140Svbart@nginx.com c = req->conn; 770112Smax.romanov@nginx.com path = req->parser.path; 77151Svbart@nginx.com 772*632Svbart@nginx.com if (nxt_str_start(&path, "/config", 7)) { 773*632Svbart@nginx.com 774*632Svbart@nginx.com if (path.length == 7) { 775*632Svbart@nginx.com path.length = 1; 776*632Svbart@nginx.com 777*632Svbart@nginx.com } else if (path.start[7] == '/') { 778*632Svbart@nginx.com path.length -= 7; 779*632Svbart@nginx.com path.start += 7; 780*632Svbart@nginx.com } 781*632Svbart@nginx.com } 782*632Svbart@nginx.com 78351Svbart@nginx.com if (path.length > 1 && path.start[path.length - 1] == '/') { 78451Svbart@nginx.com path.length--; 78551Svbart@nginx.com } 78651Svbart@nginx.com 78744Svbart@nginx.com nxt_memzero(&resp, sizeof(nxt_controller_response_t)); 78844Svbart@nginx.com 78944Svbart@nginx.com if (nxt_str_eq(&req->parser.method, "GET", 3)) { 79046Svbart@nginx.com 791106Svbart@nginx.com value = nxt_conf_get_path(nxt_controller_conf.root, &path); 79251Svbart@nginx.com 79351Svbart@nginx.com if (value == NULL) { 794208Svbart@nginx.com goto not_found; 79551Svbart@nginx.com } 79651Svbart@nginx.com 797208Svbart@nginx.com resp.status = 200; 798106Svbart@nginx.com resp.conf = value; 79946Svbart@nginx.com 800208Svbart@nginx.com nxt_controller_response(task, req, &resp); 801208Svbart@nginx.com return; 80251Svbart@nginx.com } 80351Svbart@nginx.com 80451Svbart@nginx.com if (nxt_str_eq(&req->parser.method, "PUT", 3)) { 80546Svbart@nginx.com 806238Svbart@nginx.com if (!nxt_queue_is_empty(&nxt_controller_waiting_requests)) { 807238Svbart@nginx.com nxt_queue_insert_tail(&nxt_controller_waiting_requests, &req->link); 808238Svbart@nginx.com return; 809238Svbart@nginx.com } 810238Svbart@nginx.com 81165Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 81251Svbart@nginx.com 81351Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 814208Svbart@nginx.com goto alloc_fail; 81546Svbart@nginx.com } 81646Svbart@nginx.com 81751Svbart@nginx.com mbuf = &c->read->mem; 81851Svbart@nginx.com 819208Svbart@nginx.com nxt_memzero(&error, sizeof(nxt_conf_json_error_t)); 820208Svbart@nginx.com 821208Svbart@nginx.com value = nxt_conf_json_parse(mp, mbuf->pos, mbuf->free, &error); 82251Svbart@nginx.com 82351Svbart@nginx.com if (value == NULL) { 82465Sigor@sysoev.ru nxt_mp_destroy(mp); 825208Svbart@nginx.com 826208Svbart@nginx.com if (error.pos == NULL) { 827208Svbart@nginx.com goto alloc_fail; 828208Svbart@nginx.com } 829208Svbart@nginx.com 830208Svbart@nginx.com resp.status = 400; 831208Svbart@nginx.com resp.title = (u_char *) "Invalid JSON."; 832357Svbart@nginx.com resp.detail.length = nxt_strlen(error.detail); 833357Svbart@nginx.com resp.detail.start = error.detail; 834208Svbart@nginx.com resp.offset = error.pos - mbuf->pos; 835208Svbart@nginx.com 836208Svbart@nginx.com nxt_conf_json_position(mbuf->pos, error.pos, 837208Svbart@nginx.com &resp.line, &resp.column); 838208Svbart@nginx.com 839208Svbart@nginx.com nxt_controller_response(task, req, &resp); 840208Svbart@nginx.com return; 84151Svbart@nginx.com } 84251Svbart@nginx.com 84351Svbart@nginx.com if (path.length != 1) { 844106Svbart@nginx.com rc = nxt_conf_op_compile(c->mem_pool, &ops, 845106Svbart@nginx.com nxt_controller_conf.root, 846106Svbart@nginx.com &path, value); 84746Svbart@nginx.com 84851Svbart@nginx.com if (rc != NXT_OK) { 849619Svbart@nginx.com nxt_mp_destroy(mp); 850619Svbart@nginx.com 85151Svbart@nginx.com if (rc == NXT_DECLINED) { 852208Svbart@nginx.com goto not_found; 85351Svbart@nginx.com } 85446Svbart@nginx.com 855208Svbart@nginx.com goto alloc_fail; 85651Svbart@nginx.com } 85751Svbart@nginx.com 858106Svbart@nginx.com value = nxt_conf_clone(mp, ops, nxt_controller_conf.root); 85951Svbart@nginx.com 86051Svbart@nginx.com if (nxt_slow_path(value == NULL)) { 86165Sigor@sysoev.ru nxt_mp_destroy(mp); 862208Svbart@nginx.com goto alloc_fail; 86351Svbart@nginx.com } 86446Svbart@nginx.com } 86544Svbart@nginx.com 866357Svbart@nginx.com nxt_memzero(&vldt, sizeof(nxt_conf_validation_t)); 867357Svbart@nginx.com 868357Svbart@nginx.com vldt.conf = value; 869357Svbart@nginx.com vldt.pool = c->mem_pool; 870357Svbart@nginx.com 871357Svbart@nginx.com rc = nxt_conf_validate(&vldt); 872357Svbart@nginx.com 873357Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 874121Svbart@nginx.com nxt_mp_destroy(mp); 875357Svbart@nginx.com 876357Svbart@nginx.com if (rc == NXT_DECLINED) { 877357Svbart@nginx.com resp.detail = vldt.error; 878357Svbart@nginx.com goto invalid_conf; 879357Svbart@nginx.com } 880357Svbart@nginx.com 881357Svbart@nginx.com /* rc == NXT_ERROR */ 882357Svbart@nginx.com goto alloc_fail; 883116Svbart@nginx.com } 884116Svbart@nginx.com 885249Svbart@nginx.com rc = nxt_controller_conf_send(task, value, 886249Svbart@nginx.com nxt_controller_conf_handler, req); 887247Svbart@nginx.com 888247Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 889121Svbart@nginx.com nxt_mp_destroy(mp); 890247Svbart@nginx.com 891247Svbart@nginx.com if (rc == NXT_DECLINED) { 892247Svbart@nginx.com goto no_router; 893247Svbart@nginx.com } 894247Svbart@nginx.com 895247Svbart@nginx.com /* rc == NXT_ERROR */ 896208Svbart@nginx.com goto alloc_fail; 897121Svbart@nginx.com } 898121Svbart@nginx.com 899249Svbart@nginx.com req->conf.root = value; 900249Svbart@nginx.com req->conf.pool = mp; 901249Svbart@nginx.com 902249Svbart@nginx.com nxt_queue_insert_head(&nxt_controller_waiting_requests, &req->link); 903249Svbart@nginx.com 904140Svbart@nginx.com return; 90551Svbart@nginx.com } 90627Svbart@nginx.com 90751Svbart@nginx.com if (nxt_str_eq(&req->parser.method, "DELETE", 6)) { 90851Svbart@nginx.com 909238Svbart@nginx.com if (!nxt_queue_is_empty(&nxt_controller_waiting_requests)) { 910238Svbart@nginx.com nxt_queue_insert_tail(&nxt_controller_waiting_requests, &req->link); 911238Svbart@nginx.com return; 912238Svbart@nginx.com } 913238Svbart@nginx.com 91451Svbart@nginx.com if (path.length == 1) { 91565Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 91644Svbart@nginx.com 91751Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 918208Svbart@nginx.com goto alloc_fail; 91951Svbart@nginx.com } 92051Svbart@nginx.com 921106Svbart@nginx.com value = nxt_conf_json_parse_str(mp, &empty_obj); 92227Svbart@nginx.com 92344Svbart@nginx.com } else { 924106Svbart@nginx.com rc = nxt_conf_op_compile(c->mem_pool, &ops, 925106Svbart@nginx.com nxt_controller_conf.root, 926106Svbart@nginx.com &path, NULL); 92751Svbart@nginx.com 92851Svbart@nginx.com if (rc != NXT_OK) { 92951Svbart@nginx.com if (rc == NXT_DECLINED) { 930208Svbart@nginx.com goto not_found; 93151Svbart@nginx.com } 93251Svbart@nginx.com 933208Svbart@nginx.com goto alloc_fail; 93451Svbart@nginx.com } 93551Svbart@nginx.com 93665Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 93751Svbart@nginx.com 93851Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 939208Svbart@nginx.com goto alloc_fail; 94051Svbart@nginx.com } 94151Svbart@nginx.com 942106Svbart@nginx.com value = nxt_conf_clone(mp, ops, nxt_controller_conf.root); 94351Svbart@nginx.com } 94451Svbart@nginx.com 94551Svbart@nginx.com if (nxt_slow_path(value == NULL)) { 94665Sigor@sysoev.ru nxt_mp_destroy(mp); 947208Svbart@nginx.com goto alloc_fail; 94844Svbart@nginx.com } 94944Svbart@nginx.com 950357Svbart@nginx.com nxt_memzero(&vldt, sizeof(nxt_conf_validation_t)); 951357Svbart@nginx.com 952357Svbart@nginx.com vldt.conf = value; 953357Svbart@nginx.com vldt.pool = c->mem_pool; 954357Svbart@nginx.com 955357Svbart@nginx.com rc = nxt_conf_validate(&vldt); 956357Svbart@nginx.com 957357Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 958121Svbart@nginx.com nxt_mp_destroy(mp); 959357Svbart@nginx.com 960357Svbart@nginx.com if (rc == NXT_DECLINED) { 961357Svbart@nginx.com resp.detail = vldt.error; 962357Svbart@nginx.com goto invalid_conf; 963357Svbart@nginx.com } 964357Svbart@nginx.com 965357Svbart@nginx.com /* rc == NXT_ERROR */ 966357Svbart@nginx.com goto alloc_fail; 967116Svbart@nginx.com } 968116Svbart@nginx.com 969249Svbart@nginx.com rc = nxt_controller_conf_send(task, value, 970249Svbart@nginx.com nxt_controller_conf_handler, req); 971247Svbart@nginx.com 972247Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 973121Svbart@nginx.com nxt_mp_destroy(mp); 974247Svbart@nginx.com 975247Svbart@nginx.com if (rc == NXT_DECLINED) { 976247Svbart@nginx.com goto no_router; 977247Svbart@nginx.com } 978247Svbart@nginx.com 979247Svbart@nginx.com /* rc == NXT_ERROR */ 980208Svbart@nginx.com goto alloc_fail; 981121Svbart@nginx.com } 982121Svbart@nginx.com 983249Svbart@nginx.com req->conf.root = value; 984249Svbart@nginx.com req->conf.pool = mp; 985249Svbart@nginx.com 986249Svbart@nginx.com nxt_queue_insert_head(&nxt_controller_waiting_requests, &req->link); 987249Svbart@nginx.com 988140Svbart@nginx.com return; 98951Svbart@nginx.com } 99051Svbart@nginx.com 991208Svbart@nginx.com resp.status = 405; 992208Svbart@nginx.com resp.title = (u_char *) "Invalid method."; 993208Svbart@nginx.com resp.offset = -1; 99451Svbart@nginx.com 995208Svbart@nginx.com nxt_controller_response(task, req, &resp); 996208Svbart@nginx.com return; 99751Svbart@nginx.com 998208Svbart@nginx.com not_found: 999208Svbart@nginx.com 1000208Svbart@nginx.com resp.status = 404; 1001208Svbart@nginx.com resp.title = (u_char *) "Value doesn't exist."; 1002208Svbart@nginx.com resp.offset = -1; 1003208Svbart@nginx.com 1004208Svbart@nginx.com nxt_controller_response(task, req, &resp); 1005208Svbart@nginx.com return; 1006208Svbart@nginx.com 1007208Svbart@nginx.com invalid_conf: 1008208Svbart@nginx.com 1009208Svbart@nginx.com resp.status = 400; 1010208Svbart@nginx.com resp.title = (u_char *) "Invalid configuration."; 1011208Svbart@nginx.com resp.offset = -1; 1012208Svbart@nginx.com 1013208Svbart@nginx.com nxt_controller_response(task, req, &resp); 1014208Svbart@nginx.com return; 1015247Svbart@nginx.com 1016247Svbart@nginx.com alloc_fail: 1017247Svbart@nginx.com 1018247Svbart@nginx.com resp.status = 500; 1019247Svbart@nginx.com resp.title = (u_char *) "Memory allocation failed."; 1020247Svbart@nginx.com resp.offset = -1; 1021247Svbart@nginx.com 1022247Svbart@nginx.com nxt_controller_response(task, req, &resp); 1023247Svbart@nginx.com return; 1024247Svbart@nginx.com 1025247Svbart@nginx.com no_router: 1026247Svbart@nginx.com 1027247Svbart@nginx.com resp.status = 500; 1028247Svbart@nginx.com resp.title = (u_char *) "Router process isn't available."; 1029247Svbart@nginx.com resp.offset = -1; 1030247Svbart@nginx.com 1031247Svbart@nginx.com nxt_controller_response(task, req, &resp); 1032247Svbart@nginx.com return; 103327Svbart@nginx.com } 103427Svbart@nginx.com 103527Svbart@nginx.com 1036193Smax.romanov@nginx.com static void 1037193Smax.romanov@nginx.com nxt_controller_conf_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 1038193Smax.romanov@nginx.com void *data) 1039140Svbart@nginx.com { 1040238Svbart@nginx.com nxt_queue_t queue; 1041140Svbart@nginx.com nxt_controller_request_t *req; 1042140Svbart@nginx.com nxt_controller_response_t resp; 1043140Svbart@nginx.com 1044238Svbart@nginx.com req = data; 1045238Svbart@nginx.com 1046201Svbart@nginx.com nxt_debug(task, "controller conf ready: %*s", 1047201Svbart@nginx.com nxt_buf_mem_used_size(&msg->buf->mem), msg->buf->mem.pos); 1048140Svbart@nginx.com 1049238Svbart@nginx.com nxt_queue_remove(&req->link); 1050140Svbart@nginx.com 1051238Svbart@nginx.com nxt_memzero(&resp, sizeof(nxt_controller_response_t)); 1052140Svbart@nginx.com 1053193Smax.romanov@nginx.com if (msg->port_msg.type == NXT_PORT_MSG_RPC_READY) { 1054140Svbart@nginx.com nxt_mp_destroy(nxt_controller_conf.pool); 1055140Svbart@nginx.com 1056140Svbart@nginx.com nxt_controller_conf = req->conf; 1057140Svbart@nginx.com 1058314Svbart@nginx.com nxt_controller_conf_store(task, req->conf.root); 1059314Svbart@nginx.com 1060208Svbart@nginx.com resp.status = 200; 1061208Svbart@nginx.com resp.title = (u_char *) "Reconfiguration done."; 1062140Svbart@nginx.com 1063140Svbart@nginx.com } else { 1064140Svbart@nginx.com nxt_mp_destroy(req->conf.pool); 1065140Svbart@nginx.com 1066208Svbart@nginx.com resp.status = 500; 1067208Svbart@nginx.com resp.title = (u_char *) "Failed to apply new configuration."; 1068208Svbart@nginx.com resp.offset = -1; 1069140Svbart@nginx.com } 1070140Svbart@nginx.com 1071140Svbart@nginx.com nxt_controller_response(task, req, &resp); 1072140Svbart@nginx.com 1073238Svbart@nginx.com nxt_queue_init(&queue); 1074238Svbart@nginx.com nxt_queue_add(&queue, &nxt_controller_waiting_requests); 1075140Svbart@nginx.com 1076238Svbart@nginx.com nxt_queue_init(&nxt_controller_waiting_requests); 1077121Svbart@nginx.com 1078238Svbart@nginx.com nxt_queue_each(req, &queue, nxt_controller_request_t, link) { 1079238Svbart@nginx.com nxt_controller_process_request(task, req); 1080238Svbart@nginx.com } nxt_queue_loop; 1081121Svbart@nginx.com } 1082121Svbart@nginx.com 1083121Svbart@nginx.com 1084140Svbart@nginx.com static void 1085314Svbart@nginx.com nxt_controller_conf_store(nxt_task_t *task, nxt_conf_value_t *conf) 1086314Svbart@nginx.com { 1087314Svbart@nginx.com size_t size; 1088314Svbart@nginx.com nxt_buf_t *b; 1089314Svbart@nginx.com nxt_port_t *main_port; 1090314Svbart@nginx.com nxt_runtime_t *rt; 1091314Svbart@nginx.com 1092314Svbart@nginx.com rt = task->thread->runtime; 1093314Svbart@nginx.com 1094314Svbart@nginx.com main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 1095314Svbart@nginx.com 1096314Svbart@nginx.com size = nxt_conf_json_length(conf, NULL); 1097314Svbart@nginx.com 1098342Smax.romanov@nginx.com b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, size); 1099314Svbart@nginx.com 1100314Svbart@nginx.com if (nxt_fast_path(b != NULL)) { 1101314Svbart@nginx.com b->mem.free = nxt_conf_json_print(b->mem.free, conf, NULL); 1102314Svbart@nginx.com 1103314Svbart@nginx.com (void) nxt_port_socket_write(task, main_port, NXT_PORT_MSG_CONF_STORE, 1104314Svbart@nginx.com -1, 0, -1, b); 1105314Svbart@nginx.com } 1106314Svbart@nginx.com } 1107314Svbart@nginx.com 1108314Svbart@nginx.com 1109314Svbart@nginx.com static void 1110140Svbart@nginx.com nxt_controller_response(nxt_task_t *task, nxt_controller_request_t *req, 111144Svbart@nginx.com nxt_controller_response_t *resp) 111233Svbart@nginx.com { 1113208Svbart@nginx.com size_t size; 1114208Svbart@nginx.com nxt_str_t status_line, str; 1115208Svbart@nginx.com nxt_buf_t *b, *body; 1116208Svbart@nginx.com nxt_conn_t *c; 1117208Svbart@nginx.com nxt_uint_t n; 1118208Svbart@nginx.com nxt_conf_value_t *value, *location; 1119208Svbart@nginx.com nxt_conf_json_pretty_t pretty; 1120208Svbart@nginx.com 1121208Svbart@nginx.com static nxt_str_t success_str = nxt_string("success"); 1122208Svbart@nginx.com static nxt_str_t error_str = nxt_string("error"); 1123208Svbart@nginx.com static nxt_str_t detail_str = nxt_string("detail"); 1124208Svbart@nginx.com static nxt_str_t location_str = nxt_string("location"); 1125208Svbart@nginx.com static nxt_str_t offset_str = nxt_string("offset"); 1126208Svbart@nginx.com static nxt_str_t line_str = nxt_string("line"); 1127208Svbart@nginx.com static nxt_str_t column_str = nxt_string("column"); 1128208Svbart@nginx.com 1129208Svbart@nginx.com static nxt_time_string_t date_cache = { 1130208Svbart@nginx.com (nxt_atomic_uint_t) -1, 1131208Svbart@nginx.com nxt_controller_date, 1132208Svbart@nginx.com "%s, %02d %s %4d %02d:%02d:%02d GMT", 1133208Svbart@nginx.com sizeof("Wed, 31 Dec 1986 16:40:00 GMT") - 1, 1134208Svbart@nginx.com NXT_THREAD_TIME_GMT, 1135208Svbart@nginx.com NXT_THREAD_TIME_SEC, 1136208Svbart@nginx.com }; 1137208Svbart@nginx.com 1138208Svbart@nginx.com switch (resp->status) { 1139208Svbart@nginx.com 1140208Svbart@nginx.com case 200: 1141208Svbart@nginx.com nxt_str_set(&status_line, "200 OK"); 1142208Svbart@nginx.com break; 1143208Svbart@nginx.com 1144208Svbart@nginx.com case 400: 1145208Svbart@nginx.com nxt_str_set(&status_line, "400 Bad Request"); 1146208Svbart@nginx.com break; 1147208Svbart@nginx.com 1148208Svbart@nginx.com case 404: 1149208Svbart@nginx.com nxt_str_set(&status_line, "404 Not Found"); 1150208Svbart@nginx.com break; 1151208Svbart@nginx.com 1152208Svbart@nginx.com case 405: 1153208Svbart@nginx.com nxt_str_set(&status_line, "405 Method Not Allowed"); 1154208Svbart@nginx.com break; 1155208Svbart@nginx.com 1156209Svbart@nginx.com default: 1157208Svbart@nginx.com nxt_str_set(&status_line, "500 Internal Server Error"); 1158208Svbart@nginx.com break; 1159208Svbart@nginx.com } 1160140Svbart@nginx.com 1161140Svbart@nginx.com c = req->conn; 1162208Svbart@nginx.com value = resp->conf; 116333Svbart@nginx.com 1164208Svbart@nginx.com if (value == NULL) { 1165208Svbart@nginx.com n = 1 1166357Svbart@nginx.com + (resp->detail.length != 0) 1167208Svbart@nginx.com + (resp->status >= 400 && resp->offset != -1); 1168208Svbart@nginx.com 1169208Svbart@nginx.com value = nxt_conf_create_object(c->mem_pool, n); 1170208Svbart@nginx.com 1171208Svbart@nginx.com if (nxt_slow_path(value == NULL)) { 1172208Svbart@nginx.com nxt_controller_conn_close(task, c, req); 1173208Svbart@nginx.com return; 1174208Svbart@nginx.com } 1175208Svbart@nginx.com 1176208Svbart@nginx.com str.length = nxt_strlen(resp->title); 1177208Svbart@nginx.com str.start = resp->title; 1178208Svbart@nginx.com 1179208Svbart@nginx.com if (resp->status < 400) { 1180208Svbart@nginx.com nxt_conf_set_member_string(value, &success_str, &str, 0); 1181208Svbart@nginx.com 1182208Svbart@nginx.com } else { 1183208Svbart@nginx.com nxt_conf_set_member_string(value, &error_str, &str, 0); 1184208Svbart@nginx.com } 1185208Svbart@nginx.com 1186208Svbart@nginx.com n = 0; 1187208Svbart@nginx.com 1188357Svbart@nginx.com if (resp->detail.length != 0) { 1189208Svbart@nginx.com n++; 1190208Svbart@nginx.com 1191357Svbart@nginx.com nxt_conf_set_member_string(value, &detail_str, &resp->detail, n); 1192208Svbart@nginx.com } 1193208Svbart@nginx.com 1194208Svbart@nginx.com if (resp->status >= 400 && resp->offset != -1) { 1195208Svbart@nginx.com n++; 1196208Svbart@nginx.com 1197208Svbart@nginx.com location = nxt_conf_create_object(c->mem_pool, 1198208Svbart@nginx.com resp->line != 0 ? 3 : 1); 1199208Svbart@nginx.com 1200208Svbart@nginx.com nxt_conf_set_member(value, &location_str, location, n); 1201208Svbart@nginx.com 1202208Svbart@nginx.com nxt_conf_set_member_integer(location, &offset_str, resp->offset, 0); 1203208Svbart@nginx.com 1204208Svbart@nginx.com if (resp->line != 0) { 1205208Svbart@nginx.com nxt_conf_set_member_integer(location, &line_str, 1206208Svbart@nginx.com resp->line, 1); 1207208Svbart@nginx.com 1208208Svbart@nginx.com nxt_conf_set_member_integer(location, &column_str, 1209208Svbart@nginx.com resp->column, 2); 1210208Svbart@nginx.com } 1211208Svbart@nginx.com } 1212208Svbart@nginx.com } 1213208Svbart@nginx.com 1214208Svbart@nginx.com nxt_memzero(&pretty, sizeof(nxt_conf_json_pretty_t)); 1215208Svbart@nginx.com 1216208Svbart@nginx.com size = nxt_conf_json_length(value, &pretty) + 2; 1217208Svbart@nginx.com 1218208Svbart@nginx.com body = nxt_buf_mem_alloc(c->mem_pool, size, 0); 1219208Svbart@nginx.com if (nxt_slow_path(body == NULL)) { 1220208Svbart@nginx.com nxt_controller_conn_close(task, c, req); 1221208Svbart@nginx.com return; 1222208Svbart@nginx.com } 1223208Svbart@nginx.com 1224208Svbart@nginx.com nxt_memzero(&pretty, sizeof(nxt_conf_json_pretty_t)); 1225208Svbart@nginx.com 1226208Svbart@nginx.com body->mem.free = nxt_conf_json_print(body->mem.free, value, &pretty); 1227208Svbart@nginx.com 1228208Svbart@nginx.com body->mem.free = nxt_cpymem(body->mem.free, "\r\n", 2); 1229208Svbart@nginx.com 1230208Svbart@nginx.com size = sizeof("HTTP/1.1 " "\r\n") - 1 + status_line.length 1231569Svbart@nginx.com + sizeof("Server: Unit/" NXT_VERSION "\r\n") - 1 1232208Svbart@nginx.com + sizeof("Date: Wed, 31 Dec 1986 16:40:00 GMT\r\n") - 1 1233208Svbart@nginx.com + sizeof("Content-Type: application/json\r\n") - 1 1234208Svbart@nginx.com + sizeof("Content-Length: " "\r\n") - 1 + NXT_SIZE_T_LEN 1235208Svbart@nginx.com + sizeof("Connection: close\r\n") - 1 1236208Svbart@nginx.com + sizeof("\r\n") - 1; 123733Svbart@nginx.com 123844Svbart@nginx.com b = nxt_buf_mem_alloc(c->mem_pool, size, 0); 123933Svbart@nginx.com if (nxt_slow_path(b == NULL)) { 1240140Svbart@nginx.com nxt_controller_conn_close(task, c, req); 1241140Svbart@nginx.com return; 124233Svbart@nginx.com } 124333Svbart@nginx.com 1244208Svbart@nginx.com b->next = body; 1245208Svbart@nginx.com 1246208Svbart@nginx.com nxt_str_set(&str, "HTTP/1.1 "); 124744Svbart@nginx.com 1248208Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length); 1249208Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, status_line.start, 1250208Svbart@nginx.com status_line.length); 1251208Svbart@nginx.com 1252208Svbart@nginx.com nxt_str_set(&str, "\r\n" 1253569Svbart@nginx.com "Server: Unit/" NXT_VERSION "\r\n" 1254208Svbart@nginx.com "Date: "); 1255208Svbart@nginx.com 1256208Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length); 125744Svbart@nginx.com 1258208Svbart@nginx.com b->mem.free = nxt_thread_time_string(task->thread, &date_cache, 1259208Svbart@nginx.com b->mem.free); 1260208Svbart@nginx.com 1261208Svbart@nginx.com nxt_str_set(&str, "\r\n" 1262208Svbart@nginx.com "Content-Type: application/json\r\n" 1263208Svbart@nginx.com "Content-Length: "); 1264208Svbart@nginx.com 1265208Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length); 126645Svbart@nginx.com 1267208Svbart@nginx.com b->mem.free = nxt_sprintf(b->mem.free, b->mem.end, "%uz", 1268208Svbart@nginx.com nxt_buf_mem_used_size(&body->mem)); 1269208Svbart@nginx.com 1270208Svbart@nginx.com nxt_str_set(&str, "\r\n" 1271208Svbart@nginx.com "Connection: close\r\n" 1272208Svbart@nginx.com "\r\n"); 1273208Svbart@nginx.com 1274208Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length); 127533Svbart@nginx.com 127633Svbart@nginx.com c->write = b; 127744Svbart@nginx.com c->write_state = &nxt_controller_conn_write_state; 127833Svbart@nginx.com 127962Sigor@sysoev.ru nxt_conn_write(task->thread->engine, c); 128033Svbart@nginx.com } 128145Svbart@nginx.com 128245Svbart@nginx.com 1283208Svbart@nginx.com static u_char * 1284208Svbart@nginx.com nxt_controller_date(u_char *buf, nxt_realtime_t *now, struct tm *tm, 1285208Svbart@nginx.com size_t size, const char *format) 128645Svbart@nginx.com { 1287208Svbart@nginx.com static const char *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", 1288208Svbart@nginx.com "Sat" }; 128945Svbart@nginx.com 1290208Svbart@nginx.com static const char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", 1291208Svbart@nginx.com "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; 129245Svbart@nginx.com 1293208Svbart@nginx.com return nxt_sprintf(buf, buf + size, format, 1294208Svbart@nginx.com week[tm->tm_wday], tm->tm_mday, 1295208Svbart@nginx.com month[tm->tm_mon], tm->tm_year + 1900, 1296208Svbart@nginx.com tm->tm_hour, tm->tm_min, tm->tm_sec); 129745Svbart@nginx.com } 1298