# HG changeset patch
# User Yichun Zhang <agentzh@gmail.com>
# Date 1424037188 28800
#      Sun Feb 15 13:53:08 2015 -0800
# Node ID aa15033f24da93a2c7c971d5a95ae44ce21754a6
# Parent  f3f25ad09deee27485050a75732e5f46ab1b18b3
Upstream: fixed $upstream_response_time for filter_finalize + error_page.

ngx_http_upstream_finalize_request() is always called twice when an
output filter module calls ngx_http_filter_finalize_request() *and*
a custom error page is configured by the error_page directive. This
is because

1. ngx_http_filter_finalize_request() triggers
        calling ngx_http_terminate_request
        => calling ngx_http_upstream_cleanup
        => calling ngx_http_upstream_finalize_request

2. ngx_http_internal_redirect() returns NGX_DONE
        ==> ngx_http_special_response_handler() returns NGX_DONE
        ==> ngx_http_filter_finalize_request() returns NGX_ERROR
        ==> ngx_http_send_header() returns NGX_ERROR
        ==> ngx_http_upstream_send_response() calls
            ngx_http_upstream_finalize_request() again in the same
            ngx_http_upstream_send_response() call as 1).

This might result in corrupted $upstream_response_time values (close
to the absolute timestamp value) when u->state->response_sec happens
to be non-zero.

This patch ensures that the $upstream_response_time value is only
calculated upon the first ngx_http_upstream_finalize_request()
invocation.

diff -r f3f25ad09dee -r aa15033f24da src/http/ngx_http_upstream.c
--- a/src/http/ngx_http_upstream.c	Wed Feb 11 20:18:55 2015 +0300
+++ b/src/http/ngx_http_upstream.c	Sun Feb 15 13:53:08 2015 -0800
@@ -3744,10 +3744,14 @@ ngx_http_upstream_finalize_request(ngx_h
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "finalize http upstream request: %i", rc);
 
-    if (u->cleanup) {
-        *u->cleanup = NULL;
-        u->cleanup = NULL;
-    }
+    if (u->cleanup == NULL) {
+        /* the request was already finalized */
+        ngx_http_finalize_request(r, NGX_DONE);
+        return;
+    }
+
+    *u->cleanup = NULL;
+    u->cleanup = NULL;
 
     if (u->resolved && u->resolved->ctx) {
         ngx_resolve_name_done(u->resolved->ctx);
