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; 1644Svbart@nginx.com nxt_mem_pool_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); 3720Sigor@sysoev.ru static nxt_msec_t nxt_controller_conn_timeout_value(nxt_event_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, 5427Svbart@nginx.com nxt_str_t *name, nxt_str_t *value, uintptr_t data); 5527Svbart@nginx.com 5627Svbart@nginx.com static void nxt_controller_process_request(nxt_task_t *task, 5727Svbart@nginx.com nxt_event_conn_t *c, nxt_controller_request_t *r); 5844Svbart@nginx.com static nxt_int_t nxt_controller_response(nxt_task_t *task, nxt_event_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, 6145Svbart@nginx.com nxt_mem_pool_t *pool); 6227Svbart@nginx.com 6327Svbart@nginx.com 6427Svbart@nginx.com static nxt_http_fields_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 7144Svbart@nginx.com static nxt_http_fields_hash_t *nxt_controller_request_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 { 8644Svbart@nginx.com nxt_mem_pool_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 9327Svbart@nginx.com hash = nxt_http_fields_hash(nxt_controller_request_fields, rt->mem_pool); 9427Svbart@nginx.com 9527Svbart@nginx.com if (nxt_slow_path(hash == NULL)) { 9627Svbart@nginx.com return NXT_ERROR; 9727Svbart@nginx.com } 9827Svbart@nginx.com 9927Svbart@nginx.com nxt_controller_request_fields_hash = hash; 10027Svbart@nginx.com 10120Sigor@sysoev.ru if (nxt_event_conn_listen(task, rt->controller_socket) != NXT_OK) { 10220Sigor@sysoev.ru return NXT_ERROR; 10320Sigor@sysoev.ru } 10420Sigor@sysoev.ru 10544Svbart@nginx.com mp = nxt_mem_pool_create(256); 10644Svbart@nginx.com 10744Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 10844Svbart@nginx.com return NXT_ERROR; 10944Svbart@nginx.com } 11044Svbart@nginx.com 11144Svbart@nginx.com conf = nxt_conf_json_parse(json.start, json.length, mp); 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 14820Sigor@sysoev.ru ls = nxt_mem_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; 16020Sigor@sysoev.ru 16120Sigor@sysoev.ru nxt_sockaddr_text(ls->sockaddr); 16220Sigor@sysoev.ru 16320Sigor@sysoev.ru ls->socket = -1; 16420Sigor@sysoev.ru ls->backlog = NXT_LISTEN_BACKLOG; 16520Sigor@sysoev.ru ls->read_after_accept = 1; 16620Sigor@sysoev.ru ls->flags = NXT_NONBLOCK; 16720Sigor@sysoev.ru 16820Sigor@sysoev.ru #if 0 16920Sigor@sysoev.ru /* STUB */ 17020Sigor@sysoev.ru wq = nxt_mem_zalloc(cf->mem_pool, sizeof(nxt_work_queue_t)); 17120Sigor@sysoev.ru if (wq == NULL) { 17220Sigor@sysoev.ru return NXT_ERROR; 17320Sigor@sysoev.ru } 17420Sigor@sysoev.ru nxt_work_queue_name(wq, "listen"); 17520Sigor@sysoev.ru /**/ 17620Sigor@sysoev.ru 17720Sigor@sysoev.ru ls->work_queue = wq; 17820Sigor@sysoev.ru #endif 17920Sigor@sysoev.ru ls->handler = nxt_controller_conn_init; 18020Sigor@sysoev.ru 18120Sigor@sysoev.ru /* 18220Sigor@sysoev.ru * Connection memory pool chunk size is tunned to 18320Sigor@sysoev.ru * allocate the most data in one mem_pool chunk. 18420Sigor@sysoev.ru */ 18520Sigor@sysoev.ru ls->mem_pool_size = nxt_listen_socket_pool_min_size(ls) 18620Sigor@sysoev.ru + sizeof(nxt_event_conn_proxy_t) 18720Sigor@sysoev.ru + sizeof(nxt_event_conn_t) 18820Sigor@sysoev.ru + 4 * sizeof(nxt_buf_t); 18920Sigor@sysoev.ru 19020Sigor@sysoev.ru if (nxt_listen_socket_create(task, ls, 0) != NXT_OK) { 19120Sigor@sysoev.ru return NXT_ERROR; 19220Sigor@sysoev.ru } 19320Sigor@sysoev.ru 19420Sigor@sysoev.ru rt->controller_socket = ls; 19520Sigor@sysoev.ru 19620Sigor@sysoev.ru return NXT_OK; 19720Sigor@sysoev.ru } 19820Sigor@sysoev.ru 19920Sigor@sysoev.ru 20020Sigor@sysoev.ru static void 20120Sigor@sysoev.ru nxt_controller_conn_init(nxt_task_t *task, void *obj, void *data) 20220Sigor@sysoev.ru { 20327Svbart@nginx.com nxt_buf_t *b; 20427Svbart@nginx.com nxt_event_conn_t *c; 20527Svbart@nginx.com nxt_event_engine_t *engine; 20627Svbart@nginx.com nxt_controller_request_t *r; 20720Sigor@sysoev.ru 20820Sigor@sysoev.ru c = obj; 20920Sigor@sysoev.ru 21020Sigor@sysoev.ru nxt_debug(task, "controller conn init fd:%d", c->socket.fd); 21120Sigor@sysoev.ru 21227Svbart@nginx.com r = nxt_mem_zalloc(c->mem_pool, sizeof(nxt_controller_request_t)); 21327Svbart@nginx.com if (nxt_slow_path(r == NULL)) { 21427Svbart@nginx.com nxt_controller_conn_free(task, c, NULL); 21527Svbart@nginx.com return; 21627Svbart@nginx.com } 21727Svbart@nginx.com 21827Svbart@nginx.com r->parser.hash = nxt_controller_request_fields_hash; 21927Svbart@nginx.com r->parser.ctx = r; 22027Svbart@nginx.com 22120Sigor@sysoev.ru b = nxt_buf_mem_alloc(c->mem_pool, 1024, 0); 22220Sigor@sysoev.ru if (nxt_slow_path(b == NULL)) { 22320Sigor@sysoev.ru nxt_controller_conn_free(task, c, NULL); 22420Sigor@sysoev.ru return; 22520Sigor@sysoev.ru } 22620Sigor@sysoev.ru 22720Sigor@sysoev.ru c->read = b; 22827Svbart@nginx.com c->socket.data = r; 22920Sigor@sysoev.ru c->socket.read_ready = 1; 23020Sigor@sysoev.ru c->read_state = &nxt_controller_conn_read_state; 23120Sigor@sysoev.ru 23220Sigor@sysoev.ru engine = task->thread->engine; 23320Sigor@sysoev.ru c->read_work_queue = &engine->read_work_queue; 23427Svbart@nginx.com c->write_work_queue = &engine->write_work_queue; 23520Sigor@sysoev.ru 23620Sigor@sysoev.ru nxt_event_conn_read(engine, c); 23720Sigor@sysoev.ru } 23820Sigor@sysoev.ru 23920Sigor@sysoev.ru 24020Sigor@sysoev.ru static const nxt_event_conn_state_t nxt_controller_conn_read_state 24120Sigor@sysoev.ru nxt_aligned(64) = 24220Sigor@sysoev.ru { 24320Sigor@sysoev.ru NXT_EVENT_NO_BUF_PROCESS, 24420Sigor@sysoev.ru NXT_EVENT_TIMER_NO_AUTORESET, 24520Sigor@sysoev.ru 24620Sigor@sysoev.ru nxt_controller_conn_read, 24720Sigor@sysoev.ru nxt_controller_conn_close, 24820Sigor@sysoev.ru nxt_controller_conn_read_error, 24920Sigor@sysoev.ru 25020Sigor@sysoev.ru nxt_controller_conn_read_timeout, 25120Sigor@sysoev.ru nxt_controller_conn_timeout_value, 25220Sigor@sysoev.ru 60 * 1000, 25320Sigor@sysoev.ru }; 25420Sigor@sysoev.ru 25520Sigor@sysoev.ru 25620Sigor@sysoev.ru static void 25720Sigor@sysoev.ru nxt_controller_conn_read(nxt_task_t *task, void *obj, void *data) 25820Sigor@sysoev.ru { 25927Svbart@nginx.com size_t preread; 26027Svbart@nginx.com nxt_buf_t *b; 26127Svbart@nginx.com nxt_int_t rc; 26227Svbart@nginx.com nxt_event_conn_t *c; 26327Svbart@nginx.com nxt_controller_request_t *r; 26420Sigor@sysoev.ru 26520Sigor@sysoev.ru c = obj; 26627Svbart@nginx.com r = data; 26720Sigor@sysoev.ru 26820Sigor@sysoev.ru nxt_debug(task, "controller conn read"); 26920Sigor@sysoev.ru 27027Svbart@nginx.com nxt_queue_remove(&c->link); 27127Svbart@nginx.com nxt_queue_self(&c->link); 27227Svbart@nginx.com 27327Svbart@nginx.com b = c->read; 27427Svbart@nginx.com 27527Svbart@nginx.com rc = nxt_http_parse_request(&r->parser, &b->mem); 27627Svbart@nginx.com 27727Svbart@nginx.com if (nxt_slow_path(rc != NXT_DONE)) { 27827Svbart@nginx.com 27927Svbart@nginx.com if (rc == NXT_AGAIN) { 28027Svbart@nginx.com if (nxt_buf_mem_free_size(&b->mem) == 0) { 28127Svbart@nginx.com nxt_log(task, NXT_LOG_ERR, "too long request headers"); 28227Svbart@nginx.com nxt_controller_conn_close(task, c, r); 28327Svbart@nginx.com return; 28427Svbart@nginx.com } 28527Svbart@nginx.com 28627Svbart@nginx.com nxt_event_conn_read(task->thread->engine, c); 28727Svbart@nginx.com return; 28827Svbart@nginx.com } 28927Svbart@nginx.com 29027Svbart@nginx.com /* rc == NXT_ERROR */ 29127Svbart@nginx.com 29227Svbart@nginx.com nxt_log(task, NXT_LOG_ERR, "parsing error"); 29327Svbart@nginx.com 29427Svbart@nginx.com nxt_controller_conn_close(task, c, r); 29527Svbart@nginx.com return; 29627Svbart@nginx.com } 29727Svbart@nginx.com 29827Svbart@nginx.com preread = nxt_buf_mem_used_size(&b->mem); 29927Svbart@nginx.com 30027Svbart@nginx.com nxt_debug(task, "controller request header parsing complete, " 30127Svbart@nginx.com "body length: %O, preread: %uz", 30227Svbart@nginx.com r->length, preread); 30327Svbart@nginx.com 30427Svbart@nginx.com if (preread >= r->length) { 30527Svbart@nginx.com nxt_controller_process_request(task, c, r); 30627Svbart@nginx.com return; 30727Svbart@nginx.com } 30827Svbart@nginx.com 30927Svbart@nginx.com if (r->length - preread > (size_t) nxt_buf_mem_free_size(&b->mem)) { 31027Svbart@nginx.com b = nxt_buf_mem_alloc(c->mem_pool, r->length, 0); 31127Svbart@nginx.com if (nxt_slow_path(b == NULL)) { 31227Svbart@nginx.com nxt_controller_conn_free(task, c, NULL); 31327Svbart@nginx.com return; 31427Svbart@nginx.com } 31527Svbart@nginx.com 31627Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, c->read->mem.pos, preread); 31727Svbart@nginx.com 31827Svbart@nginx.com c->read = b; 31927Svbart@nginx.com } 32027Svbart@nginx.com 32127Svbart@nginx.com c->read_state = &nxt_controller_conn_body_read_state; 32227Svbart@nginx.com 32327Svbart@nginx.com nxt_event_conn_read(task->thread->engine, c); 32420Sigor@sysoev.ru } 32520Sigor@sysoev.ru 32620Sigor@sysoev.ru 32720Sigor@sysoev.ru static nxt_msec_t 32820Sigor@sysoev.ru nxt_controller_conn_timeout_value(nxt_event_conn_t *c, uintptr_t data) 32920Sigor@sysoev.ru { 33020Sigor@sysoev.ru return (nxt_msec_t) data; 33120Sigor@sysoev.ru } 33220Sigor@sysoev.ru 33320Sigor@sysoev.ru 33420Sigor@sysoev.ru static void 33520Sigor@sysoev.ru nxt_controller_conn_read_error(nxt_task_t *task, void *obj, void *data) 33620Sigor@sysoev.ru { 33720Sigor@sysoev.ru nxt_event_conn_t *c; 33820Sigor@sysoev.ru 33920Sigor@sysoev.ru c = obj; 34020Sigor@sysoev.ru 34120Sigor@sysoev.ru nxt_debug(task, "controller conn read error"); 34220Sigor@sysoev.ru 34327Svbart@nginx.com nxt_controller_conn_close(task, c, data); 34420Sigor@sysoev.ru } 34520Sigor@sysoev.ru 34620Sigor@sysoev.ru 34720Sigor@sysoev.ru static void 34820Sigor@sysoev.ru nxt_controller_conn_read_timeout(nxt_task_t *task, void *obj, void *data) 34920Sigor@sysoev.ru { 35020Sigor@sysoev.ru nxt_timer_t *ev; 35120Sigor@sysoev.ru nxt_event_conn_t *c; 35220Sigor@sysoev.ru 35320Sigor@sysoev.ru ev = obj; 35420Sigor@sysoev.ru 35520Sigor@sysoev.ru c = nxt_event_read_timer_conn(ev); 35620Sigor@sysoev.ru c->socket.timedout = 1; 35720Sigor@sysoev.ru c->socket.closed = 1; 35820Sigor@sysoev.ru 35920Sigor@sysoev.ru nxt_debug(task, "controller conn read timeout"); 36020Sigor@sysoev.ru 36127Svbart@nginx.com nxt_controller_conn_close(task, c, data); 36227Svbart@nginx.com } 36327Svbart@nginx.com 36427Svbart@nginx.com 36527Svbart@nginx.com static const nxt_event_conn_state_t nxt_controller_conn_body_read_state 36627Svbart@nginx.com nxt_aligned(64) = 36727Svbart@nginx.com { 36827Svbart@nginx.com NXT_EVENT_NO_BUF_PROCESS, 36927Svbart@nginx.com NXT_EVENT_TIMER_AUTORESET, 37027Svbart@nginx.com 37127Svbart@nginx.com nxt_controller_conn_body_read, 37227Svbart@nginx.com nxt_controller_conn_close, 37327Svbart@nginx.com nxt_controller_conn_read_error, 37427Svbart@nginx.com 37527Svbart@nginx.com nxt_controller_conn_read_timeout, 37627Svbart@nginx.com nxt_controller_conn_timeout_value, 37727Svbart@nginx.com 60 * 1000, 37827Svbart@nginx.com }; 37927Svbart@nginx.com 38027Svbart@nginx.com 38127Svbart@nginx.com static void 38227Svbart@nginx.com nxt_controller_conn_body_read(nxt_task_t *task, void *obj, void *data) 38327Svbart@nginx.com { 38427Svbart@nginx.com size_t rest; 38527Svbart@nginx.com nxt_buf_t *b; 38627Svbart@nginx.com nxt_event_conn_t *c; 38727Svbart@nginx.com 38827Svbart@nginx.com c = obj; 38927Svbart@nginx.com 39027Svbart@nginx.com nxt_debug(task, "controller conn body read"); 39127Svbart@nginx.com 39227Svbart@nginx.com b = c->read; 39327Svbart@nginx.com 39427Svbart@nginx.com rest = nxt_buf_mem_free_size(&b->mem); 39527Svbart@nginx.com 39627Svbart@nginx.com if (rest == 0) { 39727Svbart@nginx.com nxt_debug(task, "controller conn body read complete"); 39827Svbart@nginx.com 39927Svbart@nginx.com nxt_controller_process_request(task, c, data); 40027Svbart@nginx.com return; 40127Svbart@nginx.com } 40227Svbart@nginx.com 40327Svbart@nginx.com nxt_debug(task, "controller conn body read again, rest: %uz", rest); 40427Svbart@nginx.com 40527Svbart@nginx.com nxt_event_conn_read(task->thread->engine, c); 40627Svbart@nginx.com } 40727Svbart@nginx.com 40827Svbart@nginx.com 40927Svbart@nginx.com static const nxt_event_conn_state_t nxt_controller_conn_write_state 41027Svbart@nginx.com nxt_aligned(64) = 41127Svbart@nginx.com { 41227Svbart@nginx.com NXT_EVENT_NO_BUF_PROCESS, 41327Svbart@nginx.com NXT_EVENT_TIMER_AUTORESET, 41427Svbart@nginx.com 41527Svbart@nginx.com nxt_controller_conn_write, 41627Svbart@nginx.com NULL, 41727Svbart@nginx.com nxt_controller_conn_write_error, 41827Svbart@nginx.com 41927Svbart@nginx.com nxt_controller_conn_write_timeout, 42027Svbart@nginx.com nxt_controller_conn_timeout_value, 42127Svbart@nginx.com 60 * 1000, 42227Svbart@nginx.com }; 42327Svbart@nginx.com 42427Svbart@nginx.com 42527Svbart@nginx.com static void 42627Svbart@nginx.com nxt_controller_conn_write(nxt_task_t *task, void *obj, void *data) 42727Svbart@nginx.com { 42827Svbart@nginx.com nxt_buf_t *b; 42927Svbart@nginx.com nxt_event_conn_t *c; 43027Svbart@nginx.com 43127Svbart@nginx.com c = obj; 43227Svbart@nginx.com 43327Svbart@nginx.com nxt_debug(task, "controller conn write"); 43427Svbart@nginx.com 43527Svbart@nginx.com b = c->write; 43627Svbart@nginx.com 43727Svbart@nginx.com if (b->mem.pos != b->mem.free) { 43827Svbart@nginx.com nxt_event_conn_write(task->thread->engine, c); 43927Svbart@nginx.com return; 44027Svbart@nginx.com } 44127Svbart@nginx.com 44227Svbart@nginx.com nxt_debug(task, "controller conn write complete"); 44327Svbart@nginx.com 44427Svbart@nginx.com nxt_controller_conn_close(task, c, data); 44527Svbart@nginx.com } 44627Svbart@nginx.com 44727Svbart@nginx.com 44827Svbart@nginx.com static void 44927Svbart@nginx.com nxt_controller_conn_write_error(nxt_task_t *task, void *obj, void *data) 45027Svbart@nginx.com { 45127Svbart@nginx.com nxt_event_conn_t *c; 45227Svbart@nginx.com 45327Svbart@nginx.com c = obj; 45427Svbart@nginx.com 45527Svbart@nginx.com nxt_debug(task, "controller conn write error"); 45627Svbart@nginx.com 45727Svbart@nginx.com nxt_controller_conn_close(task, c, data); 45827Svbart@nginx.com } 45927Svbart@nginx.com 46027Svbart@nginx.com 46127Svbart@nginx.com static void 46227Svbart@nginx.com nxt_controller_conn_write_timeout(nxt_task_t *task, void *obj, void *data) 46327Svbart@nginx.com { 46427Svbart@nginx.com nxt_timer_t *ev; 46527Svbart@nginx.com nxt_event_conn_t *c; 46627Svbart@nginx.com 46727Svbart@nginx.com ev = obj; 46827Svbart@nginx.com 46927Svbart@nginx.com c = nxt_event_write_timer_conn(ev); 47027Svbart@nginx.com c->socket.timedout = 1; 47127Svbart@nginx.com c->socket.closed = 1; 47227Svbart@nginx.com 47327Svbart@nginx.com nxt_debug(task, "controller conn write timeout"); 47427Svbart@nginx.com 47527Svbart@nginx.com nxt_controller_conn_close(task, c, data); 47620Sigor@sysoev.ru } 47720Sigor@sysoev.ru 47820Sigor@sysoev.ru 47920Sigor@sysoev.ru static const nxt_event_conn_state_t nxt_controller_conn_close_state 48020Sigor@sysoev.ru nxt_aligned(64) = 48120Sigor@sysoev.ru { 48220Sigor@sysoev.ru NXT_EVENT_NO_BUF_PROCESS, 48320Sigor@sysoev.ru NXT_EVENT_TIMER_NO_AUTORESET, 48420Sigor@sysoev.ru 48520Sigor@sysoev.ru nxt_controller_conn_free, 48620Sigor@sysoev.ru NULL, 48720Sigor@sysoev.ru NULL, 48820Sigor@sysoev.ru 48920Sigor@sysoev.ru NULL, 49020Sigor@sysoev.ru NULL, 49120Sigor@sysoev.ru 0, 49220Sigor@sysoev.ru }; 49320Sigor@sysoev.ru 49420Sigor@sysoev.ru 49520Sigor@sysoev.ru static void 49620Sigor@sysoev.ru nxt_controller_conn_close(nxt_task_t *task, void *obj, void *data) 49720Sigor@sysoev.ru { 49820Sigor@sysoev.ru nxt_event_conn_t *c; 49920Sigor@sysoev.ru 50020Sigor@sysoev.ru c = obj; 50120Sigor@sysoev.ru 50220Sigor@sysoev.ru nxt_debug(task, "controller conn close"); 50320Sigor@sysoev.ru 50427Svbart@nginx.com nxt_queue_remove(&c->link); 50527Svbart@nginx.com 50620Sigor@sysoev.ru c->write_state = &nxt_controller_conn_close_state; 50720Sigor@sysoev.ru 50820Sigor@sysoev.ru nxt_event_conn_close(task->thread->engine, c); 50920Sigor@sysoev.ru } 51020Sigor@sysoev.ru 51120Sigor@sysoev.ru 51220Sigor@sysoev.ru static void 51320Sigor@sysoev.ru nxt_controller_conn_free(nxt_task_t *task, void *obj, void *data) 51420Sigor@sysoev.ru { 51520Sigor@sysoev.ru nxt_event_conn_t *c; 51620Sigor@sysoev.ru 51720Sigor@sysoev.ru c = obj; 51820Sigor@sysoev.ru 51920Sigor@sysoev.ru nxt_debug(task, "controller conn free"); 52020Sigor@sysoev.ru 52120Sigor@sysoev.ru nxt_mem_pool_destroy(c->mem_pool); 52220Sigor@sysoev.ru 52320Sigor@sysoev.ru //nxt_free(c); 52420Sigor@sysoev.ru } 52527Svbart@nginx.com 52627Svbart@nginx.com 52727Svbart@nginx.com static nxt_int_t 52827Svbart@nginx.com nxt_controller_request_content_length(void *ctx, nxt_str_t *name, 52927Svbart@nginx.com nxt_str_t *value, uintptr_t data) 53027Svbart@nginx.com { 53127Svbart@nginx.com off_t length; 53227Svbart@nginx.com nxt_controller_request_t *r; 53327Svbart@nginx.com 53427Svbart@nginx.com r = ctx; 53527Svbart@nginx.com 53627Svbart@nginx.com length = nxt_off_t_parse(value->start, value->length); 53727Svbart@nginx.com 53827Svbart@nginx.com if (nxt_fast_path(length > 0)) { 53927Svbart@nginx.com /* TODO length too big */ 54027Svbart@nginx.com 54127Svbart@nginx.com r->length = length; 54227Svbart@nginx.com return NXT_OK; 54327Svbart@nginx.com } 54427Svbart@nginx.com 54527Svbart@nginx.com /* TODO logging (task?) */ 54627Svbart@nginx.com 54727Svbart@nginx.com return NXT_ERROR; 54827Svbart@nginx.com } 54927Svbart@nginx.com 55027Svbart@nginx.com 55127Svbart@nginx.com static void 55227Svbart@nginx.com nxt_controller_process_request(nxt_task_t *task, nxt_event_conn_t *c, 55344Svbart@nginx.com nxt_controller_request_t *req) 55427Svbart@nginx.com { 555*51Svbart@nginx.com nxt_int_t rc; 55646Svbart@nginx.com nxt_str_t path; 557*51Svbart@nginx.com nxt_uint_t status; 558*51Svbart@nginx.com nxt_buf_mem_t *mbuf; 559*51Svbart@nginx.com nxt_mem_pool_t *mp; 560*51Svbart@nginx.com nxt_conf_json_op_t *ops; 56146Svbart@nginx.com nxt_conf_json_value_t *value; 56244Svbart@nginx.com nxt_controller_response_t resp; 56344Svbart@nginx.com 564*51Svbart@nginx.com static const nxt_str_t empty_obj = nxt_string("{}"); 565*51Svbart@nginx.com 566*51Svbart@nginx.com path.start = req->parser.target_start; 567*51Svbart@nginx.com 568*51Svbart@nginx.com if (req->parser.args_start != NULL) { 569*51Svbart@nginx.com path.length = req->parser.args_start - path.start; 570*51Svbart@nginx.com 571*51Svbart@nginx.com } else { 572*51Svbart@nginx.com path.length = req->parser.target_end - path.start; 573*51Svbart@nginx.com } 574*51Svbart@nginx.com 575*51Svbart@nginx.com if (path.length > 1 && path.start[path.length - 1] == '/') { 576*51Svbart@nginx.com path.length--; 577*51Svbart@nginx.com } 578*51Svbart@nginx.com 57944Svbart@nginx.com nxt_memzero(&resp, sizeof(nxt_controller_response_t)); 58044Svbart@nginx.com 58144Svbart@nginx.com if (nxt_str_eq(&req->parser.method, "GET", 3)) { 58246Svbart@nginx.com 583*51Svbart@nginx.com value = nxt_conf_json_get_value(nxt_controller_conf.root, &path); 584*51Svbart@nginx.com 585*51Svbart@nginx.com if (value == NULL) { 586*51Svbart@nginx.com status = 404; 587*51Svbart@nginx.com goto done; 588*51Svbart@nginx.com } 589*51Svbart@nginx.com 590*51Svbart@nginx.com resp.json_value = value; 59146Svbart@nginx.com 592*51Svbart@nginx.com status = 200; 593*51Svbart@nginx.com goto done; 594*51Svbart@nginx.com } 595*51Svbart@nginx.com 596*51Svbart@nginx.com if (nxt_str_eq(&req->parser.method, "PUT", 3)) { 59746Svbart@nginx.com 598*51Svbart@nginx.com mp = nxt_mem_pool_create(512); 599*51Svbart@nginx.com 600*51Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 601*51Svbart@nginx.com status = 500; 602*51Svbart@nginx.com goto done; 60346Svbart@nginx.com } 60446Svbart@nginx.com 605*51Svbart@nginx.com mbuf = &c->read->mem; 606*51Svbart@nginx.com 607*51Svbart@nginx.com value = nxt_conf_json_parse(mbuf->pos, mbuf->free - mbuf->pos, mp); 608*51Svbart@nginx.com 609*51Svbart@nginx.com if (value == NULL) { 610*51Svbart@nginx.com nxt_mem_pool_destroy(mp); 611*51Svbart@nginx.com status = 400; 612*51Svbart@nginx.com goto done; 613*51Svbart@nginx.com } 614*51Svbart@nginx.com 615*51Svbart@nginx.com if (path.length != 1) { 616*51Svbart@nginx.com rc = nxt_conf_json_op_compile(nxt_controller_conf.root, value, 617*51Svbart@nginx.com &ops, &path, c->mem_pool); 61846Svbart@nginx.com 619*51Svbart@nginx.com if (rc != NXT_OK) { 620*51Svbart@nginx.com if (rc == NXT_DECLINED) { 621*51Svbart@nginx.com status = 404; 622*51Svbart@nginx.com goto done; 623*51Svbart@nginx.com } 62446Svbart@nginx.com 625*51Svbart@nginx.com status = 500; 626*51Svbart@nginx.com goto done; 627*51Svbart@nginx.com } 628*51Svbart@nginx.com 629*51Svbart@nginx.com value = nxt_conf_json_clone_value(nxt_controller_conf.root, 630*51Svbart@nginx.com ops, mp); 631*51Svbart@nginx.com 632*51Svbart@nginx.com if (nxt_slow_path(value == NULL)) { 633*51Svbart@nginx.com nxt_mem_pool_destroy(mp); 634*51Svbart@nginx.com status = 500; 635*51Svbart@nginx.com goto done; 636*51Svbart@nginx.com } 63746Svbart@nginx.com } 63844Svbart@nginx.com 639*51Svbart@nginx.com nxt_mem_pool_destroy(nxt_controller_conf.pool); 640*51Svbart@nginx.com 641*51Svbart@nginx.com nxt_controller_conf.root = value; 642*51Svbart@nginx.com nxt_controller_conf.pool = mp; 64344Svbart@nginx.com 644*51Svbart@nginx.com nxt_str_set(&resp.json_string, "{ \"success\": \"Updated.\" }"); 645*51Svbart@nginx.com 646*51Svbart@nginx.com status = 200; 647*51Svbart@nginx.com goto done; 648*51Svbart@nginx.com } 64927Svbart@nginx.com 650*51Svbart@nginx.com if (nxt_str_eq(&req->parser.method, "DELETE", 6)) { 651*51Svbart@nginx.com 652*51Svbart@nginx.com if (path.length == 1) { 653*51Svbart@nginx.com mp = nxt_mem_pool_create(128); 65444Svbart@nginx.com 655*51Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 656*51Svbart@nginx.com status = 500; 657*51Svbart@nginx.com goto done; 658*51Svbart@nginx.com } 659*51Svbart@nginx.com 660*51Svbart@nginx.com value = nxt_conf_json_parse(empty_obj.start, empty_obj.length, mp); 66127Svbart@nginx.com 66244Svbart@nginx.com } else { 663*51Svbart@nginx.com rc = nxt_conf_json_op_compile(nxt_controller_conf.root, NULL, &ops, 664*51Svbart@nginx.com &path, c->mem_pool); 665*51Svbart@nginx.com 666*51Svbart@nginx.com if (rc != NXT_OK) { 667*51Svbart@nginx.com if (rc == NXT_DECLINED) { 668*51Svbart@nginx.com status = 404; 669*51Svbart@nginx.com goto done; 670*51Svbart@nginx.com } 671*51Svbart@nginx.com 672*51Svbart@nginx.com status = 500; 673*51Svbart@nginx.com goto done; 674*51Svbart@nginx.com } 675*51Svbart@nginx.com 676*51Svbart@nginx.com mp = nxt_mem_pool_create(512); 677*51Svbart@nginx.com 678*51Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 679*51Svbart@nginx.com status = 500; 680*51Svbart@nginx.com goto done; 681*51Svbart@nginx.com } 682*51Svbart@nginx.com 683*51Svbart@nginx.com value = nxt_conf_json_clone_value(nxt_controller_conf.root, 684*51Svbart@nginx.com ops, mp); 685*51Svbart@nginx.com } 686*51Svbart@nginx.com 687*51Svbart@nginx.com if (nxt_slow_path(value == NULL)) { 688*51Svbart@nginx.com nxt_mem_pool_destroy(mp); 689*51Svbart@nginx.com status = 500; 690*51Svbart@nginx.com goto done; 69144Svbart@nginx.com } 69244Svbart@nginx.com 693*51Svbart@nginx.com nxt_mem_pool_destroy(nxt_controller_conf.pool); 694*51Svbart@nginx.com 695*51Svbart@nginx.com nxt_controller_conf.root = value; 696*51Svbart@nginx.com nxt_controller_conf.pool = mp; 697*51Svbart@nginx.com 698*51Svbart@nginx.com nxt_str_set(&resp.json_string, "{ \"success\": \"Deleted.\" }"); 699*51Svbart@nginx.com 700*51Svbart@nginx.com status = 200; 701*51Svbart@nginx.com goto done; 702*51Svbart@nginx.com } 703*51Svbart@nginx.com 704*51Svbart@nginx.com status = 405; 705*51Svbart@nginx.com 706*51Svbart@nginx.com done: 707*51Svbart@nginx.com 708*51Svbart@nginx.com switch (status) { 709*51Svbart@nginx.com 710*51Svbart@nginx.com case 200: 711*51Svbart@nginx.com nxt_str_set(&resp.status_line, "200 OK"); 712*51Svbart@nginx.com break; 713*51Svbart@nginx.com 714*51Svbart@nginx.com case 400: 715*51Svbart@nginx.com nxt_str_set(&resp.status_line, "400 Bad Request"); 716*51Svbart@nginx.com nxt_str_set(&resp.json_string, 717*51Svbart@nginx.com "{ \"error\": \"Invalid JSON.\" }"); 718*51Svbart@nginx.com break; 719*51Svbart@nginx.com 720*51Svbart@nginx.com case 404: 721*51Svbart@nginx.com nxt_str_set(&resp.status_line, "404 Not Found"); 722*51Svbart@nginx.com nxt_str_set(&resp.json_string, 723*51Svbart@nginx.com "{ \"error\": \"Value doesn't exist.\" }"); 724*51Svbart@nginx.com break; 725*51Svbart@nginx.com 726*51Svbart@nginx.com case 405: 72744Svbart@nginx.com nxt_str_set(&resp.status_line, "405 Method Not Allowed"); 728*51Svbart@nginx.com nxt_str_set(&resp.json_string, "{ \"error\": \"Invalid method.\" }"); 729*51Svbart@nginx.com break; 730*51Svbart@nginx.com 731*51Svbart@nginx.com case 500: 732*51Svbart@nginx.com nxt_str_set(&resp.status_line, "500 Internal Server Error"); 733*51Svbart@nginx.com nxt_str_set(&resp.json_string, 734*51Svbart@nginx.com "{ \"error\": \"Memory allocation failed.\" }"); 735*51Svbart@nginx.com break; 73629Svbart@nginx.com } 73727Svbart@nginx.com 73844Svbart@nginx.com if (nxt_controller_response(task, c, &resp) != NXT_OK) { 73944Svbart@nginx.com nxt_controller_conn_close(task, c, req); 74027Svbart@nginx.com } 74127Svbart@nginx.com } 74227Svbart@nginx.com 74327Svbart@nginx.com 74427Svbart@nginx.com static nxt_int_t 74544Svbart@nginx.com nxt_controller_response(nxt_task_t *task, nxt_event_conn_t *c, 74644Svbart@nginx.com nxt_controller_response_t *resp) 74733Svbart@nginx.com { 74844Svbart@nginx.com size_t size; 74933Svbart@nginx.com nxt_buf_t *b; 75033Svbart@nginx.com 75145Svbart@nginx.com size = sizeof("HTTP/1.0 " "\r\n\r\n") - 1 + resp->status_line.length; 75233Svbart@nginx.com 75344Svbart@nginx.com b = nxt_buf_mem_alloc(c->mem_pool, size, 0); 75433Svbart@nginx.com if (nxt_slow_path(b == NULL)) { 75544Svbart@nginx.com return NXT_ERROR; 75633Svbart@nginx.com } 75733Svbart@nginx.com 75844Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, "HTTP/1.0 ", sizeof("HTTP/1.0 ") - 1); 75944Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, resp->status_line.start, 76044Svbart@nginx.com resp->status_line.length); 76144Svbart@nginx.com 76244Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, "\r\n\r\n", sizeof("\r\n\r\n") - 1); 76344Svbart@nginx.com 76445Svbart@nginx.com b->next = nxt_controller_response_body(resp, c->mem_pool); 76545Svbart@nginx.com 76645Svbart@nginx.com if (nxt_slow_path(b->next == NULL)) { 76745Svbart@nginx.com return NXT_ERROR; 76844Svbart@nginx.com } 76933Svbart@nginx.com 77033Svbart@nginx.com c->write = b; 77144Svbart@nginx.com c->write_state = &nxt_controller_conn_write_state; 77233Svbart@nginx.com 77344Svbart@nginx.com nxt_event_conn_write(task->thread->engine, c); 77433Svbart@nginx.com 77544Svbart@nginx.com return NXT_OK; 77633Svbart@nginx.com } 77745Svbart@nginx.com 77845Svbart@nginx.com 77945Svbart@nginx.com static nxt_buf_t * 78045Svbart@nginx.com nxt_controller_response_body(nxt_controller_response_t *resp, 78145Svbart@nginx.com nxt_mem_pool_t *pool) 78245Svbart@nginx.com { 78345Svbart@nginx.com size_t size; 78445Svbart@nginx.com nxt_buf_t *b; 78545Svbart@nginx.com nxt_conf_json_value_t *value; 78645Svbart@nginx.com nxt_conf_json_pretty_t pretty; 78745Svbart@nginx.com 78845Svbart@nginx.com if (resp->json_value) { 78945Svbart@nginx.com value = resp->json_value; 79045Svbart@nginx.com 79145Svbart@nginx.com } else { 79245Svbart@nginx.com value = nxt_conf_json_parse(resp->json_string.start, 79345Svbart@nginx.com resp->json_string.length, pool); 79445Svbart@nginx.com 79545Svbart@nginx.com if (nxt_slow_path(value == NULL)) { 79645Svbart@nginx.com return NULL; 79745Svbart@nginx.com } 79845Svbart@nginx.com } 79945Svbart@nginx.com 80045Svbart@nginx.com nxt_memzero(&pretty, sizeof(nxt_conf_json_pretty_t)); 80145Svbart@nginx.com 80245Svbart@nginx.com size = nxt_conf_json_print_value(NULL, value, &pretty) + 2; 80345Svbart@nginx.com 80445Svbart@nginx.com b = nxt_buf_mem_alloc(pool, size, 0); 80545Svbart@nginx.com if (nxt_slow_path(b == NULL)) { 80645Svbart@nginx.com return NULL; 80745Svbart@nginx.com } 80845Svbart@nginx.com 80945Svbart@nginx.com nxt_memzero(&pretty, sizeof(nxt_conf_json_pretty_t)); 81045Svbart@nginx.com 81145Svbart@nginx.com b->mem.free = (u_char *) nxt_conf_json_print_value(b->mem.free, value, 81245Svbart@nginx.com &pretty); 81345Svbart@nginx.com 81445Svbart@nginx.com *b->mem.free++ = '\r'; 81545Svbart@nginx.com *b->mem.free++ = '\n'; 81645Svbart@nginx.com 81745Svbart@nginx.com return b; 81845Svbart@nginx.com } 819