xref: /unit/src/nxt_http_proxy.c (revision 1394)
11270Sigor@sysoev.ru 
21270Sigor@sysoev.ru /*
31270Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
41270Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
51270Sigor@sysoev.ru  */
61270Sigor@sysoev.ru 
71270Sigor@sysoev.ru #include <nxt_router.h>
81270Sigor@sysoev.ru #include <nxt_http.h>
9*1394Sigor@sysoev.ru #include <nxt_upstream.h>
101270Sigor@sysoev.ru 
111270Sigor@sysoev.ru 
12*1394Sigor@sysoev.ru struct nxt_upstream_proxy_s {
13*1394Sigor@sysoev.ru     nxt_sockaddr_t  *sockaddr;
14*1394Sigor@sysoev.ru     uint8_t         protocol;
151270Sigor@sysoev.ru };
161270Sigor@sysoev.ru 
171270Sigor@sysoev.ru 
18*1394Sigor@sysoev.ru static void nxt_http_proxy_server_get(nxt_task_t *task,
19*1394Sigor@sysoev.ru     nxt_upstream_server_t *us);
20*1394Sigor@sysoev.ru static void nxt_http_proxy_upstream_ready(nxt_task_t *task,
21*1394Sigor@sysoev.ru     nxt_upstream_server_t *us);
22*1394Sigor@sysoev.ru static void nxt_http_proxy_upstream_error(nxt_task_t *task,
23*1394Sigor@sysoev.ru     nxt_upstream_server_t *us);
241270Sigor@sysoev.ru static nxt_http_action_t *nxt_http_proxy_handler(nxt_task_t *task,
251270Sigor@sysoev.ru     nxt_http_request_t *r, nxt_http_action_t *action);
261270Sigor@sysoev.ru static void nxt_http_proxy_header_send(nxt_task_t *task, void *obj, void *data);
271270Sigor@sysoev.ru static void nxt_http_proxy_header_sent(nxt_task_t *task, void *obj, void *data);
281270Sigor@sysoev.ru static void nxt_http_proxy_header_read(nxt_task_t *task, void *obj, void *data);
291270Sigor@sysoev.ru static void nxt_http_proxy_send_body(nxt_task_t *task, void *obj, void *data);
301271Sigor@sysoev.ru static void nxt_http_proxy_request_send(nxt_task_t *task,
311271Sigor@sysoev.ru     nxt_http_request_t *r, nxt_buf_t *out);
321270Sigor@sysoev.ru static void nxt_http_proxy_read(nxt_task_t *task, void *obj, void *data);
331270Sigor@sysoev.ru static void nxt_http_proxy_buf_mem_completion(nxt_task_t *task, void *obj,
341270Sigor@sysoev.ru     void *data);
351270Sigor@sysoev.ru static void nxt_http_proxy_error(nxt_task_t *task, void *obj, void *data);
361270Sigor@sysoev.ru 
371270Sigor@sysoev.ru 
381270Sigor@sysoev.ru static const nxt_http_request_state_t  nxt_http_proxy_header_send_state;
391270Sigor@sysoev.ru static const nxt_http_request_state_t  nxt_http_proxy_header_sent_state;
401270Sigor@sysoev.ru static const nxt_http_request_state_t  nxt_http_proxy_header_read_state;
411270Sigor@sysoev.ru static const nxt_http_request_state_t  nxt_http_proxy_read_state;
421270Sigor@sysoev.ru 
431270Sigor@sysoev.ru 
44*1394Sigor@sysoev.ru static const nxt_upstream_server_proto_t  nxt_upstream_simple_proto = {
45*1394Sigor@sysoev.ru     .get = nxt_http_proxy_server_get,
46*1394Sigor@sysoev.ru };
47*1394Sigor@sysoev.ru 
48*1394Sigor@sysoev.ru 
49*1394Sigor@sysoev.ru static const nxt_upstream_peer_state_t  nxt_upstream_proxy_state = {
50*1394Sigor@sysoev.ru     .ready = nxt_http_proxy_upstream_ready,
51*1394Sigor@sysoev.ru     .error = nxt_http_proxy_upstream_error,
52*1394Sigor@sysoev.ru };
53*1394Sigor@sysoev.ru 
54*1394Sigor@sysoev.ru 
551270Sigor@sysoev.ru nxt_int_t
561270Sigor@sysoev.ru nxt_http_proxy_create(nxt_mp_t *mp, nxt_http_action_t *action)
571270Sigor@sysoev.ru {
58*1394Sigor@sysoev.ru     nxt_str_t             name;
59*1394Sigor@sysoev.ru     nxt_sockaddr_t        *sa;
60*1394Sigor@sysoev.ru     nxt_upstream_t        *up;
61*1394Sigor@sysoev.ru     nxt_upstream_proxy_t  *proxy;
621270Sigor@sysoev.ru 
631270Sigor@sysoev.ru     sa = NULL;
641270Sigor@sysoev.ru     name = action->name;
651270Sigor@sysoev.ru 
661270Sigor@sysoev.ru     if (nxt_str_start(&name, "http://", 7)) {
671270Sigor@sysoev.ru         name.length -= 7;
681270Sigor@sysoev.ru         name.start += 7;
691270Sigor@sysoev.ru 
701270Sigor@sysoev.ru         sa = nxt_sockaddr_parse(mp, &name);
711270Sigor@sysoev.ru         if (nxt_slow_path(sa == NULL)) {
721270Sigor@sysoev.ru             return NXT_ERROR;
731270Sigor@sysoev.ru         }
741270Sigor@sysoev.ru 
751270Sigor@sysoev.ru         sa->type = SOCK_STREAM;
761270Sigor@sysoev.ru     }
771270Sigor@sysoev.ru 
781270Sigor@sysoev.ru     if (sa != NULL) {
79*1394Sigor@sysoev.ru         up = nxt_mp_alloc(mp, sizeof(nxt_upstream_t));
80*1394Sigor@sysoev.ru         if (nxt_slow_path(up == NULL)) {
811270Sigor@sysoev.ru             return NXT_ERROR;
821270Sigor@sysoev.ru         }
831270Sigor@sysoev.ru 
84*1394Sigor@sysoev.ru         up->name.length = sa->length;
85*1394Sigor@sysoev.ru         up->name.start = nxt_sockaddr_start(sa);
86*1394Sigor@sysoev.ru         up->proto = &nxt_upstream_simple_proto;
871270Sigor@sysoev.ru 
88*1394Sigor@sysoev.ru         proxy = nxt_mp_alloc(mp, sizeof(nxt_upstream_proxy_t));
89*1394Sigor@sysoev.ru         if (nxt_slow_path(proxy == NULL)) {
90*1394Sigor@sysoev.ru             return NXT_ERROR;
91*1394Sigor@sysoev.ru         }
92*1394Sigor@sysoev.ru 
93*1394Sigor@sysoev.ru         proxy->sockaddr = sa;
94*1394Sigor@sysoev.ru         proxy->protocol = NXT_HTTP_PROTO_H1;
95*1394Sigor@sysoev.ru         up->type.proxy = proxy;
96*1394Sigor@sysoev.ru 
97*1394Sigor@sysoev.ru         action->u.upstream = up;
981270Sigor@sysoev.ru         action->handler = nxt_http_proxy_handler;
991270Sigor@sysoev.ru     }
1001270Sigor@sysoev.ru 
1011270Sigor@sysoev.ru     return NXT_OK;
1021270Sigor@sysoev.ru }
1031270Sigor@sysoev.ru 
1041270Sigor@sysoev.ru 
1051270Sigor@sysoev.ru static nxt_http_action_t *
1061270Sigor@sysoev.ru nxt_http_proxy_handler(nxt_task_t *task, nxt_http_request_t *r,
1071270Sigor@sysoev.ru     nxt_http_action_t *action)
1081270Sigor@sysoev.ru {
109*1394Sigor@sysoev.ru     return nxt_upstream_proxy_handler(task, r, action->u.upstream);
110*1394Sigor@sysoev.ru }
111*1394Sigor@sysoev.ru 
112*1394Sigor@sysoev.ru 
113*1394Sigor@sysoev.ru nxt_http_action_t *
114*1394Sigor@sysoev.ru nxt_upstream_proxy_handler(nxt_task_t *task, nxt_http_request_t *r,
115*1394Sigor@sysoev.ru     nxt_upstream_t *upstream)
116*1394Sigor@sysoev.ru {
117*1394Sigor@sysoev.ru     nxt_http_peer_t        *peer;
118*1394Sigor@sysoev.ru     nxt_upstream_server_t  *us;
119*1394Sigor@sysoev.ru 
120*1394Sigor@sysoev.ru     us = nxt_mp_zalloc(r->mem_pool, sizeof(nxt_upstream_server_t));
121*1394Sigor@sysoev.ru     if (nxt_slow_path(us == NULL)) {
122*1394Sigor@sysoev.ru         nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
123*1394Sigor@sysoev.ru         return NULL;
124*1394Sigor@sysoev.ru     }
1251270Sigor@sysoev.ru 
1261270Sigor@sysoev.ru     peer = nxt_mp_zalloc(r->mem_pool, sizeof(nxt_http_peer_t));
1271270Sigor@sysoev.ru     if (nxt_slow_path(peer == NULL)) {
1281270Sigor@sysoev.ru         nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
1291270Sigor@sysoev.ru         return NULL;
1301270Sigor@sysoev.ru     }
1311270Sigor@sysoev.ru 
1321270Sigor@sysoev.ru     peer->request = r;
1331270Sigor@sysoev.ru     r->peer = peer;
1341270Sigor@sysoev.ru 
1351270Sigor@sysoev.ru     nxt_mp_retain(r->mem_pool);
1361270Sigor@sysoev.ru 
137*1394Sigor@sysoev.ru     us->state = &nxt_upstream_proxy_state;
138*1394Sigor@sysoev.ru     us->peer.http = peer;
139*1394Sigor@sysoev.ru     peer->server = us;
140*1394Sigor@sysoev.ru 
141*1394Sigor@sysoev.ru     us->upstream = upstream;
142*1394Sigor@sysoev.ru     upstream->proto->get(task, us);
1431270Sigor@sysoev.ru 
1441270Sigor@sysoev.ru     return NULL;
1451270Sigor@sysoev.ru }
1461270Sigor@sysoev.ru 
1471270Sigor@sysoev.ru 
1481270Sigor@sysoev.ru static void
149*1394Sigor@sysoev.ru nxt_http_proxy_server_get(nxt_task_t *task, nxt_upstream_server_t *us)
1501270Sigor@sysoev.ru {
151*1394Sigor@sysoev.ru     nxt_upstream_proxy_t  *proxy;
152*1394Sigor@sysoev.ru 
153*1394Sigor@sysoev.ru     proxy = us->upstream->type.proxy;
154*1394Sigor@sysoev.ru 
155*1394Sigor@sysoev.ru     us->sockaddr = proxy->sockaddr;
156*1394Sigor@sysoev.ru     us->protocol = proxy->protocol;
157*1394Sigor@sysoev.ru 
158*1394Sigor@sysoev.ru     us->state->ready(task, us);
159*1394Sigor@sysoev.ru }
160*1394Sigor@sysoev.ru 
161*1394Sigor@sysoev.ru 
162*1394Sigor@sysoev.ru static void
163*1394Sigor@sysoev.ru nxt_http_proxy_upstream_ready(nxt_task_t *task, nxt_upstream_server_t *us)
164*1394Sigor@sysoev.ru {
165*1394Sigor@sysoev.ru     nxt_http_peer_t  *peer;
166*1394Sigor@sysoev.ru 
167*1394Sigor@sysoev.ru     peer = us->peer.http;
168*1394Sigor@sysoev.ru 
169*1394Sigor@sysoev.ru     peer->protocol = us->protocol;
1701270Sigor@sysoev.ru 
1711270Sigor@sysoev.ru     peer->request->state = &nxt_http_proxy_header_send_state;
1721270Sigor@sysoev.ru 
1731270Sigor@sysoev.ru     nxt_http_proto[peer->protocol].peer_connect(task, peer);
1741270Sigor@sysoev.ru }
1751270Sigor@sysoev.ru 
1761270Sigor@sysoev.ru 
177*1394Sigor@sysoev.ru static void
178*1394Sigor@sysoev.ru nxt_http_proxy_upstream_error(nxt_task_t *task, nxt_upstream_server_t *us)
179*1394Sigor@sysoev.ru {
180*1394Sigor@sysoev.ru     nxt_http_request_t  *r;
181*1394Sigor@sysoev.ru 
182*1394Sigor@sysoev.ru     r = us->peer.http->request;
183*1394Sigor@sysoev.ru 
184*1394Sigor@sysoev.ru     nxt_mp_release(r->mem_pool);
185*1394Sigor@sysoev.ru 
186*1394Sigor@sysoev.ru     nxt_http_request_error(task, r, NXT_HTTP_BAD_GATEWAY);
187*1394Sigor@sysoev.ru }
188*1394Sigor@sysoev.ru 
189*1394Sigor@sysoev.ru 
1901270Sigor@sysoev.ru static const nxt_http_request_state_t  nxt_http_proxy_header_send_state
1911270Sigor@sysoev.ru     nxt_aligned(64) =
1921270Sigor@sysoev.ru {
1931270Sigor@sysoev.ru     .ready_handler = nxt_http_proxy_header_send,
1941270Sigor@sysoev.ru     .error_handler = nxt_http_proxy_error,
1951270Sigor@sysoev.ru };
1961270Sigor@sysoev.ru 
1971270Sigor@sysoev.ru 
1981270Sigor@sysoev.ru static void
1991270Sigor@sysoev.ru nxt_http_proxy_header_send(nxt_task_t *task, void *obj, void *data)
2001270Sigor@sysoev.ru {
2011270Sigor@sysoev.ru     nxt_http_peer_t     *peer;
2021270Sigor@sysoev.ru     nxt_http_request_t  *r;
2031270Sigor@sysoev.ru 
2041270Sigor@sysoev.ru     r = obj;
2051270Sigor@sysoev.ru     peer = data;
2061270Sigor@sysoev.ru     r->state = &nxt_http_proxy_header_sent_state;
2071270Sigor@sysoev.ru 
2081270Sigor@sysoev.ru     nxt_http_proto[peer->protocol].peer_header_send(task, peer);
2091270Sigor@sysoev.ru }
2101270Sigor@sysoev.ru 
2111270Sigor@sysoev.ru 
2121270Sigor@sysoev.ru static const nxt_http_request_state_t  nxt_http_proxy_header_sent_state
2131270Sigor@sysoev.ru     nxt_aligned(64) =
2141270Sigor@sysoev.ru {
2151270Sigor@sysoev.ru     .ready_handler = nxt_http_proxy_header_sent,
2161270Sigor@sysoev.ru     .error_handler = nxt_http_proxy_error,
2171270Sigor@sysoev.ru };
2181270Sigor@sysoev.ru 
2191270Sigor@sysoev.ru 
2201270Sigor@sysoev.ru static void
2211270Sigor@sysoev.ru nxt_http_proxy_header_sent(nxt_task_t *task, void *obj, void *data)
2221270Sigor@sysoev.ru {
2231270Sigor@sysoev.ru     nxt_http_peer_t     *peer;
2241270Sigor@sysoev.ru     nxt_http_request_t  *r;
2251270Sigor@sysoev.ru 
2261270Sigor@sysoev.ru     r = obj;
2271270Sigor@sysoev.ru     peer = data;
2281270Sigor@sysoev.ru     r->state = &nxt_http_proxy_header_read_state;
2291270Sigor@sysoev.ru 
2301270Sigor@sysoev.ru     nxt_http_proto[peer->protocol].peer_header_read(task, peer);
2311270Sigor@sysoev.ru }
2321270Sigor@sysoev.ru 
2331270Sigor@sysoev.ru 
2341270Sigor@sysoev.ru static const nxt_http_request_state_t  nxt_http_proxy_header_read_state
2351270Sigor@sysoev.ru     nxt_aligned(64) =
2361270Sigor@sysoev.ru {
2371270Sigor@sysoev.ru     .ready_handler = nxt_http_proxy_header_read,
2381270Sigor@sysoev.ru     .error_handler = nxt_http_proxy_error,
2391270Sigor@sysoev.ru };
2401270Sigor@sysoev.ru 
2411270Sigor@sysoev.ru 
2421270Sigor@sysoev.ru static void
2431270Sigor@sysoev.ru nxt_http_proxy_header_read(nxt_task_t *task, void *obj, void *data)
2441270Sigor@sysoev.ru {
2451270Sigor@sysoev.ru     nxt_http_peer_t     *peer;
2461270Sigor@sysoev.ru     nxt_http_field_t    *f, *field;
2471270Sigor@sysoev.ru     nxt_http_request_t  *r;
2481270Sigor@sysoev.ru 
2491270Sigor@sysoev.ru     r = obj;
2501270Sigor@sysoev.ru     peer = data;
2511270Sigor@sysoev.ru 
2521270Sigor@sysoev.ru     r->status = peer->status;
2531270Sigor@sysoev.ru 
2541270Sigor@sysoev.ru     nxt_debug(task, "http proxy status: %d", peer->status);
2551270Sigor@sysoev.ru 
2561271Sigor@sysoev.ru     if (r->resp.content_length_n > 0) {
2571271Sigor@sysoev.ru         peer->remainder = r->resp.content_length_n;
2581271Sigor@sysoev.ru     }
2591271Sigor@sysoev.ru 
2601270Sigor@sysoev.ru     nxt_list_each(field, peer->fields) {
2611270Sigor@sysoev.ru 
2621270Sigor@sysoev.ru         nxt_debug(task, "http proxy header: \"%*s: %*s\"",
2631270Sigor@sysoev.ru                   (size_t) field->name_length, field->name,
2641270Sigor@sysoev.ru                   (size_t) field->value_length, field->value);
2651270Sigor@sysoev.ru 
2661270Sigor@sysoev.ru         if (!field->skip) {
2671270Sigor@sysoev.ru             f = nxt_list_add(r->resp.fields);
2681270Sigor@sysoev.ru             if (nxt_slow_path(f == NULL)) {
2691270Sigor@sysoev.ru                 nxt_http_proxy_error(task, r, peer);
2701270Sigor@sysoev.ru                 return;
2711270Sigor@sysoev.ru             }
2721270Sigor@sysoev.ru 
2731270Sigor@sysoev.ru             *f = *field;
2741270Sigor@sysoev.ru         }
2751270Sigor@sysoev.ru 
2761270Sigor@sysoev.ru     } nxt_list_loop;
2771270Sigor@sysoev.ru 
2781270Sigor@sysoev.ru     nxt_http_request_header_send(task, r, nxt_http_proxy_send_body, peer);
2791270Sigor@sysoev.ru }
2801270Sigor@sysoev.ru 
2811270Sigor@sysoev.ru 
2821270Sigor@sysoev.ru static void
2831270Sigor@sysoev.ru nxt_http_proxy_send_body(nxt_task_t *task, void *obj, void *data)
2841270Sigor@sysoev.ru {
2851270Sigor@sysoev.ru     nxt_buf_t           *out;
2861270Sigor@sysoev.ru     nxt_http_peer_t     *peer;
2871270Sigor@sysoev.ru     nxt_http_request_t  *r;
2881270Sigor@sysoev.ru 
2891270Sigor@sysoev.ru     r = obj;
2901270Sigor@sysoev.ru     peer = data;
2911270Sigor@sysoev.ru     out = peer->body;
2921270Sigor@sysoev.ru 
2931270Sigor@sysoev.ru     if (out != NULL) {
2941270Sigor@sysoev.ru         peer->body = NULL;
2951271Sigor@sysoev.ru         nxt_http_proxy_request_send(task, r, out);
2961270Sigor@sysoev.ru     }
2971270Sigor@sysoev.ru 
2981270Sigor@sysoev.ru     r->state = &nxt_http_proxy_read_state;
2991270Sigor@sysoev.ru 
3001270Sigor@sysoev.ru     nxt_http_proto[peer->protocol].peer_read(task, peer);
3011270Sigor@sysoev.ru }
3021270Sigor@sysoev.ru 
3031270Sigor@sysoev.ru 
3041271Sigor@sysoev.ru static void
3051271Sigor@sysoev.ru nxt_http_proxy_request_send(nxt_task_t *task, nxt_http_request_t *r,
3061271Sigor@sysoev.ru     nxt_buf_t *out)
3071271Sigor@sysoev.ru {
3081271Sigor@sysoev.ru     size_t  length;
3091271Sigor@sysoev.ru 
3101271Sigor@sysoev.ru     if (r->peer->remainder > 0) {
3111271Sigor@sysoev.ru         length = nxt_buf_chain_length(out);
3121271Sigor@sysoev.ru         r->peer->remainder -= length;
3131271Sigor@sysoev.ru     }
3141271Sigor@sysoev.ru 
3151271Sigor@sysoev.ru     nxt_http_request_send(task, r, out);
3161271Sigor@sysoev.ru }
3171271Sigor@sysoev.ru 
3181271Sigor@sysoev.ru 
3191270Sigor@sysoev.ru static const nxt_http_request_state_t  nxt_http_proxy_read_state
3201270Sigor@sysoev.ru     nxt_aligned(64) =
3211270Sigor@sysoev.ru {
3221270Sigor@sysoev.ru     .ready_handler = nxt_http_proxy_read,
3231270Sigor@sysoev.ru     .error_handler = nxt_http_proxy_error,
3241270Sigor@sysoev.ru };
3251270Sigor@sysoev.ru 
3261270Sigor@sysoev.ru 
3271270Sigor@sysoev.ru static void
3281270Sigor@sysoev.ru nxt_http_proxy_read(nxt_task_t *task, void *obj, void *data)
3291270Sigor@sysoev.ru {
3301270Sigor@sysoev.ru     nxt_buf_t           *out;
3311270Sigor@sysoev.ru     nxt_bool_t          last;
3321270Sigor@sysoev.ru     nxt_http_peer_t     *peer;
3331270Sigor@sysoev.ru     nxt_http_request_t  *r;
3341270Sigor@sysoev.ru 
3351270Sigor@sysoev.ru     r = obj;
3361270Sigor@sysoev.ru     peer = data;
3371270Sigor@sysoev.ru     out = peer->body;
3381270Sigor@sysoev.ru     peer->body = NULL;
3391270Sigor@sysoev.ru     last = nxt_buf_is_last(out);
3401270Sigor@sysoev.ru 
3411271Sigor@sysoev.ru     nxt_http_proxy_request_send(task, r, out);
3421270Sigor@sysoev.ru 
3431270Sigor@sysoev.ru     if (!last) {
3441270Sigor@sysoev.ru         nxt_http_proto[peer->protocol].peer_read(task, peer);
3451270Sigor@sysoev.ru 
3461270Sigor@sysoev.ru     } else {
3471271Sigor@sysoev.ru         r->inconsistent = (peer->remainder != 0);
3481271Sigor@sysoev.ru 
3491270Sigor@sysoev.ru         nxt_http_proto[peer->protocol].peer_close(task, peer);
3501270Sigor@sysoev.ru 
3511270Sigor@sysoev.ru         nxt_mp_release(r->mem_pool);
3521270Sigor@sysoev.ru     }
3531270Sigor@sysoev.ru }
3541270Sigor@sysoev.ru 
3551270Sigor@sysoev.ru 
3561270Sigor@sysoev.ru nxt_buf_t *
3571270Sigor@sysoev.ru nxt_http_proxy_buf_mem_alloc(nxt_task_t *task, nxt_http_request_t *r,
3581270Sigor@sysoev.ru     size_t size)
3591270Sigor@sysoev.ru {
3601270Sigor@sysoev.ru     nxt_buf_t  *b;
3611270Sigor@sysoev.ru 
3621270Sigor@sysoev.ru     b = nxt_event_engine_buf_mem_alloc(task->thread->engine, size);
3631270Sigor@sysoev.ru     if (nxt_fast_path(b != NULL)) {
3641270Sigor@sysoev.ru         b->completion_handler = nxt_http_proxy_buf_mem_completion;
3651270Sigor@sysoev.ru         b->parent = r;
3661270Sigor@sysoev.ru         nxt_mp_retain(r->mem_pool);
3671270Sigor@sysoev.ru 
3681270Sigor@sysoev.ru     } else {
3691270Sigor@sysoev.ru         nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
3701270Sigor@sysoev.ru     }
3711270Sigor@sysoev.ru 
3721270Sigor@sysoev.ru     return b;
3731270Sigor@sysoev.ru }
3741270Sigor@sysoev.ru 
3751270Sigor@sysoev.ru 
3761270Sigor@sysoev.ru static void
3771270Sigor@sysoev.ru nxt_http_proxy_buf_mem_completion(nxt_task_t *task, void *obj, void *data)
3781270Sigor@sysoev.ru {
3791270Sigor@sysoev.ru     nxt_buf_t           *b, *next;
3801270Sigor@sysoev.ru     nxt_http_peer_t     *peer;
3811270Sigor@sysoev.ru     nxt_http_request_t  *r;
3821270Sigor@sysoev.ru 
3831270Sigor@sysoev.ru     b = obj;
3841270Sigor@sysoev.ru     r = data;
3851270Sigor@sysoev.ru 
3861270Sigor@sysoev.ru     peer = r->peer;
3871270Sigor@sysoev.ru 
3881270Sigor@sysoev.ru     do {
3891270Sigor@sysoev.ru         next = b->next;
3901270Sigor@sysoev.ru 
3911270Sigor@sysoev.ru         nxt_http_proxy_buf_mem_free(task, r, b);
3921270Sigor@sysoev.ru 
3931270Sigor@sysoev.ru         b = next;
3941270Sigor@sysoev.ru     } while (b != NULL);
3951270Sigor@sysoev.ru 
3961270Sigor@sysoev.ru     if (!peer->closed) {
3971270Sigor@sysoev.ru         nxt_http_proto[peer->protocol].peer_read(task, peer);
3981270Sigor@sysoev.ru     }
3991270Sigor@sysoev.ru }
4001270Sigor@sysoev.ru 
4011270Sigor@sysoev.ru 
4021270Sigor@sysoev.ru void
4031270Sigor@sysoev.ru nxt_http_proxy_buf_mem_free(nxt_task_t *task, nxt_http_request_t *r,
4041270Sigor@sysoev.ru     nxt_buf_t *b)
4051270Sigor@sysoev.ru {
4061270Sigor@sysoev.ru     nxt_event_engine_buf_mem_free(task->thread->engine, b);
4071270Sigor@sysoev.ru 
4081270Sigor@sysoev.ru     nxt_mp_release(r->mem_pool);
4091270Sigor@sysoev.ru }
4101270Sigor@sysoev.ru 
4111270Sigor@sysoev.ru 
4121270Sigor@sysoev.ru static void
4131270Sigor@sysoev.ru nxt_http_proxy_error(nxt_task_t *task, void *obj, void *data)
4141270Sigor@sysoev.ru {
4151270Sigor@sysoev.ru     nxt_http_peer_t     *peer;
4161270Sigor@sysoev.ru     nxt_http_request_t  *r;
4171270Sigor@sysoev.ru 
4181270Sigor@sysoev.ru     r = obj;
4191270Sigor@sysoev.ru     peer = r->peer;
4201270Sigor@sysoev.ru 
4211270Sigor@sysoev.ru     nxt_http_proto[peer->protocol].peer_close(task, peer);
4221270Sigor@sysoev.ru 
4231270Sigor@sysoev.ru     nxt_mp_release(r->mem_pool);
4241270Sigor@sysoev.ru 
4251270Sigor@sysoev.ru     nxt_http_request_error(task, r, peer->status);
4261270Sigor@sysoev.ru }
4271270Sigor@sysoev.ru 
4281270Sigor@sysoev.ru 
4291270Sigor@sysoev.ru nxt_int_t
4301270Sigor@sysoev.ru nxt_http_proxy_date(void *ctx, nxt_http_field_t *field, uintptr_t data)
4311270Sigor@sysoev.ru {
4321270Sigor@sysoev.ru     nxt_http_request_t  *r;
4331270Sigor@sysoev.ru 
4341270Sigor@sysoev.ru     r = ctx;
4351270Sigor@sysoev.ru 
4361270Sigor@sysoev.ru     r->resp.date = field;
4371270Sigor@sysoev.ru 
4381270Sigor@sysoev.ru     return NXT_OK;
4391270Sigor@sysoev.ru }
4401270Sigor@sysoev.ru 
4411270Sigor@sysoev.ru 
4421270Sigor@sysoev.ru nxt_int_t
4431270Sigor@sysoev.ru nxt_http_proxy_content_length(void *ctx, nxt_http_field_t *field,
4441270Sigor@sysoev.ru     uintptr_t data)
4451270Sigor@sysoev.ru {
4461270Sigor@sysoev.ru     nxt_off_t           n;
4471270Sigor@sysoev.ru     nxt_http_request_t  *r;
4481270Sigor@sysoev.ru 
4491270Sigor@sysoev.ru     r = ctx;
4501270Sigor@sysoev.ru 
4511270Sigor@sysoev.ru     r->resp.content_length = field;
4521270Sigor@sysoev.ru 
4531270Sigor@sysoev.ru     n = nxt_off_t_parse(field->value, field->value_length);
4541270Sigor@sysoev.ru 
4551270Sigor@sysoev.ru     if (nxt_fast_path(n >= 0)) {
4561270Sigor@sysoev.ru         r->resp.content_length_n = n;
4571270Sigor@sysoev.ru     }
4581270Sigor@sysoev.ru 
4591270Sigor@sysoev.ru     return NXT_OK;
4601270Sigor@sysoev.ru }
4611270Sigor@sysoev.ru 
4621270Sigor@sysoev.ru 
4631270Sigor@sysoev.ru nxt_int_t
4641270Sigor@sysoev.ru nxt_http_proxy_skip(void *ctx, nxt_http_field_t *field, uintptr_t data)
4651270Sigor@sysoev.ru {
4661270Sigor@sysoev.ru     field->skip = 1;
4671270Sigor@sysoev.ru 
4681270Sigor@sysoev.ru     return NXT_OK;
4691270Sigor@sysoev.ru }
470