From 4a75e1a63c5cf3d278c7d7e50e012391b44b5e3c Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Fri, 4 Jul 2014 20:47:16 +0400 Subject: [PATCH] Upstream: p->downstream_error instead of closing connection. Previously, nginx closed client connection in cases when a response body from upstream was needed to be cached or stored but shouldn't be sent to the client. While this is normal for HTTP, it is unacceptable for SPDY. Fix is to use instead the p->downstream_error flag to prevent nginx from sending anything downstream. To make this work, the event pipe code was modified to properly cache empty responses with the flag set. --- src/event/ngx_event_pipe.c | 15 +++++---------- src/http/ngx_http_upstream.c | 20 ++++++++------------ 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/src/event/ngx_event_pipe.c b/src/event/ngx_event_pipe.c index eed807d61..64fb07bde 100644 --- a/src/event/ngx_event_pipe.c +++ b/src/event/ngx_event_pipe.c @@ -439,7 +439,11 @@ ngx_event_pipe_read_upstream(ngx_event_pipe_t *p) } } - if (p->cacheable && p->in) { + if (p->cacheable && (p->in || p->buf_to_file)) { + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0, + "pipe write chain"); + if (ngx_event_pipe_write_chain_to_temp_file(p) == NGX_ABORT) { return NGX_ABORT; } @@ -515,15 +519,6 @@ ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p) p->in = NULL; } - if (p->cacheable && p->buf_to_file) { - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0, - "pipe write chain"); - - if (ngx_event_pipe_write_chain_to_temp_file(p) == NGX_ABORT) { - return NGX_ABORT; - } - } - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe write downstream done"); diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 20722ac3f..012969170 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -2357,21 +2357,17 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) if (r->header_only) { - if (u->cacheable || u->store) { - - if (ngx_shutdown_socket(c->fd, NGX_WRITE_SHUTDOWN) == -1) { - ngx_connection_error(c, ngx_socket_errno, - ngx_shutdown_socket_n " failed"); - } - - r->read_event_handler = ngx_http_request_empty_handler; - r->write_event_handler = ngx_http_request_empty_handler; - c->error = 1; - - } else { + if (!u->buffering) { ngx_http_upstream_finalize_request(r, u, rc); return; } + + if (!u->cacheable && !u->store) { + ngx_http_upstream_finalize_request(r, u, rc); + return; + } + + u->pipe->downstream_error = 1; } if (r->request_body && r->request_body->temp_file) {