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_sockaddr_t *sa; 40620Sigor@sysoev.ru nxt_listen_socket_t *ls; 40720Sigor@sysoev.ru 40820Sigor@sysoev.ru sa = rt->controller_listen; 40920Sigor@sysoev.ru 41065Sigor@sysoev.ru ls = nxt_mp_alloc(rt->mem_pool, sizeof(nxt_listen_socket_t)); 41120Sigor@sysoev.ru if (ls == NULL) { 41220Sigor@sysoev.ru return NXT_ERROR; 41320Sigor@sysoev.ru } 41420Sigor@sysoev.ru 41520Sigor@sysoev.ru ls->sockaddr = nxt_sockaddr_create(rt->mem_pool, &sa->u.sockaddr, 41620Sigor@sysoev.ru sa->socklen, sa->length); 41720Sigor@sysoev.ru if (ls->sockaddr == NULL) { 41820Sigor@sysoev.ru return NXT_ERROR; 41920Sigor@sysoev.ru } 42020Sigor@sysoev.ru 42120Sigor@sysoev.ru ls->sockaddr->type = sa->type; 422312Sigor@sysoev.ru nxt_sockaddr_text(ls->sockaddr); 42320Sigor@sysoev.ru 424359Sigor@sysoev.ru nxt_listen_socket_remote_size(ls); 42520Sigor@sysoev.ru 42620Sigor@sysoev.ru ls->socket = -1; 42720Sigor@sysoev.ru ls->backlog = NXT_LISTEN_BACKLOG; 42820Sigor@sysoev.ru ls->read_after_accept = 1; 42920Sigor@sysoev.ru ls->flags = NXT_NONBLOCK; 43020Sigor@sysoev.ru 43120Sigor@sysoev.ru #if 0 43220Sigor@sysoev.ru /* STUB */ 43365Sigor@sysoev.ru wq = nxt_mp_zget(cf->mem_pool, sizeof(nxt_work_queue_t)); 43420Sigor@sysoev.ru if (wq == NULL) { 43520Sigor@sysoev.ru return NXT_ERROR; 43620Sigor@sysoev.ru } 43720Sigor@sysoev.ru nxt_work_queue_name(wq, "listen"); 43820Sigor@sysoev.ru /**/ 43920Sigor@sysoev.ru 44020Sigor@sysoev.ru ls->work_queue = wq; 44120Sigor@sysoev.ru #endif 44220Sigor@sysoev.ru ls->handler = nxt_controller_conn_init; 44320Sigor@sysoev.ru 44420Sigor@sysoev.ru if (nxt_listen_socket_create(task, ls, 0) != NXT_OK) { 44520Sigor@sysoev.ru return NXT_ERROR; 44620Sigor@sysoev.ru } 44720Sigor@sysoev.ru 44820Sigor@sysoev.ru rt->controller_socket = ls; 44920Sigor@sysoev.ru 45020Sigor@sysoev.ru return NXT_OK; 45120Sigor@sysoev.ru } 45220Sigor@sysoev.ru 45320Sigor@sysoev.ru 45420Sigor@sysoev.ru static void 45520Sigor@sysoev.ru nxt_controller_conn_init(nxt_task_t *task, void *obj, void *data) 45620Sigor@sysoev.ru { 45727Svbart@nginx.com nxt_buf_t *b; 45862Sigor@sysoev.ru nxt_conn_t *c; 45927Svbart@nginx.com nxt_event_engine_t *engine; 46027Svbart@nginx.com nxt_controller_request_t *r; 46120Sigor@sysoev.ru 46220Sigor@sysoev.ru c = obj; 46320Sigor@sysoev.ru 46420Sigor@sysoev.ru nxt_debug(task, "controller conn init fd:%d", c->socket.fd); 46520Sigor@sysoev.ru 46665Sigor@sysoev.ru r = nxt_mp_zget(c->mem_pool, sizeof(nxt_controller_request_t)); 46727Svbart@nginx.com if (nxt_slow_path(r == NULL)) { 46827Svbart@nginx.com nxt_controller_conn_free(task, c, NULL); 46927Svbart@nginx.com return; 47027Svbart@nginx.com } 47127Svbart@nginx.com 472140Svbart@nginx.com r->conn = c; 473140Svbart@nginx.com 47460Svbart@nginx.com if (nxt_slow_path(nxt_http_parse_request_init(&r->parser, c->mem_pool) 47560Svbart@nginx.com != NXT_OK)) 47660Svbart@nginx.com { 47760Svbart@nginx.com nxt_controller_conn_free(task, c, NULL); 47860Svbart@nginx.com return; 47960Svbart@nginx.com } 48027Svbart@nginx.com 481*1167Svbart@nginx.com r->parser.encoded_slashes = 1; 482*1167Svbart@nginx.com 48320Sigor@sysoev.ru b = nxt_buf_mem_alloc(c->mem_pool, 1024, 0); 48420Sigor@sysoev.ru if (nxt_slow_path(b == NULL)) { 48520Sigor@sysoev.ru nxt_controller_conn_free(task, c, NULL); 48620Sigor@sysoev.ru return; 48720Sigor@sysoev.ru } 48820Sigor@sysoev.ru 48920Sigor@sysoev.ru c->read = b; 49027Svbart@nginx.com c->socket.data = r; 49120Sigor@sysoev.ru c->socket.read_ready = 1; 49220Sigor@sysoev.ru c->read_state = &nxt_controller_conn_read_state; 49320Sigor@sysoev.ru 49420Sigor@sysoev.ru engine = task->thread->engine; 49520Sigor@sysoev.ru c->read_work_queue = &engine->read_work_queue; 49627Svbart@nginx.com c->write_work_queue = &engine->write_work_queue; 49720Sigor@sysoev.ru 49862Sigor@sysoev.ru nxt_conn_read(engine, c); 49920Sigor@sysoev.ru } 50020Sigor@sysoev.ru 50120Sigor@sysoev.ru 50220Sigor@sysoev.ru static const nxt_event_conn_state_t nxt_controller_conn_read_state 50320Sigor@sysoev.ru nxt_aligned(64) = 50420Sigor@sysoev.ru { 50556Sigor@sysoev.ru .ready_handler = nxt_controller_conn_read, 50656Sigor@sysoev.ru .close_handler = nxt_controller_conn_close, 50756Sigor@sysoev.ru .error_handler = nxt_controller_conn_read_error, 50820Sigor@sysoev.ru 50956Sigor@sysoev.ru .timer_handler = nxt_controller_conn_read_timeout, 51056Sigor@sysoev.ru .timer_value = nxt_controller_conn_timeout_value, 51156Sigor@sysoev.ru .timer_data = 60 * 1000, 51220Sigor@sysoev.ru }; 51320Sigor@sysoev.ru 51420Sigor@sysoev.ru 51520Sigor@sysoev.ru static void 51620Sigor@sysoev.ru nxt_controller_conn_read(nxt_task_t *task, void *obj, void *data) 51720Sigor@sysoev.ru { 51827Svbart@nginx.com size_t preread; 51927Svbart@nginx.com nxt_buf_t *b; 52027Svbart@nginx.com nxt_int_t rc; 52162Sigor@sysoev.ru nxt_conn_t *c; 52227Svbart@nginx.com nxt_controller_request_t *r; 52320Sigor@sysoev.ru 52420Sigor@sysoev.ru c = obj; 52527Svbart@nginx.com r = data; 52620Sigor@sysoev.ru 52720Sigor@sysoev.ru nxt_debug(task, "controller conn read"); 52820Sigor@sysoev.ru 52927Svbart@nginx.com nxt_queue_remove(&c->link); 53027Svbart@nginx.com nxt_queue_self(&c->link); 53127Svbart@nginx.com 53227Svbart@nginx.com b = c->read; 53327Svbart@nginx.com 53427Svbart@nginx.com rc = nxt_http_parse_request(&r->parser, &b->mem); 53527Svbart@nginx.com 53627Svbart@nginx.com if (nxt_slow_path(rc != NXT_DONE)) { 53727Svbart@nginx.com 53827Svbart@nginx.com if (rc == NXT_AGAIN) { 53927Svbart@nginx.com if (nxt_buf_mem_free_size(&b->mem) == 0) { 54027Svbart@nginx.com nxt_log(task, NXT_LOG_ERR, "too long request headers"); 54127Svbart@nginx.com nxt_controller_conn_close(task, c, r); 54227Svbart@nginx.com return; 54327Svbart@nginx.com } 54427Svbart@nginx.com 54562Sigor@sysoev.ru nxt_conn_read(task->thread->engine, c); 54627Svbart@nginx.com return; 54727Svbart@nginx.com } 54827Svbart@nginx.com 54927Svbart@nginx.com /* rc == NXT_ERROR */ 55027Svbart@nginx.com 55127Svbart@nginx.com nxt_log(task, NXT_LOG_ERR, "parsing error"); 55227Svbart@nginx.com 55327Svbart@nginx.com nxt_controller_conn_close(task, c, r); 55427Svbart@nginx.com return; 55527Svbart@nginx.com } 55627Svbart@nginx.com 557417Svbart@nginx.com rc = nxt_http_fields_process(r->parser.fields, &nxt_controller_fields_hash, 558417Svbart@nginx.com r); 55960Svbart@nginx.com 56060Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 56160Svbart@nginx.com nxt_controller_conn_close(task, c, r); 56260Svbart@nginx.com return; 56360Svbart@nginx.com } 56460Svbart@nginx.com 56527Svbart@nginx.com preread = nxt_buf_mem_used_size(&b->mem); 56627Svbart@nginx.com 56727Svbart@nginx.com nxt_debug(task, "controller request header parsing complete, " 568107Svbart@nginx.com "body length: %uz, preread: %uz", 56927Svbart@nginx.com r->length, preread); 57027Svbart@nginx.com 57127Svbart@nginx.com if (preread >= r->length) { 572140Svbart@nginx.com nxt_controller_process_request(task, r); 57327Svbart@nginx.com return; 57427Svbart@nginx.com } 57527Svbart@nginx.com 57627Svbart@nginx.com if (r->length - preread > (size_t) nxt_buf_mem_free_size(&b->mem)) { 57727Svbart@nginx.com b = nxt_buf_mem_alloc(c->mem_pool, r->length, 0); 57827Svbart@nginx.com if (nxt_slow_path(b == NULL)) { 57927Svbart@nginx.com nxt_controller_conn_free(task, c, NULL); 58027Svbart@nginx.com return; 58127Svbart@nginx.com } 58227Svbart@nginx.com 58327Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, c->read->mem.pos, preread); 58427Svbart@nginx.com 58527Svbart@nginx.com c->read = b; 58627Svbart@nginx.com } 58727Svbart@nginx.com 58827Svbart@nginx.com c->read_state = &nxt_controller_conn_body_read_state; 58927Svbart@nginx.com 59062Sigor@sysoev.ru nxt_conn_read(task->thread->engine, c); 59120Sigor@sysoev.ru } 59220Sigor@sysoev.ru 59320Sigor@sysoev.ru 59420Sigor@sysoev.ru static nxt_msec_t 59562Sigor@sysoev.ru nxt_controller_conn_timeout_value(nxt_conn_t *c, uintptr_t data) 59620Sigor@sysoev.ru { 59720Sigor@sysoev.ru return (nxt_msec_t) data; 59820Sigor@sysoev.ru } 59920Sigor@sysoev.ru 60020Sigor@sysoev.ru 60120Sigor@sysoev.ru static void 60220Sigor@sysoev.ru nxt_controller_conn_read_error(nxt_task_t *task, void *obj, void *data) 60320Sigor@sysoev.ru { 60462Sigor@sysoev.ru nxt_conn_t *c; 60520Sigor@sysoev.ru 60620Sigor@sysoev.ru c = obj; 60720Sigor@sysoev.ru 60820Sigor@sysoev.ru nxt_debug(task, "controller conn read error"); 60920Sigor@sysoev.ru 61027Svbart@nginx.com nxt_controller_conn_close(task, c, data); 61120Sigor@sysoev.ru } 61220Sigor@sysoev.ru 61320Sigor@sysoev.ru 61420Sigor@sysoev.ru static void 61520Sigor@sysoev.ru nxt_controller_conn_read_timeout(nxt_task_t *task, void *obj, void *data) 61620Sigor@sysoev.ru { 61762Sigor@sysoev.ru nxt_timer_t *timer; 61862Sigor@sysoev.ru nxt_conn_t *c; 61920Sigor@sysoev.ru 62062Sigor@sysoev.ru timer = obj; 62120Sigor@sysoev.ru 62262Sigor@sysoev.ru c = nxt_read_timer_conn(timer); 62320Sigor@sysoev.ru c->socket.timedout = 1; 62420Sigor@sysoev.ru c->socket.closed = 1; 62520Sigor@sysoev.ru 62620Sigor@sysoev.ru nxt_debug(task, "controller conn read timeout"); 62720Sigor@sysoev.ru 62827Svbart@nginx.com nxt_controller_conn_close(task, c, data); 62927Svbart@nginx.com } 63027Svbart@nginx.com 63127Svbart@nginx.com 63227Svbart@nginx.com static const nxt_event_conn_state_t nxt_controller_conn_body_read_state 63327Svbart@nginx.com nxt_aligned(64) = 63427Svbart@nginx.com { 63556Sigor@sysoev.ru .ready_handler = nxt_controller_conn_body_read, 63656Sigor@sysoev.ru .close_handler = nxt_controller_conn_close, 63756Sigor@sysoev.ru .error_handler = nxt_controller_conn_read_error, 63827Svbart@nginx.com 63956Sigor@sysoev.ru .timer_handler = nxt_controller_conn_read_timeout, 64056Sigor@sysoev.ru .timer_value = nxt_controller_conn_timeout_value, 64156Sigor@sysoev.ru .timer_data = 60 * 1000, 64256Sigor@sysoev.ru .timer_autoreset = 1, 64327Svbart@nginx.com }; 64427Svbart@nginx.com 64527Svbart@nginx.com 64627Svbart@nginx.com static void 64727Svbart@nginx.com nxt_controller_conn_body_read(nxt_task_t *task, void *obj, void *data) 64827Svbart@nginx.com { 649107Svbart@nginx.com size_t read; 650107Svbart@nginx.com nxt_buf_t *b; 651107Svbart@nginx.com nxt_conn_t *c; 652107Svbart@nginx.com nxt_controller_request_t *r; 65327Svbart@nginx.com 65427Svbart@nginx.com c = obj; 655107Svbart@nginx.com r = data; 65627Svbart@nginx.com b = c->read; 65727Svbart@nginx.com 658107Svbart@nginx.com read = nxt_buf_mem_used_size(&b->mem); 65927Svbart@nginx.com 660107Svbart@nginx.com nxt_debug(task, "controller conn body read: %uz of %uz", 661107Svbart@nginx.com read, r->length); 66227Svbart@nginx.com 663107Svbart@nginx.com if (read >= r->length) { 664140Svbart@nginx.com nxt_controller_process_request(task, r); 66527Svbart@nginx.com return; 66627Svbart@nginx.com } 66727Svbart@nginx.com 66862Sigor@sysoev.ru nxt_conn_read(task->thread->engine, c); 66927Svbart@nginx.com } 67027Svbart@nginx.com 67127Svbart@nginx.com 67227Svbart@nginx.com static const nxt_event_conn_state_t nxt_controller_conn_write_state 67327Svbart@nginx.com nxt_aligned(64) = 67427Svbart@nginx.com { 67556Sigor@sysoev.ru .ready_handler = nxt_controller_conn_write, 67656Sigor@sysoev.ru .error_handler = nxt_controller_conn_write_error, 67727Svbart@nginx.com 67856Sigor@sysoev.ru .timer_handler = nxt_controller_conn_write_timeout, 67956Sigor@sysoev.ru .timer_value = nxt_controller_conn_timeout_value, 68056Sigor@sysoev.ru .timer_data = 60 * 1000, 68156Sigor@sysoev.ru .timer_autoreset = 1, 68227Svbart@nginx.com }; 68327Svbart@nginx.com 68427Svbart@nginx.com 68527Svbart@nginx.com static void 68627Svbart@nginx.com nxt_controller_conn_write(nxt_task_t *task, void *obj, void *data) 68727Svbart@nginx.com { 68862Sigor@sysoev.ru nxt_buf_t *b; 68962Sigor@sysoev.ru nxt_conn_t *c; 69027Svbart@nginx.com 69127Svbart@nginx.com c = obj; 69227Svbart@nginx.com 69327Svbart@nginx.com nxt_debug(task, "controller conn write"); 69427Svbart@nginx.com 69527Svbart@nginx.com b = c->write; 69627Svbart@nginx.com 69727Svbart@nginx.com if (b->mem.pos != b->mem.free) { 69862Sigor@sysoev.ru nxt_conn_write(task->thread->engine, c); 69927Svbart@nginx.com return; 70027Svbart@nginx.com } 70127Svbart@nginx.com 70227Svbart@nginx.com nxt_debug(task, "controller conn write complete"); 70327Svbart@nginx.com 70427Svbart@nginx.com nxt_controller_conn_close(task, c, data); 70527Svbart@nginx.com } 70627Svbart@nginx.com 70727Svbart@nginx.com 70827Svbart@nginx.com static void 70927Svbart@nginx.com nxt_controller_conn_write_error(nxt_task_t *task, void *obj, void *data) 71027Svbart@nginx.com { 71162Sigor@sysoev.ru nxt_conn_t *c; 71227Svbart@nginx.com 71327Svbart@nginx.com c = obj; 71427Svbart@nginx.com 71527Svbart@nginx.com nxt_debug(task, "controller conn write error"); 71627Svbart@nginx.com 71727Svbart@nginx.com nxt_controller_conn_close(task, c, data); 71827Svbart@nginx.com } 71927Svbart@nginx.com 72027Svbart@nginx.com 72127Svbart@nginx.com static void 72227Svbart@nginx.com nxt_controller_conn_write_timeout(nxt_task_t *task, void *obj, void *data) 72327Svbart@nginx.com { 72462Sigor@sysoev.ru nxt_conn_t *c; 72562Sigor@sysoev.ru nxt_timer_t *timer; 72627Svbart@nginx.com 72762Sigor@sysoev.ru timer = obj; 72827Svbart@nginx.com 72962Sigor@sysoev.ru c = nxt_write_timer_conn(timer); 73027Svbart@nginx.com c->socket.timedout = 1; 73127Svbart@nginx.com c->socket.closed = 1; 73227Svbart@nginx.com 73327Svbart@nginx.com nxt_debug(task, "controller conn write timeout"); 73427Svbart@nginx.com 73527Svbart@nginx.com nxt_controller_conn_close(task, c, data); 73620Sigor@sysoev.ru } 73720Sigor@sysoev.ru 73820Sigor@sysoev.ru 73920Sigor@sysoev.ru static const nxt_event_conn_state_t nxt_controller_conn_close_state 74020Sigor@sysoev.ru nxt_aligned(64) = 74120Sigor@sysoev.ru { 74256Sigor@sysoev.ru .ready_handler = nxt_controller_conn_free, 74320Sigor@sysoev.ru }; 74420Sigor@sysoev.ru 74520Sigor@sysoev.ru 74620Sigor@sysoev.ru static void 74720Sigor@sysoev.ru nxt_controller_conn_close(nxt_task_t *task, void *obj, void *data) 74820Sigor@sysoev.ru { 74962Sigor@sysoev.ru nxt_conn_t *c; 75020Sigor@sysoev.ru 75120Sigor@sysoev.ru c = obj; 75220Sigor@sysoev.ru 75320Sigor@sysoev.ru nxt_debug(task, "controller conn close"); 75420Sigor@sysoev.ru 75527Svbart@nginx.com nxt_queue_remove(&c->link); 75627Svbart@nginx.com 75720Sigor@sysoev.ru c->write_state = &nxt_controller_conn_close_state; 75820Sigor@sysoev.ru 75962Sigor@sysoev.ru nxt_conn_close(task->thread->engine, c); 76020Sigor@sysoev.ru } 76120Sigor@sysoev.ru 76220Sigor@sysoev.ru 76320Sigor@sysoev.ru static void 76420Sigor@sysoev.ru nxt_controller_conn_free(nxt_task_t *task, void *obj, void *data) 76520Sigor@sysoev.ru { 76662Sigor@sysoev.ru nxt_conn_t *c; 76720Sigor@sysoev.ru 76820Sigor@sysoev.ru c = obj; 76920Sigor@sysoev.ru 77020Sigor@sysoev.ru nxt_debug(task, "controller conn free"); 77120Sigor@sysoev.ru 772337Sigor@sysoev.ru nxt_sockaddr_cache_free(task->thread->engine, c); 773337Sigor@sysoev.ru 774386Sigor@sysoev.ru nxt_conn_free(task, c); 77520Sigor@sysoev.ru } 77627Svbart@nginx.com 77727Svbart@nginx.com 77827Svbart@nginx.com static nxt_int_t 77960Svbart@nginx.com nxt_controller_request_content_length(void *ctx, nxt_http_field_t *field, 780417Svbart@nginx.com uintptr_t data) 78127Svbart@nginx.com { 78227Svbart@nginx.com off_t length; 78327Svbart@nginx.com nxt_controller_request_t *r; 78427Svbart@nginx.com 78527Svbart@nginx.com r = ctx; 78627Svbart@nginx.com 787417Svbart@nginx.com length = nxt_off_t_parse(field->value, field->value_length); 78827Svbart@nginx.com 789710Svbart@nginx.com if (nxt_fast_path(length >= 0)) { 790107Svbart@nginx.com 791107Svbart@nginx.com if (nxt_slow_path(length > NXT_SIZE_T_MAX)) { 792417Svbart@nginx.com nxt_log_error(NXT_LOG_ERR, &r->conn->log, 793417Svbart@nginx.com "Content-Length is too big"); 794107Svbart@nginx.com return NXT_ERROR; 795107Svbart@nginx.com } 79627Svbart@nginx.com 79727Svbart@nginx.com r->length = length; 79827Svbart@nginx.com return NXT_OK; 79927Svbart@nginx.com } 80027Svbart@nginx.com 801417Svbart@nginx.com nxt_log_error(NXT_LOG_ERR, &r->conn->log, "Content-Length is invalid"); 80227Svbart@nginx.com 80327Svbart@nginx.com return NXT_ERROR; 80427Svbart@nginx.com } 80527Svbart@nginx.com 80627Svbart@nginx.com 80727Svbart@nginx.com static void 808140Svbart@nginx.com nxt_controller_process_request(nxt_task_t *task, nxt_controller_request_t *req) 80927Svbart@nginx.com { 810774Svbart@nginx.com uint32_t i, count; 811774Svbart@nginx.com nxt_str_t path; 812774Svbart@nginx.com nxt_conn_t *c; 813774Svbart@nginx.com nxt_conf_value_t *value; 814774Svbart@nginx.com nxt_controller_response_t resp; 815774Svbart@nginx.com #if (NXT_TLS) 816774Svbart@nginx.com nxt_conf_value_t *certs; 817774Svbart@nginx.com 818774Svbart@nginx.com static nxt_str_t certificates = nxt_string("certificates"); 819774Svbart@nginx.com #endif 820774Svbart@nginx.com static nxt_str_t config = nxt_string("config"); 821774Svbart@nginx.com 822774Svbart@nginx.com c = req->conn; 823774Svbart@nginx.com path = req->parser.path; 824774Svbart@nginx.com 825774Svbart@nginx.com if (path.length > 1 && path.start[path.length - 1] == '/') { 826774Svbart@nginx.com path.length--; 827774Svbart@nginx.com } 828774Svbart@nginx.com 829774Svbart@nginx.com if (nxt_str_start(&path, "/config", 7) 830774Svbart@nginx.com && (path.length == 7 || path.start[7] == '/')) 831774Svbart@nginx.com { 832774Svbart@nginx.com if (path.length == 7) { 833774Svbart@nginx.com path.length = 1; 834774Svbart@nginx.com 835774Svbart@nginx.com } else { 836774Svbart@nginx.com path.length -= 7; 837774Svbart@nginx.com path.start += 7; 838774Svbart@nginx.com } 839774Svbart@nginx.com 840774Svbart@nginx.com nxt_controller_process_config(task, req, &path); 841774Svbart@nginx.com return; 842774Svbart@nginx.com } 843774Svbart@nginx.com 844774Svbart@nginx.com #if (NXT_TLS) 845774Svbart@nginx.com 846774Svbart@nginx.com if (nxt_str_start(&path, "/certificates", 13) 847774Svbart@nginx.com && (path.length == 13 || path.start[13] == '/')) 848774Svbart@nginx.com { 849774Svbart@nginx.com if (path.length == 13) { 850774Svbart@nginx.com path.length = 1; 851774Svbart@nginx.com 852774Svbart@nginx.com } else { 853774Svbart@nginx.com path.length -= 13; 854774Svbart@nginx.com path.start += 13; 855774Svbart@nginx.com } 856774Svbart@nginx.com 857774Svbart@nginx.com nxt_controller_process_cert(task, req, &path); 858774Svbart@nginx.com return; 859774Svbart@nginx.com } 860774Svbart@nginx.com 861774Svbart@nginx.com #endif 862774Svbart@nginx.com 863774Svbart@nginx.com nxt_memzero(&resp, sizeof(nxt_controller_response_t)); 864774Svbart@nginx.com 865774Svbart@nginx.com if (path.length == 1 && path.start[0] == '/') { 866774Svbart@nginx.com 867774Svbart@nginx.com if (!nxt_str_eq(&req->parser.method, "GET", 3)) { 868774Svbart@nginx.com goto invalid_method; 869774Svbart@nginx.com } 870774Svbart@nginx.com 871774Svbart@nginx.com count = 1; 872774Svbart@nginx.com #if (NXT_TLS) 873774Svbart@nginx.com count++; 874774Svbart@nginx.com #endif 875774Svbart@nginx.com 876774Svbart@nginx.com value = nxt_conf_create_object(c->mem_pool, count); 877774Svbart@nginx.com if (nxt_slow_path(value == NULL)) { 878774Svbart@nginx.com goto alloc_fail; 879774Svbart@nginx.com } 880774Svbart@nginx.com 881774Svbart@nginx.com i = 0; 882774Svbart@nginx.com 883774Svbart@nginx.com #if (NXT_TLS) 884774Svbart@nginx.com certs = nxt_cert_info_get_all(c->mem_pool); 885774Svbart@nginx.com if (nxt_slow_path(certs == NULL)) { 886774Svbart@nginx.com goto alloc_fail; 887774Svbart@nginx.com } 888774Svbart@nginx.com 889774Svbart@nginx.com nxt_conf_set_member(value, &certificates, certs, i++); 890774Svbart@nginx.com #endif 891774Svbart@nginx.com 892774Svbart@nginx.com nxt_conf_set_member(value, &config, nxt_controller_conf.root, i); 893774Svbart@nginx.com 894774Svbart@nginx.com resp.status = 200; 895774Svbart@nginx.com resp.conf = value; 896774Svbart@nginx.com 897774Svbart@nginx.com nxt_controller_response(task, req, &resp); 898774Svbart@nginx.com return; 899774Svbart@nginx.com } 900774Svbart@nginx.com 901774Svbart@nginx.com resp.status = 404; 902774Svbart@nginx.com resp.title = (u_char *) "Value doesn't exist."; 903774Svbart@nginx.com resp.offset = -1; 904774Svbart@nginx.com 905774Svbart@nginx.com nxt_controller_response(task, req, &resp); 906774Svbart@nginx.com return; 907774Svbart@nginx.com 908774Svbart@nginx.com invalid_method: 909774Svbart@nginx.com 910774Svbart@nginx.com resp.status = 405; 911774Svbart@nginx.com resp.title = (u_char *) "Invalid method."; 912774Svbart@nginx.com resp.offset = -1; 913774Svbart@nginx.com 914774Svbart@nginx.com nxt_controller_response(task, req, &resp); 915774Svbart@nginx.com return; 916774Svbart@nginx.com 917774Svbart@nginx.com alloc_fail: 918774Svbart@nginx.com 919774Svbart@nginx.com resp.status = 500; 920774Svbart@nginx.com resp.title = (u_char *) "Memory allocation failed."; 921774Svbart@nginx.com resp.offset = -1; 922774Svbart@nginx.com 923774Svbart@nginx.com nxt_controller_response(task, req, &resp); 924774Svbart@nginx.com return; 925774Svbart@nginx.com } 926774Svbart@nginx.com 927774Svbart@nginx.com 928774Svbart@nginx.com static void 929774Svbart@nginx.com nxt_controller_process_config(nxt_task_t *task, nxt_controller_request_t *req, 930774Svbart@nginx.com nxt_str_t *path) 931774Svbart@nginx.com { 93265Sigor@sysoev.ru nxt_mp_t *mp; 93351Svbart@nginx.com nxt_int_t rc; 934140Svbart@nginx.com nxt_conn_t *c; 9351049Svbart@nginx.com nxt_bool_t post; 93651Svbart@nginx.com nxt_buf_mem_t *mbuf; 937106Svbart@nginx.com nxt_conf_op_t *ops; 938106Svbart@nginx.com nxt_conf_value_t *value; 939357Svbart@nginx.com nxt_conf_validation_t vldt; 940208Svbart@nginx.com nxt_conf_json_error_t error; 94144Svbart@nginx.com nxt_controller_response_t resp; 94244Svbart@nginx.com 94351Svbart@nginx.com static const nxt_str_t empty_obj = nxt_string("{}"); 94451Svbart@nginx.com 945774Svbart@nginx.com nxt_memzero(&resp, sizeof(nxt_controller_response_t)); 946632Svbart@nginx.com 947774Svbart@nginx.com c = req->conn; 94844Svbart@nginx.com 94944Svbart@nginx.com if (nxt_str_eq(&req->parser.method, "GET", 3)) { 95046Svbart@nginx.com 951774Svbart@nginx.com value = nxt_conf_get_path(nxt_controller_conf.root, path); 95251Svbart@nginx.com 95351Svbart@nginx.com if (value == NULL) { 954208Svbart@nginx.com goto not_found; 95551Svbart@nginx.com } 95651Svbart@nginx.com 957208Svbart@nginx.com resp.status = 200; 958106Svbart@nginx.com resp.conf = value; 95946Svbart@nginx.com 960208Svbart@nginx.com nxt_controller_response(task, req, &resp); 961208Svbart@nginx.com return; 96251Svbart@nginx.com } 96351Svbart@nginx.com 9641049Svbart@nginx.com if (nxt_str_eq(&req->parser.method, "POST", 4)) { 9651049Svbart@nginx.com if (path->length == 1) { 9661049Svbart@nginx.com goto not_allowed; 9671049Svbart@nginx.com } 9681049Svbart@nginx.com 9691049Svbart@nginx.com post = 1; 9701049Svbart@nginx.com 9711049Svbart@nginx.com } else { 9721049Svbart@nginx.com post = 0; 9731049Svbart@nginx.com } 9741049Svbart@nginx.com 9751049Svbart@nginx.com if (post || nxt_str_eq(&req->parser.method, "PUT", 3)) { 97646Svbart@nginx.com 977238Svbart@nginx.com if (!nxt_queue_is_empty(&nxt_controller_waiting_requests)) { 978238Svbart@nginx.com nxt_queue_insert_tail(&nxt_controller_waiting_requests, &req->link); 979238Svbart@nginx.com return; 980238Svbart@nginx.com } 981238Svbart@nginx.com 98265Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 98351Svbart@nginx.com 98451Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 985208Svbart@nginx.com goto alloc_fail; 98646Svbart@nginx.com } 98746Svbart@nginx.com 98851Svbart@nginx.com mbuf = &c->read->mem; 98951Svbart@nginx.com 990208Svbart@nginx.com nxt_memzero(&error, sizeof(nxt_conf_json_error_t)); 991208Svbart@nginx.com 992208Svbart@nginx.com value = nxt_conf_json_parse(mp, mbuf->pos, mbuf->free, &error); 99351Svbart@nginx.com 99451Svbart@nginx.com if (value == NULL) { 99565Sigor@sysoev.ru nxt_mp_destroy(mp); 996208Svbart@nginx.com 997208Svbart@nginx.com if (error.pos == NULL) { 998208Svbart@nginx.com goto alloc_fail; 999208Svbart@nginx.com } 1000208Svbart@nginx.com 1001208Svbart@nginx.com resp.status = 400; 1002208Svbart@nginx.com resp.title = (u_char *) "Invalid JSON."; 1003357Svbart@nginx.com resp.detail.length = nxt_strlen(error.detail); 1004357Svbart@nginx.com resp.detail.start = error.detail; 1005208Svbart@nginx.com resp.offset = error.pos - mbuf->pos; 1006208Svbart@nginx.com 1007208Svbart@nginx.com nxt_conf_json_position(mbuf->pos, error.pos, 1008208Svbart@nginx.com &resp.line, &resp.column); 1009208Svbart@nginx.com 1010208Svbart@nginx.com nxt_controller_response(task, req, &resp); 1011208Svbart@nginx.com return; 101251Svbart@nginx.com } 101351Svbart@nginx.com 1014774Svbart@nginx.com if (path->length != 1) { 1015106Svbart@nginx.com rc = nxt_conf_op_compile(c->mem_pool, &ops, 1016106Svbart@nginx.com nxt_controller_conf.root, 10171049Svbart@nginx.com path, value, post); 101846Svbart@nginx.com 10191049Svbart@nginx.com if (rc != NXT_CONF_OP_OK) { 1020619Svbart@nginx.com nxt_mp_destroy(mp); 1021619Svbart@nginx.com 10221049Svbart@nginx.com switch (rc) { 10231049Svbart@nginx.com case NXT_CONF_OP_NOT_FOUND: 1024208Svbart@nginx.com goto not_found; 10251049Svbart@nginx.com 10261049Svbart@nginx.com case NXT_CONF_OP_NOT_ALLOWED: 10271049Svbart@nginx.com goto not_allowed; 102851Svbart@nginx.com } 102946Svbart@nginx.com 10301049Svbart@nginx.com /* rc == NXT_CONF_OP_ERROR */ 1031208Svbart@nginx.com goto alloc_fail; 103251Svbart@nginx.com } 103351Svbart@nginx.com 1034106Svbart@nginx.com value = nxt_conf_clone(mp, ops, nxt_controller_conf.root); 103551Svbart@nginx.com 103651Svbart@nginx.com if (nxt_slow_path(value == NULL)) { 103765Sigor@sysoev.ru nxt_mp_destroy(mp); 1038208Svbart@nginx.com goto alloc_fail; 103951Svbart@nginx.com } 104046Svbart@nginx.com } 104144Svbart@nginx.com 1042357Svbart@nginx.com nxt_memzero(&vldt, sizeof(nxt_conf_validation_t)); 1043357Svbart@nginx.com 1044357Svbart@nginx.com vldt.conf = value; 1045357Svbart@nginx.com vldt.pool = c->mem_pool; 1046357Svbart@nginx.com 1047357Svbart@nginx.com rc = nxt_conf_validate(&vldt); 1048357Svbart@nginx.com 1049357Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 1050121Svbart@nginx.com nxt_mp_destroy(mp); 1051357Svbart@nginx.com 1052357Svbart@nginx.com if (rc == NXT_DECLINED) { 1053357Svbart@nginx.com resp.detail = vldt.error; 1054357Svbart@nginx.com goto invalid_conf; 1055357Svbart@nginx.com } 1056357Svbart@nginx.com 1057357Svbart@nginx.com /* rc == NXT_ERROR */ 1058357Svbart@nginx.com goto alloc_fail; 1059116Svbart@nginx.com } 1060116Svbart@nginx.com 1061249Svbart@nginx.com rc = nxt_controller_conf_send(task, value, 1062249Svbart@nginx.com nxt_controller_conf_handler, req); 1063247Svbart@nginx.com 1064247Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 1065121Svbart@nginx.com nxt_mp_destroy(mp); 1066247Svbart@nginx.com 1067247Svbart@nginx.com if (rc == NXT_DECLINED) { 1068247Svbart@nginx.com goto no_router; 1069247Svbart@nginx.com } 1070247Svbart@nginx.com 1071247Svbart@nginx.com /* rc == NXT_ERROR */ 1072208Svbart@nginx.com goto alloc_fail; 1073121Svbart@nginx.com } 1074121Svbart@nginx.com 1075249Svbart@nginx.com req->conf.root = value; 1076249Svbart@nginx.com req->conf.pool = mp; 1077249Svbart@nginx.com 1078249Svbart@nginx.com nxt_queue_insert_head(&nxt_controller_waiting_requests, &req->link); 1079249Svbart@nginx.com 1080140Svbart@nginx.com return; 108151Svbart@nginx.com } 108227Svbart@nginx.com 108351Svbart@nginx.com if (nxt_str_eq(&req->parser.method, "DELETE", 6)) { 108451Svbart@nginx.com 1085238Svbart@nginx.com if (!nxt_queue_is_empty(&nxt_controller_waiting_requests)) { 1086238Svbart@nginx.com nxt_queue_insert_tail(&nxt_controller_waiting_requests, &req->link); 1087238Svbart@nginx.com return; 1088238Svbart@nginx.com } 1089238Svbart@nginx.com 1090774Svbart@nginx.com if (path->length == 1) { 109165Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 109244Svbart@nginx.com 109351Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 1094208Svbart@nginx.com goto alloc_fail; 109551Svbart@nginx.com } 109651Svbart@nginx.com 1097106Svbart@nginx.com value = nxt_conf_json_parse_str(mp, &empty_obj); 109827Svbart@nginx.com 109944Svbart@nginx.com } else { 1100106Svbart@nginx.com rc = nxt_conf_op_compile(c->mem_pool, &ops, 1101106Svbart@nginx.com nxt_controller_conf.root, 11021049Svbart@nginx.com path, NULL, 0); 110351Svbart@nginx.com 110451Svbart@nginx.com if (rc != NXT_OK) { 11051049Svbart@nginx.com if (rc == NXT_CONF_OP_NOT_FOUND) { 1106208Svbart@nginx.com goto not_found; 110751Svbart@nginx.com } 110851Svbart@nginx.com 11091049Svbart@nginx.com /* rc == NXT_CONF_OP_ERROR */ 1110208Svbart@nginx.com goto alloc_fail; 111151Svbart@nginx.com } 111251Svbart@nginx.com 111365Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 111451Svbart@nginx.com 111551Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 1116208Svbart@nginx.com goto alloc_fail; 111751Svbart@nginx.com } 111851Svbart@nginx.com 1119106Svbart@nginx.com value = nxt_conf_clone(mp, ops, nxt_controller_conf.root); 112051Svbart@nginx.com } 112151Svbart@nginx.com 112251Svbart@nginx.com if (nxt_slow_path(value == NULL)) { 112365Sigor@sysoev.ru nxt_mp_destroy(mp); 1124208Svbart@nginx.com goto alloc_fail; 112544Svbart@nginx.com } 112644Svbart@nginx.com 1127357Svbart@nginx.com nxt_memzero(&vldt, sizeof(nxt_conf_validation_t)); 1128357Svbart@nginx.com 1129357Svbart@nginx.com vldt.conf = value; 1130357Svbart@nginx.com vldt.pool = c->mem_pool; 1131357Svbart@nginx.com 1132357Svbart@nginx.com rc = nxt_conf_validate(&vldt); 1133357Svbart@nginx.com 1134357Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 1135121Svbart@nginx.com nxt_mp_destroy(mp); 1136357Svbart@nginx.com 1137357Svbart@nginx.com if (rc == NXT_DECLINED) { 1138357Svbart@nginx.com resp.detail = vldt.error; 1139357Svbart@nginx.com goto invalid_conf; 1140357Svbart@nginx.com } 1141357Svbart@nginx.com 1142357Svbart@nginx.com /* rc == NXT_ERROR */ 1143357Svbart@nginx.com goto alloc_fail; 1144116Svbart@nginx.com } 1145116Svbart@nginx.com 1146249Svbart@nginx.com rc = nxt_controller_conf_send(task, value, 1147249Svbart@nginx.com nxt_controller_conf_handler, req); 1148247Svbart@nginx.com 1149247Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 1150121Svbart@nginx.com nxt_mp_destroy(mp); 1151247Svbart@nginx.com 1152247Svbart@nginx.com if (rc == NXT_DECLINED) { 1153247Svbart@nginx.com goto no_router; 1154247Svbart@nginx.com } 1155247Svbart@nginx.com 1156247Svbart@nginx.com /* rc == NXT_ERROR */ 1157208Svbart@nginx.com goto alloc_fail; 1158121Svbart@nginx.com } 1159121Svbart@nginx.com 1160249Svbart@nginx.com req->conf.root = value; 1161249Svbart@nginx.com req->conf.pool = mp; 1162249Svbart@nginx.com 1163249Svbart@nginx.com nxt_queue_insert_head(&nxt_controller_waiting_requests, &req->link); 1164249Svbart@nginx.com 1165140Svbart@nginx.com return; 116651Svbart@nginx.com } 116751Svbart@nginx.com 11681049Svbart@nginx.com not_allowed: 11691049Svbart@nginx.com 1170208Svbart@nginx.com resp.status = 405; 11711049Svbart@nginx.com resp.title = (u_char *) "Method isn't allowed."; 1172208Svbart@nginx.com resp.offset = -1; 117351Svbart@nginx.com 1174208Svbart@nginx.com nxt_controller_response(task, req, &resp); 1175208Svbart@nginx.com return; 117651Svbart@nginx.com 1177208Svbart@nginx.com not_found: 1178208Svbart@nginx.com 1179208Svbart@nginx.com resp.status = 404; 1180208Svbart@nginx.com resp.title = (u_char *) "Value doesn't exist."; 1181208Svbart@nginx.com resp.offset = -1; 1182208Svbart@nginx.com 1183208Svbart@nginx.com nxt_controller_response(task, req, &resp); 1184208Svbart@nginx.com return; 1185208Svbart@nginx.com 1186208Svbart@nginx.com invalid_conf: 1187208Svbart@nginx.com 1188208Svbart@nginx.com resp.status = 400; 1189208Svbart@nginx.com resp.title = (u_char *) "Invalid configuration."; 1190208Svbart@nginx.com resp.offset = -1; 1191208Svbart@nginx.com 1192208Svbart@nginx.com nxt_controller_response(task, req, &resp); 1193208Svbart@nginx.com return; 1194247Svbart@nginx.com 1195247Svbart@nginx.com alloc_fail: 1196247Svbart@nginx.com 1197247Svbart@nginx.com resp.status = 500; 1198247Svbart@nginx.com resp.title = (u_char *) "Memory allocation failed."; 1199247Svbart@nginx.com resp.offset = -1; 1200247Svbart@nginx.com 1201247Svbart@nginx.com nxt_controller_response(task, req, &resp); 1202247Svbart@nginx.com return; 1203247Svbart@nginx.com 1204247Svbart@nginx.com no_router: 1205247Svbart@nginx.com 1206247Svbart@nginx.com resp.status = 500; 1207247Svbart@nginx.com resp.title = (u_char *) "Router process isn't available."; 1208247Svbart@nginx.com resp.offset = -1; 1209247Svbart@nginx.com 1210247Svbart@nginx.com nxt_controller_response(task, req, &resp); 1211247Svbart@nginx.com return; 121227Svbart@nginx.com } 121327Svbart@nginx.com 121427Svbart@nginx.com 1215774Svbart@nginx.com #if (NXT_TLS) 1216774Svbart@nginx.com 1217774Svbart@nginx.com static void 1218774Svbart@nginx.com nxt_controller_process_cert(nxt_task_t *task, 1219774Svbart@nginx.com nxt_controller_request_t *req, nxt_str_t *path) 1220774Svbart@nginx.com { 1221774Svbart@nginx.com u_char *p; 1222774Svbart@nginx.com nxt_str_t name; 1223774Svbart@nginx.com nxt_int_t ret; 1224774Svbart@nginx.com nxt_conn_t *c; 1225774Svbart@nginx.com nxt_cert_t *cert; 1226774Svbart@nginx.com nxt_conf_value_t *value; 1227774Svbart@nginx.com nxt_controller_response_t resp; 1228774Svbart@nginx.com 1229774Svbart@nginx.com name.length = path->length - 1; 1230774Svbart@nginx.com name.start = path->start + 1; 1231774Svbart@nginx.com 1232774Svbart@nginx.com p = nxt_memchr(name.start, '/', name.length); 1233774Svbart@nginx.com 1234774Svbart@nginx.com if (p != NULL) { 1235774Svbart@nginx.com name.length = p - name.start; 1236774Svbart@nginx.com 1237774Svbart@nginx.com path->length -= p - path->start; 1238774Svbart@nginx.com path->start = p; 1239774Svbart@nginx.com 1240774Svbart@nginx.com } else { 1241774Svbart@nginx.com path = NULL; 1242774Svbart@nginx.com } 1243774Svbart@nginx.com 1244774Svbart@nginx.com nxt_memzero(&resp, sizeof(nxt_controller_response_t)); 1245774Svbart@nginx.com 1246774Svbart@nginx.com c = req->conn; 1247774Svbart@nginx.com 1248774Svbart@nginx.com if (nxt_str_eq(&req->parser.method, "GET", 3)) { 1249774Svbart@nginx.com 1250774Svbart@nginx.com if (name.length != 0) { 1251774Svbart@nginx.com value = nxt_cert_info_get(&name); 1252774Svbart@nginx.com if (value == NULL) { 1253774Svbart@nginx.com goto cert_not_found; 1254774Svbart@nginx.com } 1255774Svbart@nginx.com 1256774Svbart@nginx.com if (path != NULL) { 1257774Svbart@nginx.com value = nxt_conf_get_path(value, path); 1258774Svbart@nginx.com if (value == NULL) { 1259774Svbart@nginx.com goto not_found; 1260774Svbart@nginx.com } 1261774Svbart@nginx.com } 1262774Svbart@nginx.com 1263774Svbart@nginx.com } else { 1264774Svbart@nginx.com value = nxt_cert_info_get_all(c->mem_pool); 1265774Svbart@nginx.com if (value == NULL) { 1266774Svbart@nginx.com goto alloc_fail; 1267774Svbart@nginx.com } 1268774Svbart@nginx.com } 1269774Svbart@nginx.com 1270774Svbart@nginx.com resp.status = 200; 1271774Svbart@nginx.com resp.conf = value; 1272774Svbart@nginx.com 1273774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1274774Svbart@nginx.com return; 1275774Svbart@nginx.com } 1276774Svbart@nginx.com 1277774Svbart@nginx.com if (name.length == 0 || path != NULL) { 1278774Svbart@nginx.com goto invalid_name; 1279774Svbart@nginx.com } 1280774Svbart@nginx.com 1281774Svbart@nginx.com if (nxt_str_eq(&req->parser.method, "PUT", 3)) { 1282774Svbart@nginx.com value = nxt_cert_info_get(&name); 1283774Svbart@nginx.com if (value != NULL) { 1284774Svbart@nginx.com goto exists_cert; 1285774Svbart@nginx.com } 1286774Svbart@nginx.com 1287774Svbart@nginx.com cert = nxt_cert_mem(task, &c->read->mem); 1288774Svbart@nginx.com if (cert == NULL) { 1289774Svbart@nginx.com goto invalid_cert; 1290774Svbart@nginx.com } 1291774Svbart@nginx.com 1292774Svbart@nginx.com ret = nxt_cert_info_save(&name, cert); 1293774Svbart@nginx.com 1294774Svbart@nginx.com nxt_cert_destroy(cert); 1295774Svbart@nginx.com 1296774Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 1297774Svbart@nginx.com goto alloc_fail; 1298774Svbart@nginx.com } 1299774Svbart@nginx.com 1300774Svbart@nginx.com nxt_cert_store_get(task, &name, c->mem_pool, 1301774Svbart@nginx.com nxt_controller_process_cert_save, req); 1302774Svbart@nginx.com return; 1303774Svbart@nginx.com } 1304774Svbart@nginx.com 1305774Svbart@nginx.com if (nxt_str_eq(&req->parser.method, "DELETE", 6)) { 1306774Svbart@nginx.com 1307774Svbart@nginx.com if (nxt_controller_cert_in_use(&name)) { 1308774Svbart@nginx.com goto cert_in_use; 1309774Svbart@nginx.com } 1310774Svbart@nginx.com 1311774Svbart@nginx.com if (nxt_cert_info_delete(&name) != NXT_OK) { 1312774Svbart@nginx.com goto cert_not_found; 1313774Svbart@nginx.com } 1314774Svbart@nginx.com 1315774Svbart@nginx.com nxt_cert_store_delete(task, &name, c->mem_pool); 1316774Svbart@nginx.com 1317774Svbart@nginx.com resp.status = 200; 1318774Svbart@nginx.com resp.title = (u_char *) "Certificate deleted."; 1319774Svbart@nginx.com 1320774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1321774Svbart@nginx.com return; 1322774Svbart@nginx.com } 1323774Svbart@nginx.com 1324774Svbart@nginx.com resp.status = 405; 1325774Svbart@nginx.com resp.title = (u_char *) "Invalid method."; 1326774Svbart@nginx.com resp.offset = -1; 1327774Svbart@nginx.com 1328774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1329774Svbart@nginx.com return; 1330774Svbart@nginx.com 1331774Svbart@nginx.com invalid_name: 1332774Svbart@nginx.com 1333774Svbart@nginx.com resp.status = 400; 1334774Svbart@nginx.com resp.title = (u_char *) "Invalid certificate name."; 1335774Svbart@nginx.com resp.offset = -1; 1336774Svbart@nginx.com 1337774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1338774Svbart@nginx.com return; 1339774Svbart@nginx.com 1340774Svbart@nginx.com invalid_cert: 1341774Svbart@nginx.com 1342774Svbart@nginx.com resp.status = 400; 1343774Svbart@nginx.com resp.title = (u_char *) "Invalid certificate."; 1344774Svbart@nginx.com resp.offset = -1; 1345774Svbart@nginx.com 1346774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1347774Svbart@nginx.com return; 1348774Svbart@nginx.com 1349774Svbart@nginx.com exists_cert: 1350774Svbart@nginx.com 1351774Svbart@nginx.com resp.status = 400; 1352774Svbart@nginx.com resp.title = (u_char *) "Certificate already exists."; 1353774Svbart@nginx.com resp.offset = -1; 1354774Svbart@nginx.com 1355774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1356774Svbart@nginx.com return; 1357774Svbart@nginx.com 1358774Svbart@nginx.com cert_in_use: 1359774Svbart@nginx.com 1360774Svbart@nginx.com resp.status = 400; 1361774Svbart@nginx.com resp.title = (u_char *) "Certificate is used in the configuration."; 1362774Svbart@nginx.com resp.offset = -1; 1363774Svbart@nginx.com 1364774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1365774Svbart@nginx.com return; 1366774Svbart@nginx.com 1367774Svbart@nginx.com cert_not_found: 1368774Svbart@nginx.com 1369774Svbart@nginx.com resp.status = 404; 1370774Svbart@nginx.com resp.title = (u_char *) "Certificate doesn't exist."; 1371774Svbart@nginx.com resp.offset = -1; 1372774Svbart@nginx.com 1373774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1374774Svbart@nginx.com return; 1375774Svbart@nginx.com 1376774Svbart@nginx.com not_found: 1377774Svbart@nginx.com 1378774Svbart@nginx.com resp.status = 404; 1379774Svbart@nginx.com resp.title = (u_char *) "Invalid path."; 1380774Svbart@nginx.com resp.offset = -1; 1381774Svbart@nginx.com 1382774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1383774Svbart@nginx.com return; 1384774Svbart@nginx.com 1385774Svbart@nginx.com alloc_fail: 1386774Svbart@nginx.com 1387774Svbart@nginx.com resp.status = 500; 1388774Svbart@nginx.com resp.title = (u_char *) "Memory allocation failed."; 1389774Svbart@nginx.com resp.offset = -1; 1390774Svbart@nginx.com 1391774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1392774Svbart@nginx.com return; 1393774Svbart@nginx.com } 1394774Svbart@nginx.com 1395774Svbart@nginx.com 1396774Svbart@nginx.com static void 1397774Svbart@nginx.com nxt_controller_process_cert_save(nxt_task_t *task, nxt_port_recv_msg_t *msg, 1398774Svbart@nginx.com void *data) 1399774Svbart@nginx.com { 1400774Svbart@nginx.com nxt_conn_t *c; 1401774Svbart@nginx.com nxt_buf_mem_t *mbuf; 1402774Svbart@nginx.com nxt_controller_request_t *req; 1403774Svbart@nginx.com nxt_controller_response_t resp; 1404774Svbart@nginx.com 1405774Svbart@nginx.com req = data; 1406774Svbart@nginx.com 1407774Svbart@nginx.com nxt_memzero(&resp, sizeof(nxt_controller_response_t)); 1408774Svbart@nginx.com 1409774Svbart@nginx.com if (msg == NULL || msg->port_msg.type == _NXT_PORT_MSG_RPC_ERROR) { 1410774Svbart@nginx.com resp.status = 500; 1411774Svbart@nginx.com resp.title = (u_char *) "Failed to store certificate."; 1412774Svbart@nginx.com 1413774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1414774Svbart@nginx.com return; 1415774Svbart@nginx.com } 1416774Svbart@nginx.com 1417774Svbart@nginx.com c = req->conn; 1418774Svbart@nginx.com 1419774Svbart@nginx.com mbuf = &c->read->mem; 1420774Svbart@nginx.com 1421774Svbart@nginx.com nxt_fd_write(msg->fd, mbuf->pos, nxt_buf_mem_used_size(mbuf)); 1422774Svbart@nginx.com 1423774Svbart@nginx.com nxt_fd_close(msg->fd); 1424774Svbart@nginx.com 1425774Svbart@nginx.com nxt_memzero(&resp, sizeof(nxt_controller_response_t)); 1426774Svbart@nginx.com 1427774Svbart@nginx.com resp.status = 200; 1428774Svbart@nginx.com resp.title = (u_char *) "Certificate chain uploaded."; 1429774Svbart@nginx.com 1430774Svbart@nginx.com nxt_controller_response(task, req, &resp); 1431774Svbart@nginx.com } 1432774Svbart@nginx.com 1433774Svbart@nginx.com 1434774Svbart@nginx.com static nxt_bool_t 1435774Svbart@nginx.com nxt_controller_cert_in_use(nxt_str_t *name) 1436774Svbart@nginx.com { 1437774Svbart@nginx.com uint32_t next; 1438774Svbart@nginx.com nxt_str_t str; 1439774Svbart@nginx.com nxt_conf_value_t *listeners, *listener, *value; 1440774Svbart@nginx.com 1441774Svbart@nginx.com static nxt_str_t listeners_path = nxt_string("/listeners"); 1442774Svbart@nginx.com static nxt_str_t certificate_path = nxt_string("/tls/certificate"); 1443774Svbart@nginx.com 1444774Svbart@nginx.com listeners = nxt_conf_get_path(nxt_controller_conf.root, &listeners_path); 1445774Svbart@nginx.com 1446774Svbart@nginx.com if (listeners != NULL) { 1447774Svbart@nginx.com next = 0; 1448774Svbart@nginx.com 1449774Svbart@nginx.com for ( ;; ) { 1450774Svbart@nginx.com listener = nxt_conf_next_object_member(listeners, &str, &next); 1451774Svbart@nginx.com if (listener == NULL) { 1452774Svbart@nginx.com break; 1453774Svbart@nginx.com } 1454774Svbart@nginx.com 1455774Svbart@nginx.com value = nxt_conf_get_path(listener, &certificate_path); 1456774Svbart@nginx.com if (value == NULL) { 1457774Svbart@nginx.com continue; 1458774Svbart@nginx.com } 1459774Svbart@nginx.com 1460774Svbart@nginx.com nxt_conf_get_string(value, &str); 1461774Svbart@nginx.com 1462774Svbart@nginx.com if (nxt_strstr_eq(&str, name)) { 1463774Svbart@nginx.com return 1; 1464774Svbart@nginx.com } 1465774Svbart@nginx.com } 1466774Svbart@nginx.com } 1467774Svbart@nginx.com 1468774Svbart@nginx.com return 0; 1469774Svbart@nginx.com } 1470774Svbart@nginx.com 1471774Svbart@nginx.com #endif 1472774Svbart@nginx.com 1473774Svbart@nginx.com 1474193Smax.romanov@nginx.com static void 1475193Smax.romanov@nginx.com nxt_controller_conf_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 1476193Smax.romanov@nginx.com void *data) 1477140Svbart@nginx.com { 1478238Svbart@nginx.com nxt_queue_t queue; 1479140Svbart@nginx.com nxt_controller_request_t *req; 1480140Svbart@nginx.com nxt_controller_response_t resp; 1481140Svbart@nginx.com 1482238Svbart@nginx.com req = data; 1483238Svbart@nginx.com 1484201Svbart@nginx.com nxt_debug(task, "controller conf ready: %*s", 1485201Svbart@nginx.com nxt_buf_mem_used_size(&msg->buf->mem), msg->buf->mem.pos); 1486140Svbart@nginx.com 1487238Svbart@nginx.com nxt_queue_remove(&req->link); 1488140Svbart@nginx.com 1489238Svbart@nginx.com nxt_memzero(&resp, sizeof(nxt_controller_response_t)); 1490140Svbart@nginx.com 1491193Smax.romanov@nginx.com if (msg->port_msg.type == NXT_PORT_MSG_RPC_READY) { 1492140Svbart@nginx.com nxt_mp_destroy(nxt_controller_conf.pool); 1493140Svbart@nginx.com 1494140Svbart@nginx.com nxt_controller_conf = req->conf; 1495140Svbart@nginx.com 1496314Svbart@nginx.com nxt_controller_conf_store(task, req->conf.root); 1497314Svbart@nginx.com 1498208Svbart@nginx.com resp.status = 200; 1499208Svbart@nginx.com resp.title = (u_char *) "Reconfiguration done."; 1500140Svbart@nginx.com 1501140Svbart@nginx.com } else { 1502140Svbart@nginx.com nxt_mp_destroy(req->conf.pool); 1503140Svbart@nginx.com 1504208Svbart@nginx.com resp.status = 500; 1505208Svbart@nginx.com resp.title = (u_char *) "Failed to apply new configuration."; 1506208Svbart@nginx.com resp.offset = -1; 1507140Svbart@nginx.com } 1508140Svbart@nginx.com 1509140Svbart@nginx.com nxt_controller_response(task, req, &resp); 1510140Svbart@nginx.com 1511238Svbart@nginx.com nxt_queue_init(&queue); 1512238Svbart@nginx.com nxt_queue_add(&queue, &nxt_controller_waiting_requests); 1513140Svbart@nginx.com 1514238Svbart@nginx.com nxt_queue_init(&nxt_controller_waiting_requests); 1515121Svbart@nginx.com 1516238Svbart@nginx.com nxt_queue_each(req, &queue, nxt_controller_request_t, link) { 1517238Svbart@nginx.com nxt_controller_process_request(task, req); 1518238Svbart@nginx.com } nxt_queue_loop; 1519121Svbart@nginx.com } 1520121Svbart@nginx.com 1521121Svbart@nginx.com 1522140Svbart@nginx.com static void 1523314Svbart@nginx.com nxt_controller_conf_store(nxt_task_t *task, nxt_conf_value_t *conf) 1524314Svbart@nginx.com { 1525314Svbart@nginx.com size_t size; 1526314Svbart@nginx.com nxt_buf_t *b; 1527314Svbart@nginx.com nxt_port_t *main_port; 1528314Svbart@nginx.com nxt_runtime_t *rt; 1529314Svbart@nginx.com 1530314Svbart@nginx.com rt = task->thread->runtime; 1531314Svbart@nginx.com 1532314Svbart@nginx.com main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 1533314Svbart@nginx.com 1534314Svbart@nginx.com size = nxt_conf_json_length(conf, NULL); 1535314Svbart@nginx.com 1536342Smax.romanov@nginx.com b = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool, size); 1537314Svbart@nginx.com 1538314Svbart@nginx.com if (nxt_fast_path(b != NULL)) { 1539314Svbart@nginx.com b->mem.free = nxt_conf_json_print(b->mem.free, conf, NULL); 1540314Svbart@nginx.com 1541314Svbart@nginx.com (void) nxt_port_socket_write(task, main_port, NXT_PORT_MSG_CONF_STORE, 1542314Svbart@nginx.com -1, 0, -1, b); 1543314Svbart@nginx.com } 1544314Svbart@nginx.com } 1545314Svbart@nginx.com 1546314Svbart@nginx.com 1547314Svbart@nginx.com static void 1548140Svbart@nginx.com nxt_controller_response(nxt_task_t *task, nxt_controller_request_t *req, 154944Svbart@nginx.com nxt_controller_response_t *resp) 155033Svbart@nginx.com { 1551208Svbart@nginx.com size_t size; 1552208Svbart@nginx.com nxt_str_t status_line, str; 1553208Svbart@nginx.com nxt_buf_t *b, *body; 1554208Svbart@nginx.com nxt_conn_t *c; 1555208Svbart@nginx.com nxt_uint_t n; 1556208Svbart@nginx.com nxt_conf_value_t *value, *location; 1557208Svbart@nginx.com nxt_conf_json_pretty_t pretty; 1558208Svbart@nginx.com 1559208Svbart@nginx.com static nxt_str_t success_str = nxt_string("success"); 1560208Svbart@nginx.com static nxt_str_t error_str = nxt_string("error"); 1561208Svbart@nginx.com static nxt_str_t detail_str = nxt_string("detail"); 1562208Svbart@nginx.com static nxt_str_t location_str = nxt_string("location"); 1563208Svbart@nginx.com static nxt_str_t offset_str = nxt_string("offset"); 1564208Svbart@nginx.com static nxt_str_t line_str = nxt_string("line"); 1565208Svbart@nginx.com static nxt_str_t column_str = nxt_string("column"); 1566208Svbart@nginx.com 1567208Svbart@nginx.com static nxt_time_string_t date_cache = { 1568208Svbart@nginx.com (nxt_atomic_uint_t) -1, 1569208Svbart@nginx.com nxt_controller_date, 1570208Svbart@nginx.com "%s, %02d %s %4d %02d:%02d:%02d GMT", 1571703Svbart@nginx.com nxt_length("Wed, 31 Dec 1986 16:40:00 GMT"), 1572208Svbart@nginx.com NXT_THREAD_TIME_GMT, 1573208Svbart@nginx.com NXT_THREAD_TIME_SEC, 1574208Svbart@nginx.com }; 1575208Svbart@nginx.com 1576208Svbart@nginx.com switch (resp->status) { 1577208Svbart@nginx.com 1578208Svbart@nginx.com case 200: 1579208Svbart@nginx.com nxt_str_set(&status_line, "200 OK"); 1580208Svbart@nginx.com break; 1581208Svbart@nginx.com 1582208Svbart@nginx.com case 400: 1583208Svbart@nginx.com nxt_str_set(&status_line, "400 Bad Request"); 1584208Svbart@nginx.com break; 1585208Svbart@nginx.com 1586208Svbart@nginx.com case 404: 1587208Svbart@nginx.com nxt_str_set(&status_line, "404 Not Found"); 1588208Svbart@nginx.com break; 1589208Svbart@nginx.com 1590208Svbart@nginx.com case 405: 1591208Svbart@nginx.com nxt_str_set(&status_line, "405 Method Not Allowed"); 1592208Svbart@nginx.com break; 1593208Svbart@nginx.com 1594209Svbart@nginx.com default: 1595208Svbart@nginx.com nxt_str_set(&status_line, "500 Internal Server Error"); 1596208Svbart@nginx.com break; 1597208Svbart@nginx.com } 1598140Svbart@nginx.com 1599140Svbart@nginx.com c = req->conn; 1600208Svbart@nginx.com value = resp->conf; 160133Svbart@nginx.com 1602208Svbart@nginx.com if (value == NULL) { 1603208Svbart@nginx.com n = 1 1604357Svbart@nginx.com + (resp->detail.length != 0) 1605208Svbart@nginx.com + (resp->status >= 400 && resp->offset != -1); 1606208Svbart@nginx.com 1607208Svbart@nginx.com value = nxt_conf_create_object(c->mem_pool, n); 1608208Svbart@nginx.com 1609208Svbart@nginx.com if (nxt_slow_path(value == NULL)) { 1610208Svbart@nginx.com nxt_controller_conn_close(task, c, req); 1611208Svbart@nginx.com return; 1612208Svbart@nginx.com } 1613208Svbart@nginx.com 1614208Svbart@nginx.com str.length = nxt_strlen(resp->title); 1615208Svbart@nginx.com str.start = resp->title; 1616208Svbart@nginx.com 1617208Svbart@nginx.com if (resp->status < 400) { 1618208Svbart@nginx.com nxt_conf_set_member_string(value, &success_str, &str, 0); 1619208Svbart@nginx.com 1620208Svbart@nginx.com } else { 1621208Svbart@nginx.com nxt_conf_set_member_string(value, &error_str, &str, 0); 1622208Svbart@nginx.com } 1623208Svbart@nginx.com 1624208Svbart@nginx.com n = 0; 1625208Svbart@nginx.com 1626357Svbart@nginx.com if (resp->detail.length != 0) { 1627208Svbart@nginx.com n++; 1628208Svbart@nginx.com 1629357Svbart@nginx.com nxt_conf_set_member_string(value, &detail_str, &resp->detail, n); 1630208Svbart@nginx.com } 1631208Svbart@nginx.com 1632208Svbart@nginx.com if (resp->status >= 400 && resp->offset != -1) { 1633208Svbart@nginx.com n++; 1634208Svbart@nginx.com 1635208Svbart@nginx.com location = nxt_conf_create_object(c->mem_pool, 1636208Svbart@nginx.com resp->line != 0 ? 3 : 1); 1637208Svbart@nginx.com 1638208Svbart@nginx.com nxt_conf_set_member(value, &location_str, location, n); 1639208Svbart@nginx.com 1640208Svbart@nginx.com nxt_conf_set_member_integer(location, &offset_str, resp->offset, 0); 1641208Svbart@nginx.com 1642208Svbart@nginx.com if (resp->line != 0) { 1643208Svbart@nginx.com nxt_conf_set_member_integer(location, &line_str, 1644208Svbart@nginx.com resp->line, 1); 1645208Svbart@nginx.com 1646208Svbart@nginx.com nxt_conf_set_member_integer(location, &column_str, 1647208Svbart@nginx.com resp->column, 2); 1648208Svbart@nginx.com } 1649208Svbart@nginx.com } 1650208Svbart@nginx.com } 1651208Svbart@nginx.com 1652208Svbart@nginx.com nxt_memzero(&pretty, sizeof(nxt_conf_json_pretty_t)); 1653208Svbart@nginx.com 1654208Svbart@nginx.com size = nxt_conf_json_length(value, &pretty) + 2; 1655208Svbart@nginx.com 1656208Svbart@nginx.com body = nxt_buf_mem_alloc(c->mem_pool, size, 0); 1657208Svbart@nginx.com if (nxt_slow_path(body == NULL)) { 1658208Svbart@nginx.com nxt_controller_conn_close(task, c, req); 1659208Svbart@nginx.com return; 1660208Svbart@nginx.com } 1661208Svbart@nginx.com 1662208Svbart@nginx.com nxt_memzero(&pretty, sizeof(nxt_conf_json_pretty_t)); 1663208Svbart@nginx.com 1664208Svbart@nginx.com body->mem.free = nxt_conf_json_print(body->mem.free, value, &pretty); 1665208Svbart@nginx.com 1666208Svbart@nginx.com body->mem.free = nxt_cpymem(body->mem.free, "\r\n", 2); 1667208Svbart@nginx.com 1668703Svbart@nginx.com size = nxt_length("HTTP/1.1 " "\r\n") + status_line.length 1669703Svbart@nginx.com + nxt_length("Server: " NXT_SERVER "\r\n") 1670703Svbart@nginx.com + nxt_length("Date: Wed, 31 Dec 1986 16:40:00 GMT\r\n") 1671703Svbart@nginx.com + nxt_length("Content-Type: application/json\r\n") 1672703Svbart@nginx.com + nxt_length("Content-Length: " "\r\n") + NXT_SIZE_T_LEN 1673703Svbart@nginx.com + nxt_length("Connection: close\r\n") 1674703Svbart@nginx.com + nxt_length("\r\n"); 167533Svbart@nginx.com 167644Svbart@nginx.com b = nxt_buf_mem_alloc(c->mem_pool, size, 0); 167733Svbart@nginx.com if (nxt_slow_path(b == NULL)) { 1678140Svbart@nginx.com nxt_controller_conn_close(task, c, req); 1679140Svbart@nginx.com return; 168033Svbart@nginx.com } 168133Svbart@nginx.com 1682208Svbart@nginx.com b->next = body; 1683208Svbart@nginx.com 1684208Svbart@nginx.com nxt_str_set(&str, "HTTP/1.1 "); 168544Svbart@nginx.com 1686208Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length); 1687208Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, status_line.start, 1688208Svbart@nginx.com status_line.length); 1689208Svbart@nginx.com 1690208Svbart@nginx.com nxt_str_set(&str, "\r\n" 1691673Svbart@nginx.com "Server: " NXT_SERVER "\r\n" 1692208Svbart@nginx.com "Date: "); 1693208Svbart@nginx.com 1694208Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length); 169544Svbart@nginx.com 1696208Svbart@nginx.com b->mem.free = nxt_thread_time_string(task->thread, &date_cache, 1697208Svbart@nginx.com b->mem.free); 1698208Svbart@nginx.com 1699208Svbart@nginx.com nxt_str_set(&str, "\r\n" 1700208Svbart@nginx.com "Content-Type: application/json\r\n" 1701208Svbart@nginx.com "Content-Length: "); 1702208Svbart@nginx.com 1703208Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length); 170445Svbart@nginx.com 1705208Svbart@nginx.com b->mem.free = nxt_sprintf(b->mem.free, b->mem.end, "%uz", 1706208Svbart@nginx.com nxt_buf_mem_used_size(&body->mem)); 1707208Svbart@nginx.com 1708208Svbart@nginx.com nxt_str_set(&str, "\r\n" 1709208Svbart@nginx.com "Connection: close\r\n" 1710208Svbart@nginx.com "\r\n"); 1711208Svbart@nginx.com 1712208Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length); 171333Svbart@nginx.com 171433Svbart@nginx.com c->write = b; 171544Svbart@nginx.com c->write_state = &nxt_controller_conn_write_state; 171633Svbart@nginx.com 171762Sigor@sysoev.ru nxt_conn_write(task->thread->engine, c); 171833Svbart@nginx.com } 171945Svbart@nginx.com 172045Svbart@nginx.com 1721208Svbart@nginx.com static u_char * 1722208Svbart@nginx.com nxt_controller_date(u_char *buf, nxt_realtime_t *now, struct tm *tm, 1723208Svbart@nginx.com size_t size, const char *format) 172445Svbart@nginx.com { 1725208Svbart@nginx.com static const char *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", 1726208Svbart@nginx.com "Sat" }; 172745Svbart@nginx.com 1728208Svbart@nginx.com static const char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", 1729208Svbart@nginx.com "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; 173045Svbart@nginx.com 1731208Svbart@nginx.com return nxt_sprintf(buf, buf + size, format, 1732208Svbart@nginx.com week[tm->tm_wday], tm->tm_mday, 1733208Svbart@nginx.com month[tm->tm_mon], tm->tm_year + 1900, 1734208Svbart@nginx.com tm->tm_hour, tm->tm_min, tm->tm_sec); 173545Svbart@nginx.com } 1736