xref: /unit/src/nxt_controller.c (revision 33)
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 {
1527Svbart@nginx.com     nxt_http_request_parse_t  parser;
1627Svbart@nginx.com     size_t                    length;
17*33Svbart@nginx.com 
18*33Svbart@nginx.com     nxt_conf_json_value_t     *conf;
1927Svbart@nginx.com } nxt_controller_request_t;
2027Svbart@nginx.com 
2127Svbart@nginx.com 
2220Sigor@sysoev.ru static void nxt_controller_conn_init(nxt_task_t *task, void *obj, void *data);
2320Sigor@sysoev.ru static void nxt_controller_conn_read(nxt_task_t *task, void *obj, void *data);
2420Sigor@sysoev.ru static nxt_msec_t nxt_controller_conn_timeout_value(nxt_event_conn_t *c,
2520Sigor@sysoev.ru     uintptr_t data);
2620Sigor@sysoev.ru static void nxt_controller_conn_read_error(nxt_task_t *task, void *obj,
2720Sigor@sysoev.ru     void *data);
2820Sigor@sysoev.ru static void nxt_controller_conn_read_timeout(nxt_task_t *task, void *obj,
2920Sigor@sysoev.ru     void *data);
3027Svbart@nginx.com static void nxt_controller_conn_body_read(nxt_task_t *task, void *obj,
3127Svbart@nginx.com     void *data);
3227Svbart@nginx.com static void nxt_controller_conn_write(nxt_task_t *task, void *obj, void *data);
3327Svbart@nginx.com static void nxt_controller_conn_write_error(nxt_task_t *task, void *obj,
3427Svbart@nginx.com     void *data);
3527Svbart@nginx.com static void nxt_controller_conn_write_timeout(nxt_task_t *task, void *obj,
3627Svbart@nginx.com     void *data);
3720Sigor@sysoev.ru static void nxt_controller_conn_close(nxt_task_t *task, void *obj, void *data);
3820Sigor@sysoev.ru static void nxt_controller_conn_free(nxt_task_t *task, void *obj, void *data);
3920Sigor@sysoev.ru 
4027Svbart@nginx.com static nxt_int_t nxt_controller_request_content_length(void *ctx,
4127Svbart@nginx.com     nxt_str_t *name, nxt_str_t *value, uintptr_t data);
4227Svbart@nginx.com 
4327Svbart@nginx.com static void nxt_controller_process_request(nxt_task_t *task,
4427Svbart@nginx.com     nxt_event_conn_t *c, nxt_controller_request_t *r);
4529Svbart@nginx.com static nxt_int_t nxt_controller_request_body_parse(nxt_task_t *task,
46*33Svbart@nginx.com     nxt_event_conn_t *c, nxt_controller_request_t *r);
47*33Svbart@nginx.com static void nxt_controller_conf_output(nxt_task_t *task, nxt_event_conn_t *c,
48*33Svbart@nginx.com     nxt_controller_request_t *r);
4927Svbart@nginx.com 
5027Svbart@nginx.com 
5127Svbart@nginx.com static nxt_http_fields_t  nxt_controller_request_fields[] = {
5227Svbart@nginx.com     { nxt_string("Content-Length"),
5327Svbart@nginx.com       &nxt_controller_request_content_length, 0 },
5427Svbart@nginx.com 
5527Svbart@nginx.com     { nxt_null_string, NULL, 0 }
5627Svbart@nginx.com };
5727Svbart@nginx.com 
5827Svbart@nginx.com 
5927Svbart@nginx.com static nxt_http_fields_hash_t  *nxt_controller_request_fields_hash;
6027Svbart@nginx.com 
6120Sigor@sysoev.ru 
6220Sigor@sysoev.ru static const nxt_event_conn_state_t  nxt_controller_conn_read_state;
6327Svbart@nginx.com static const nxt_event_conn_state_t  nxt_controller_conn_body_read_state;
6427Svbart@nginx.com static const nxt_event_conn_state_t  nxt_controller_conn_write_state;
6520Sigor@sysoev.ru static const nxt_event_conn_state_t  nxt_controller_conn_close_state;
6620Sigor@sysoev.ru 
6720Sigor@sysoev.ru 
6820Sigor@sysoev.ru nxt_int_t
6920Sigor@sysoev.ru nxt_controller_start(nxt_task_t *task, nxt_runtime_t *rt)
7020Sigor@sysoev.ru {
7127Svbart@nginx.com     nxt_http_fields_hash_t  *hash;
7227Svbart@nginx.com 
7327Svbart@nginx.com     hash = nxt_http_fields_hash(nxt_controller_request_fields, rt->mem_pool);
7427Svbart@nginx.com 
7527Svbart@nginx.com     if (nxt_slow_path(hash == NULL)) {
7627Svbart@nginx.com         return NXT_ERROR;
7727Svbart@nginx.com     }
7827Svbart@nginx.com 
7927Svbart@nginx.com     nxt_controller_request_fields_hash = hash;
8027Svbart@nginx.com 
8120Sigor@sysoev.ru     if (nxt_event_conn_listen(task, rt->controller_socket) != NXT_OK) {
8220Sigor@sysoev.ru         return NXT_ERROR;
8320Sigor@sysoev.ru     }
8420Sigor@sysoev.ru 
8520Sigor@sysoev.ru     return NXT_OK;
8620Sigor@sysoev.ru }
8720Sigor@sysoev.ru 
8820Sigor@sysoev.ru 
8920Sigor@sysoev.ru nxt_int_t
9020Sigor@sysoev.ru nxt_runtime_controller_socket(nxt_task_t *task, nxt_runtime_t *rt)
9120Sigor@sysoev.ru {
9220Sigor@sysoev.ru     nxt_sockaddr_t       *sa;
9320Sigor@sysoev.ru     nxt_listen_socket_t  *ls;
9420Sigor@sysoev.ru 
9520Sigor@sysoev.ru     sa = rt->controller_listen;
9620Sigor@sysoev.ru 
9720Sigor@sysoev.ru     if (rt->controller_listen == NULL) {
9820Sigor@sysoev.ru         sa = nxt_sockaddr_alloc(rt->mem_pool, sizeof(struct sockaddr_in),
9920Sigor@sysoev.ru                                 NXT_INET_ADDR_STR_LEN);
10020Sigor@sysoev.ru         if (sa == NULL) {
10120Sigor@sysoev.ru             return NXT_ERROR;
10220Sigor@sysoev.ru         }
10320Sigor@sysoev.ru 
10420Sigor@sysoev.ru         sa->type = SOCK_STREAM;
10520Sigor@sysoev.ru         sa->u.sockaddr_in.sin_family = AF_INET;
10620Sigor@sysoev.ru         sa->u.sockaddr_in.sin_port = htons(8443);
10720Sigor@sysoev.ru 
10820Sigor@sysoev.ru         nxt_sockaddr_text(sa);
10920Sigor@sysoev.ru 
11020Sigor@sysoev.ru         rt->controller_listen = sa;
11120Sigor@sysoev.ru     }
11220Sigor@sysoev.ru 
11320Sigor@sysoev.ru     ls = nxt_mem_alloc(rt->mem_pool, sizeof(nxt_listen_socket_t));
11420Sigor@sysoev.ru     if (ls == NULL) {
11520Sigor@sysoev.ru         return NXT_ERROR;
11620Sigor@sysoev.ru     }
11720Sigor@sysoev.ru 
11820Sigor@sysoev.ru     ls->sockaddr = nxt_sockaddr_create(rt->mem_pool, &sa->u.sockaddr,
11920Sigor@sysoev.ru                                        sa->socklen, sa->length);
12020Sigor@sysoev.ru     if (ls->sockaddr == NULL) {
12120Sigor@sysoev.ru         return NXT_ERROR;
12220Sigor@sysoev.ru     }
12320Sigor@sysoev.ru 
12420Sigor@sysoev.ru     ls->sockaddr->type = sa->type;
12520Sigor@sysoev.ru 
12620Sigor@sysoev.ru     nxt_sockaddr_text(ls->sockaddr);
12720Sigor@sysoev.ru 
12820Sigor@sysoev.ru     ls->socket = -1;
12920Sigor@sysoev.ru     ls->backlog = NXT_LISTEN_BACKLOG;
13020Sigor@sysoev.ru     ls->read_after_accept = 1;
13120Sigor@sysoev.ru     ls->flags = NXT_NONBLOCK;
13220Sigor@sysoev.ru 
13320Sigor@sysoev.ru #if 0
13420Sigor@sysoev.ru     /* STUB */
13520Sigor@sysoev.ru     wq = nxt_mem_zalloc(cf->mem_pool, sizeof(nxt_work_queue_t));
13620Sigor@sysoev.ru     if (wq == NULL) {
13720Sigor@sysoev.ru         return NXT_ERROR;
13820Sigor@sysoev.ru     }
13920Sigor@sysoev.ru     nxt_work_queue_name(wq, "listen");
14020Sigor@sysoev.ru     /**/
14120Sigor@sysoev.ru 
14220Sigor@sysoev.ru     ls->work_queue = wq;
14320Sigor@sysoev.ru #endif
14420Sigor@sysoev.ru     ls->handler = nxt_controller_conn_init;
14520Sigor@sysoev.ru 
14620Sigor@sysoev.ru     /*
14720Sigor@sysoev.ru      * Connection memory pool chunk size is tunned to
14820Sigor@sysoev.ru      * allocate the most data in one mem_pool chunk.
14920Sigor@sysoev.ru      */
15020Sigor@sysoev.ru     ls->mem_pool_size = nxt_listen_socket_pool_min_size(ls)
15120Sigor@sysoev.ru                         + sizeof(nxt_event_conn_proxy_t)
15220Sigor@sysoev.ru                         + sizeof(nxt_event_conn_t)
15320Sigor@sysoev.ru                         + 4 * sizeof(nxt_buf_t);
15420Sigor@sysoev.ru 
15520Sigor@sysoev.ru     if (nxt_listen_socket_create(task, ls, 0) != NXT_OK) {
15620Sigor@sysoev.ru         return NXT_ERROR;
15720Sigor@sysoev.ru     }
15820Sigor@sysoev.ru 
15920Sigor@sysoev.ru     rt->controller_socket = ls;
16020Sigor@sysoev.ru 
16120Sigor@sysoev.ru     return NXT_OK;
16220Sigor@sysoev.ru }
16320Sigor@sysoev.ru 
16420Sigor@sysoev.ru 
16520Sigor@sysoev.ru static void
16620Sigor@sysoev.ru nxt_controller_conn_init(nxt_task_t *task, void *obj, void *data)
16720Sigor@sysoev.ru {
16827Svbart@nginx.com     nxt_buf_t                 *b;
16927Svbart@nginx.com     nxt_event_conn_t          *c;
17027Svbart@nginx.com     nxt_event_engine_t        *engine;
17127Svbart@nginx.com     nxt_controller_request_t  *r;
17220Sigor@sysoev.ru 
17320Sigor@sysoev.ru     c = obj;
17420Sigor@sysoev.ru 
17520Sigor@sysoev.ru     nxt_debug(task, "controller conn init fd:%d", c->socket.fd);
17620Sigor@sysoev.ru 
17727Svbart@nginx.com     r = nxt_mem_zalloc(c->mem_pool, sizeof(nxt_controller_request_t));
17827Svbart@nginx.com     if (nxt_slow_path(r == NULL)) {
17927Svbart@nginx.com         nxt_controller_conn_free(task, c, NULL);
18027Svbart@nginx.com         return;
18127Svbart@nginx.com     }
18227Svbart@nginx.com 
18327Svbart@nginx.com     r->parser.hash = nxt_controller_request_fields_hash;
18427Svbart@nginx.com     r->parser.ctx = r;
18527Svbart@nginx.com 
18620Sigor@sysoev.ru     b = nxt_buf_mem_alloc(c->mem_pool, 1024, 0);
18720Sigor@sysoev.ru     if (nxt_slow_path(b == NULL)) {
18820Sigor@sysoev.ru         nxt_controller_conn_free(task, c, NULL);
18920Sigor@sysoev.ru         return;
19020Sigor@sysoev.ru     }
19120Sigor@sysoev.ru 
19220Sigor@sysoev.ru     c->read = b;
19327Svbart@nginx.com     c->socket.data = r;
19420Sigor@sysoev.ru     c->socket.read_ready = 1;
19520Sigor@sysoev.ru     c->read_state = &nxt_controller_conn_read_state;
19620Sigor@sysoev.ru 
19720Sigor@sysoev.ru     engine = task->thread->engine;
19820Sigor@sysoev.ru     c->read_work_queue = &engine->read_work_queue;
19927Svbart@nginx.com     c->write_work_queue = &engine->write_work_queue;
20020Sigor@sysoev.ru 
20120Sigor@sysoev.ru     nxt_event_conn_read(engine, c);
20220Sigor@sysoev.ru }
20320Sigor@sysoev.ru 
20420Sigor@sysoev.ru 
20520Sigor@sysoev.ru static const nxt_event_conn_state_t  nxt_controller_conn_read_state
20620Sigor@sysoev.ru     nxt_aligned(64) =
20720Sigor@sysoev.ru {
20820Sigor@sysoev.ru     NXT_EVENT_NO_BUF_PROCESS,
20920Sigor@sysoev.ru     NXT_EVENT_TIMER_NO_AUTORESET,
21020Sigor@sysoev.ru 
21120Sigor@sysoev.ru     nxt_controller_conn_read,
21220Sigor@sysoev.ru     nxt_controller_conn_close,
21320Sigor@sysoev.ru     nxt_controller_conn_read_error,
21420Sigor@sysoev.ru 
21520Sigor@sysoev.ru     nxt_controller_conn_read_timeout,
21620Sigor@sysoev.ru     nxt_controller_conn_timeout_value,
21720Sigor@sysoev.ru     60 * 1000,
21820Sigor@sysoev.ru };
21920Sigor@sysoev.ru 
22020Sigor@sysoev.ru 
22120Sigor@sysoev.ru static void
22220Sigor@sysoev.ru nxt_controller_conn_read(nxt_task_t *task, void *obj, void *data)
22320Sigor@sysoev.ru {
22427Svbart@nginx.com     size_t                    preread;
22527Svbart@nginx.com     nxt_buf_t                 *b;
22627Svbart@nginx.com     nxt_int_t                 rc;
22727Svbart@nginx.com     nxt_event_conn_t          *c;
22827Svbart@nginx.com     nxt_controller_request_t  *r;
22920Sigor@sysoev.ru 
23020Sigor@sysoev.ru     c = obj;
23127Svbart@nginx.com     r = data;
23220Sigor@sysoev.ru 
23320Sigor@sysoev.ru     nxt_debug(task, "controller conn read");
23420Sigor@sysoev.ru 
23527Svbart@nginx.com     nxt_queue_remove(&c->link);
23627Svbart@nginx.com     nxt_queue_self(&c->link);
23727Svbart@nginx.com 
23827Svbart@nginx.com     b = c->read;
23927Svbart@nginx.com 
24027Svbart@nginx.com     rc = nxt_http_parse_request(&r->parser, &b->mem);
24127Svbart@nginx.com 
24227Svbart@nginx.com     if (nxt_slow_path(rc != NXT_DONE)) {
24327Svbart@nginx.com 
24427Svbart@nginx.com         if (rc == NXT_AGAIN) {
24527Svbart@nginx.com             if (nxt_buf_mem_free_size(&b->mem) == 0) {
24627Svbart@nginx.com                 nxt_log(task, NXT_LOG_ERR, "too long request headers");
24727Svbart@nginx.com                 nxt_controller_conn_close(task, c, r);
24827Svbart@nginx.com                 return;
24927Svbart@nginx.com             }
25027Svbart@nginx.com 
25127Svbart@nginx.com             nxt_event_conn_read(task->thread->engine, c);
25227Svbart@nginx.com             return;
25327Svbart@nginx.com         }
25427Svbart@nginx.com 
25527Svbart@nginx.com         /* rc == NXT_ERROR */
25627Svbart@nginx.com 
25727Svbart@nginx.com         nxt_log(task, NXT_LOG_ERR, "parsing error");
25827Svbart@nginx.com 
25927Svbart@nginx.com         nxt_controller_conn_close(task, c, r);
26027Svbart@nginx.com         return;
26127Svbart@nginx.com     }
26227Svbart@nginx.com 
26327Svbart@nginx.com     preread = nxt_buf_mem_used_size(&b->mem);
26427Svbart@nginx.com 
26527Svbart@nginx.com     nxt_debug(task, "controller request header parsing complete, "
26627Svbart@nginx.com                     "body length: %O, preread: %uz",
26727Svbart@nginx.com                     r->length, preread);
26827Svbart@nginx.com 
26927Svbart@nginx.com     if (preread >= r->length) {
27027Svbart@nginx.com         nxt_controller_process_request(task, c, r);
27127Svbart@nginx.com         return;
27227Svbart@nginx.com     }
27327Svbart@nginx.com 
27427Svbart@nginx.com     if (r->length - preread > (size_t) nxt_buf_mem_free_size(&b->mem)) {
27527Svbart@nginx.com         b = nxt_buf_mem_alloc(c->mem_pool, r->length, 0);
27627Svbart@nginx.com         if (nxt_slow_path(b == NULL)) {
27727Svbart@nginx.com             nxt_controller_conn_free(task, c, NULL);
27827Svbart@nginx.com             return;
27927Svbart@nginx.com         }
28027Svbart@nginx.com 
28127Svbart@nginx.com         b->mem.free = nxt_cpymem(b->mem.free, c->read->mem.pos, preread);
28227Svbart@nginx.com 
28327Svbart@nginx.com         c->read = b;
28427Svbart@nginx.com     }
28527Svbart@nginx.com 
28627Svbart@nginx.com     c->read_state = &nxt_controller_conn_body_read_state;
28727Svbart@nginx.com 
28827Svbart@nginx.com     nxt_event_conn_read(task->thread->engine, c);
28920Sigor@sysoev.ru }
29020Sigor@sysoev.ru 
29120Sigor@sysoev.ru 
29220Sigor@sysoev.ru static nxt_msec_t
29320Sigor@sysoev.ru nxt_controller_conn_timeout_value(nxt_event_conn_t *c, uintptr_t data)
29420Sigor@sysoev.ru {
29520Sigor@sysoev.ru     return (nxt_msec_t) data;
29620Sigor@sysoev.ru }
29720Sigor@sysoev.ru 
29820Sigor@sysoev.ru 
29920Sigor@sysoev.ru static void
30020Sigor@sysoev.ru nxt_controller_conn_read_error(nxt_task_t *task, void *obj, void *data)
30120Sigor@sysoev.ru {
30220Sigor@sysoev.ru     nxt_event_conn_t  *c;
30320Sigor@sysoev.ru 
30420Sigor@sysoev.ru     c = obj;
30520Sigor@sysoev.ru 
30620Sigor@sysoev.ru     nxt_debug(task, "controller conn read error");
30720Sigor@sysoev.ru 
30827Svbart@nginx.com     nxt_controller_conn_close(task, c, data);
30920Sigor@sysoev.ru }
31020Sigor@sysoev.ru 
31120Sigor@sysoev.ru 
31220Sigor@sysoev.ru static void
31320Sigor@sysoev.ru nxt_controller_conn_read_timeout(nxt_task_t *task, void *obj, void *data)
31420Sigor@sysoev.ru {
31520Sigor@sysoev.ru     nxt_timer_t       *ev;
31620Sigor@sysoev.ru     nxt_event_conn_t  *c;
31720Sigor@sysoev.ru 
31820Sigor@sysoev.ru     ev = obj;
31920Sigor@sysoev.ru 
32020Sigor@sysoev.ru     c = nxt_event_read_timer_conn(ev);
32120Sigor@sysoev.ru     c->socket.timedout = 1;
32220Sigor@sysoev.ru     c->socket.closed = 1;
32320Sigor@sysoev.ru 
32420Sigor@sysoev.ru     nxt_debug(task, "controller conn read timeout");
32520Sigor@sysoev.ru 
32627Svbart@nginx.com     nxt_controller_conn_close(task, c, data);
32727Svbart@nginx.com }
32827Svbart@nginx.com 
32927Svbart@nginx.com 
33027Svbart@nginx.com static const nxt_event_conn_state_t  nxt_controller_conn_body_read_state
33127Svbart@nginx.com     nxt_aligned(64) =
33227Svbart@nginx.com {
33327Svbart@nginx.com     NXT_EVENT_NO_BUF_PROCESS,
33427Svbart@nginx.com     NXT_EVENT_TIMER_AUTORESET,
33527Svbart@nginx.com 
33627Svbart@nginx.com     nxt_controller_conn_body_read,
33727Svbart@nginx.com     nxt_controller_conn_close,
33827Svbart@nginx.com     nxt_controller_conn_read_error,
33927Svbart@nginx.com 
34027Svbart@nginx.com     nxt_controller_conn_read_timeout,
34127Svbart@nginx.com     nxt_controller_conn_timeout_value,
34227Svbart@nginx.com     60 * 1000,
34327Svbart@nginx.com };
34427Svbart@nginx.com 
34527Svbart@nginx.com 
34627Svbart@nginx.com static void
34727Svbart@nginx.com nxt_controller_conn_body_read(nxt_task_t *task, void *obj, void *data)
34827Svbart@nginx.com {
34927Svbart@nginx.com     size_t            rest;
35027Svbart@nginx.com     nxt_buf_t         *b;
35127Svbart@nginx.com     nxt_event_conn_t  *c;
35227Svbart@nginx.com 
35327Svbart@nginx.com     c = obj;
35427Svbart@nginx.com 
35527Svbart@nginx.com     nxt_debug(task, "controller conn body read");
35627Svbart@nginx.com 
35727Svbart@nginx.com     b = c->read;
35827Svbart@nginx.com 
35927Svbart@nginx.com     rest = nxt_buf_mem_free_size(&b->mem);
36027Svbart@nginx.com 
36127Svbart@nginx.com     if (rest == 0) {
36227Svbart@nginx.com         nxt_debug(task, "controller conn body read complete");
36327Svbart@nginx.com 
36427Svbart@nginx.com         nxt_controller_process_request(task, c, data);
36527Svbart@nginx.com         return;
36627Svbart@nginx.com     }
36727Svbart@nginx.com 
36827Svbart@nginx.com     nxt_debug(task, "controller conn body read again, rest: %uz", rest);
36927Svbart@nginx.com 
37027Svbart@nginx.com     nxt_event_conn_read(task->thread->engine, c);
37127Svbart@nginx.com }
37227Svbart@nginx.com 
37327Svbart@nginx.com 
37427Svbart@nginx.com static const nxt_event_conn_state_t  nxt_controller_conn_write_state
37527Svbart@nginx.com     nxt_aligned(64) =
37627Svbart@nginx.com {
37727Svbart@nginx.com     NXT_EVENT_NO_BUF_PROCESS,
37827Svbart@nginx.com     NXT_EVENT_TIMER_AUTORESET,
37927Svbart@nginx.com 
38027Svbart@nginx.com     nxt_controller_conn_write,
38127Svbart@nginx.com     NULL,
38227Svbart@nginx.com     nxt_controller_conn_write_error,
38327Svbart@nginx.com 
38427Svbart@nginx.com     nxt_controller_conn_write_timeout,
38527Svbart@nginx.com     nxt_controller_conn_timeout_value,
38627Svbart@nginx.com     60 * 1000,
38727Svbart@nginx.com };
38827Svbart@nginx.com 
38927Svbart@nginx.com 
39027Svbart@nginx.com static void
39127Svbart@nginx.com nxt_controller_conn_write(nxt_task_t *task, void *obj, void *data)
39227Svbart@nginx.com {
39327Svbart@nginx.com     nxt_buf_t         *b;
39427Svbart@nginx.com     nxt_event_conn_t  *c;
39527Svbart@nginx.com 
39627Svbart@nginx.com     c = obj;
39727Svbart@nginx.com 
39827Svbart@nginx.com     nxt_debug(task, "controller conn write");
39927Svbart@nginx.com 
40027Svbart@nginx.com     b = c->write;
40127Svbart@nginx.com 
40227Svbart@nginx.com     if (b->mem.pos != b->mem.free) {
40327Svbart@nginx.com         nxt_event_conn_write(task->thread->engine, c);
40427Svbart@nginx.com         return;
40527Svbart@nginx.com     }
40627Svbart@nginx.com 
40727Svbart@nginx.com     nxt_debug(task, "controller conn write complete");
40827Svbart@nginx.com 
40927Svbart@nginx.com     nxt_controller_conn_close(task, c, data);
41027Svbart@nginx.com }
41127Svbart@nginx.com 
41227Svbart@nginx.com 
41327Svbart@nginx.com static void
41427Svbart@nginx.com nxt_controller_conn_write_error(nxt_task_t *task, void *obj, void *data)
41527Svbart@nginx.com {
41627Svbart@nginx.com     nxt_event_conn_t  *c;
41727Svbart@nginx.com 
41827Svbart@nginx.com     c = obj;
41927Svbart@nginx.com 
42027Svbart@nginx.com     nxt_debug(task, "controller conn write error");
42127Svbart@nginx.com 
42227Svbart@nginx.com     nxt_controller_conn_close(task, c, data);
42327Svbart@nginx.com }
42427Svbart@nginx.com 
42527Svbart@nginx.com 
42627Svbart@nginx.com static void
42727Svbart@nginx.com nxt_controller_conn_write_timeout(nxt_task_t *task, void *obj, void *data)
42827Svbart@nginx.com {
42927Svbart@nginx.com     nxt_timer_t       *ev;
43027Svbart@nginx.com     nxt_event_conn_t  *c;
43127Svbart@nginx.com 
43227Svbart@nginx.com     ev = obj;
43327Svbart@nginx.com 
43427Svbart@nginx.com     c = nxt_event_write_timer_conn(ev);
43527Svbart@nginx.com     c->socket.timedout = 1;
43627Svbart@nginx.com     c->socket.closed = 1;
43727Svbart@nginx.com 
43827Svbart@nginx.com     nxt_debug(task, "controller conn write timeout");
43927Svbart@nginx.com 
44027Svbart@nginx.com     nxt_controller_conn_close(task, c, data);
44120Sigor@sysoev.ru }
44220Sigor@sysoev.ru 
44320Sigor@sysoev.ru 
44420Sigor@sysoev.ru static const nxt_event_conn_state_t  nxt_controller_conn_close_state
44520Sigor@sysoev.ru     nxt_aligned(64) =
44620Sigor@sysoev.ru {
44720Sigor@sysoev.ru     NXT_EVENT_NO_BUF_PROCESS,
44820Sigor@sysoev.ru     NXT_EVENT_TIMER_NO_AUTORESET,
44920Sigor@sysoev.ru 
45020Sigor@sysoev.ru     nxt_controller_conn_free,
45120Sigor@sysoev.ru     NULL,
45220Sigor@sysoev.ru     NULL,
45320Sigor@sysoev.ru 
45420Sigor@sysoev.ru     NULL,
45520Sigor@sysoev.ru     NULL,
45620Sigor@sysoev.ru     0,
45720Sigor@sysoev.ru };
45820Sigor@sysoev.ru 
45920Sigor@sysoev.ru 
46020Sigor@sysoev.ru static void
46120Sigor@sysoev.ru nxt_controller_conn_close(nxt_task_t *task, void *obj, void *data)
46220Sigor@sysoev.ru {
46320Sigor@sysoev.ru     nxt_event_conn_t  *c;
46420Sigor@sysoev.ru 
46520Sigor@sysoev.ru     c = obj;
46620Sigor@sysoev.ru 
46720Sigor@sysoev.ru     nxt_debug(task, "controller conn close");
46820Sigor@sysoev.ru 
46927Svbart@nginx.com     nxt_queue_remove(&c->link);
47027Svbart@nginx.com 
47120Sigor@sysoev.ru     c->write_state = &nxt_controller_conn_close_state;
47220Sigor@sysoev.ru 
47320Sigor@sysoev.ru     nxt_event_conn_close(task->thread->engine, c);
47420Sigor@sysoev.ru }
47520Sigor@sysoev.ru 
47620Sigor@sysoev.ru 
47720Sigor@sysoev.ru static void
47820Sigor@sysoev.ru nxt_controller_conn_free(nxt_task_t *task, void *obj, void *data)
47920Sigor@sysoev.ru {
48020Sigor@sysoev.ru     nxt_event_conn_t  *c;
48120Sigor@sysoev.ru 
48220Sigor@sysoev.ru     c = obj;
48320Sigor@sysoev.ru 
48420Sigor@sysoev.ru     nxt_debug(task, "controller conn free");
48520Sigor@sysoev.ru 
48620Sigor@sysoev.ru     nxt_mem_pool_destroy(c->mem_pool);
48720Sigor@sysoev.ru 
48820Sigor@sysoev.ru     //nxt_free(c);
48920Sigor@sysoev.ru }
49027Svbart@nginx.com 
49127Svbart@nginx.com 
49227Svbart@nginx.com static nxt_int_t
49327Svbart@nginx.com nxt_controller_request_content_length(void *ctx, nxt_str_t *name,
49427Svbart@nginx.com     nxt_str_t *value, uintptr_t data)
49527Svbart@nginx.com {
49627Svbart@nginx.com     off_t                     length;
49727Svbart@nginx.com     nxt_controller_request_t  *r;
49827Svbart@nginx.com 
49927Svbart@nginx.com     r = ctx;
50027Svbart@nginx.com 
50127Svbart@nginx.com     length = nxt_off_t_parse(value->start, value->length);
50227Svbart@nginx.com 
50327Svbart@nginx.com     if (nxt_fast_path(length > 0)) {
50427Svbart@nginx.com         /* TODO length too big */
50527Svbart@nginx.com 
50627Svbart@nginx.com         r->length = length;
50727Svbart@nginx.com         return NXT_OK;
50827Svbart@nginx.com     }
50927Svbart@nginx.com 
51027Svbart@nginx.com     /* TODO logging (task?) */
51127Svbart@nginx.com 
51227Svbart@nginx.com     return NXT_ERROR;
51327Svbart@nginx.com }
51427Svbart@nginx.com 
51527Svbart@nginx.com 
51627Svbart@nginx.com static void
51727Svbart@nginx.com nxt_controller_process_request(nxt_task_t *task, nxt_event_conn_t *c,
51827Svbart@nginx.com     nxt_controller_request_t *r)
51927Svbart@nginx.com {
52029Svbart@nginx.com     nxt_buf_t  *b;
52127Svbart@nginx.com 
522*33Svbart@nginx.com     static const nxt_str_t resp418
523*33Svbart@nginx.com         = nxt_string("HTTP/1.0 418 I'm a teapot\r\n\r\nerror\r\n");
52427Svbart@nginx.com 
525*33Svbart@nginx.com     if (nxt_controller_request_body_parse(task, c, r) != NXT_OK) {
526*33Svbart@nginx.com         goto error;
52729Svbart@nginx.com     }
52827Svbart@nginx.com 
529*33Svbart@nginx.com     nxt_controller_conf_output(task, c, r);
530*33Svbart@nginx.com 
531*33Svbart@nginx.com     return;
532*33Svbart@nginx.com 
533*33Svbart@nginx.com error:
534*33Svbart@nginx.com 
535*33Svbart@nginx.com     b = nxt_buf_mem_alloc(c->mem_pool, resp418.length, 0);
53629Svbart@nginx.com     if (nxt_slow_path(b == NULL)) {
53727Svbart@nginx.com         nxt_controller_conn_close(task, c, r);
53827Svbart@nginx.com         return;
53927Svbart@nginx.com     }
54027Svbart@nginx.com 
541*33Svbart@nginx.com     b->mem.free = nxt_cpymem(b->mem.free, resp418.start, resp418.length);
54227Svbart@nginx.com 
54329Svbart@nginx.com     c->write = b;
54427Svbart@nginx.com     c->write_state = &nxt_controller_conn_write_state;
54527Svbart@nginx.com 
54627Svbart@nginx.com     nxt_event_conn_write(task->thread->engine, c);
54727Svbart@nginx.com }
54827Svbart@nginx.com 
54927Svbart@nginx.com 
55027Svbart@nginx.com static nxt_int_t
551*33Svbart@nginx.com nxt_controller_request_body_parse(nxt_task_t *task, nxt_event_conn_t *c,
552*33Svbart@nginx.com     nxt_controller_request_t *r)
55327Svbart@nginx.com {
55429Svbart@nginx.com     nxt_buf_t              *b;
55529Svbart@nginx.com     nxt_conf_json_value_t  *value;
55629Svbart@nginx.com 
55729Svbart@nginx.com     b = c->read;
55829Svbart@nginx.com 
55929Svbart@nginx.com     value = nxt_conf_json_parse(&b->mem, c->mem_pool);
56029Svbart@nginx.com 
56129Svbart@nginx.com     if (value == NULL) {
56229Svbart@nginx.com         return NXT_ERROR;
56329Svbart@nginx.com     }
56429Svbart@nginx.com 
565*33Svbart@nginx.com     r->conf = value;
566*33Svbart@nginx.com 
56727Svbart@nginx.com     return NXT_OK;
56827Svbart@nginx.com }
569*33Svbart@nginx.com 
570*33Svbart@nginx.com 
571*33Svbart@nginx.com static void
572*33Svbart@nginx.com nxt_controller_conf_output(nxt_task_t *task, nxt_event_conn_t *c,
573*33Svbart@nginx.com     nxt_controller_request_t *r)
574*33Svbart@nginx.com {
575*33Svbart@nginx.com     nxt_buf_t  *b;
576*33Svbart@nginx.com 
577*33Svbart@nginx.com     static const nxt_str_t head = nxt_string("HTTP/1.0 200 OK\r\n\r\n");
578*33Svbart@nginx.com 
579*33Svbart@nginx.com     b = nxt_buf_mem_alloc(c->mem_pool, head.length, 0);
580*33Svbart@nginx.com     if (nxt_slow_path(b == NULL)) {
581*33Svbart@nginx.com         nxt_controller_conn_close(task, c, r);
582*33Svbart@nginx.com         return;
583*33Svbart@nginx.com     }
584*33Svbart@nginx.com 
585*33Svbart@nginx.com     b->mem.free = nxt_cpymem(b->mem.free, head.start, head.length);
586*33Svbart@nginx.com 
587*33Svbart@nginx.com     c->write = b;
588*33Svbart@nginx.com 
589*33Svbart@nginx.com     b = nxt_conf_json_print(r->conf, c->mem_pool);
590*33Svbart@nginx.com 
591*33Svbart@nginx.com     if (b == NULL) {
592*33Svbart@nginx.com         nxt_controller_conn_close(task, c, r);
593*33Svbart@nginx.com         return;
594*33Svbart@nginx.com     }
595*33Svbart@nginx.com 
596*33Svbart@nginx.com     c->write->next = b;
597*33Svbart@nginx.com     c->write_state = &nxt_controller_conn_write_state;
598*33Svbart@nginx.com 
599*33Svbart@nginx.com     nxt_event_conn_write(task->thread->engine, c);
600*33Svbart@nginx.com     return;
601*33Svbart@nginx.com }
602