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 { 15106Svbart@nginx.com nxt_conf_value_t *root; 16106Svbart@nginx.com 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; 2344Svbart@nginx.com nxt_controller_conf_t conf; 24140Svbart@nginx.com nxt_conn_t *conn; 25140Svbart@nginx.com nxt_queue_link_t link; 2627Svbart@nginx.com } nxt_controller_request_t; 2727Svbart@nginx.com 2827Svbart@nginx.com 2944Svbart@nginx.com typedef struct { 30208Svbart@nginx.com nxt_uint_t status; 31106Svbart@nginx.com nxt_conf_value_t *conf; 32208Svbart@nginx.com 33208Svbart@nginx.com u_char *title; 34208Svbart@nginx.com u_char *detail; 35208Svbart@nginx.com ssize_t offset; 36208Svbart@nginx.com nxt_uint_t line; 37208Svbart@nginx.com nxt_uint_t column; 3844Svbart@nginx.com } nxt_controller_response_t; 3944Svbart@nginx.com 4044Svbart@nginx.com 4120Sigor@sysoev.ru static void nxt_controller_conn_init(nxt_task_t *task, void *obj, void *data); 4220Sigor@sysoev.ru static void nxt_controller_conn_read(nxt_task_t *task, void *obj, void *data); 4362Sigor@sysoev.ru static nxt_msec_t nxt_controller_conn_timeout_value(nxt_conn_t *c, 4420Sigor@sysoev.ru uintptr_t data); 4520Sigor@sysoev.ru static void nxt_controller_conn_read_error(nxt_task_t *task, void *obj, 4620Sigor@sysoev.ru void *data); 4720Sigor@sysoev.ru static void nxt_controller_conn_read_timeout(nxt_task_t *task, void *obj, 4820Sigor@sysoev.ru void *data); 4927Svbart@nginx.com static void nxt_controller_conn_body_read(nxt_task_t *task, void *obj, 5027Svbart@nginx.com void *data); 5127Svbart@nginx.com static void nxt_controller_conn_write(nxt_task_t *task, void *obj, void *data); 5227Svbart@nginx.com static void nxt_controller_conn_write_error(nxt_task_t *task, void *obj, 5327Svbart@nginx.com void *data); 5427Svbart@nginx.com static void nxt_controller_conn_write_timeout(nxt_task_t *task, void *obj, 5527Svbart@nginx.com void *data); 5620Sigor@sysoev.ru static void nxt_controller_conn_close(nxt_task_t *task, void *obj, void *data); 5720Sigor@sysoev.ru static void nxt_controller_conn_free(nxt_task_t *task, void *obj, void *data); 5820Sigor@sysoev.ru 5927Svbart@nginx.com static nxt_int_t nxt_controller_request_content_length(void *ctx, 6067Svbart@nginx.com nxt_http_field_t *field, nxt_log_t *log); 6127Svbart@nginx.com 6227Svbart@nginx.com static void nxt_controller_process_request(nxt_task_t *task, 63140Svbart@nginx.com nxt_controller_request_t *req); 64121Svbart@nginx.com static nxt_int_t nxt_controller_conf_apply(nxt_task_t *task, 65140Svbart@nginx.com nxt_controller_request_t *req); 66*238Svbart@nginx.com static void nxt_controller_conf_handler(nxt_task_t *task, 67*238Svbart@nginx.com nxt_port_recv_msg_t *msg, void *data); 68140Svbart@nginx.com static void nxt_controller_response(nxt_task_t *task, 69140Svbart@nginx.com nxt_controller_request_t *req, nxt_controller_response_t *resp); 70208Svbart@nginx.com static u_char *nxt_controller_date(u_char *buf, nxt_realtime_t *now, 71208Svbart@nginx.com struct tm *tm, size_t size, const char *format); 7227Svbart@nginx.com 7327Svbart@nginx.com 7460Svbart@nginx.com static nxt_http_fields_hash_entry_t nxt_controller_request_fields[] = { 7527Svbart@nginx.com { nxt_string("Content-Length"), 7627Svbart@nginx.com &nxt_controller_request_content_length, 0 }, 7727Svbart@nginx.com 7827Svbart@nginx.com { nxt_null_string, NULL, 0 } 7927Svbart@nginx.com }; 8027Svbart@nginx.com 8160Svbart@nginx.com static nxt_http_fields_hash_t *nxt_controller_fields_hash; 8227Svbart@nginx.com 83*238Svbart@nginx.com static nxt_controller_conf_t nxt_controller_conf; 84*238Svbart@nginx.com static nxt_queue_t nxt_controller_waiting_requests; 8527Svbart@nginx.com 8620Sigor@sysoev.ru 8720Sigor@sysoev.ru static const nxt_event_conn_state_t nxt_controller_conn_read_state; 8827Svbart@nginx.com static const nxt_event_conn_state_t nxt_controller_conn_body_read_state; 8927Svbart@nginx.com static const nxt_event_conn_state_t nxt_controller_conn_write_state; 9020Sigor@sysoev.ru static const nxt_event_conn_state_t nxt_controller_conn_close_state; 9120Sigor@sysoev.ru 9220Sigor@sysoev.ru 9320Sigor@sysoev.ru nxt_int_t 94141Smax.romanov@nginx.com nxt_controller_start(nxt_task_t *task, void *data) 9520Sigor@sysoev.ru { 9665Sigor@sysoev.ru nxt_mp_t *mp; 97141Smax.romanov@nginx.com nxt_runtime_t *rt; 98106Svbart@nginx.com nxt_conf_value_t *conf; 9927Svbart@nginx.com nxt_http_fields_hash_t *hash; 10027Svbart@nginx.com 10144Svbart@nginx.com static const nxt_str_t json 102116Svbart@nginx.com = nxt_string("{ \"listeners\": {}, \"applications\": {} }"); 10344Svbart@nginx.com 104141Smax.romanov@nginx.com rt = task->thread->runtime; 105141Smax.romanov@nginx.com 10660Svbart@nginx.com hash = nxt_http_fields_hash_create(nxt_controller_request_fields, 10760Svbart@nginx.com rt->mem_pool); 10827Svbart@nginx.com if (nxt_slow_path(hash == NULL)) { 10927Svbart@nginx.com return NXT_ERROR; 11027Svbart@nginx.com } 11127Svbart@nginx.com 11260Svbart@nginx.com nxt_controller_fields_hash = hash; 11327Svbart@nginx.com 11454Sigor@sysoev.ru if (nxt_listen_event(task, rt->controller_socket) == NULL) { 11520Sigor@sysoev.ru return NXT_ERROR; 11620Sigor@sysoev.ru } 11720Sigor@sysoev.ru 11865Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 11944Svbart@nginx.com 12044Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 12144Svbart@nginx.com return NXT_ERROR; 12244Svbart@nginx.com } 12344Svbart@nginx.com 124106Svbart@nginx.com conf = nxt_conf_json_parse_str(mp, &json); 12544Svbart@nginx.com 12644Svbart@nginx.com if (conf == NULL) { 12744Svbart@nginx.com return NXT_ERROR; 12844Svbart@nginx.com } 12944Svbart@nginx.com 13044Svbart@nginx.com nxt_controller_conf.root = conf; 13144Svbart@nginx.com nxt_controller_conf.pool = mp; 13244Svbart@nginx.com 133140Svbart@nginx.com nxt_queue_init(&nxt_controller_waiting_requests); 134140Svbart@nginx.com 13520Sigor@sysoev.ru return NXT_OK; 13620Sigor@sysoev.ru } 13720Sigor@sysoev.ru 13820Sigor@sysoev.ru 13920Sigor@sysoev.ru nxt_int_t 14020Sigor@sysoev.ru nxt_runtime_controller_socket(nxt_task_t *task, nxt_runtime_t *rt) 14120Sigor@sysoev.ru { 14220Sigor@sysoev.ru nxt_sockaddr_t *sa; 14320Sigor@sysoev.ru nxt_listen_socket_t *ls; 14420Sigor@sysoev.ru 14520Sigor@sysoev.ru sa = rt->controller_listen; 14620Sigor@sysoev.ru 14765Sigor@sysoev.ru ls = nxt_mp_alloc(rt->mem_pool, sizeof(nxt_listen_socket_t)); 14820Sigor@sysoev.ru if (ls == NULL) { 14920Sigor@sysoev.ru return NXT_ERROR; 15020Sigor@sysoev.ru } 15120Sigor@sysoev.ru 15220Sigor@sysoev.ru ls->sockaddr = nxt_sockaddr_create(rt->mem_pool, &sa->u.sockaddr, 15320Sigor@sysoev.ru sa->socklen, sa->length); 15420Sigor@sysoev.ru if (ls->sockaddr == NULL) { 15520Sigor@sysoev.ru return NXT_ERROR; 15620Sigor@sysoev.ru } 15720Sigor@sysoev.ru 15820Sigor@sysoev.ru ls->sockaddr->type = sa->type; 159103Sigor@sysoev.ru ls->socklen = sa->socklen; 160103Sigor@sysoev.ru ls->address_length = sa->length; 16120Sigor@sysoev.ru 16220Sigor@sysoev.ru nxt_sockaddr_text(ls->sockaddr); 16320Sigor@sysoev.ru 16420Sigor@sysoev.ru ls->socket = -1; 16520Sigor@sysoev.ru ls->backlog = NXT_LISTEN_BACKLOG; 16620Sigor@sysoev.ru ls->read_after_accept = 1; 16720Sigor@sysoev.ru ls->flags = NXT_NONBLOCK; 16820Sigor@sysoev.ru 16920Sigor@sysoev.ru #if 0 17020Sigor@sysoev.ru /* STUB */ 17165Sigor@sysoev.ru wq = nxt_mp_zget(cf->mem_pool, sizeof(nxt_work_queue_t)); 17220Sigor@sysoev.ru if (wq == NULL) { 17320Sigor@sysoev.ru return NXT_ERROR; 17420Sigor@sysoev.ru } 17520Sigor@sysoev.ru nxt_work_queue_name(wq, "listen"); 17620Sigor@sysoev.ru /**/ 17720Sigor@sysoev.ru 17820Sigor@sysoev.ru ls->work_queue = wq; 17920Sigor@sysoev.ru #endif 18020Sigor@sysoev.ru ls->handler = nxt_controller_conn_init; 18120Sigor@sysoev.ru 18220Sigor@sysoev.ru if (nxt_listen_socket_create(task, ls, 0) != NXT_OK) { 18320Sigor@sysoev.ru return NXT_ERROR; 18420Sigor@sysoev.ru } 18520Sigor@sysoev.ru 18620Sigor@sysoev.ru rt->controller_socket = ls; 18720Sigor@sysoev.ru 18820Sigor@sysoev.ru return NXT_OK; 18920Sigor@sysoev.ru } 19020Sigor@sysoev.ru 19120Sigor@sysoev.ru 19220Sigor@sysoev.ru static void 19320Sigor@sysoev.ru nxt_controller_conn_init(nxt_task_t *task, void *obj, void *data) 19420Sigor@sysoev.ru { 19527Svbart@nginx.com nxt_buf_t *b; 19662Sigor@sysoev.ru nxt_conn_t *c; 19727Svbart@nginx.com nxt_event_engine_t *engine; 19827Svbart@nginx.com nxt_controller_request_t *r; 19920Sigor@sysoev.ru 20020Sigor@sysoev.ru c = obj; 20120Sigor@sysoev.ru 20220Sigor@sysoev.ru nxt_debug(task, "controller conn init fd:%d", c->socket.fd); 20320Sigor@sysoev.ru 20465Sigor@sysoev.ru r = nxt_mp_zget(c->mem_pool, sizeof(nxt_controller_request_t)); 20527Svbart@nginx.com if (nxt_slow_path(r == NULL)) { 20627Svbart@nginx.com nxt_controller_conn_free(task, c, NULL); 20727Svbart@nginx.com return; 20827Svbart@nginx.com } 20927Svbart@nginx.com 210140Svbart@nginx.com r->conn = c; 211140Svbart@nginx.com 21260Svbart@nginx.com if (nxt_slow_path(nxt_http_parse_request_init(&r->parser, c->mem_pool) 21360Svbart@nginx.com != NXT_OK)) 21460Svbart@nginx.com { 21560Svbart@nginx.com nxt_controller_conn_free(task, c, NULL); 21660Svbart@nginx.com return; 21760Svbart@nginx.com } 21827Svbart@nginx.com 21967Svbart@nginx.com r->parser.fields_hash = nxt_controller_fields_hash; 22067Svbart@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 23662Sigor@sysoev.ru nxt_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 { 24356Sigor@sysoev.ru .ready_handler = nxt_controller_conn_read, 24456Sigor@sysoev.ru .close_handler = nxt_controller_conn_close, 24556Sigor@sysoev.ru .error_handler = nxt_controller_conn_read_error, 24620Sigor@sysoev.ru 24756Sigor@sysoev.ru .timer_handler = nxt_controller_conn_read_timeout, 24856Sigor@sysoev.ru .timer_value = nxt_controller_conn_timeout_value, 24956Sigor@sysoev.ru .timer_data = 60 * 1000, 25020Sigor@sysoev.ru }; 25120Sigor@sysoev.ru 25220Sigor@sysoev.ru 25320Sigor@sysoev.ru static void 25420Sigor@sysoev.ru nxt_controller_conn_read(nxt_task_t *task, void *obj, void *data) 25520Sigor@sysoev.ru { 25627Svbart@nginx.com size_t preread; 25727Svbart@nginx.com nxt_buf_t *b; 25827Svbart@nginx.com nxt_int_t rc; 25962Sigor@sysoev.ru nxt_conn_t *c; 26027Svbart@nginx.com nxt_controller_request_t *r; 26120Sigor@sysoev.ru 26220Sigor@sysoev.ru c = obj; 26327Svbart@nginx.com r = data; 26420Sigor@sysoev.ru 26520Sigor@sysoev.ru nxt_debug(task, "controller conn read"); 26620Sigor@sysoev.ru 26727Svbart@nginx.com nxt_queue_remove(&c->link); 26827Svbart@nginx.com nxt_queue_self(&c->link); 26927Svbart@nginx.com 27027Svbart@nginx.com b = c->read; 27127Svbart@nginx.com 27227Svbart@nginx.com rc = nxt_http_parse_request(&r->parser, &b->mem); 27327Svbart@nginx.com 27427Svbart@nginx.com if (nxt_slow_path(rc != NXT_DONE)) { 27527Svbart@nginx.com 27627Svbart@nginx.com if (rc == NXT_AGAIN) { 27727Svbart@nginx.com if (nxt_buf_mem_free_size(&b->mem) == 0) { 27827Svbart@nginx.com nxt_log(task, NXT_LOG_ERR, "too long request headers"); 27927Svbart@nginx.com nxt_controller_conn_close(task, c, r); 28027Svbart@nginx.com return; 28127Svbart@nginx.com } 28227Svbart@nginx.com 28362Sigor@sysoev.ru nxt_conn_read(task->thread->engine, c); 28427Svbart@nginx.com return; 28527Svbart@nginx.com } 28627Svbart@nginx.com 28727Svbart@nginx.com /* rc == NXT_ERROR */ 28827Svbart@nginx.com 28927Svbart@nginx.com nxt_log(task, NXT_LOG_ERR, "parsing error"); 29027Svbart@nginx.com 29127Svbart@nginx.com nxt_controller_conn_close(task, c, r); 29227Svbart@nginx.com return; 29327Svbart@nginx.com } 29427Svbart@nginx.com 29567Svbart@nginx.com rc = nxt_http_fields_process(r->parser.fields, r, task->log); 29660Svbart@nginx.com 29760Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 29860Svbart@nginx.com nxt_controller_conn_close(task, c, r); 29960Svbart@nginx.com return; 30060Svbart@nginx.com } 30160Svbart@nginx.com 30227Svbart@nginx.com preread = nxt_buf_mem_used_size(&b->mem); 30327Svbart@nginx.com 30427Svbart@nginx.com nxt_debug(task, "controller request header parsing complete, " 305107Svbart@nginx.com "body length: %uz, preread: %uz", 30627Svbart@nginx.com r->length, preread); 30727Svbart@nginx.com 30827Svbart@nginx.com if (preread >= r->length) { 309140Svbart@nginx.com nxt_controller_process_request(task, r); 31027Svbart@nginx.com return; 31127Svbart@nginx.com } 31227Svbart@nginx.com 31327Svbart@nginx.com if (r->length - preread > (size_t) nxt_buf_mem_free_size(&b->mem)) { 31427Svbart@nginx.com b = nxt_buf_mem_alloc(c->mem_pool, r->length, 0); 31527Svbart@nginx.com if (nxt_slow_path(b == NULL)) { 31627Svbart@nginx.com nxt_controller_conn_free(task, c, NULL); 31727Svbart@nginx.com return; 31827Svbart@nginx.com } 31927Svbart@nginx.com 32027Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, c->read->mem.pos, preread); 32127Svbart@nginx.com 32227Svbart@nginx.com c->read = b; 32327Svbart@nginx.com } 32427Svbart@nginx.com 32527Svbart@nginx.com c->read_state = &nxt_controller_conn_body_read_state; 32627Svbart@nginx.com 32762Sigor@sysoev.ru nxt_conn_read(task->thread->engine, c); 32820Sigor@sysoev.ru } 32920Sigor@sysoev.ru 33020Sigor@sysoev.ru 33120Sigor@sysoev.ru static nxt_msec_t 33262Sigor@sysoev.ru nxt_controller_conn_timeout_value(nxt_conn_t *c, uintptr_t data) 33320Sigor@sysoev.ru { 33420Sigor@sysoev.ru return (nxt_msec_t) data; 33520Sigor@sysoev.ru } 33620Sigor@sysoev.ru 33720Sigor@sysoev.ru 33820Sigor@sysoev.ru static void 33920Sigor@sysoev.ru nxt_controller_conn_read_error(nxt_task_t *task, void *obj, void *data) 34020Sigor@sysoev.ru { 34162Sigor@sysoev.ru nxt_conn_t *c; 34220Sigor@sysoev.ru 34320Sigor@sysoev.ru c = obj; 34420Sigor@sysoev.ru 34520Sigor@sysoev.ru nxt_debug(task, "controller conn read error"); 34620Sigor@sysoev.ru 34727Svbart@nginx.com nxt_controller_conn_close(task, c, data); 34820Sigor@sysoev.ru } 34920Sigor@sysoev.ru 35020Sigor@sysoev.ru 35120Sigor@sysoev.ru static void 35220Sigor@sysoev.ru nxt_controller_conn_read_timeout(nxt_task_t *task, void *obj, void *data) 35320Sigor@sysoev.ru { 35462Sigor@sysoev.ru nxt_timer_t *timer; 35562Sigor@sysoev.ru nxt_conn_t *c; 35620Sigor@sysoev.ru 35762Sigor@sysoev.ru timer = obj; 35820Sigor@sysoev.ru 35962Sigor@sysoev.ru c = nxt_read_timer_conn(timer); 36020Sigor@sysoev.ru c->socket.timedout = 1; 36120Sigor@sysoev.ru c->socket.closed = 1; 36220Sigor@sysoev.ru 36320Sigor@sysoev.ru nxt_debug(task, "controller conn read timeout"); 36420Sigor@sysoev.ru 36527Svbart@nginx.com nxt_controller_conn_close(task, c, data); 36627Svbart@nginx.com } 36727Svbart@nginx.com 36827Svbart@nginx.com 36927Svbart@nginx.com static const nxt_event_conn_state_t nxt_controller_conn_body_read_state 37027Svbart@nginx.com nxt_aligned(64) = 37127Svbart@nginx.com { 37256Sigor@sysoev.ru .ready_handler = nxt_controller_conn_body_read, 37356Sigor@sysoev.ru .close_handler = nxt_controller_conn_close, 37456Sigor@sysoev.ru .error_handler = nxt_controller_conn_read_error, 37527Svbart@nginx.com 37656Sigor@sysoev.ru .timer_handler = nxt_controller_conn_read_timeout, 37756Sigor@sysoev.ru .timer_value = nxt_controller_conn_timeout_value, 37856Sigor@sysoev.ru .timer_data = 60 * 1000, 37956Sigor@sysoev.ru .timer_autoreset = 1, 38027Svbart@nginx.com }; 38127Svbart@nginx.com 38227Svbart@nginx.com 38327Svbart@nginx.com static void 38427Svbart@nginx.com nxt_controller_conn_body_read(nxt_task_t *task, void *obj, void *data) 38527Svbart@nginx.com { 386107Svbart@nginx.com size_t read; 387107Svbart@nginx.com nxt_buf_t *b; 388107Svbart@nginx.com nxt_conn_t *c; 389107Svbart@nginx.com nxt_controller_request_t *r; 39027Svbart@nginx.com 39127Svbart@nginx.com c = obj; 392107Svbart@nginx.com r = data; 39327Svbart@nginx.com b = c->read; 39427Svbart@nginx.com 395107Svbart@nginx.com read = nxt_buf_mem_used_size(&b->mem); 39627Svbart@nginx.com 397107Svbart@nginx.com nxt_debug(task, "controller conn body read: %uz of %uz", 398107Svbart@nginx.com read, r->length); 39927Svbart@nginx.com 400107Svbart@nginx.com if (read >= r->length) { 401140Svbart@nginx.com nxt_controller_process_request(task, r); 40227Svbart@nginx.com return; 40327Svbart@nginx.com } 40427Svbart@nginx.com 40562Sigor@sysoev.ru nxt_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 { 41256Sigor@sysoev.ru .ready_handler = nxt_controller_conn_write, 41356Sigor@sysoev.ru .error_handler = nxt_controller_conn_write_error, 41427Svbart@nginx.com 41556Sigor@sysoev.ru .timer_handler = nxt_controller_conn_write_timeout, 41656Sigor@sysoev.ru .timer_value = nxt_controller_conn_timeout_value, 41756Sigor@sysoev.ru .timer_data = 60 * 1000, 41856Sigor@sysoev.ru .timer_autoreset = 1, 41927Svbart@nginx.com }; 42027Svbart@nginx.com 42127Svbart@nginx.com 42227Svbart@nginx.com static void 42327Svbart@nginx.com nxt_controller_conn_write(nxt_task_t *task, void *obj, void *data) 42427Svbart@nginx.com { 42562Sigor@sysoev.ru nxt_buf_t *b; 42662Sigor@sysoev.ru nxt_conn_t *c; 42727Svbart@nginx.com 42827Svbart@nginx.com c = obj; 42927Svbart@nginx.com 43027Svbart@nginx.com nxt_debug(task, "controller conn write"); 43127Svbart@nginx.com 43227Svbart@nginx.com b = c->write; 43327Svbart@nginx.com 43427Svbart@nginx.com if (b->mem.pos != b->mem.free) { 43562Sigor@sysoev.ru nxt_conn_write(task->thread->engine, c); 43627Svbart@nginx.com return; 43727Svbart@nginx.com } 43827Svbart@nginx.com 43927Svbart@nginx.com nxt_debug(task, "controller conn write complete"); 44027Svbart@nginx.com 44127Svbart@nginx.com nxt_controller_conn_close(task, c, data); 44227Svbart@nginx.com } 44327Svbart@nginx.com 44427Svbart@nginx.com 44527Svbart@nginx.com static void 44627Svbart@nginx.com nxt_controller_conn_write_error(nxt_task_t *task, void *obj, void *data) 44727Svbart@nginx.com { 44862Sigor@sysoev.ru nxt_conn_t *c; 44927Svbart@nginx.com 45027Svbart@nginx.com c = obj; 45127Svbart@nginx.com 45227Svbart@nginx.com nxt_debug(task, "controller conn write error"); 45327Svbart@nginx.com 45427Svbart@nginx.com nxt_controller_conn_close(task, c, data); 45527Svbart@nginx.com } 45627Svbart@nginx.com 45727Svbart@nginx.com 45827Svbart@nginx.com static void 45927Svbart@nginx.com nxt_controller_conn_write_timeout(nxt_task_t *task, void *obj, void *data) 46027Svbart@nginx.com { 46162Sigor@sysoev.ru nxt_conn_t *c; 46262Sigor@sysoev.ru nxt_timer_t *timer; 46327Svbart@nginx.com 46462Sigor@sysoev.ru timer = obj; 46527Svbart@nginx.com 46662Sigor@sysoev.ru c = nxt_write_timer_conn(timer); 46727Svbart@nginx.com c->socket.timedout = 1; 46827Svbart@nginx.com c->socket.closed = 1; 46927Svbart@nginx.com 47027Svbart@nginx.com nxt_debug(task, "controller conn write timeout"); 47127Svbart@nginx.com 47227Svbart@nginx.com nxt_controller_conn_close(task, c, data); 47320Sigor@sysoev.ru } 47420Sigor@sysoev.ru 47520Sigor@sysoev.ru 47620Sigor@sysoev.ru static const nxt_event_conn_state_t nxt_controller_conn_close_state 47720Sigor@sysoev.ru nxt_aligned(64) = 47820Sigor@sysoev.ru { 47956Sigor@sysoev.ru .ready_handler = nxt_controller_conn_free, 48020Sigor@sysoev.ru }; 48120Sigor@sysoev.ru 48220Sigor@sysoev.ru 48320Sigor@sysoev.ru static void 48420Sigor@sysoev.ru nxt_controller_conn_close(nxt_task_t *task, void *obj, void *data) 48520Sigor@sysoev.ru { 48662Sigor@sysoev.ru nxt_conn_t *c; 48720Sigor@sysoev.ru 48820Sigor@sysoev.ru c = obj; 48920Sigor@sysoev.ru 49020Sigor@sysoev.ru nxt_debug(task, "controller conn close"); 49120Sigor@sysoev.ru 49227Svbart@nginx.com nxt_queue_remove(&c->link); 49327Svbart@nginx.com 49420Sigor@sysoev.ru c->write_state = &nxt_controller_conn_close_state; 49520Sigor@sysoev.ru 49662Sigor@sysoev.ru nxt_conn_close(task->thread->engine, c); 49720Sigor@sysoev.ru } 49820Sigor@sysoev.ru 49920Sigor@sysoev.ru 50020Sigor@sysoev.ru static void 50120Sigor@sysoev.ru nxt_controller_conn_free(nxt_task_t *task, void *obj, void *data) 50220Sigor@sysoev.ru { 50362Sigor@sysoev.ru nxt_conn_t *c; 50420Sigor@sysoev.ru 50520Sigor@sysoev.ru c = obj; 50620Sigor@sysoev.ru 50720Sigor@sysoev.ru nxt_debug(task, "controller conn free"); 50820Sigor@sysoev.ru 50965Sigor@sysoev.ru nxt_mp_destroy(c->mem_pool); 51020Sigor@sysoev.ru 51120Sigor@sysoev.ru //nxt_free(c); 51220Sigor@sysoev.ru } 51327Svbart@nginx.com 51427Svbart@nginx.com 51527Svbart@nginx.com static nxt_int_t 51660Svbart@nginx.com nxt_controller_request_content_length(void *ctx, nxt_http_field_t *field, 51767Svbart@nginx.com nxt_log_t *log) 51827Svbart@nginx.com { 51927Svbart@nginx.com off_t length; 52027Svbart@nginx.com nxt_controller_request_t *r; 52127Svbart@nginx.com 52227Svbart@nginx.com r = ctx; 52327Svbart@nginx.com 52460Svbart@nginx.com length = nxt_off_t_parse(field->value.start, field->value.length); 52527Svbart@nginx.com 52627Svbart@nginx.com if (nxt_fast_path(length > 0)) { 527107Svbart@nginx.com 528107Svbart@nginx.com if (nxt_slow_path(length > NXT_SIZE_T_MAX)) { 529107Svbart@nginx.com nxt_log_error(NXT_LOG_ERR, log, "Content-Length is too big"); 530107Svbart@nginx.com return NXT_ERROR; 531107Svbart@nginx.com } 53227Svbart@nginx.com 53327Svbart@nginx.com r->length = length; 53427Svbart@nginx.com return NXT_OK; 53527Svbart@nginx.com } 53627Svbart@nginx.com 53760Svbart@nginx.com nxt_log_error(NXT_LOG_ERR, log, "Content-Length is invalid"); 53827Svbart@nginx.com 53927Svbart@nginx.com return NXT_ERROR; 54027Svbart@nginx.com } 54127Svbart@nginx.com 54227Svbart@nginx.com 54327Svbart@nginx.com static void 544140Svbart@nginx.com nxt_controller_process_request(nxt_task_t *task, nxt_controller_request_t *req) 54527Svbart@nginx.com { 54665Sigor@sysoev.ru nxt_mp_t *mp; 54751Svbart@nginx.com nxt_int_t rc; 54846Svbart@nginx.com nxt_str_t path; 549140Svbart@nginx.com nxt_conn_t *c; 55051Svbart@nginx.com nxt_buf_mem_t *mbuf; 551106Svbart@nginx.com nxt_conf_op_t *ops; 552106Svbart@nginx.com nxt_conf_value_t *value; 553208Svbart@nginx.com nxt_conf_json_error_t error; 55444Svbart@nginx.com nxt_controller_response_t resp; 55544Svbart@nginx.com 55651Svbart@nginx.com static const nxt_str_t empty_obj = nxt_string("{}"); 55751Svbart@nginx.com 558140Svbart@nginx.com c = req->conn; 559112Smax.romanov@nginx.com path = req->parser.path; 56051Svbart@nginx.com 56151Svbart@nginx.com if (path.length > 1 && path.start[path.length - 1] == '/') { 56251Svbart@nginx.com path.length--; 56351Svbart@nginx.com } 56451Svbart@nginx.com 56544Svbart@nginx.com nxt_memzero(&resp, sizeof(nxt_controller_response_t)); 56644Svbart@nginx.com 56744Svbart@nginx.com if (nxt_str_eq(&req->parser.method, "GET", 3)) { 56846Svbart@nginx.com 569106Svbart@nginx.com value = nxt_conf_get_path(nxt_controller_conf.root, &path); 57051Svbart@nginx.com 57151Svbart@nginx.com if (value == NULL) { 572208Svbart@nginx.com goto not_found; 57351Svbart@nginx.com } 57451Svbart@nginx.com 575208Svbart@nginx.com resp.status = 200; 576106Svbart@nginx.com resp.conf = value; 57746Svbart@nginx.com 578208Svbart@nginx.com nxt_controller_response(task, req, &resp); 579208Svbart@nginx.com return; 58051Svbart@nginx.com } 58151Svbart@nginx.com 58251Svbart@nginx.com if (nxt_str_eq(&req->parser.method, "PUT", 3)) { 58346Svbart@nginx.com 584*238Svbart@nginx.com if (!nxt_queue_is_empty(&nxt_controller_waiting_requests)) { 585*238Svbart@nginx.com nxt_queue_insert_tail(&nxt_controller_waiting_requests, &req->link); 586*238Svbart@nginx.com return; 587*238Svbart@nginx.com } 588*238Svbart@nginx.com 58965Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 59051Svbart@nginx.com 59151Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 592208Svbart@nginx.com goto alloc_fail; 59346Svbart@nginx.com } 59446Svbart@nginx.com 59551Svbart@nginx.com mbuf = &c->read->mem; 59651Svbart@nginx.com 597208Svbart@nginx.com nxt_memzero(&error, sizeof(nxt_conf_json_error_t)); 598208Svbart@nginx.com 599208Svbart@nginx.com value = nxt_conf_json_parse(mp, mbuf->pos, mbuf->free, &error); 60051Svbart@nginx.com 60151Svbart@nginx.com if (value == NULL) { 60265Sigor@sysoev.ru nxt_mp_destroy(mp); 603208Svbart@nginx.com 604208Svbart@nginx.com if (error.pos == NULL) { 605208Svbart@nginx.com goto alloc_fail; 606208Svbart@nginx.com } 607208Svbart@nginx.com 608208Svbart@nginx.com resp.status = 400; 609208Svbart@nginx.com resp.title = (u_char *) "Invalid JSON."; 610208Svbart@nginx.com resp.detail = error.detail; 611208Svbart@nginx.com resp.offset = error.pos - mbuf->pos; 612208Svbart@nginx.com 613208Svbart@nginx.com nxt_conf_json_position(mbuf->pos, error.pos, 614208Svbart@nginx.com &resp.line, &resp.column); 615208Svbart@nginx.com 616208Svbart@nginx.com nxt_controller_response(task, req, &resp); 617208Svbart@nginx.com return; 61851Svbart@nginx.com } 61951Svbart@nginx.com 62051Svbart@nginx.com if (path.length != 1) { 621106Svbart@nginx.com rc = nxt_conf_op_compile(c->mem_pool, &ops, 622106Svbart@nginx.com nxt_controller_conf.root, 623106Svbart@nginx.com &path, value); 62446Svbart@nginx.com 62551Svbart@nginx.com if (rc != NXT_OK) { 62651Svbart@nginx.com if (rc == NXT_DECLINED) { 627208Svbart@nginx.com goto not_found; 62851Svbart@nginx.com } 62946Svbart@nginx.com 630208Svbart@nginx.com goto alloc_fail; 63151Svbart@nginx.com } 63251Svbart@nginx.com 633106Svbart@nginx.com value = nxt_conf_clone(mp, ops, nxt_controller_conf.root); 63451Svbart@nginx.com 63551Svbart@nginx.com if (nxt_slow_path(value == NULL)) { 63665Sigor@sysoev.ru nxt_mp_destroy(mp); 637208Svbart@nginx.com goto alloc_fail; 63851Svbart@nginx.com } 63946Svbart@nginx.com } 64044Svbart@nginx.com 641116Svbart@nginx.com if (nxt_slow_path(nxt_conf_validate(value) != NXT_OK)) { 642121Svbart@nginx.com nxt_mp_destroy(mp); 643208Svbart@nginx.com goto invalid_conf; 644116Svbart@nginx.com } 645116Svbart@nginx.com 646140Svbart@nginx.com req->conf.root = value; 647140Svbart@nginx.com req->conf.pool = mp; 648140Svbart@nginx.com 649140Svbart@nginx.com if (nxt_controller_conf_apply(task, req) != NXT_OK) { 650121Svbart@nginx.com nxt_mp_destroy(mp); 651208Svbart@nginx.com goto alloc_fail; 652121Svbart@nginx.com } 653121Svbart@nginx.com 654140Svbart@nginx.com return; 65551Svbart@nginx.com } 65627Svbart@nginx.com 65751Svbart@nginx.com if (nxt_str_eq(&req->parser.method, "DELETE", 6)) { 65851Svbart@nginx.com 659*238Svbart@nginx.com if (!nxt_queue_is_empty(&nxt_controller_waiting_requests)) { 660*238Svbart@nginx.com nxt_queue_insert_tail(&nxt_controller_waiting_requests, &req->link); 661*238Svbart@nginx.com return; 662*238Svbart@nginx.com } 663*238Svbart@nginx.com 66451Svbart@nginx.com if (path.length == 1) { 66565Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 66644Svbart@nginx.com 66751Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 668208Svbart@nginx.com goto alloc_fail; 66951Svbart@nginx.com } 67051Svbart@nginx.com 671106Svbart@nginx.com value = nxt_conf_json_parse_str(mp, &empty_obj); 67227Svbart@nginx.com 67344Svbart@nginx.com } else { 674106Svbart@nginx.com rc = nxt_conf_op_compile(c->mem_pool, &ops, 675106Svbart@nginx.com nxt_controller_conf.root, 676106Svbart@nginx.com &path, NULL); 67751Svbart@nginx.com 67851Svbart@nginx.com if (rc != NXT_OK) { 67951Svbart@nginx.com if (rc == NXT_DECLINED) { 680208Svbart@nginx.com goto not_found; 68151Svbart@nginx.com } 68251Svbart@nginx.com 683208Svbart@nginx.com goto alloc_fail; 68451Svbart@nginx.com } 68551Svbart@nginx.com 68665Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 68751Svbart@nginx.com 68851Svbart@nginx.com if (nxt_slow_path(mp == NULL)) { 689208Svbart@nginx.com goto alloc_fail; 69051Svbart@nginx.com } 69151Svbart@nginx.com 692106Svbart@nginx.com value = nxt_conf_clone(mp, ops, nxt_controller_conf.root); 69351Svbart@nginx.com } 69451Svbart@nginx.com 69551Svbart@nginx.com if (nxt_slow_path(value == NULL)) { 69665Sigor@sysoev.ru nxt_mp_destroy(mp); 697208Svbart@nginx.com goto alloc_fail; 69844Svbart@nginx.com } 69944Svbart@nginx.com 700116Svbart@nginx.com if (nxt_slow_path(nxt_conf_validate(value) != NXT_OK)) { 701121Svbart@nginx.com nxt_mp_destroy(mp); 702208Svbart@nginx.com goto invalid_conf; 703116Svbart@nginx.com } 704116Svbart@nginx.com 705140Svbart@nginx.com req->conf.root = value; 706140Svbart@nginx.com req->conf.pool = mp; 707140Svbart@nginx.com 708140Svbart@nginx.com if (nxt_controller_conf_apply(task, req) != NXT_OK) { 709121Svbart@nginx.com nxt_mp_destroy(mp); 710208Svbart@nginx.com goto alloc_fail; 711121Svbart@nginx.com } 712121Svbart@nginx.com 713140Svbart@nginx.com return; 71451Svbart@nginx.com } 71551Svbart@nginx.com 716208Svbart@nginx.com resp.status = 405; 717208Svbart@nginx.com resp.title = (u_char *) "Invalid method."; 718208Svbart@nginx.com resp.offset = -1; 71951Svbart@nginx.com 720208Svbart@nginx.com nxt_controller_response(task, req, &resp); 721208Svbart@nginx.com return; 72251Svbart@nginx.com 723208Svbart@nginx.com alloc_fail: 72451Svbart@nginx.com 725208Svbart@nginx.com resp.status = 500; 726208Svbart@nginx.com resp.title = (u_char *) "Memory allocation failed."; 727208Svbart@nginx.com resp.offset = -1; 72827Svbart@nginx.com 729140Svbart@nginx.com nxt_controller_response(task, req, &resp); 730208Svbart@nginx.com return; 731208Svbart@nginx.com 732208Svbart@nginx.com not_found: 733208Svbart@nginx.com 734208Svbart@nginx.com resp.status = 404; 735208Svbart@nginx.com resp.title = (u_char *) "Value doesn't exist."; 736208Svbart@nginx.com resp.offset = -1; 737208Svbart@nginx.com 738208Svbart@nginx.com nxt_controller_response(task, req, &resp); 739208Svbart@nginx.com return; 740208Svbart@nginx.com 741208Svbart@nginx.com invalid_conf: 742208Svbart@nginx.com 743208Svbart@nginx.com resp.status = 400; 744208Svbart@nginx.com resp.title = (u_char *) "Invalid configuration."; 745208Svbart@nginx.com resp.offset = -1; 746208Svbart@nginx.com 747208Svbart@nginx.com nxt_controller_response(task, req, &resp); 748208Svbart@nginx.com return; 74927Svbart@nginx.com } 75027Svbart@nginx.com 75127Svbart@nginx.com 75227Svbart@nginx.com static nxt_int_t 753140Svbart@nginx.com nxt_controller_conf_apply(nxt_task_t *task, nxt_controller_request_t *req) 754140Svbart@nginx.com { 755*238Svbart@nginx.com size_t size; 756*238Svbart@nginx.com uint32_t stream; 757*238Svbart@nginx.com nxt_int_t rc; 758*238Svbart@nginx.com nxt_buf_t *b; 759*238Svbart@nginx.com nxt_port_t *router_port, *controller_port; 760*238Svbart@nginx.com nxt_runtime_t *rt; 761*238Svbart@nginx.com 762*238Svbart@nginx.com rt = task->thread->runtime; 763*238Svbart@nginx.com 764*238Svbart@nginx.com router_port = rt->port_by_type[NXT_PROCESS_ROUTER]; 765*238Svbart@nginx.com controller_port = rt->port_by_type[NXT_PROCESS_CONTROLLER]; 766140Svbart@nginx.com 767*238Svbart@nginx.com size = nxt_conf_json_length(req->conf.root, NULL); 768*238Svbart@nginx.com 769*238Svbart@nginx.com b = nxt_port_mmap_get_buf(task, router_port, size); 770*238Svbart@nginx.com 771*238Svbart@nginx.com b->mem.free = nxt_conf_json_print(b->mem.free, req->conf.root, NULL); 772140Svbart@nginx.com 773*238Svbart@nginx.com stream = nxt_port_rpc_register_handler(task, controller_port, 774*238Svbart@nginx.com nxt_controller_conf_handler, 775*238Svbart@nginx.com nxt_controller_conf_handler, 776*238Svbart@nginx.com router_port->pid, req); 777*238Svbart@nginx.com 778*238Svbart@nginx.com rc = nxt_port_socket_write(task, router_port, NXT_PORT_MSG_DATA_LAST, -1, 779*238Svbart@nginx.com stream, controller_port->id, b); 780140Svbart@nginx.com 781140Svbart@nginx.com if (nxt_slow_path(rc != NXT_OK)) { 782*238Svbart@nginx.com nxt_port_rpc_cancel(task, controller_port, stream); 783140Svbart@nginx.com return NXT_ERROR; 784140Svbart@nginx.com } 785140Svbart@nginx.com 786*238Svbart@nginx.com nxt_queue_insert_head(&nxt_controller_waiting_requests, &req->link); 787140Svbart@nginx.com 788140Svbart@nginx.com return NXT_OK; 789140Svbart@nginx.com } 790140Svbart@nginx.com 791140Svbart@nginx.com 792193Smax.romanov@nginx.com static void 793193Smax.romanov@nginx.com nxt_controller_conf_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg, 794193Smax.romanov@nginx.com void *data) 795140Svbart@nginx.com { 796*238Svbart@nginx.com nxt_queue_t queue; 797140Svbart@nginx.com nxt_controller_request_t *req; 798140Svbart@nginx.com nxt_controller_response_t resp; 799140Svbart@nginx.com 800*238Svbart@nginx.com req = data; 801*238Svbart@nginx.com 802201Svbart@nginx.com nxt_debug(task, "controller conf ready: %*s", 803201Svbart@nginx.com nxt_buf_mem_used_size(&msg->buf->mem), msg->buf->mem.pos); 804140Svbart@nginx.com 805*238Svbart@nginx.com nxt_queue_remove(&req->link); 806140Svbart@nginx.com 807*238Svbart@nginx.com nxt_memzero(&resp, sizeof(nxt_controller_response_t)); 808140Svbart@nginx.com 809193Smax.romanov@nginx.com if (msg->port_msg.type == NXT_PORT_MSG_RPC_READY) { 810140Svbart@nginx.com nxt_mp_destroy(nxt_controller_conf.pool); 811140Svbart@nginx.com 812140Svbart@nginx.com nxt_controller_conf = req->conf; 813140Svbart@nginx.com 814208Svbart@nginx.com resp.status = 200; 815208Svbart@nginx.com resp.title = (u_char *) "Reconfiguration done."; 816140Svbart@nginx.com 817140Svbart@nginx.com } else { 818140Svbart@nginx.com nxt_mp_destroy(req->conf.pool); 819140Svbart@nginx.com 820208Svbart@nginx.com resp.status = 500; 821208Svbart@nginx.com resp.title = (u_char *) "Failed to apply new configuration."; 822208Svbart@nginx.com resp.offset = -1; 823140Svbart@nginx.com } 824140Svbart@nginx.com 825140Svbart@nginx.com nxt_controller_response(task, req, &resp); 826140Svbart@nginx.com 827*238Svbart@nginx.com nxt_queue_init(&queue); 828*238Svbart@nginx.com nxt_queue_add(&queue, &nxt_controller_waiting_requests); 829140Svbart@nginx.com 830*238Svbart@nginx.com nxt_queue_init(&nxt_controller_waiting_requests); 831121Svbart@nginx.com 832*238Svbart@nginx.com nxt_queue_each(req, &queue, nxt_controller_request_t, link) { 833*238Svbart@nginx.com nxt_controller_process_request(task, req); 834*238Svbart@nginx.com } nxt_queue_loop; 835121Svbart@nginx.com } 836121Svbart@nginx.com 837121Svbart@nginx.com 838140Svbart@nginx.com static void 839140Svbart@nginx.com nxt_controller_response(nxt_task_t *task, nxt_controller_request_t *req, 84044Svbart@nginx.com nxt_controller_response_t *resp) 84133Svbart@nginx.com { 842208Svbart@nginx.com size_t size; 843208Svbart@nginx.com nxt_str_t status_line, str; 844208Svbart@nginx.com nxt_buf_t *b, *body; 845208Svbart@nginx.com nxt_conn_t *c; 846208Svbart@nginx.com nxt_uint_t n; 847208Svbart@nginx.com nxt_conf_value_t *value, *location; 848208Svbart@nginx.com nxt_conf_json_pretty_t pretty; 849208Svbart@nginx.com 850208Svbart@nginx.com static nxt_str_t success_str = nxt_string("success"); 851208Svbart@nginx.com static nxt_str_t error_str = nxt_string("error"); 852208Svbart@nginx.com static nxt_str_t detail_str = nxt_string("detail"); 853208Svbart@nginx.com static nxt_str_t location_str = nxt_string("location"); 854208Svbart@nginx.com static nxt_str_t offset_str = nxt_string("offset"); 855208Svbart@nginx.com static nxt_str_t line_str = nxt_string("line"); 856208Svbart@nginx.com static nxt_str_t column_str = nxt_string("column"); 857208Svbart@nginx.com 858208Svbart@nginx.com static nxt_time_string_t date_cache = { 859208Svbart@nginx.com (nxt_atomic_uint_t) -1, 860208Svbart@nginx.com nxt_controller_date, 861208Svbart@nginx.com "%s, %02d %s %4d %02d:%02d:%02d GMT", 862208Svbart@nginx.com sizeof("Wed, 31 Dec 1986 16:40:00 GMT") - 1, 863208Svbart@nginx.com NXT_THREAD_TIME_GMT, 864208Svbart@nginx.com NXT_THREAD_TIME_SEC, 865208Svbart@nginx.com }; 866208Svbart@nginx.com 867208Svbart@nginx.com switch (resp->status) { 868208Svbart@nginx.com 869208Svbart@nginx.com case 200: 870208Svbart@nginx.com nxt_str_set(&status_line, "200 OK"); 871208Svbart@nginx.com break; 872208Svbart@nginx.com 873208Svbart@nginx.com case 400: 874208Svbart@nginx.com nxt_str_set(&status_line, "400 Bad Request"); 875208Svbart@nginx.com break; 876208Svbart@nginx.com 877208Svbart@nginx.com case 404: 878208Svbart@nginx.com nxt_str_set(&status_line, "404 Not Found"); 879208Svbart@nginx.com break; 880208Svbart@nginx.com 881208Svbart@nginx.com case 405: 882208Svbart@nginx.com nxt_str_set(&status_line, "405 Method Not Allowed"); 883208Svbart@nginx.com break; 884208Svbart@nginx.com 885209Svbart@nginx.com default: 886208Svbart@nginx.com nxt_str_set(&status_line, "500 Internal Server Error"); 887208Svbart@nginx.com break; 888208Svbart@nginx.com } 889140Svbart@nginx.com 890140Svbart@nginx.com c = req->conn; 891208Svbart@nginx.com value = resp->conf; 89233Svbart@nginx.com 893208Svbart@nginx.com if (value == NULL) { 894208Svbart@nginx.com n = 1 895208Svbart@nginx.com + (resp->detail != NULL) 896208Svbart@nginx.com + (resp->status >= 400 && resp->offset != -1); 897208Svbart@nginx.com 898208Svbart@nginx.com value = nxt_conf_create_object(c->mem_pool, n); 899208Svbart@nginx.com 900208Svbart@nginx.com if (nxt_slow_path(value == NULL)) { 901208Svbart@nginx.com nxt_controller_conn_close(task, c, req); 902208Svbart@nginx.com return; 903208Svbart@nginx.com } 904208Svbart@nginx.com 905208Svbart@nginx.com str.length = nxt_strlen(resp->title); 906208Svbart@nginx.com str.start = resp->title; 907208Svbart@nginx.com 908208Svbart@nginx.com if (resp->status < 400) { 909208Svbart@nginx.com nxt_conf_set_member_string(value, &success_str, &str, 0); 910208Svbart@nginx.com 911208Svbart@nginx.com } else { 912208Svbart@nginx.com nxt_conf_set_member_string(value, &error_str, &str, 0); 913208Svbart@nginx.com } 914208Svbart@nginx.com 915208Svbart@nginx.com n = 0; 916208Svbart@nginx.com 917208Svbart@nginx.com if (resp->detail != NULL) { 918208Svbart@nginx.com str.length = nxt_strlen(resp->detail); 919208Svbart@nginx.com str.start = resp->detail; 920208Svbart@nginx.com 921208Svbart@nginx.com n++; 922208Svbart@nginx.com 923208Svbart@nginx.com nxt_conf_set_member_string(value, &detail_str, &str, n); 924208Svbart@nginx.com } 925208Svbart@nginx.com 926208Svbart@nginx.com if (resp->status >= 400 && resp->offset != -1) { 927208Svbart@nginx.com n++; 928208Svbart@nginx.com 929208Svbart@nginx.com location = nxt_conf_create_object(c->mem_pool, 930208Svbart@nginx.com resp->line != 0 ? 3 : 1); 931208Svbart@nginx.com 932208Svbart@nginx.com nxt_conf_set_member(value, &location_str, location, n); 933208Svbart@nginx.com 934208Svbart@nginx.com nxt_conf_set_member_integer(location, &offset_str, resp->offset, 0); 935208Svbart@nginx.com 936208Svbart@nginx.com if (resp->line != 0) { 937208Svbart@nginx.com nxt_conf_set_member_integer(location, &line_str, 938208Svbart@nginx.com resp->line, 1); 939208Svbart@nginx.com 940208Svbart@nginx.com nxt_conf_set_member_integer(location, &column_str, 941208Svbart@nginx.com resp->column, 2); 942208Svbart@nginx.com } 943208Svbart@nginx.com } 944208Svbart@nginx.com } 945208Svbart@nginx.com 946208Svbart@nginx.com nxt_memzero(&pretty, sizeof(nxt_conf_json_pretty_t)); 947208Svbart@nginx.com 948208Svbart@nginx.com size = nxt_conf_json_length(value, &pretty) + 2; 949208Svbart@nginx.com 950208Svbart@nginx.com body = nxt_buf_mem_alloc(c->mem_pool, size, 0); 951208Svbart@nginx.com if (nxt_slow_path(body == NULL)) { 952208Svbart@nginx.com nxt_controller_conn_close(task, c, req); 953208Svbart@nginx.com return; 954208Svbart@nginx.com } 955208Svbart@nginx.com 956208Svbart@nginx.com nxt_memzero(&pretty, sizeof(nxt_conf_json_pretty_t)); 957208Svbart@nginx.com 958208Svbart@nginx.com body->mem.free = nxt_conf_json_print(body->mem.free, value, &pretty); 959208Svbart@nginx.com 960208Svbart@nginx.com body->mem.free = nxt_cpymem(body->mem.free, "\r\n", 2); 961208Svbart@nginx.com 962208Svbart@nginx.com size = sizeof("HTTP/1.1 " "\r\n") - 1 + status_line.length 963208Svbart@nginx.com + sizeof("Server: nginext/0.1\r\n") - 1 964208Svbart@nginx.com + sizeof("Date: Wed, 31 Dec 1986 16:40:00 GMT\r\n") - 1 965208Svbart@nginx.com + sizeof("Content-Type: application/json\r\n") - 1 966208Svbart@nginx.com + sizeof("Content-Length: " "\r\n") - 1 + NXT_SIZE_T_LEN 967208Svbart@nginx.com + sizeof("Connection: close\r\n") - 1 968208Svbart@nginx.com + sizeof("\r\n") - 1; 96933Svbart@nginx.com 97044Svbart@nginx.com b = nxt_buf_mem_alloc(c->mem_pool, size, 0); 97133Svbart@nginx.com if (nxt_slow_path(b == NULL)) { 972140Svbart@nginx.com nxt_controller_conn_close(task, c, req); 973140Svbart@nginx.com return; 97433Svbart@nginx.com } 97533Svbart@nginx.com 976208Svbart@nginx.com b->next = body; 977208Svbart@nginx.com 978208Svbart@nginx.com nxt_str_set(&str, "HTTP/1.1 "); 97944Svbart@nginx.com 980208Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length); 981208Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, status_line.start, 982208Svbart@nginx.com status_line.length); 983208Svbart@nginx.com 984208Svbart@nginx.com nxt_str_set(&str, "\r\n" 985208Svbart@nginx.com "Server: nginext/0.1\r\n" 986208Svbart@nginx.com "Date: "); 987208Svbart@nginx.com 988208Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length); 98944Svbart@nginx.com 990208Svbart@nginx.com b->mem.free = nxt_thread_time_string(task->thread, &date_cache, 991208Svbart@nginx.com b->mem.free); 992208Svbart@nginx.com 993208Svbart@nginx.com nxt_str_set(&str, "\r\n" 994208Svbart@nginx.com "Content-Type: application/json\r\n" 995208Svbart@nginx.com "Content-Length: "); 996208Svbart@nginx.com 997208Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length); 99845Svbart@nginx.com 999208Svbart@nginx.com b->mem.free = nxt_sprintf(b->mem.free, b->mem.end, "%uz", 1000208Svbart@nginx.com nxt_buf_mem_used_size(&body->mem)); 1001208Svbart@nginx.com 1002208Svbart@nginx.com nxt_str_set(&str, "\r\n" 1003208Svbart@nginx.com "Connection: close\r\n" 1004208Svbart@nginx.com "\r\n"); 1005208Svbart@nginx.com 1006208Svbart@nginx.com b->mem.free = nxt_cpymem(b->mem.free, str.start, str.length); 100733Svbart@nginx.com 100833Svbart@nginx.com c->write = b; 100944Svbart@nginx.com c->write_state = &nxt_controller_conn_write_state; 101033Svbart@nginx.com 101162Sigor@sysoev.ru nxt_conn_write(task->thread->engine, c); 101233Svbart@nginx.com } 101345Svbart@nginx.com 101445Svbart@nginx.com 1015208Svbart@nginx.com static u_char * 1016208Svbart@nginx.com nxt_controller_date(u_char *buf, nxt_realtime_t *now, struct tm *tm, 1017208Svbart@nginx.com size_t size, const char *format) 101845Svbart@nginx.com { 1019208Svbart@nginx.com static const char *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", 1020208Svbart@nginx.com "Sat" }; 102145Svbart@nginx.com 1022208Svbart@nginx.com static const char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", 1023208Svbart@nginx.com "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; 102445Svbart@nginx.com 1025208Svbart@nginx.com return nxt_sprintf(buf, buf + size, format, 1026208Svbart@nginx.com week[tm->tm_wday], tm->tm_mday, 1027208Svbart@nginx.com month[tm->tm_mon], tm->tm_year + 1900, 1028