summaryrefslogtreecommitdiffstats
path: root/usr.sbin/nginx/src/http/ngx_http_upstream.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/nginx/src/http/ngx_http_upstream.c')
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_upstream.c404
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;