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