Reorganizing the repository: swapping out what was HEAD (the old 3.1 branch)
[privoxy.git] / parsers.c
similarity index 82%
rename from src/parsers.c
rename to parsers.c
index e8ef114..dd8929b 100644 (file)
+++ b/parsers.c
@@ -1,7 +1,7 @@
-const char parsers_rcs[] = "$Id: parsers.c,v 2.6 2003/10/02 19:41:23 david__schmidt Exp $";
+const char parsers_rcs[] = "$Id: parsers.c,v 1.56.2.10 2006/01/21 16:16:08 david__schmidt Exp $";
 /*********************************************************************
  *
- * File        :  $Source: /cvsroot/ijbswa/current/src/parsers.c,v $
+ * File        :  $Source: /cvsroot/ijbswa/current/Attic/parsers.c,v $
  *
  * Purpose     :  Declares functions to parse/crunch headers and pages.
  *                Functions declared include:
@@ -40,33 +40,52 @@ const char parsers_rcs[] = "$Id: parsers.c,v 2.6 2003/10/02 19:41:23 david__schm
  *
  * Revisions   :
  *    $Log: parsers.c,v $
- *    Revision 2.6  2003/10/02 19:41:23  david__schmidt
- *    Updated header debug logging to show the header text that is
- *    being crunched; refactored functions in parsers.c to have a
- *    single, common exit point
- *
- *    Revision 2.5  2003/09/25 01:44:33  david__schmidt
- *    Resyncing HEAD with v_3_0_branch for two OSX fixes:
- *    Making thread IDs look sane in the logfile for Mach kernels,
- *    and fixing multithreading crashes due to thread-unsafe
- *    system calls.
- *    and
- *
- *    Revision 2.4  2003/01/26 20:24:26  david__schmidt
- *    Updated activity console instrumentation locations
- *
- *    Revision 2.3  2002/12/28 03:58:19  david__schmidt
- *    Initial drop of dashboard instrumentation - enabled with
- *    --enable-activity-console
- *
- *    Revision 2.2  2002/11/10 04:20:38  hal9
+ *    Revision 1.56.2.10  2006/01/21 16:16:08  david__schmidt
+ *    Thanks to  Edward Carrel for his patch to modernize OSX's\rpthreads support.  See bug #1409623.
+ *
+ *    Revision 1.56.2.9  2004/10/03 12:53:45  david__schmidt
+ *    Add the ability to check jpeg images for invalid
+ *    lengths of comment blocks.  Defensive strategy
+ *    against the exploit:
+ *       Microsoft Security Bulletin MS04-028
+ *       Buffer Overrun in JPEG Processing (GDI+) Could
+ *       Allow Code Execution (833987)
+ *    Enabled with +inspect-jpegs in actions files.
+ *
+ *    Revision 1.56.2.8  2003/07/11 13:21:25  oes
+ *    Excluded text/plain objects from filtering. This fixes a
+ *    couple of client-crashing, download corruption and
+ *    Privoxy performance issues, whose root cause lies in
+ *    web servers labelling content of unknown type as text/plain.
+ *
+ *    Revision 1.56.2.7  2003/05/06 12:07:26  oes
+ *    Fixed bug #729900: Suspicious HOST: headers are now killed and regenerated if necessary
+ *
+ *    Revision 1.56.2.6  2003/04/14 21:28:30  oes
+ *    Completing the previous change
+ *
+ *    Revision 1.56.2.5  2003/04/14 12:08:16  oes
+ *    Added temporary workaround for bug in PHP < 4.2.3
+ *
+ *    Revision 1.56.2.4  2003/03/07 03:41:05  david__schmidt
+ *    Wrapping all *_r functions (the non-_r versions of them) with mutex semaphores for OSX.  Hopefully this will take care of all of those pesky crash reports.
+ *
+ *    Revision 1.56.2.3  2002/11/10 04:20:02  hal9
  *    Fix typo: supressed -> suppressed
  *
- *    Revision 2.1  2002/09/11 11:23:59  oes
- *    Fixed logging of cookies: Killed incoming cookies now logged; incoming/outgoing cookies now distinguished in log
+ *    Revision 1.56.2.2  2002/09/25 14:59:53  oes
+ *    Improved cookie logging
  *
- *    Revision 2.0  2002/06/04 14:34:21  jongfoster
- *    Moving source files to src/
+ *    Revision 1.56.2.1  2002/09/25 14:52:45  oes
+ *    Added basic support for OPTIONS and TRACE HTTP methods:
+ *     - New parser function client_max_forwards which decrements
+ *       the Max-Forwards HTTP header field of OPTIONS and TRACE
+ *       requests by one before forwarding
+ *     - New parser function client_host which extracts the host
+ *       and port information from the HTTP header field if the
+ *       request URI was not absolute
+ *     - Don't crumble and re-add the Host: header, but only generate
+ *       and append if missing
  *
  *    Revision 1.56  2002/05/12 15:34:22  jongfoster
  *    Fixing typo in a comment
@@ -430,12 +449,13 @@ const char parsers_rcs[] = "$Id: parsers.c,v 2.6 2003/10/02 19:41:23 david__schm
 #include <unistd.h>
 #endif
 
+#include "project.h"
+
 #ifdef OSX_DARWIN
 #include <pthread.h>
 #include "jcc.h"
 /* jcc.h is for mutex semapores only */
 #endif /* def OSX_DARWIN */
