If we think we already got a complete request, don't try to read from the client...
authorFabian Keil <fk@fabiankeil.de>
Sun, 28 Jun 2009 14:31:43 +0000 (14:31 +0000)
committerFabian Keil <fk@fabiankeil.de>
Sun, 28 Jun 2009 14:31:43 +0000 (14:31 +0000)
If we notice that we got more than a single request, mark
the server socket tainted and only serve the first request.

jcc.c
parsers.c
project.h

diff --git a/jcc.c b/jcc.c
index 932f7a4..867a5c9 100644 (file)
--- a/jcc.c
+++ b/jcc.c
@@ -1,4 +1,4 @@
-const char jcc_rcs[] = "$Id: jcc.c,v 1.257 2009/06/12 13:39:02 fabiankeil Exp $";
+const char jcc_rcs[] = "$Id: jcc.c,v 1.258 2009/06/27 11:22:52 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/jcc.c,v $
@@ -1143,6 +1143,7 @@ static void mark_server_socket_tainted(struct client_state *csp)
    {
       log_error(LOG_LEVEL_CONNECT, "Unsetting keep-alive flag.");
       csp->flags &= ~CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE;
+      csp->flags |= CSP_FLAG_SERVER_SOCKET_TAINTED;
    }
 }
 
@@ -1442,6 +1443,39 @@ static jb_err parse_client_request(struct client_state *csp)
       return JB_ERR_PARSE;
    }
 
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+   if ((csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE))
+   {
+      if (csp->iob->cur[0] != '\0')
+      {
+         csp->flags |= CSP_FLAG_SERVER_SOCKET_TAINTED;
+         if (!strcmpic(csp->http->gpc, "POST"))
+         {
+            /* XXX: this is an incomplete hack */
+            csp->flags &= ~CSP_FLAG_CLIENT_REQUEST_COMPLETELY_READ;
+            log_error(LOG_LEVEL_CONNECT,
+               "POST request detected. The connection will not be kept alive.");
+         }
+         else
+         {
+            /* XXX: and so is this */
+            csp->flags |= CSP_FLAG_CLIENT_REQUEST_COMPLETELY_READ;
+            log_error(LOG_LEVEL_CONNECT,
+               "Possible pipeline attempt detected. The connection will not "
+               "be kept alive and we will only serve the first request.");
+            /* Nuke the pipelined requests from orbit, just to be sure. */
+            csp->iob->buf[0] = '\0';
+            csp->iob->eod = csp->iob->cur = csp->iob->buf;
+         }
+      }
+      else
+      {
+         csp->flags |= CSP_FLAG_CLIENT_REQUEST_COMPLETELY_READ;
+         log_error(LOG_LEVEL_CONNECT, "Complete client request received.");
+      }
+   }
+#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
+
    return JB_ERR_OK;
 
 }
@@ -1727,7 +1761,17 @@ static void chat(struct client_state *csp)
 #else
       FD_ZERO(&rfds);
 #endif
-      FD_SET(csp->cfd, &rfds);
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+      if ((csp->flags & CSP_FLAG_CLIENT_REQUEST_COMPLETELY_READ))
+      {
+         maxfd = csp->sfd;
+      }
+      else
+#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
+      {
+         FD_SET(csp->cfd, &rfds);
+      }
+
       FD_SET(csp->sfd, &rfds);
 
 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
@@ -2279,6 +2323,7 @@ static void serve(struct client_state *csp)
       continue_chatting = (csp->config->feature_flags
          & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)
          && (csp->flags & CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE)
+         && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED)
          && (csp->cfd != JB_INVALID_SOCKET)
          && (csp->sfd != JB_INVALID_SOCKET)
          && socket_is_still_usable(csp->sfd);
index f3d8274..a8d3683 100644 (file)
--- a/parsers.c
+++ b/parsers.c
@@ -1,4 +1,4 @@
-const char parsers_rcs[] = "$Id: parsers.c,v 1.184 2009/06/18 17:10:16 fabiankeil Exp $";
+const char parsers_rcs[] = "$Id: parsers.c,v 1.185 2009/06/27 11:25:33 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/parsers.c,v $
@@ -1580,7 +1580,11 @@ static jb_err filter_header(struct client_state *csp, char **header)
  *********************************************************************/
 static jb_err server_connection(struct client_state *csp, char **header)
 {
-   if (!strcmpic(*header, "Connection: keep-alive"))
+   if (!strcmpic(*header, "Connection: keep-alive")
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+    && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED)
+#endif
+      )
    {
 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
       if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE))
@@ -3403,7 +3407,11 @@ static jb_err server_connection_adder(struct client_state *csp)
    if ((csp->config->feature_flags &
         RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)
     && (NULL != response_status_line)
-    && !strncmpic(response_status_line, "HTTP/1.1", 8))
+    && !strncmpic(response_status_line, "HTTP/1.1", 8)
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+    && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED)
+#endif
+       )
    {
       log_error(LOG_LEVEL_HEADER, "A HTTP/1.1 response "
          "without Connection header implies keep-alive.");
@@ -3437,7 +3445,8 @@ static jb_err server_proxy_connection_adder(struct client_state *csp)
    static const char proxy_connection_header[] = "Proxy-Connection: keep-alive";
    jb_err err = JB_ERR_OK;
 
-   if ((csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE))
+   if ((csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE)
+    && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED))
    {
       log_error(LOG_LEVEL_HEADER, "Adding: %s", proxy_connection_header);
       err = enlist(csp->headers, proxy_connection_header);
@@ -4048,6 +4057,9 @@ static const char *get_appropiate_connection_header(const struct client_state *c
    static const char connection_close[] = "Connection: close";
 
    if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+    && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED)
+#endif
     && (csp->http->ssl == 0))
    {
       return connection_keep_alive;
index 4d0d986..0353de7 100644 (file)
--- a/project.h
+++ b/project.h
@@ -1,7 +1,7 @@
 #ifndef PROJECT_H_INCLUDED
 #define PROJECT_H_INCLUDED
 /** Version string. */
-#define PROJECT_H_VERSION "$Id: project.h,v 1.141 2009/06/11 11:46:22 fabiankeil Exp $"
+#define PROJECT_H_VERSION "$Id: project.h,v 1.142 2009/06/11 11:49:11 fabiankeil Exp $"
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/project.h,v $
@@ -755,8 +755,23 @@ struct reusable_connection
  * the connection alive.
  */
 #define CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE  0x00008000U
+
+/**
+ * Flag for csp->flags: Set if we think we got the whole
+ * client request and shouldn't read any additional data
+ * coming from the client until the current request has
+ * been dealt with.
+ */
+#define CSP_FLAG_CLIENT_REQUEST_COMPLETELY_READ 0x00010000U
+
 #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
 
+/**
+ * Flag for csp->flags: Set if we think we can't reuse
+ * the server socket.
+ */
+#define CSP_FLAG_SERVER_SOCKET_TAINTED          0x00020000U
+
 /*
  * Flags for use in return codes of child processes
  */