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> 12774Svbart@nginx.com #include <nxt_cert.h> 1320Sigor@sysoev.ru 1420Sigor@sysoev.ru 1527Svbart@nginx.com typedef struct { 16106Svbart@nginx.com nxt_conf_value_t *root; 17106Svbart@nginx.com nxt_mp_t *pool; 1844Svbart@nginx.com } nxt_controller_conf_t; 1944Svbart@nginx.com 2044Svbart@nginx.com 2144Svbart@nginx.com typedef struct { 2227Svbart@nginx.com nxt_http_request_parse_t parser; 2327Svbart@nginx.com size_t length; 2444Svbart@nginx.com nxt_controller_conf_t conf; 25140Svbart@nginx.com nxt_conn_t *conn; 26140Svbart@nginx.com nxt_queue_link_t link; 2727Svbart@nginx.com } nxt_controller_request_t; 2827Svbart@nginx.com 2927Svbart@nginx.com 3044Svbart@nginx.com typedef struct { 31208Svbart@nginx.com nxt_uint_t status; 32106Svbart@nginx.com nxt_conf_value_t *conf; 33208Svbart@nginx.com 34208Svbart@nginx.com u_char *title; 35357Svbart@nginx.com nxt_str_t detail; 36208Svbart@nginx.com ssize_t offset; 37208Svbart@nginx.com nxt_uint_t line; 38208Svbart@nginx.com nxt_uint_t column; 3944Svbart@nginx.com } nxt_controller_response_t; 4044Svbart@nginx.com 4144Svbart@nginx.com 42248Svbart@nginx.com static void nxt_controller_process_new_port_handler(nxt_task_t *task, 43248Svbart@nginx.com nxt_port_recv_msg_t *msg); 44662Smax.romanov@nginx.com static void nxt_controller_send_current_conf(nxt_task_t *task); 45662Smax.romanov@nginx.com static void nxt_controller_router_ready_handler(nxt_task_t *task, 46662Smax.romanov@nginx.com nxt_port_recv_msg_t *msg); 47249Svbart@nginx.com static nxt_int_t nxt_controller_conf_default(void); 48249Svbart@nginx.com static void nxt_controller_conf_init_handler(nxt_task_t *task, 49249Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 50249Svbart@nginx.com static nxt_int_t nxt_controller_conf_send(nxt_task_t *task, 51249Svbart@nginx.com nxt_conf_value_t *conf, nxt_port_rpc_handler_t handler, void *data); 52248Svbart@nginx.com 5320Sigor@sysoev.ru static void nxt_controller_conn_init(nxt_task_t *task, void *obj, void *data); 5420Sigor@sysoev.ru static void nxt_controller_conn_read(nxt_task_t *task, void *obj, void *data); 5562Sigor@sysoev.ru static nxt_msec_t nxt_controller_conn_timeout_value(nxt_conn_t *c, 5620Sigor@sysoev.ru uintptr_t data); 5720Sigor@sysoev.ru static void nxt_controller_conn_read_error(nxt_task_t *task, void *obj, 5820Sigor@sysoev.ru void *data); 5920Sigor@sysoev.ru static void nxt_controller_conn_read_timeout(nxt_task_t *task, void *obj, 6020Sigor@sysoev.ru void *data); 6127Svbart@nginx.com static void nxt_controller_conn_body_read(nxt_task_t *task, void *obj, 6227Svbart@nginx.com void *data); 6327Svbart@nginx.com static void nxt_controller_conn_write(nxt_task_t *task, void *obj, void *data); 6427Svbart@nginx.com static void nxt_controller_conn_write_error(nxt_task_t *task, void *obj, 6527Svbart@nginx.com void *data); 6627Svbart@nginx.com static void nxt_controller_conn_write_timeout(nxt_task_t *task, void *obj, 6727Svbart@nginx.com void *data); 6820Sigor@sysoev.ru static void nxt_controller_conn_close(nxt_task_t *task, void *obj, void *data); 6920Sigor@sysoev.ru static void nxt_controller_conn_free(nxt_task_t *task, void *obj, void *data); 7020Sigor@sysoev.ru 7127Svbart@nginx.com static nxt_int_t nxt_controller_request_content_length(void *ctx, 72417Svbart@nginx.com nxt_http_field_t *field, uintptr_t data); 7327Svbart@nginx.com 7427Svbart@nginx.com static void nxt_controller_process_request(nxt_task_t *task, 75140Svbart@nginx.com nxt_controller_request_t *req); 76774Svbart@nginx.com static void nxt_controller_process_config(nxt_task_t *task, 77774Svbart@nginx.com nxt_controller_request_t *req, nxt_str_t *path); 78774Svbart@nginx.com #if (NXT_TLS) 79774Svbart@nginx.com static void nxt_controller_process_cert(nxt_task_t *task, 80774Svbart@nginx.com nxt_controller_request_t *req, nxt_str_t *path); 81774Svbart@nginx.com static void nxt_controller_process_cert_save(nxt_task_t *task, 82774Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 83774Svbart@nginx.com static nxt_bool_t nxt_controller_cert_in_use(nxt_str_t *name); 84774Svbart@nginx.com #endif 85238Svbart@nginx.com static void nxt_controller_conf_handler(nxt_task_t *task, 86238Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 87314Svbart@nginx.com static void nxt_controller_conf_store(nxt_task_t *task, 88314Svbart@nginx.com nxt_conf_value_t *conf); 89140Svbart@nginx.com static void nxt_controller_response(nxt_task_t *task, 90140Svbart@nginx.com nxt_controller_request_t *req, nxt_controller_response_t *resp); 91208Svbart@nginx.com static u_char *nxt_controller_date(u_char *buf, nxt_realtime_t *now, 92208Svbart@nginx.com struct tm *tm, size_t size, const char *format); 9327Svbart@nginx.com 9427Svbart@nginx.com 95417Svbart@nginx.com static nxt_http_field_proc_t nxt_controller_request_fields[] = { 9627Svbart@nginx.com { nxt_string("Content-Length"), 9727Svbart@nginx.com &nxt_controller_request_content_length, 0 }, 9827Svbart@nginx.com }; 9927Svbart@nginx.com 100417Svbart@nginx.com static nxt_lvlhsh_t nxt_controller_fields_hash; 10127Svbart@nginx.com 102314Svbart@nginx.com static nxt_uint_t nxt_controller_listening; 103662Smax.romanov@nginx.com static nxt_uint_t nxt_controller_router_ready; 104238Svbart@nginx.com static nxt_controller_conf_t nxt_controller_conf; 105238Svbart@nginx.com static nxt_queue_t nxt_controller_waiting_requests; 10627Svbart@nginx.com 10720Sigor@sysoev.ru 10820Sigor@sysoev.ru static const nxt_event_conn_state_t nxt_controller_conn_read_state; 10927Svbart@nginx.com static const nxt_event_conn_state_t nxt_controller_conn_body_read_state; 11027Svbart@nginx.com static const nxt_event_conn_state_t nxt_controller_conn_write_state; 11120Sigor@sysoev.ru static const nxt_event_conn_state_t nxt_controller_conn_close_state; 11220Sigor@sysoev.ru 11320Sigor@sysoev.ru 114320Smax.romanov@nginx.com nxt_port_handlers_t nxt_controller_process_port_handlers = { 115662Smax.romanov@nginx.com .quit = nxt_worker_process_quit_handler, 116662Smax.romanov@nginx.com .new_port = nxt_controller_process_new_port_handler, 117662Smax.romanov@nginx.com .change_file = nxt_port_change_log_file_handler, 118662Smax.romanov@nginx.com .mmap = nxt_port_mmap_handler, 119662Smax.romanov@nginx.com .process_ready = nxt_controller_router_ready_handler, 120662Smax.romanov@nginx.com .data = nxt_port_data_handler, 121662Smax.romanov@nginx.com .remove_pid = nxt_port_remove_pid_handler, 122662Smax.romanov@nginx.com .rpc_ready = nxt_port_rpc_handler, 123662Smax.romanov@nginx.com .rpc_error = nxt_port_rpc_handler, 124248Svbart@nginx.com }; 125248Svbart@nginx.com 126248Svbart@nginx.com 12720Sigor@sysoev.ru nxt_int_t 128141Smax.romanov@nginx.com nxt_controller_start(nxt_task_t *task, void *data) 12920Sigor@sysoev.ru { 130417Svbart@nginx.com nxt_mp_t *mp; 131417Svbart@nginx.com nxt_int_t ret; 132417Svbart@nginx.com nxt_str_t *json; 133417Svbart@nginx.com nxt_runtime_t *rt; 134417Svbart@nginx.com nxt_conf_value_t *conf; 135417Svbart@nginx.com nxt_conf_validation_t vldt; 136774Svbart@nginx.com nxt_controller_init_t *init; 13727Svbart@nginx.com 138141Smax.romanov@nginx.com rt = task->thread->runtime; 139141Smax.romanov@nginx.com 140417Svbart@nginx.com ret = nxt_http_fields_hash(&nxt_controller_fields_hash, rt->mem_pool, 141417Svbart@nginx.com nxt_controller_request_fields, 142417Svbart@nginx.com nxt_nitems(nxt_controller_request_fields)); 143417Svbart@nginx.com 144417Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 14527Svbart@nginx.com return NXT_ERROR; 14627Svbart@nginx.com } 14727Svbart@nginx.com 148248Svbart@nginx.com nxt_queue_init(&nxt_controller_waiting_requests); 14927Svbart@nginx.com 150774Svbart@nginx.com init = data; 151774Svbart@nginx.com 152774Svbart@nginx.com #if (NXT_TLS) 153314Svbart@nginx.com 154774Svbart@nginx.com if (init->certs != NULL) { 155774Svbart@nginx.com nxt_cert_info_init(task, init->certs); 156774Svbart@nginx.com nxt_cert_store_release(init->certs); 157774Svbart@nginx.com } 158774Svbart@nginx.com 159774Svbart@nginx.com #endif 160774Svbart@nginx.com 161774Svbart@nginx.com json = &init->conf; 162774Svbart@nginx.com 163774Svbart@nginx.com if (json->start == NULL) { 164314Svbart@nginx.com return NXT_OK; 165314Svbart@nginx.com } 166314Svbart@nginx.com 167314Svbart@nginx.com mp = nxt_mp_create(1024, 128, 256, 32); 168314Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 169314Svbart@nginx.com return NXT_ERROR; 170314Svbart@nginx.com } 171314Svbart@nginx.com 172314Svbart@nginx.com conf = nxt_conf_json_parse_str(mp, json); 173314Svbart@nginx.com nxt_free(json->start); 174314Svbart@nginx.com 175314Svbart@nginx.com if (nxt_slow_path(conf == NULL)) { 176564Svbart@nginx.com nxt_alert(task, "failed to restore previous configuration: " 177564Svbart@nginx.com "file is corrupted or not enough memory"); 178314Svbart@nginx.com 179314Svbart@nginx.com nxt_mp_destroy(mp); 180314Svbart@nginx.com return NXT_OK; 181314Svbart@nginx.com } 182314Svbart@nginx.com 183357Svbart@nginx.com nxt_memzero(&vldt, sizeof(nxt_conf_validation_t)); 184314Svbart@nginx.com 185357Svbart@nginx.com vldt.pool = nxt_mp_create(1024, 128, 256, 32); 186357Svbart@nginx.com if (nxt_slow_path(vldt.pool == NULL)) { 1871013Smax.romanov@nginx.com nxt_mp_destroy(mp); 188357Svbart@nginx.com return NXT_ERROR; 189314Svbart@nginx.com } 190314Svbart@nginx.com 191357Svbart@nginx.com vldt.conf = conf; 192357Svbart@nginx.com 193357Svbart@nginx.com ret = nxt_conf_validate(&vldt); 194357Svbart@nginx.com 195357Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 196357Svbart@nginx.com 197357Svbart@nginx.com if (ret == NXT_DECLINED) { 198564Svbart@nginx.com nxt_alert(task, "the previous configuration is invalid: %V", 199564Svbart@nginx.com &vldt.error); 200357Svbart@nginx.com 201357Svbart@nginx.com nxt_mp_destroy(vldt.pool); 202357Svbart@nginx.com nxt_mp_destroy(mp); 203357Svbart@nginx.com 204357Svbart@nginx.com return NXT_OK; 205357Svbart@nginx.com } 206357Svbart@nginx.com 207357Svbart@nginx.com /* ret == NXT_ERROR */ 208357Svbart@nginx.com 209357Svbart@nginx.com return NXT_ERROR; 210357Svbart@nginx.com } 211357Svbart@nginx.com 212357Svbart@nginx.com nxt_mp_destroy(vldt.pool); 213314Svbart@nginx.com 214314Svbart@nginx.com nxt_controller_conf.root = conf; 215314Svbart@nginx.com nxt_controller_conf.pool = mp; 216314Svbart@nginx.com 217248Svbart@nginx.com return NXT_OK; 218248Svbart@nginx.com } 219248Svbart@nginx.com 220248Svbart@nginx.com 221248Svbart@nginx.com static void 222248Svbart@nginx.com nxt_controller_process_new_port_handler(nxt_task_t *task, 223248Svbart@nginx.com nxt_port_recv_msg_t *msg) 224248Svbart@nginx.com { 225662Smax.romanov@nginx.com nxt_port_new_port_handler(task, msg); 226662Smax.romanov@nginx.com 227662Smax.romanov@nginx.com if (msg->u.new_port->type != NXT_PROCESS_ROUTER 228662Smax.romanov@nginx.com || !nxt_controller_router_ready) 229662Smax.romanov@nginx.com { 230662Smax.romanov@nginx.com return; 231662Smax.romanov@nginx.com } 232662Smax.romanov@nginx.com 233662Smax.romanov@nginx.com nxt_controller_send_current_conf(task); 234662Smax.romanov@nginx.com } 235662Smax.romanov@nginx.com 236662Smax.romanov@nginx.com 237662Smax.romanov@nginx.com static void 238662Smax.romanov@nginx.com nxt_controller_send_current_conf(nxt_task_t *task) 239662Smax.romanov@nginx.com { 240249Svbart@nginx.com nxt_int_t rc; 241248Svbart@nginx.com nxt_runtime_t *rt; 242248Svbart@nginx.com nxt_conf_value_t *conf; 243248Svbart@nginx.com 244249Svbart@nginx.com conf = nxt_controller_conf.root; 245249Svbart@nginx.com 246249Svbart@nginx.com if (conf != NULL) { 247249Svbart@nginx.com rc = nxt_controller_conf_send(task, conf, 248249Svbart@nginx.com nxt_controller_conf_init_handler, NULL); 24944Svbart@nginx.com 250249Svbart@nginx.com if (nxt_fast_path(rc == NXT_OK)) { 251249Svbart@nginx.com return; 252249Svbart@nginx.com } 253249Svbart@nginx.com 254249Svbart@nginx.com nxt_mp_destroy(nxt_controller_conf.pool); 255249Svbart@nginx.com 256249Svbart@nginx.com if (nxt_slow_path(nxt_controller_conf_default() != NXT_OK)) { 257249Svbart@nginx.com nxt_abort(); 258249Svbart@nginx.com } 25944Svbart@nginx.com } 26044Svbart@nginx.com 261249Svbart@nginx.com if (nxt_slow_path(nxt_controller_conf_default() != NXT_OK)) { 262248Svbart@nginx.com nxt_abort(); 26344Svbart@nginx.com } 26444Svbart@nginx.com 265248Svbart@nginx.com rt = task->thread->runtime; 266140Svbart@nginx.com 267248Svbart@nginx.com if (nxt_slow_path(nxt_listen_event(task, rt->controller_socket) == NULL)) { 268248Svbart@nginx.com nxt_abort(); 269248Svbart@nginx.com } 270314Svbart@nginx.com 271314Svbart@nginx.com nxt_controller_listening = 1; 27220Sigor@sysoev.ru } 27320Sigor@sysoev.ru 27420Sigor@sysoev.ru 275662Smax.romanov@nginx.com static void 276662Smax.romanov@nginx.com nxt_controller_router_ready_handler(nxt_task_t *task, 277662Smax.romanov@nginx.com nxt_port_recv_msg_t *msg) 278662Smax.romanov@nginx.com { 279662Smax.romanov@nginx.com nxt_port_t *router_port; 280662Smax.romanov@nginx.com nxt_runtime_t *rt; 281662Smax.romanov@nginx.com 282662Smax.romanov@nginx.com rt = task->thread->runtime; 283662Smax.romanov@nginx.com 284662Smax.romanov@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 285662Smax.romanov@nginx.com 286662Smax.romanov@nginx.com nxt_controller_router_ready = 1; 287662Smax.romanov@nginx.com 288662Smax.romanov@nginx.com if (router_port != NULL) { 289662Smax.romanov@nginx.com nxt_controller_send_current_conf(task); 290662Smax.romanov@nginx.com } 291662Smax.romanov@nginx.com } 292662Smax.romanov@nginx.com 293662Smax.romanov@nginx.com 294249Svbart@nginx.com static nxt_int_t 295249Svbart@nginx.com nxt_controller_conf_default(void) 296249Svbart@nginx.com { 297249Svbart@nginx.com nxt_mp_t *mp; 298249Svbart@nginx.com nxt_conf_value_t *conf; 299249Svbart@nginx.com 300249Svbart@nginx.com static const nxt_str_t json 301249Svbart@nginx.com = nxt_string("{ \"listeners\": {}, \"applications\": {} }"); 302249Svbart@nginx.com 303249Svbart@nginx.com mp = nxt_mp_create(1024, 128, 256, 32); 304249Svbart@nginx.com 305249Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 306249Svbart@nginx.com return NXT_ERROR; 307249Svbart@nginx.com } 308249Svbart@nginx.com 309249Svbart@nginx.com conf = nxt_conf_json_parse_str(mp, &json); 310249Svbart@nginx.com 311249Svbart@nginx.com if (nxt_slow_path(conf == NULL)) { 312249Svbart@nginx.com return NXT_ERROR; 313249Svbart@nginx.com } 314249Svbart@nginx.com 315249Svbart@nginx.com nxt_controller_conf.root = conf; 316249Svbart@nginx.com nxt_controller_conf.pool = mp; 317249Svbart@nginx.com 318249Svbart@nginx.com return NXT_OK; 319249Svbart@nginx.com } 320249Svbart@nginx.com 321249Svbart@nginx.com 322249Svbart@nginx.com static void 323249Svbart@nginx.com nxt_controller_conf_init_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 324249Svbart@nginx.com void *data) 325249Svbart@nginx.com { 326314Svbart@nginx.com nxt_runtime_t *rt; 327314Svbart@nginx.com 328249Svbart@nginx.com if (msg->port_msg.type != NXT_PORT_MSG_RPC_READY) { 329564Svbart@nginx.com nxt_alert(task, "failed to apply previous configuration"); 330314Svbart@nginx.com 331249Svbart@nginx.com nxt_mp_destroy(nxt_controller_conf.pool); 332249Svbart@nginx.com 333249Svbart@nginx.com if (nxt_slow_path(nxt_controller_conf_default() != NXT_OK)) { 334249Svbart@nginx.com nxt_abort(); 335249Svbart@nginx.com } 336249Svbart@nginx.com } 337314Svbart@nginx.com 338314Svbart@nginx.com if (nxt_controller_listening == 0) { 339314Svbart@nginx.com rt = task->thread->runtime; 340314Svbart@nginx.com 341314Svbart@nginx.com if (nxt_slow_path(nxt_listen_event(task, rt->controller_socket) 342314Svbart@nginx.com == NULL)) 343314Svbart@nginx.com { 344314Svbart@nginx.com nxt_abort(); 345314Svbart@nginx.com } 346314Svbart@nginx.com 347314Svbart@nginx.com nxt_controller_listening = 1; 348314Svbart@nginx.com } 349249Svbart@nginx.com } 350249Svbart@nginx.com 351249Svbart@nginx.com 352249Svbart@nginx.com static nxt_int_t 353249Svbart@nginx.com nxt_controller_conf_send(nxt_task_t *task, nxt_conf_value_t *conf, 354249Svbart@nginx.com nxt_port_rpc_handler_t handler, void *data) 355249Svbart@nginx.com { 356249Svbart@nginx.com size_t size; 357249Svbart@nginx.com uint32_t stream; 358249Svbart@nginx.com nxt_int_t rc; 359249Svbart@nginx.com nxt_buf_t *b; 360249Svbart@nginx.com nxt_port_t *router_port, *controller_port; 361249Svbart@nginx.com nxt_runtime_t *rt; 362249Svbart@nginx.com 363249Svbart@nginx.com rt = task->thread->runtime; 364249Svbart@nginx.com 365249Svbart@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 366249Svbart@nginx.com 367662Smax.romanov@nginx.com if (nxt_slow_path(router_port == NULL || !nxt_controller_router_ready)) { 368249Svbart@nginx.com return NXT_DECLINED; 369249Svbart@nginx.com } 370249Svbart@nginx.com 371249Svbart@nginx.com controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER]; 372249Svbart@nginx.com 373249Svbart@nginx.com size = nxt_conf_json_length(conf, NULL); 374249Svbart@nginx.com 375249Svbart@nginx.com b = nxt_port_mmap_get_buf(task, router_port, size); 376379Smax.romanov@nginx.com if (nxt_slow_path(b == NULL)) { 377379Smax.romanov@nginx.com return NXT_ERROR; 378379Smax.romanov@nginx.com } 379249Svbart@nginx.com 380249Svbart@nginx.com b->mem.free = nxt_conf_json_print(b->mem.free, conf, NULL); 381249Svbart@nginx.com 382249Svbart@nginx.com stream = nxt_port_rpc_register_handler(task, controller_port, 383249Svbart@nginx.com handler, handler, 384249Svbart@nginx.com router_port->pid, data); 385249Svbart@nginx.com 386645Svbart@nginx.com if (nxt_slow_path(stream == 0)) { 387645Svbart@nginx.com return NXT_ERROR; 388645Svbart@nginx.com } 389645Svbart@nginx.com 390249Svbart@nginx.com rc = nxt_port_socket_write(task, router_port, NXT_PORT_MSG_DATA_LAST, -1, 391249Svbart@nginx.com stream, controller_port->id, b); 392249Svbart@nginx.com 393249Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 394249Svbart@nginx.com nxt_port_rpc_cancel(task, controller_port, stream); 395249Svbart@nginx.com return NXT_ERROR; 396249Svbart@nginx.com } 397249Svbart@nginx.com 398249Svbart@nginx.com return NXT_OK; 399249Svbart@nginx.com } 400249Svbart@nginx.com 401249Svbart@nginx.com 40220Sigor@sysoev.ru nxt_int_t 40320Sigor@sysoev.ru nxt_runtime_controller_socket(nxt_task_t *task, nxt_runtime_t *rt) 40420Sigor@sysoev.ru { 40520Sigor@sysoev.ru nxt_listen_socket_t *ls; 40620Sigor@sysoev.ru 40765Sigor@sysoev.ru ls = nxt_mp_alloc(rt->mem_pool, sizeof(nxt_listen_socket_t)); 40820Sigor@sysoev.ru if (ls == NULL) { 40920Sigor@sysoev.ru return NXT_ERROR; 41020Sigor@sysoev.ru } 41120Sigor@sysoev.ru 4121448Svbart@nginx.com ls->sockaddr = rt->controller_listen; 41320Sigor@sysoev.ru 414359Sigor@sysoev.ru nxt_listen_socket_remote_size(ls); 41520Sigor@sysoev.ru 41620Sigor@sysoev.ru ls->socket = -1; 41720Sigor@sysoev.ru ls->backlog = NXT_LISTEN_BACKLOG; 41820Sigor@sysoev.ru ls->read_after_accept = 1; 41920Sigor@sysoev.ru ls->flags = NXT_NONBLOCK; 42020Sigor@sysoev.ru 42120Sigor@sysoev.ru #if 0 42220Sigor@sysoev.ru /* STUB */ 42365Sigor@sysoev.ru wq = nxt_mp_zget(cf->mem_pool, sizeof(nxt_work_queue_t)); 42420Sigor@sysoev.ru if (wq == NULL) { 42520Sigor@sysoev.ru return NXT_ERROR; 42620Sigor@sysoev.ru } 42720Sigor@sysoev.ru nxt_work_queue_name(wq, "listen"); 42820Sigor@sysoev.ru /**/ 42920Sigor@sysoev.ru 43020Sigor@sysoev.ru ls->work_queue = wq; 43120Sigor@sysoev.ru #endif 43220Sigor@sysoev.ru ls->handler = nxt_controller_conn_init; 43320Sigor@sysoev.ru 434*1451Svbart@nginx.com if (nxt_listen_socket_create(task, rt->mem_pool, ls) != NXT_OK) { 43520Sigor@sysoev.ru return NXT_ERROR; 43620Sigor@sysoev.ru } 43720Sigor@sysoev.ru 43820Sigor@sysoev.ru rt->controller_socket = ls; 43920Sigor@sysoev.ru 44020Sigor@sysoev.ru return NXT_OK; 44120Sigor@sysoev.ru } 44220Sigor@sysoev.ru 44320Sigor@sysoev.ru 44420Sigor@sysoev.ru static void 44520Sigor@sysoev.ru nxt_controller_conn_init(nxt_task_t *task, void *obj, void *data) 44620Sigor@sysoev.ru { 44727Svbart@nginx.com nxt_buf_t *b; 44862Sigor@sysoev.ru nxt_conn_t *c; 44927Svbart@nginx.com nxt_event_engine_t *engine; 45027Svbart@nginx.com nxt_controller_request_t *r; 45120Sigor@sysoev.ru 45220Sigor@sysoev.ru c = obj; 45320Sigor@sysoev.ru 45420Sigor@sysoev.ru nxt_debug(task, "controller conn init fd:%d", c->socket.fd); 45520Sigor@sysoev.ru 45665Sigor@sysoev.ru r = nxt_mp_zget(c->mem_pool, sizeof(nxt_controller_request_t)); 45727Svbart@nginx.com if (nxt_slow_path(r == NULL)) { 45827Svbart@nginx.com nxt_controller_conn_free(task, c, NULL); 45927Svbart@nginx.com return; 46027Svbart@nginx.com } 46127Svbart@nginx.com 462140Svbart@nginx.com r->conn = c; 463140Svbart@nginx.com 46460Svbart@nginx.com if (nxt_slow_path(nxt_http_parse_request_init(&r->parser, c->mem_pool) 46560Svbart@nginx.com != NXT_OK)) 46660Svbart@nginx.com { 46760Svbart@nginx.com nxt_controller_conn_free(task, c, NULL); 46860Svbart@nginx.com return; 46960Svbart@nginx.com } 47027Svbart@nginx.com 4711167Svbart@nginx.com r->parser.encoded_slashes = 1; 4721167Svbart@nginx.com 47320Sigor@sysoev.ru b = nxt_buf_mem_alloc(c->mem_pool, 1024, 0); 47420Sigor@sysoev.ru if (nxt_slow_path(b == NULL)) { 47520Sigor@sysoev.ru nxt_controller_conn_free(task, c, NULL); 47620Sigor@sysoev.ru return; 47720Sigor@sysoev.ru } 47820Sigor@sysoev.ru 47920Sigor@sysoev.ru c->read = b; 48027Svbart@nginx.com c->socket.data = r; 48120Sigor@sysoev.ru c->socket.read_ready = 1; 48220Sigor@sysoev.ru c->read_state = &nxt_controller_conn_read_state; 48320Sigor@sysoev.ru 48420Sigor@sysoev.ru engine = task->thread->engine; 48520Sigor@sysoev.ru c->read_work_queue = &engine->read_work_queue; 48627Svbart@nginx.com c->write_work_queue = &engine->write_work_queue; 48720Sigor@sysoev.ru 48862Sigor@sysoev.ru nxt_conn_read(engine, c); 48920Sigor@sysoev.ru } 49020Sigor@sysoev.ru 49120Sigor@sysoev.ru 49220Sigor@sysoev.ru static const nxt_event_conn_state_t nxt_controller_conn_read_state 49320Sigor@sysoev.ru nxt_aligned(64) = 49420Sigor@sysoev.ru { 49556Sigor@sysoev.ru .ready_handler = nxt_controller_conn_read, 49656Sigor@sysoev.ru .close_handler = nxt_controller_conn_close, 49756Sigor@sysoev.ru .error_handler = nxt_controller_conn_read_error, 49820Sigor@sysoev.ru 49956Sigor@sysoev.ru .timer_handler = nxt_controller_conn_read_timeout, 50056Sigor@sysoev.ru .timer_value = nxt_controller_conn_timeout_value, 50156Sigor@sysoev.ru .timer_data = 60 * 1000, 50220Sigor@sysoev.ru }; 50320Sigor@sysoev.ru 50420Sigor@sysoev.ru 50520Sigor@sysoev.ru static void 50620Sigor@sysoev.ru nxt_controller_conn_read(nxt_task_t *task, void *obj, void *data) 50720Sigor@sysoev.ru { 50827Svbart@nginx.com size_t preread; 50927Svbart@nginx.com nxt_buf_t *b; 51027Svbart@nginx.com nxt_int_t rc; 51162Sigor@sysoev.ru nxt_conn_t *c; 51227Svbart@nginx.com nxt_controller_request_t *r; 51320Sigor@sysoev.ru 51420Sigor@sysoev.ru c = obj; 51527Svbart@nginx.com r = data; 51620Sigor@sysoev.ru 51720Sigor@sysoev.ru nxt_debug(task, "controller conn read"); 51820Sigor@sysoev.ru 51927Svbart@nginx.com nxt_queue_remove(&c->link); 52027Svbart@nginx.com nxt_queue_self(&c->link); 52127Svbart@nginx.com 52227Svbart@nginx.com b = c->read; 52327Svbart@nginx.com 52427Svbart@nginx.com rc = nxt_http_parse_request(&r->parser, &b->mem); 52527Svbart@nginx.com 52627Svbart@nginx.com if (nxt_slow_path(rc != NXT_DONE)) { 52727Svbart@nginx.com 52827Svbart@nginx.com if (rc == NXT_AGAIN) { 52927Svbart@nginx.com if (nxt_buf_mem_free_size(&b->mem) == 0) { 53027Svbart@nginx.com nxt_log(task, NXT_LOG_ERR, "too long request headers"); 53127Svbart@nginx.com nxt_controller_conn_close(task, c, r); 53227Svbart@nginx.com return; 53327Svbart@nginx.com } 53427Svbart@nginx.com 53562Sigor@sysoev.ru nxt_conn_read(task->thread->engine, c); 53627Svbart@nginx.com return; 53727Svbart@nginx.com } 53827Svbart@nginx.com 53927Svbart@nginx.com /* rc == NXT_ERROR */ 54027Svbart@nginx.com 54127Svbart@nginx.com nxt_log(task, NXT_LOG_ERR, "parsing error"); 54227Svbart@nginx.com 54327Svbart@nginx.com nxt_controller_conn_close(task, c, r); 54427Svbart@nginx.com return; 54527Svbart@nginx.com } 54627Svbart@nginx.com 547417Svbart@nginx.com rc = nxt_http_fields_process(r->parser.fields, &nxt_controller_fields_hash, 548417Svbart@nginx.com r); 54960Svbart@nginx.com 55060Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 55160Svbart@nginx.com nxt_controller_conn_close(task, c, r); 55260Svbart@nginx.com return; 55360Svbart@nginx.com } 55460Svbart@nginx.com 55527Svbart@nginx.com preread = nxt_buf_mem_used_size(&b->mem); 55627Svbart@nginx.com 55727Svbart@nginx.com nxt_debug(task, "controller request header parsing complete, " 558107Svbart@nginx.com "body length: %uz, preread: %uz", 55927Svbart@nginx.com r->length, preread); 56027Svbart@nginx.com 56127Svbart@nginx.com if (preread >= r->length) { 562140Svbart@nginx.com nxt_controller_process_request(task, r); 56327Svbart@nginx.com return; 56427Svbart@nginx.com } 56527Svbart@nginx.com 56627Svbart@nginx.com if (r->length - preread > (size_t) nxt_buf_mem_free_size(&b->mem)) { 56727Svbart@nginx.com b = nxt_buf_mem_alloc(c->mem_pool, r->length, 0); 56827Svbart@nginx.com if (nxt_slow_path(b == NULL)) { 56927Svbart@nginx.com nxt_controller_conn_free(task, c, NULL); 57027Svbart@nginx.com return; 57127Svbart@nginx.com } 57227Svbart@nginx.com 57327Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, c->read->mem.pos, preread); 57427Svbart@nginx.com 57527Svbart@nginx.com c->read = b; 57627Svbart@nginx.com } 57727Svbart@nginx.com 57827Svbart@nginx.com c->read_state = &nxt_controller_conn_body_read_state; 57927Svbart@nginx.com 58062Sigor@sysoev.ru nxt_conn_read(task->thread->engine, c); 58120Sigor@sysoev.ru } 58220Sigor@sysoev.ru 58320Sigor@sysoev.ru 58420Sigor@sysoev.ru static nxt_msec_t 58562Sigor@sysoev.ru nxt_controller_conn_timeout_value(nxt_conn_t *c, uintptr_t data) 58620Sigor@sysoev.ru { 58720Sigor@sysoev.ru return (nxt_msec_t) data; 58820Sigor@sysoev.ru } 58920Sigor@sysoev.ru 59020Sigor@sysoev.ru 59120Sigor@sysoev.ru static void 59220Sigor@sysoev.ru nxt_controller_conn_read_error(nxt_task_t *task, void *obj, void *data) 59320Sigor@sysoev.ru { 59462Sigor@sysoev.ru nxt_conn_t *c; 59520Sigor@sysoev.ru 59620Sigor@sysoev.ru c = obj; 59720Sigor@sysoev.ru 59820Sigor@sysoev.ru nxt_debug(task, "controller conn read error"); 59920Sigor@sysoev.ru 60027Svbart@nginx.com nxt_controller_conn_close(task, c, data); 60120Sigor@sysoev.ru } 60220Sigor@sysoev.ru 60320Sigor@sysoev.ru 60420Sigor@sysoev.ru static void 60520Sigor@sysoev.ru nxt_controller_conn_read_timeout(nxt_task_t *task, void *obj, void *data) 60620Sigor@sysoev.ru { 60762Sigor@sysoev.ru nxt_timer_t *timer; 60862Sigor@sysoev.ru nxt_conn_t *c; 60920Sigor@sysoev.ru 61062Sigor@sysoev.ru timer = obj; 61120Sigor@sysoev.ru 61262Sigor@sysoev.ru c = nxt_read_timer_conn(timer); 61320Sigor@sysoev.ru c->socket.timedout = 1; 61420Sigor@sysoev.ru c->socket.closed = 1; 61520Sigor@sysoev.ru 61620Sigor@sysoev.ru nxt_debug(task, "controller conn read timeout"); 61720Sigor@sysoev.ru 61827Svbart@nginx.com nxt_controller_conn_close(task, c, data); 61927Svbart@nginx.com } 62027Svbart@nginx.com 62127Svbart@nginx.com 62227Svbart@nginx.com static const nxt_event_conn_state_t nxt_controller_conn_body_read_state 62327Svbart@nginx.com nxt_aligned(64) = 62427Svbart@nginx.com { 62556Sigor@sysoev.ru .ready_handler = nxt_controller_conn_body_read, 62656Sigor@sysoev.ru .close_handler = nxt_controller_conn_close, 62756Sigor@sysoev.ru .error_handler = nxt_controller_conn_read_error, 62827Svbart@nginx.com 62956Sigor@sysoev.ru .timer_handler = nxt_controller_conn_read_timeout, 63056Sigor@sysoev.ru .timer_value = nxt_controller_conn_timeout_value, 63156Sigor@sysoev.ru .timer_data = 60 * 1000, 63256Sigor@sysoev.ru .timer_autoreset = 1, 63327Svbart@nginx.com }; 63427Svbart@nginx.com 63527Svbart@nginx.com 63627Svbart@nginx.com static void 63727Svbart@nginx.com nxt_controller_conn_body_read(nxt_task_t *task, void *obj, void *data) 63827Svbart@nginx.com { 639107Svbart@nginx.com size_t read; 640107Svbart@nginx.com nxt_buf_t *b; 641107Svbart@nginx.com nxt_conn_t *c; 642107Svbart@nginx.com nxt_controller_request_t *r; 64327Svbart@nginx.com 64427Svbart@nginx.com c = obj; 645107Svbart@nginx.com r = data; 64627Svbart@nginx.com b = c->read; 64727Svbart@nginx.com 648107Svbart@nginx.com read = nxt_buf_mem_used_size(&b->mem); 64927Svbart@nginx.com 650107Svbart@nginx.com nxt_debug(task, "controller conn body read: %uz of %uz", 651107Svbart@nginx.com read, r->length); 65227Svbart@nginx.com 653107Svbart@nginx.com if (read >= r->length) { 654140Svbart@nginx.com nxt_controller_process_request(task, r); 65527Svbart@nginx.com return; 65627Svbart@nginx.com } 65727Svbart@nginx.com 65862Sigor@sysoev.ru nxt_conn_read(task->thread->engine, c); 65927Svbart@nginx.com } 66027Svbart@nginx.com 66127Svbart@nginx.com 66227Svbart@nginx.com static const nxt_event_conn_state_t nxt_controller_conn_write_state 66327Svbart@nginx.com nxt_aligned(64) = 66427Svbart@nginx.com { 66556Sigor@sysoev.ru .ready_handler = nxt_controller_conn_write, 66656Sigor@sysoev.ru .error_handler = nxt_controller_conn_write_error, 66727Svbart@nginx.com 66856Sigor@sysoev.ru .timer_handler = nxt_controller_conn_write_timeout, 66956Sigor@sysoev.ru .timer_value = nxt_controller_conn_timeout_value, 67056Sigor@sysoev.ru .timer_data = 60 * 1000, 67156Sigor@sysoev.ru .timer_autoreset = 1, 67227Svbart@nginx.com }; 67327Svbart@nginx.com 67427Svbart@nginx.com 67527Svbart@nginx.com static void 67627Svbart@nginx.com nxt_controller_conn_write(nxt_task_t *task, void *obj, void *data) 67727Svbart@nginx.com { 67862Sigor@sysoev.ru nxt_buf_t *b; 67962Sigor@sysoev.ru nxt_conn_t *c; 68027Svbart@nginx.com 68127Svbart@nginx.com c = obj; 68227Svbart@nginx.com 68327Svbart@nginx.com nxt_debug(task, "controller conn write"); 68427Svbart@nginx.com 68527Svbart@nginx.com b = c->write; 68627Svbart@nginx.com 68727Svbart@nginx.com if (b->mem.pos != b->mem.free) { 68862Sigor@sysoev.ru nxt_conn_write(task->thread->engine, c); 68927Svbart@nginx.com return; 69027Svbart@nginx.com } 69127Svbart@nginx.com 69227Svbart@nginx.com nxt_debug(task, "controller conn write complete"); 69327Svbart@nginx.com 69427Svbart@nginx.com nxt_controller_conn_close(task, c, data); 69527Svbart@nginx.com } 69627Svbart@nginx.com 69727Svbart@nginx.com 69827Svbart@nginx.com static void 69927Svbart@nginx.com nxt_controller_conn_write_error(nxt_task_t *task, void *obj, void *data) 70027Svbart@nginx.com { 70162Sigor@sysoev.ru nxt_conn_t *c; 70227Svbart@nginx.com 70327Svbart@nginx.com c = obj; 70427Svbart@nginx.com 70527Svbart@nginx.com nxt_debug(task, "controller conn write error"); 70627Svbart@nginx.com 70727Svbart@nginx.com nxt_controller_conn_close(task, c, data); 70827Svbart@nginx.com } 70927Svbart@nginx.com 71027Svbart@nginx.com 71127Svbart@nginx.com static void 71227Svbart@nginx.com nxt_controller_conn_write_timeout(nxt_task_t *task, void *obj, void *data) 71327Svbart@nginx.com { 71462Sigor@sysoev.ru nxt_conn_t *c; 71562Sigor@sysoev.ru nxt_timer_t *timer; 71627Svbart@nginx.com 71762Sigor@sysoev.ru timer = obj; 71827Svbart@nginx.com 71962Sigor@sysoev.ru c = nxt_write_timer_conn(timer); 72027Svbart@nginx.com c->socket.timedout = 1; 72127Svbart@nginx.com c->socket.closed = 1; 72227Svbart@nginx.com 72327Svbart@nginx.com nxt_debug(task, "controller conn write timeout"); 72427Svbart@nginx.com 72527Svbart@nginx.com nxt_controller_conn_close(task, c, data); 72620Sigor@sysoev.ru } 72720Sigor@sysoev.ru 72820Sigor@sysoev.ru 72920Sigor@sysoev.ru static const nxt_event_conn_state_t nxt_controller_conn_close_state 73020Sigor@sysoev.ru nxt_aligned(64) = 73120Sigor@sysoev.ru { 73256Sigor@sysoev.ru .ready_handler = nxt_controller_conn_free, 73320Sigor@sysoev.ru }; 73420Sigor@sysoev.ru 73520Sigor@sysoev.ru 73620Sigor@sysoev.ru static void 73720Sigor@sysoev.ru nxt_controller_conn_close(nxt_task_t *task, void *obj, void *data) 73820Sigor@sysoev.ru { 73962Sigor@sysoev.ru nxt_conn_t *c; 74020Sigor@sysoev.ru 74120Sigor@sysoev.ru c = obj; 74220Sigor@sysoev.ru 74320Sigor@sysoev.ru nxt_debug(task, "controller conn close"); 74420Sigor@sysoev.ru 74527Svbart@nginx.com nxt_queue_remove(&c->link); 74627Svbart@nginx.com 74720Sigor@sysoev.ru c->write_state = &nxt_controller_conn_close_state; 74820Sigor@sysoev.ru 74962Sigor@sysoev.ru nxt_conn_close(task->thread->engine, c); 75020Sigor@sysoev.ru } 75120Sigor@sysoev.ru 75220Sigor@sysoev.ru 75320Sigor@sysoev.ru static void 75420Sigor@sysoev.ru nxt_controller_conn_free(nxt_task_t *task, void *obj, void *data) 75520Sigor@sysoev.ru { 75662Sigor@sysoev.ru nxt_conn_t *c; 75720Sigor@sysoev.ru 75820Sigor@sysoev.ru c = obj; 75920Sigor@sysoev.ru 76020Sigor@sysoev.ru nxt_debug(task, "controller conn free"); 76120Sigor@sysoev.ru 762337Sigor@sysoev.ru nxt_sockaddr_cache_free(task->thread->engine, c); 763337Sigor@sysoev.ru 764386Sigor@sysoev.ru nxt_conn_free(task, c); 76520Sigor@sysoev.ru } 76627Svbart@nginx.com 76727Svbart@nginx.com 76827Svbart@nginx.com static nxt_int_t 76960Svbart@nginx.com nxt_controller_request_content_length(void *ctx, nxt_http_field_t *field, 770417Svbart@nginx.com uintptr_t data) 77127Svbart@nginx.com { 77227Svbart@nginx.com off_t length; 77327Svbart@nginx.com nxt_controller_request_t *r; 77427Svbart@nginx.com 77527Svbart@nginx.com r = ctx; 77627Svbart@nginx.com 777417Svbart@nginx.com length = nxt_off_t_parse(field->value, field->value_length); 77827Svbart@nginx.com 779710Svbart@nginx.com if (nxt_fast_path(length >= 0)) { 780107Svbart@nginx.com 781107Svbart@nginx.com if (nxt_slow_path(length > NXT_SIZE_T_MAX)) { 782417Svbart@nginx.com nxt_log_error(NXT_LOG_ERR, &r->conn->log, 783417Svbart@nginx.com "Content-Length is too big"); 784107Svbart@nginx.com return NXT_ERROR; 785107Svbart@nginx.com } 78627Svbart@nginx.com 78727Svbart@nginx.com r->length = length; 78827Svbart@nginx.com return NXT_OK; 78927Svbart@nginx.com } 79027Svbart@nginx.com 791417Svbart@nginx.com nxt_log_error(NXT_LOG_ERR, &r->conn->log, "Content-Length is invalid"); 79227Svbart@nginx.com 79327Svbart@nginx.com return NXT_ERROR; 79427Svbart@nginx.com } 79527Svbart@nginx.com 79627Svbart@nginx.com 79727Svbart@nginx.com static void 798140Svbart@nginx.com nxt_controller_process_request(nxt_task_t *task, nxt_controller_request_t *req) 79927Svbart@nginx.com { 800774Svbart@nginx.com uint32_t i, count; 801774Svbart@nginx.com nxt_str_t path; 802774Svbart@nginx.com nxt_conn_t *c; 803774Svbart@nginx.com nxt_conf_value_t *value; 804774Svbart@nginx.com nxt_controller_response_t resp; 805774Svbart@nginx.com #if (NXT_TLS) 806774Svbart@nginx.com nxt_conf_value_t *certs; 807774Svbart@nginx.com 808774Svbart@nginx.com static nxt_str_t certificates = nxt_string("certificates"); 809774Svbart@nginx.com #endif 810774Svbart@nginx.com static nxt_str_t config = nxt_string("config"); 811774Svbart@nginx.com 812774Svbart@nginx.com c = req->conn; 813774Svbart@nginx.com path = req->parser.path; 814774Svbart@nginx.com 815774Svbart@nginx.com if (path.length > 1 && path.start[path.length - 1] == '/') { 816774Svbart@nginx.com path.length--; 817774Svbart@nginx.com } 818774Svbart@nginx.com 819774Svbart@nginx.com if (nxt_str_start(&path, "/config", 7) 820774Svbart@nginx.com && (path.length == 7 || path.start[7] == '/')) 821774Svbart@nginx.com { 822774Svbart@nginx.com if (path.length == 7) { 823774Svbart@nginx.com path.length = 1; 824774Svbart@nginx.com 825774Svbart@nginx.com } else { 826774Svbart@nginx.com path.length -= 7; 827774Svbart@nginx.com path.start += 7; 828774Svbart@nginx.com } 829774Svbart@nginx.com 830774Svbart@nginx.com nxt_controller_process_config(task, req, &path); 831774Svbart@nginx.com return; 832774Svbart@nginx.com } 833774Svbart@nginx.com 834774Svbart@nginx.com #if (NXT_TLS) 835774Svbart@nginx.com 836774Svbart@nginx.com if (nxt_str_start(&path, "/certificates", 13) 837774Svbart@nginx.com && (path.length == 13 || path.start[13] == '/')) 838774Svbart@nginx.com { 839774Svbart@nginx.com if (path.length == 13) { 840774Svbart@nginx.com path.length = 1; 841774Svbart@nginx.com 842774Svbart@nginx.com } else { 843774Svbart@nginx.com path.length -= 13; 844774Svbart@nginx.com path.start += 13; 845774Svbart@nginx.com } 846774Svbart@nginx.com 847774Svbart@nginx.com nxt_controller_process_cert(task, req, &path); 848774Svbart@nginx.com return; 849774Svbart@nginx.com } 850774Svbart@nginx.com 851774Svbart@nginx.com #endif 852774Svbart@nginx.com 853774Svbart@nginx.com nxt_memzero(&resp, sizeof(nxt_controller_response_t)); 854774Svbart@nginx.com 855774Svbart@nginx.com if (path.length == 1 && path.start[0] == '/') { 856774Svbart@nginx.com 857774Svbart@nginx.com if (!nxt_str_eq(&req->parser.method, "GET", 3)) { 858774Svbart@nginx.com goto invalid_method; 859774Svbart@nginx.com } 860774Svbart@nginx.com 861774Svbart@nginx.com count = 1; 862774Svbart@nginx.com #if (NXT_TLS) 863774Svbart@nginx.com count++; 864774Svbart@nginx.com #endif 865774Svbart@nginx.com 866774Svbart@nginx.com value = nxt_conf_create_object(c->mem_pool, count); 867774Svbart@nginx.com if (nxt_slow_path(value == NULL)) { 868774Svbart@nginx.com goto alloc_fail; 869774Svbart@nginx.com } 870774Svbart@nginx.com 871774Svbart@nginx.com i = 0; 872774Svbart@nginx.com 873774Svbart@nginx.com #if (NXT_TLS) 874774Svbart@nginx.com certs = nxt_cert_info_get_all(c->mem_pool); 875774Svbart@nginx.com if (nxt_slow_path(certs == NULL)) { 876774Svbart@nginx.com goto alloc_fail; 877774Svbart@nginx.com } 878774Svbart@nginx.com 879774Svbart@nginx.com nxt_conf_set_member(value, &certificates, certs, i++); 880774Svbart@nginx.com #endif 881774Svbart@nginx.com 882774Svbart@nginx.com nxt_conf_set_member(value, &config, nxt_controller_conf.root, i); 883774Svbart@nginx.com 884774Svbart@nginx.com resp.status = 200; 885774Svbart@nginx.com resp.conf = value; 886774Svbart@nginx.com 887774Svbart@nginx.com nxt_controller_response(task, req, &resp); 888774Svbart@nginx.com return; 889774Svbart@nginx.com } 890774Svbart@nginx.com 891774Svbart@nginx.com resp.status = 404; 892774Svbart@nginx.com resp.title = (u_char *) "Value doesn't exist."; 893774Svbart@nginx.com resp.offset = -1; 894774Svbart@nginx.com 895774Svbart@nginx.com nxt_controller_response(task, req, &resp); 896774Svbart@nginx.com return; 897774Svbart@nginx.com 898774Svbart@nginx.com invalid_method: 899774Svbart@nginx.com 900774Svbart@nginx.com resp.status = 405; 901774Svbart@nginx.com resp.title = (u_char *) "Invalid method."; 902774Svbart@nginx.com resp.offset = -1; 903774Svbart@nginx.com 904774Svbart@nginx.com nxt_controller_response(task, req, &resp); 905774Svbart@nginx.com return; 906774Svbart@nginx.com 907774Svbart@nginx.com alloc_fail: 908774Svbart@nginx.com 909774Svbart@nginx.com resp.status = 500; 910774Svbart@nginx.com resp.title = (u_char *) "Memory allocation failed."; 911774Svbart@nginx.com resp.offset = -1; 912774Svbart@nginx.com 913774Svbart@nginx.com nxt_controller_response(task, req, &resp); 914774Svbart@nginx.com return; 915774Svbart@nginx.com } 916774Svbart@nginx.com 917774Svbart@nginx.com 918774Svbart@nginx.com static void 919774Svbart@nginx.com nxt_controller_process_config(nxt_task_t *task, nxt_controller_request_t *req, 920774Svbart@nginx.com nxt_str_t *path) 921774Svbart@nginx.com { 92265Sigor@sysoev.ru nxt_mp_t *mp; 92351Svbart@nginx.com nxt_int_t rc; 924140Svbart@nginx.com nxt_conn_t *c; 9251049Svbart@nginx.com nxt_bool_t post; 92651Svbart@nginx.com nxt_buf_mem_t *mbuf; 927106Svbart@nginx.com nxt_conf_op_t *ops; 928106Svbart@nginx.com nxt_conf_value_t *value; 929357Svbart@nginx.com nxt_conf_validation_t vldt; 930208Svbart@nginx.com nxt_conf_json_error_t error; 93144Svbart@nginx.com nxt_controller_response_t resp; 93244Svbart@nginx.com 93351Svbart@nginx.com static const nxt_str_t empty_obj = nxt_string("{}"); 93451Svbart@nginx.com 935774Svbart@nginx.com nxt_memzero(&resp, sizeof(nxt_controller_response_t)); 936632Svbart@nginx.com 937774Svbart@nginx.com c = req->conn; 93844Svbart@nginx.com 93944Svbart@nginx.com if (nxt_str_eq(&req->parser.method, "GET", 3)) { 94046Svbart@nginx.com 941774Svbart@nginx.com value = nxt_conf_get_path(nxt_controller_conf.root, path); 94251Svbart@nginx.com 94351Svbart@nginx.com if (value == NULL) { 944208Svbart@nginx.com goto not_found; 94551Svbart@nginx.com } 94651Svbart@nginx.com 947208Svbart@nginx.com resp.status = 200; 948106Svbart@nginx.com resp.conf = value; 94946Svbart@nginx.com 950208Svbart@nginx.com nxt_controller_response(task, req, &resp); 951208Svbart@nginx.com return; 95251Svbart@nginx.com } 95351Svbart@nginx.com 9541049Svbart@nginx.com if (nxt_str_eq(&req->parser.method, "POST", 4)) { 9551049Svbart@nginx.com if (path->length == 1) { 9561049Svbart@nginx.com goto not_allowed; 9571049Svbart@nginx.com } 9581049Svbart@nginx.com 9591049Svbart@nginx.com post = 1; 9601049Svbart@nginx.com 9611049Svbart@nginx.com } else { 9621049Svbart@nginx.com post = 0; 9631049Svbart@nginx.com } 9641049Svbart@nginx.com 9651049Svbart@nginx.com if (post || nxt_str_eq(&req->parser.method, "PUT", 3)) { 96646Svbart@nginx.com 967238Svbart@nginx.com if (!nxt_queue_is_empty(&nxt_controller_waiting_requests)) { 968238Svbart@nginx.com nxt_queue_insert_tail(&nxt_controller_waiting_requests, &req->link); 969238Svbart@nginx.com return; 970238Svbart@nginx.com } 971238Svbart@nginx.com 97265Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 97351Svbart@nginx.com 97451Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 975208Svbart@nginx.com goto alloc_fail; 97646Svbart@nginx.com } 97746Svbart@nginx.com 97851Svbart@nginx.com mbuf = &c->read->mem; 97951Svbart@nginx.com 980208Svbart@nginx.com nxt_memzero(&error, sizeof(nxt_conf_json_error_t)); 981208Svbart@nginx.com 9821364Svbart@nginx.com /* Skip UTF-8 BOM. */ 9831364Svbart@nginx.com if (nxt_buf_mem_used_size(mbuf) >= 3 9841364Svbart@nginx.com && nxt_memcmp(mbuf->pos, "\xEF\xBB\xBF", 3) == 0) 9851364Svbart@nginx.com { 9861364Svbart@nginx.com mbuf->pos += 3; 9871364Svbart@nginx.com } 9881364Svbart@nginx.com 989208Svbart@nginx.com value = nxt_conf_json_parse(mp, mbuf->pos, mbuf->free, &error); 99051Svbart@nginx.com 99151Svbart@nginx.com if (value == NULL) { 99265Sigor@sysoev.ru nxt_mp_destroy(mp); 993208Svbart@nginx.com 994208Svbart@nginx.com if (error.pos == NULL) { 995208Svbart@nginx.com goto alloc_fail; 996208Svbart@nginx.com } 997208Svbart@nginx.com 998208Svbart@nginx.com resp.status = 400; 999208Svbart@nginx.com resp.title = (u_char *) "Invalid JSON."; 1000357Svbart@nginx.com resp.detail.length = nxt_strlen(error.detail); 1001357Svbart@nginx.com resp.detail.start = error.detail; 1002208Svbart@nginx.com resp.offset = error.pos - mbuf->pos; 1003208Svbart@nginx.com 1004208Svbart@nginx.com nxt_conf_json_position(mbuf->pos, error.pos, 1005208Svbart@nginx.com &resp.line, &resp.column); 1006208Svbart@nginx.com 1007208Svbart@nginx.com nxt_controller_response(task, req, &resp); 1008208Svbart@nginx.com return; 100951Svbart@nginx.com } 101051Svbart@nginx.com 1011774Svbart@nginx.com if (path->length != 1) { 1012106Svbart@nginx.com rc = nxt_conf_op_compile(c->mem_pool, &ops, 1013106Svbart@nginx.com nxt_controller_conf.root, 10141049Svbart@nginx.com path, value, post); 101546Svbart@nginx.com 10161049Svbart@nginx.com if (rc != NXT_CONF_OP_OK) { 1017619Svbart@nginx.com nxt_mp_destroy(mp); 1018619Svbart@nginx.com 10191049Svbart@nginx.com switch (rc) { 10201049Svbart@nginx.com case NXT_CONF_OP_NOT_FOUND: 1021208Svbart@nginx.com goto not_found; 10221049Svbart@nginx.com 10231049Svbart@nginx.com case NXT_CONF_OP_NOT_ALLOWED: 10241049Svbart@nginx.com goto not_allowed; 102551Svbart@nginx.com } 102646Svbart@nginx.com 10271049Svbart@nginx.com /* rc == NXT_CONF_OP_ERROR */ 1028208Svbart@nginx.com goto alloc_fail; 102951Svbart@nginx.com } 103051Svbart@nginx.com 1031106Svbart@nginx.com value = nxt_conf_clone(mp, ops, nxt_controller_conf.root); 103251Svbart@nginx.com 103351Svbart@nginx.com if (nxt_slow_path(value == NULL)) { 103465Sigor@sysoev.ru nxt_mp_destroy(mp); 1035208Svbart@nginx.com goto alloc_fail; 103651Svbart@nginx.com } 103746Svbart@nginx.com } 103844Svbart@nginx.com 1039357Svbart@nginx.com nxt_memzero(&vldt, sizeof(nxt_conf_validation_t)); 1040357Svbart@nginx.com 1041357Svbart@nginx.com vldt.conf = value; 1042357Svbart@nginx.com vldt.pool = c->mem_pool; 1043357Svbart@nginx.com 1044357Svbart@nginx.com rc = nxt_conf_validate(&vldt); 1045357Svbart@nginx.com 1046357Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 1047121Svbart@nginx.com nxt_mp_destroy(mp); 1048357Svbart@nginx.com 1049357Svbart@nginx.com if (rc == NXT_DECLINED) { 1050