diff options
Diffstat (limited to 'usr.sbin/nginx/src/http/ngx_http_upstream.c')
| -rw-r--r-- | usr.sbin/nginx/src/http/ngx_http_upstream.c | 404 |
1 files changed, 290 insertions, 114 deletions
diff --git a/usr.sbin/nginx/src/http/ngx_http_upstream.c b/usr.sbin/nginx/src/http/ngx_http_upstream.c index d99d8545488..040bda10623 100644 --- a/usr.sbin/nginx/src/http/ngx_http_upstream.c +++ b/usr.sbin/nginx/src/http/ngx_http_upstream.c @@ -17,6 +17,8 @@ static ngx_int_t ngx_http_upstream_cache_send(ngx_http_request_t *r, ngx_http_upstream_t *u); static ngx_int_t ngx_http_upstream_cache_status(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_upstream_cache_last_modified(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); #endif static void ngx_http_upstream_init_request(ngx_http_request_t *r); @@ -358,6 +360,10 @@ static ngx_http_variable_t ngx_http_upstream_vars[] = { ngx_http_upstream_cache_status, 0, NGX_HTTP_VAR_NOCACHEABLE, 0 }, + { ngx_string("upstream_cache_last_modified"), NULL, + ngx_http_upstream_cache_last_modified, 0, + NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, + #endif { ngx_null_string, NULL, NULL, 0, 0, 0 } @@ -369,6 +375,7 @@ static ngx_http_upstream_next_t ngx_http_upstream_next_errors[] = { { 502, NGX_HTTP_UPSTREAM_FT_HTTP_502 }, { 503, NGX_HTTP_UPSTREAM_FT_HTTP_503 }, { 504, NGX_HTTP_UPSTREAM_FT_HTTP_504 }, + { 403, NGX_HTTP_UPSTREAM_FT_HTTP_403 }, { 404, NGX_HTTP_UPSTREAM_FT_HTTP_404 }, { 0, 0 } }; @@ -605,7 +612,7 @@ ngx_http_upstream_init_request(ngx_http_request_t *r) if (uscf->host.len == host->len && ((uscf->port == 0 && u->resolved->no_port) || uscf->port == u->resolved->port) - && ngx_memcmp(uscf->host.data, host->data, host->len) == 0) + && ngx_strncasecmp(uscf->host.data, host->data, host->len) == 0) { goto found; } @@ -637,7 +644,6 @@ ngx_http_upstream_init_request(ngx_http_request_t *r) } ctx->name = *host; - ctx->type = NGX_RESOLVE_A; ctx->handler = ngx_http_upstream_resolve_handler; ctx->data = r; ctx->timeout = clcf->resolver_timeout; @@ -709,7 +715,7 @@ ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u) if (r->cache->header_start + 256 >= u->conf->buffer_size) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "%V_buffer_size %uz is not enough for cache key, " - "it should increased at least to %uz", + "it should be increased to at least %uz", &u->conf->module, u->conf->buffer_size, ngx_align(r->cache->header_start + 256, 1024)); @@ -911,16 +917,18 @@ ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx) #if (NGX_DEBUG) { - in_addr_t addr; + u_char text[NGX_SOCKADDR_STRLEN]; + ngx_str_t addr; ngx_uint_t i; + addr.data = text; + for (i = 0; i < ctx->naddrs; i++) { - addr = ntohl(ur->addrs[i]); + addr.len = ngx_sock_ntop(ur->addrs[i].sockaddr, ur->addrs[i].socklen, + text, NGX_SOCKADDR_STRLEN, 0); - ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "name was resolved to %ud.%ud.%ud.%ud", - (addr >> 24) & 0xff, (addr >> 16) & 0xff, - (addr >> 8) & 0xff, addr & 0xff); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "name was resolved to %V", &addr); } } #endif @@ -1069,6 +1077,55 @@ ngx_http_upstream_check_broken_connection(ngx_http_request_t *r, #endif +#if (NGX_HAVE_EPOLLRDHUP) + + if ((ngx_event_flags & NGX_USE_EPOLL_EVENT) && ev->pending_eof) { + socklen_t len; + + ev->eof = 1; + c->error = 1; + + err = 0; + len = sizeof(ngx_err_t); + + /* + * BSDs and Linux return 0 and set a pending error in err + * Solaris returns -1 and sets errno + */ + + if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void *) &err, &len) + == -1) + { + err = ngx_socket_errno; + } + + if (err) { + ev->error = 1; + } + + if (!u->cacheable && u->peer.connection) { + ngx_log_error(NGX_LOG_INFO, ev->log, err, + "epoll_wait() reported that client prematurely closed " + "connection, so upstream connection is closed too"); + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_CLIENT_CLOSED_REQUEST); + return; + } + + ngx_log_error(NGX_LOG_INFO, ev->log, err, + "epoll_wait() reported that client prematurely closed " + "connection"); + + if (u->peer.connection == NULL) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_CLIENT_CLOSED_REQUEST); + } + + return; + } + +#endif + n = recv(c->fd, buf, 1, MSG_PEEK); err = ngx_socket_errno; @@ -1180,7 +1237,7 @@ ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u) return; } - /* rc == NGX_OK || rc == NGX_AGAIN */ + /* rc == NGX_OK || rc == NGX_AGAIN || rc == NGX_DONE */ c = u->peer.connection; @@ -1281,6 +1338,11 @@ ngx_http_upstream_ssl_init_connection(ngx_http_request_t *r, { ngx_int_t rc; + if (ngx_http_upstream_test_connect(c) != NGX_OK) { + ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR); + return; + } + if (ngx_ssl_create_connection(u->conf->ssl, c, NGX_SSL_BUFFER|NGX_SSL_CLIENT) != NGX_OK) @@ -1332,13 +1394,19 @@ ngx_http_upstream_ssl_handshake(ngx_connection_t *c) c->write->handler = ngx_http_upstream_handler; c->read->handler = ngx_http_upstream_handler; + c = r->connection; + ngx_http_upstream_send_request(r, u); + ngx_http_run_posted_requests(c); return; } + c = r->connection; + ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR); + ngx_http_run_posted_requests(c); } #endif @@ -1471,22 +1539,10 @@ ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u) ngx_add_timer(c->read, u->conf->read_timeout); -#if 1 if (c->read->ready) { - - /* post aio operation */ - - /* - * TODO comment - * although we can post aio operation just in the end - * of ngx_http_upstream_connect() CHECK IT !!! - * it's better to do here because we postpone header buffer allocation - */ - ngx_http_upstream_process_header(r, u); return; } -#endif u->write_event_handler = ngx_http_upstream_dummy_handler; @@ -1660,11 +1716,7 @@ ngx_http_upstream_process_header(ngx_http_request_t *r, ngx_http_upstream_t *u) /* rc == NGX_OK */ - if (u->headers_in.status_n > NGX_HTTP_SPECIAL_RESPONSE) { - - if (r->subrequest_in_memory) { - u->buffer.last = u->buffer.pos; - } + if (u->headers_in.status_n >= NGX_HTTP_SPECIAL_RESPONSE) { if (ngx_http_upstream_test_next(r, u) == NGX_OK) { return; @@ -1693,15 +1745,14 @@ ngx_http_upstream_process_header(ngx_http_request_t *r, ngx_http_upstream_t *u) } if (u->input_filter_init(u->input_filter_ctx) == NGX_ERROR) { - ngx_http_upstream_finalize_request(r, u, - NGX_HTTP_INTERNAL_SERVER_ERROR); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } n = u->buffer.last - u->buffer.pos; if (n) { - u->buffer.last -= n; + u->buffer.last = u->buffer.pos; u->state->response_length += n; @@ -1709,11 +1760,11 @@ ngx_http_upstream_process_header(ngx_http_request_t *r, ngx_http_upstream_t *u) ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } + } - if (u->length == 0) { - ngx_http_upstream_finalize_request(r, u, 0); - return; - } + if (u->length == 0) { + ngx_http_upstream_finalize_request(r, u, 0); + return; } u->read_event_handler = ngx_http_upstream_process_body_in_memory; @@ -1762,6 +1813,56 @@ ngx_http_upstream_test_next(ngx_http_request_t *r, ngx_http_upstream_t *u) #endif } +#if (NGX_HTTP_CACHE) + + if (status == NGX_HTTP_NOT_MODIFIED + && u->cache_status == NGX_HTTP_CACHE_EXPIRED + && u->conf->cache_revalidate) + { + time_t now, valid; + ngx_int_t rc; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http upstream not modified"); + + now = ngx_time(); + valid = r->cache->valid_sec; + + rc = u->reinit_request(r); + + if (rc != NGX_OK) { + ngx_http_upstream_finalize_request(r, u, rc); + return NGX_OK; + } + + u->cache_status = NGX_HTTP_CACHE_REVALIDATED; + rc = ngx_http_upstream_cache_send(r, u); + + if (valid == 0) { + valid = r->cache->valid_sec; + } + + if (valid == 0) { + valid = ngx_http_file_cache_valid(u->conf->cache_valid, + u->headers_in.status_n); + if (valid) { + valid = now + valid; + } + } + + if (valid) { + r->cache->valid_sec = valid; + r->cache->date = now; + + ngx_http_file_cache_update_header(r); + } + + ngx_http_upstream_finalize_request(r, u, rc); + return NGX_OK; + } + +#endif + return NGX_DECLINED; } @@ -1876,7 +1977,7 @@ ngx_http_upstream_test_connect(ngx_connection_t *c) if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void *) &err, &len) == -1) { - err = ngx_errno; + err = ngx_socket_errno; } if (err) { @@ -1893,7 +1994,7 @@ ngx_http_upstream_test_connect(ngx_connection_t *c) static ngx_int_t ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u) { - ngx_str_t *uri, args; + ngx_str_t uri, args; ngx_uint_t i, flags; ngx_list_part_t *part; ngx_table_elt_t *h; @@ -1934,11 +2035,11 @@ ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u) } } - uri = &u->headers_in.x_accel_redirect->value; + uri = u->headers_in.x_accel_redirect->value; ngx_str_null(&args); flags = NGX_HTTP_LOG_UNSAFE; - if (ngx_http_parse_unsafe_uri(r, uri, &args, &flags) != NGX_OK) { + if (ngx_http_parse_unsafe_uri(r, &uri, &args, &flags) != NGX_OK) { ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND); return NGX_DONE; } @@ -1947,7 +2048,7 @@ ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u) r->method = NGX_HTTP_GET; } - ngx_http_internal_redirect(r, uri, &args); + ngx_http_internal_redirect(r, &uri, &args); ngx_http_finalize_request(r, NGX_DONE); return NGX_DONE; } @@ -2006,7 +2107,7 @@ ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u) r->headers_out.content_length_n = u->headers_in.content_length_n; - u->length = u->headers_in.content_length_n; + u->length = -1; return NGX_OK; } @@ -2030,7 +2131,7 @@ ngx_http_upstream_process_body_in_memory(ngx_http_request_t *r, if (rev->timedout) { ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out"); - ngx_http_upstream_finalize_request(r, u, NGX_ETIMEDOUT); + ngx_http_upstream_finalize_request(r, u, NGX_HTTP_GATEWAY_TIME_OUT); return; } @@ -2106,6 +2207,8 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) return; } + u->header_sent = 1; + if (u->upgrade) { ngx_http_upstream_upgrade(r, u); return; @@ -2132,8 +2235,6 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) } } - u->header_sent = 1; - if (r->request_body && r->request_body->temp_file) { ngx_pool_run_cleanup_file(r->pool, r->request_body->temp_file->file.fd); r->request_body->temp_file->file.fd = NGX_INVALID_FILE; @@ -2156,7 +2257,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) r->limit_rate = 0; if (u->input_filter_init(u->input_filter_ctx) == NGX_ERROR) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -2170,7 +2271,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) { ngx_connection_error(c, ngx_socket_errno, "setsockopt(TCP_NODELAY) failed"); - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -2185,7 +2286,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) u->state->response_length += n; if (u->input_filter(u->input_filter_ctx, n) == NGX_ERROR) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -2196,7 +2297,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) u->buffer.last = u->buffer.start; if (ngx_http_send_special(r, NGX_HTTP_FLUSH) == NGX_ERROR) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -2220,7 +2321,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) switch (ngx_http_test_predicates(r, u->conf->no_cache)) { case NGX_ERROR: - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; case NGX_DECLINED: @@ -2236,7 +2337,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) r->cache->file_cache = u->conf->cache->data; if (ngx_http_file_cache_create(r) != NGX_OK) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } } @@ -2297,7 +2398,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) p->temp_file = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)); if (p->temp_file == NULL) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -2320,7 +2421,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) p->preread_bufs = ngx_alloc_chain_link(r->pool); if (p->preread_bufs == NULL) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -2334,7 +2435,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) p->buf_to_file = ngx_calloc_buf(r->pool); if (p->buf_to_file == NULL) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -2382,7 +2483,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) if (u->input_filter_init && u->input_filter_init(p->input_ctx) != NGX_OK) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -2424,7 +2525,7 @@ ngx_http_upstream_upgrade(ngx_http_request_t *r, ngx_http_upstream_t *u) { ngx_connection_error(c, ngx_socket_errno, "setsockopt(TCP_NODELAY) failed"); - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -2440,7 +2541,7 @@ ngx_http_upstream_upgrade(ngx_http_request_t *r, ngx_http_upstream_t *u) { ngx_connection_error(u->peer.connection, ngx_socket_errno, "setsockopt(TCP_NODELAY) failed"); - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -2449,7 +2550,7 @@ ngx_http_upstream_upgrade(ngx_http_request_t *r, ngx_http_upstream_t *u) } if (ngx_http_send_special(r, NGX_HTTP_FLUSH) == NGX_ERROR) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -2524,7 +2625,7 @@ ngx_http_upstream_process_upgraded(ngx_http_request_t *r, if (upstream->read->timedout || upstream->write->timedout) { ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out"); - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_HTTP_GATEWAY_TIME_OUT); return; } @@ -2547,7 +2648,7 @@ ngx_http_upstream_process_upgraded(ngx_http_request_t *r, if (b->start == NULL) { b->start = ngx_palloc(r->pool, u->conf->buffer_size); if (b->start == NULL) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -2570,7 +2671,7 @@ ngx_http_upstream_process_upgraded(ngx_http_request_t *r, n = dst->send(dst, b->pos, size); if (n == NGX_ERROR) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -2625,7 +2726,7 @@ ngx_http_upstream_process_upgraded(ngx_http_request_t *r, if (ngx_handle_write_event(upstream->write, u->conf->send_lowat) != NGX_OK) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -2637,7 +2738,7 @@ ngx_http_upstream_process_upgraded(ngx_http_request_t *r, } if (ngx_handle_read_event(upstream->read, 0) != NGX_OK) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -2651,12 +2752,12 @@ ngx_http_upstream_process_upgraded(ngx_http_request_t *r, if (ngx_handle_write_event(downstream->write, clcf->send_lowat) != NGX_OK) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } if (ngx_handle_read_event(downstream->read, 0) != NGX_OK) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -2711,7 +2812,7 @@ ngx_http_upstream_process_non_buffered_upstream(ngx_http_request_t *r, if (c->read->timedout) { ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out"); - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_HTTP_GATEWAY_TIME_OUT); return; } @@ -2747,7 +2848,7 @@ ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r, rc = ngx_http_output_filter(r, u->out_bufs); if (rc == NGX_ERROR) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -2758,13 +2859,27 @@ ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r, if (u->busy_bufs == NULL) { if (u->length == 0 - || upstream->read->eof - || upstream->read->error) + || (upstream->read->eof && u->length == -1)) { ngx_http_upstream_finalize_request(r, u, 0); return; } + if (upstream->read->eof) { + ngx_log_error(NGX_LOG_ERR, upstream->log, 0, + "upstream prematurely closed connection"); + + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_BAD_GATEWAY); + return; + } + + if (upstream->read->error) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_BAD_GATEWAY); + return; + } + b->pos = b->start; b->last = b->start; } @@ -2784,7 +2899,7 @@ ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r, u->state->response_length += n; if (u->input_filter(u->input_filter_ctx, n) == NGX_ERROR) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } } @@ -2803,7 +2918,7 @@ ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r, if (ngx_handle_write_event(downstream->write, clcf->send_lowat) != NGX_OK) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } } @@ -2816,7 +2931,7 @@ ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r, } if (ngx_handle_read_event(upstream->read, 0) != NGX_OK) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -2907,14 +3022,14 @@ ngx_http_upstream_process_downstream(ngx_http_request_t *r) ngx_add_timer(wev, p->send_timeout); if (ngx_handle_write_event(wev, p->send_lowat) != NGX_OK) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); } return; } if (ngx_event_pipe(p, wev->write) == NGX_ABORT) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -2932,14 +3047,14 @@ ngx_http_upstream_process_downstream(ngx_http_request_t *r) "http downstream delayed"); if (ngx_handle_write_event(wev, p->send_lowat) != NGX_OK) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); } return; } if (ngx_event_pipe(p, 1) == NGX_ABORT) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } } @@ -2967,7 +3082,7 @@ ngx_http_upstream_process_upstream(ngx_http_request_t *r, } else { if (ngx_event_pipe(u->pipe, 0) == NGX_ABORT) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } } @@ -2992,11 +3107,12 @@ ngx_http_upstream_process_request(ngx_http_request_t *r) if (p->upstream_eof || p->upstream_done) { - tf = u->pipe->temp_file; + tf = p->temp_file; if (u->headers_in.status_n == NGX_HTTP_OK + && (p->upstream_done || p->length == -1) && (u->headers_in.content_length_n == -1 - || (u->headers_in.content_length_n == tf->offset))) + || u->headers_in.content_length_n == tf->offset)) { ngx_http_upstream_store(r, u); u->store = 0; @@ -3009,15 +3125,16 @@ ngx_http_upstream_process_request(ngx_http_request_t *r) if (u->cacheable) { if (p->upstream_done) { - ngx_http_file_cache_update(r, u->pipe->temp_file); + ngx_http_file_cache_update(r, p->temp_file); } else if (p->upstream_eof) { - tf = u->pipe->temp_file; + tf = p->temp_file; - if (u->headers_in.content_length_n == -1 - || u->headers_in.content_length_n - == tf->offset - (off_t) r->cache->body_start) + if (p->length == -1 + && (u->headers_in.content_length_n == -1 + || u->headers_in.content_length_n + == tf->offset - (off_t) r->cache->body_start)) { ngx_http_file_cache_update(r, tf); @@ -3026,7 +3143,7 @@ ngx_http_upstream_process_request(ngx_http_request_t *r) } } else if (p->upstream_error) { - ngx_http_file_cache_free(r->cache, u->pipe->temp_file); + ngx_http_file_cache_free(r->cache, p->temp_file); } } @@ -3035,10 +3152,20 @@ ngx_http_upstream_process_request(ngx_http_request_t *r) if (p->upstream_done || p->upstream_eof || p->upstream_error) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http upstream exit: %p", p->out); -#if 0 - ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock); -#endif - ngx_http_upstream_finalize_request(r, u, 0); + + if (p->upstream_done + || (p->upstream_eof && p->length == -1)) + { + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + + if (p->upstream_eof) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream prematurely closed connection"); + } + + ngx_http_upstream_finalize_request(r, u, NGX_HTTP_BAD_GATEWAY); return; } } @@ -3048,7 +3175,7 @@ ngx_http_upstream_process_request(ngx_http_request_t *r) "http upstream downstream error"); if (!u->cacheable && !u->store && u->peer.connection) { - ngx_http_upstream_finalize_request(r, u, 0); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); } } } @@ -3148,14 +3275,13 @@ ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u, ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http next upstream, %xi", ft_type); -#if 0 - ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock); -#endif - if (u->peer.sockaddr) { - if (ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_404) { + if (ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_403 + || ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_404) + { state = NGX_PEER_NEXT; + } else { state = NGX_PEER_FAILED; } @@ -3187,6 +3313,10 @@ ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u, status = NGX_HTTP_INTERNAL_SERVER_ERROR; break; + case NGX_HTTP_UPSTREAM_FT_HTTP_403: + status = NGX_HTTP_FORBIDDEN; + break; + case NGX_HTTP_UPSTREAM_FT_HTTP_404: status = NGX_HTTP_NOT_FOUND; break; @@ -3258,13 +3388,6 @@ ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u, u->peer.connection = NULL; } -#if 0 - if (u->conf->busy_lock && !u->busy_locked) { - ngx_http_upstream_busy_lock(p); - return; - } -#endif - ngx_http_upstream_connect(r, u); } @@ -3285,6 +3408,7 @@ static void ngx_http_upstream_finalize_request(ngx_http_request_t *r, ngx_http_upstream_t *u, ngx_int_t rc) { + ngx_uint_t flush; ngx_time_t *tp; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -3391,11 +3515,10 @@ ngx_http_upstream_finalize_request(ngx_http_request_t *r, #endif - if (u->header_sent - && rc != NGX_HTTP_REQUEST_TIME_OUT - && (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE)) + if (r->subrequest_in_memory + && u->headers_in.status_n >= NGX_HTTP_SPECIAL_RESPONSE) { - rc = 0; + u->buffer.last = u->buffer.pos; } if (rc == NGX_DECLINED) { @@ -3404,14 +3527,32 @@ ngx_http_upstream_finalize_request(ngx_http_request_t *r, r->connection->log->action = "sending to client"; - if (rc == 0 - && !r->header_only -#if (NGX_HTTP_CACHE) - && !r->cached -#endif - ) + if (!u->header_sent + || rc == NGX_HTTP_REQUEST_TIME_OUT + || rc == NGX_HTTP_CLIENT_CLOSED_REQUEST) { + ngx_http_finalize_request(r, rc); + return; + } + + flush = 0; + + if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { + rc = NGX_ERROR; + flush = 1; + } + + if (r->header_only) { + ngx_http_finalize_request(r, rc); + return; + } + + if (rc == 0) { rc = ngx_http_send_special(r, NGX_HTTP_LAST); + + } else if (flush) { + r->keepalive = 0; + rc = ngx_http_send_special(r, NGX_HTTP_FLUSH); } ngx_http_finalize_request(r, rc); @@ -3513,7 +3654,7 @@ ngx_http_upstream_process_cache_control(ngx_http_request_t *r, return NGX_OK; } - if (r->cache->valid_sec != 0) { + if (r->cache->valid_sec != 0 && u->headers_in.x_accel_expires != NULL) { return NGX_OK; } @@ -4042,7 +4183,12 @@ ngx_http_upstream_copy_allow_ranges(ngx_http_request_t *r, if (r->cached) { r->allow_ranges = 1; return NGX_OK; + } + if (r->upstream->cacheable) { + r->allow_ranges = 1; + r->single_range = 1; + return NGX_OK; } #endif @@ -4274,7 +4420,7 @@ ngx_http_upstream_response_time_variable(ngx_http_request_t *r, ms = (ngx_msec_int_t) (state[i].response_sec * 1000 + state[i].response_msec); ms = ngx_max(ms, 0); - p = ngx_sprintf(p, "%d.%03d", ms / 1000, ms % 1000); + p = ngx_sprintf(p, "%T.%03M", (time_t) ms / 1000, ms % 1000); } else { *p++ = '-'; @@ -4406,6 +4552,36 @@ ngx_http_upstream_cache_status(ngx_http_request_t *r, return NGX_OK; } + +static ngx_int_t +ngx_http_upstream_cache_last_modified(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + u_char *p; + + if (r->upstream == NULL + || !r->upstream->conf->cache_revalidate + || r->upstream->cache_status != NGX_HTTP_CACHE_EXPIRED + || r->cache->last_modified == -1) + { + v->not_found = 1; + return NGX_OK; + } + + p = ngx_pnalloc(r->pool, sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1); + if (p == NULL) { + return NGX_ERROR; + } + + v->len = ngx_http_time(p, r->cache->last_modified) - p; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = p; + + return NGX_OK; +} + #endif @@ -4615,7 +4791,7 @@ ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) continue; } - if (ngx_strncmp(value[i].data, "backup", 6) == 0) { + if (ngx_strcmp(value[i].data, "backup") == 0) { if (!(uscf->flags & NGX_HTTP_UPSTREAM_BACKUP)) { goto invalid; @@ -4626,7 +4802,7 @@ ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) continue; } - if (ngx_strncmp(value[i].data, "down", 4) == 0) { + if (ngx_strcmp(value[i].data, "down") == 0) { if (!(uscf->flags & NGX_HTTP_UPSTREAM_DOWN)) { goto invalid; |
