Background subrequests for cache updates.

Previously, cache background update might not work as expected, making client
wait for it to complete before receiving the final part of a stale response.
This could happen if the response could not be sent to the client socket in one
filter chain call.

Now background cache update is done in a background subrequest.  This type of
subrequest does not block any other subrequests or the main request.
diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c
index af67b7f..7e40e78 100644
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -2518,6 +2518,7 @@
 
     sr->subrequest_in_memory = (flags & NGX_HTTP_SUBREQUEST_IN_MEMORY) != 0;
     sr->waited = (flags & NGX_HTTP_SUBREQUEST_WAITED) != 0;
+    sr->background = (flags & NGX_HTTP_SUBREQUEST_BACKGROUND) != 0;
 
     sr->unparsed_uri = r->unparsed_uri;
     sr->method_name = ngx_http_core_get_method;
@@ -2531,29 +2532,31 @@
     sr->read_event_handler = ngx_http_request_empty_handler;
     sr->write_event_handler = ngx_http_handler;
 
-    if (c->data == r && r->postponed == NULL) {
-        c->data = sr;
-    }
-
     sr->variables = r->variables;
 
     sr->log_handler = r->log_handler;
 
-    pr = ngx_palloc(r->pool, sizeof(ngx_http_postponed_request_t));
-    if (pr == NULL) {
-        return NGX_ERROR;
-    }
+    if (!sr->background) {
+        if (c->data == r && r->postponed == NULL) {
+            c->data = sr;
+        }
 
-    pr->request = sr;
-    pr->out = NULL;
-    pr->next = NULL;
+        pr = ngx_palloc(r->pool, sizeof(ngx_http_postponed_request_t));
+        if (pr == NULL) {
+            return NGX_ERROR;
+        }
 
-    if (r->postponed) {
-        for (p = r->postponed; p->next; p = p->next) { /* void */ }
-        p->next = pr;
+        pr->request = sr;
+        pr->out = NULL;
+        pr->next = NULL;
 
-    } else {
-        r->postponed = pr;
+        if (r->postponed) {
+            for (p = r->postponed; p->next; p = p->next) { /* void */ }
+            p->next = pr;
+
+        } else {
+            r->postponed = pr;
+        }
     }
 
     sr->internal = 1;
diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
index 7af45c5..43301fd 100644
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -2357,6 +2357,26 @@
     }
 
     if (r != r->main) {
+        clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+        if (r->background) {
+            if (!r->logged) {
+                if (clcf->log_subrequest) {
+                    ngx_http_log_request(r);
+                }
+
+                r->logged = 1;
+
+            } else {
+                ngx_log_error(NGX_LOG_ALERT, c->log, 0,
+                              "subrequest: \"%V?%V\" logged again",
+                              &r->uri, &r->args);
+            }
+
+            r->done = 1;
+            ngx_http_finalize_connection(r);
+            return;
+        }
 
         if (r->buffered || r->postponed) {
 
@@ -2374,9 +2394,6 @@
             r->main->count--;
 
             if (!r->logged) {
-
-                clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
-
                 if (clcf->log_subrequest) {
                     ngx_http_log_request(r);
                 }
@@ -2440,6 +2457,8 @@
     }
 
     r->done = 1;
+
+    r->read_event_handler = ngx_http_block_reading;
     r->write_event_handler = ngx_http_request_empty_handler;
 
     if (!r->post_action) {
@@ -2558,6 +2577,8 @@
         return;
     }
 
+    r = r->main;
+
     if (r->reading_body) {
         r->keepalive = 0;
         r->lingering_close = 1;
diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h
index 98c0de7..283c582 100644
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -64,6 +64,7 @@
 #define NGX_HTTP_SUBREQUEST_IN_MEMORY      2
 #define NGX_HTTP_SUBREQUEST_WAITED         4
 #define NGX_HTTP_SUBREQUEST_CLONE          8
+#define NGX_HTTP_SUBREQUEST_BACKGROUND     16
 
 #define NGX_HTTP_LOG_UNSAFE                1
 
@@ -486,7 +487,6 @@
 
 #if (NGX_HTTP_CACHE)
     unsigned                          cached:1;
-    unsigned                          cache_updater:1;
 #endif
 
 #if (NGX_HTTP_GZIP)
@@ -543,6 +543,7 @@
     unsigned                          stat_writing:1;
     unsigned                          stat_processing:1;
 
+    unsigned                          background:1;
     unsigned                          health_check:1;
 
     /* used to parse HTTP headers */
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
index fcfa2ad..2a3bb16 100644
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -879,7 +879,7 @@
     case NGX_HTTP_CACHE_STALE:
 
         if (((u->conf->cache_use_stale & NGX_HTTP_UPSTREAM_FT_UPDATING)
-             || c->stale_updating) && !r->cache_updater
+             || c->stale_updating) && !r->background
             && u->conf->cache_background_update)
         {
             r->cache->background = 1;
@@ -892,7 +892,7 @@
     case NGX_HTTP_CACHE_UPDATING:
 
         if (((u->conf->cache_use_stale & NGX_HTTP_UPSTREAM_FT_UPDATING)
-             || c->stale_updating) && !r->cache_updater)
+             || c->stale_updating) && !r->background)
         {
             u->cache_status = rc;
             rc = NGX_OK;
@@ -1076,14 +1076,14 @@
     }
 
     if (ngx_http_subrequest(r, &r->uri, &r->args, &sr, NULL,
-                            NGX_HTTP_SUBREQUEST_CLONE)
+                            NGX_HTTP_SUBREQUEST_CLONE
+                            |NGX_HTTP_SUBREQUEST_BACKGROUND)
         != NGX_OK)
     {
         return NGX_ERROR;
     }
 
     sr->header_only = 1;
-    sr->cache_updater = 1;
 
     return NGX_OK;
 }