-#include "project.h"
 #include "list.h"
 #include "parsers.h"
 #include "encode.h"
@@ -444,9 +464,6 @@ const char parsers_rcs[] = "$Id: parsers.c,v 2.6 2003/10/02 19:41:23 david__schm
 #include "jbsockets.h"
 #include "miscutil.h"
 #include "list.h"
-#ifdef FEATURE_ACTIVITY_CONSOLE
-#include "stats.h"
-#endif /* def FEATURE_ACTIVITY_CONSOLE */
 
 const char parsers_h_rcs[] = PARSERS_H_VERSION;
 
@@ -472,12 +489,13 @@ const struct parsers client_patterns[] = {
    { "cookie:",                  7,    client_send_cookie },
    { "x-forwarded-for:",         16,   client_x_forwarded },
    { "Accept-Encoding:",         16,   client_accept_encoding },
-   { "TE:",                      3,    client_te },
-   { "Host:",                     5,   crumble },
+   { "TE:",                       3,   client_te },
+   { "Host:",                     5,   client_host },
 /* { "if-modified-since:",       18,   crumble }, */
    { "Keep-Alive:",              11,   crumble },
    { "connection:",              11,   crumble },
    { "proxy-connection:",        17,   crumble },
+   { "max-forwards:",            13,   client_max_forwards },
    { NULL,                       0,    NULL }
 };
 
@@ -501,7 +519,7 @@ const add_header_func_ptr add_client_headers[] = {
    client_cookie_adder,
    client_x_forwarded_adder,
    client_xtra_adder,
-   client_accept_encoding_adder,
+   /* Temporarily disabled:    client_accept_encoding_adder, */
    connection_close_adder,
    NULL
 };
