xref: /unit/src/nxt_http_request.c (revision 2139:99d792169ffb)
1431Sigor@sysoev.ru 
2431Sigor@sysoev.ru /*
3431Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
4431Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
5431Sigor@sysoev.ru  */
6431Sigor@sysoev.ru 
7431Sigor@sysoev.ru #include <nxt_router.h>
8431Sigor@sysoev.ru #include <nxt_http.h>
9431Sigor@sysoev.ru 
10431Sigor@sysoev.ru 
11945Svbart@nginx.com static nxt_int_t nxt_http_validate_host(nxt_str_t *host, nxt_mp_t *mp);
12431Sigor@sysoev.ru static void nxt_http_request_start(nxt_task_t *task, void *obj, void *data);
132133Sz.hong@f5.com static nxt_int_t nxt_http_request_forward(nxt_task_t *task,
142133Sz.hong@f5.com     nxt_http_request_t *r, nxt_http_forward_t *forward);
152133Sz.hong@f5.com static void nxt_http_request_forward_client_ip(nxt_http_request_t *r,
162133Sz.hong@f5.com     nxt_http_forward_t *forward, nxt_array_t *fields);
171936So.canty@f5.com static nxt_sockaddr_t *nxt_http_request_client_ip_sockaddr(
181936So.canty@f5.com     nxt_http_request_t *r, u_char *start, size_t len);
192133Sz.hong@f5.com static void nxt_http_request_forward_protocol(nxt_http_request_t *r,
202133Sz.hong@f5.com     nxt_http_field_t *field);
211563Svbart@nginx.com static void nxt_http_request_ready(nxt_task_t *task, void *obj, void *data);
221011Smax.romanov@nginx.com static void nxt_http_request_proto_info(nxt_task_t *task,
231011Smax.romanov@nginx.com     nxt_http_request_t *r);
24608Sigor@sysoev.ru static void nxt_http_request_mem_buf_completion(nxt_task_t *task, void *obj,
25608Sigor@sysoev.ru     void *data);
26431Sigor@sysoev.ru static void nxt_http_request_done(nxt_task_t *task, void *obj, void *data);
27431Sigor@sysoev.ru 
281183Svbart@nginx.com static u_char *nxt_http_date_cache_handler(u_char *buf, nxt_realtime_t *now,
291183Svbart@nginx.com     struct tm *tm, size_t size, const char *format);
30543Svbart@nginx.com 
312104Sz.hong@f5.com static nxt_http_name_value_t *nxt_http_argument(nxt_array_t *array,
322104Sz.hong@f5.com     u_char *name, size_t name_length, uint32_t hash, u_char *start,
33*2139Sandrew@digital-domain.net     const u_char *end);
342104Sz.hong@f5.com static nxt_int_t nxt_http_cookie_parse(nxt_array_t *cookies, u_char *start,
35*2139Sandrew@digital-domain.net     const u_char *end);
362104Sz.hong@f5.com static nxt_http_name_value_t *nxt_http_cookie(nxt_array_t *array, u_char *name,
37*2139Sandrew@digital-domain.net     size_t name_length, u_char *start, const u_char *end);
382104Sz.hong@f5.com 
392104Sz.hong@f5.com 
402104Sz.hong@f5.com #define NXT_HTTP_COOKIE_HASH                                                  \
412104Sz.hong@f5.com     (nxt_http_field_hash_end(                                                 \
422104Sz.hong@f5.com      nxt_http_field_hash_char(                                                \
432104Sz.hong@f5.com      nxt_http_field_hash_char(                                                \
442104Sz.hong@f5.com      nxt_http_field_hash_char(                                                \
452104Sz.hong@f5.com      nxt_http_field_hash_char(                                                \
462104Sz.hong@f5.com      nxt_http_field_hash_char(                                                \
472104Sz.hong@f5.com      nxt_http_field_hash_char(NXT_HTTP_FIELD_HASH_INIT,                       \
482104Sz.hong@f5.com         'c'), 'o'), 'o'), 'k'), 'i'), 'e')) & 0xFFFF)
492104Sz.hong@f5.com 
50431Sigor@sysoev.ru 
51431Sigor@sysoev.ru static const nxt_http_request_state_t  nxt_http_request_init_state;
52431Sigor@sysoev.ru static const nxt_http_request_state_t  nxt_http_request_body_state;
53431Sigor@sysoev.ru 
54431Sigor@sysoev.ru 
55740Sigor@sysoev.ru nxt_time_string_t  nxt_http_date_cache = {
56740Sigor@sysoev.ru     (nxt_atomic_uint_t) -1,
571183Svbart@nginx.com     nxt_http_date_cache_handler,
581183Svbart@nginx.com     NULL,
591183Svbart@nginx.com     NXT_HTTP_DATE_LEN,
60740Sigor@sysoev.ru     NXT_THREAD_TIME_GMT,
61740Sigor@sysoev.ru     NXT_THREAD_TIME_SEC,
62740Sigor@sysoev.ru };
63740Sigor@sysoev.ru 
64740Sigor@sysoev.ru 
65431Sigor@sysoev.ru nxt_int_t
nxt_http_init(nxt_task_t * task)661459Smax.romanov@nginx.com nxt_http_init(nxt_task_t *task)
67431Sigor@sysoev.ru {
68431Sigor@sysoev.ru     nxt_int_t  ret;
69431Sigor@sysoev.ru 
701459Smax.romanov@nginx.com     ret = nxt_h1p_init(task);
71431Sigor@sysoev.ru 
72431Sigor@sysoev.ru     if (ret != NXT_OK) {
73431Sigor@sysoev.ru         return ret;
74431Sigor@sysoev.ru     }
75431Sigor@sysoev.ru 
761459Smax.romanov@nginx.com     return nxt_http_response_hash_init(task);
77431Sigor@sysoev.ru }
78431Sigor@sysoev.ru 
79431Sigor@sysoev.ru 
80431Sigor@sysoev.ru nxt_int_t
nxt_http_request_host(void * ctx,nxt_http_field_t * field,uintptr_t data)81431Sigor@sysoev.ru nxt_http_request_host(void *ctx, nxt_http_field_t *field, uintptr_t data)
82431Sigor@sysoev.ru {
83945Svbart@nginx.com     nxt_int_t           ret;
84945Svbart@nginx.com     nxt_str_t           host;
85431Sigor@sysoev.ru     nxt_http_request_t  *r;
86431Sigor@sysoev.ru 
87431Sigor@sysoev.ru     r = ctx;
88431Sigor@sysoev.ru 
89945Svbart@nginx.com     if (nxt_slow_path(r->host.start != NULL)) {
90945Svbart@nginx.com         return NXT_HTTP_BAD_REQUEST;
91945Svbart@nginx.com     }
92945Svbart@nginx.com 
93945Svbart@nginx.com     host.length = field->value_length;
94945Svbart@nginx.com     host.start = field->value;
95945Svbart@nginx.com 
96945Svbart@nginx.com     ret = nxt_http_validate_host(&host, r->mem_pool);
97945Svbart@nginx.com 
98945Svbart@nginx.com     if (nxt_fast_path(ret == NXT_OK)) {
99945Svbart@nginx.com         r->host = host;
100945Svbart@nginx.com     }
101945Svbart@nginx.com 
102945Svbart@nginx.com     return ret;
103945Svbart@nginx.com }
104945Svbart@nginx.com 
105945Svbart@nginx.com 
106945Svbart@nginx.com static nxt_int_t
nxt_http_validate_host(nxt_str_t * host,nxt_mp_t * mp)107945Svbart@nginx.com nxt_http_validate_host(nxt_str_t *host, nxt_mp_t *mp)
108945Svbart@nginx.com {
109945Svbart@nginx.com     u_char      *h, ch;
110945Svbart@nginx.com     size_t      i, dot_pos, host_length;
111945Svbart@nginx.com     nxt_bool_t  lowcase;
112945Svbart@nginx.com 
113945Svbart@nginx.com     enum {
114945Svbart@nginx.com         sw_usual,
115945Svbart@nginx.com         sw_literal,
116945Svbart@nginx.com         sw_rest
117945Svbart@nginx.com     } state;
118945Svbart@nginx.com 
119945Svbart@nginx.com     dot_pos = host->length;
120945Svbart@nginx.com     host_length = host->length;
121945Svbart@nginx.com 
122945Svbart@nginx.com     h = host->start;
123945Svbart@nginx.com 
124945Svbart@nginx.com     lowcase = 0;
125945Svbart@nginx.com     state = sw_usual;
126945Svbart@nginx.com 
127945Svbart@nginx.com     for (i = 0; i < host->length; i++) {
128945Svbart@nginx.com         ch = h[i];
129945Svbart@nginx.com 
130945Svbart@nginx.com         if (ch > ']') {
131945Svbart@nginx.com             /* Short path. */
132945Svbart@nginx.com             continue;
133945Svbart@nginx.com         }
134945Svbart@nginx.com 
135945Svbart@nginx.com         switch (ch) {
136945Svbart@nginx.com 
137945Svbart@nginx.com         case '.':
138945Svbart@nginx.com             if (dot_pos == i - 1) {
139945Svbart@nginx.com                 return NXT_HTTP_BAD_REQUEST;
140945Svbart@nginx.com             }
141431Sigor@sysoev.ru 
142945Svbart@nginx.com             dot_pos = i;
143945Svbart@nginx.com             break;
144945Svbart@nginx.com 
145945Svbart@nginx.com         case ':':
146945Svbart@nginx.com             if (state == sw_usual) {
147945Svbart@nginx.com                 host_length = i;
148945Svbart@nginx.com                 state = sw_rest;
149945Svbart@nginx.com             }
150945Svbart@nginx.com 
151945Svbart@nginx.com             break;
152945Svbart@nginx.com 
153945Svbart@nginx.com         case '[':
154945Svbart@nginx.com             if (i == 0) {
155945Svbart@nginx.com                 state = sw_literal;
156945Svbart@nginx.com             }
157945Svbart@nginx.com 
158945Svbart@nginx.com             break;
159945Svbart@nginx.com 
160945Svbart@nginx.com         case ']':
161945Svbart@nginx.com             if (state == sw_literal) {
162945Svbart@nginx.com                 host_length = i + 1;
163945Svbart@nginx.com                 state = sw_rest;
164945Svbart@nginx.com             }
165945Svbart@nginx.com 
166945Svbart@nginx.com             break;
167945Svbart@nginx.com 
168945Svbart@nginx.com         case '/':
169945Svbart@nginx.com             return NXT_HTTP_BAD_REQUEST;
170945Svbart@nginx.com 
171945Svbart@nginx.com         default:
172945Svbart@nginx.com             if (ch >= 'A' && ch <= 'Z') {
173945Svbart@nginx.com                 lowcase = 1;
174945Svbart@nginx.com             }
175945Svbart@nginx.com 
176945Svbart@nginx.com             break;
177945Svbart@nginx.com         }
178945Svbart@nginx.com     }
179945Svbart@nginx.com 
180945Svbart@nginx.com     if (dot_pos == host_length - 1) {
181945Svbart@nginx.com         host_length--;
182945Svbart@nginx.com     }
183945Svbart@nginx.com 
184945Svbart@nginx.com     host->length = host_length;
185945Svbart@nginx.com 
186945Svbart@nginx.com     if (lowcase) {
187945Svbart@nginx.com         host->start = nxt_mp_nget(mp, host_length);
188945Svbart@nginx.com         if (nxt_slow_path(host->start == NULL)) {
189945Svbart@nginx.com             return NXT_HTTP_INTERNAL_SERVER_ERROR;
190945Svbart@nginx.com         }
191945Svbart@nginx.com 
192945Svbart@nginx.com         nxt_memcpy_lowcase(host->start, h, host_length);
193945Svbart@nginx.com     }
194431Sigor@sysoev.ru 
195431Sigor@sysoev.ru     return NXT_OK;
196431Sigor@sysoev.ru }
197431Sigor@sysoev.ru 
198431Sigor@sysoev.ru 
199431Sigor@sysoev.ru nxt_int_t
nxt_http_request_field(void * ctx,nxt_http_field_t * field,uintptr_t offset)200431Sigor@sysoev.ru nxt_http_request_field(void *ctx, nxt_http_field_t *field, uintptr_t offset)
201431Sigor@sysoev.ru {
202431Sigor@sysoev.ru     nxt_http_request_t  *r;
203431Sigor@sysoev.ru 
204431Sigor@sysoev.ru     r = ctx;
205431Sigor@sysoev.ru 
206431Sigor@sysoev.ru     nxt_value_at(nxt_http_field_t *, r, offset) = field;
207431Sigor@sysoev.ru 
208431Sigor@sysoev.ru     return NXT_OK;
209431Sigor@sysoev.ru }
210431Sigor@sysoev.ru 
211431Sigor@sysoev.ru 
212431Sigor@sysoev.ru nxt_int_t
nxt_http_request_content_length(void * ctx,nxt_http_field_t * field,uintptr_t data)213431Sigor@sysoev.ru nxt_http_request_content_length(void *ctx, nxt_http_field_t *field,
214431Sigor@sysoev.ru     uintptr_t data)
215431Sigor@sysoev.ru {
2161401Smax.romanov@nginx.com     nxt_off_t           n, max_body_size;
217431Sigor@sysoev.ru     nxt_http_request_t  *r;
218431Sigor@sysoev.ru 
219431Sigor@sysoev.ru     r = ctx;
220431Sigor@sysoev.ru 
221942Svbart@nginx.com     if (nxt_fast_path(r->content_length == NULL)) {
222942Svbart@nginx.com         r->content_length = field;
223431Sigor@sysoev.ru 
224942Svbart@nginx.com         n = nxt_off_t_parse(field->value, field->value_length);
225942Svbart@nginx.com 
226942Svbart@nginx.com         if (nxt_fast_path(n >= 0)) {
227942Svbart@nginx.com             r->content_length_n = n;
2281401Smax.romanov@nginx.com 
2291401Smax.romanov@nginx.com             max_body_size = r->conf->socket_conf->max_body_size;
2301401Smax.romanov@nginx.com 
2311401Smax.romanov@nginx.com             if (nxt_slow_path(n > max_body_size)) {
2321401Smax.romanov@nginx.com                 return NXT_HTTP_PAYLOAD_TOO_LARGE;
2331401Smax.romanov@nginx.com             }
2341401Smax.romanov@nginx.com 
235942Svbart@nginx.com             return NXT_OK;
236942Svbart@nginx.com         }
237918Svbart@nginx.com     }
238918Svbart@nginx.com 
239945Svbart@nginx.com     return NXT_HTTP_BAD_REQUEST;
240431Sigor@sysoev.ru }
241431Sigor@sysoev.ru 
242431Sigor@sysoev.ru 
243431Sigor@sysoev.ru nxt_http_request_t *
nxt_http_request_create(nxt_task_t * task)244431Sigor@sysoev.ru nxt_http_request_create(nxt_task_t *task)
245431Sigor@sysoev.ru {
246431Sigor@sysoev.ru     nxt_mp_t            *mp;
247608Sigor@sysoev.ru     nxt_buf_t           *last;
248431Sigor@sysoev.ru     nxt_http_request_t  *r;
249431Sigor@sysoev.ru 
2501656Svbart@nginx.com     mp = nxt_mp_create(4096, 128, 512, 32);
251431Sigor@sysoev.ru     if (nxt_slow_path(mp == NULL)) {
252431Sigor@sysoev.ru         return NULL;
253431Sigor@sysoev.ru     }
254431Sigor@sysoev.ru 
255431Sigor@sysoev.ru     r = nxt_mp_zget(mp, sizeof(nxt_http_request_t));
256431Sigor@sysoev.ru     if (nxt_slow_path(r == NULL)) {
257431Sigor@sysoev.ru         goto fail;
258431Sigor@sysoev.ru     }
259431Sigor@sysoev.ru 
260431Sigor@sysoev.ru     r->resp.fields = nxt_list_create(mp, 8, sizeof(nxt_http_field_t));
261451Sigor@sysoev.ru     if (nxt_slow_path(r->resp.fields == NULL)) {
262431Sigor@sysoev.ru         goto fail;
263431Sigor@sysoev.ru     }
264431Sigor@sysoev.ru 
265608Sigor@sysoev.ru     last = nxt_mp_zget(mp, NXT_BUF_SYNC_SIZE);
266608Sigor@sysoev.ru     if (nxt_slow_path(last == NULL)) {
267608Sigor@sysoev.ru         goto fail;
268608Sigor@sysoev.ru     }
269608Sigor@sysoev.ru 
270608Sigor@sysoev.ru     nxt_buf_set_sync(last);
271608Sigor@sysoev.ru     nxt_buf_set_last(last);
272608Sigor@sysoev.ru     last->completion_handler = nxt_http_request_done;
273608Sigor@sysoev.ru     last->parent = r;
274608Sigor@sysoev.ru     r->last = last;
275608Sigor@sysoev.ru 
276431Sigor@sysoev.ru     r->mem_pool = mp;
277431Sigor@sysoev.ru     r->content_length_n = -1;
278431Sigor@sysoev.ru     r->resp.content_length_n = -1;
279431Sigor@sysoev.ru     r->state = &nxt_http_request_init_state;
280431Sigor@sysoev.ru 
281431Sigor@sysoev.ru     return r;
282431Sigor@sysoev.ru 
283431Sigor@sysoev.ru fail:
284431Sigor@sysoev.ru 
285431Sigor@sysoev.ru     nxt_mp_release(mp);
286608Sigor@sysoev.ru 
287431Sigor@sysoev.ru     return NULL;
288431Sigor@sysoev.ru }
289431Sigor@sysoev.ru 
290431Sigor@sysoev.ru 
291431Sigor@sysoev.ru static const nxt_http_request_state_t  nxt_http_request_init_state
292431Sigor@sysoev.ru     nxt_aligned(64) =
293431Sigor@sysoev.ru {
294431Sigor@sysoev.ru     .ready_handler = nxt_http_request_start,
295431Sigor@sysoev.ru     .error_handler = nxt_http_request_close_handler,
296431Sigor@sysoev.ru };
297431Sigor@sysoev.ru 
298431Sigor@sysoev.ru 
299431Sigor@sysoev.ru static void
nxt_http_request_start(nxt_task_t * task,void * obj,void * data)300431Sigor@sysoev.ru nxt_http_request_start(nxt_task_t *task, void *obj, void *data)
301431Sigor@sysoev.ru {
3021936So.canty@f5.com     nxt_int_t           ret;
3032133Sz.hong@f5.com     nxt_socket_conf_t   *skcf;
304431Sigor@sysoev.ru     nxt_http_request_t  *r;
305431Sigor@sysoev.ru 
306431Sigor@sysoev.ru     r = obj;
307431Sigor@sysoev.ru 
308431Sigor@sysoev.ru     r->state = &nxt_http_request_body_state;
309431Sigor@sysoev.ru 
3102133Sz.hong@f5.com     skcf = r->conf->socket_conf;
3112133Sz.hong@f5.com 
3122133Sz.hong@f5.com     if (skcf->forwarded != NULL) {
3132133Sz.hong@f5.com         ret = nxt_http_request_forward(task, r, skcf->forwarded);
3142133Sz.hong@f5.com         if (nxt_slow_path(ret != NXT_OK)) {
3152133Sz.hong@f5.com             goto fail;
3162133Sz.hong@f5.com         }
3172133Sz.hong@f5.com     }
3182133Sz.hong@f5.com 
3192133Sz.hong@f5.com     if (skcf->client_ip != NULL) {
3202133Sz.hong@f5.com         ret = nxt_http_request_forward(task, r, skcf->client_ip);
3212133Sz.hong@f5.com         if (nxt_slow_path(ret != NXT_OK)) {
3222133Sz.hong@f5.com             goto fail;
3232133Sz.hong@f5.com         }
3241936So.canty@f5.com     }
3251936So.canty@f5.com 
326431Sigor@sysoev.ru     nxt_http_request_read_body(task, r);
3272133Sz.hong@f5.com 
3282133Sz.hong@f5.com     return;
3292133Sz.hong@f5.com 
3302133Sz.hong@f5.com fail:
3312133Sz.hong@f5.com     nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
332431Sigor@sysoev.ru }
333431Sigor@sysoev.ru 
334431Sigor@sysoev.ru 
3351936So.canty@f5.com static nxt_int_t
nxt_http_request_forward(nxt_task_t * task,nxt_http_request_t * r,nxt_http_forward_t * forward)3362133Sz.hong@f5.com nxt_http_request_forward(nxt_task_t *task, nxt_http_request_t *r,
3372133Sz.hong@f5.com     nxt_http_forward_t *forward)
3381936So.canty@f5.com {
3392133Sz.hong@f5.com     nxt_int_t                  ret;
3402133Sz.hong@f5.com     nxt_array_t                *client_ip_fields;
3412133Sz.hong@f5.com     nxt_http_field_t           *f, **fields, *protocol_field;
3422133Sz.hong@f5.com     nxt_http_forward_header_t  *client_ip, *protocol;
3431936So.canty@f5.com 
3442132Sz.hong@f5.com     ret = nxt_http_route_addr_rule(r, forward->source, r->remote);
3451936So.canty@f5.com     if (ret <= 0) {
3461936So.canty@f5.com         return NXT_OK;
3471936So.canty@f5.com     }
3481936So.canty@f5.com 
3492132Sz.hong@f5.com     client_ip = &forward->client_ip;
3502133Sz.hong@f5.com     protocol = &forward->protocol;
3511936So.canty@f5.com 
3522133Sz.hong@f5.com     if (client_ip->header != NULL) {
3532133Sz.hong@f5.com         client_ip_fields = nxt_array_create(r->mem_pool, 1,
3542133Sz.hong@f5.com                                             sizeof(nxt_http_field_t *));
3552133Sz.hong@f5.com         if (nxt_slow_path(client_ip_fields == NULL)) {
3562133Sz.hong@f5.com             return NXT_ERROR;
3572133Sz.hong@f5.com         }
3582133Sz.hong@f5.com 
3592133Sz.hong@f5.com     } else {
3602133Sz.hong@f5.com         client_ip_fields = NULL;
3611936So.canty@f5.com     }
3621936So.canty@f5.com 
3632133Sz.hong@f5.com     protocol_field = NULL;
3642133Sz.hong@f5.com 
3651936So.canty@f5.com     nxt_list_each(f, r->fields) {
3662133Sz.hong@f5.com         if (client_ip_fields != NULL
3672133Sz.hong@f5.com             && f->hash == client_ip->header_hash
3681936So.canty@f5.com             && f->value_length > 0
3692133Sz.hong@f5.com             && f->name_length == client_ip->header->length
3702133Sz.hong@f5.com             && nxt_memcasecmp(f->name, client_ip->header->start,
3712133Sz.hong@f5.com                               client_ip->header->length) == 0)
3721936So.canty@f5.com         {
3732133Sz.hong@f5.com             fields = nxt_array_add(client_ip_fields);
3741936So.canty@f5.com             if (nxt_slow_path(fields == NULL)) {
3751936So.canty@f5.com                 return NXT_ERROR;
3761936So.canty@f5.com             }
3771936So.canty@f5.com 
3781936So.canty@f5.com             *fields = f;
3791936So.canty@f5.com         }
3802133Sz.hong@f5.com 
3812133Sz.hong@f5.com         if (protocol->header != NULL
3822133Sz.hong@f5.com             && protocol_field == NULL
3832133Sz.hong@f5.com             && f->hash == protocol->header_hash
3842133Sz.hong@f5.com             && f->value_length > 0
3852133Sz.hong@f5.com             && f->name_length == protocol->header->length
3862133Sz.hong@f5.com             && nxt_memcasecmp(f->name, protocol->header->start,
3872133Sz.hong@f5.com                               protocol->header->length) == 0)
3882133Sz.hong@f5.com         {
3892133Sz.hong@f5.com             protocol_field = f;
3902133Sz.hong@f5.com         }
3911936So.canty@f5.com     } nxt_list_loop;
3921936So.canty@f5.com 
3932133Sz.hong@f5.com     if (client_ip_fields != NULL) {
3942133Sz.hong@f5.com         nxt_http_request_forward_client_ip(r, forward, client_ip_fields);
3952133Sz.hong@f5.com     }
3962133Sz.hong@f5.com 
3972133Sz.hong@f5.com     if (protocol_field != NULL) {
3982133Sz.hong@f5.com         nxt_http_request_forward_protocol(r, protocol_field);
3992133Sz.hong@f5.com     }
4002133Sz.hong@f5.com 
4012133Sz.hong@f5.com     return NXT_OK;
4022133Sz.hong@f5.com }
4032133Sz.hong@f5.com 
4042133Sz.hong@f5.com 
4052133Sz.hong@f5.com static void
nxt_http_request_forward_client_ip(nxt_http_request_t * r,nxt_http_forward_t * forward,nxt_array_t * fields)4062133Sz.hong@f5.com nxt_http_request_forward_client_ip(nxt_http_request_t *r,
4072133Sz.hong@f5.com     nxt_http_forward_t *forward, nxt_array_t *fields)
4082133Sz.hong@f5.com {
4092133Sz.hong@f5.com     u_char            *start, *p;
4102133Sz.hong@f5.com     nxt_int_t         ret, i, len;
4112133Sz.hong@f5.com     nxt_sockaddr_t    *sa, *prev_sa;
4122133Sz.hong@f5.com     nxt_http_field_t  **f;
4132133Sz.hong@f5.com 
4141936So.canty@f5.com     prev_sa = r->remote;
4152133Sz.hong@f5.com     f = (nxt_http_field_t **) fields->elts;
4161936So.canty@f5.com 
4172133Sz.hong@f5.com     i = fields->nelts;
4181936So.canty@f5.com 
4191936So.canty@f5.com     while (i-- > 0) {
4202133Sz.hong@f5.com         start = f[i]->value;
4212133Sz.hong@f5.com         len = f[i]->value_length;
4221936So.canty@f5.com 
4231936So.canty@f5.com         do {
4241936So.canty@f5.com             for (p = start + len - 1; p > start; p--, len--) {
4251936So.canty@f5.com                 if (*p != ' ' && *p != ',') {
4261936So.canty@f5.com                     break;
4271936So.canty@f5.com                 }
4281936So.canty@f5.com             }
4291936So.canty@f5.com 
4301936So.canty@f5.com             for (/* void */; p > start; p--) {
4311936So.canty@f5.com                 if (*p == ' ' || *p == ',') {
4321936So.canty@f5.com                     p++;
4331936So.canty@f5.com                     break;
4341936So.canty@f5.com                 }
4351936So.canty@f5.com             }
4361936So.canty@f5.com 
4371936So.canty@f5.com             sa = nxt_http_request_client_ip_sockaddr(r, p, len - (p - start));
4381936So.canty@f5.com             if (nxt_slow_path(sa == NULL)) {
4391936So.canty@f5.com                 if (prev_sa != NULL) {
4401936So.canty@f5.com                     r->remote = prev_sa;
4411936So.canty@f5.com                 }
4421936So.canty@f5.com 
4432133Sz.hong@f5.com                 return;
4441936So.canty@f5.com             }
4451936So.canty@f5.com 
4462132Sz.hong@f5.com             if (!forward->recursive) {
4471936So.canty@f5.com                 r->remote = sa;
4482133Sz.hong@f5.com                 return;
4491936So.canty@f5.com             }
4501936So.canty@f5.com 
4512132Sz.hong@f5.com             ret = nxt_http_route_addr_rule(r, forward->source, sa);
4521936So.canty@f5.com             if (ret <= 0 || (i == 0 && p == start)) {
4531936So.canty@f5.com                 r->remote = sa;
4542133Sz.hong@f5.com                 return;
4551936So.canty@f5.com             }
4561936So.canty@f5.com 
4571936So.canty@f5.com             prev_sa = sa;
4581936So.canty@f5.com             len = p - 1 - start;
4591936So.canty@f5.com 
4601936So.canty@f5.com         } while (len > 0);
4611936So.canty@f5.com     }
4621936So.canty@f5.com }
4631936So.canty@f5.com 
4641936So.canty@f5.com 
4651936So.canty@f5.com static nxt_sockaddr_t *
nxt_http_request_client_ip_sockaddr(nxt_http_request_t * r,u_char * start,size_t len)4661936So.canty@f5.com nxt_http_request_client_ip_sockaddr(nxt_http_request_t *r, u_char *start,
4671936So.canty@f5.com     size_t len)
4681936So.canty@f5.com {
4691936So.canty@f5.com     nxt_str_t       addr;
4701936So.canty@f5.com     nxt_sockaddr_t  *sa;
4711936So.canty@f5.com 
4721936So.canty@f5.com     addr.start = start;
4731936So.canty@f5.com     addr.length = len;
4741936So.canty@f5.com 
4751936So.canty@f5.com     sa = nxt_sockaddr_parse_optport(r->mem_pool, &addr);
4761936So.canty@f5.com     if (nxt_slow_path(sa == NULL)) {
4771936So.canty@f5.com         return NULL;
4781936So.canty@f5.com     }
4791936So.canty@f5.com 
4801936So.canty@f5.com     switch (sa->u.sockaddr.sa_family) {
4811936So.canty@f5.com         case AF_INET:
4821936So.canty@f5.com             if (sa->u.sockaddr_in.sin_addr.s_addr == INADDR_ANY) {
4831936So.canty@f5.com                 return NULL;
4841936So.canty@f5.com             }
4851936So.canty@f5.com 
4861936So.canty@f5.com             break;
4871936So.canty@f5.com 
4881936So.canty@f5.com #if (NXT_INET6)
4891936So.canty@f5.com         case AF_INET6:
4901936So.canty@f5.com             if (IN6_IS_ADDR_UNSPECIFIED(&sa->u.sockaddr_in6.sin6_addr)) {
4911936So.canty@f5.com                 return NULL;
4921936So.canty@f5.com             }
4931936So.canty@f5.com 
4941936So.canty@f5.com             break;
4951936So.canty@f5.com #endif /* NXT_INET6 */
4961936So.canty@f5.com 
4971936So.canty@f5.com         default:
4981936So.canty@f5.com             return NULL;
499