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); 13*2133Sz.hong@f5.com static nxt_int_t nxt_http_request_forward(nxt_task_t *task, 14*2133Sz.hong@f5.com nxt_http_request_t *r, nxt_http_forward_t *forward); 15*2133Sz.hong@f5.com static void nxt_http_request_forward_client_ip(nxt_http_request_t *r, 16*2133Sz.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); 19*2133Sz.hong@f5.com static void nxt_http_request_forward_protocol(nxt_http_request_t *r, 20*2133Sz.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, 332104Sz.hong@f5.com u_char *end); 342104Sz.hong@f5.com static nxt_int_t nxt_http_cookie_parse(nxt_array_t *cookies, u_char *start, 352104Sz.hong@f5.com u_char *end); 362104Sz.hong@f5.com static nxt_http_name_value_t *nxt_http_cookie(nxt_array_t *array, u_char *name, 372104Sz.hong@f5.com size_t name_length, u_char *start, 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 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 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 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 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 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 * 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 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; 303*2133Sz.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 310*2133Sz.hong@f5.com skcf = r->conf->socket_conf; 311*2133Sz.hong@f5.com 312*2133Sz.hong@f5.com if (skcf->forwarded != NULL) { 313*2133Sz.hong@f5.com ret = nxt_http_request_forward(task, r, skcf->forwarded); 314*2133Sz.hong@f5.com if (nxt_slow_path(ret != NXT_OK)) { 315*2133Sz.hong@f5.com goto fail; 316*2133Sz.hong@f5.com } 317*2133Sz.hong@f5.com } 318*2133Sz.hong@f5.com 319*2133Sz.hong@f5.com if (skcf->client_ip != NULL) { 320*2133Sz.hong@f5.com ret = nxt_http_request_forward(task, r, skcf->client_ip); 321*2133Sz.hong@f5.com if (nxt_slow_path(ret != NXT_OK)) { 322*2133Sz.hong@f5.com goto fail; 323*2133Sz.hong@f5.com } 3241936So.canty@f5.com } 3251936So.canty@f5.com 326431Sigor@sysoev.ru nxt_http_request_read_body(task, r); 327*2133Sz.hong@f5.com 328*2133Sz.hong@f5.com return; 329*2133Sz.hong@f5.com 330*2133Sz.hong@f5.com fail: 331*2133Sz.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 336*2133Sz.hong@f5.com nxt_http_request_forward(nxt_task_t *task, nxt_http_request_t *r, 337*2133Sz.hong@f5.com nxt_http_forward_t *forward) 3381936So.canty@f5.com { 339*2133Sz.hong@f5.com nxt_int_t ret; 340*2133Sz.hong@f5.com nxt_array_t *client_ip_fields; 341*2133Sz.hong@f5.com nxt_http_field_t *f, **fields, *protocol_field; 342*2133Sz.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; 350*2133Sz.hong@f5.com protocol = &forward->protocol; 3511936So.canty@f5.com 352*2133Sz.hong@f5.com if (client_ip->header != NULL) { 353*2133Sz.hong@f5.com client_ip_fields = nxt_array_create(r->mem_pool, 1, 354*2133Sz.hong@f5.com sizeof(nxt_http_field_t *)); 355*2133Sz.hong@f5.com if (nxt_slow_path(client_ip_fields == NULL)) { 356*2133Sz.hong@f5.com return NXT_ERROR; 357*2133Sz.hong@f5.com } 358*2133Sz.hong@f5.com 359*2133Sz.hong@f5.com } else { 360*2133Sz.hong@f5.com client_ip_fields = NULL; 3611936So.canty@f5.com } 3621936So.canty@f5.com 363*2133Sz.hong@f5.com protocol_field = NULL; 364*2133Sz.hong@f5.com 3651936So.canty@f5.com nxt_list_each(f, r->fields) { 366*2133Sz.hong@f5.com if (client_ip_fields != NULL 367*2133Sz.hong@f5.com && f->hash == client_ip->header_hash 3681936So.canty@f5.com && f->value_length > 0 369*2133Sz.hong@f5.com && f->name_length == client_ip->header->length 370*2133Sz.hong@f5.com && nxt_memcasecmp(f->name, client_ip->header->start, 371*2133Sz.hong@f5.com client_ip->header->length) == 0) 3721936So.canty@f5.com { 373*2133Sz.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 } 380*2133Sz.hong@f5.com 381*2133Sz.hong@f5.com if (protocol->header != NULL 382*2133Sz.hong@f5.com && protocol_field == NULL 383*2133Sz.hong@f5.com && f->hash == protocol->header_hash 384*2133Sz.hong@f5.com && f->value_length > 0 385*2133Sz.hong@f5.com && f->name_length == protocol->header->length 386*2133Sz.hong@f5.com && nxt_memcasecmp(f->name, protocol->header->start, 387*2133Sz.hong@f5.com protocol->header->length) == 0) 388*2133Sz.hong@f5.com { 389*2133Sz.hong@f5.com protocol_field = f; 390*2133Sz.hong@f5.com } 3911936So.canty@f5.com } nxt_list_loop; 3921936So.canty@f5.com 393*2133Sz.hong@f5.com if (client_ip_fields != NULL) { 394*2133Sz.hong@f5.com nxt_http_request_forward_client_ip(r, forward, client_ip_fields); 395*2133Sz.hong@f5.com } 396*2133Sz.hong@f5.com 397*2133Sz.hong@f5.com if (protocol_field != NULL) { 398*2133Sz.hong@f5.com nxt_http_request_forward_protocol(r, protocol_field); 399*2133Sz.hong@f5.com } 400*2133Sz.hong@f5.com 401*2133Sz.hong@f5.com return NXT_OK; 402*2133Sz.hong@f5.com } 403*2133Sz.hong@f5.com 404*2133Sz.hong@f5.com 405*2133Sz.hong@f5.com static void 406*2133Sz.hong@f5.com nxt_http_request_forward_client_ip(nxt_http_request_t *r, 407*2133Sz.hong@f5.com nxt_http_forward_t *forward, nxt_array_t *fields) 408*2133Sz.hong@f5.com { 409*2133Sz.hong@f5.com u_char *start, *p; 410*2133Sz.hong@f5.com nxt_int_t ret, i, len; 411*2133Sz.hong@f5.com nxt_sockaddr_t *sa, *prev_sa; 412*2133Sz.hong@f5.com nxt_http_field_t **f; 413*2133Sz.hong@f5.com 4141936So.canty@f5.com prev_sa = r->remote; 415*2133Sz.hong@f5.com f = (nxt_http_field_t **) fields->elts; 4161936So.canty@f5.com 417*2133Sz.hong@f5.com i = fields->nelts; 4181936So.canty@f5.com 4191936So.canty@f5.com while (i-- > 0) { 420*2133Sz.hong@f5.com start = f[i]->value; 421*2133Sz.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 443*2133Sz.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; 448*2133Sz.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; 454*2133Sz.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 * 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; 4991936So.canty@f5.com } 5001936So.canty@f5.com 5011936So.canty@f5.com return sa; 5021936So.canty@f5.com } 5031936So.canty@f5.com 5041936So.canty@f5.com 505*2133Sz.hong@f5.com static void 506*2133Sz.hong@f5.com nxt_http_request_forward_protocol(nxt_http_request_t *r, 507*2133Sz.hong@f5.com nxt_http_field_t *field) 508*2133Sz.hong@f5.com { 509*2133Sz.hong@f5.com if (field->value_length == 4) { 510*2133Sz.hong@f5.com if (nxt_memcasecmp(field->value, "http", 4) == 0) { 511*2133Sz.hong@f5.com r->tls = 0; 512*2133Sz.hong@f5.com } 513*2133Sz.hong@f5.com 514*2133Sz.hong@f5.com } else if (field->value_length == 5) { 515*2133Sz.hong@f5.com if (nxt_memcasecmp(field->value, "https", 5) == 0) { 516*2133Sz.hong@f5.com r->tls = 1; 517*2133Sz.hong@f5.com } 518*2133Sz.hong@f5.com 519*2133Sz.hong@f5.com } else if (field->value_length == 2) { 520*2133Sz.hong@f5.com if (nxt_memcasecmp(field->value, "on", 2) == 0) { 521*2133Sz.hong@f5.com r->tls = 1; 522*2133Sz.hong@f5.com } 523*2133Sz.hong@f5.com } 524*2133Sz.hong@f5.com } 525*2133Sz.hong@f5.com 526*2133Sz.hong@f5.com 527431Sigor@sysoev.ru static const nxt_http_request_state_t nxt_http_request_body_state 528431Sigor@sysoev.ru nxt_aligned(64) = 529431Sigor@sysoev.ru { 5301563Svbart@nginx.com .ready_handler = nxt_http_request_ready, 531431Sigor@sysoev.ru .error_handler = nxt_http_request_close_handler, 532431Sigor@sysoev.ru }; 533431Sigor@sysoev.ru 534431Sigor@sysoev.ru 535431Sigor@sysoev.ru static void 5361563Svbart@nginx.com nxt_http_request_ready(nxt_task_t *task, void *obj, void *data) 537964Sigor@sysoev.ru { 5381264Sigor@sysoev.ru nxt_http_action_t *action; 539964Sigor@sysoev.ru nxt_http_request_t *r; 540964Sigor@sysoev.ru 541964Sigor@sysoev.ru r = obj; 5421264Sigor@sysoev.ru action = r->conf->socket_conf->action; 543964Sigor@sysoev.ru 5441563Svbart@nginx.com nxt_http_request_action(task, r, action); 5451563Svbart@nginx.com } 5461563Svbart@nginx.com 5471563Svbart@nginx.com 5481563Svbart@nginx.com void 5491563Svbart@nginx.com nxt_http_request_action(nxt_task_t *task, nxt_http_request_t *r, 5501563Svbart@nginx.com nxt_http_action_t *action) 5511563Svbart@nginx.com { 5521264Sigor@sysoev.ru if (nxt_fast_path(action != NULL)) { 553964Sigor@sysoev.ru 5541060Sigor@sysoev.ru do { 5551264Sigor@sysoev.ru action = action->handler(task, r, action); 556964Sigor@sysoev.ru 5571264Sigor@sysoev.ru if (action == NULL) { 5581060Sigor@sysoev.ru return; 5591060Sigor@sysoev.ru } 560964Sigor@sysoev.ru 5611264Sigor@sysoev.ru if (action == NXT_HTTP_ACTION_ERROR) { 5621060Sigor@sysoev.ru break; 5631060Sigor@sysoev.ru } 5641060Sigor@sysoev.ru 5651060Sigor@sysoev.ru } while (r->pass_count++ < 255); 566964Sigor@sysoev.ru } 567964Sigor@sysoev.ru 568964Sigor@sysoev.ru nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 569964Sigor@sysoev.ru } 570964Sigor@sysoev.ru 571964Sigor@sysoev.ru 5721264Sigor@sysoev.ru nxt_http_action_t * 5731264Sigor@sysoev.ru nxt_http_application_handler(nxt_task_t *task, nxt_http_request_t *r, 5741264Sigor@sysoev.ru nxt_http_action_t *action) 575431Sigor@sysoev.ru { 5761264Sigor@sysoev.ru nxt_debug(task, "http application handler"); 577431Sigor@sysoev.ru 578431Sigor@sysoev.ru /* 579431Sigor@sysoev.ru * TODO: need an application flag to get local address 580431Sigor@sysoev.ru * required by "SERVER_ADDR" in Pyhton and PHP. Not used in Go. 581431Sigor@sysoev.ru */ 5821011Smax.romanov@nginx.com nxt_http_request_proto_info(task, r); 583431Sigor@sysoev.ru 584967Svbart@nginx.com if (r->host.length != 0) { 5851007Salexander.borisov@nginx.com r->server_name = r->host; 586967Svbart@nginx.com 587967Svbart@nginx.com } else { 5881007Salexander.borisov@nginx.com nxt_str_set(&r->server_name, "localhost"); 589431Sigor@sysoev.ru } 590431Sigor@sysoev.ru 5911925Sz.hong@f5.com nxt_router_process_http_request(task, r, action); 592964Sigor@sysoev.ru 593964Sigor@sysoev.ru return NULL; 594431Sigor@sysoev.ru } 595431Sigor@sysoev.ru 596431Sigor@sysoev.ru 5971011Smax.romanov@nginx.com static void 5981011Smax.romanov@nginx.com nxt_http_request_proto_info(nxt_task_t *task, nxt_http_request_t *r) 5991011Smax.romanov@nginx.com { 6001112Sigor@sysoev.ru if (nxt_fast_path(r->proto.any != NULL)) { 6011112Sigor@sysoev.ru nxt_http_proto[r->protocol].local_addr(task, r); 6021011Smax.romanov@nginx.com } 6031011Smax.romanov@nginx.com } 6041011Smax.romanov@nginx.com 6051011Smax.romanov@nginx.com 606431Sigor@sysoev.ru void 607431Sigor@sysoev.ru nxt_http_request_read_body(nxt_task_t *task, nxt_http_request_t *r) 608431Sigor@sysoev.ru { 6091112Sigor@sysoev.ru if (nxt_fast_path(r->proto.any != NULL)) { 6101112Sigor@sysoev.ru nxt_http_proto[r->protocol].body_read(task, r); 611431Sigor@sysoev.ru } 612431Sigor@sysoev.ru } 613431Sigor@sysoev.ru 614431Sigor@sysoev.ru 615431Sigor@sysoev.ru void 6161148Sigor@sysoev.ru nxt_http_request_header_send(nxt_task_t *task, nxt_http_request_t *r, 6171270Sigor@sysoev.ru nxt_work_handler_t body_handler, void *data) 618431Sigor@sysoev.ru { 619431Sigor@sysoev.ru u_char *p, *end; 620543Svbart@nginx.com nxt_http_field_t *server, *date, *content_length; 621543Svbart@nginx.com 622431Sigor@sysoev.ru /* 623543Svbart@nginx.com * TODO: "Server", "Date", and "Content-Length" processing should be moved 624431Sigor@sysoev.ru * to the last header filter. 625431Sigor@sysoev.ru */ 626431Sigor@sysoev.ru 627431Sigor@sysoev.ru server = nxt_list_zero_add(r->resp.fields); 628431Sigor@sysoev.ru if (nxt_slow_path(server == NULL)) { 629431Sigor@sysoev.ru goto fail; 630431Sigor@sysoev.ru } 631431Sigor@sysoev.ru 632673Svbart@nginx.com nxt_http_field_set(server, "Server", NXT_SERVER); 633431Sigor@sysoev.ru 634543Svbart@nginx.com if (r->resp.date == NULL) { 635543Svbart@nginx.com date = nxt_list_zero_add(r->resp.fields); 636543Svbart@nginx.com if (nxt_slow_path(date == NULL)) { 637543Svbart@nginx.com goto fail; 638543Svbart@nginx.com } 639543Svbart@nginx.com 640543Svbart@nginx.com nxt_http_field_name_set(date, "Date"); 641543Svbart@nginx.com 642740Sigor@sysoev.ru p = nxt_mp_nget(r->mem_pool, nxt_http_date_cache.size); 643543Svbart@nginx.com if (nxt_slow_path(p == NULL)) { 644543Svbart@nginx.com goto fail; 645543Svbart@nginx.com } 646543Svbart@nginx.com 647740Sigor@sysoev.ru (void) nxt_thread_time_string(task->thread, &nxt_http_date_cache, p); 648543Svbart@nginx.com 649543Svbart@nginx.com date->value = p; 650740Sigor@sysoev.ru date->value_length = nxt_http_date_cache.size; 651543Svbart@nginx.com 652543Svbart@nginx.com r->resp.date = date; 653543Svbart@nginx.com } 654543Svbart@nginx.com 655431Sigor@sysoev.ru if (r->resp.content_length_n != -1 656431Sigor@sysoev.ru && (r->resp.content_length == NULL || r->resp.content_length->skip)) 657431Sigor@sysoev.ru { 658431Sigor@sysoev.ru content_length = nxt_list_zero_add(r->resp.fields); 659431Sigor@sysoev.ru if (nxt_slow_path(content_length == NULL)) { 660431Sigor@sysoev.ru goto fail; 661431Sigor@sysoev.ru } 662431Sigor@sysoev.ru 663431Sigor@sysoev.ru nxt_http_field_name_set(content_length, "Content-Length"); 664431Sigor@sysoev.ru 665431Sigor@sysoev.ru p = nxt_mp_nget(r->mem_pool, NXT_OFF_T_LEN); 666431Sigor@sysoev.ru if (nxt_slow_path(p == NULL)) { 667431Sigor@sysoev.ru goto fail; 668431Sigor@sysoev.ru } 669431Sigor@sysoev.ru 670431Sigor@sysoev.ru content_length->value = p; 671431Sigor@sysoev.ru end = nxt_sprintf(p, p + NXT_OFF_T_LEN, "%O", r->resp.content_length_n); 672431Sigor@sysoev.ru content_length->value_length = end - p; 673431Sigor@sysoev.ru 674431Sigor@sysoev.ru r->resp.content_length = content_length; 675431Sigor@sysoev.ru } 676431Sigor@sysoev.ru 6771112Sigor@sysoev.ru if (nxt_fast_path(r->proto.any != NULL)) { 6781270Sigor@sysoev.ru nxt_http_proto[r->protocol].header_send(task, r, body_handler, data); 679431Sigor@sysoev.ru } 680431Sigor@sysoev.ru 681431Sigor@sysoev.ru return; 682431Sigor@sysoev.ru 683431Sigor@sysoev.ru fail: 684431Sigor@sysoev.ru 685431Sigor@sysoev.ru nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 686431Sigor@sysoev.ru } 687431Sigor@sysoev.ru 688431Sigor@sysoev.ru 689431Sigor@sysoev.ru void 6901131Smax.romanov@nginx.com nxt_http_request_ws_frame_start(nxt_task_t *task, nxt_http_request_t *r, 6911131Smax.romanov@nginx.com nxt_buf_t *ws_frame) 6921131Smax.romanov@nginx.com { 6931131Smax.romanov@nginx.com if (r->proto.any != NULL) { 6941131Smax.romanov@nginx.com nxt_http_proto[r->protocol].ws_frame_start(task, r, ws_frame); 6951131Smax.romanov@nginx.com } 6961131Smax.romanov@nginx.com } 6971131Smax.romanov@nginx.com 6981131Smax.romanov@nginx.com 6991131Smax.romanov@nginx.com void 700431Sigor@sysoev.ru nxt_http_request_send(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *out) 701431Sigor@sysoev.ru { 7021112Sigor@sysoev.ru if (nxt_fast_path(r->proto.any != NULL)) { 7031112Sigor@sysoev.ru nxt_http_proto[r->protocol].send(task, r, out); 704431Sigor@sysoev.ru } 705431Sigor@sysoev.ru } 706431Sigor@sysoev.ru 707431Sigor@sysoev.ru 708431Sigor@sysoev.ru nxt_buf_t * 709608Sigor@sysoev.ru nxt_http_buf_mem(nxt_task_t *task, nxt_http_request_t *r, size_t size) 710431Sigor@sysoev.ru { 711431Sigor@sysoev.ru nxt_buf_t *b; 712431Sigor@sysoev.ru 713608Sigor@sysoev.ru b = nxt_buf_mem_alloc(r->mem_pool, size, 0); 714431Sigor@sysoev.ru if (nxt_fast_path(b != NULL)) { 715608Sigor@sysoev.ru b->completion_handler = nxt_http_request_mem_buf_completion; 716431Sigor@sysoev.ru b->parent = r; 717608Sigor@sysoev.ru nxt_mp_retain(r->mem_pool); 718431Sigor@sysoev.ru 719431Sigor@sysoev.ru } else { 720608Sigor@sysoev.ru nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 721431Sigor@sysoev.ru } 722431Sigor@sysoev.ru 723431Sigor@sysoev.ru return b; 724431Sigor@sysoev.ru } 725431Sigor@sysoev.ru 726431Sigor@sysoev.ru 727431Sigor@sysoev.ru static void 728608Sigor@sysoev.ru nxt_http_request_mem_buf_completion(nxt_task_t *task, void *obj, void *data) 729608Sigor@sysoev.ru { 7301269Sigor@sysoev.ru nxt_buf_t *b, *next; 731608Sigor@sysoev.ru nxt_http_request_t *r; 732608Sigor@sysoev.ru 733608Sigor@sysoev.ru b = obj; 734608Sigor@sysoev.ru r = data; 735608Sigor@sysoev.ru 7361269Sigor@sysoev.ru do { 7371269Sigor@sysoev.ru next = b->next; 738608Sigor@sysoev.ru 7391269Sigor@sysoev.ru nxt_mp_free(r->mem_pool, b); 7401269Sigor@sysoev.ru nxt_mp_release(r->mem_pool); 7411269Sigor@sysoev.ru 7421269Sigor@sysoev.ru b = next; 7431269Sigor@sysoev.ru } while (b != NULL); 744608Sigor@sysoev.ru } 745608Sigor@sysoev.ru 746608Sigor@sysoev.ru 747608Sigor@sysoev.ru nxt_buf_t * 748608Sigor@sysoev.ru nxt_http_buf_last(nxt_http_request_t *r) 749608Sigor@sysoev.ru { 750608Sigor@sysoev.ru nxt_buf_t *last; 751608Sigor@sysoev.ru 752608Sigor@sysoev.ru last = r->last; 753608Sigor@sysoev.ru r->last = NULL; 754608Sigor@sysoev.ru 755608Sigor@sysoev.ru return last; 756608Sigor@sysoev.ru } 757608Sigor@sysoev.ru 758608Sigor@sysoev.ru 759608Sigor@sysoev.ru static void 760431Sigor@sysoev.ru nxt_http_request_done(nxt_task_t *task, void *obj, void *data) 761431Sigor@sysoev.ru { 762431Sigor@sysoev.ru nxt_http_request_t *r; 763431Sigor@sysoev.ru 764431Sigor@sysoev.ru r = data; 765431Sigor@sysoev.ru 766431Sigor@sysoev.ru nxt_debug(task, "http request done"); 767431Sigor@sysoev.ru 768431Sigor@sysoev.ru nxt_http_request_close_handler(task, r, r->proto.any); 769431Sigor@sysoev.ru } 770431Sigor@sysoev.ru 771431Sigor@sysoev.ru 772431Sigor@sysoev.ru void 773608Sigor@sysoev.ru nxt_http_request_error_handler(nxt_task_t *task, void *obj, void *data) 774431Sigor@sysoev.ru { 775608Sigor@sysoev.ru nxt_http_proto_t proto; 776608Sigor@sysoev.ru nxt_http_request_t *r; 777608Sigor@sysoev.ru 778608Sigor@sysoev.ru r = obj; 779608Sigor@sysoev.ru proto.any = data; 780431Sigor@sysoev.ru 781608Sigor@sysoev.ru nxt_debug(task, "http request error handler"); 782608Sigor@sysoev.ru 7831009Smax.romanov@nginx.com r->error = 1; 7841009Smax.romanov@nginx.com 7851112Sigor@sysoev.ru if (nxt_fast_path(proto.any != NULL)) { 7861112Sigor@sysoev.ru nxt_http_proto[r->protocol].discard(task, r, nxt_http_buf_last(r)); 787608Sigor@sysoev.ru } 788431Sigor@sysoev.ru } 789431Sigor@sysoev.ru 790431Sigor@sysoev.ru 7911131Smax.romanov@nginx.com void 792431Sigor@sysoev.ru nxt_http_request_close_handler(nxt_task_t *task, void *obj, void *data) 793431Sigor@sysoev.ru { 794630Svbart@nginx.com nxt_http_proto_t proto; 795630Svbart@nginx.com nxt_http_request_t *r; 7961112Sigor@sysoev.ru nxt_http_protocol_t protocol; 797683Sigor@sysoev.ru nxt_socket_conf_joint_t *conf; 798630Svbart@nginx.com nxt_router_access_log_t *access_log; 799431Sigor@sysoev.ru 800431Sigor@sysoev.ru r = obj; 801431Sigor@sysoev.ru proto.any = data; 802431Sigor@sysoev.ru 803431Sigor@sysoev.ru nxt_debug(task, "http request close handler"); 804431Sigor@sysoev.ru 805683Sigor@sysoev.ru conf = r->conf; 806683Sigor@sysoev.ru 807431Sigor@sysoev.ru if (!r->logged) { 808431Sigor@sysoev.ru r->logged = 1; 809630Svbart@nginx.com 810683Sigor@sysoev.ru access_log = conf->socket_conf->router_conf->access_log; 811630Svbart@nginx.com 812630Svbart@nginx.com if (access_log != NULL) { 813630Svbart@nginx.com access_log->handler(task, r, access_log); 814630Svbart@nginx.com } 815431Sigor@sysoev.ru } 816431Sigor@sysoev.ru 817431Sigor@sysoev.ru r->proto.any = NULL; 818431Sigor@sysoev.ru 8191403Smax.romanov@nginx.com if (r->body != NULL && nxt_buf_is_file(r->body) 8201403Smax.romanov@nginx.com && r->body->file->fd != -1) 8211403Smax.romanov@nginx.com { 8221403Smax.romanov@nginx.com nxt_fd_close(r->body->file->fd); 8231403Smax.romanov@nginx.com 8241403Smax.romanov@nginx.com r->body->file->fd = -1; 8251403Smax.romanov@nginx.com } 8261403Smax.romanov@nginx.com 8271112Sigor@sysoev.ru if (nxt_fast_path(proto.any != NULL)) { 8281131Smax.romanov@nginx.com protocol = r->protocol; 8291131Smax.romanov@nginx.com 8301265Sigor@sysoev.ru nxt_http_proto[protocol].close(task, proto, conf); 8311131Smax.romanov@nginx.com 8321265Sigor@sysoev.ru nxt_mp_release(r->mem_pool); 833431Sigor@sysoev.ru } 834431Sigor@sysoev.ru } 835543Svbart@nginx.com 836543Svbart@nginx.com 837543Svbart@nginx.com static u_char * 8381183Svbart@nginx.com nxt_http_date_cache_handler(u_char *buf, nxt_realtime_t *now, struct tm *tm, 8391183Svbart@nginx.com size_t size, const char *format) 840543Svbart@nginx.com { 8411183Svbart@nginx.com return nxt_http_date(buf, tm); 842543Svbart@nginx.com } 8432104Sz.hong@f5.com 8442104Sz.hong@f5.com 8452104Sz.hong@f5.com nxt_array_t * 8462104Sz.hong@f5.com nxt_http_arguments_parse(nxt_http_request_t *r) 8472104Sz.hong@f5.com { 8482104Sz.hong@f5.com size_t name_length; 8492104Sz.hong@f5.com u_char *p, *dst, *dst_start, *start, *end, *name; 8502104Sz.hong@f5.com uint8_t d0, d1; 8512104Sz.hong@f5.com uint32_t hash; 8522104Sz.hong@f5.com nxt_array_t *args; 8532104Sz.hong@f5.com nxt_http_name_value_t *nv; 8542104Sz.hong@f5.com 8552104Sz.hong@f5.com if (r->arguments != NULL) { 8562104Sz.hong@f5.com return r->arguments; 8572104Sz.hong@f5.com } 8582104Sz.hong@f5.com 8592104Sz.hong@f5.com args = nxt_array_create(r->mem_pool, 2, sizeof(nxt_http_name_value_t)); 8602104Sz.hong@f5.com if (nxt_slow_path(args == NULL)) { 8612104Sz.hong@f5.com return NULL; 8622104Sz.hong@f5.com } 8632104Sz.hong@f5.com 8642104Sz.hong@f5.com hash = NXT_HTTP_FIELD_HASH_INIT; 8652104Sz.hong@f5.com name = NULL; 8662104Sz.hong@f5.com name_length = 0; 8672104Sz.hong@f5.com 8682104Sz.hong@f5.com dst_start = nxt_mp_nget(r->mem_pool, r->args->length); 8692104Sz.hong@f5.com if (nxt_slow_path(dst_start == NULL)) { 8702104Sz.hong@f5.com return NULL; 8712104Sz.hong@f5.com } 8722104Sz.hong@f5.com 8732104Sz.hong@f5.com r->args_decoded.start = dst_start; 8742104Sz.hong@f5.com 8752104Sz.hong@f5.com start = r->args->start; 8762104Sz.hong@f5.com end = start + r->args->length; 8772104Sz.hong@f5.com 8782104Sz.hong@f5.com for (p = start, dst = dst_start; p < end; p++, dst++) { 8792104Sz.hong@f5.com *dst = *p; 8802104Sz.hong@f5.com 8812104Sz.hong@f5.com switch (*p) { 8822104Sz.hong@f5.com case '=': 8832104Sz.hong@f5.com if (name == NULL) { 8842104Sz.hong@f5.com name_length = dst - dst_start; 8852104Sz.hong@f5.com name = dst_start; 8862104Sz.hong@f5.com dst_start = dst + 1; 8872104Sz.hong@f5.com } 8882104Sz.hong@f5.com 8892104Sz.hong@f5.com continue; 8902104Sz.hong@f5.com 8912104Sz.hong@f5.com case '&': 8922104Sz.hong@f5.com if (name_length != 0 || dst != dst_start) { 8932104Sz.hong@f5.com nv = nxt_http_argument(args, name, name_length, hash, dst_start, 8942104Sz.hong@f5.com dst); 8952104Sz.hong@f5.com if (nxt_slow_path(nv == NULL)) { 8962104Sz.hong@f5.com return NULL; 8972104Sz.hong@f5.com } 8982104Sz.hong@f5.com } 8992104Sz.hong@f5.com 9002104Sz.hong@f5.com hash = NXT_HTTP_FIELD_HASH_INIT; 9012104Sz.hong@f5.com name_length = 0; 9022104Sz.hong@f5.com name = NULL; 9032104Sz.hong@f5.com dst_start = dst + 1; 9042104Sz.hong@f5.com 9052104Sz.hong@f5.com continue; 9062104Sz.hong@f5.com 9072104Sz.hong@f5.com case '+': 9082104Sz.hong@f5.com *dst = ' '; 9092104Sz.hong@f5.com 9102104Sz.hong@f5.com break; 9112104Sz.hong@f5.com 9122104Sz.hong@f5.com case '%': 9132104Sz.hong@f5.com if (nxt_slow_path(end - p <= 2)) { 9142104Sz.hong@f5.com break; 9152104Sz.hong@f5.com } 9162104Sz.hong@f5.com 9172104Sz.hong@f5.com d0 = nxt_hex2int[p[1]]; 9182104Sz.hong@f5.com d1 = nxt_hex2int[p[2]]; 9192104Sz.hong@f5.com 9202104Sz.hong@f5.com if (nxt_slow_path((d0 | d1) >= 16)) { 9212104Sz.hong@f5.com break; 9222104Sz.hong@f5.com } 9232104Sz.hong@f5.com 9242104Sz.hong@f5.com p += 2; 9252104Sz.hong@f5.com *dst = (d0 << 4) + d1; 9262104Sz.hong@f5.com 9272104Sz.hong@f5.com break; 9282104Sz.hong@f5.com } 9292104Sz.hong@f5.com 9302104Sz.hong@f5.com if (name == NULL) { 9312104Sz.hong@f5.com hash = nxt_http_field_hash_char(hash, *dst); 9322104Sz.hong@f5.com } 9332104Sz.hong@f5.com } 9342104Sz.hong@f5.com 9352104Sz.hong@f5.com r->args_decoded.length = dst - r->args_decoded.start; 9362104Sz.hong@f5.com 9372104Sz.hong@f5.com if (name_length != 0 || dst != dst_start) { 9382104Sz.hong@f5.com nv = nxt_http_argument(args, name, name_length, hash, dst_start, dst); 9392104Sz.hong@f5.com if (nxt_slow_path(nv == NULL)) { 9402104Sz.hong@f5.com return NULL; 9412104Sz.hong@f5.com } 9422104Sz.hong@f5.com } 9432104Sz.hong@f5.com 9442104Sz.hong@f5.com r->arguments = args; 9452104Sz.hong@f5.com 9462104Sz.hong@f5.com return args; 9472104Sz.hong@f5.com } 9482104Sz.hong@f5.com 9492104Sz.hong@f5.com 9502104Sz.hong@f5.com static nxt_http_name_value_t * 9512104Sz.hong@f5.com nxt_http_argument(nxt_array_t *array, u_char *name, size_t name_length, 9522104Sz.hong@f5.com uint32_t hash, u_char *start, u_char *end) 9532104Sz.hong@f5.com { 9542104Sz.hong@f5.com size_t length; 9552104Sz.hong@f5.com nxt_http_name_value_t *nv; 9562104Sz.hong@f5.com 9572104Sz.hong@f5.com nv = nxt_array_add(array); 9582104Sz.hong@f5.com if (nxt_slow_path(nv == NULL)) { 9592104Sz.hong@f5.com return NULL; 9602104Sz.hong@f5.com } 9612104Sz.hong@f5.com 9622104Sz.hong@f5.com nv->hash = nxt_http_field_hash_end(hash) & 0xFFFF; 9632104Sz.hong@f5.com 9642104Sz.hong@f5.com length = end - start; 9652104Sz.hong@f5.com 9662104Sz.hong@f5.com if (name == NULL) { 9672104Sz.hong@f5.com name_length = length; 9682104Sz.hong@f5.com name = start; 9692104Sz.hong@f5.com length = 0; 9702104Sz.hong@f5.com } 9712104Sz.hong@f5.com 9722104Sz.hong@f5.com nv->name_length = name_length; 9732104Sz.hong@f5.com nv->value_length = length; 9742104Sz.hong@f5.com nv->name = name; 9752104Sz.hong@f5.com nv->value = start; 9762104Sz.hong@f5.com 9772104Sz.hong@f5.com return nv; 9782104Sz.hong@f5.com } 9792104Sz.hong@f5.com 9802104Sz.hong@f5.com 9812104Sz.hong@f5.com nxt_array_t * 9822104Sz.hong@f5.com nxt_http_cookies_parse(nxt_http_request_t *r) 9832104Sz.hong@f5.com { 9842104Sz.hong@f5.com nxt_int_t ret; 9852104Sz.hong@f5.com nxt_array_t *cookies; 9862104Sz.hong@f5.com nxt_http_field_t *f; 9872104Sz.hong@f5.com 9882104Sz.hong@f5.com if (r->cookies != NULL) { 9892104Sz.hong@f5.com return r->cookies; 9902104Sz.hong@f5.com } 9912104Sz.hong@f5.com 9922104Sz.hong@f5.com cookies = nxt_array_create(r->mem_pool, 2, sizeof(nxt_http_name_value_t)); 9932104Sz.hong@f5.com if (nxt_slow_path(cookies == NULL)) { 9942104Sz.hong@f5.com return NULL; 9952104Sz.hong@f5.com } 9962104Sz.hong@f5.com 9972104Sz.hong@f5.com nxt_list_each(f, r->fields) { 9982104Sz.hong@f5.com 9992104Sz.hong@f5.com if (f->hash != NXT_HTTP_COOKIE_HASH 10002104Sz.hong@f5.com || f->name_length != 6 10012104Sz.hong@f5.com || nxt_strncasecmp(f->name, (u_char *) "Cookie", 6) != 0) 10022104Sz.hong@f5.com { 10032104Sz.hong@f5.com continue; 10042104Sz.hong@f5.com } 10052104Sz.hong@f5.com 10062104Sz.hong@f5.com ret = nxt_http_cookie_parse(cookies, f->value, 10072104Sz.hong@f5.com f->value + f->value_length); 10082104Sz.hong@f5.com if (ret != NXT_OK) { 10092104Sz.hong@f5.com return NULL; 10102104Sz.hong@f5.com } 10112104Sz.hong@f5.com 10122104Sz.hong@f5.com } nxt_list_loop; 10132104Sz.hong@f5.com 10142104Sz.hong@f5.com r->cookies = cookies; 10152104Sz.hong@f5.com 10162104Sz.hong@f5.com return cookies; 10172104Sz.hong@f5.com } 10182104Sz.hong@f5.com 10192104Sz.hong@f5.com 10202104Sz.hong@f5.com static nxt_int_t 10212104Sz.hong@f5.com nxt_http_cookie_parse(nxt_array_t *cookies, u_char *start, u_char *end) 10222104Sz.hong@f5.com { 10232104Sz.hong@f5.com size_t name_length; 10242104Sz.hong@f5.com u_char c, *p, *name; 10252104Sz.hong@f5.com nxt_http_name_value_t *nv; 10262104Sz.hong@f5.com 10272104Sz.hong@f5.com name = NULL; 10282104Sz.hong@f5.com name_length = 0; 10292104Sz.hong@f5.com 10302104Sz.hong@f5.com for (p = start; p < end; p++) { 10312104Sz.hong@f5.com c = *p; 10322104Sz.hong@f5.com 10332104Sz.hong@f5.com if (c == '=') { 10342104Sz.hong@f5.com while (start[0] == ' ') { start++; } 10352104Sz.hong@f5.com 10362104Sz.hong@f5.com name_length = p - start; 10372104Sz.hong@f5.com 10382104Sz.hong@f5.com if (name_length != 0) { 10392104Sz.hong@f5.com name = start; 10402104Sz.hong@f5.com } 10412104Sz.hong@f5.com 10422104Sz.hong@f5.com start = p + 1; 10432104Sz.hong@f5.com 10442104Sz.hong@f5.com } else if (c == ';') { 10452104Sz.hong@f5.com if (name != NULL) { 10462104Sz.hong@f5.com nv = nxt_http_cookie(cookies, name, name_length, start, p); 10472104Sz.hong@f5.com if (nxt_slow_path(nv == NULL)) { 10482104Sz.hong@f5.com return NXT_ERROR; 10492104Sz.hong@f5.com } 10502104Sz.hong@f5.com } 10512104Sz.hong@f5.com 10522104Sz.hong@f5.com name = NULL; 10532104Sz.hong@f5.com start = p + 1; 10542104Sz.hong@f5.com } 10552104Sz.hong@f5.com } 10562104Sz.hong@f5.com 10572104Sz.hong@f5.com if (name != NULL) { 10582104Sz.hong@f5.com nv = nxt_http_cookie(cookies, name, name_length, start, p); 10592104Sz.hong@f5.com if (nxt_slow_path(nv == NULL)) { 10602104Sz.hong@f5.com return NXT_ERROR; 10612104Sz.hong@f5.com } 10622104Sz.hong@f5.com } 10632104Sz.hong@f5.com 10642104Sz.hong@f5.com return NXT_OK; 10652104Sz.hong@f5.com } 10662104Sz.hong@f5.com 10672104Sz.hong@f5.com 10682104Sz.hong@f5.com static nxt_http_name_value_t * 10692104Sz.hong@f5.com nxt_http_cookie(nxt_array_t *array, u_char *name, size_t name_length, 10702104Sz.hong@f5.com u_char *start, u_char *end) 10712104Sz.hong@f5.com { 10722104Sz.hong@f5.com u_char c, *p; 10732104Sz.hong@f5.com uint32_t hash; 10742104Sz.hong@f5.com nxt_http_name_value_t *nv; 10752104Sz.hong@f5.com 10762104Sz.hong@f5.com nv = nxt_array_add(array); 10772104Sz.hong@f5.com if (nxt_slow_path(nv == NULL)) { 10782104Sz.hong@f5.com return NULL; 10792104Sz.hong@f5.com } 10802104Sz.hong@f5.com 10812104Sz.hong@f5.com nv->name_length = name_length; 10822104Sz.hong@f5.com nv->name = name; 10832104Sz.hong@f5.com 10842104Sz.hong@f5.com hash = NXT_HTTP_FIELD_HASH_INIT; 10852104Sz.hong@f5.com 10862104Sz.hong@f5.com for (p = name; p < name + name_length; p++) { 10872104Sz.hong@f5.com c = *p; 10882104Sz.hong@f5.com hash = nxt_http_field_hash_char(hash, c); 10892104Sz.hong@f5.com } 10902104Sz.hong@f5.com 10912104Sz.hong@f5.com nv->hash = nxt_http_field_hash_end(hash) & 0xFFFF; 10922104Sz.hong@f5.com 10932104Sz.hong@f5.com while (start < end && end[-1] == ' ') { end--; } 10942104Sz.hong@f5.com 10952104Sz.hong@f5.com nv->value_length = end - start; 10962104Sz.hong@f5.com nv->value = start; 10972104Sz.hong@f5.com 10982104Sz.hong@f5.com return nv; 10992104Sz.hong@f5.com } 11002123Sz.hong@f5.com 11012123Sz.hong@f5.com 11022123Sz.hong@f5.com int64_t 11032123Sz.hong@f5.com nxt_http_field_hash(nxt_mp_t *mp, nxt_str_t *name, nxt_bool_t case_sensitive, 11042123Sz.hong@f5.com uint8_t encoding) 11052123Sz.hong@f5.com { 11062123Sz.hong@f5.com u_char c, *p, *src, *start, *end, plus; 11072123Sz.hong@f5.com uint8_t d0, d1; 11082123Sz.hong@f5.com uint32_t hash; 11092123Sz.hong@f5.com nxt_str_t str; 11102123Sz.hong@f5.com nxt_uint_t i; 11112123Sz.hong@f5.com 11122123Sz.hong@f5.com str.length = name->length; 11132123Sz.hong@f5.com 11142123Sz.hong@f5.com str.start = nxt_mp_nget(mp, str.length); 11152123Sz.hong@f5.com if (nxt_slow_path(str.start == NULL)) { 11162123Sz.hong@f5.com return -1; 11172123Sz.hong@f5.com } 11182123Sz.hong@f5.com 11192123Sz.hong@f5.com p = str.start; 11202123Sz.hong@f5.com 11212123Sz.hong@f5.com hash = NXT_HTTP_FIELD_HASH_INIT; 11222123Sz.hong@f5.com 11232123Sz.hong@f5.com if (encoding == NXT_HTTP_URI_ENCODING_NONE) { 11242123Sz.hong@f5.com for (i = 0; i < name->length; i++) { 11252123Sz.hong@f5.com c = name->start[i]; 11262123Sz.hong@f5.com *p++ = c; 11272123Sz.hong@f5.com 11282123Sz.hong@f5.com c = case_sensitive ? c : nxt_lowcase(c); 11292123Sz.hong@f5.com hash = nxt_http_field_hash_char(hash, c); 11302123Sz.hong@f5.com } 11312123Sz.hong@f5.com 11322123Sz.hong@f5.com goto end; 11332123Sz.hong@f5.com } 11342123Sz.hong@f5.com 11352123Sz.hong@f5.com plus = (encoding == NXT_HTTP_URI_ENCODING_PLUS) ? ' ' : '+'; 11362123Sz.hong@f5.com 11372123Sz.hong@f5.com start = name->start; 11382123Sz.hong@f5.com end = start + name->length; 11392123Sz.hong@f5.com 11402123Sz.hong@f5.com for (src = start; src < end; src++) { 11412123Sz.hong@f5.com c = *src; 11422123Sz.hong@f5.com 11432123Sz.hong@f5.com switch (c) { 11442123Sz.hong@f5.com case '%': 11452123Sz.hong@f5.com if (nxt_slow_path(end - src <= 2)) { 11462123Sz.hong@f5.com return -1; 11472123Sz.hong@f5.com } 11482123Sz.hong@f5.com 11492123Sz.hong@f5.com d0 = nxt_hex2int[src[1]]; 11502123Sz.hong@f5.com d1 = nxt_hex2int[src[2]]; 11512123Sz.hong@f5.com src += 2; 11522123Sz.hong@f5.com 11532123Sz.hong@f5.com if (nxt_slow_path((d0 | d1) >= 16)) { 11542123Sz.hong@f5.com return -1; 11552123Sz.hong@f5.com } 11562123Sz.hong@f5.com 11572123Sz.hong@f5.com c = (d0 << 4) + d1; 11582123Sz.hong@f5.com *p++ = c; 11592123Sz.hong@f5.com break; 11602123Sz.hong@f5.com 11612123Sz.hong@f5.com case '+': 11622123Sz.hong@f5.com c = plus; 11632123Sz.hong@f5.com *p++ = c; 11642123Sz.hong@f5.com break; 11652123Sz.hong@f5.com 11662123Sz.hong@f5.com default: 11672123Sz.hong@f5.com *p++ = c; 11682123Sz.hong@f5.com break; 11692123Sz.hong@f5.com } 11702123Sz.hong@f5.com 11712123Sz.hong@f5.com c = case_sensitive ? c : nxt_lowcase(c); 11722123Sz.hong@f5.com hash = nxt_http_field_hash_char(hash, c); 11732123Sz.hong@f5.com } 11742123Sz.hong@f5.com 11752123Sz.hong@f5.com str.length = p - str.start; 11762123Sz.hong@f5.com 11772123Sz.hong@f5.com end: 11782123Sz.hong@f5.com 11792123Sz.hong@f5.com *name = str; 11802123Sz.hong@f5.com 11812123Sz.hong@f5.com return nxt_http_field_hash_end(hash) & 0xFFFF; 11822123Sz.hong@f5.com } 1183