Fix handling of chunked request bodies.  Even though the FastCGI
protocol is "streamy", it (via the CGI/1.1 spec) requires
content-length to be known and delivered for chunked requests:

* modules/fcgid/fcgid_bridge.c
  (add_request_body): Return the request body length.
  (bridge_request): Fetch the request body earlier, and
  send Content-Length if the request was chunked.

PR: 53332
Submitted by: Dominic Benson  <dominic.benson thirdlight.com>, jorton


git-svn-id: https://svn.apache.org/repos/asf/httpd/mod_fcgid/trunk@1848298 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/CHANGES-FCGID b/CHANGES-FCGID
index 541662a..f96fb79 100644
--- a/CHANGES-FCGID
+++ b/CHANGES-FCGID
@@ -1,6 +1,9 @@
                                                          -*- coding: utf-8 -*-
 Changes with mod_fcgid 2.3.10
 
+  *) Send Content-Length to backend for chunked request bodies.  PR 53332.
+     [Dominic Benson, Joe Orton]
+
   *) Fix memory consumption for large requests.  PR 51747.
      [Dominic Benson, Jan Stürtz]
 
diff --git a/modules/fcgid/fcgid_bridge.c b/modules/fcgid/fcgid_bridge.c
index 180f582..c68f60f 100644
--- a/modules/fcgid/fcgid_bridge.c
+++ b/modules/fcgid/fcgid_bridge.c
@@ -526,7 +526,8 @@
 }
 
 static int add_request_body(request_rec *r, apr_pool_t *request_pool,
-                            apr_bucket_brigade *output_brigade)
+                            apr_bucket_brigade *output_brigade,
+                            apr_off_t *body_length)
 {
     apr_bucket *bucket_input, *bucket_header;
     apr_file_t *fd = NULL;
@@ -729,22 +730,49 @@
     }
     APR_BRIGADE_INSERT_TAIL(output_brigade, bucket_header);
 
+    *body_length = request_size;
+    
     return 0;
 }
 
 int bridge_request(request_rec * r, int role, fcgid_cmd_conf *cmd_conf)
 {
-    apr_bucket_brigade *output_brigade;
+    apr_bucket_brigade *output_brigade, *body_brigade;
     apr_bucket *bucket_eos;
-    char **envp = ap_create_environment(r->pool,
-                                        r->subprocess_env);
+    char **envp;
     int rc;
 
     /* Create brigade for the request to fastcgi server */
+    body_brigade
+        = apr_brigade_create(r->pool, r->connection->bucket_alloc);
     output_brigade =
         apr_brigade_create(r->pool, r->connection->bucket_alloc);
 
-    /* Build the begin request and environ request, append them to output_brigade */
+    /* In responder mode, handle the request body up front to ensure
+     * the content-length is known (even if the request body is
+     * chunked) and sent in the header. */
+    if (role == FCGI_RESPONDER) {
+        apr_off_t body_length;
+        
+        rc = add_request_body(r, r->pool, body_brigade, &body_length);
+        if (rc) {
+            return rc;
+        }
+
+        if (body_length && !apr_table_get(r->headers_in, "Content-Length")) {
+            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+                          "mod_fcgid: dechunked request body length %" APR_OFF_T_FMT,
+                          body_length);
+        
+            apr_table_set(r->subprocess_env, "CONTENT_LENGTH",
+                          apr_off_t_toa(r->pool, body_length));
+            apr_table_unset(r->subprocess_env, "HTTP_TRANSFER_ENCODING");
+        }
+    }
+
+    envp = ap_create_environment(r->pool, r->subprocess_env);
+          
+    /* Build the begin request and environ request, add them to output_brigade */
     if (!build_begin_block
         (role, r, r->connection->bucket_alloc, output_brigade)
         || !build_env_block(r, envp, r->connection->bucket_alloc,
@@ -754,12 +782,8 @@
         return HTTP_INTERNAL_SERVER_ERROR;
     }
 
-    if (role == FCGI_RESPONDER) {
-        rc = add_request_body(r, r->pool, output_brigade);
-        if (rc) {
-            return rc;
-        }
-    }
+    /* Append the body output. */
+    APR_BRIGADE_CONCAT(output_brigade, body_brigade);
 
     /* The eos bucket now */
     bucket_eos = apr_bucket_eos_create(r->connection->bucket_alloc);