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> 1020Sigor@sysoev.ru #include <nxt_master_process.h> 1129Svbart@nginx.com #include <nxt_conf.h> 1220Sigor@sysoev.ru 1320Sigor@sysoev.ru 1427Svbart@nginx.com typedef struct { 1544Svbart@nginx.com nxt_conf_json_value_t *root; 1665Sigor@sysoev.ru nxt_mp_t *pool; 1744Svbart@nginx.com } nxt_controller_conf_t; 1844Svbart@nginx.com 1944Svbart@nginx.com 2044Svbart@nginx.com typedef struct { 2127Svbart@nginx.com nxt_http_request_parse_t parser; 2227Svbart@nginx.com size_t length; 2333Svbart@nginx.com 2444Svbart@nginx.com nxt_controller_conf_t conf; 2527Svbart@nginx.com } nxt_controller_request_t; 2627Svbart@nginx.com 2727Svbart@nginx.com 2844Svbart@nginx.com typedef struct { 2944Svbart@nginx.com nxt_str_t status_line; 3044Svbart@nginx.com nxt_conf_json_value_t *json_value; 3144Svbart@nginx.com nxt_str_t json_string; 3244Svbart@nginx.com } nxt_controller_response_t; 3344Svbart@nginx.com 3444Svbart@nginx.com 3520Sigor@sysoev.ru static void nxt_controller_conn_init(nxt_task_t *task, void *obj, void *data); 3620Sigor@sysoev.ru static void nxt_controller_conn_read(nxt_task_t *task, void *obj, void *data); 3762Sigor@sysoev.ru static nxt_msec_t nxt_controller_conn_timeout_value(nxt_conn_t *c, 3820Sigor@sysoev.ru uintptr_t data); 3920Sigor@sysoev.ru static void nxt_controller_conn_read_error(nxt_task_t *task, void *obj, 4020Sigor@sysoev.ru void *data); 4120Sigor@sysoev.ru static void nxt_controller_conn_read_timeout(nxt_task_t *task, void *obj, 4220Sigor@sysoev.ru void *data); 4327Svbart@nginx.com static void nxt_controller_conn_body_read(nxt_task_t *task, void *obj, 4427Svbart@nginx.com void *data); 4527Svbart@nginx.com static void nxt_controller_conn_write(nxt_task_t *task, void *obj, void *data); 4627Svbart@nginx.com static void nxt_controller_conn_write_error(nxt_task_t *task, void *obj, 4727Svbart@nginx.com void *data); 4827Svbart@nginx.com static void nxt_controller_conn_write_timeout(nxt_task_t *task, void *obj, 4927Svbart@nginx.com void *data); 5020Sigor@sysoev.ru static void nxt_controller_conn_close(nxt_task_t *task, void *obj, void *data); 5120Sigor@sysoev.ru static void nxt_controller_conn_free(nxt_task_t *task, void *obj, void *data); 5220Sigor@sysoev.ru 5327Svbart@nginx.com static nxt_int_t nxt_controller_request_content_length(void *ctx, 5467Svbart@nginx.com nxt_http_field_t *field, nxt_log_t *log); 5527Svbart@nginx.com 5627Svbart@nginx.com static void nxt_controller_process_request(nxt_task_t *task, 5762Sigor@sysoev.ru nxt_conn_t *c, nxt_controller_request_t *r); 5862Sigor@sysoev.ru static nxt_int_t nxt_controller_response(nxt_task_t *task, nxt_conn_t *c, 5944Svbart@nginx.com nxt_controller_response_t *resp); 6045Svbart@nginx.com static nxt_buf_t *nxt_controller_response_body(nxt_controller_response_t *resp, 6165Sigor@sysoev.ru nxt_mp_t *pool); 6227Svbart@nginx.com 6327Svbart@nginx.com 6460Svbart@nginx.com static nxt_http_fields_hash_entry_t nxt_controller_request_fields[] = { 6527Svbart@nginx.com { nxt_string("Content-Length"), 6627Svbart@nginx.com &nxt_controller_request_content_length, 0 }, 6727Svbart@nginx.com 6827Svbart@nginx.com { nxt_null_string, NULL, 0 } 6927Svbart@nginx.com }; 7027Svbart@nginx.com 7160Svbart@nginx.com static nxt_http_fields_hash_t *nxt_controller_fields_hash; 7227Svbart@nginx.com 7344Svbart@nginx.com 7444Svbart@nginx.com static nxt_controller_conf_t nxt_controller_conf; 7527Svbart@nginx.com 7620Sigor@sysoev.ru 7720Sigor@sysoev.ru static const nxt_event_conn_state_t nxt_controller_conn_read_state; 7827Svbart@nginx.com static const nxt_event_conn_state_t nxt_controller_conn_body_read_state; 7927Svbart@nginx.com static const nxt_event_conn_state_t nxt_controller_conn_write_state; 8020Sigor@sysoev.ru static const nxt_event_conn_state_t nxt_controller_conn_close_state; 8120Sigor@sysoev.ru 8220Sigor@sysoev.ru 8320Sigor@sysoev.ru nxt_int_t 8420Sigor@sysoev.ru nxt_controller_start(nxt_task_t *task, nxt_runtime_t *rt) 8520Sigor@sysoev.ru { 8665Sigor@sysoev.ru nxt_mp_t *mp; 8744Svbart@nginx.com nxt_conf_json_value_t *conf; 8827Svbart@nginx.com nxt_http_fields_hash_t *hash; 8927Svbart@nginx.com 9044Svbart@nginx.com static const nxt_str_t json 9144Svbart@nginx.com = nxt_string("{ \"sockets\": {}, \"applications\": {} }"); 9244Svbart@nginx.com 9360Svbart@nginx.com hash = nxt_http_fields_hash_create(nxt_controller_request_fields, 9460Svbart@nginx.com rt->mem_pool); 9527Svbart@nginx.com if (nxt_slow_path(hash == NULL)) { 9627Svbart@nginx.com return NXT_ERROR; 9727Svbart@nginx.com } 9827Svbart@nginx.com 9960Svbart@nginx.com nxt_controller_fields_hash = hash; 10027Svbart@nginx.com 10154Sigor@sysoev.ru if (nxt_listen_event(task, rt->controller_socket) == NULL) { 10220Sigor@sysoev.ru return NXT_ERROR; 10320Sigor@sysoev.ru } 10420Sigor@sysoev.ru 10565Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 10644Svbart@nginx.com 10744Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 10844Svbart@nginx.com return NXT_ERROR; 10944Svbart@nginx.com } 11044Svbart@nginx.com 11191Svbart@nginx.com conf = nxt_conf_json_str_parse(mp, &json); 11244Svbart@nginx.com 11344Svbart@nginx.com if (conf == NULL) { 11444Svbart@nginx.com return NXT_ERROR; 11544Svbart@nginx.com } 11644Svbart@nginx.com 11744Svbart@nginx.com nxt_controller_conf.root = conf; 11844Svbart@nginx.com nxt_controller_conf.pool = mp; 11944Svbart@nginx.com 12020Sigor@sysoev.ru return NXT_OK; 12120Sigor@sysoev.ru } 12220Sigor@sysoev.ru 12320Sigor@sysoev.ru 12420Sigor@sysoev.ru nxt_int_t 12520Sigor@sysoev.ru nxt_runtime_controller_socket(nxt_task_t *task, nxt_runtime_t *rt) 12620Sigor@sysoev.ru { 12720Sigor@sysoev.ru nxt_sockaddr_t *sa; 12820Sigor@sysoev.ru nxt_listen_socket_t *ls; 12920Sigor@sysoev.ru 13020Sigor@sysoev.ru sa = rt->controller_listen; 13120Sigor@sysoev.ru 13220Sigor@sysoev.ru if (rt->controller_listen == NULL) { 13320Sigor@sysoev.ru sa = nxt_sockaddr_alloc(rt->mem_pool, sizeof(struct sockaddr_in), 13420Sigor@sysoev.ru NXT_INET_ADDR_STR_LEN); 13520Sigor@sysoev.ru if (sa == NULL) { 13620Sigor@sysoev.ru return NXT_ERROR; 13720Sigor@sysoev.ru } 13820Sigor@sysoev.ru 13920Sigor@sysoev.ru sa->type = SOCK_STREAM; 14020Sigor@sysoev.ru sa->u.sockaddr_in.sin_family = AF_INET; 14120Sigor@sysoev.ru sa->u.sockaddr_in.sin_port = htons(8443); 14220Sigor@sysoev.ru 14320Sigor@sysoev.ru nxt_sockaddr_text(sa); 14420Sigor@sysoev.ru 14520Sigor@sysoev.ru rt->controller_listen = sa; 14620Sigor@sysoev.ru } 14720Sigor@sysoev.ru 14865Sigor@sysoev.ru ls = nxt_mp_alloc(rt->mem_pool, sizeof(nxt_listen_socket_t)); 14920Sigor@sysoev.ru if (ls == NULL) { 15020Sigor@sysoev.ru return NXT_ERROR; 15120Sigor@sysoev.ru } 15220Sigor@sysoev.ru 15320Sigor@sysoev.ru ls->sockaddr = nxt_sockaddr_create(rt->mem_pool, &sa->u.sockaddr, 15420Sigor@sysoev.ru sa->socklen, sa->length); 15520Sigor@sysoev.ru if (ls->sockaddr == NULL) { 15620Sigor@sysoev.ru return NXT_ERROR; 15720Sigor@sysoev.ru } 15820Sigor@sysoev.ru 15920Sigor@sysoev.ru ls->sockaddr->type = sa->type; 160*103Sigor@sysoev.ru ls->socklen = sa->socklen; 161*103Sigor@sysoev.ru ls->address_length = sa->length; 16220Sigor@sysoev.ru 16320Sigor@sysoev.ru nxt_sockaddr_text(ls->sockaddr); 16420Sigor@sysoev.ru 16520Sigor@sysoev.ru ls->socket = -1; 16620Sigor@sysoev.ru ls->backlog = NXT_LISTEN_BACKLOG; 16720Sigor@sysoev.ru ls->read_after_accept = 1; 16820Sigor@sysoev.ru ls->flags = NXT_NONBLOCK; 16920Sigor@sysoev.ru 17020Sigor@sysoev.ru #if 0 17120Sigor@sysoev.ru /* STUB */ 17265Sigor@sysoev.ru wq = nxt_mp_zget(cf->mem_pool, sizeof(nxt_work_queue_t)); 17320Sigor@sysoev.ru if (wq == NULL) { 17420Sigor@sysoev.ru return NXT_ERROR; 17520Sigor@sysoev.ru } 17620Sigor@sysoev.ru nxt_work_queue_name(wq, "listen"); 17720Sigor@sysoev.ru /**/ 17820Sigor@sysoev.ru 17920Sigor@sysoev.ru ls->work_queue = wq; 18020Sigor@sysoev.ru #endif 18120Sigor@sysoev.ru ls->handler = nxt_controller_conn_init; 18220Sigor@sysoev.ru 18320Sigor@sysoev.ru if (nxt_listen_socket_create(task, ls, 0) != NXT_OK) { 18420Sigor@sysoev.ru return NXT_ERROR; 18520Sigor@sysoev.ru } 18620Sigor@sysoev.ru 18720Sigor@sysoev.ru rt->controller_socket = ls; 18820Sigor@sysoev.ru 18920Sigor@sysoev.ru return NXT_OK; 19020Sigor@sysoev.ru } 19120Sigor@sysoev.ru 19220Sigor@sysoev.ru 19320Sigor@sysoev.ru static void 19420Sigor@sysoev.ru nxt_controller_conn_init(nxt_task_t *task, void *obj, void *data) 19520Sigor@sysoev.ru { 19627Svbart@nginx.com nxt_buf_t *b; 19762Sigor@sysoev.ru nxt_conn_t *c; 19827Svbart@nginx.com nxt_event_engine_t *engine; 19927Svbart@nginx.com nxt_controller_request_t *r; 20020Sigor@sysoev.ru 20120Sigor@sysoev.ru c = obj; 20220Sigor@sysoev.ru 20320Sigor@sysoev.ru nxt_debug(task, "controller conn init fd:%d", c->socket.fd); 20420Sigor@sysoev.ru 20565Sigor@sysoev.ru r = nxt_mp_zget(c->mem_pool, sizeof(nxt_controller_request_t)); 20627Svbart@nginx.com if (nxt_slow_path(r == NULL)) { 20727Svbart@nginx.com nxt_controller_conn_free(task, c, NULL); 20827Svbart@nginx.com return; 20927Svbart@nginx.com } 21027Svbart@nginx.com 21160Svbart@nginx.com if (nxt_slow_path(nxt_http_parse_request_init(&r->parser, c->mem_pool) 21260Svbart@nginx.com != NXT_OK)) 21360Svbart@nginx.com { 21460Svbart@nginx.com nxt_controller_conn_free(task, c, NULL); 21560Svbart@nginx.com return; 21660Svbart@nginx.com } 21727Svbart@nginx.com 21867Svbart@nginx.com r->parser.fields_hash = nxt_controller_fields_hash; 21967Svbart@nginx.com 22020Sigor@sysoev.ru b = nxt_buf_mem_alloc(c->mem_pool, 1024, 0); 22120Sigor@sysoev.ru if (nxt_slow_path(b == NULL)) { 22220Sigor@sysoev.ru nxt_controller_conn_free(task, c, NULL); 22320Sigor@sysoev.ru return; 22420Sigor@sysoev.ru } 22520Sigor@sysoev.ru 22620Sigor@sysoev.ru c->read = b; 22727Svbart@nginx.com c->socket.data = r; 22820Sigor@sysoev.ru c->socket.read_ready = 1; 22920Sigor@sysoev.ru c->read_state = &nxt_controller_conn_read_state; 23020Sigor@sysoev.ru 23120Sigor@sysoev.ru engine = task->thread->engine; 23220Sigor@sysoev.ru c->read_work_queue = &engine->read_work_queue; 23327Svbart@nginx.com c->write_work_queue = &engine->write_work_queue; 23420Sigor@sysoev.ru 23562Sigor@sysoev.ru nxt_conn_read(engine, c); 23620Sigor@sysoev.ru } 23720Sigor@sysoev.ru 23820Sigor@sysoev.ru 23920Sigor@sysoev.ru static const nxt_event_conn_state_t nxt_controller_conn_read_state 24020Sigor@sysoev.ru nxt_aligned(64) = 24120Sigor@sysoev.ru { 24256Sigor@sysoev.ru .ready_handler = nxt_controller_conn_read, 24356Sigor@sysoev.ru .close_handler = nxt_controller_conn_close, 24456Sigor@sysoev.ru .error_handler = nxt_controller_conn_read_error, 24520Sigor@sysoev.ru 24656Sigor@sysoev.ru .timer_handler = nxt_controller_conn_read_timeout, 24756Sigor@sysoev.ru .timer_value = nxt_controller_conn_timeout_value, 24856Sigor@sysoev.ru .timer_data = 60 * 1000, 24920Sigor@sysoev.ru }; 25020Sigor@sysoev.ru 25120Sigor@sysoev.ru 25220Sigor@sysoev.ru static void 25320Sigor@sysoev.ru nxt_controller_conn_read(nxt_task_t *task, void *obj, void *data) 25420Sigor@sysoev.ru { 25527Svbart@nginx.com size_t preread; 25627Svbart@nginx.com nxt_buf_t *b; 25727Svbart@nginx.com nxt_int_t rc; 25862Sigor@sysoev.ru nxt_conn_t *c; 25927Svbart@nginx.com nxt_controller_request_t *r; 26020Sigor@sysoev.ru 26120Sigor@sysoev.ru c = obj; 26227Svbart@nginx.com r = data; 26320Sigor@sysoev.ru 26420Sigor@sysoev.ru nxt_debug(task, "controller conn read"); 26520Sigor@sysoev.ru 26627Svbart@nginx.com nxt_queue_remove(&c->link); 26727Svbart@nginx.com nxt_queue_self(&c->link); 26827Svbart@nginx.com 26927Svbart@nginx.com b = c->read; 27027Svbart@nginx.com 27127Svbart@nginx.com rc = nxt_http_parse_request(&r->parser, &b->mem); 27227Svbart@nginx.com 27327Svbart@nginx.com if (nxt_slow_path(rc != NXT_DONE)) { 27427Svbart@nginx.com 27527Svbart@nginx.com if (rc == NXT_AGAIN) { 27627Svbart@nginx.com if (nxt_buf_mem_free_size(&b->mem) == 0) { 27727Svbart@nginx.com nxt_log(task, NXT_LOG_ERR, "too long request headers"); 27827Svbart@nginx.com nxt_controller_conn_close(task, c, r); 27927Svbart@nginx.com return; 28027Svbart@nginx.com } 28127Svbart@nginx.com 28262Sigor@sysoev.ru nxt_conn_read(task->thread->engine, c); 28327Svbart@nginx.com return; 28427Svbart@nginx.com } 28527Svbart@nginx.com 28627Svbart@nginx.com /* rc == NXT_ERROR */ 28727Svbart@nginx.com 28827Svbart@nginx.com nxt_log(task, NXT_LOG_ERR, "parsing error"); 28927Svbart@nginx.com 29027Svbart@nginx.com nxt_controller_conn_close(task, c, r); 29127Svbart@nginx.com return; 29227Svbart@nginx.com } 29327Svbart@nginx.com 29467Svbart@nginx.com rc = nxt_http_fields_process(r->parser.fields, r, task->log); 29560Svbart@nginx.com 29660Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 29760Svbart@nginx.com nxt_controller_conn_close(task, c, r); 29860Svbart@nginx.com return; 29960Svbart@nginx.com } 30060Svbart@nginx.com 30127Svbart@nginx.com preread = nxt_buf_mem_used_size(&b->mem); 30227Svbart@nginx.com 30327Svbart@nginx.com nxt_debug(task, "controller request header parsing complete, " 30427Svbart@nginx.com "body length: %O, preread: %uz", 30527Svbart@nginx.com r->length, preread); 30627Svbart@nginx.com 30727Svbart@nginx.com if (preread >= r->length) { 30827Svbart@nginx.com nxt_controller_process_request(task, c, r); 30927Svbart@nginx.com return; 31027Svbart@nginx.com } 31127Svbart@nginx.com 31227Svbart@nginx.com if (r->length - preread > (size_t) nxt_buf_mem_free_size(&b->mem)) { 31327Svbart@nginx.com b = nxt_buf_mem_alloc(c->mem_pool, r->length, 0); 31427Svbart@nginx.com if (nxt_slow_path(b == NULL)) { 31527Svbart@nginx.com nxt_controller_conn_free(task, c, NULL); 31627Svbart@nginx.com return; 31727Svbart@nginx.com } 31827Svbart@nginx.com 31927Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, c->read->mem.pos, preread); 32027Svbart@nginx.com 32127Svbart@nginx.com c->read = b; 32227Svbart@nginx.com } 32327Svbart@nginx.com 32427Svbart@nginx.com c->read_state = &nxt_controller_conn_body_read_state; 32527Svbart@nginx.com 32662Sigor@sysoev.ru nxt_conn_read(task->thread->engine, c); 32720Sigor@sysoev.ru } 32820Sigor@sysoev.ru 32920Sigor@sysoev.ru 33020Sigor@sysoev.ru static nxt_msec_t 33162Sigor@sysoev.ru nxt_controller_conn_timeout_value(nxt_conn_t *c, uintptr_t data) 33220Sigor@sysoev.ru { 33320Sigor@sysoev.ru return (nxt_msec_t) data; 33420Sigor@sysoev.ru } 33520Sigor@sysoev.ru 33620Sigor@sysoev.ru 33720Sigor@sysoev.ru static void 33820Sigor@sysoev.ru nxt_controller_conn_read_error(nxt_task_t *task, void *obj, void *data) 33920Sigor@sysoev.ru { 34062Sigor@sysoev.ru nxt_conn_t *c; 34120Sigor@sysoev.ru 34220Sigor@sysoev.ru c = obj; 34320Sigor@sysoev.ru 34420Sigor@sysoev.ru nxt_debug(task, "controller conn read error"); 34520Sigor@sysoev.ru 34627Svbart@nginx.com nxt_controller_conn_close(task, c, data); 34720Sigor@sysoev.ru } 34820Sigor@sysoev.ru 34920Sigor@sysoev.ru 35020Sigor@sysoev.ru static void 35120Sigor@sysoev.ru nxt_controller_conn_read_timeout(nxt_task_t *task, void *obj, void *data) 35220Sigor@sysoev.ru { 35362Sigor@sysoev.ru nxt_timer_t *timer; 35462Sigor@sysoev.ru nxt_conn_t *c; 35520Sigor@sysoev.ru 35662Sigor@sysoev.ru timer = obj; 35720Sigor@sysoev.ru 35862Sigor@sysoev.ru c = nxt_read_timer_conn(timer); 35920Sigor@sysoev.ru c->socket.timedout = 1; 36020Sigor@sysoev.ru c->socket.closed = 1; 36120Sigor@sysoev.ru 36220Sigor@sysoev.ru nxt_debug(task, "controller conn read timeout"); 36320Sigor@sysoev.ru 36427Svbart@nginx.com nxt_controller_conn_close(task, c, data); 36527Svbart@nginx.com } 36627Svbart@nginx.com 36727Svbart@nginx.com 36827Svbart@nginx.com static const nxt_event_conn_state_t nxt_controller_conn_body_read_state 36927Svbart@nginx.com nxt_aligned(64) = 37027Svbart@nginx.com { 37156Sigor@sysoev.ru .ready_handler = nxt_controller_conn_body_read, 37256Sigor@sysoev.ru .close_handler = nxt_controller_conn_close, 37356Sigor@sysoev.ru .error_handler = nxt_controller_conn_read_error, 37427Svbart@nginx.com 37556Sigor@sysoev.ru .timer_handler = nxt_controller_conn_read_timeout, 37656Sigor@sysoev.ru .timer_value = nxt_controller_conn_timeout_value, 37756Sigor@sysoev.ru .timer_data = 60 * 1000, 37856Sigor@sysoev.ru .timer_autoreset = 1, 37927Svbart@nginx.com }; 38027Svbart@nginx.com 38127Svbart@nginx.com 38227Svbart@nginx.com static void 38327Svbart@nginx.com nxt_controller_conn_body_read(nxt_task_t *task, void *obj, void *data) 38427Svbart@nginx.com { 38562Sigor@sysoev.ru size_t rest; 38662Sigor@sysoev.ru nxt_buf_t *b; 38762Sigor@sysoev.ru nxt_conn_t *c; 38827Svbart@nginx.com 38927Svbart@nginx.com c = obj; 39027Svbart@nginx.com 39127Svbart@nginx.com nxt_debug(task, "controller conn body read"); 39227Svbart@nginx.com 39327Svbart@nginx.com b = c->read; 39427Svbart@nginx.com 39527Svbart@nginx.com rest = nxt_buf_mem_free_size(&b->mem); 39627Svbart@nginx.com 39727Svbart@nginx.com if (rest == 0) { 39827Svbart@nginx.com nxt_debug(task, "controller conn body read complete"); 39927Svbart@nginx.com 40027Svbart@nginx.com nxt_controller_process_request(task, c, data); 40127Svbart@nginx.com return; 40227Svbart@nginx.com } 40327Svbart@nginx.com 40427Svbart@nginx.com nxt_debug(task, "controller conn body read again, rest: %uz", rest); 40527Svbart@nginx.com 40662Sigor@sysoev.ru nxt_conn_read(task->thread->engine, c); 40727Svbart@nginx.com } 40827Svbart@nginx.com 40927Svbart@nginx.com 41027Svbart@nginx.com static const nxt_event_conn_state_t nxt_controller_conn_write_state 41127Svbart@nginx.com nxt_aligned(64) = 41227Svbart@nginx.com { 41356Sigor@sysoev.ru .ready_handler = nxt_controller_conn_write, 41456Sigor@sysoev.ru .error_handler = nxt_controller_conn_write_error, 41527Svbart@nginx.com 41656Sigor@sysoev.ru .timer_handler = nxt_controller_conn_write_timeout, 41756Sigor@sysoev.ru .timer_value = nxt_controller_conn_timeout_value, 41856Sigor@sysoev.ru .timer_data = 60 * 1000, 41956Sigor@sysoev.ru .timer_autoreset = 1, 42027Svbart@nginx.com }; 42127Svbart@nginx.com 42227Svbart@nginx.com 42327Svbart@nginx.com static void 42427Svbart@nginx.com nxt_controller_conn_write(nxt_task_t *task, void *obj, void *data) 42527Svbart@nginx.com { 42662Sigor@sysoev.ru nxt_buf_t *b; 42762Sigor@sysoev.ru nxt_conn_t *c; 42827Svbart@nginx.com 42927Svbart@nginx.com c = obj; 43027Svbart@nginx.com 43127Svbart@nginx.com nxt_debug(task, "controller conn write"); 43227Svbart@nginx.com 43327Svbart@nginx.com b = c->write; 43427Svbart@nginx.com 43527Svbart@nginx.com if (b->mem.pos != b->mem.free) { 43662Sigor@sysoev.ru nxt_conn_write(task->thread->engine, c); 43727Svbart@nginx.com return; 43827Svbart@nginx.com } 43927Svbart@nginx.com 44027Svbart@nginx.com nxt_debug(task, "controller conn write complete"); 44127Svbart@nginx.com 44227Svbart@nginx.com nxt_controller_conn_close(task, c, data); 44327Svbart@nginx.com } 44427Svbart@nginx.com 44527Svbart@nginx.com 44627Svbart@nginx.com static void 44727Svbart@nginx.com nxt_controller_conn_write_error(nxt_task_t *task, void *obj, void *data) 44827Svbart@nginx.com { 44962Sigor@sysoev.ru nxt_conn_t *c; 45027Svbart@nginx.com 45127Svbart@nginx.com c = obj; 45227Svbart@nginx.com 45327Svbart@nginx.com nxt_debug(task, "controller conn write error"); 45427Svbart@nginx.com 45527Svbart@nginx.com nxt_controller_conn_close(task, c, data); 45627Svbart@nginx.com } 45727Svbart@nginx.com 45827Svbart@nginx.com 45927Svbart@nginx.com static void 46027Svbart@nginx.com nxt_controller_conn_write_timeout(nxt_task_t *task, void *obj, void *data) 46127Svbart@nginx.com { 46262Sigor@sysoev.ru nxt_conn_t *c; 46362Sigor@sysoev.ru nxt_timer_t *timer; 46427Svbart@nginx.com 46562Sigor@sysoev.ru timer = obj; 46627Svbart@nginx.com 46762Sigor@sysoev.ru c = nxt_write_timer_conn(timer); 46827Svbart@nginx.com c->socket.timedout = 1; 46927Svbart@nginx.com c->socket.closed = 1; 47027Svbart@nginx.com 47127Svbart@nginx.com nxt_debug(task, "controller conn write timeout"); 47227Svbart@nginx.com 47327Svbart@nginx.com nxt_controller_conn_close(task, c, data); 47420Sigor@sysoev.ru } 47520Sigor@sysoev.ru 47620Sigor@sysoev.ru 47720Sigor@sysoev.ru static const nxt_event_conn_state_t nxt_controller_conn_close_state 47820Sigor@sysoev.ru nxt_aligned(64) = 47920Sigor@sysoev.ru { 48056Sigor@sysoev.ru .ready_handler = nxt_controller_conn_free, 48120Sigor@sysoev.ru }; 48220Sigor@sysoev.ru 48320Sigor@sysoev.ru 48420Sigor@sysoev.ru static void 48520Sigor@sysoev.ru nxt_controller_conn_close(nxt_task_t *task, void *obj, void *data) 48620Sigor@sysoev.ru { 48762Sigor@sysoev.ru nxt_conn_t *c; 48820Sigor@sysoev.ru 48920Sigor@sysoev.ru c = obj; 49020Sigor@sysoev.ru 49120Sigor@sysoev.ru nxt_debug(task, "controller conn close"); 49220Sigor@sysoev.ru 49327Svbart@nginx.com nxt_queue_remove(&c->link); 49427Svbart@nginx.com 49520Sigor@sysoev.ru c->write_state = &nxt_controller_conn_close_state; 49620Sigor@sysoev.ru 49762Sigor@sysoev.ru nxt_conn_close(task->thread->engine, c); 49820Sigor@sysoev.ru } 49920Sigor@sysoev.ru 50020Sigor@sysoev.ru 50120Sigor@sysoev.ru static void 50220Sigor@sysoev.ru nxt_controller_conn_free(nxt_task_t *task, void *obj, void *data) 50320Sigor@sysoev.ru { 50462Sigor@sysoev.ru nxt_conn_t *c; 50520Sigor@sysoev.ru 50620Sigor@sysoev.ru c = obj; 50720Sigor@sysoev.ru 50820Sigor@sysoev.ru nxt_debug(task, "controller conn free"); 50920Sigor@sysoev.ru 51065Sigor@sysoev.ru nxt_mp_destroy(c->mem_pool); 51120Sigor@sysoev.ru 51220Sigor@sysoev.ru //nxt_free(c); 51320Sigor@sysoev.ru } 51427Svbart@nginx.com 51527Svbart@nginx.com 51627Svbart@nginx.com static nxt_int_t 51760Svbart@nginx.com nxt_controller_request_content_length(void *ctx, nxt_http_field_t *field, 51867Svbart@nginx.com nxt_log_t *log) 51927Svbart@nginx.com { 52027Svbart@nginx.com off_t length; 52127Svbart@nginx.com nxt_controller_request_t *r; 52227Svbart@nginx.com 52327Svbart@nginx.com r = ctx; 52427Svbart@nginx.com 52560Svbart@nginx.com length = nxt_off_t_parse(field->value.start, field->value.length); 52627Svbart@nginx.com 52727Svbart@nginx.com if (nxt_fast_path(length > 0)) { 52860Svbart@nginx.com nxt_log_error(NXT_LOG_ERR, log, "Content-Length is too big"); 52927Svbart@nginx.com 53027Svbart@nginx.com r->length = length; 53127Svbart@nginx.com return NXT_OK; 53227Svbart@nginx.com } 53327Svbart@nginx.com 53460Svbart@nginx.com nxt_log_error(NXT_LOG_ERR, log, "Content-Length is invalid"); 53527Svbart@nginx.com 53627Svbart@nginx.com return NXT_ERROR; 53727Svbart@nginx.com } 53827Svbart@nginx.com 53927Svbart@nginx.com 54027Svbart@nginx.com static void 54162Sigor@sysoev.ru nxt_controller_process_request(nxt_task_t *task, nxt_conn_t *c, 54244Svbart@nginx.com nxt_controller_request_t *req) 54327Svbart@nginx.com { 54465Sigor@sysoev.ru nxt_mp_t *mp; 54551Svbart@nginx.com nxt_int_t rc; 54646Svbart@nginx.com nxt_str_t path; 54751Svbart@nginx.com nxt_uint_t status; 54851Svbart@nginx.com nxt_buf_mem_t *mbuf; 54951Svbart@nginx.com nxt_conf_json_op_t *ops; 55046Svbart@nginx.com nxt_conf_json_value_t *value; 55144Svbart@nginx.com nxt_controller_response_t resp; 55244Svbart@nginx.com 55351Svbart@nginx.com static const nxt_str_t empty_obj = nxt_string("{}"); 55451Svbart@nginx.com 55551Svbart@nginx.com path.start = req->parser.target_start; 55651Svbart@nginx.com 55751Svbart@nginx.com if (req->parser.args_start != NULL) { 55851Svbart@nginx.com path.length = req->parser.args_start - path.start; 55951Svbart@nginx.com 56051Svbart@nginx.com } else { 56151Svbart@nginx.com path.length = req->parser.target_end - path.start; 56251Svbart@nginx.com } 56351Svbart@nginx.com 56451Svbart@nginx.com if (path.length > 1 && path.start[path.length - 1] == '/') { 56551Svbart@nginx.com path.length--; 56651Svbart@nginx.com } 56751Svbart@nginx.com 56844Svbart@nginx.com nxt_memzero(&resp, sizeof(nxt_controller_response_t)); 56944Svbart@nginx.com 57044Svbart@nginx.com if (nxt_str_eq(&req->parser.method, "GET", 3)) { 57146Svbart@nginx.com 57251Svbart@nginx.com value = nxt_conf_json_get_value(nxt_controller_conf.root, &path); 57351Svbart@nginx.com 57451Svbart@nginx.com if (value == NULL) { 57551Svbart@nginx.com status = 404; 57651Svbart@nginx.com goto done; 57751Svbart@nginx.com } 57851Svbart@nginx.com 57951Svbart@nginx.com resp.json_value = value; 58046Svbart@nginx.com 58151Svbart@nginx.com status = 200; 58251Svbart@nginx.com goto done; 58351Svbart@nginx.com } 58451Svbart@nginx.com 58551Svbart@nginx.com if (nxt_str_eq(&req->parser.method, "PUT", 3)) { 58646Svbart@nginx.com 58765Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 58851Svbart@nginx.com 58951Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 59051Svbart@nginx.com status = 500; 59151Svbart@nginx.com goto done; 59246Svbart@nginx.com } 59346Svbart@nginx.com 59451Svbart@nginx.com mbuf = &c->read->mem; 59551Svbart@nginx.com 59691Svbart@nginx.com value = nxt_conf_json_parse(mp, mbuf->pos, mbuf->free); 59751Svbart@nginx.com 59851Svbart@nginx.com if (value == NULL) { 59965Sigor@sysoev.ru nxt_mp_destroy(mp); 60051Svbart@nginx.com status = 400; 60151Svbart@nginx.com goto done; 60251Svbart@nginx.com } 60351Svbart@nginx.com 60451Svbart@nginx.com if (path.length != 1) { 60591Svbart@nginx.com rc = nxt_conf_json_op_compile(c->mem_pool, &ops, 60691Svbart@nginx.com nxt_controller_conf.root, 60791Svbart@nginx.com &path, value); 60846Svbart@nginx.com 60951Svbart@nginx.com if (rc != NXT_OK) { 61051Svbart@nginx.com if (rc == NXT_DECLINED) { 61151Svbart@nginx.com status = 404; 61251Svbart@nginx.com goto done; 61351Svbart@nginx.com } 61446Svbart@nginx.com 61551Svbart@nginx.com status = 500; 61651Svbart@nginx.com goto done; 61751Svbart@nginx.com } 61851Svbart@nginx.com 61991Svbart@nginx.com value = nxt_conf_json_clone_value(mp, ops, 62091Svbart@nginx.com nxt_controller_conf.root); 62151Svbart@nginx.com 62251Svbart@nginx.com if (nxt_slow_path(value == NULL)) { 62365Sigor@sysoev.ru nxt_mp_destroy(mp); 62451Svbart@nginx.com status = 500; 62551Svbart@nginx.com goto done; 62651Svbart@nginx.com } 62746Svbart@nginx.com } 62844Svbart@nginx.com 62965Sigor@sysoev.ru nxt_mp_destroy(nxt_controller_conf.pool); 63051Svbart@nginx.com 63151Svbart@nginx.com nxt_controller_conf.root = value; 63251Svbart@nginx.com nxt_controller_conf.pool = mp; 63344Svbart@nginx.com 63451Svbart@nginx.com nxt_str_set(&resp.json_string, "{ \"success\": \"Updated.\" }"); 63551Svbart@nginx.com 63651Svbart@nginx.com status = 200; 63751Svbart@nginx.com goto done; 63851Svbart@nginx.com } 63927Svbart@nginx.com 64051Svbart@nginx.com if (nxt_str_eq(&req->parser.method, "DELETE", 6)) { 64151Svbart@nginx.com 64251Svbart@nginx.com if (path.length == 1) { 64365Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 64444Svbart@nginx.com 64551Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 64651Svbart@nginx.com status = 500; 64751Svbart@nginx.com goto done; 64851Svbart@nginx.com } 64951Svbart@nginx.com 65091Svbart@nginx.com value = nxt_conf_json_str_parse(mp, &empty_obj); 65127Svbart@nginx.com 65244Svbart@nginx.com } else { 65391Svbart@nginx.com rc = nxt_conf_json_op_compile(c->mem_pool, &ops, 65491Svbart@nginx.com nxt_controller_conf.root, 65591Svbart@nginx.com &path, NULL); 65651Svbart@nginx.com 65751Svbart@nginx.com if (rc != NXT_OK) { 65851Svbart@nginx.com if (rc == NXT_DECLINED) { 65951Svbart@nginx.com status = 404; 66051Svbart@nginx.com goto done; 66151Svbart@nginx.com } 66251Svbart@nginx.com 66351Svbart@nginx.com status = 500; 66451Svbart@nginx.com goto done; 66551Svbart@nginx.com } 66651Svbart@nginx.com 66765Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 66851Svbart@nginx.com 66951Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 67051Svbart@nginx.com status = 500; 67151Svbart@nginx.com goto done; 67251Svbart@nginx.com } 67351Svbart@nginx.com 67491Svbart@nginx.com value = nxt_conf_json_clone_value(mp, ops, 67591Svbart@nginx.com nxt_controller_conf.root); 67651Svbart@nginx.com } 67751Svbart@nginx.com 67851Svbart@nginx.com if (nxt_slow_path(value == NULL)) { 67965Sigor@sysoev.ru nxt_mp_destroy(mp); 68051Svbart@nginx.com status = 500; 68151Svbart@nginx.com goto done; 68244Svbart@nginx.com } 68344Svbart@nginx.com 68465Sigor@sysoev.ru nxt_mp_destroy(nxt_controller_conf.pool); 68551Svbart@nginx.com 68651Svbart@nginx.com nxt_controller_conf.root = value; 68751Svbart@nginx.com nxt_controller_conf.pool = mp; 68851Svbart@nginx.com 68951Svbart@nginx.com nxt_str_set(&resp.json_string, "{ \"success\": \"Deleted.\" }"); 69051Svbart@nginx.com 69151Svbart@nginx.com status = 200; 69251Svbart@nginx.com goto done; 69351Svbart@nginx.com } 69451Svbart@nginx.com 69551Svbart@nginx.com status = 405; 69651Svbart@nginx.com 69751Svbart@nginx.com done: 69851Svbart@nginx.com 69951Svbart@nginx.com switch (status) { 70051Svbart@nginx.com 70151Svbart@nginx.com case 200: 70251Svbart@nginx.com nxt_str_set(&resp.status_line, "200 OK"); 70351Svbart@nginx.com break; 70451Svbart@nginx.com 70551Svbart@nginx.com case 400: 70651Svbart@nginx.com nxt_str_set(&resp.status_line, "400 Bad Request"); 70751Svbart@nginx.com nxt_str_set(&resp.json_string, 70851Svbart@nginx.com "{ \"error\": \"Invalid JSON.\" }"); 70951Svbart@nginx.com break; 71051Svbart@nginx.com 71151Svbart@nginx.com case 404: 71251Svbart@nginx.com nxt_str_set(&resp.status_line, "404 Not Found"); 71351Svbart@nginx.com nxt_str_set(&resp.json_string, 71451Svbart@nginx.com "{ \"error\": \"Value doesn't exist.\" }"); 71551Svbart@nginx.com break; 71651Svbart@nginx.com 71751Svbart@nginx.com case 405: 71844Svbart@nginx.com nxt_str_set(&resp.status_line, "405 Method Not Allowed"); 71951Svbart@nginx.com nxt_str_set(&resp.json_string, "{ \"error\": \"Invalid method.\" }"); 72051Svbart@nginx.com break; 72151Svbart@nginx.com 72251Svbart@nginx.com case 500: 72351Svbart@nginx.com nxt_str_set(&resp.status_line, "500 Internal Server Error"); 72451Svbart@nginx.com nxt_str_set(&resp.json_string, 72551Svbart@nginx.com "{ \"error\": \"Memory allocation failed.\" }"); 72651Svbart@nginx.com break; 72729Svbart@nginx.com } 72827Svbart@nginx.com 72944Svbart@nginx.com if (nxt_controller_response(task, c, &resp) != NXT_OK) { 73044Svbart@nginx.com nxt_controller_conn_close(task, c, req); 73127Svbart@nginx.com } 73227Svbart@nginx.com } 73327Svbart@nginx.com 73427Svbart@nginx.com 73527Svbart@nginx.com static nxt_int_t 73662Sigor@sysoev.ru nxt_controller_response(nxt_task_t *task, nxt_conn_t *c, 73744Svbart@nginx.com nxt_controller_response_t *resp) 73833Svbart@nginx.com { 73944Svbart@nginx.com size_t size; 74033Svbart@nginx.com nxt_buf_t *b; 74133Svbart@nginx.com 74245Svbart@nginx.com size = sizeof("HTTP/1.0 " "\r\n\r\n") - 1 + resp->status_line.length; 74333Svbart@nginx.com 74444Svbart@nginx.com b = nxt_buf_mem_alloc(c->mem_pool, size, 0); 74533Svbart@nginx.com if (nxt_slow_path(b == NULL)) { 74644Svbart@nginx.com return NXT_ERROR; 74733Svbart@nginx.com } 74833Svbart@nginx.com 74944Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, "HTTP/1.0 ", sizeof("HTTP/1.0 ") - 1); 75044Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, resp->status_line.start, 75144Svbart@nginx.com resp->status_line.length); 75244Svbart@nginx.com 75344Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, "\r\n\r\n", sizeof("\r\n\r\n") - 1); 75444Svbart@nginx.com 75545Svbart@nginx.com b->next = nxt_controller_response_body(resp, c->mem_pool); 75645Svbart@nginx.com 75745Svbart@nginx.com if (nxt_slow_path(b->next == NULL)) { 75845Svbart@nginx.com return NXT_ERROR; 75944Svbart@nginx.com } 76033Svbart@nginx.com 76133Svbart@nginx.com c->write = b; 76244Svbart@nginx.com c->write_state = &nxt_controller_conn_write_state; 76333Svbart@nginx.com 76462Sigor@sysoev.ru nxt_conn_write(task->thread->engine, c); 76533Svbart@nginx.com 76644Svbart@nginx.com return NXT_OK; 76733Svbart@nginx.com } 76845Svbart@nginx.com 76945Svbart@nginx.com 77045Svbart@nginx.com static nxt_buf_t * 77165Sigor@sysoev.ru nxt_controller_response_body(nxt_controller_response_t *resp, nxt_mp_t *pool) 77245Svbart@nginx.com { 77345Svbart@nginx.com size_t size; 77445Svbart@nginx.com nxt_buf_t *b; 77545Svbart@nginx.com nxt_conf_json_value_t *value; 77645Svbart@nginx.com nxt_conf_json_pretty_t pretty; 77745Svbart@nginx.com 77845Svbart@nginx.com if (resp->json_value) { 77945Svbart@nginx.com value = resp->json_value; 78045Svbart@nginx.com 78145Svbart@nginx.com } else { 78291Svbart@nginx.com value = nxt_conf_json_str_parse(pool, &resp->json_string); 78345Svbart@nginx.com 78445Svbart@nginx.com if (nxt_slow_path(value == NULL)) { 78545Svbart@nginx.com return NULL; 78645Svbart@nginx.com } 78745Svbart@nginx.com } 78845Svbart@nginx.com 78945Svbart@nginx.com nxt_memzero(&pretty, sizeof(nxt_conf_json_pretty_t)); 79045Svbart@nginx.com 79192Svbart@nginx.com size = nxt_conf_json_value_length(value, &pretty) + 2; 79245Svbart@nginx.com 79345Svbart@nginx.com b = nxt_buf_mem_alloc(pool, size, 0); 79445Svbart@nginx.com if (nxt_slow_path(b == NULL)) { 79545Svbart@nginx.com return NULL; 79645Svbart@nginx.com } 79745Svbart@nginx.com 79845Svbart@nginx.com nxt_memzero(&pretty, sizeof(nxt_conf_json_pretty_t)); 79945Svbart@nginx.com 80092Svbart@nginx.com b->mem.free = nxt_conf_json_value_print(b->mem.free, value, &pretty); 80145Svbart@nginx.com 80245Svbart@nginx.com *b->mem.free++ = '\r'; 80345Svbart@nginx.com *b->mem.free++ = '\n'; 80445Svbart@nginx.com 80545Svbart@nginx.com return b; 80645Svbart@nginx.com } 807