[FASTCGI] 100-continue support for mod_fastcgi

Yehuda Sadeh Weinraub yehudasa at gmail.com
Tue Sep 7 16:41:02 EDT 2010


Hi,
   a major problem that we encountered when using the fastcgi apache
module was that when using it, the expect-100-continue sequence was
broken. If a client has the "Expect: 100-continue" in the HTTP header,
there is no way for the server to specify whether it is ok for the
client to continue with sending data or not, and the module triggers
an automatic 100-continue response for the client. So clients continue
sending the data for requests that will eventually fail. The following
patch modified the fastcgi module a bit, so that when an
expect-100-continue attribute is sent, it'll wait for the server to
send a 'Status: 100' response before starting to read the data from
the client (which will trigger the 100-continue response). It would be
best if someone that is more familiar withe the fastcgi code reviews
it, and any comments/suggestions are truly appreciated.

Thanks,
Yehuda

diff -upr orig/mod_fastcgi-SNAP-0910052141/fcgi.h
mod_fastcgi-SNAP-0910052141/fcgi.h
--- orig/mod_fastcgi-SNAP-0910052141/fcgi.h	2008-09-22 03:36:06.000000000 -0700
+++ mod_fastcgi-SNAP-0910052141/fcgi.h	2010-09-03 17:12:57.000000000 -0700
@@ -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
  */
 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 -upr orig/mod_fastcgi-SNAP-0910052141/fcgi_protocol.c
mod_fastcgi-SNAP-0910052141/fcgi_protocol.c
--- orig/mod_fastcgi-SNAP-0910052141/fcgi_protocol.c	2008-09-23
07:48:13.000000000 -0700
+++ mod_fastcgi-SNAP-0910052141/fcgi_protocol.c	2010-09-03
17:13:39.000000000 -0700
@@ -221,9 +221,11 @@ static void add_pass_header_vars(fcgi_re
  * 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
         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 -upr orig/mod_fastcgi-SNAP-0910052141/mod_fastcgi.c
mod_fastcgi-SNAP-0910052141/mod_fastcgi.c
--- orig/mod_fastcgi-SNAP-0910052141/mod_fastcgi.c	2008-11-09
06:31:03.000000000 -0800
+++ mod_fastcgi-SNAP-0910052141/mod_fastcgi.c	2010-09-03
17:24:16.000000000 -0700
@@ -646,7 +646,7 @@ static void close_connection_to_fs(fcgi_
 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(reque
     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(reque
                 name = "Invalid Character";
                 goto BadHeader;
             default:
+		newl = 0;
                 flag = 0;
                 break;
         }
@@ -1597,6 +1605,7 @@ static int npipe_io(fcgi_request * const
     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
         {
         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 * cons
     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 * cons
         {
         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 * cons
             /* 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)


More information about the FastCGI-developers mailing list