@@ -815,7 +833,7 @@ char *sed(const struct parsers pats[],
  *********************************************************************/
 jb_err crumble(struct client_state *csp, char **header)
 {
-   log_error(LOG_LEVEL_HEADER, "crunch: %s",*header);
+   log_error(LOG_LEVEL_HEADER, "crunch!");
    freez(*header);
    return JB_ERR_OK;
 }
@@ -828,6 +846,9 @@ jb_err crumble(struct client_state *csp, char **header)
  * Description :  Set the content-type for filterable types (text/.*,
  *                javascript and image/gif) unless filtering has been
  *                forbidden (CT_TABOO) while parsing earlier headers.
+ *                NOTE: Since text/plain is commonly used by web servers
+ *                      for files whose correct type is unknown, we don't
+ *                      set CT_TEXT for it.
  *
  * Parameters  :
  *          1  :  csp = Current client state (buffers, headers, etc...)
@@ -844,7 +865,7 @@ jb_err server_content_type(struct client_state *csp, char **header)
 {
    if (csp->content_type != CT_TABOO)
    {
-      if (strstr(*header, " text/")
+      if ((strstr(*header, " text/") && !strstr(*header, "plain"))
        || strstr(*header, "application/x-javascript"))
          csp->content_type = CT_TEXT;
       else if (strstr(*header, " image/gif"))
@@ -1004,7 +1025,7 @@ jb_err server_content_md5(struct client_state *csp, char **header)
 {
    if (csp->flags & CSP_FLAG_MODIFIED)
    {
-      log_error(LOG_LEVEL_HEADER, "Crunching Content-MD5: %s", *header);
+      log_error(LOG_LEVEL_HEADER, "Crunching Content-MD5");
       freez(*header);
    }
 
@@ -1038,14 +1059,20 @@ jb_err client_accept_encoding(struct client_state *csp, char **header)
       log_error(LOG_LEVEL_HEADER, "Suppressed offer to compress content");
 
       freez(*header);
-      if (!strcmpic(csp->http->ver, "HTTP/1.1"))
-      {
-         *header = strdup("Accept-Encoding: identity;q=1.0, *;q=0");
-         if (*header == NULL)
-         {
-            return JB_ERR_MEMORY;
-         }
-      }
+
+      /* Temporarily disable the correct behaviour to
+       * work around a PHP bug. 
+       *
+       * if (!strcmpic(csp->http->ver, "HTTP/1.1"))
+       * {
+       *    *header = strdup("Accept-Encoding: identity;q=1.0, *;q=0");
+       *    if (*header == NULL)
+       *    {
+       *       return JB_ERR_MEMORY;
+       *    }
+       * }
+       * 
+       */
    }
 
    return JB_ERR_OK;
@@ -1102,7 +1129,6 @@ jb_err client_te(struct client_state *csp, char **header)
 jb_err client_referrer(struct client_state *csp, char **header)
 {
    const char *newval;
-   jb_err err = JB_ERR_OK;
 
 #ifdef FEATURE_FORCE_LOAD
    /* Since the referrer can include the prefix even
@@ -1113,74 +1139,58 @@ jb_err client_referrer(struct client_state *csp, char **header)
 #endif /* def FEATURE_FORCE_LOAD */
 
    /*
-    * As long as we're not blocking the referer...
+    * Are we sending referer?
     */
-   if ((csp->action->flags & ACTION_HIDE_REFERER) != 0)
+   if ((csp->action->flags & ACTION_HIDE_REFERER) == 0)
    {
+      return JB_ERR_OK;
+   }
 
-      newval = csp->action->string[ACTION_STRING_REFERER];
+   freez(*header);
 
-#ifdef FEATURE_ACTIVITY_CONSOLE
-      /* We are doing something with the referer. */
-      accumulate_stats(STATS_REFERER, 1);
-#endif /* def FEATURE_ACTIVITY_CONSOLE */
+   newval = csp->action->string[ACTION_STRING_REFERER];
 
+   if ((newval == NULL) || (0 == strcmpic(newval, "block")) )
+   {
       /*
-       * Note that each clause needs to freez the header pointer;
-       * but everybody needs to use it for logging purposes before
-       * it gets freed, so always free it just after logging it.
+       * Blocking referer
        */
-      if ((newval == NULL) || (0 == strcmpic(newval, "block")) )
-      {
-         /*
-          * Blocking referer
-          */
-         log_error(LOG_LEVEL_HEADER, "crunch: %s", *header);
-         freez(*header);
-         err = JB_ERR_OK;
-      }
-      else if (0 == strncmpic(newval, "http://", 7))
+      log_error(LOG_LEVEL_HEADER, "crunch!");
+      return JB_ERR_OK;
+   }
+   else if (0 == strncmpic(newval, "http://", 7))
+   {
+      /*
+       * We have a specific (fixed) referer we want to send.
+       */
+      log_error(LOG_LEVEL_HEADER, "modified");
+
+      *header = strdup("Referer: ");
+      string_append(header, newval);
+
+      return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK;
+   }
+   else
+   {
+      /*
+       * Forge a referer as http://[hostname:port of REQUEST]/
+       * to fool stupid checks for in-site links
+       */
+      if (0 != strcmpic(newval, "forge"))
       {
          /*
-          * We have a specific (fixed) referer we want to send.
+          * Invalid choice - but forge is probably the best default.
           */
-         log_error(LOG_LEVEL_HEADER, "modified: %s", *header);
-         freez(*header);
-         *header = strdup("Referer: ");
-         if (NULL == *header)
-            err = JB_ERR_MEMORY;
-         else
-            err = string_append(header, newval);
+         log_error(LOG_LEVEL_ERROR, "Bad parameter: +referer{%s}", newval);
       }
-      else
-      {
-         /*
-          * Forge a referer as http://[hostname:port of REQUEST]/
-          * to fool stupid checks for in-site links
-          */
-         if (0 != strcmpic(newval, "forge"))
-         {
-            /*
-             * Invalid choice - but forge is probably the best default.
-             */
-            log_error(LOG_LEVEL_ERROR, "Bad parameter: +referer{%s}", newval);
-         }
 
-         log_error(LOG_LEVEL_HEADER, "crunch+forge: %s", *header);
-         freez(*header);
-         *header = strdup("Referer: http://");
-         if (NULL == *header)
-            err = JB_ERR_MEMORY;
-         else
-         {
-            err = string_append(header, csp->http->hostport);
-            err = string_append(header, "/");
-            if (JB_ERR_OK == err)
-               log_error(LOG_LEVEL_HEADER, "crunch+forged to: %s", *header);
-         }
-      }
+      *header = strdup("Referer: http://");
+      string_append(header, csp->http->hostport);
+      string_append(header, "/");
+      log_error(LOG_LEVEL_HEADER, "crunch+forge to %s", *header);
+      
+      return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK;
    }
-   return err;
 }
 
 
@@ -1206,25 +1216,25 @@ jb_err client_referrer(struct client_state *csp, char **header)
 jb_err client_uagent(struct client_state *csp, char **header)
 {
    const char *newval;
-   jb_err err = JB_ERR_OK;
 
-   /*
-    * As long as we don't want to hide user-agent...
-    */
-   if ((csp->action->flags & ACTION_HIDE_USER_AGENT) != 0)
+   if ((csp->action->flags & ACTION_HIDE_USER_AGENT) == 0)
    {
-      newval = csp->action->string[ACTION_STRING_USER_AGENT];
-      if (NULL != newval)
-      {
-         log_error(LOG_LEVEL_HEADER, "modified: %s", *header);
+      return JB_ERR_OK;
+   }
 
-         freez(*header);
-         *header = strdup("User-Agent: ");
-         err = string_append(header, newval);
-      }
+   newval = csp->action->string[ACTION_STRING_USER_AGENT];
+   if (newval == NULL)
+   {
+      return JB_ERR_OK;
    }
 
-   return err;
+   log_error(LOG_LEVEL_HEADER, "modified");
+
+   freez(*header);
+   *header = strdup("User-Agent: ");
+   string_append(header, newval);
+
+   return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK;
 }
 
 
@@ -1249,10 +1259,7 @@ jb_err client_ua(struct client_state *csp, char **header)
 {
    if ((csp->action->flags & ACTION_HIDE_USER_AGENT) != 0)
    {
-#ifdef FEATURE_ACTIVITY_CONSOLE
-      accumulate_stats(STATS_CLIENT_UA, 1);
-#endif /* def FEATURE_ACTIVITY_CONSOLE */
-      log_error(LOG_LEVEL_HEADER, "crunch: %s", *header);
+      log_error(LOG_LEVEL_HEADER, "crunch!");
       freez(*header);
    }
 
@@ -1281,37 +1288,31 @@ jb_err client_ua(struct client_state *csp, char **header)
 jb_err client_from(struct client_state *csp, char **header)
 {
    const char *newval;
-   jb_err err = JB_ERR_OK;
 
-   /* 
-    * As long as we should handle the "from" setting...
-    */
-   if ((csp->action->flags & ACTION_HIDE_FROM) != 0)
+   if ((csp->action->flags & ACTION_HIDE_FROM) == 0)
    {
-#ifdef FEATURE_ACTIVITY_CONSOLE
-      /* We're doing something with it. */
-      accumulate_stats(STATS_CLIENT_FROM, 1);
-#endif /* def FEATURE_ACTIVITY_CONSOLE */
+      return JB_ERR_OK;
+   }
 
-      newval = csp->action->string[ACTION_STRING_FROM];
+   freez(*header);
 
-      /*
-       * Are we blocking the e-mail address?
-       */
-      if ((NULL == newval) || (0 == strcmpic(newval, "block")) )
-      {
-         log_error(LOG_LEVEL_HEADER, "crunch: %s", *header);
-         err = JB_ERR_OK;
-      }
-      else
-      {
-         log_error(LOG_LEVEL_HEADER, "modified: %s", *header);
-         freez(*header);
-         *header = strdup("From: ");
-         err = string_append(header, newval);
-      }
+   newval = csp->action->string[ACTION_STRING_FROM];
+
+   /*
+    * Are we blocking the e-mail address?
+    */
+   if ((newval == NULL) || (0 == strcmpic(newval, "block")) )
+   {
+      log_error(LOG_LEVEL_HEADER, "crunch!");
+      return JB_ERR_OK;
    }
-   return err;
+
+   log_error(LOG_LEVEL_HEADER, " modified");
+
+   *header = strdup("From: ");
+   string_append(header, newval);
+
+   return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK;
 }
 
 
@@ -1336,16 +1337,16 @@ jb_err client_from(struct client_state *csp, char **header)
  *********************************************************************/
 jb_err client_send_cookie(struct client_state *csp, char **header)
 {
-   jb_err err = JB_ERR_OK;
+   jb_err result = JB_ERR_OK;
 
    if ((csp->action->flags & ACTION_NO_COOKIE_READ) == 0)
    {
       /* strlen("cookie: ") == 8 */
-      err = enlist(csp->cookie_list, *header + 8);
+      result = enlist(csp->cookie_list, *header + 8);
    }
    else
    {
-      log_error(LOG_LEVEL_HEADER, "Crunched cookie: %s", *header);
+      log_error(LOG_LEVEL_HEADER, "Crunched outgoing cookie -- yum!");
    }
 
    /*
@@ -1354,7 +1355,7 @@ jb_err client_send_cookie(struct client_state *csp, char **header)
     */
    freez(*header);
 
-   return err;
+   return result;
 }
 
 
@@ -1392,66 +1393,176 @@ jb_err client_x_forwarded(struct client_state *csp, char **header)
    }
    else
    {
-#ifdef FEATURE_ACTIVITY_CONSOLE
-      accumulate_stats(STATS_CLIENT_X_FORWARDED, 1);
-#endif /* def FEATURE_ACTIVITY_CONSOLE */
-      log_error(LOG_LEVEL_HEADER, "crunch: %s", *header);
       freez(*header);
+      log_error(LOG_LEVEL_HEADER, " crunch!");
    }
 
    return JB_ERR_OK;
 }
 
-/* the following functions add headers directly to the header list */
 
 /*********************************************************************
  *
- * Function    :  client_host_adder
+ * Function    :  client_max_forwards
  *
- * Description :  (re)adds the host header. Called from `sed'.
+ * Description :  If the HTTP method is OPTIONS or TRACE, subtract one
+ *                from the value of the Max-Forwards header field.
  *
  * Parameters  :
  *          1  :  csp = Current client state (buffers, headers, etc...)
+ *          2  :  header = On input, pointer to header to modify.
+ *                On output, pointer to the modified header, or NULL
+ *                to remove the header.  This function frees the
+ *                original string if necessary.
  *
  * Returns     :  JB_ERR_OK on success, or
  *                JB_ERR_MEMORY on out-of-memory error.
  *
  *********************************************************************/
-jb_err client_host_adder(struct client_state *csp)
+jb_err client_max_forwards(struct client_state *csp, char **header)
 {
-   char *p;
-   char *pos;
-   jb_err err = JB_ERR_OK;
+   unsigned int max_forwards;
 
-   if ( csp->http->hostport && *(csp->http->hostport))
+   if ((0 == strcmpic(csp->http->gpc, "trace"))
+      || (0 == strcmpic(csp->http->gpc, "options")))
    {
-      p = strdup("Host: ");
-      if (NULL != p)
+      if (1 == sscanf(*header, "Max-Forwards: %u", &max_forwards))
       {
-         /*
-          * remove 'user:pass@' from 'proto://user:pass@host'
-          */
-         if ( (pos = strchr( csp->http->hostport, '@')) != NULL )
+         if (max_forwards-- >= 1)
          {
-             string_append(&p, pos+1);
+            sprintf(*header, "Max-Forwards: %u", max_forwards);
+            log_error(LOG_LEVEL_HEADER, "Max forwards of %s request now %d", csp->http->gpc, max_forwards);
          }
          else
          {
-            string_append(&p, csp->http->hostport);
+            log_error(LOG_LEVEL_ERROR, "Non-intercepted %s request with Max-Forwards zero!", csp->http->gpc);
          }
+      }
+   }
 
-         log_error(LOG_LEVEL_HEADER, "addh: %s", p);
+   return JB_ERR_OK;
+}
 
-         err = enlist(csp->headers, p);
 
+/*********************************************************************
+ *
+ * Function    :  client_host
+ *
+ * Description :  If the request URI did not contain host and
+ *                port information, parse and evaluate the Host
+ *                header field.
+ *
+ *                Also, kill ill-formed HOST: headers as sent by
+ *                Apple's iTunes software when used with a proxy.
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *          2  :  header = On input, pointer to header to modify.
+ *                On output, pointer to the modified header, or NULL
+ *                to remove the header.  This function frees the
+ *                original string if necessary.
+ *
+ * Returns     :  JB_ERR_OK on success, or
+ *                JB_ERR_MEMORY on out-of-memory error.
+ *
+ *********************************************************************/
+jb_err client_host(struct client_state *csp, char **header)
+{
+   char *p, *q;
+
+   /*
+    * If the header field name is all upper-case, chances are that it's
+    * an ill-formed one from iTunes. BTW, killing innocent headers here is
+    * not a problem -- they are regenerated later.
+    */
+   if ((*header)[1] == 'O')
+   {
+      log_error(LOG_LEVEL_HEADER, "Killed all-caps Host header line: %s", *header);
+      freez(*header);
+      return JB_ERR_OK;
+   }
+
+   if (!csp->http->hostport || (*csp->http->hostport == '*') ||  
+       *csp->http->hostport == ' ' || *csp->http->hostport == '\0')
+   {
+      
+      if (NULL == (p = strdup((*header)+6)))
+      {
+         return JB_ERR_MEMORY;
+      }
+      chomp(p);
+      if (NULL == (q = strdup(p)))
+      {
          freez(p);
+         return JB_ERR_MEMORY;
+      }
+
+      freez(csp->http->hostport);
+      csp->http->hostport = p;
+      freez(csp->http->host);
+      csp->http->host = q;
+      q = strchr(csp->http->host, ':');
+      if (q != NULL)
+      {
+         /* Terminate hostname and evaluate port string */
+         *q++ = '\0';
+         csp->http->port = atoi(q);
       }
       else
       {
-         err = JB_ERR_MEMORY;
+         csp->http->port = csp->http->ssl ? 443 : 80;
       }
+
+      log_error(LOG_LEVEL_HEADER, "New host and port from Host field: %s = %s:%d",
+                csp->http->hostport, csp->http->host, csp->http->port);
+   }
+
+   return JB_ERR_OK;
+}
+
+
+/* the following functions add headers directly to the header list */
+
+/*********************************************************************
+ *
+ * Function    :  client_host_adder
+ *
+ * Description :  Adds the Host: header field if it is missing.
+ *                Called from `sed'.
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  JB_ERR_OK on success, or
+ *                JB_ERR_MEMORY on out-of-memory error.
+ *
+ *********************************************************************/
+jb_err client_host_adder(struct client_state *csp)
+{
+   char *p;
+   jb_err err;
+
+   if ( !csp->http->hostport || !*(csp->http->hostport))
+   {
+      return JB_ERR_OK;
    }
+
+   /*
+    * remove 'user:pass@' from 'proto://user:pass@host'
+    */
+   if ( (p = strchr( csp->http->hostport, '@')) != NULL )
+   {
+      p++;
+   }
+   else
+   {
+      p = csp->http->hostport;
+   }
+
+   log_error(LOG_LEVEL_HEADER, "addh-unique: Host: %s", p);
+   err = enlist_unique_header(csp->headers, "Host", p);
    return err;
+
 }
 
 
@@ -1475,47 +1586,50 @@ jb_err client_cookie_adder(struct client_state *csp)
    struct list_entry *list1 = csp->cookie_list->first;
    struct list_entry *list2 = csp->action->multi[ACTION_MULTI_WAFER]->first;
    int first_cookie = 1;
-   jb_err err = JB_ERR_OK;
+   jb_err err;
 
-   if ((list1 != NULL) || (list2 != NULL))
+   if ((list1 == NULL) && (list2 == NULL))
    {
-      tmp = strdup("Cookie: ");
-      if (NULL != tmp)
+      /* Nothing to do */
+      return JB_ERR_OK;
+   }
+
+   tmp = strdup("Cookie: ");
+
+   for (lst = list1; lst ; lst = lst->next)
+   {
+      if (first_cookie)
       {
-         for (lst = list1; lst ; lst = lst->next)
-         {
-            if (first_cookie)
-            {
-               first_cookie = 0;
-            }
-            else
-            {
-               string_append(&tmp, "; ");
-            }
-            string_append(&tmp, lst->str);
-         }
+         first_cookie = 0;
+      }
+      else
+      {
+         string_append(&tmp, "; ");
+      }
+      string_append(&tmp, lst->str);
+   }
 
-         for (lst = list2;  lst ; lst = lst->next)
-         {
-            if (first_cookie)
-            {
-               first_cookie = 0;
-            }
-            else
-            {
-               string_append(&tmp, "; ");
-            }
-            string_join(&tmp, cookie_encode(lst->str));
-         }
-         log_error(LOG_LEVEL_HEADER, "addh: %s", tmp);
-         err = enlist(csp->headers, tmp);
-         free(tmp);
+   for (lst = list2;  lst ; lst = lst->next)
+   {
+      if (first_cookie)
+      {
+         first_cookie = 0;
       }
       else
       {
-         err = JB_ERR_MEMORY;
+         string_append(&tmp, "; ");
       }
+      string_join(&tmp, cookie_encode(lst->str));
    }
+
+   if (tmp == NULL)
+   {
+      return JB_ERR_MEMORY;
+   }
+
+   log_error(LOG_LEVEL_HEADER, "addh: %s", tmp);
+   err = enlist(csp->headers, tmp);
+   free(tmp);
    return err;
 }
 
@@ -1598,29 +1712,33 @@ jb_err client_xtra_adder(struct client_state *csp)
 jb_err client_x_forwarded_adder(struct client_state *csp)
 {
    char *p = NULL;
-   jb_err err = JB_ERR_OK;
+   jb_err err;
 
-   if (0 == (csp->action->flags & ACTION_HIDE_FORWARDED))
+   if ((csp->action->flags & ACTION_HIDE_FORWARDED) != 0)
    {
+      return JB_ERR_OK;
+   }
 
-      if (csp->x_forwarded)
-      {
-         p = strdup(csp->x_forwarded);
-         err = string_append(&p, ", ");
-      }
-      else
-      {
-         p = strdup("X-Forwarded-For: ");
-      }
-      err = string_append(&p, csp->ip_addr_str);
+   if (csp->x_forwarded)
+   {
+      p = strdup(csp->x_forwarded);
+      string_append(&p, ", ");
+   }
+   else
+   {
+      p = strdup("X-Forwarded-For: ");
+   }
+   string_append(&p, csp->ip_addr_str);
 
-      if (NULL != p)
-      {
-         log_error(LOG_LEVEL_HEADER, "addh: %s", p);
-         err = enlist(csp->headers, p);
-         freez(p);
-      }
+   if (p == NULL)
+   {
+      return JB_ERR_MEMORY;
    }
+
+   log_error(LOG_LEVEL_HEADER, "addh: %s", p);
+   err = enlist(csp->headers, p);
+   free(p);
+
    return err;
 }
 
@@ -1707,8 +1825,6 @@ jb_err server_http(struct client_state *csp, char **header)
  *********************************************************************/
 jb_err server_set_cookie(struct client_state *csp, char **header)
 {
-   jb_err err = JB_ERR_OK;
-
 #ifdef FEATURE_COOKIE_JAR
    if (csp->config->jar)
    {
@@ -1741,10 +1857,7 @@ jb_err server_set_cookie(struct client_state *csp, char **header)
    if ((csp->action->flags & ACTION_NO_COOKIE_SET) != 0)
    {
       log_error(LOG_LEVEL_HEADER, "Crunched incoming cookie -- yum!");
-#ifdef FEATURE_ACTIVITY_CONSOLE
-      accumulate_stats(STATS_COOKIE, 1);
-#endif /* def FEATURE_ACTIVITY_CONSOLE */
-      err = crumble(csp, header);
+      return crumble(csp, header);
    }
    else if ((csp->action->flags & ACTION_NO_COOKIE_KEEP) != 0)
    {
@@ -1815,7 +1928,7 @@ jb_err server_set_cookie(struct client_state *csp, char **header)
       }
    }
 
-   return err;
+   return JB_ERR_OK;
 }