From: Yehuda Sadeh <yehuda@hq.newdream.net>
Date: Fri, 25 Feb 2011 11:09:19 -0800
Subject: [PATCH] handle expect-100-continue differently

When expecting a 100-continue, wait for the application to return
that status before trying to read the data. That won't trigger the
apache early response.
---
 fcgi.h          |  3 ++-
 fcgi_protocol.c | 15 ++++++++++++++-
 mod_fastcgi.c   | 25 +++++++++++++++++++++----
 3 files changed, 37 insertions(+), 6 deletions(-)

diff --git a/fcgi.h b/fcgi.h
index 1f3111c..0aebc16 100644
--- a/fcgi.h
+++ b/fcgi.h
@@ -294,6 +294,7 @@ typedef struct {
     char *fs_stderr;
     int fs_stderr_len;
     int parseHeader;                /* TRUE iff parsing response headers */
+    int gotCont;
     request_rec *r;
     int readingEndRequestBody;
     FCGI_EndRequestBody endRequestBody;
@@ -498,7 +499,7 @@ int fcgi_pm_main(void *dummy, child_info *info);
  */
 void fcgi_protocol_queue_begin_request(fcgi_request *fr);
 void fcgi_protocol_queue_client_buffer(fcgi_request *fr);
-int fcgi_protocol_queue_env(request_rec *r, fcgi_request *fr, env_status *env);
+int fcgi_protocol_queue_env(request_rec *r, fcgi_request *fr, env_status *env, int *expect_cont);
 int fcgi_protocol_dequeue(pool *p, fcgi_request *fr);
 
 /*
diff --git a/fcgi_protocol.c b/fcgi_protocol.c
index 55da311..f80c5a5 100644
--- a/fcgi_protocol.c
+++ b/fcgi_protocol.c
@@ -221,9 +221,11 @@ static void add_pass_header_vars(fcgi_request *fr)
  * complete ENV was buffered, FALSE otherwise.  Note: envp is updated to
  * reflect the current position in the ENV.
  */
-int fcgi_protocol_queue_env(request_rec *r, fcgi_request *fr, env_status *env)
+int fcgi_protocol_queue_env(request_rec *r, fcgi_request *fr, env_status *env,
+			    int *expect_cont)
 {
     int charCount;
+    const char *name, *val;
 
     if (env->envp == NULL) {
         ap_add_common_vars(r);
@@ -237,15 +239,26 @@ int fcgi_protocol_queue_env(request_rec *r, fcgi_request *fr, env_status *env)
         env->envp = ap_create_environment(r->pool, r->subprocess_env);
         env->pass = PREP;
     }
+    *expect_cont = 0;
 
     while (*env->envp) {
+	ap_log_error(FCGI_LOG_WARN_NOERRNO, fcgi_apache_main_server,
+			"FastCGI: JJJ envp=%s", *env->envp);
         switch (env->pass) 
         {
         case PREP:
             env->equalPtr = strchr(*env->envp, '=');
             ASSERT(env->equalPtr != NULL);
+	    name = *env->envp; 
+	    val = env->equalPtr + 1;
             env->nameLen = env->equalPtr - *env->envp;
             env->valueLen = strlen(++env->equalPtr);
+	    ap_log_error(FCGI_LOG_WARN_NOERRNO, fcgi_apache_main_server,
+			"FastCGI: JJJ name='%.*s' val='%.*s'", env->nameLen, *env->envp, env->valueLen, val);
+	    if (val && env->nameLen == sizeof("HTTP_EXPECT") - 1 &&
+                strncasecmp(name, "HTTP_EXPECT", env->nameLen) == 0 &&
+		strncasecmp(val, "100-continue", env->valueLen) == 0)
+		*expect_cont = 1;
             build_env_header(env->nameLen, env->valueLen, env->headerBuff, &env->headerLen);
             env->totalLen = env->headerLen + env->nameLen + env->valueLen;
             env->pass = HEADER;
diff --git a/mod_fastcgi.c b/mod_fastcgi.c
index 67a70aa..e3c1e48 100644
--- a/mod_fastcgi.c
+++ b/mod_fastcgi.c
@@ -646,7 +646,7 @@ static void close_connection_to_fs(fcgi_request *fr)
 static const char *process_headers(request_rec *r, fcgi_request *fr)
 {
     char *p, *next, *name, *value;
-    int len, flag;
+    int len, flag, newl;
     int hasLocation = FALSE;
 
     ASSERT(fr->parseHeader == SCAN_CGI_READING_HEADERS);
@@ -661,11 +661,18 @@ static const char *process_headers(request_rec *r, fcgi_request *fr)
     p = (char *)fr->header->elts;
     len = fr->header->nelts;
     flag = 0;
+    newl = 1;
     while(len-- && flag < 2) {
-        switch(*p) {
+	if (newl && !fr->gotCont && strncasecmp(p, "Status: 100", 11) == 0) {
+		fr->gotCont = 1;
+		ap_log_error(FCGI_LOG_WARN_NOERRNO, fcgi_apache_main_server,
+			"FastCGI: JJJ gotCont=1");
+	}
+	switch(*p) {
             case '\r':
                 break;
             case '\n':
+		newl = 1;
                 flag++;
                 break;
             case '\0':
@@ -674,6 +681,7 @@ static const char *process_headers(request_rec *r, fcgi_request *fr)
                 name = "Invalid Character";
                 goto BadHeader;
             default:
+		newl = 0;
                 flag = 0;
                 break;
         }
@@ -1597,6 +1605,7 @@ static int npipe_io(fcgi_request * const fr)
     pool * const rp = r->pool;
     int is_connected = 0;
     DWORD recv_count = 0;
+    int expect_cont = 0;
 
     dynamic_last_io_time.tv_sec = 0;
     dynamic_last_io_time.tv_usec = 0;
@@ -1637,7 +1646,7 @@ static int npipe_io(fcgi_request * const fr)
         {
         case STATE_ENV_SEND:
 
-            if (fcgi_protocol_queue_env(r, fr, &env_status) == 0)
+            if (fcgi_protocol_queue_env(r, fr, &env_status, &expect_cont) == 0)
             {
                 goto SERVER_SEND;
             }
@@ -2010,6 +2019,7 @@ static int socket_io(fcgi_request * const fr)
     env_status env;
     pool *rp = r->pool;
     int is_connected = 0;
+    int expect_cont = 0;
     
     dynamic_last_io_time.tv_sec = 0;
     dynamic_last_io_time.tv_usec = 0;
@@ -2046,7 +2056,7 @@ static int socket_io(fcgi_request * const fr)
         {
         case STATE_ENV_SEND:
 
-            if (fcgi_protocol_queue_env(r, fr, &env) == 0)
+            if (fcgi_protocol_queue_env(r, fr, &env, &expect_cont) == 0)
             {
                 goto SERVER_SEND;
             }
@@ -2056,6 +2066,9 @@ static int socket_io(fcgi_request * const fr)
             /* fall through */
 
         case STATE_CLIENT_RECV:
+	    if (expect_cont && !fr->gotCont) {
+		goto SERVER_SEND;
+	    }
 
             if (read_from_client_n_queue(fr))
             {
@@ -2328,6 +2341,10 @@ SERVER_SEND:
                 state = STATE_ERROR;
                 break;
             }
+	    if (expect_cont && fr->gotCont) {
+		state = STATE_CLIENT_RECV;
+		continue;
+	    }
         }
 
         if (fr->exitStatusSet) 
