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) { 1050357Svbart@nginx.com resp.detail = vldt.error; 1051357Svbart@nginx.com goto invalid_conf; 1052357Svbart@nginx.com } 1053357Svbart@nginx.com 1054357Svbart@nginx.com /* rc == NXT_ERROR */ 1055357Svbart@nginx.com goto alloc_fail; 1056116Svbart@nginx.com } 1057116Svbart@nginx.com 1058249Svbart@nginx.com rc = nxt_controller_conf_send(task, value, 1059249Svbart@nginx.com nxt_controller_conf_handler, req); 1060247Svbart@nginx.com 1061247Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 1062121Svbart@nginx.com nxt_mp_destroy(mp); 1063247Svbart@nginx.com 1064247Svbart@nginx.com if (rc == NXT_DECLINED) { 1065247Svbart@nginx.com goto no_router; 1066247Svbart@nginx.com } 1067247Svbart@nginx.com 1068247Svbart@nginx.com /* rc == NXT_ERROR */ 1069208Svbart@nginx.com goto alloc_fail; 1070121Svbart@nginx.com } 1071121Svbart@nginx.com 1072249Svbart@nginx.com req->conf.root = value; 1073249Svbart@nginx.com req->conf.pool = mp; 1074249Svbart@nginx.com 1075249Svbart@nginx.com nxt_queue_insert_head(&nxt_controller_waiting_requests, &req->link); 1076249Svbart@nginx.com 1077140Svbart@nginx.com return; 107851Svbart@nginx.com } 107927Svbart@nginx.com 108051Svbart@nginx.com if (nxt_str_eq(&req->parser.method, "DELETE", 6)) { 108151Svbart@nginx.com 1082238Svbart@nginx.com if (!nxt_queue_is_empty(&nxt_controller_waiting_requests)) { 1083238Svbart@nginx.com nxt_queue_insert_tail(&nxt_controller_waiting_requests, &req->link); 1084238Svbart@nginx.com return; 1085238Svbart@nginx.com } 1086238Svbart@nginx.com 1087774Svbart@nginx.com if (path->length == 1) { 108865Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 108944Svbart@nginx.com 109051Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 1091208Svbart@nginx.com goto alloc_fail; 109251Svbart@nginx.com } 109351Svbart@nginx.com 1094106Svbart@nginx.com value = nxt_conf_json_parse_str(mp, &empty_obj); 109527Svbart@nginx.com 109644Svbart@nginx.com } else { 1097106Svbart@nginx.com rc = nxt_conf_op_compile(c->mem_pool, &ops, 1098106Svbart@nginx.com nxt_controller_conf.root, 10991049Svbart@nginx.com path, NULL, 0); 110051Svbart@nginx.com 110151Svbart@nginx.com if (rc != NXT_OK) { 11021049Svbart@nginx.com if (rc == NXT_CONF_OP_NOT_FOUND) { 1103208Svbart@nginx.com goto not_found; 110451Svbart@nginx.com } 110551Svbart@nginx.com 11061049Svbart@nginx.com /* rc == NXT_CONF_OP_ERROR */ 1107208Svbart@nginx.com goto alloc_fail; 110851Svbart@nginx.com } 110951Svbart@nginx.com 111065Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 111151Svbart@nginx.com 111251Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 1113208Svbart@nginx.com goto alloc_fail; 111451Svbart@nginx.com } 111551Svbart@nginx.com 1116106Svbart@nginx.com value = nxt_conf_clone(mp, ops, nxt_controller_conf.root); 111751Svbart@nginx.com } 111851Svbart@nginx.com 111951Svbart@nginx.com if (nxt_slow_path(value == NULL)) { 112065Sigor@sysoev.ru nxt_mp_destroy(mp); 1121208Svbart@nginx.com goto alloc_fail; 112244Svbart@nginx.com } 112344Svbart@nginx.com 1124357Svbart@nginx.com nxt_memzero(&vldt, sizeof(nxt_conf_validation_t)); 1125357Svbart@nginx.com 1126357Svbart@nginx.com vldt.conf = value; 1127357Svbart@nginx.com vldt.pool = c->mem_pool; 1128357Svbart@nginx.com 1129357Svbart@nginx.com rc = nxt_conf_validate(&vldt); 1130357Svbart@nginx.com 1131357Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 1132121Svbart@nginx.com nxt_mp_destroy(mp); 1133357Svbart@nginx.com 1134357Svbart@nginx.com if (rc == NXT_DECLINED) { 1135357Svbart@nginx.com resp.detail = vldt.error; 1136357Svbart@nginx.com goto invalid_conf; 1137357Svbart@nginx.com } 1138357Svbart@nginx.com 1139357Svbart@nginx.com /* rc == NXT_ERROR */ 1140357Svbart@nginx.com goto alloc_fail; 1141116Svbart@nginx.com } 1142116Svbart@nginx.com 1143249Svbart@nginx.com rc = nxt_controller_conf_send(task, value, 1144249Svbart@nginx.com nxt_controller_conf_handler, req); 1145247Svbart@nginx.com 1146247Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 1147121Svbart@nginx.com nxt_mp_destroy(mp); 1148247Svbart@nginx.com 1149247Svbart@nginx.com if (rc == NXT_DECLINED) { 1150247Svbart@nginx.com goto no_router; 1151247Svbart@nginx.com } 1152247Svbart@nginx.com 1153247Svbart@nginx.com /* rc == NXT_ERROR */ 1154208Svbart@nginx.com goto alloc_fail; 1155121Svbart@nginx.com } 1156121Svbart@nginx.com 1157249Svbart@nginx.com req->conf.root = value; 1158249Svbart@nginx.com req->conf.pool = mp; 1159249Svbart@nginx.com 1160249Svbart@nginx.com nxt_queue_insert_head(&nxt_controller_waiting_requests, &req->link); 1161249Svbart@nginx.com 1162140Svbart@nginx.com return; 116351Svbart@nginx.com } 116451Svbart@nginx.com 11651049Svbart@nginx.com not_allowed: 11661049Svbart@nginx.com 1167208Svbart@nginx.com resp.status = 405; 11681049Svbart@nginx.com resp.title = (u_char *) "Method isn't allowed."; 1169208Svbart@nginx.com resp.offset = -1; 117051Svbart@nginx.com 1171208Svbart@nginx.com nxt_controller_response(task, req, &resp); 1172208Svbart@nginx.com return; 117351Svbart@nginx.com 1174208Svbart@nginx.com not_found: 1175208Svbart@nginx.com 1176208Svbart@nginx.com resp.status = 404; 1177208Svbart@nginx.com resp.title = (u_char *) "Value doesn't exist."; 1178208Svbart@nginx.com resp.offset = -1; 1179208Svbart@nginx.com 1180208Svbart@nginx.com nxt_controller_response(task, req, &resp); 1181208Svbart@nginx.com return; 1182208Svbart@nginx.com 1183208Svbart@nginx.com invalid_conf: 1184208Svbart@nginx.com 1185208Svbart@nginx.com resp.status = 400; 1186208Svbart@nginx.com resp.title = (u_char *) "Invalid configuration."; 1187208Svbart@nginx.com resp.offset = -1; 1188208Svbart@nginx.com 1189208Svbart@nginx.com nxt_controller_response(task, req, &resp); 1190208Svbart@nginx.com return; 1191247Svbart@nginx.com 1192247Svbart@nginx.com alloc_fail: 1193247Svbart@nginx.com 1194247Svbart@nginx.com resp.status = 500; 1195247Svbart@nginx.com resp.title = (u_char *) "Memory allocation failed."; 1196247Svbart@nginx.com resp.offset = -1; 1197247Svbart@nginx.com 1198247Svbart@nginx.com nxt_controller_response(task, req, &resp); 1199247Svbart@nginx.com return; 1200247Svbart@nginx.com 1201247Svbart@nginx.com no_router: 1202247Svbart@nginx.com 1203247Svbart@nginx.com resp.status = 500; 1204247Svbart@nginx.com resp.title = (u_char *) "Router process isn't available."; 1205247Svbart@nginx.com resp.offset = -1; 1206247Svbart@nginx.com 1207247Svbart@nginx.com nxt_controller_response(task, req, &resp); 1208247Svbart@nginx.com return; 120927Svbart@nginx.com } 121027Svbart@nginx.com 121127Svbart@nginx.com 1212774Svbart@nginx.com #if (NXT_TLS) 1213774Svbart@nginx.com 1214774Svbart@nginx.com static void 1215774Svbart@nginx.com nxt_controller_process_cert(nxt_task_t *task, 1216774Svbart@nginx.com nxt_controller_request_t *req, nxt_str_t *path) 1217774Svbart@nginx.com { 1218774Svbart@nginx.com u_char *p; 1219774Svbart@nginx.com nxt_str_t name; 1220774Svbart@nginx.com nxt_int_t ret; 1221774Svbart@nginx.com nxt_conn_t *c; 1222774Svbart@nginx.com nxt_cert_t *cert; 1223774Svbart@nginx.com nxt_conf_value_t *value; 1224774Svbart@nginx.com nxt_controller_response_t resp; 1225774Svbart@nginx.com 1226774Svbart@nginx.com name.length = path->length - 1; 1227774Svbart@nginx.com name.start = path->start + 1; 1228774Svbart@nginx.com 1229774Svbart@nginx.com p = nxt_memchr(name.start, '/', name.length); 1230774Svbart@nginx.com 1231774Svbart@nginx.com if (p != NULL) { 1232774Svbart@nginx.com name.length = p - name.start; 1233774Svbart@nginx.com 1234774Svbart@nginx.com path->length -= p - path->start; 1235774Svbart@nginx.com path->start = p; 1236774Svbart@nginx.com 1237774Svbart@nginx.com } else { 1238774Svbart@nginx.com path = NULL; 1239774Svbart@nginx.com } 1240774Svbart@nginx.com 1241774Svbart@nginx.com nxt_memzero(&resp, sizeof(nxt_controller_response_t)); 1242774Svbart@nginx.com 1243774Svbart@nginx.com c = req->conn; 1244774Svbart@nginx.com 1245774Svbart@nginx.com if (nxt_str_eq(&req->parser.method, "GET", 3)) { 1246774Svbart@nginx.com 1247774Svbart@nginx.com if (name.length != 0) { 1248774Svbart@nginx.com value = nxt_cert_info_get(&name); 1249774Svbart@nginx.com if (value == NULL) { 1250774Svbart@nginx.com goto cert_not_found; 1251774Svbart@nginx.com } 1252774Svbart@nginx.com 1253774Svbart@nginx.com if (path != NULL) { 1254774Svbart@nginx.com value = nxt_conf_get_path(value, path); 1255774Svbart@nginx.com if (value == NULL) { 1256774Svbart@nginx.com goto not_found; 1257774Svbart@nginx.com } 1258774Svbart@nginx.com } 1259774Svbart@nginx.com 1260774Svbart@nginx.com } else { 1261774Svbart@nginx.com value = nxt_cert_info_get_all(c->mem_pool); 1262774Svbart@nginx.com if (value == NULL) { 1263774Svbart@nginx.com goto alloc_fail; 1264774Svbart@nginx.com } 1265774Svbart@nginx.com } 1266774Svbart@nginx.com 1267774Svbart@nginx.com resp.status = 200; 1268774Svbart@nginx.com resp.conf = value; 1269774Svbart@nginx.com 1270774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1271774Svbart@nginx.com return; 1272774Svbart@nginx.com } 1273774Svbart@nginx.com 1274774Svbart@nginx.com if (name.length == 0 || path != NULL) { 1275774Svbart@nginx.com goto invalid_name; 1276774Svbart@nginx.com } 1277774Svbart@nginx.com 1278774Svbart@nginx.com if (nxt_str_eq(&req->parser.method, "PUT", 3)) { 1279774Svbart@nginx.com value = nxt_cert_info_get(&name); 1280774Svbart@nginx.com if (value != NULL) { 1281774Svbart@nginx.com goto exists_cert; 1282774Svbart@nginx.com } 1283774Svbart@nginx.com 1284774Svbart@nginx.com cert = nxt_cert_mem(task, &c->read->mem); 1285774Svbart@nginx.com if (cert == NULL) { 1286774Svbart@nginx.com goto invalid_cert; 1287774Svbart@nginx.com } 1288774Svbart@nginx.com 1289774Svbart@nginx.com ret = nxt_cert_info_save(&name, cert); 1290774Svbart@nginx.com 1291774Svbart@nginx.com nxt_cert_destroy(cert); 1292774Svbart@nginx.com 1293774Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 1294774Svbart@nginx.com goto alloc_fail; 1295774Svbart@nginx.com } 1296774Svbart@nginx.com 1297774Svbart@nginx.com nxt_cert_store_get(task, &name, c->mem_pool, 1298774Svbart@nginx.com nxt_controller_process_cert_save, req); 1299774Svbart@nginx.com return; 1300774Svbart@nginx.com } 1301774Svbart@nginx.com 1302774Svbart@nginx.com if (nxt_str_eq(&req->parser.method, "DELETE", 6)) { 1303774Svbart@nginx.com 1304774Svbart@nginx.com if (nxt_controller_cert_in_use(&name)) { 1305774Svbart@nginx.com goto cert_in_use; 1306774Svbart@nginx.com } 1307774Svbart@nginx.com 1308774Svbart@nginx.com if (nxt_cert_info_delete(&name) != NXT_OK) { 1309774Svbart@nginx.com goto cert_not_found; 1310774Svbart@nginx.com } 1311774Svbart@nginx.com 1312774Svbart@nginx.com nxt_cert_store_delete(task, &name, c->mem_pool); 1313774Svbart@nginx.com 1314774Svbart@nginx.com resp.status = 200; 1315774Svbart@nginx.com resp.title = (u_char *) "Certificate deleted."; 1316774Svbart@nginx.com 1317774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1318774Svbart@nginx.com return; 1319774Svbart@nginx.com } 1320774Svbart@nginx.com 1321774Svbart@nginx.com resp.status = 405; 1322774Svbart@nginx.com resp.title = (u_char *) "Invalid method."; 1323774Svbart@nginx.com resp.offset = -1; 1324774Svbart@nginx.com 1325774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1326774Svbart@nginx.com return; 1327774Svbart@nginx.com 1328774Svbart@nginx.com invalid_name: 1329774Svbart@nginx.com 1330774Svbart@nginx.com resp.status = 400; 1331774Svbart@nginx.com resp.title = (u_char *) "Invalid certificate name."; 1332774Svbart@nginx.com resp.offset = -1; 1333774Svbart@nginx.com 1334774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1335774Svbart@nginx.com return; 1336774Svbart@nginx.com 1337774Svbart@nginx.com invalid_cert: 1338774Svbart@nginx.com 1339774Svbart@nginx.com resp.status = 400; 1340774Svbart@nginx.com resp.title = (u_char *) "Invalid certificate."; 1341774Svbart@nginx.com resp.offset = -1; 1342774Svbart@nginx.com 1343774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1344774Svbart@nginx.com return; 1345774Svbart@nginx.com 1346774Svbart@nginx.com exists_cert: 1347774Svbart@nginx.com 1348774Svbart@nginx.com resp.status = 400; 1349774Svbart@nginx.com resp.title = (u_char *) "Certificate already exists."; 1350774Svbart@nginx.com resp.offset = -1; 1351774Svbart@nginx.com 1352774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1353774Svbart@nginx.com return; 1354774Svbart@nginx.com 1355774Svbart@nginx.com cert_in_use: 1356774Svbart@nginx.com 1357774Svbart@nginx.com resp.status = 400; 1358774Svbart@nginx.com resp.title = (u_char *) "Certificate is used in the configuration."; 1359774Svbart@nginx.com resp.offset = -1; 1360774Svbart@nginx.com 1361774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1362774Svbart@nginx.com return; 1363774Svbart@nginx.com 1364774Svbart@nginx.com cert_not_found: 1365774Svbart@nginx.com 1366774Svbart@nginx.com resp.status = 404; 1367774Svbart@nginx.com resp.title = (u_char *) "Certificate doesn't exist."; 1368774Svbart@nginx.com resp.offset = -1; 1369774Svbart@nginx.com 1370774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1371774Svbart@nginx.com return; 1372774Svbart@nginx.com 1373774Svbart@nginx.com not_found: 1374774Svbart@nginx.com 1375774Svbart@nginx.com resp.status = 404; 1376774Svbart@nginx.com resp.title = (u_char *) "Invalid path."; 1377774Svbart@nginx.com resp.offset = -1; 1378774Svbart@nginx.com 1379774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1380774Svbart@nginx.com return; 1381774Svbart@nginx.com 1382774Svbart@nginx.com alloc_fail: 1383774Svbart@nginx.com 1384774Svbart@nginx.com resp.status = 500; 1385774Svbart@nginx.com resp.title = (u_char *) "Memory allocation failed."; 1386774Svbart@nginx.com resp.offset = -1; 1387774Svbart@nginx.com 1388774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1389774Svbart@nginx.com return; 1390774Svbart@nginx.com } 1391774Svbart@nginx.com 1392774Svbart@nginx.com 1393774Svbart@nginx.com static void 1394774Svbart@nginx.com nxt_controller_process_cert_save(nxt_task_t *task, nxt_port_recv_msg_t *msg, 1395774Svbart@nginx.com void *data) 1396774Svbart@nginx.com { 1397774Svbart@nginx.com nxt_conn_t *c; 1398774Svbart@nginx.com nxt_buf_mem_t *mbuf; 1399774Svbart@nginx.com nxt_controller_request_t *req; 1400774Svbart@nginx.com nxt_controller_response_t resp; 1401774Svbart@nginx.com 1402774Svbart@nginx.com req = data; 1403774Svbart@nginx.com 1404774Svbart@nginx.com nxt_memzero(&resp, sizeof(nxt_controller_response_t)); 1405774Svbart@nginx.com 1406774Svbart@nginx.com if (msg == NULL || msg->port_msg.type == _NXT_PORT_MSG_RPC_ERROR) { 1407774Svbart@nginx.com resp.status = 500; 1408774Svbart@nginx.com resp.title = (u_char *) "Failed to store certificate."; 1409774Svbart@nginx.com 1410774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1411774Svbart@nginx.com return; 1412774Svbart@nginx.com } 1413774Svbart@nginx.com 1414774Svbart@nginx.com c = req->conn; 1415774Svbart@nginx.com 1416774Svbart@nginx.com mbuf = &c->read->mem; 1417774Svbart@nginx.com 1418774Svbart@nginx.com nxt_fd_write(msg->fd, mbuf->pos, nxt_buf_mem_used_size(mbuf)); 1419774Svbart@nginx.com 1420774Svbart@nginx.com nxt_fd_close(msg->fd); 1421774Svbart@nginx.com 1422774Svbart@nginx.com nxt_memzero(&resp, sizeof(nxt_controller_response_t)); 1423774Svbart@nginx.com 1424774Svbart@nginx.com resp.status = 200; 1425774Svbart@nginx.com resp.title = (u_char *) "Certificate chain uploaded."; 1426774Svbart@nginx.com 1427774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1428774Svbart@nginx.com } 1429774Svbart@nginx.com 1430774Svbart@nginx.com 1431774Svbart@nginx.com static nxt_bool_t 1432774Svbart@nginx.com nxt_controller_cert_in_use(nxt_str_t *name) 1433774Svbart@nginx.com { 1434774Svbart@nginx.com uint32_t next; 1435774Svbart@nginx.com nxt_str_t str; 1436774Svbart@nginx.com nxt_conf_value_t *listeners, *listener, *value; 1437774Svbart@nginx.com 1438774Svbart@nginx.com static nxt_str_t listeners_path = nxt_string("/listeners"); 1439774Svbart@nginx.com static nxt_str_t certificate_path = nxt_string("/tls/certificate"); 1440774Svbart@nginx.com 1441774Svbart@nginx.com listeners = nxt_conf_get_path(nxt_controller_conf.root, &listeners_path); 1442774Svbart@nginx.com 1443774Svbart@nginx.com if (listeners != NULL) { 1444774Svbart@nginx.com next = 0; 1445774Svbart@nginx.com 1446774Svbart@nginx.com for ( ;; ) { 1447774Svbart@nginx.com listener = nxt_conf_next_object_member(listeners, &str, &next); 1448774Svbart@nginx.com if (listener == NULL) { 1449774Svbart@nginx.com break; 1450774Svbart@nginx.com } 1451774Svbart@nginx.com 1452774Svbart@nginx.com value = nxt_conf_get_path(listener, &certificate_path); 1453774Svbart@nginx.com if (value == NULL) { 1454774Svbart@nginx.com continue; 1455774Svbart@nginx.com } 1456774Svbart@nginx.com 1457774Svbart@nginx.com nxt_conf_get_string(value, &str); 1458774Svbart@nginx.com 1459774Svbart@nginx.com if (nxt_strstr_eq(&str, name)) { 1460774Svbart@nginx.com return 1; 1461774Svbart@nginx.com } 1462774Svbart@nginx.com } 1463774Svbart@nginx.com } 1464774Svbart@nginx.com 1465774Svbart@nginx.com return 0; 1466774Svbart@nginx.com } 1467774Svbart@nginx.com 1468774Svbart@nginx.com #endif 1469774Svbart@nginx.com 1470774Svbart@nginx.com 1471193Smax.romanov@nginx.com static void 1472193Smax.romanov@nginx.com nxt_controller_conf_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 1473193Smax.romanov@nginx.com void *data) 1474140Svbart@nginx.com { 1475238Svbart@nginx.com nxt_queue_t queue; 1476140Svbart@nginx.com nxt_controller_request_t *req; 1477140Svbart@nginx.com nxt_controller_response_t resp; 1478140Svbart@nginx.com 1479238Svbart@nginx.com req = data; 1480238Svbart@nginx.com 1481201Svbart@nginx.com nxt_debug(task, "controller conf ready: %*s", 1482201Svbart@nginx.com nxt_buf_mem_used_size(&msg->buf->mem), msg->buf->mem.pos); 1483140Svbart@nginx.com 1484238Svbart@nginx.com nxt_queue_remove(&req->link); 1485140Svbart@nginx.com 1486238Svbart@nginx.com nxt_memzero(&resp, sizeof(nxt_controller_response_t)); 1487140Svbart@nginx.com 1488193Smax.romanov@nginx.com if (msg->port_msg.type == NXT_PORT_MSG_RPC_READY) { 1489140Svbart@nginx.com nxt_mp_destroy(nxt_controller_conf.pool); 1490140Svbart@nginx.com 1491140Svbart@nginx.com nxt_controller_conf = req->conf; 1492140Svbart@nginx.com 1493314Svbart@nginx.com nxt_controller_conf_store(task, req->conf.root); 1494314Svbart@nginx.com 1495208Svbart@nginx.com resp.status = 200; 1496208Svbart@nginx.com resp.title = (u_char *) "Reconfiguration done."; 1497140Svbart@nginx.com 1498140Svbart@nginx.com } else { 1499140Svbart@nginx.com nxt_mp_destroy(req->conf.pool); 1500140Svbart@nginx.com 1501208Svbart@nginx.com resp.status = 500; 1502208Svbart@nginx.com resp.title = (u_char *) "Failed to apply new configuration."; 1503208Svbart@nginx.com resp.offset = -1; 1504140Svbart@nginx.com } 1505140Svbart@nginx.com 1506140Svbart@nginx.com nxt_controller_response(task, req, &resp); 1507140Svbart@nginx.com 1508238Svbart@nginx.com nxt_queue_init(&queue); 1509238Svbart@nginx.com nxt_queue_add(&queue, &nxt_controller_waiting_requests); 1510140Svbart@nginx.com 1511238Svbart@nginx.com nxt_queue_init(&nxt_controller_waiting_requests); 1512121Svbart@nginx.com 1513238Svbart@nginx.com nxt_queue_each(req, &queue, nxt_controller_request_t, link) { 1514238Svbart@nginx.com nxt_controller_process_request(task, req); 1515238Svbart@nginx.com } nxt_queue_loop; 1516121Svbart@nginx.com } 1517121Svbart@nginx.com 1518121Svbart@nginx.com 1519140Svbart@nginx.com static void 1520314Svbart@nginx.com nxt_controller_conf_store(nxt_task_t *task, nxt_conf_value_t *conf) 1521314Svbart@nginx.com { 1522314Svbart@nginx.com size_t size; 1523314Svbart@nginx.com nxt_buf_t *b; 1524314Svbart@nginx.com nxt_port_t *main_port; 1525314Svbart@nginx.com nxt_runtime_t *rt; 1526314Svbart@nginx.com 1527314Svbart@nginx.com rt = task->thread->runtime; 1528314Svbart@nginx.com 1529314Svbart@nginx.com main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 1530314Svbart@nginx.com 1531314Svbart@nginx.com size = nxt_conf_json_length(conf, NULL); 1532314Svbart@nginx.com 1533342Smax.romanov@nginx.com b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, size); 1534314Svbart@nginx.com 1535314Svbart@nginx.com if (nxt_fast_path(b != NULL)) { 1536314Svbart@nginx.com b->mem.free = nxt_conf_json_print(b->mem.free, conf, NULL); 1537314Svbart@nginx.com 1538314Svbart@nginx.com (void) nxt_port_socket_write(task, main_port, NXT_PORT_MSG_CONF_STORE, 1539314Svbart@nginx.com -1, 0, -1, b); 1540314Svbart@nginx.com } 1541314Svbart@nginx.com } 1542314Svbart@nginx.com 1543314Svbart@nginx.com 1544314Svbart@nginx.com static void 1545140Svbart@nginx.com nxt_controller_response(nxt_task_t *task, nxt_controller_request_t *req, 154644Svbart@nginx.com nxt_controller_response_t *resp) 154733Svbart@nginx.com { 1548208Svbart@nginx.com size_t size; 1549208Svbart@nginx.com nxt_str_t status_line, str; 1550208Svbart@nginx.com nxt_buf_t *b, *body; 1551208Svbart@nginx.com nxt_conn_t *c; 1552208Svbart@nginx.com nxt_uint_t n; 1553208Svbart@nginx.com nxt_conf_value_t *value, *location; 1554208Svbart@nginx.com nxt_conf_json_pretty_t pretty; 1555208Svbart@nginx.com 1556208Svbart@nginx.com static nxt_str_t success_str = nxt_string("success"); 1557208Svbart@nginx.com static nxt_str_t error_str = nxt_string("error"); 1558208Svbart@nginx.com static nxt_str_t detail_str = nxt_string("detail"); 1559208Svbart@nginx.com static nxt_str_t location_str = nxt_string("location"); 1560208Svbart@nginx.com static nxt_str_t offset_str = nxt_string("offset"); 1561208Svbart@nginx.com static nxt_str_t line_str = nxt_string("line"); 1562208Svbart@nginx.com static nxt_str_t column_str = nxt_string("column"); 1563208Svbart@nginx.com 1564208Svbart@nginx.com static nxt_time_string_t date_cache = { 1565208Svbart@nginx.com (nxt_atomic_uint_t) -1, 1566208Svbart@nginx.com nxt_controller_date, 1567208Svbart@nginx.com "%s, %02d %s %4d %02d:%02d:%02d GMT", 1568703Svbart@nginx.com nxt_length("Wed, 31 Dec 1986 16:40:00 GMT"), 1569208Svbart@nginx.com NXT_THREAD_TIME_GMT, 1570208Svbart@nginx.com NXT_THREAD_TIME_SEC, 1571208Svbart@nginx.com }; 1572208Svbart@nginx.com 1573208Svbart@nginx.com switch (resp->status) { 1574208Svbart@nginx.com 1575208Svbart@nginx.com case 200: 1576208Svbart@nginx.com nxt_str_set(&status_line, "200 OK"); 1577208Svbart@nginx.com break; 1578208Svbart@nginx.com 1579208Svbart@nginx.com case 400: 1580208Svbart@nginx.com nxt_str_set(&status_line, "400 Bad Request"); 1581208Svbart@nginx.com break; 1582208Svbart@nginx.com 1583208Svbart@nginx.com case 404: 1584208Svbart@nginx.com nxt_str_set(&status_line, "404 Not Found"); 1585208Svbart@nginx.com break; 1586208Svbart@nginx.com 1587208Svbart@nginx.com case 405: 1588208Svbart@nginx.com nxt_str_set(&status_line, "405 Method Not Allowed"); 1589208Svbart@nginx.com break; 1590208Svbart@nginx.com 1591209Svbart@nginx.com default: 1592208Svbart@nginx.com nxt_str_set(&status_line, "500 Internal Server Error"); 1593208Svbart@nginx.com break; 1594208Svbart@nginx.com } 1595140Svbart@nginx.com 1596140Svbart@nginx.com c = req->conn; 1597208Svbart@nginx.com value = resp->conf; 159833Svbart@nginx.com 1599208Svbart@nginx.com if (value == NULL) { 1600208Svbart@nginx.com n = 1 1601357Svbart@nginx.com + (resp->detail.length != 0) 1602208Svbart@nginx.com + (resp->status >= 400 && resp->offset != -1); 1603208Svbart@nginx.com 1604208Svbart@nginx.com value = nxt_conf_create_object(c->mem_pool, n); 1605208Svbart@nginx.com 1606208Svbart@nginx.com if (nxt_slow_path(value == NULL)) { 1607208Svbart@nginx.com nxt_controller_conn_close(task, c, req); 1608208Svbart@nginx.com return; 1609208Svbart@nginx.com } 1610208Svbart@nginx.com 1611208Svbart@nginx.com str.length = nxt_strlen(resp->title); 1612208Svbart@nginx.com str.start = resp->title; 1613208Svbart@nginx.com 1614208Svbart@nginx.com if (resp->status < 400) { 1615208Svbart@nginx.com nxt_conf_set_member_string(value, &success_str, &str, 0); 1616208Svbart@nginx.com 1617208Svbart@nginx.com } else { 1618208Svbart@nginx.com nxt_conf_set_member_string(value, &error_str, &str, 0); 1619208Svbart@nginx.com } 1620208Svbart@nginx.com 1621208Svbart@nginx.com n = 0; 1622208Svbart@nginx.com 1623357Svbart@nginx.com if (resp->detail.length != 0) { 1624208Svbart@nginx.com n++; 1625208Svbart@nginx.com 1626357Svbart@nginx.com nxt_conf_set_member_string(value, &detail_str, &resp->detail, n); 1627208Svbart@nginx.com } 1628208Svbart@nginx.com 1629208Svbart@nginx.com if (resp->status >= 400 && resp->offset != -1) { 1630208Svbart@nginx.com n++; 1631208Svbart@nginx.com 1632208Svbart@nginx.com location = nxt_conf_create_object(c->mem_pool, 1633208Svbart@nginx.com resp->line != 0 ? 3 : 1); 1634208Svbart@nginx.com 1635208Svbart@nginx.com nxt_conf_set_member(value, &location_str, location, n); 1636208Svbart@nginx.com 1637208Svbart@nginx.com nxt_conf_set_member_integer(location, &offset_str, resp->offset, 0); 1638208Svbart@nginx.com 1639208Svbart@nginx.com if (resp->line != 0) { 1640208Svbart@nginx.com nxt_conf_set_member_integer(location, &line_str, 1641208Svbart@nginx.com resp->line, 1); 1642208Svbart@nginx.com 1643208Svbart@nginx.com nxt_conf_set_member_integer(location, &column_str, 1644208Svbart@nginx.com resp->column, 2); 1645208Svbart@nginx.com } 1646208Svbart@nginx.com } 1647208Svbart@nginx.com } 1648208Svbart@nginx.com 1649208Svbart@nginx.com nxt_memzero(&pretty, sizeof(nxt_conf_json_pretty_t)); 1650208Svbart@nginx.com 1651208Svbart@nginx.com size = nxt_conf_json_length(value, &pretty) + 2; 1652208Svbart@nginx.com 1653208Svbart@nginx.com body = nxt_buf_mem_alloc(c->mem_pool, size, 0); 1654208Svbart@nginx.com if (nxt_slow_path(body == NULL)) { 1655208Svbart@nginx.com nxt_controller_conn_close(task, c, req); 1656208Svbart@nginx.com return; 1657208Svbart@nginx.com } 1658208Svbart@nginx.com 1659208Svbart@nginx.com nxt_memzero(&pretty, sizeof(nxt_conf_json_pretty_t)); 1660208Svbart@nginx.com 1661208Svbart@nginx.com body->mem.free = nxt_conf_json_print(body->mem.free, value, &pretty); 1662208Svbart@nginx.com 1663208Svbart@nginx.com body->mem.free = nxt_cpymem(body->mem.free, "\r\n", 2); 1664208Svbart@nginx.com 1665703Svbart@nginx.com size = nxt_length("HTTP/1.1 " "\r\n") + status_line.length 1666703Svbart@nginx.com + nxt_length("Server: " NXT_SERVER "\r\n") 1667703Svbart@nginx.com + nxt_length("Date: Wed, 31 Dec 1986 16:40:00 GMT\r\n") 1668703Svbart@nginx.com + nxt_length("Content-Type: application/json\r\n") 1669703Svbart@nginx.com + nxt_length("Content-Length: " "\r\n") + NXT_SIZE_T_LEN 1670703Svbart@nginx.com + nxt_length("Connection: close\r\n") 1671703Svbart@nginx.com + nxt_length("\r\n"); 167233Svbart@nginx.com 167344Svbart@nginx.com b = nxt_buf_mem_alloc(c->mem_pool, size, 0); 167433Svbart@nginx.com if (nxt_slow_path(b == NULL)) { 1675140Svbart@nginx.com nxt_controller_conn_close(task, c, req); 1676140Svbart@nginx.com return; 167733Svbart@nginx.com } 167833Svbart@nginx.com 1679208Svbart@nginx.com b->next = body; 1680208Svbart@nginx.com 1681208Svbart@nginx.com nxt_str_set(&str, "HTTP/1.1 "); 168244Svbart@nginx.com 1683208Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length); 1684208Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, status_line.start, 1685208Svbart@nginx.com status_line.length); 1686208Svbart@nginx.com 1687208Svbart@nginx.com nxt_str_set(&str, "\r\n" 1688673Svbart@nginx.com "Server: " NXT_SERVER "\r\n" 1689208Svbart@nginx.com "Date: "); 1690208Svbart@nginx.com 1691208Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length); 169244Svbart@nginx.com 1693208Svbart@nginx.com b->mem.free = nxt_thread_time_string(task->thread, &date_cache, 1694208Svbart@nginx.com b->mem.free); 1695208Svbart@nginx.com 1696208Svbart@nginx.com nxt_str_set(&str, "\r\n" 1697208Svbart@nginx.com "Content-Type: application/json\r\n" 1698208Svbart@nginx.com "Content-Length: "); 1699208Svbart@nginx.com 1700208Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length); 170145Svbart@nginx.com 1702208Svbart@nginx.com b->mem.free = nxt_sprintf(b->mem.free, b->mem.end, "%uz", 1703208Svbart@nginx.com nxt_buf_mem_used_size(&body->mem)); 1704208Svbart@nginx.com 1705208Svbart@nginx.com nxt_str_set(&str, "\r\n" 1706208Svbart@nginx.com "Connection: close\r\n" 1707208Svbart@nginx.com "\r\n"); 1708208Svbart@nginx.com 1709208Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length); 171033Svbart@nginx.com 171133Svbart@nginx.com c->write = b; 171244Svbart@nginx.com c->write_state = &nxt_controller_conn_write_state; 171333Svbart@nginx.com 171462Sigor@sysoev.ru nxt_conn_write(task->thread->engine, c); 171533Svbart@nginx.com } 171645Svbart@nginx.com 171745Svbart@nginx.com 1718208Svbart@nginx.com static u_char * 1719208Svbart@nginx.com nxt_controller_date(u_char *buf, nxt_realtime_t *now, struct tm *tm, 1720208Svbart@nginx.com size_t size, const char *format) 172145Svbart@nginx.com { 1722208Svbart@nginx.com static const char *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", 1723208Svbart@nginx.com "Sat" }; 172445Svbart@nginx.com 1725208Svbart@nginx.com static const char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", 1726208Svbart@nginx.com "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; 172745Svbart@nginx.com 1728208Svbart@nginx.com return nxt_sprintf(buf, buf + size, format, 1729208Svbart@nginx.com week[tm->tm_wday], tm->tm_mday, 1730208Svbart@nginx.com month[tm->tm_mon], tm->tm_year + 1900, 1731208Svbart@nginx.com tm->tm_hour, tm->tm_min, tm->tm_sec); 173245Svbart@nginx.com } 1733