Return to ngx_http_request.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / nginx / src / http |
1.1 ! misho 1: ! 2: /* ! 3: * Copyright (C) Igor Sysoev ! 4: * Copyright (C) Nginx, Inc. ! 5: */ ! 6: ! 7: ! 8: #include <ngx_config.h> ! 9: #include <ngx_core.h> ! 10: #include <ngx_http.h> ! 11: ! 12: ! 13: static void ngx_http_wait_request_handler(ngx_event_t *ev); ! 14: static void ngx_http_process_request_line(ngx_event_t *rev); ! 15: static void ngx_http_process_request_headers(ngx_event_t *rev); ! 16: static ssize_t ngx_http_read_request_header(ngx_http_request_t *r); ! 17: static ngx_int_t ngx_http_alloc_large_header_buffer(ngx_http_request_t *r, ! 18: ngx_uint_t request_line); ! 19: ! 20: static ngx_int_t ngx_http_process_header_line(ngx_http_request_t *r, ! 21: ngx_table_elt_t *h, ngx_uint_t offset); ! 22: static ngx_int_t ngx_http_process_unique_header_line(ngx_http_request_t *r, ! 23: ngx_table_elt_t *h, ngx_uint_t offset); ! 24: static ngx_int_t ngx_http_process_multi_header_lines(ngx_http_request_t *r, ! 25: ngx_table_elt_t *h, ngx_uint_t offset); ! 26: static ngx_int_t ngx_http_process_host(ngx_http_request_t *r, ! 27: ngx_table_elt_t *h, ngx_uint_t offset); ! 28: static ngx_int_t ngx_http_process_connection(ngx_http_request_t *r, ! 29: ngx_table_elt_t *h, ngx_uint_t offset); ! 30: static ngx_int_t ngx_http_process_user_agent(ngx_http_request_t *r, ! 31: ngx_table_elt_t *h, ngx_uint_t offset); ! 32: ! 33: static ngx_int_t ngx_http_validate_host(ngx_str_t *host, ngx_pool_t *pool, ! 34: ngx_uint_t alloc); ! 35: static ngx_int_t ngx_http_set_virtual_server(ngx_http_request_t *r, ! 36: ngx_str_t *host); ! 37: static ngx_int_t ngx_http_find_virtual_server(ngx_connection_t *c, ! 38: ngx_http_virtual_names_t *virtual_names, ngx_str_t *host, ! 39: ngx_http_request_t *r, ngx_http_core_srv_conf_t **cscfp); ! 40: ! 41: static void ngx_http_request_handler(ngx_event_t *ev); ! 42: static void ngx_http_terminate_request(ngx_http_request_t *r, ngx_int_t rc); ! 43: static void ngx_http_terminate_handler(ngx_http_request_t *r); ! 44: static void ngx_http_finalize_connection(ngx_http_request_t *r); ! 45: static ngx_int_t ngx_http_set_write_handler(ngx_http_request_t *r); ! 46: static void ngx_http_writer(ngx_http_request_t *r); ! 47: static void ngx_http_request_finalizer(ngx_http_request_t *r); ! 48: ! 49: static void ngx_http_set_keepalive(ngx_http_request_t *r); ! 50: static void ngx_http_keepalive_handler(ngx_event_t *ev); ! 51: static void ngx_http_set_lingering_close(ngx_http_request_t *r); ! 52: static void ngx_http_lingering_close_handler(ngx_event_t *ev); ! 53: static ngx_int_t ngx_http_post_action(ngx_http_request_t *r); ! 54: static void ngx_http_close_request(ngx_http_request_t *r, ngx_int_t error); ! 55: static void ngx_http_log_request(ngx_http_request_t *r); ! 56: ! 57: static u_char *ngx_http_log_error(ngx_log_t *log, u_char *buf, size_t len); ! 58: static u_char *ngx_http_log_error_handler(ngx_http_request_t *r, ! 59: ngx_http_request_t *sr, u_char *buf, size_t len); ! 60: ! 61: #if (NGX_HTTP_SSL) ! 62: static void ngx_http_ssl_handshake(ngx_event_t *rev); ! 63: static void ngx_http_ssl_handshake_handler(ngx_connection_t *c); ! 64: #endif ! 65: ! 66: ! 67: static char *ngx_http_client_errors[] = { ! 68: ! 69: /* NGX_HTTP_PARSE_INVALID_METHOD */ ! 70: "client sent invalid method", ! 71: ! 72: /* NGX_HTTP_PARSE_INVALID_REQUEST */ ! 73: "client sent invalid request", ! 74: ! 75: /* NGX_HTTP_PARSE_INVALID_09_METHOD */ ! 76: "client sent invalid method in HTTP/0.9 request" ! 77: }; ! 78: ! 79: ! 80: ngx_http_header_t ngx_http_headers_in[] = { ! 81: { ngx_string("Host"), offsetof(ngx_http_headers_in_t, host), ! 82: ngx_http_process_host }, ! 83: ! 84: { ngx_string("Connection"), offsetof(ngx_http_headers_in_t, connection), ! 85: ngx_http_process_connection }, ! 86: ! 87: { ngx_string("If-Modified-Since"), ! 88: offsetof(ngx_http_headers_in_t, if_modified_since), ! 89: ngx_http_process_unique_header_line }, ! 90: ! 91: { ngx_string("If-Unmodified-Since"), ! 92: offsetof(ngx_http_headers_in_t, if_unmodified_since), ! 93: ngx_http_process_unique_header_line }, ! 94: ! 95: { ngx_string("If-Match"), ! 96: offsetof(ngx_http_headers_in_t, if_match), ! 97: ngx_http_process_unique_header_line }, ! 98: ! 99: { ngx_string("If-None-Match"), ! 100: offsetof(ngx_http_headers_in_t, if_none_match), ! 101: ngx_http_process_unique_header_line }, ! 102: ! 103: { ngx_string("User-Agent"), offsetof(ngx_http_headers_in_t, user_agent), ! 104: ngx_http_process_user_agent }, ! 105: ! 106: { ngx_string("Referer"), offsetof(ngx_http_headers_in_t, referer), ! 107: ngx_http_process_header_line }, ! 108: ! 109: { ngx_string("Content-Length"), ! 110: offsetof(ngx_http_headers_in_t, content_length), ! 111: ngx_http_process_unique_header_line }, ! 112: ! 113: { ngx_string("Content-Type"), ! 114: offsetof(ngx_http_headers_in_t, content_type), ! 115: ngx_http_process_header_line }, ! 116: ! 117: { ngx_string("Range"), offsetof(ngx_http_headers_in_t, range), ! 118: ngx_http_process_header_line }, ! 119: ! 120: { ngx_string("If-Range"), ! 121: offsetof(ngx_http_headers_in_t, if_range), ! 122: ngx_http_process_unique_header_line }, ! 123: ! 124: { ngx_string("Transfer-Encoding"), ! 125: offsetof(ngx_http_headers_in_t, transfer_encoding), ! 126: ngx_http_process_header_line }, ! 127: ! 128: { ngx_string("Expect"), ! 129: offsetof(ngx_http_headers_in_t, expect), ! 130: ngx_http_process_unique_header_line }, ! 131: ! 132: { ngx_string("Upgrade"), ! 133: offsetof(ngx_http_headers_in_t, upgrade), ! 134: ngx_http_process_header_line }, ! 135: ! 136: #if (NGX_HTTP_GZIP) ! 137: { ngx_string("Accept-Encoding"), ! 138: offsetof(ngx_http_headers_in_t, accept_encoding), ! 139: ngx_http_process_header_line }, ! 140: ! 141: { ngx_string("Via"), offsetof(ngx_http_headers_in_t, via), ! 142: ngx_http_process_header_line }, ! 143: #endif ! 144: ! 145: { ngx_string("Authorization"), ! 146: offsetof(ngx_http_headers_in_t, authorization), ! 147: ngx_http_process_unique_header_line }, ! 148: ! 149: { ngx_string("Keep-Alive"), offsetof(ngx_http_headers_in_t, keep_alive), ! 150: ngx_http_process_header_line }, ! 151: ! 152: #if (NGX_HTTP_X_FORWARDED_FOR) ! 153: { ngx_string("X-Forwarded-For"), ! 154: offsetof(ngx_http_headers_in_t, x_forwarded_for), ! 155: ngx_http_process_multi_header_lines }, ! 156: #endif ! 157: ! 158: #if (NGX_HTTP_REALIP) ! 159: { ngx_string("X-Real-IP"), ! 160: offsetof(ngx_http_headers_in_t, x_real_ip), ! 161: ngx_http_process_header_line }, ! 162: #endif ! 163: ! 164: #if (NGX_HTTP_HEADERS) ! 165: { ngx_string("Accept"), offsetof(ngx_http_headers_in_t, accept), ! 166: ngx_http_process_header_line }, ! 167: ! 168: { ngx_string("Accept-Language"), ! 169: offsetof(ngx_http_headers_in_t, accept_language), ! 170: ngx_http_process_header_line }, ! 171: #endif ! 172: ! 173: #if (NGX_HTTP_DAV) ! 174: { ngx_string("Depth"), offsetof(ngx_http_headers_in_t, depth), ! 175: ngx_http_process_header_line }, ! 176: ! 177: { ngx_string("Destination"), offsetof(ngx_http_headers_in_t, destination), ! 178: ngx_http_process_header_line }, ! 179: ! 180: { ngx_string("Overwrite"), offsetof(ngx_http_headers_in_t, overwrite), ! 181: ngx_http_process_header_line }, ! 182: ! 183: { ngx_string("Date"), offsetof(ngx_http_headers_in_t, date), ! 184: ngx_http_process_header_line }, ! 185: #endif ! 186: ! 187: { ngx_string("Cookie"), offsetof(ngx_http_headers_in_t, cookies), ! 188: ngx_http_process_multi_header_lines }, ! 189: ! 190: { ngx_null_string, 0, NULL } ! 191: }; ! 192: ! 193: ! 194: void ! 195: ngx_http_init_connection(ngx_connection_t *c) ! 196: { ! 197: ngx_uint_t i; ! 198: ngx_event_t *rev; ! 199: struct sockaddr_in *sin; ! 200: ngx_http_port_t *port; ! 201: ngx_http_in_addr_t *addr; ! 202: ngx_http_log_ctx_t *ctx; ! 203: ngx_http_connection_t *hc; ! 204: #if (NGX_HAVE_INET6) ! 205: struct sockaddr_in6 *sin6; ! 206: ngx_http_in6_addr_t *addr6; ! 207: #endif ! 208: ! 209: hc = ngx_pcalloc(c->pool, sizeof(ngx_http_connection_t)); ! 210: if (hc == NULL) { ! 211: ngx_http_close_connection(c); ! 212: return; ! 213: } ! 214: ! 215: c->data = hc; ! 216: ! 217: /* find the server configuration for the address:port */ ! 218: ! 219: port = c->listening->servers; ! 220: ! 221: if (port->naddrs > 1) { ! 222: ! 223: /* ! 224: * there are several addresses on this port and one of them ! 225: * is an "*:port" wildcard so getsockname() in ngx_http_server_addr() ! 226: * is required to determine a server address ! 227: */ ! 228: ! 229: if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) { ! 230: ngx_http_close_connection(c); ! 231: return; ! 232: } ! 233: ! 234: switch (c->local_sockaddr->sa_family) { ! 235: ! 236: #if (NGX_HAVE_INET6) ! 237: case AF_INET6: ! 238: sin6 = (struct sockaddr_in6 *) c->local_sockaddr; ! 239: ! 240: addr6 = port->addrs; ! 241: ! 242: /* the last address is "*" */ ! 243: ! 244: for (i = 0; i < port->naddrs - 1; i++) { ! 245: if (ngx_memcmp(&addr6[i].addr6, &sin6->sin6_addr, 16) == 0) { ! 246: break; ! 247: } ! 248: } ! 249: ! 250: hc->addr_conf = &addr6[i].conf; ! 251: ! 252: break; ! 253: #endif ! 254: ! 255: default: /* AF_INET */ ! 256: sin = (struct sockaddr_in *) c->local_sockaddr; ! 257: ! 258: addr = port->addrs; ! 259: ! 260: /* the last address is "*" */ ! 261: ! 262: for (i = 0; i < port->naddrs - 1; i++) { ! 263: if (addr[i].addr == sin->sin_addr.s_addr) { ! 264: break; ! 265: } ! 266: } ! 267: ! 268: hc->addr_conf = &addr[i].conf; ! 269: ! 270: break; ! 271: } ! 272: ! 273: } else { ! 274: ! 275: switch (c->local_sockaddr->sa_family) { ! 276: ! 277: #if (NGX_HAVE_INET6) ! 278: case AF_INET6: ! 279: addr6 = port->addrs; ! 280: hc->addr_conf = &addr6[0].conf; ! 281: break; ! 282: #endif ! 283: ! 284: default: /* AF_INET */ ! 285: addr = port->addrs; ! 286: hc->addr_conf = &addr[0].conf; ! 287: break; ! 288: } ! 289: } ! 290: ! 291: /* the default server configuration for the address:port */ ! 292: hc->conf_ctx = hc->addr_conf->default_server->ctx; ! 293: ! 294: ctx = ngx_palloc(c->pool, sizeof(ngx_http_log_ctx_t)); ! 295: if (ctx == NULL) { ! 296: ngx_http_close_connection(c); ! 297: return; ! 298: } ! 299: ! 300: ctx->connection = c; ! 301: ctx->request = NULL; ! 302: ctx->current_request = NULL; ! 303: ! 304: c->log->connection = c->number; ! 305: c->log->handler = ngx_http_log_error; ! 306: c->log->data = ctx; ! 307: c->log->action = "waiting for request"; ! 308: ! 309: c->log_error = NGX_ERROR_INFO; ! 310: ! 311: rev = c->read; ! 312: rev->handler = ngx_http_wait_request_handler; ! 313: c->write->handler = ngx_http_empty_handler; ! 314: ! 315: #if (NGX_HTTP_SPDY) ! 316: if (hc->addr_conf->spdy) { ! 317: rev->handler = ngx_http_spdy_init; ! 318: } ! 319: #endif ! 320: ! 321: #if (NGX_HTTP_SSL) ! 322: { ! 323: ngx_http_ssl_srv_conf_t *sscf; ! 324: ! 325: sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module); ! 326: ! 327: if (sscf->enable || hc->addr_conf->ssl) { ! 328: ! 329: c->log->action = "SSL handshaking"; ! 330: ! 331: if (hc->addr_conf->ssl && sscf->ssl.ctx == NULL) { ! 332: ngx_log_error(NGX_LOG_ERR, c->log, 0, ! 333: "no \"ssl_certificate\" is defined " ! 334: "in server listening on SSL port"); ! 335: ngx_http_close_connection(c); ! 336: return; ! 337: } ! 338: ! 339: hc->ssl = 1; ! 340: ! 341: rev->handler = ngx_http_ssl_handshake; ! 342: } ! 343: } ! 344: #endif ! 345: ! 346: if (rev->ready) { ! 347: /* the deferred accept(), rtsig, aio, iocp */ ! 348: ! 349: if (ngx_use_accept_mutex) { ! 350: ngx_post_event(rev, &ngx_posted_events); ! 351: return; ! 352: } ! 353: ! 354: rev->handler(rev); ! 355: return; ! 356: } ! 357: ! 358: ngx_add_timer(rev, c->listening->post_accept_timeout); ! 359: ngx_reusable_connection(c, 1); ! 360: ! 361: if (ngx_handle_read_event(rev, 0) != NGX_OK) { ! 362: ngx_http_close_connection(c); ! 363: return; ! 364: } ! 365: } ! 366: ! 367: ! 368: static void ! 369: ngx_http_wait_request_handler(ngx_event_t *rev) ! 370: { ! 371: size_t size; ! 372: ssize_t n; ! 373: ngx_buf_t *b; ! 374: ngx_connection_t *c; ! 375: ngx_http_connection_t *hc; ! 376: ngx_http_core_srv_conf_t *cscf; ! 377: ! 378: c = rev->data; ! 379: ! 380: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http wait request handler"); ! 381: ! 382: if (rev->timedout) { ! 383: ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); ! 384: ngx_http_close_connection(c); ! 385: return; ! 386: } ! 387: ! 388: if (c->close) { ! 389: ngx_http_close_connection(c); ! 390: return; ! 391: } ! 392: ! 393: hc = c->data; ! 394: cscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_core_module); ! 395: ! 396: size = cscf->client_header_buffer_size; ! 397: ! 398: b = c->buffer; ! 399: ! 400: if (b == NULL) { ! 401: b = ngx_create_temp_buf(c->pool, size); ! 402: if (b == NULL) { ! 403: ngx_http_close_connection(c); ! 404: return; ! 405: } ! 406: ! 407: c->buffer = b; ! 408: ! 409: } else if (b->start == NULL) { ! 410: ! 411: b->start = ngx_palloc(c->pool, size); ! 412: if (b->start == NULL) { ! 413: ngx_http_close_connection(c); ! 414: return; ! 415: } ! 416: ! 417: b->pos = b->start; ! 418: b->last = b->start; ! 419: b->end = b->last + size; ! 420: } ! 421: ! 422: n = c->recv(c, b->last, size); ! 423: ! 424: if (n == NGX_AGAIN) { ! 425: ! 426: #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) ! 427: if (c->listening->deferred_accept ! 428: #if (NGX_HTTP_SSL) ! 429: && c->ssl == NULL ! 430: #endif ! 431: ) ! 432: { ! 433: ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, ! 434: "client timed out in deferred accept"); ! 435: ngx_http_close_connection(c); ! 436: return; ! 437: } ! 438: #endif ! 439: ! 440: if (!rev->timer_set) { ! 441: ngx_add_timer(rev, c->listening->post_accept_timeout); ! 442: ngx_reusable_connection(c, 1); ! 443: } ! 444: ! 445: if (ngx_handle_read_event(rev, 0) != NGX_OK) { ! 446: ngx_http_close_connection(c); ! 447: return; ! 448: } ! 449: ! 450: /* ! 451: * We are trying to not hold c->buffer's memory for an idle connection. ! 452: */ ! 453: ! 454: if (ngx_pfree(c->pool, b->start) == NGX_OK) { ! 455: b->start = NULL; ! 456: } ! 457: ! 458: return; ! 459: } ! 460: ! 461: if (n == NGX_ERROR) { ! 462: ngx_http_close_connection(c); ! 463: return; ! 464: } ! 465: ! 466: if (n == 0) { ! 467: ngx_log_error(NGX_LOG_INFO, c->log, 0, ! 468: "client closed connection"); ! 469: ngx_http_close_connection(c); ! 470: return; ! 471: } ! 472: ! 473: b->last += n; ! 474: ! 475: c->log->action = "reading client request line"; ! 476: ! 477: ngx_reusable_connection(c, 0); ! 478: ! 479: c->data = ngx_http_create_request(c); ! 480: if (c->data == NULL) { ! 481: ngx_http_close_connection(c); ! 482: return; ! 483: } ! 484: ! 485: rev->handler = ngx_http_process_request_line; ! 486: ngx_http_process_request_line(rev); ! 487: } ! 488: ! 489: ! 490: ngx_http_request_t * ! 491: ngx_http_create_request(ngx_connection_t *c) ! 492: { ! 493: ngx_pool_t *pool; ! 494: ngx_time_t *tp; ! 495: ngx_http_request_t *r; ! 496: ngx_http_log_ctx_t *ctx; ! 497: ngx_http_connection_t *hc; ! 498: ngx_http_core_srv_conf_t *cscf; ! 499: ngx_http_core_loc_conf_t *clcf; ! 500: ngx_http_core_main_conf_t *cmcf; ! 501: ! 502: c->requests++; ! 503: ! 504: hc = c->data; ! 505: ! 506: cscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_core_module); ! 507: ! 508: pool = ngx_create_pool(cscf->request_pool_size, c->log); ! 509: if (pool == NULL) { ! 510: return NULL; ! 511: } ! 512: ! 513: r = ngx_pcalloc(pool, sizeof(ngx_http_request_t)); ! 514: if (r == NULL) { ! 515: ngx_destroy_pool(pool); ! 516: return NULL; ! 517: } ! 518: ! 519: r->pool = pool; ! 520: ! 521: r->http_connection = hc; ! 522: r->signature = NGX_HTTP_MODULE; ! 523: r->connection = c; ! 524: ! 525: r->main_conf = hc->conf_ctx->main_conf; ! 526: r->srv_conf = hc->conf_ctx->srv_conf; ! 527: r->loc_conf = hc->conf_ctx->loc_conf; ! 528: ! 529: r->read_event_handler = ngx_http_block_reading; ! 530: ! 531: clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ! 532: ! 533: ngx_http_set_connection_log(r->connection, clcf->error_log); ! 534: ! 535: r->header_in = hc->nbusy ? hc->busy[0] : c->buffer; ! 536: ! 537: if (ngx_list_init(&r->headers_out.headers, r->pool, 20, ! 538: sizeof(ngx_table_elt_t)) ! 539: != NGX_OK) ! 540: { ! 541: ngx_destroy_pool(r->pool); ! 542: return NULL; ! 543: } ! 544: ! 545: r->ctx = ngx_pcalloc(r->pool, sizeof(void *) * ngx_http_max_module); ! 546: if (r->ctx == NULL) { ! 547: ngx_destroy_pool(r->pool); ! 548: return NULL; ! 549: } ! 550: ! 551: cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); ! 552: ! 553: r->variables = ngx_pcalloc(r->pool, cmcf->variables.nelts ! 554: * sizeof(ngx_http_variable_value_t)); ! 555: if (r->variables == NULL) { ! 556: ngx_destroy_pool(r->pool); ! 557: return NULL; ! 558: } ! 559: ! 560: #if (NGX_HTTP_SSL) ! 561: if (c->ssl) { ! 562: r->main_filter_need_in_memory = 1; ! 563: } ! 564: #endif ! 565: ! 566: r->main = r; ! 567: r->count = 1; ! 568: ! 569: tp = ngx_timeofday(); ! 570: r->start_sec = tp->sec; ! 571: r->start_msec = tp->msec; ! 572: ! 573: r->method = NGX_HTTP_UNKNOWN; ! 574: ! 575: r->headers_in.content_length_n = -1; ! 576: r->headers_in.keep_alive_n = -1; ! 577: r->headers_out.content_length_n = -1; ! 578: r->headers_out.last_modified_time = -1; ! 579: ! 580: r->uri_changes = NGX_HTTP_MAX_URI_CHANGES + 1; ! 581: r->subrequests = NGX_HTTP_MAX_SUBREQUESTS + 1; ! 582: ! 583: r->http_state = NGX_HTTP_READING_REQUEST_STATE; ! 584: ! 585: ctx = c->log->data; ! 586: ctx->request = r; ! 587: ctx->current_request = r; ! 588: r->log_handler = ngx_http_log_error_handler; ! 589: ! 590: #if (NGX_STAT_STUB) ! 591: (void) ngx_atomic_fetch_add(ngx_stat_reading, 1); ! 592: r->stat_reading = 1; ! 593: (void) ngx_atomic_fetch_add(ngx_stat_requests, 1); ! 594: #endif ! 595: ! 596: return r; ! 597: } ! 598: ! 599: ! 600: #if (NGX_HTTP_SSL) ! 601: ! 602: static void ! 603: ngx_http_ssl_handshake(ngx_event_t *rev) ! 604: { ! 605: u_char buf[1]; ! 606: ssize_t n; ! 607: ngx_err_t err; ! 608: ngx_int_t rc; ! 609: ngx_connection_t *c; ! 610: ngx_http_connection_t *hc; ! 611: ngx_http_ssl_srv_conf_t *sscf; ! 612: ! 613: c = rev->data; ! 614: ! 615: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, ! 616: "http check ssl handshake"); ! 617: ! 618: if (rev->timedout) { ! 619: ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); ! 620: ngx_http_close_connection(c); ! 621: return; ! 622: } ! 623: ! 624: if (c->close) { ! 625: ngx_http_close_connection(c); ! 626: return; ! 627: } ! 628: ! 629: n = recv(c->fd, (char *) buf, 1, MSG_PEEK); ! 630: ! 631: err = ngx_socket_errno; ! 632: ! 633: ngx_log_debug1(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http recv(): %d", n); ! 634: ! 635: if (n == -1) { ! 636: if (err == NGX_EAGAIN) { ! 637: ! 638: #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) ! 639: if (c->listening->deferred_accept) { ! 640: ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, ! 641: "client timed out in deferred accept"); ! 642: ngx_http_close_connection(c); ! 643: return; ! 644: } ! 645: #endif ! 646: ! 647: if (!rev->timer_set) { ! 648: ngx_add_timer(rev, c->listening->post_accept_timeout); ! 649: ngx_reusable_connection(c, 1); ! 650: } ! 651: ! 652: if (ngx_handle_read_event(rev, 0) != NGX_OK) { ! 653: ngx_http_close_connection(c); ! 654: } ! 655: ! 656: return; ! 657: } ! 658: ! 659: ngx_connection_error(c, err, "recv() failed"); ! 660: ngx_http_close_connection(c); ! 661: ! 662: return; ! 663: } ! 664: ! 665: if (n == 1) { ! 666: if (buf[0] & 0x80 /* SSLv2 */ || buf[0] == 0x16 /* SSLv3/TLSv1 */) { ! 667: ngx_log_debug1(NGX_LOG_DEBUG_HTTP, rev->log, 0, ! 668: "https ssl handshake: 0x%02Xd", buf[0]); ! 669: ! 670: hc = c->data; ! 671: sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ! 672: ngx_http_ssl_module); ! 673: ! 674: if (ngx_ssl_create_connection(&sscf->ssl, c, NGX_SSL_BUFFER) ! 675: != NGX_OK) ! 676: { ! 677: ngx_http_close_connection(c); ! 678: return; ! 679: } ! 680: ! 681: rc = ngx_ssl_handshake(c); ! 682: ! 683: if (rc == NGX_AGAIN) { ! 684: ! 685: if (!rev->timer_set) { ! 686: ngx_add_timer(rev, c->listening->post_accept_timeout); ! 687: } ! 688: ! 689: ngx_reusable_connection(c, 0); ! 690: ! 691: c->ssl->handler = ngx_http_ssl_handshake_handler; ! 692: return; ! 693: } ! 694: ! 695: ngx_http_ssl_handshake_handler(c); ! 696: ! 697: return; ! 698: } ! 699: ! 700: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "plain http"); ! 701: ! 702: c->log->action = "waiting for request"; ! 703: ! 704: rev->handler = ngx_http_wait_request_handler; ! 705: ngx_http_wait_request_handler(rev); ! 706: ! 707: return; ! 708: } ! 709: ! 710: ngx_log_error(NGX_LOG_INFO, c->log, 0, "client closed connection"); ! 711: ngx_http_close_connection(c); ! 712: } ! 713: ! 714: ! 715: static void ! 716: ngx_http_ssl_handshake_handler(ngx_connection_t *c) ! 717: { ! 718: if (c->ssl->handshaked) { ! 719: ! 720: /* ! 721: * The majority of browsers do not send the "close notify" alert. ! 722: * Among them are MSIE, old Mozilla, Netscape 4, Konqueror, ! 723: * and Links. And what is more, MSIE ignores the server's alert. ! 724: * ! 725: * Opera and recent Mozilla send the alert. ! 726: */ ! 727: ! 728: c->ssl->no_wait_shutdown = 1; ! 729: ! 730: #if (NGX_HTTP_SPDY && defined TLSEXT_TYPE_next_proto_neg) ! 731: { ! 732: unsigned int len; ! 733: const unsigned char *data; ! 734: static const ngx_str_t spdy = ngx_string(NGX_SPDY_NPN_NEGOTIATED); ! 735: ! 736: SSL_get0_next_proto_negotiated(c->ssl->connection, &data, &len); ! 737: ! 738: if (len == spdy.len && ngx_strncmp(data, spdy.data, spdy.len) == 0) { ! 739: ngx_http_spdy_init(c->read); ! 740: return; ! 741: } ! 742: } ! 743: #endif ! 744: ! 745: c->log->action = "waiting for request"; ! 746: ! 747: c->read->handler = ngx_http_wait_request_handler; ! 748: /* STUB: epoll edge */ c->write->handler = ngx_http_empty_handler; ! 749: ! 750: ngx_reusable_connection(c, 1); ! 751: ! 752: ngx_http_wait_request_handler(c->read); ! 753: ! 754: return; ! 755: } ! 756: ! 757: if (c->read->timedout) { ! 758: ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); ! 759: } ! 760: ! 761: ngx_http_close_connection(c); ! 762: } ! 763: ! 764: #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME ! 765: ! 766: int ! 767: ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) ! 768: { ! 769: ngx_str_t host; ! 770: const char *servername; ! 771: ngx_connection_t *c; ! 772: ngx_http_connection_t *hc; ! 773: ngx_http_ssl_srv_conf_t *sscf; ! 774: ngx_http_core_loc_conf_t *clcf; ! 775: ngx_http_core_srv_conf_t *cscf; ! 776: ! 777: servername = SSL_get_servername(ssl_conn, TLSEXT_NAMETYPE_host_name); ! 778: ! 779: if (servername == NULL) { ! 780: return SSL_TLSEXT_ERR_NOACK; ! 781: } ! 782: ! 783: c = ngx_ssl_get_connection(ssl_conn); ! 784: ! 785: ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, ! 786: "SSL server name: \"%s\"", servername); ! 787: ! 788: host.len = ngx_strlen(servername); ! 789: ! 790: if (host.len == 0) { ! 791: return SSL_TLSEXT_ERR_NOACK; ! 792: } ! 793: ! 794: host.data = (u_char *) servername; ! 795: ! 796: if (ngx_http_validate_host(&host, c->pool, 1) != NGX_OK) { ! 797: return SSL_TLSEXT_ERR_NOACK; ! 798: } ! 799: ! 800: hc = c->data; ! 801: ! 802: if (ngx_http_find_virtual_server(c, hc->addr_conf->virtual_names, &host, ! 803: NULL, &cscf) ! 804: != NGX_OK) ! 805: { ! 806: return SSL_TLSEXT_ERR_NOACK; ! 807: } ! 808: ! 809: hc->ssl_servername = ngx_palloc(c->pool, sizeof(ngx_str_t)); ! 810: if (hc->ssl_servername == NULL) { ! 811: return SSL_TLSEXT_ERR_NOACK; ! 812: } ! 813: ! 814: *hc->ssl_servername = host; ! 815: ! 816: hc->conf_ctx = cscf->ctx; ! 817: ! 818: clcf = ngx_http_get_module_loc_conf(hc->conf_ctx, ngx_http_core_module); ! 819: ! 820: ngx_http_set_connection_log(c, clcf->error_log); ! 821: ! 822: sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module); ! 823: ! 824: if (sscf->ssl.ctx) { ! 825: SSL_set_SSL_CTX(ssl_conn, sscf->ssl.ctx); ! 826: ! 827: /* ! 828: * SSL_set_SSL_CTX() only changes certs as of 1.0.0d ! 829: * adjust other things we care about ! 830: */ ! 831: ! 832: SSL_set_verify(ssl_conn, SSL_CTX_get_verify_mode(sscf->ssl.ctx), ! 833: SSL_CTX_get_verify_callback(sscf->ssl.ctx)); ! 834: ! 835: SSL_set_verify_depth(ssl_conn, SSL_CTX_get_verify_depth(sscf->ssl.ctx)); ! 836: ! 837: #ifdef SSL_CTRL_CLEAR_OPTIONS ! 838: /* only in 0.9.8m+ */ ! 839: SSL_clear_options(ssl_conn, SSL_get_options(ssl_conn) & ! 840: ~SSL_CTX_get_options(sscf->ssl.ctx)); ! 841: #endif ! 842: ! 843: SSL_set_options(ssl_conn, SSL_CTX_get_options(sscf->ssl.ctx)); ! 844: } ! 845: ! 846: return SSL_TLSEXT_ERR_OK; ! 847: } ! 848: ! 849: #endif ! 850: ! 851: #endif ! 852: ! 853: ! 854: static void ! 855: ngx_http_process_request_line(ngx_event_t *rev) ! 856: { ! 857: ssize_t n; ! 858: ngx_int_t rc, rv; ! 859: ngx_str_t host; ! 860: ngx_connection_t *c; ! 861: ngx_http_request_t *r; ! 862: ! 863: c = rev->data; ! 864: r = c->data; ! 865: ! 866: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, ! 867: "http process request line"); ! 868: ! 869: if (rev->timedout) { ! 870: ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); ! 871: c->timedout = 1; ! 872: ngx_http_close_request(r, NGX_HTTP_REQUEST_TIME_OUT); ! 873: return; ! 874: } ! 875: ! 876: rc = NGX_AGAIN; ! 877: ! 878: for ( ;; ) { ! 879: ! 880: if (rc == NGX_AGAIN) { ! 881: n = ngx_http_read_request_header(r); ! 882: ! 883: if (n == NGX_AGAIN || n == NGX_ERROR) { ! 884: return; ! 885: } ! 886: } ! 887: ! 888: rc = ngx_http_parse_request_line(r, r->header_in); ! 889: ! 890: if (rc == NGX_OK) { ! 891: ! 892: /* the request line has been parsed successfully */ ! 893: ! 894: r->request_line.len = r->request_end - r->request_start; ! 895: r->request_line.data = r->request_start; ! 896: r->request_length = r->header_in->pos - r->request_start; ! 897: ! 898: ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, ! 899: "http request line: \"%V\"", &r->request_line); ! 900: ! 901: r->method_name.len = r->method_end - r->request_start + 1; ! 902: r->method_name.data = r->request_line.data; ! 903: ! 904: if (r->http_protocol.data) { ! 905: r->http_protocol.len = r->request_end - r->http_protocol.data; ! 906: } ! 907: ! 908: if (ngx_http_process_request_uri(r) != NGX_OK) { ! 909: return; ! 910: } ! 911: ! 912: if (r->host_start && r->host_end) { ! 913: ! 914: host.len = r->host_end - r->host_start; ! 915: host.data = r->host_start; ! 916: ! 917: rc = ngx_http_validate_host(&host, r->pool, 0); ! 918: ! 919: if (rc == NGX_DECLINED) { ! 920: ngx_log_error(NGX_LOG_INFO, c->log, 0, ! 921: "client sent invalid host in request line"); ! 922: ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); ! 923: return; ! 924: } ! 925: ! 926: if (rc == NGX_ERROR) { ! 927: ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); ! 928: return; ! 929: } ! 930: ! 931: if (ngx_http_set_virtual_server(r, &host) == NGX_ERROR) { ! 932: return; ! 933: } ! 934: ! 935: r->headers_in.server = host; ! 936: } ! 937: ! 938: if (r->http_version < NGX_HTTP_VERSION_10) { ! 939: ! 940: if (r->headers_in.server.len == 0 ! 941: && ngx_http_set_virtual_server(r, &r->headers_in.server) ! 942: == NGX_ERROR) ! 943: { ! 944: return; ! 945: } ! 946: ! 947: ngx_http_process_request(r); ! 948: return; ! 949: } ! 950: ! 951: ! 952: if (ngx_list_init(&r->headers_in.headers, r->pool, 20, ! 953: sizeof(ngx_table_elt_t)) ! 954: != NGX_OK) ! 955: { ! 956: ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); ! 957: return; ! 958: } ! 959: ! 960: c->log->action = "reading client request headers"; ! 961: ! 962: rev->handler = ngx_http_process_request_headers; ! 963: ngx_http_process_request_headers(rev); ! 964: ! 965: return; ! 966: } ! 967: ! 968: if (rc != NGX_AGAIN) { ! 969: ! 970: /* there was error while a request line parsing */ ! 971: ! 972: ngx_log_error(NGX_LOG_INFO, c->log, 0, ! 973: ngx_http_client_errors[rc - NGX_HTTP_CLIENT_ERROR]); ! 974: ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); ! 975: return; ! 976: } ! 977: ! 978: /* NGX_AGAIN: a request line parsing is still incomplete */ ! 979: ! 980: if (r->header_in->pos == r->header_in->end) { ! 981: ! 982: rv = ngx_http_alloc_large_header_buffer(r, 1); ! 983: ! 984: if (rv == NGX_ERROR) { ! 985: ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); ! 986: return; ! 987: } ! 988: ! 989: if (rv == NGX_DECLINED) { ! 990: r->request_line.len = r->header_in->end - r->request_start; ! 991: r->request_line.data = r->request_start; ! 992: ! 993: ngx_log_error(NGX_LOG_INFO, c->log, 0, ! 994: "client sent too long URI"); ! 995: ngx_http_finalize_request(r, NGX_HTTP_REQUEST_URI_TOO_LARGE); ! 996: return; ! 997: } ! 998: } ! 999: } ! 1000: } ! 1001: ! 1002: ! 1003: ngx_int_t ! 1004: ngx_http_process_request_uri(ngx_http_request_t *r) ! 1005: { ! 1006: ngx_http_core_srv_conf_t *cscf; ! 1007: ! 1008: if (r->args_start) { ! 1009: r->uri.len = r->args_start - 1 - r->uri_start; ! 1010: } else { ! 1011: r->uri.len = r->uri_end - r->uri_start; ! 1012: } ! 1013: ! 1014: if (r->complex_uri || r->quoted_uri) { ! 1015: ! 1016: r->uri.data = ngx_pnalloc(r->pool, r->uri.len + 1); ! 1017: if (r->uri.data == NULL) { ! 1018: ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); ! 1019: return NGX_ERROR; ! 1020: } ! 1021: ! 1022: cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); ! 1023: ! 1024: if (ngx_http_parse_complex_uri(r, cscf->merge_slashes) != NGX_OK) { ! 1025: ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, ! 1026: "client sent invalid request"); ! 1027: ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); ! 1028: return NGX_ERROR; ! 1029: } ! 1030: ! 1031: } else { ! 1032: r->uri.data = r->uri_start; ! 1033: } ! 1034: ! 1035: r->unparsed_uri.len = r->uri_end - r->uri_start; ! 1036: r->unparsed_uri.data = r->uri_start; ! 1037: ! 1038: r->valid_unparsed_uri = r->space_in_uri ? 0 : 1; ! 1039: ! 1040: if (r->uri_ext) { ! 1041: if (r->args_start) { ! 1042: r->exten.len = r->args_start - 1 - r->uri_ext; ! 1043: } else { ! 1044: r->exten.len = r->uri_end - r->uri_ext; ! 1045: } ! 1046: ! 1047: r->exten.data = r->uri_ext; ! 1048: } ! 1049: ! 1050: if (r->args_start && r->uri_end > r->args_start) { ! 1051: r->args.len = r->uri_end - r->args_start; ! 1052: r->args.data = r->args_start; ! 1053: } ! 1054: ! 1055: #if (NGX_WIN32) ! 1056: { ! 1057: u_char *p, *last; ! 1058: ! 1059: p = r->uri.data; ! 1060: last = r->uri.data + r->uri.len; ! 1061: ! 1062: while (p < last) { ! 1063: ! 1064: if (*p++ == ':') { ! 1065: ! 1066: /* ! 1067: * this check covers "::$data", "::$index_allocation" and ! 1068: * ":$i30:$index_allocation" ! 1069: */ ! 1070: ! 1071: if (p < last && *p == '$') { ! 1072: ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, ! 1073: "client sent unsafe win32 URI"); ! 1074: ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); ! 1075: return NGX_ERROR; ! 1076: } ! 1077: } ! 1078: } ! 1079: ! 1080: p = r->uri.data + r->uri.len - 1; ! 1081: ! 1082: while (p > r->uri.data) { ! 1083: ! 1084: if (*p == ' ') { ! 1085: p--; ! 1086: continue; ! 1087: } ! 1088: ! 1089: if (*p == '.') { ! 1090: p--; ! 1091: continue; ! 1092: } ! 1093: ! 1094: break; ! 1095: } ! 1096: ! 1097: if (p != r->uri.data + r->uri.len - 1) { ! 1098: r->uri.len = p + 1 - r->uri.data; ! 1099: ngx_http_set_exten(r); ! 1100: } ! 1101: ! 1102: } ! 1103: #endif ! 1104: ! 1105: ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, ! 1106: "http uri: \"%V\"", &r->uri); ! 1107: ! 1108: ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, ! 1109: "http args: \"%V\"", &r->args); ! 1110: ! 1111: ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, ! 1112: "http exten: \"%V\"", &r->exten); ! 1113: ! 1114: return NGX_OK; ! 1115: } ! 1116: ! 1117: ! 1118: static void ! 1119: ngx_http_process_request_headers(ngx_event_t *rev) ! 1120: { ! 1121: u_char *p; ! 1122: size_t len; ! 1123: ssize_t n; ! 1124: ngx_int_t rc, rv; ! 1125: ngx_table_elt_t *h; ! 1126: ngx_connection_t *c; ! 1127: ngx_http_header_t *hh; ! 1128: ngx_http_request_t *r; ! 1129: ngx_http_core_srv_conf_t *cscf; ! 1130: ngx_http_core_main_conf_t *cmcf; ! 1131: ! 1132: c = rev->data; ! 1133: r = c->data; ! 1134: ! 1135: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, ! 1136: "http process request header line"); ! 1137: ! 1138: if (rev->timedout) { ! 1139: ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); ! 1140: c->timedout = 1; ! 1141: ngx_http_close_request(r, NGX_HTTP_REQUEST_TIME_OUT); ! 1142: return; ! 1143: } ! 1144: ! 1145: cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); ! 1146: ! 1147: rc = NGX_AGAIN; ! 1148: ! 1149: for ( ;; ) { ! 1150: ! 1151: if (rc == NGX_AGAIN) { ! 1152: ! 1153: if (r->header_in->pos == r->header_in->end) { ! 1154: ! 1155: rv = ngx_http_alloc_large_header_buffer(r, 0); ! 1156: ! 1157: if (rv == NGX_ERROR) { ! 1158: ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); ! 1159: return; ! 1160: } ! 1161: ! 1162: if (rv == NGX_DECLINED) { ! 1163: p = r->header_name_start; ! 1164: ! 1165: r->lingering_close = 1; ! 1166: ! 1167: if (p == NULL) { ! 1168: ngx_log_error(NGX_LOG_INFO, c->log, 0, ! 1169: "client sent too large request"); ! 1170: ngx_http_finalize_request(r, ! 1171: NGX_HTTP_REQUEST_HEADER_TOO_LARGE); ! 1172: return; ! 1173: } ! 1174: ! 1175: len = r->header_in->end - p; ! 1176: ! 1177: if (len > NGX_MAX_ERROR_STR - 300) { ! 1178: len = NGX_MAX_ERROR_STR - 300; ! 1179: p[len++] = '.'; p[len++] = '.'; p[len++] = '.'; ! 1180: } ! 1181: ! 1182: ngx_log_error(NGX_LOG_INFO, c->log, 0, ! 1183: "client sent too long header line: \"%*s\"", ! 1184: len, r->header_name_start); ! 1185: ! 1186: ngx_http_finalize_request(r, ! 1187: NGX_HTTP_REQUEST_HEADER_TOO_LARGE); ! 1188: return; ! 1189: } ! 1190: } ! 1191: ! 1192: n = ngx_http_read_request_header(r); ! 1193: ! 1194: if (n == NGX_AGAIN || n == NGX_ERROR) { ! 1195: return; ! 1196: } ! 1197: } ! 1198: ! 1199: /* the host header could change the server configuration context */ ! 1200: cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); ! 1201: ! 1202: rc = ngx_http_parse_header_line(r, r->header_in, ! 1203: cscf->underscores_in_headers); ! 1204: ! 1205: if (rc == NGX_OK) { ! 1206: ! 1207: r->request_length += r->header_in->pos - r->header_name_start; ! 1208: ! 1209: if (r->invalid_header && cscf->ignore_invalid_headers) { ! 1210: ! 1211: /* there was error while a header line parsing */ ! 1212: ! 1213: ngx_log_error(NGX_LOG_INFO, c->log, 0, ! 1214: "client sent invalid header line: \"%*s\"", ! 1215: r->header_end - r->header_name_start, ! 1216: r->header_name_start); ! 1217: continue; ! 1218: } ! 1219: ! 1220: /* a header line has been parsed successfully */ ! 1221: ! 1222: h = ngx_list_push(&r->headers_in.headers); ! 1223: if (h == NULL) { ! 1224: ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); ! 1225: return; ! 1226: } ! 1227: ! 1228: h->hash = r->header_hash; ! 1229: ! 1230: h->key.len = r->header_name_end - r->header_name_start; ! 1231: h->key.data = r->header_name_start; ! 1232: h->key.data[h->key.len] = '\0'; ! 1233: ! 1234: h->value.len = r->header_end - r->header_start; ! 1235: h->value.data = r->header_start; ! 1236: h->value.data[h->value.len] = '\0'; ! 1237: ! 1238: h->lowcase_key = ngx_pnalloc(r->pool, h->key.len); ! 1239: if (h->lowcase_key == NULL) { ! 1240: ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); ! 1241: return; ! 1242: } ! 1243: ! 1244: if (h->key.len == r->lowcase_index) { ! 1245: ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len); ! 1246: ! 1247: } else { ! 1248: ngx_strlow(h->lowcase_key, h->key.data, h->key.len); ! 1249: } ! 1250: ! 1251: hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash, ! 1252: h->lowcase_key, h->key.len); ! 1253: ! 1254: if (hh && hh->handler(r, h, hh->offset) != NGX_OK) { ! 1255: return; ! 1256: } ! 1257: ! 1258: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, ! 1259: "http header: \"%V: %V\"", ! 1260: &h->key, &h->value); ! 1261: ! 1262: continue; ! 1263: } ! 1264: ! 1265: if (rc == NGX_HTTP_PARSE_HEADER_DONE) { ! 1266: ! 1267: /* a whole header has been parsed successfully */ ! 1268: ! 1269: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, ! 1270: "http header done"); ! 1271: ! 1272: r->request_length += r->header_in->pos - r->header_name_start; ! 1273: ! 1274: r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE; ! 1275: ! 1276: rc = ngx_http_process_request_header(r); ! 1277: ! 1278: if (rc != NGX_OK) { ! 1279: return; ! 1280: } ! 1281: ! 1282: ngx_http_process_request(r); ! 1283: ! 1284: return; ! 1285: } ! 1286: ! 1287: if (rc == NGX_AGAIN) { ! 1288: ! 1289: /* a header line parsing is still not complete */ ! 1290: ! 1291: continue; ! 1292: } ! 1293: ! 1294: /* rc == NGX_HTTP_PARSE_INVALID_HEADER: "\r" is not followed by "\n" */ ! 1295: ! 1296: ngx_log_error(NGX_LOG_INFO, c->log, 0, ! 1297: "client sent invalid header line: \"%*s\\r...\"", ! 1298: r->header_end - r->header_name_start, ! 1299: r->header_name_start); ! 1300: ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); ! 1301: return; ! 1302: } ! 1303: } ! 1304: ! 1305: ! 1306: static ssize_t ! 1307: ngx_http_read_request_header(ngx_http_request_t *r) ! 1308: { ! 1309: ssize_t n; ! 1310: ngx_event_t *rev; ! 1311: ngx_connection_t *c; ! 1312: ngx_http_core_srv_conf_t *cscf; ! 1313: ! 1314: c = r->connection; ! 1315: rev = c->read; ! 1316: ! 1317: n = r->header_in->last - r->header_in->pos; ! 1318: ! 1319: if (n > 0) { ! 1320: return n; ! 1321: } ! 1322: ! 1323: if (rev->ready) { ! 1324: n = c->recv(c, r->header_in->last, ! 1325: r->header_in->end - r->header_in->last); ! 1326: } else { ! 1327: n = NGX_AGAIN; ! 1328: } ! 1329: ! 1330: if (n == NGX_AGAIN) { ! 1331: if (!rev->timer_set) { ! 1332: cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); ! 1333: ngx_add_timer(rev, cscf->client_header_timeout); ! 1334: } ! 1335: ! 1336: if (ngx_handle_read_event(rev, 0) != NGX_OK) { ! 1337: ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); ! 1338: return NGX_ERROR; ! 1339: } ! 1340: ! 1341: return NGX_AGAIN; ! 1342: } ! 1343: ! 1344: if (n == 0) { ! 1345: ngx_log_error(NGX_LOG_INFO, c->log, 0, ! 1346: "client prematurely closed connection"); ! 1347: } ! 1348: ! 1349: if (n == 0 || n == NGX_ERROR) { ! 1350: c->error = 1; ! 1351: c->log->action = "reading client request headers"; ! 1352: ! 1353: ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); ! 1354: return NGX_ERROR; ! 1355: } ! 1356: ! 1357: r->header_in->last += n; ! 1358: ! 1359: return n; ! 1360: } ! 1361: ! 1362: ! 1363: static ngx_int_t ! 1364: ngx_http_alloc_large_header_buffer(ngx_http_request_t *r, ! 1365: ngx_uint_t request_line) ! 1366: { ! 1367: u_char *old, *new; ! 1368: ngx_buf_t *b; ! 1369: ngx_http_connection_t *hc; ! 1370: ngx_http_core_srv_conf_t *cscf; ! 1371: ! 1372: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, ! 1373: "http alloc large header buffer"); ! 1374: ! 1375: if (request_line && r->state == 0) { ! 1376: ! 1377: /* the client fills up the buffer with "\r\n" */ ! 1378: ! 1379: r->header_in->pos = r->header_in->start; ! 1380: r->header_in->last = r->header_in->start; ! 1381: ! 1382: return NGX_OK; ! 1383: } ! 1384: ! 1385: old = request_line ? r->request_start : r->header_name_start; ! 1386: ! 1387: cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); ! 1388: ! 1389: if (r->state != 0 ! 1390: && (size_t) (r->header_in->pos - old) ! 1391: >= cscf->large_client_header_buffers.size) ! 1392: { ! 1393: return NGX_DECLINED; ! 1394: } ! 1395: ! 1396: hc = r->http_connection; ! 1397: ! 1398: if (hc->nfree) { ! 1399: b = hc->free[--hc->nfree]; ! 1400: ! 1401: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, ! 1402: "http large header free: %p %uz", ! 1403: b->pos, b->end - b->last); ! 1404: ! 1405: } else if (hc->nbusy < cscf->large_client_header_buffers.num) { ! 1406: ! 1407: if (hc->busy == NULL) { ! 1408: hc->busy = ngx_palloc(r->connection->pool, ! 1409: cscf->large_client_header_buffers.num * sizeof(ngx_buf_t *)); ! 1410: if (hc->busy == NULL) { ! 1411: return NGX_ERROR; ! 1412: } ! 1413: } ! 1414: ! 1415: b = ngx_create_temp_buf(r->connection->pool, ! 1416: cscf->large_client_header_buffers.size); ! 1417: if (b == NULL) { ! 1418: return NGX_ERROR; ! 1419: } ! 1420: ! 1421: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, ! 1422: "http large header alloc: %p %uz", ! 1423: b->pos, b->end - b->last); ! 1424: ! 1425: } else { ! 1426: return NGX_DECLINED; ! 1427: } ! 1428: ! 1429: hc->busy[hc->nbusy++] = b; ! 1430: ! 1431: if (r->state == 0) { ! 1432: /* ! 1433: * r->state == 0 means that a header line was parsed successfully ! 1434: * and we do not need to copy incomplete header line and ! 1435: * to relocate the parser header pointers ! 1436: */ ! 1437: ! 1438: r->header_in = b; ! 1439: ! 1440: return NGX_OK; ! 1441: } ! 1442: ! 1443: ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, ! 1444: "http large header copy: %d", r->header_in->pos - old); ! 1445: ! 1446: new = b->start; ! 1447: ! 1448: ngx_memcpy(new, old, r->header_in->pos - old); ! 1449: ! 1450: b->pos = new + (r->header_in->pos - old); ! 1451: b->last = new + (r->header_in->pos - old); ! 1452: ! 1453: if (request_line) { ! 1454: r->request_start = new; ! 1455: ! 1456: if (r->request_end) { ! 1457: r->request_end = new + (r->request_end - old); ! 1458: } ! 1459: ! 1460: r->method_end = new + (r->method_end - old); ! 1461: ! 1462: r->uri_start = new + (r->uri_start - old); ! 1463: r->uri_end = new + (r->uri_end - old); ! 1464: ! 1465: if (r->schema_start) { ! 1466: r->schema_start = new + (r->schema_start - old); ! 1467: r->schema_end = new + (r->schema_end - old); ! 1468: } ! 1469: ! 1470: if (r->host_start) { ! 1471: r->host_start = new + (r->host_start - old); ! 1472: if (r->host_end) { ! 1473: r->host_end = new + (r->host_end - old); ! 1474: } ! 1475: } ! 1476: ! 1477: if (r->port_start) { ! 1478: r->port_start = new + (r->port_start - old); ! 1479: r->port_end = new + (r->port_end - old); ! 1480: } ! 1481: ! 1482: if (r->uri_ext) { ! 1483: r->uri_ext = new + (r->uri_ext - old); ! 1484: } ! 1485: ! 1486: if (r->args_start) { ! 1487: r->args_start = new + (r->args_start - old); ! 1488: } ! 1489: ! 1490: if (r->http_protocol.data) { ! 1491: r->http_protocol.data = new + (r->http_protocol.data - old); ! 1492: } ! 1493: ! 1494: } else { ! 1495: r->header_name_start = new; ! 1496: r->header_name_end = new + (r->header_name_end - old); ! 1497: r->header_start = new + (r->header_start - old); ! 1498: r->header_end = new + (r->header_end - old); ! 1499: } ! 1500: ! 1501: r->header_in = b; ! 1502: ! 1503: return NGX_OK; ! 1504: } ! 1505: ! 1506: ! 1507: static ngx_int_t ! 1508: ngx_http_process_header_line(ngx_http_request_t *r, ngx_table_elt_t *h, ! 1509: ngx_uint_t offset) ! 1510: { ! 1511: ngx_table_elt_t **ph; ! 1512: ! 1513: ph = (ngx_table_elt_t **) ((char *) &r->headers_in + offset); ! 1514: ! 1515: if (*ph == NULL) { ! 1516: *ph = h; ! 1517: } ! 1518: ! 1519: return NGX_OK; ! 1520: } ! 1521: ! 1522: ! 1523: static ngx_int_t ! 1524: ngx_http_process_unique_header_line(ngx_http_request_t *r, ngx_table_elt_t *h, ! 1525: ngx_uint_t offset) ! 1526: { ! 1527: ngx_table_elt_t **ph; ! 1528: ! 1529: ph = (ngx_table_elt_t **) ((char *) &r->headers_in + offset); ! 1530: ! 1531: if (*ph == NULL) { ! 1532: *ph = h; ! 1533: return NGX_OK; ! 1534: } ! 1535: ! 1536: ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, ! 1537: "client sent duplicate header line: \"%V: %V\", " ! 1538: "previous value: \"%V: %V\"", ! 1539: &h->key, &h->value, &(*ph)->key, &(*ph)->value); ! 1540: ! 1541: ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); ! 1542: ! 1543: return NGX_ERROR; ! 1544: } ! 1545: ! 1546: ! 1547: static ngx_int_t ! 1548: ngx_http_process_host(ngx_http_request_t *r, ngx_table_elt_t *h, ! 1549: ngx_uint_t offset) ! 1550: { ! 1551: ngx_int_t rc; ! 1552: ngx_str_t host; ! 1553: ! 1554: if (r->headers_in.host == NULL) { ! 1555: r->headers_in.host = h; ! 1556: } ! 1557: ! 1558: host = h->value; ! 1559: ! 1560: rc = ngx_http_validate_host(&host, r->pool, 0); ! 1561: ! 1562: if (rc == NGX_DECLINED) { ! 1563: ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, ! 1564: "client sent invalid host header"); ! 1565: ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); ! 1566: return NGX_ERROR; ! 1567: } ! 1568: ! 1569: if (rc == NGX_ERROR) { ! 1570: ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); ! 1571: return NGX_ERROR; ! 1572: } ! 1573: ! 1574: if (r->headers_in.server.len) { ! 1575: return NGX_OK; ! 1576: } ! 1577: ! 1578: if (ngx_http_set_virtual_server(r, &host) == NGX_ERROR) { ! 1579: return NGX_ERROR; ! 1580: } ! 1581: ! 1582: r->headers_in.server = host; ! 1583: ! 1584: return NGX_OK; ! 1585: } ! 1586: ! 1587: ! 1588: static ngx_int_t ! 1589: ngx_http_process_connection(ngx_http_request_t *r, ngx_table_elt_t *h, ! 1590: ngx_uint_t offset) ! 1591: { ! 1592: if (ngx_strcasestrn(h->value.data, "close", 5 - 1)) { ! 1593: r->headers_in.connection_type = NGX_HTTP_CONNECTION_CLOSE; ! 1594: ! 1595: } else if (ngx_strcasestrn(h->value.data, "keep-alive", 10 - 1)) { ! 1596: r->headers_in.connection_type = NGX_HTTP_CONNECTION_KEEP_ALIVE; ! 1597: } ! 1598: ! 1599: return NGX_OK; ! 1600: } ! 1601: ! 1602: ! 1603: static ngx_int_t ! 1604: ngx_http_process_user_agent(ngx_http_request_t *r, ngx_table_elt_t *h, ! 1605: ngx_uint_t offset) ! 1606: { ! 1607: u_char *user_agent, *msie; ! 1608: ! 1609: if (r->headers_in.user_agent) { ! 1610: return NGX_OK; ! 1611: } ! 1612: ! 1613: r->headers_in.user_agent = h; ! 1614: ! 1615: /* check some widespread browsers while the header is in CPU cache */ ! 1616: ! 1617: user_agent = h->value.data; ! 1618: ! 1619: msie = ngx_strstrn(user_agent, "MSIE ", 5 - 1); ! 1620: ! 1621: if (msie && msie + 7 < user_agent + h->value.len) { ! 1622: ! 1623: r->headers_in.msie = 1; ! 1624: ! 1625: if (msie[6] == '.') { ! 1626: ! 1627: switch (msie[5]) { ! 1628: case '4': ! 1629: case '5': ! 1630: r->headers_in.msie6 = 1; ! 1631: break; ! 1632: case '6': ! 1633: if (ngx_strstrn(msie + 8, "SV1", 3 - 1) == NULL) { ! 1634: r->headers_in.msie6 = 1; ! 1635: } ! 1636: break; ! 1637: } ! 1638: } ! 1639: ! 1640: #if 0 ! 1641: /* MSIE ignores the SSL "close notify" alert */ ! 1642: if (c->ssl) { ! 1643: c->ssl->no_send_shutdown = 1; ! 1644: } ! 1645: #endif ! 1646: } ! 1647: ! 1648: if (ngx_strstrn(user_agent, "Opera", 5 - 1)) { ! 1649: r->headers_in.opera = 1; ! 1650: r->headers_in.msie = 0; ! 1651: r->headers_in.msie6 = 0; ! 1652: } ! 1653: ! 1654: if (!r->headers_in.msie && !r->headers_in.opera) { ! 1655: ! 1656: if (ngx_strstrn(user_agent, "Gecko/", 6 - 1)) { ! 1657: r->headers_in.gecko = 1; ! 1658: ! 1659: } else if (ngx_strstrn(user_agent, "Chrome/", 7 - 1)) { ! 1660: r->headers_in.chrome = 1; ! 1661: ! 1662: } else if (ngx_strstrn(user_agent, "Safari/", 7 - 1) ! 1663: && ngx_strstrn(user_agent, "Mac OS X", 8 - 1)) ! 1664: { ! 1665: r->headers_in.safari = 1; ! 1666: ! 1667: } else if (ngx_strstrn(user_agent, "Konqueror", 9 - 1)) { ! 1668: r->headers_in.konqueror = 1; ! 1669: } ! 1670: } ! 1671: ! 1672: return NGX_OK; ! 1673: } ! 1674: ! 1675: ! 1676: static ngx_int_t ! 1677: ngx_http_process_multi_header_lines(ngx_http_request_t *r, ngx_table_elt_t *h, ! 1678: ngx_uint_t offset) ! 1679: { ! 1680: ngx_array_t *headers; ! 1681: ngx_table_elt_t **ph; ! 1682: ! 1683: headers = (ngx_array_t *) ((char *) &r->headers_in + offset); ! 1684: ! 1685: if (headers->elts == NULL) { ! 1686: if (ngx_array_init(headers, r->pool, 1, sizeof(ngx_table_elt_t *)) ! 1687: != NGX_OK) ! 1688: { ! 1689: ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); ! 1690: return NGX_ERROR; ! 1691: } ! 1692: } ! 1693: ! 1694: ph = ngx_array_push(headers); ! 1695: if (ph == NULL) { ! 1696: ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); ! 1697: return NGX_ERROR; ! 1698: } ! 1699: ! 1700: *ph = h; ! 1701: return NGX_OK; ! 1702: } ! 1703: ! 1704: ! 1705: ngx_int_t ! 1706: ngx_http_process_request_header(ngx_http_request_t *r) ! 1707: { ! 1708: if (r->headers_in.server.len == 0 ! 1709: && ngx_http_set_virtual_server(r, &r->headers_in.server) ! 1710: == NGX_ERROR) ! 1711: { ! 1712: return NGX_ERROR; ! 1713: } ! 1714: ! 1715: if (r->headers_in.host == NULL && r->http_version > NGX_HTTP_VERSION_10) { ! 1716: ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, ! 1717: "client sent HTTP/1.1 request without \"Host\" header"); ! 1718: ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); ! 1719: return NGX_ERROR; ! 1720: } ! 1721: ! 1722: if (r->headers_in.content_length) { ! 1723: r->headers_in.content_length_n = ! 1724: ngx_atoof(r->headers_in.content_length->value.data, ! 1725: r->headers_in.content_length->value.len); ! 1726: ! 1727: if (r->headers_in.content_length_n == NGX_ERROR) { ! 1728: ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, ! 1729: "client sent invalid \"Content-Length\" header"); ! 1730: ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); ! 1731: return NGX_ERROR; ! 1732: } ! 1733: } ! 1734: ! 1735: if (r->method & NGX_HTTP_TRACE) { ! 1736: ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, ! 1737: "client sent TRACE method"); ! 1738: ngx_http_finalize_request(r, NGX_HTTP_NOT_ALLOWED); ! 1739: return NGX_ERROR; ! 1740: } ! 1741: ! 1742: if (r->headers_in.transfer_encoding) { ! 1743: if (r->headers_in.transfer_encoding->value.len == 7 ! 1744: && ngx_strncasecmp(r->headers_in.transfer_encoding->value.data, ! 1745: (u_char *) "chunked", 7) == 0) ! 1746: { ! 1747: r->headers_in.content_length = NULL; ! 1748: r->headers_in.content_length_n = -1; ! 1749: r->headers_in.chunked = 1; ! 1750: ! 1751: } else if (r->headers_in.transfer_encoding->value.len != 8 ! 1752: || ngx_strncasecmp(r->headers_in.transfer_encoding->value.data, ! 1753: (u_char *) "identity", 8) != 0) ! 1754: { ! 1755: ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, ! 1756: "client sent unknown \"Transfer-Encoding\": \"%V\"", ! 1757: &r->headers_in.transfer_encoding->value); ! 1758: ngx_http_finalize_request(r, NGX_HTTP_NOT_IMPLEMENTED); ! 1759: return NGX_ERROR; ! 1760: } ! 1761: } ! 1762: ! 1763: if (r->headers_in.connection_type == NGX_HTTP_CONNECTION_KEEP_ALIVE) { ! 1764: if (r->headers_in.keep_alive) { ! 1765: r->headers_in.keep_alive_n = ! 1766: ngx_atotm(r->headers_in.keep_alive->value.data, ! 1767: r->headers_in.keep_alive->value.len); ! 1768: } ! 1769: } ! 1770: ! 1771: return NGX_OK; ! 1772: } ! 1773: ! 1774: ! 1775: void ! 1776: ngx_http_process_request(ngx_http_request_t *r) ! 1777: { ! 1778: ngx_connection_t *c; ! 1779: ! 1780: c = r->connection; ! 1781: ! 1782: #if (NGX_HTTP_SSL) ! 1783: ! 1784: if (r->http_connection->ssl) { ! 1785: long rc; ! 1786: X509 *cert; ! 1787: ngx_http_ssl_srv_conf_t *sscf; ! 1788: ! 1789: if (c->ssl == NULL) { ! 1790: ngx_log_error(NGX_LOG_INFO, c->log, 0, ! 1791: "client sent plain HTTP request to HTTPS port"); ! 1792: ngx_http_finalize_request(r, NGX_HTTP_TO_HTTPS); ! 1793: return; ! 1794: } ! 1795: ! 1796: sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module); ! 1797: ! 1798: if (sscf->verify) { ! 1799: rc = SSL_get_verify_result(c->ssl->connection); ! 1800: ! 1801: if (rc != X509_V_OK ! 1802: && (sscf->verify != 3 || !ngx_ssl_verify_error_optional(rc))) ! 1803: { ! 1804: ngx_log_error(NGX_LOG_INFO, c->log, 0, ! 1805: "client SSL certificate verify error: (%l:%s)", ! 1806: rc, X509_verify_cert_error_string(rc)); ! 1807: ! 1808: ngx_ssl_remove_cached_session(sscf->ssl.ctx, ! 1809: (SSL_get0_session(c->ssl->connection))); ! 1810: ! 1811: ngx_http_finalize_request(r, NGX_HTTPS_CERT_ERROR); ! 1812: return; ! 1813: } ! 1814: ! 1815: if (sscf->verify == 1) { ! 1816: cert = SSL_get_peer_certificate(c->ssl->connection); ! 1817: ! 1818: if (cert == NULL) { ! 1819: ngx_log_error(NGX_LOG_INFO, c->log, 0, ! 1820: "client sent no required SSL certificate"); ! 1821: ! 1822: ngx_ssl_remove_cached_session(sscf->ssl.ctx, ! 1823: (SSL_get0_session(c->ssl->connection))); ! 1824: ! 1825: ngx_http_finalize_request(r, NGX_HTTPS_NO_CERT); ! 1826: return; ! 1827: } ! 1828: ! 1829: X509_free(cert); ! 1830: } ! 1831: } ! 1832: } ! 1833: ! 1834: #endif ! 1835: ! 1836: if (c->read->timer_set) { ! 1837: ngx_del_timer(c->read); ! 1838: } ! 1839: ! 1840: #if (NGX_STAT_STUB) ! 1841: (void) ngx_atomic_fetch_add(ngx_stat_reading, -1); ! 1842: r->stat_reading = 0; ! 1843: (void) ngx_atomic_fetch_add(ngx_stat_writing, 1); ! 1844: r->stat_writing = 1; ! 1845: #endif ! 1846: ! 1847: c->read->handler = ngx_http_request_handler; ! 1848: c->write->handler = ngx_http_request_handler; ! 1849: r->read_event_handler = ngx_http_block_reading; ! 1850: ! 1851: ngx_http_handler(r); ! 1852: ! 1853: ngx_http_run_posted_requests(c); ! 1854: } ! 1855: ! 1856: ! 1857: static ngx_int_t ! 1858: ngx_http_validate_host(ngx_str_t *host, ngx_pool_t *pool, ngx_uint_t alloc) ! 1859: { ! 1860: u_char *h, ch; ! 1861: size_t i, dot_pos, host_len; ! 1862: ! 1863: enum { ! 1864: sw_usual = 0, ! 1865: sw_literal, ! 1866: sw_rest ! 1867: } state; ! 1868: ! 1869: dot_pos = host->len; ! 1870: host_len = host->len; ! 1871: ! 1872: h = host->data; ! 1873: ! 1874: state = sw_usual; ! 1875: ! 1876: for (i = 0; i < host->len; i++) { ! 1877: ch = h[i]; ! 1878: ! 1879: switch (ch) { ! 1880: ! 1881: case '.': ! 1882: if (dot_pos == i - 1) { ! 1883: return NGX_DECLINED; ! 1884: } ! 1885: dot_pos = i; ! 1886: break; ! 1887: ! 1888: case ':': ! 1889: if (state == sw_usual) { ! 1890: host_len = i; ! 1891: state = sw_rest; ! 1892: } ! 1893: break; ! 1894: ! 1895: case '[': ! 1896: if (i == 0) { ! 1897: state = sw_literal; ! 1898: } ! 1899: break; ! 1900: ! 1901: case ']': ! 1902: if (state == sw_literal) { ! 1903: host_len = i + 1; ! 1904: state = sw_rest; ! 1905: } ! 1906: break; ! 1907: ! 1908: case '\0': ! 1909: return NGX_DECLINED; ! 1910: ! 1911: default: ! 1912: ! 1913: if (ngx_path_separator(ch)) { ! 1914: return NGX_DECLINED; ! 1915: } ! 1916: ! 1917: if (ch >= 'A' && ch <= 'Z') { ! 1918: alloc = 1; ! 1919: } ! 1920: ! 1921: break; ! 1922: } ! 1923: } ! 1924: ! 1925: if (dot_pos == host_len - 1) { ! 1926: host_len--; ! 1927: } ! 1928: ! 1929: if (host_len == 0) { ! 1930: return NGX_DECLINED; ! 1931: } ! 1932: ! 1933: if (alloc) { ! 1934: host->data = ngx_pnalloc(pool, host_len); ! 1935: if (host->data == NULL) { ! 1936: return NGX_ERROR; ! 1937: } ! 1938: ! 1939: ngx_strlow(host->data, h, host_len); ! 1940: } ! 1941: ! 1942: host->len = host_len; ! 1943: ! 1944: return NGX_OK; ! 1945: } ! 1946: ! 1947: ! 1948: static ngx_int_t ! 1949: ngx_http_set_virtual_server(ngx_http_request_t *r, ngx_str_t *host) ! 1950: { ! 1951: ngx_int_t rc; ! 1952: ngx_http_connection_t *hc; ! 1953: ngx_http_core_loc_conf_t *clcf; ! 1954: ngx_http_core_srv_conf_t *cscf; ! 1955: ! 1956: hc = r->http_connection; ! 1957: ! 1958: #if (NGX_HTTP_SSL && defined SSL_CTRL_SET_TLSEXT_HOSTNAME) ! 1959: ! 1960: if (hc->ssl_servername) { ! 1961: if (hc->ssl_servername->len == host->len ! 1962: && ngx_strncmp(hc->ssl_servername->data, ! 1963: host->data, host->len) == 0) ! 1964: { ! 1965: #if (NGX_PCRE) ! 1966: if (hc->ssl_servername_regex ! 1967: && ngx_http_regex_exec(r, hc->ssl_servername_regex, ! 1968: hc->ssl_servername) != NGX_OK) ! 1969: { ! 1970: ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); ! 1971: return NGX_ERROR; ! 1972: } ! 1973: #endif ! 1974: return NGX_OK; ! 1975: } ! 1976: } ! 1977: ! 1978: #endif ! 1979: ! 1980: rc = ngx_http_find_virtual_server(r->connection, ! 1981: hc->addr_conf->virtual_names, ! 1982: host, r, &cscf); ! 1983: ! 1984: if (rc == NGX_ERROR) { ! 1985: ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); ! 1986: return NGX_ERROR; ! 1987: } ! 1988: ! 1989: #if (NGX_HTTP_SSL && defined SSL_CTRL_SET_TLSEXT_HOSTNAME) ! 1990: ! 1991: if (hc->ssl_servername) { ! 1992: ngx_http_ssl_srv_conf_t *sscf; ! 1993: ! 1994: if (rc == NGX_DECLINED) { ! 1995: cscf = hc->addr_conf->default_server; ! 1996: rc = NGX_OK; ! 1997: } ! 1998: ! 1999: sscf = ngx_http_get_module_srv_conf(cscf->ctx, ngx_http_ssl_module); ! 2000: ! 2001: if (sscf->verify) { ! 2002: ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, ! 2003: "client attempted to request the server name " ! 2004: "different from that one was negotiated"); ! 2005: ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); ! 2006: return NGX_ERROR; ! 2007: } ! 2008: } ! 2009: ! 2010: #endif ! 2011: ! 2012: if (rc == NGX_DECLINED) { ! 2013: return NGX_OK; ! 2014: } ! 2015: ! 2016: r->srv_conf = cscf->ctx->srv_conf; ! 2017: r->loc_conf = cscf->ctx->loc_conf; ! 2018: ! 2019: clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ! 2020: ! 2021: ngx_http_set_connection_log(r->connection, clcf->error_log); ! 2022: ! 2023: return NGX_OK; ! 2024: } ! 2025: ! 2026: ! 2027: static ngx_int_t ! 2028: ngx_http_find_virtual_server(ngx_connection_t *c, ! 2029: ngx_http_virtual_names_t *virtual_names, ngx_str_t *host, ! 2030: ngx_http_request_t *r, ngx_http_core_srv_conf_t **cscfp) ! 2031: { ! 2032: ngx_http_core_srv_conf_t *cscf; ! 2033: ! 2034: if (virtual_names == NULL) { ! 2035: return NGX_DECLINED; ! 2036: } ! 2037: ! 2038: cscf = ngx_hash_find_combined(&virtual_names->names, ! 2039: ngx_hash_key(host->data, host->len), ! 2040: host->data, host->len); ! 2041: ! 2042: if (cscf) { ! 2043: *cscfp = cscf; ! 2044: return NGX_OK; ! 2045: } ! 2046: ! 2047: #if (NGX_PCRE) ! 2048: ! 2049: if (host->len && virtual_names->nregex) { ! 2050: ngx_int_t n; ! 2051: ngx_uint_t i; ! 2052: ngx_http_server_name_t *sn; ! 2053: ! 2054: sn = virtual_names->regex; ! 2055: ! 2056: #if (NGX_HTTP_SSL && defined SSL_CTRL_SET_TLSEXT_HOSTNAME) ! 2057: ! 2058: if (r == NULL) { ! 2059: ngx_http_connection_t *hc; ! 2060: ! 2061: for (i = 0; i < virtual_names->nregex; i++) { ! 2062: ! 2063: n = ngx_regex_exec(sn[i].regex->regex, host, NULL, 0); ! 2064: ! 2065: if (n == NGX_REGEX_NO_MATCHED) { ! 2066: continue; ! 2067: } ! 2068: ! 2069: if (n >= 0) { ! 2070: hc = c->data; ! 2071: hc->ssl_servername_regex = sn[i].regex; ! 2072: ! 2073: *cscfp = sn[i].server; ! 2074: return NGX_OK; ! 2075: } ! 2076: ! 2077: ngx_log_error(NGX_LOG_ALERT, c->log, 0, ! 2078: ngx_regex_exec_n " failed: %i " ! 2079: "on \"%V\" using \"%V\"", ! 2080: n, host, &sn[i].regex->name); ! 2081: ! 2082: return NGX_ERROR; ! 2083: } ! 2084: ! 2085: return NGX_DECLINED; ! 2086: } ! 2087: ! 2088: #endif /* NGX_HTTP_SSL && defined SSL_CTRL_SET_TLSEXT_HOSTNAME */ ! 2089: ! 2090: for (i = 0; i < virtual_names->nregex; i++) { ! 2091: ! 2092: n = ngx_http_regex_exec(r, sn[i].regex, host); ! 2093: ! 2094: if (n == NGX_DECLINED) { ! 2095: continue; ! 2096: } ! 2097: ! 2098: if (n == NGX_OK) { ! 2099: *cscfp = sn[i].server; ! 2100: return NGX_OK; ! 2101: } ! 2102: ! 2103: return NGX_ERROR; ! 2104: } ! 2105: } ! 2106: ! 2107: #endif /* NGX_PCRE */ ! 2108: ! 2109: return NGX_DECLINED; ! 2110: } ! 2111: ! 2112: ! 2113: static void ! 2114: ngx_http_request_handler(ngx_event_t *ev) ! 2115: { ! 2116: ngx_connection_t *c; ! 2117: ngx_http_request_t *r; ! 2118: ngx_http_log_ctx_t *ctx; ! 2119: ! 2120: c = ev->data; ! 2121: r = c->data; ! 2122: ! 2123: ctx = c->log->data; ! 2124: ctx->current_request = r; ! 2125: ! 2126: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, ! 2127: "http run request: \"%V?%V\"", &r->uri, &r->args); ! 2128: ! 2129: if (ev->write) { ! 2130: r->write_event_handler(r); ! 2131: ! 2132: } else { ! 2133: r->read_event_handler(r); ! 2134: } ! 2135: ! 2136: ngx_http_run_posted_requests(c); ! 2137: } ! 2138: ! 2139: ! 2140: void ! 2141: ngx_http_run_posted_requests(ngx_connection_t *c) ! 2142: { ! 2143: ngx_http_request_t *r; ! 2144: ngx_http_log_ctx_t *ctx; ! 2145: ngx_http_posted_request_t *pr; ! 2146: ! 2147: for ( ;; ) { ! 2148: ! 2149: if (c->destroyed) { ! 2150: return; ! 2151: } ! 2152: ! 2153: r = c->data; ! 2154: pr = r->main->posted_requests; ! 2155: ! 2156: if (pr == NULL) { ! 2157: return; ! 2158: } ! 2159: ! 2160: r->main->posted_requests = pr->next; ! 2161: ! 2162: r = pr->request; ! 2163: ! 2164: ctx = c->log->data; ! 2165: ctx->current_request = r; ! 2166: ! 2167: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, ! 2168: "http posted request: \"%V?%V\"", &r->uri, &r->args); ! 2169: ! 2170: r->write_event_handler(r); ! 2171: } ! 2172: } ! 2173: ! 2174: ! 2175: ngx_int_t ! 2176: ngx_http_post_request(ngx_http_request_t *r, ngx_http_posted_request_t *pr) ! 2177: { ! 2178: ngx_http_posted_request_t **p; ! 2179: ! 2180: if (pr == NULL) { ! 2181: pr = ngx_palloc(r->pool, sizeof(ngx_http_posted_request_t)); ! 2182: if (pr == NULL) { ! 2183: return NGX_ERROR; ! 2184: } ! 2185: } ! 2186: ! 2187: pr->request = r; ! 2188: pr->next = NULL; ! 2189: ! 2190: for (p = &r->main->posted_requests; *p; p = &(*p)->next) { /* void */ } ! 2191: ! 2192: *p = pr; ! 2193: ! 2194: return NGX_OK; ! 2195: } ! 2196: ! 2197: ! 2198: void ! 2199: ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc) ! 2200: { ! 2201: ngx_connection_t *c; ! 2202: ngx_http_request_t *pr; ! 2203: ngx_http_core_loc_conf_t *clcf; ! 2204: ! 2205: c = r->connection; ! 2206: ! 2207: ngx_log_debug5(NGX_LOG_DEBUG_HTTP, c->log, 0, ! 2208: "http finalize request: %d, \"%V?%V\" a:%d, c:%d", ! 2209: rc, &r->uri, &r->args, r == c->data, r->main->count); ! 2210: ! 2211: if (rc == NGX_DONE) { ! 2212: ngx_http_finalize_connection(r); ! 2213: return; ! 2214: } ! 2215: ! 2216: if (rc == NGX_OK && r->filter_finalize) { ! 2217: c->error = 1; ! 2218: } ! 2219: ! 2220: if (rc == NGX_DECLINED) { ! 2221: r->content_handler = NULL; ! 2222: r->write_event_handler = ngx_http_core_run_phases; ! 2223: ngx_http_core_run_phases(r); ! 2224: return; ! 2225: } ! 2226: ! 2227: if (r != r->main && r->post_subrequest) { ! 2228: rc = r->post_subrequest->handler(r, r->post_subrequest->data, rc); ! 2229: } ! 2230: ! 2231: if (rc == NGX_ERROR ! 2232: || rc == NGX_HTTP_REQUEST_TIME_OUT ! 2233: || rc == NGX_HTTP_CLIENT_CLOSED_REQUEST ! 2234: || c->error) ! 2235: { ! 2236: if (ngx_http_post_action(r) == NGX_OK) { ! 2237: return; ! 2238: } ! 2239: ! 2240: if (r->main->blocked) { ! 2241: r->write_event_handler = ngx_http_request_finalizer; ! 2242: } ! 2243: ! 2244: ngx_http_terminate_request(r, rc); ! 2245: return; ! 2246: } ! 2247: ! 2248: if (rc >= NGX_HTTP_SPECIAL_RESPONSE ! 2249: || rc == NGX_HTTP_CREATED ! 2250: || rc == NGX_HTTP_NO_CONTENT) ! 2251: { ! 2252: if (rc == NGX_HTTP_CLOSE) { ! 2253: ngx_http_terminate_request(r, rc); ! 2254: return; ! 2255: } ! 2256: ! 2257: if (r == r->main) { ! 2258: if (c->read->timer_set) { ! 2259: ngx_del_timer(c->read); ! 2260: } ! 2261: ! 2262: if (c->write->timer_set) { ! 2263: ngx_del_timer(c->write); ! 2264: } ! 2265: } ! 2266: ! 2267: c->read->handler = ngx_http_request_handler; ! 2268: c->write->handler = ngx_http_request_handler; ! 2269: ! 2270: ngx_http_finalize_request(r, ngx_http_special_response_handler(r, rc)); ! 2271: return; ! 2272: } ! 2273: ! 2274: if (r != r->main) { ! 2275: ! 2276: if (r->buffered || r->postponed) { ! 2277: ! 2278: if (ngx_http_set_write_handler(r) != NGX_OK) { ! 2279: ngx_http_terminate_request(r, 0); ! 2280: } ! 2281: ! 2282: return; ! 2283: } ! 2284: ! 2285: pr = r->parent; ! 2286: ! 2287: if (r == c->data) { ! 2288: ! 2289: r->main->count--; ! 2290: r->main->subrequests++; ! 2291: ! 2292: if (!r->logged) { ! 2293: ! 2294: clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ! 2295: ! 2296: if (clcf->log_subrequest) { ! 2297: ngx_http_log_request(r); ! 2298: } ! 2299: ! 2300: r->logged = 1; ! 2301: ! 2302: } else { ! 2303: ngx_log_error(NGX_LOG_ALERT, c->log, 0, ! 2304: "subrequest: \"%V?%V\" logged again", ! 2305: &r->uri, &r->args); ! 2306: } ! 2307: ! 2308: r->done = 1; ! 2309: ! 2310: if (pr->postponed && pr->postponed->request == r) { ! 2311: pr->postponed = pr->postponed->next; ! 2312: } ! 2313: ! 2314: c->data = pr; ! 2315: ! 2316: } else { ! 2317: ! 2318: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, ! 2319: "http finalize non-active request: \"%V?%V\"", ! 2320: &r->uri, &r->args); ! 2321: ! 2322: r->write_event_handler = ngx_http_request_finalizer; ! 2323: ! 2324: if (r->waited) { ! 2325: r->done = 1; ! 2326: } ! 2327: } ! 2328: ! 2329: if (ngx_http_post_request(pr, NULL) != NGX_OK) { ! 2330: r->main->count++; ! 2331: ngx_http_terminate_request(r, 0); ! 2332: return; ! 2333: } ! 2334: ! 2335: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, ! 2336: "http wake parent request: \"%V?%V\"", ! 2337: &pr->uri, &pr->args); ! 2338: ! 2339: return; ! 2340: } ! 2341: ! 2342: if (r->buffered || c->buffered || r->postponed || r->blocked) { ! 2343: ! 2344: if (ngx_http_set_write_handler(r) != NGX_OK) { ! 2345: ngx_http_terminate_request(r, 0); ! 2346: } ! 2347: ! 2348: return; ! 2349: } ! 2350: ! 2351: if (r != c->data) { ! 2352: ngx_log_error(NGX_LOG_ALERT, c->log, 0, ! 2353: "http finalize non-active request: \"%V?%V\"", ! 2354: &r->uri, &r->args); ! 2355: return; ! 2356: } ! 2357: ! 2358: r->done = 1; ! 2359: r->write_event_handler = ngx_http_request_empty_handler; ! 2360: ! 2361: if (!r->post_action) { ! 2362: r->request_complete = 1; ! 2363: } ! 2364: ! 2365: if (ngx_http_post_action(r) == NGX_OK) { ! 2366: return; ! 2367: } ! 2368: ! 2369: if (c->read->timer_set) { ! 2370: ngx_del_timer(c->read); ! 2371: } ! 2372: ! 2373: if (c->write->timer_set) { ! 2374: c->write->delayed = 0; ! 2375: ngx_del_timer(c->write); ! 2376: } ! 2377: ! 2378: if (c->read->eof) { ! 2379: ngx_http_close_request(r, 0); ! 2380: return; ! 2381: } ! 2382: ! 2383: ngx_http_finalize_connection(r); ! 2384: } ! 2385: ! 2386: ! 2387: static void ! 2388: ngx_http_terminate_request(ngx_http_request_t *r, ngx_int_t rc) ! 2389: { ! 2390: ngx_http_cleanup_t *cln; ! 2391: ngx_http_request_t *mr; ! 2392: ngx_http_ephemeral_t *e; ! 2393: ! 2394: mr = r->main; ! 2395: ! 2396: ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, ! 2397: "http terminate request count:%d", mr->count); ! 2398: ! 2399: if (rc > 0 && (mr->headers_out.status == 0 || mr->connection->sent == 0)) { ! 2400: mr->headers_out.status = rc; ! 2401: } ! 2402: ! 2403: cln = mr->cleanup; ! 2404: mr->cleanup = NULL; ! 2405: ! 2406: while (cln) { ! 2407: if (cln->handler) { ! 2408: cln->handler(cln->data); ! 2409: } ! 2410: ! 2411: cln = cln->next; ! 2412: } ! 2413: ! 2414: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, ! 2415: "http terminate cleanup count:%d blk:%d", ! 2416: mr->count, mr->blocked); ! 2417: ! 2418: if (mr->write_event_handler) { ! 2419: ! 2420: if (mr->blocked) { ! 2421: return; ! 2422: } ! 2423: ! 2424: e = ngx_http_ephemeral(mr); ! 2425: mr->posted_requests = NULL; ! 2426: mr->write_event_handler = ngx_http_terminate_handler; ! 2427: (void) ngx_http_post_request(mr, &e->terminal_posted_request); ! 2428: return; ! 2429: } ! 2430: ! 2431: ngx_http_close_request(mr, rc); ! 2432: } ! 2433: ! 2434: ! 2435: static void ! 2436: ngx_http_terminate_handler(ngx_http_request_t *r) ! 2437: { ! 2438: ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, ! 2439: "http terminate handler count:%d", r->count); ! 2440: ! 2441: r->count = 1; ! 2442: ! 2443: ngx_http_close_request(r, 0); ! 2444: } ! 2445: ! 2446: ! 2447: static void ! 2448: ngx_http_finalize_connection(ngx_http_request_t *r) ! 2449: { ! 2450: ngx_http_core_loc_conf_t *clcf; ! 2451: ! 2452: #if (NGX_HTTP_SPDY) ! 2453: if (r->spdy_stream) { ! 2454: ngx_http_close_request(r, 0); ! 2455: return; ! 2456: } ! 2457: #endif ! 2458: ! 2459: clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ! 2460: ! 2461: if (r->main->count != 1) { ! 2462: ! 2463: if (r->discard_body) { ! 2464: r->read_event_handler = ngx_http_discarded_request_body_handler; ! 2465: ngx_add_timer(r->connection->read, clcf->lingering_timeout); ! 2466: ! 2467: if (r->lingering_time == 0) { ! 2468: r->lingering_time = ngx_time() ! 2469: + (time_t) (clcf->lingering_time / 1000); ! 2470: } ! 2471: } ! 2472: ! 2473: ngx_http_close_request(r, 0); ! 2474: return; ! 2475: } ! 2476: ! 2477: if (!ngx_terminate ! 2478: && !ngx_exiting ! 2479: && r->keepalive ! 2480: && clcf->keepalive_timeout > 0) ! 2481: { ! 2482: ngx_http_set_keepalive(r); ! 2483: return; ! 2484: } ! 2485: ! 2486: if (clcf->lingering_close == NGX_HTTP_LINGERING_ALWAYS ! 2487: || (clcf->lingering_close == NGX_HTTP_LINGERING_ON ! 2488: && (r->lingering_close ! 2489: || r->header_in->pos < r->header_in->last ! 2490: || r->connection->read->ready))) ! 2491: { ! 2492: ngx_http_set_lingering_close(r); ! 2493: return; ! 2494: } ! 2495: ! 2496: ngx_http_close_request(r, 0); ! 2497: } ! 2498: ! 2499: ! 2500: static ngx_int_t ! 2501: ngx_http_set_write_handler(ngx_http_request_t *r) ! 2502: { ! 2503: ngx_event_t *wev; ! 2504: ngx_http_core_loc_conf_t *clcf; ! 2505: ! 2506: r->http_state = NGX_HTTP_WRITING_REQUEST_STATE; ! 2507: ! 2508: r->read_event_handler = r->discard_body ? ! 2509: ngx_http_discarded_request_body_handler: ! 2510: ngx_http_test_reading; ! 2511: r->write_event_handler = ngx_http_writer; ! 2512: ! 2513: #if (NGX_HTTP_SPDY) ! 2514: if (r->spdy_stream) { ! 2515: return NGX_OK; ! 2516: } ! 2517: #endif ! 2518: ! 2519: wev = r->connection->write; ! 2520: ! 2521: if (wev->ready && wev->delayed) { ! 2522: return NGX_OK; ! 2523: } ! 2524: ! 2525: clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ! 2526: if (!wev->delayed) { ! 2527: ngx_add_timer(wev, clcf->send_timeout); ! 2528: } ! 2529: ! 2530: if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) { ! 2531: ngx_http_close_request(r, 0); ! 2532: return NGX_ERROR; ! 2533: } ! 2534: ! 2535: return NGX_OK; ! 2536: } ! 2537: ! 2538: ! 2539: static void ! 2540: ngx_http_writer(ngx_http_request_t *r) ! 2541: { ! 2542: int rc; ! 2543: ngx_event_t *wev; ! 2544: ngx_connection_t *c; ! 2545: ngx_http_core_loc_conf_t *clcf; ! 2546: ! 2547: c = r->connection; ! 2548: wev = c->write; ! 2549: ! 2550: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, wev->log, 0, ! 2551: "http writer handler: \"%V?%V\"", &r->uri, &r->args); ! 2552: ! 2553: clcf = ngx_http_get_module_loc_conf(r->main, ngx_http_core_module); ! 2554: ! 2555: if (wev->timedout) { ! 2556: if (!wev->delayed) { ! 2557: ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, ! 2558: "client timed out"); ! 2559: c->timedout = 1; ! 2560: ! 2561: ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT); ! 2562: return; ! 2563: } ! 2564: ! 2565: wev->timedout = 0; ! 2566: wev->delayed = 0; ! 2567: ! 2568: if (!wev->ready) { ! 2569: ngx_add_timer(wev, clcf->send_timeout); ! 2570: ! 2571: if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) { ! 2572: ngx_http_close_request(r, 0); ! 2573: } ! 2574: ! 2575: return; ! 2576: } ! 2577: ! 2578: } ! 2579: ! 2580: if (wev->delayed || r->aio) { ! 2581: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0, ! 2582: "http writer delayed"); ! 2583: ! 2584: if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) { ! 2585: ngx_http_close_request(r, 0); ! 2586: } ! 2587: ! 2588: return; ! 2589: } ! 2590: ! 2591: rc = ngx_http_output_filter(r, NULL); ! 2592: ! 2593: ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, ! 2594: "http writer output filter: %d, \"%V?%V\"", ! 2595: rc, &r->uri, &r->args); ! 2596: ! 2597: if (rc == NGX_ERROR) { ! 2598: ngx_http_finalize_request(r, rc); ! 2599: return; ! 2600: } ! 2601: ! 2602: if (r->buffered || r->postponed || (r == r->main && c->buffered)) { ! 2603: ! 2604: if (!wev->delayed) { ! 2605: ngx_add_timer(wev, clcf->send_timeout); ! 2606: } ! 2607: ! 2608: if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) { ! 2609: ngx_http_close_request(r, 0); ! 2610: } ! 2611: ! 2612: return; ! 2613: } ! 2614: ! 2615: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, wev->log, 0, ! 2616: "http writer done: \"%V?%V\"", &r->uri, &r->args); ! 2617: ! 2618: r->write_event_handler = ngx_http_request_empty_handler; ! 2619: ! 2620: ngx_http_finalize_request(r, rc); ! 2621: } ! 2622: ! 2623: ! 2624: static void ! 2625: ngx_http_request_finalizer(ngx_http_request_t *r) ! 2626: { ! 2627: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, ! 2628: "http finalizer done: \"%V?%V\"", &r->uri, &r->args); ! 2629: ! 2630: ngx_http_finalize_request(r, 0); ! 2631: } ! 2632: ! 2633: ! 2634: void ! 2635: ngx_http_block_reading(ngx_http_request_t *r) ! 2636: { ! 2637: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, ! 2638: "http reading blocked"); ! 2639: ! 2640: /* aio does not call this handler */ ! 2641: ! 2642: if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) ! 2643: && r->connection->read->active) ! 2644: { ! 2645: if (ngx_del_event(r->connection->read, NGX_READ_EVENT, 0) != NGX_OK) { ! 2646: ngx_http_close_request(r, 0); ! 2647: } ! 2648: } ! 2649: } ! 2650: ! 2651: ! 2652: void ! 2653: ngx_http_test_reading(ngx_http_request_t *r) ! 2654: { ! 2655: int n; ! 2656: char buf[1]; ! 2657: ngx_err_t err; ! 2658: ngx_event_t *rev; ! 2659: ngx_connection_t *c; ! 2660: ! 2661: c = r->connection; ! 2662: rev = c->read; ! 2663: ! 2664: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http test reading"); ! 2665: ! 2666: #if (NGX_HTTP_SPDY) ! 2667: ! 2668: if (r->spdy_stream) { ! 2669: if (c->error) { ! 2670: err = 0; ! 2671: goto closed; ! 2672: } ! 2673: ! 2674: return; ! 2675: } ! 2676: ! 2677: #endif ! 2678: ! 2679: #if (NGX_HAVE_KQUEUE) ! 2680: ! 2681: if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { ! 2682: ! 2683: if (!rev->pending_eof) { ! 2684: return; ! 2685: } ! 2686: ! 2687: rev->eof = 1; ! 2688: c->error = 1; ! 2689: err = rev->kq_errno; ! 2690: ! 2691: goto closed; ! 2692: } ! 2693: ! 2694: #endif ! 2695: ! 2696: n = recv(c->fd, buf, 1, MSG_PEEK); ! 2697: ! 2698: if (n == 0) { ! 2699: rev->eof = 1; ! 2700: c->error = 1; ! 2701: err = 0; ! 2702: ! 2703: goto closed; ! 2704: ! 2705: } else if (n == -1) { ! 2706: err = ngx_socket_errno; ! 2707: ! 2708: if (err != NGX_EAGAIN) { ! 2709: rev->eof = 1; ! 2710: c->error = 1; ! 2711: ! 2712: goto closed; ! 2713: } ! 2714: } ! 2715: ! 2716: /* aio does not call this handler */ ! 2717: ! 2718: if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && rev->active) { ! 2719: ! 2720: if (ngx_del_event(rev, NGX_READ_EVENT, 0) != NGX_OK) { ! 2721: ngx_http_close_request(r, 0); ! 2722: } ! 2723: } ! 2724: ! 2725: return; ! 2726: ! 2727: closed: ! 2728: ! 2729: if (err) { ! 2730: rev->error = 1; ! 2731: } ! 2732: ! 2733: ngx_log_error(NGX_LOG_INFO, c->log, err, ! 2734: "client prematurely closed connection"); ! 2735: ! 2736: ngx_http_finalize_request(r, 0); ! 2737: } ! 2738: ! 2739: ! 2740: static void ! 2741: ngx_http_set_keepalive(ngx_http_request_t *r) ! 2742: { ! 2743: int tcp_nodelay; ! 2744: ngx_int_t i; ! 2745: ngx_buf_t *b, *f; ! 2746: ngx_event_t *rev, *wev; ! 2747: ngx_connection_t *c; ! 2748: ngx_http_connection_t *hc; ! 2749: ngx_http_core_srv_conf_t *cscf; ! 2750: ngx_http_core_loc_conf_t *clcf; ! 2751: ! 2752: c = r->connection; ! 2753: rev = c->read; ! 2754: ! 2755: clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ! 2756: ! 2757: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "set http keepalive handler"); ! 2758: ! 2759: if (r->discard_body) { ! 2760: r->write_event_handler = ngx_http_request_empty_handler; ! 2761: r->lingering_time = ngx_time() + (time_t) (clcf->lingering_time / 1000); ! 2762: ngx_add_timer(rev, clcf->lingering_timeout); ! 2763: return; ! 2764: } ! 2765: ! 2766: c->log->action = "closing request"; ! 2767: ! 2768: hc = r->http_connection; ! 2769: b = r->header_in; ! 2770: ! 2771: if (b->pos < b->last) { ! 2772: ! 2773: /* the pipelined request */ ! 2774: ! 2775: if (b != c->buffer) { ! 2776: ! 2777: /* ! 2778: * If the large header buffers were allocated while the previous ! 2779: * request processing then we do not use c->buffer for ! 2780: * the pipelined request (see ngx_http_create_request()). ! 2781: * ! 2782: * Now we would move the large header buffers to the free list. ! 2783: */ ! 2784: ! 2785: cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); ! 2786: ! 2787: if (hc->free == NULL) { ! 2788: hc->free = ngx_palloc(c->pool, ! 2789: cscf->large_client_header_buffers.num * sizeof(ngx_buf_t *)); ! 2790: ! 2791: if (hc->free == NULL) { ! 2792: ngx_http_close_request(r, 0); ! 2793: return; ! 2794: } ! 2795: } ! 2796: ! 2797: for (i = 0; i < hc->nbusy - 1; i++) { ! 2798: f = hc->busy[i]; ! 2799: hc->free[hc->nfree++] = f; ! 2800: f->pos = f->start; ! 2801: f->last = f->start; ! 2802: } ! 2803: ! 2804: hc->busy[0] = b; ! 2805: hc->nbusy = 1; ! 2806: } ! 2807: } ! 2808: ! 2809: /* guard against recursive call from ngx_http_finalize_connection() */ ! 2810: r->keepalive = 0; ! 2811: ! 2812: ngx_http_free_request(r, 0); ! 2813: ! 2814: c->data = hc; ! 2815: ! 2816: if (ngx_handle_read_event(rev, 0) != NGX_OK) { ! 2817: ngx_http_close_connection(c); ! 2818: return; ! 2819: } ! 2820: ! 2821: wev = c->write; ! 2822: wev->handler = ngx_http_empty_handler; ! 2823: ! 2824: if (b->pos < b->last) { ! 2825: ! 2826: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "pipelined request"); ! 2827: ! 2828: c->log->action = "reading client pipelined request line"; ! 2829: ! 2830: r = ngx_http_create_request(c); ! 2831: if (r == NULL) { ! 2832: ngx_http_close_connection(c); ! 2833: return; ! 2834: } ! 2835: ! 2836: r->pipeline = 1; ! 2837: ! 2838: c->data = r; ! 2839: ! 2840: c->sent = 0; ! 2841: c->destroyed = 0; ! 2842: ! 2843: if (rev->timer_set) { ! 2844: ngx_del_timer(rev); ! 2845: } ! 2846: ! 2847: rev->handler = ngx_http_process_request_line; ! 2848: ngx_post_event(rev, &ngx_posted_events); ! 2849: return; ! 2850: } ! 2851: ! 2852: /* ! 2853: * To keep a memory footprint as small as possible for an idle keepalive ! 2854: * connection we try to free c->buffer's memory if it was allocated outside ! 2855: * the c->pool. The large header buffers are always allocated outside the ! 2856: * c->pool and are freed too. ! 2857: */ ! 2858: ! 2859: b = c->buffer; ! 2860: ! 2861: if (ngx_pfree(c->pool, b->start) == NGX_OK) { ! 2862: ! 2863: /* ! 2864: * the special note for ngx_http_keepalive_handler() that ! 2865: * c->buffer's memory was freed ! 2866: */ ! 2867: ! 2868: b->pos = NULL; ! 2869: ! 2870: } else { ! 2871: b->pos = b->start; ! 2872: b->last = b->start; ! 2873: } ! 2874: ! 2875: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "hc free: %p %d", ! 2876: hc->free, hc->nfree); ! 2877: ! 2878: if (hc->free) { ! 2879: for (i = 0; i < hc->nfree; i++) { ! 2880: ngx_pfree(c->pool, hc->free[i]->start); ! 2881: hc->free[i] = NULL; ! 2882: } ! 2883: ! 2884: hc->nfree = 0; ! 2885: } ! 2886: ! 2887: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "hc busy: %p %d", ! 2888: hc->busy, hc->nbusy); ! 2889: ! 2890: if (hc->busy) { ! 2891: for (i = 0; i < hc->nbusy; i++) { ! 2892: ngx_pfree(c->pool, hc->busy[i]->start); ! 2893: hc->busy[i] = NULL; ! 2894: } ! 2895: ! 2896: hc->nbusy = 0; ! 2897: } ! 2898: ! 2899: #if (NGX_HTTP_SSL) ! 2900: if (c->ssl) { ! 2901: ngx_ssl_free_buffer(c); ! 2902: } ! 2903: #endif ! 2904: ! 2905: rev->handler = ngx_http_keepalive_handler; ! 2906: ! 2907: if (wev->active && (ngx_event_flags & NGX_USE_LEVEL_EVENT)) { ! 2908: if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) != NGX_OK) { ! 2909: ngx_http_close_connection(c); ! 2910: return; ! 2911: } ! 2912: } ! 2913: ! 2914: c->log->action = "keepalive"; ! 2915: ! 2916: if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) { ! 2917: if (ngx_tcp_push(c->fd) == -1) { ! 2918: ngx_connection_error(c, ngx_socket_errno, ngx_tcp_push_n " failed"); ! 2919: ngx_http_close_connection(c); ! 2920: return; ! 2921: } ! 2922: ! 2923: c->tcp_nopush = NGX_TCP_NOPUSH_UNSET; ! 2924: tcp_nodelay = ngx_tcp_nodelay_and_tcp_nopush ? 1 : 0; ! 2925: ! 2926: } else { ! 2927: tcp_nodelay = 1; ! 2928: } ! 2929: ! 2930: if (tcp_nodelay ! 2931: && clcf->tcp_nodelay ! 2932: && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) ! 2933: { ! 2934: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay"); ! 2935: ! 2936: if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, ! 2937: (const void *) &tcp_nodelay, sizeof(int)) ! 2938: == -1) ! 2939: { ! 2940: #if (NGX_SOLARIS) ! 2941: /* Solaris returns EINVAL if a socket has been shut down */ ! 2942: c->log_error = NGX_ERROR_IGNORE_EINVAL; ! 2943: #endif ! 2944: ! 2945: ngx_connection_error(c, ngx_socket_errno, ! 2946: "setsockopt(TCP_NODELAY) failed"); ! 2947: ! 2948: c->log_error = NGX_ERROR_INFO; ! 2949: ngx_http_close_connection(c); ! 2950: return; ! 2951: } ! 2952: ! 2953: c->tcp_nodelay = NGX_TCP_NODELAY_SET; ! 2954: } ! 2955: ! 2956: #if 0 ! 2957: /* if ngx_http_request_t was freed then we need some other place */ ! 2958: r->http_state = NGX_HTTP_KEEPALIVE_STATE; ! 2959: #endif ! 2960: ! 2961: c->idle = 1; ! 2962: ngx_reusable_connection(c, 1); ! 2963: ! 2964: ngx_add_timer(rev, clcf->keepalive_timeout); ! 2965: ! 2966: if (rev->ready) { ! 2967: ngx_post_event(rev, &ngx_posted_events); ! 2968: } ! 2969: } ! 2970: ! 2971: ! 2972: static void ! 2973: ngx_http_keepalive_handler(ngx_event_t *rev) ! 2974: { ! 2975: size_t size; ! 2976: ssize_t n; ! 2977: ngx_buf_t *b; ! 2978: ngx_connection_t *c; ! 2979: ! 2980: c = rev->data; ! 2981: ! 2982: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http keepalive handler"); ! 2983: ! 2984: if (rev->timedout || c->close) { ! 2985: ngx_http_close_connection(c); ! 2986: return; ! 2987: } ! 2988: ! 2989: #if (NGX_HAVE_KQUEUE) ! 2990: ! 2991: if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { ! 2992: if (rev->pending_eof) { ! 2993: c->log->handler = NULL; ! 2994: ngx_log_error(NGX_LOG_INFO, c->log, rev->kq_errno, ! 2995: "kevent() reported that client %V closed " ! 2996: "keepalive connection", &c->addr_text); ! 2997: #if (NGX_HTTP_SSL) ! 2998: if (c->ssl) { ! 2999: c->ssl->no_send_shutdown = 1; ! 3000: } ! 3001: #endif ! 3002: ngx_http_close_connection(c); ! 3003: return; ! 3004: } ! 3005: } ! 3006: ! 3007: #endif ! 3008: ! 3009: b = c->buffer; ! 3010: size = b->end - b->start; ! 3011: ! 3012: if (b->pos == NULL) { ! 3013: ! 3014: /* ! 3015: * The c->buffer's memory was freed by ngx_http_set_keepalive(). ! 3016: * However, the c->buffer->start and c->buffer->end were not changed ! 3017: * to keep the buffer size. ! 3018: */ ! 3019: ! 3020: b->pos = ngx_palloc(c->pool, size); ! 3021: if (b->pos == NULL) { ! 3022: ngx_http_close_connection(c); ! 3023: return; ! 3024: } ! 3025: ! 3026: b->start = b->pos; ! 3027: b->last = b->pos; ! 3028: b->end = b->pos + size; ! 3029: } ! 3030: ! 3031: /* ! 3032: * MSIE closes a keepalive connection with RST flag ! 3033: * so we ignore ECONNRESET here. ! 3034: */ ! 3035: ! 3036: c->log_error = NGX_ERROR_IGNORE_ECONNRESET; ! 3037: ngx_set_socket_errno(0); ! 3038: ! 3039: n = c->recv(c, b->last, size); ! 3040: c->log_error = NGX_ERROR_INFO; ! 3041: ! 3042: if (n == NGX_AGAIN) { ! 3043: if (ngx_handle_read_event(rev, 0) != NGX_OK) { ! 3044: ngx_http_close_connection(c); ! 3045: return; ! 3046: } ! 3047: ! 3048: /* ! 3049: * Like ngx_http_set_keepalive() we are trying to not hold ! 3050: * c->buffer's memory for a keepalive connection. ! 3051: */ ! 3052: ! 3053: if (ngx_pfree(c->pool, b->start) == NGX_OK) { ! 3054: ! 3055: /* ! 3056: * the special note that c->buffer's memory was freed ! 3057: */ ! 3058: ! 3059: b->pos = NULL; ! 3060: } ! 3061: ! 3062: return; ! 3063: } ! 3064: ! 3065: if (n == NGX_ERROR) { ! 3066: ngx_http_close_connection(c); ! 3067: return; ! 3068: } ! 3069: ! 3070: c->log->handler = NULL; ! 3071: ! 3072: if (n == 0) { ! 3073: ngx_log_error(NGX_LOG_INFO, c->log, ngx_socket_errno, ! 3074: "client %V closed keepalive connection", &c->addr_text); ! 3075: ngx_http_close_connection(c); ! 3076: return; ! 3077: } ! 3078: ! 3079: b->last += n; ! 3080: ! 3081: c->log->handler = ngx_http_log_error; ! 3082: c->log->action = "reading client request line"; ! 3083: ! 3084: c->idle = 0; ! 3085: ngx_reusable_connection(c, 0); ! 3086: ! 3087: c->data = ngx_http_create_request(c); ! 3088: if (c->data == NULL) { ! 3089: ngx_http_close_connection(c); ! 3090: return; ! 3091: } ! 3092: ! 3093: c->sent = 0; ! 3094: c->destroyed = 0; ! 3095: ! 3096: ngx_del_timer(rev); ! 3097: ! 3098: rev->handler = ngx_http_process_request_line; ! 3099: ngx_http_process_request_line(rev); ! 3100: } ! 3101: ! 3102: ! 3103: static void ! 3104: ngx_http_set_lingering_close(ngx_http_request_t *r) ! 3105: { ! 3106: ngx_event_t *rev, *wev; ! 3107: ngx_connection_t *c; ! 3108: ngx_http_core_loc_conf_t *clcf; ! 3109: ! 3110: c = r->connection; ! 3111: ! 3112: clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ! 3113: ! 3114: rev = c->read; ! 3115: rev->handler = ngx_http_lingering_close_handler; ! 3116: ! 3117: r->lingering_time = ngx_time() + (time_t) (clcf->lingering_time / 1000); ! 3118: ngx_add_timer(rev, clcf->lingering_timeout); ! 3119: ! 3120: if (ngx_handle_read_event(rev, 0) != NGX_OK) { ! 3121: ngx_http_close_request(r, 0); ! 3122: return; ! 3123: } ! 3124: ! 3125: wev = c->write; ! 3126: wev->handler = ngx_http_empty_handler; ! 3127: ! 3128: if (wev->active && (ngx_event_flags & NGX_USE_LEVEL_EVENT)) { ! 3129: if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) != NGX_OK) { ! 3130: ngx_http_close_request(r, 0); ! 3131: return; ! 3132: } ! 3133: } ! 3134: ! 3135: if (ngx_shutdown_socket(c->fd, NGX_WRITE_SHUTDOWN) == -1) { ! 3136: ngx_connection_error(c, ngx_socket_errno, ! 3137: ngx_shutdown_socket_n " failed"); ! 3138: ngx_http_close_request(r, 0); ! 3139: return; ! 3140: } ! 3141: ! 3142: if (rev->ready) { ! 3143: ngx_http_lingering_close_handler(rev); ! 3144: } ! 3145: } ! 3146: ! 3147: ! 3148: static void ! 3149: ngx_http_lingering_close_handler(ngx_event_t *rev) ! 3150: { ! 3151: ssize_t n; ! 3152: ngx_msec_t timer; ! 3153: ngx_connection_t *c; ! 3154: ngx_http_request_t *r; ! 3155: ngx_http_core_loc_conf_t *clcf; ! 3156: u_char buffer[NGX_HTTP_LINGERING_BUFFER_SIZE]; ! 3157: ! 3158: c = rev->data; ! 3159: r = c->data; ! 3160: ! 3161: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, ! 3162: "http lingering close handler"); ! 3163: ! 3164: if (rev->timedout) { ! 3165: ngx_http_close_request(r, 0); ! 3166: return; ! 3167: } ! 3168: ! 3169: timer = (ngx_msec_t) (r->lingering_time - ngx_time()); ! 3170: if (timer <= 0) { ! 3171: ngx_http_close_request(r, 0); ! 3172: return; ! 3173: } ! 3174: ! 3175: do { ! 3176: n = c->recv(c, buffer, NGX_HTTP_LINGERING_BUFFER_SIZE); ! 3177: ! 3178: ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "lingering read: %d", n); ! 3179: ! 3180: if (n == NGX_ERROR || n == 0) { ! 3181: ngx_http_close_request(r, 0); ! 3182: return; ! 3183: } ! 3184: ! 3185: } while (rev->ready); ! 3186: ! 3187: if (ngx_handle_read_event(rev, 0) != NGX_OK) { ! 3188: ngx_http_close_request(r, 0); ! 3189: return; ! 3190: } ! 3191: ! 3192: clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ! 3193: ! 3194: timer *= 1000; ! 3195: ! 3196: if (timer > clcf->lingering_timeout) { ! 3197: timer = clcf->lingering_timeout; ! 3198: } ! 3199: ! 3200: ngx_add_timer(rev, timer); ! 3201: } ! 3202: ! 3203: ! 3204: void ! 3205: ngx_http_empty_handler(ngx_event_t *wev) ! 3206: { ! 3207: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0, "http empty handler"); ! 3208: ! 3209: return; ! 3210: } ! 3211: ! 3212: ! 3213: void ! 3214: ngx_http_request_empty_handler(ngx_http_request_t *r) ! 3215: { ! 3216: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, ! 3217: "http request empty handler"); ! 3218: ! 3219: return; ! 3220: } ! 3221: ! 3222: ! 3223: ngx_int_t ! 3224: ngx_http_send_special(ngx_http_request_t *r, ngx_uint_t flags) ! 3225: { ! 3226: ngx_buf_t *b; ! 3227: ngx_chain_t out; ! 3228: ! 3229: b = ngx_calloc_buf(r->pool); ! 3230: if (b == NULL) { ! 3231: return NGX_ERROR; ! 3232: } ! 3233: ! 3234: if (flags & NGX_HTTP_LAST) { ! 3235: ! 3236: if (r == r->main && !r->post_action) { ! 3237: b->last_buf = 1; ! 3238: ! 3239: } else { ! 3240: b->sync = 1; ! 3241: b->last_in_chain = 1; ! 3242: } ! 3243: } ! 3244: ! 3245: if (flags & NGX_HTTP_FLUSH) { ! 3246: b->flush = 1; ! 3247: } ! 3248: ! 3249: out.buf = b; ! 3250: out.next = NULL; ! 3251: ! 3252: return ngx_http_output_filter(r, &out); ! 3253: } ! 3254: ! 3255: ! 3256: static ngx_int_t ! 3257: ngx_http_post_action(ngx_http_request_t *r) ! 3258: { ! 3259: ngx_http_core_loc_conf_t *clcf; ! 3260: ! 3261: clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ! 3262: ! 3263: if (clcf->post_action.data == NULL) { ! 3264: return NGX_DECLINED; ! 3265: } ! 3266: ! 3267: if (r->post_action && r->uri_changes == 0) { ! 3268: return NGX_DECLINED; ! 3269: } ! 3270: ! 3271: ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, ! 3272: "post action: \"%V\"", &clcf->post_action); ! 3273: ! 3274: r->main->count--; ! 3275: ! 3276: r->http_version = NGX_HTTP_VERSION_9; ! 3277: r->header_only = 1; ! 3278: r->post_action = 1; ! 3279: ! 3280: r->read_event_handler = ngx_http_block_reading; ! 3281: ! 3282: if (clcf->post_action.data[0] == '/') { ! 3283: ngx_http_internal_redirect(r, &clcf->post_action, NULL); ! 3284: ! 3285: } else { ! 3286: ngx_http_named_location(r, &clcf->post_action); ! 3287: } ! 3288: ! 3289: return NGX_OK; ! 3290: } ! 3291: ! 3292: ! 3293: static void ! 3294: ngx_http_close_request(ngx_http_request_t *r, ngx_int_t rc) ! 3295: { ! 3296: ngx_connection_t *c; ! 3297: ! 3298: r = r->main; ! 3299: c = r->connection; ! 3300: ! 3301: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, ! 3302: "http request count:%d blk:%d", r->count, r->blocked); ! 3303: ! 3304: if (r->count == 0) { ! 3305: ngx_log_error(NGX_LOG_ALERT, c->log, 0, "http request count is zero"); ! 3306: } ! 3307: ! 3308: r->count--; ! 3309: ! 3310: if (r->count || r->blocked) { ! 3311: return; ! 3312: } ! 3313: ! 3314: #if (NGX_HTTP_SPDY) ! 3315: if (r->spdy_stream) { ! 3316: ngx_http_spdy_close_stream(r->spdy_stream, rc); ! 3317: return; ! 3318: } ! 3319: #endif ! 3320: ! 3321: ngx_http_free_request(r, rc); ! 3322: ngx_http_close_connection(c); ! 3323: } ! 3324: ! 3325: ! 3326: void ! 3327: ngx_http_free_request(ngx_http_request_t *r, ngx_int_t rc) ! 3328: { ! 3329: ngx_log_t *log; ! 3330: ngx_pool_t *pool; ! 3331: struct linger linger; ! 3332: ngx_http_cleanup_t *cln; ! 3333: ngx_http_log_ctx_t *ctx; ! 3334: ngx_http_core_loc_conf_t *clcf; ! 3335: ! 3336: log = r->connection->log; ! 3337: ! 3338: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http close request"); ! 3339: ! 3340: if (r->pool == NULL) { ! 3341: ngx_log_error(NGX_LOG_ALERT, log, 0, "http request already closed"); ! 3342: return; ! 3343: } ! 3344: ! 3345: for (cln = r->cleanup; cln; cln = cln->next) { ! 3346: if (cln->handler) { ! 3347: cln->handler(cln->data); ! 3348: } ! 3349: } ! 3350: ! 3351: #if (NGX_STAT_STUB) ! 3352: ! 3353: if (r->stat_reading) { ! 3354: (void) ngx_atomic_fetch_add(ngx_stat_reading, -1); ! 3355: } ! 3356: ! 3357: if (r->stat_writing) { ! 3358: (void) ngx_atomic_fetch_add(ngx_stat_writing, -1); ! 3359: } ! 3360: ! 3361: #endif ! 3362: ! 3363: if (rc > 0 && (r->headers_out.status == 0 || r->connection->sent == 0)) { ! 3364: r->headers_out.status = rc; ! 3365: } ! 3366: ! 3367: log->action = "logging request"; ! 3368: ! 3369: ngx_http_log_request(r); ! 3370: ! 3371: log->action = "closing request"; ! 3372: ! 3373: if (r->connection->timedout) { ! 3374: clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ! 3375: ! 3376: if (clcf->reset_timedout_connection) { ! 3377: linger.l_onoff = 1; ! 3378: linger.l_linger = 0; ! 3379: ! 3380: if (setsockopt(r->connection->fd, SOL_SOCKET, SO_LINGER, ! 3381: (const void *) &linger, sizeof(struct linger)) == -1) ! 3382: { ! 3383: ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno, ! 3384: "setsockopt(SO_LINGER) failed"); ! 3385: } ! 3386: } ! 3387: } ! 3388: ! 3389: /* the various request strings were allocated from r->pool */ ! 3390: ctx = log->data; ! 3391: ctx->request = NULL; ! 3392: ! 3393: r->request_line.len = 0; ! 3394: ! 3395: r->connection->destroyed = 1; ! 3396: ! 3397: /* ! 3398: * Setting r->pool to NULL will increase probability to catch double close ! 3399: * of request since the request object is allocated from its own pool. ! 3400: */ ! 3401: ! 3402: pool = r->pool; ! 3403: r->pool = NULL; ! 3404: ! 3405: ngx_destroy_pool(pool); ! 3406: } ! 3407: ! 3408: ! 3409: static void ! 3410: ngx_http_log_request(ngx_http_request_t *r) ! 3411: { ! 3412: ngx_uint_t i, n; ! 3413: ngx_http_handler_pt *log_handler; ! 3414: ngx_http_core_main_conf_t *cmcf; ! 3415: ! 3416: cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); ! 3417: ! 3418: log_handler = cmcf->phases[NGX_HTTP_LOG_PHASE].handlers.elts; ! 3419: n = cmcf->phases[NGX_HTTP_LOG_PHASE].handlers.nelts; ! 3420: ! 3421: for (i = 0; i < n; i++) { ! 3422: log_handler[i](r); ! 3423: } ! 3424: } ! 3425: ! 3426: ! 3427: void ! 3428: ngx_http_close_connection(ngx_connection_t *c) ! 3429: { ! 3430: ngx_pool_t *pool; ! 3431: ! 3432: ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, ! 3433: "close http connection: %d", c->fd); ! 3434: ! 3435: #if (NGX_HTTP_SSL) ! 3436: ! 3437: if (c->ssl) { ! 3438: if (ngx_ssl_shutdown(c) == NGX_AGAIN) { ! 3439: c->ssl->handler = ngx_http_close_connection; ! 3440: return; ! 3441: } ! 3442: } ! 3443: ! 3444: #endif ! 3445: ! 3446: #if (NGX_STAT_STUB) ! 3447: (void) ngx_atomic_fetch_add(ngx_stat_active, -1); ! 3448: #endif ! 3449: ! 3450: c->destroyed = 1; ! 3451: ! 3452: pool = c->pool; ! 3453: ! 3454: ngx_close_connection(c); ! 3455: ! 3456: ngx_destroy_pool(pool); ! 3457: } ! 3458: ! 3459: ! 3460: static u_char * ! 3461: ngx_http_log_error(ngx_log_t *log, u_char *buf, size_t len) ! 3462: { ! 3463: u_char *p; ! 3464: ngx_http_request_t *r; ! 3465: ngx_http_log_ctx_t *ctx; ! 3466: ! 3467: if (log->action) { ! 3468: p = ngx_snprintf(buf, len, " while %s", log->action); ! 3469: len -= p - buf; ! 3470: buf = p; ! 3471: } ! 3472: ! 3473: ctx = log->data; ! 3474: ! 3475: p = ngx_snprintf(buf, len, ", client: %V", &ctx->connection->addr_text); ! 3476: len -= p - buf; ! 3477: ! 3478: r = ctx->request; ! 3479: ! 3480: if (r) { ! 3481: return r->log_handler(r, ctx->current_request, p, len); ! 3482: ! 3483: } else { ! 3484: p = ngx_snprintf(p, len, ", server: %V", ! 3485: &ctx->connection->listening->addr_text); ! 3486: } ! 3487: ! 3488: return p; ! 3489: } ! 3490: ! 3491: ! 3492: static u_char * ! 3493: ngx_http_log_error_handler(ngx_http_request_t *r, ngx_http_request_t *sr, ! 3494: u_char *buf, size_t len) ! 3495: { ! 3496: char *uri_separator; ! 3497: u_char *p; ! 3498: ngx_http_upstream_t *u; ! 3499: ngx_http_core_srv_conf_t *cscf; ! 3500: ! 3501: cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); ! 3502: ! 3503: p = ngx_snprintf(buf, len, ", server: %V", &cscf->server_name); ! 3504: len -= p - buf; ! 3505: buf = p; ! 3506: ! 3507: if (r->request_line.data == NULL && r->request_start) { ! 3508: for (p = r->request_start; p < r->header_in->last; p++) { ! 3509: if (*p == CR || *p == LF) { ! 3510: break; ! 3511: } ! 3512: } ! 3513: ! 3514: r->request_line.len = p - r->request_start; ! 3515: r->request_line.data = r->request_start; ! 3516: } ! 3517: ! 3518: if (r->request_line.len) { ! 3519: p = ngx_snprintf(buf, len, ", request: \"%V\"", &r->request_line); ! 3520: len -= p - buf; ! 3521: buf = p; ! 3522: } ! 3523: ! 3524: if (r != sr) { ! 3525: p = ngx_snprintf(buf, len, ", subrequest: \"%V\"", &sr->uri); ! 3526: len -= p - buf; ! 3527: buf = p; ! 3528: } ! 3529: ! 3530: u = sr->upstream; ! 3531: ! 3532: if (u && u->peer.name) { ! 3533: ! 3534: uri_separator = ""; ! 3535: ! 3536: #if (NGX_HAVE_UNIX_DOMAIN) ! 3537: if (u->peer.sockaddr && u->peer.sockaddr->sa_family == AF_UNIX) { ! 3538: uri_separator = ":"; ! 3539: } ! 3540: #endif ! 3541: ! 3542: p = ngx_snprintf(buf, len, ", upstream: \"%V%V%s%V\"", ! 3543: &u->schema, u->peer.name, ! 3544: uri_separator, &u->uri); ! 3545: len -= p - buf; ! 3546: buf = p; ! 3547: } ! 3548: ! 3549: if (r->headers_in.host) { ! 3550: p = ngx_snprintf(buf, len, ", host: \"%V\"", ! 3551: &r->headers_in.host->value); ! 3552: len -= p - buf; ! 3553: buf = p; ! 3554: } ! 3555: ! 3556: if (r->headers_in.referer) { ! 3557: p = ngx_snprintf(buf, len, ", referrer: \"%V\"", ! 3558: &r->headers_in.referer->value); ! 3559: buf = p; ! 3560: } ! 3561: ! 3562: return buf; ! 3563: }