Replaced "list_share" with "list" - the tiny memory gain was not
[privoxy.git] / parsers.c
index ae6c1f4..14e92ac 100644 (file)
--- a/parsers.c
+++ b/parsers.c
@@ -1,4 +1,4 @@
-const char parsers_rcs[] = "$Id: parsers.c,v 1.1.1.1 2001/05/15 13:59:01 oes Exp $";
+const char parsers_rcs[] = "$Id: parsers.c,v 1.13 2001/05/31 21:30:33 jongfoster Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/parsers.c,v $
@@ -11,7 +11,7 @@ const char parsers_rcs[] = "$Id: parsers.c,v 1.1.1.1 2001/05/15 13:59:01 oes Exp
  *                   `client_x_forwarded_adder', `client_xtra_adder',
  *                   `content_type', `crumble', `destroy_list', `enlist',
  *                   `flush_socket', `free_http_request', `get_header',
- *                   `list_to_text', `match', `parse_http_request', `sed',
+ *                   `list_to_text', `parse_http_request', `sed',
  *                   and `server_set_cookie'.
  *
  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
@@ -41,6 +41,133 @@ const char parsers_rcs[] = "$Id: parsers.c,v 1.1.1.1 2001/05/15 13:59:01 oes Exp
  *
  * Revisions   :
  *    $Log: parsers.c,v $
+ *    Revision 1.13  2001/05/31 21:30:33  jongfoster
+ *    Removed list code - it's now in list.[ch]
+ *    Renamed "permission" to "action", and changed many features
+ *    to use the actions file rather than the global config.
+ *
+ *    Revision 1.12  2001/05/31 17:33:13  oes
+ *
+ *    CRLF -> LF
+ *
+ *    Revision 1.11  2001/05/29 20:11:19  joergs
+ *    '/* inside comment' warning removed.
+ *
+ *    Revision 1.10  2001/05/29 09:50:24  jongfoster
+ *    Unified blocklist/imagelist/permissionslist.
+ *    File format is still under discussion, but the internal changes
+ *    are (mostly) done.
+ *
+ *    Also modified interceptor behaviour:
+ *    - We now intercept all URLs beginning with one of the following
+ *      prefixes (and *only* these prefixes):
+ *        * http://i.j.b/
+ *        * http://ijbswa.sf.net/config/
+ *        * http://ijbswa.sourceforge.net/config/
+ *    - New interceptors "home page" - go to http://i.j.b/ to see it.
+ *    - Internal changes so that intercepted and fast redirect pages
+ *      are not replaced with an image.
+ *    - Interceptors now have the option to send a binary page direct
+ *      to the client. (i.e. ijb-send-banner uses this)
+ *    - Implemented show-url-info interceptor.  (Which is why I needed
+ *      the above interceptors changes - a typical URL is
+ *      "http://i.j.b/show-url-info?url=www.somesite.com/banner.gif".
+ *      The previous mechanism would not have intercepted that, and
+ *      if it had been intercepted then it then it would have replaced
+ *      it with an image.)
+ *
+ *    Revision 1.9  2001/05/28 17:26:33  jongfoster
+ *    Fixing segfault if last header was crunched.
+ *    Fixing Windows build (snprintf() is _snprintf() under Win32, but we
+ *    can use the cross-platform sprintf() instead.)
+ *
+ *    Revision 1.8  2001/05/27 22:17:04  oes
+ *
+ *    - re_process_buffer no longer writes the modified buffer
+ *      to the client, which was very ugly. It now returns the
+ *      buffer, which it is then written by chat.
+ *
+ *    - content_length now adjusts the Content-Length: header
+ *      for modified documents rather than crunch()ing it.
+ *      (Length info in csp->content_length, which is 0 for
+ *      unmodified documents)
+ *
+ *    - For this to work, sed() is called twice when filtering.
+ *
+ *    Revision 1.7  2001/05/27 13:19:06  oes
+ *    Patched Joergs solution for the content-length in.
+ *
+ *    Revision 1.6  2001/05/26 13:39:32  jongfoster
+ *    Only crunches Content-Length header if applying RE filtering.
+ *    Without this fix, Microsoft Windows Update wouldn't work.
+ *
+ *    Revision 1.5  2001/05/26 00:28:36  jongfoster
+ *    Automatic reloading of config file.
+ *    Removed obsolete SIGHUP support (Unix) and Reload menu option (Win32).
+ *    Most of the global variables have been moved to a new
+ *    struct configuration_spec, accessed through csp->config->globalname
+ *    Most of the globals remaining are used by the Win32 GUI.
+ *
+ *    Revision 1.4  2001/05/22 18:46:04  oes
+ *
+ *    - Enabled filtering banners by size rather than URL
+ *      by adding patterns that replace all standard banner
+ *      sizes with the "Junkbuster" gif to the re_filterfile
+ *
+ *    - Enabled filtering WebBugs by providing a pattern
+ *      which kills all 1x1 images
+ *
+ *    - Added support for PCRE_UNGREEDY behaviour to pcrs,
+ *      which is selected by the (nonstandard and therefore
+ *      capital) letter 'U' in the option string.
+ *      It causes the quantifiers to be ungreedy by default.
+ *      Appending a ? turns back to greedy (!).
+ *
+ *    - Added a new interceptor ijb-send-banner, which
+ *      sends back the "Junkbuster" gif. Without imagelist or
+ *      MSIE detection support, or if tinygif = 1, or the
+ *      URL isn't recognized as an imageurl, a lame HTML
+ *      explanation is sent instead.
+ *
+ *    - Added new feature, which permits blocking remote
+ *      script redirects and firing back a local redirect
+ *      to the browser.
+ *      The feature is conditionally compiled, i.e. it
+ *      can be disabled with --disable-fast-redirects,
+ *      plus it must be activated by a "fast-redirects"
+ *      line in the config file, has its own log level
+ *      and of course wants to be displayed by show-proxy-args
+ *      Note: Boy, all the #ifdefs in 1001 locations and
+ *      all the fumbling with configure.in and acconfig.h
+ *      were *way* more work than the feature itself :-(
+ *
+ *    - Because a generic redirect template was needed for
+ *      this, tinygif = 3 now uses the same.
+ *
+ *    - Moved GIFs, and other static HTTP response templates
+ *      to project.h
+ *
+ *    - Some minor fixes
+ *
+ *    - Removed some >400 CRs again (Jon, you really worked
+ *      a lot! ;-)
+ *
+ *    Revision 1.3  2001/05/20 01:21:20  jongfoster
+ *    Version 2.9.4 checkin.
+ *    - Merged popupfile and cookiefile, and added control over PCRS
+ *      filtering, in new "permissionsfile".
+ *    - Implemented LOG_LEVEL_FATAL, so that if there is a configuration
+ *      file error you now get a message box (in the Win32 GUI) rather
+ *      than the program exiting with no explanation.
+ *    - Made killpopup use the PCRS MIME-type checking and HTTP-header
+ *      skipping.
+ *    - Removed tabs from "config"
+ *    - Moved duplicated url parsing code in "loaders.c" to a new funcition.
+ *    - Bumped up version number.
+ *
+ *    Revision 1.2  2001/05/17 23:02:36  oes
+ *     - Made referrer option accept 'L' as a substitute for '§'
+ *
  *    Revision 1.1.1.1  2001/05/15 13:59:01  oes
  *    Initial import of version 2.9.3 source tree
  *
@@ -61,6 +188,7 @@ const char parsers_rcs[] = "$Id: parsers.c,v 1.1.1.1 2001/05/15 13:59:01 oes Exp
 #endif
 
 #include "project.h"
+#include "list.h"
 #include "parsers.h"
 #include "encode.h"
 #include "filters.h"
@@ -111,18 +239,22 @@ const struct parsers client_patterns[] = {
 
 const struct interceptors intercept_patterns[] = {
    { "show-proxy-args",    14, show_proxy_args },
+   { "ijb-send-banner",    14, ijb_send_banner },
 #ifdef TRUST_FILES
-   { "ij-untrusted-url",   14, ij_untrusted_url },
+   { "ij-untrusted-url",   15, ij_untrusted_url },
 #endif /* def TRUST_FILES */
+   { "show-url-info",      13, ijb_show_url_info },
    { NULL, 0, NULL }
 };
 
 const struct parsers server_patterns[] = {
    { "set-cookie:",        11, server_set_cookie },
    { "connection:",        11, crumble },
-#ifdef PCRS
+#if defined(PCRS) || defined(KILLPOPUPS)
    { "Content-Type:",      13, content_type },
-   { "Content-Length:",    15, crumble },
+#endif /* defined(PCRS) || defined(KILLPOPUPS) */
+#ifdef PCRS
+   { "Content-Length:",    15, content_length },
 #endif /* def PCRS */
    { NULL, 0, NULL }
 };
@@ -141,43 +273,6 @@ void (* const add_server_headers[])(struct client_state *) = {
 };
 
 
-/*********************************************************************
- *
- * Function    :  match
- *
- * Description :  Do a `strncmpic' on every pattern in pats.
- *
- * Parameters  :
- *          1  :  buf = a string to match to a list of patterns
- *          2  :  pats = list of strings to compare against buf.
- *
- * Returns     :  Return the matching "struct parsers *",
- *                or NULL if no pattern matches.
- *
- *********************************************************************/
-static const struct parsers *match(char *buf, const struct parsers *pats)
-{
-   const struct parsers *v;
-
-   if (buf == NULL)
-   {
-      /* hit me */
-      log_error(LOG_LEVEL_ERROR, "NULL parameter to match()");
-      return(NULL);
-   }
-
-   for (v = pats; v->str ; v++)
-   {
-      if (strncmpic(buf, v->str, v->len) == 0)
-      {
-         return(v);
-      }
-   }
-   return(NULL);
-
-}
-
-
 /*********************************************************************
  *
  * Function    :  flush_socket
@@ -334,125 +429,6 @@ char *get_header(struct client_state *csp)
 }
 
 
-/*********************************************************************
- *
- * Function    :  enlist
- *
- * Description :  Append a string into a specified string list.
- *
- * Parameters  :
- *          1  :  h = pointer to list 'dummy' header
- *          2  :  s = string to add to the list
- *
- * Returns     :  N/A
- *
- *********************************************************************/
-void enlist(struct list *h, const char *s)
-{
-   struct list *n = (struct list *)malloc(sizeof(*n));
-   struct list *l;
-
-   if (n)
-   {
-      n->str  = strdup(s);
-      n->next = NULL;
-
-      if ((l = h->last))
-      {
-         l->next = n;
-      }
-      else
-      {
-         h->next = n;
-      }
-
-      h->last = n;
-   }
-
-}
-
-
-/*********************************************************************
- *
- * Function    :  destroy_list
- *
- * Description :  Destroy a string list (opposite of enlist)
- *
- * Parameters  :
- *          1  :  h = pointer to list 'dummy' header
- *
- * Returns     :  N/A
- *
- *********************************************************************/
-void destroy_list(struct list *h)
-{
-   struct list *p, *n;
-
-   for (p = h->next; p ; p = n)
-   {
-      n = p->next;
-      freez(p->str);
-      freez(p);
-   }
-
-   memset(h, '\0', sizeof(*h));
-
-}
-
-
-/*********************************************************************
- *
- * Function    :  list_to_text
- *
- * Description :  "Flaten" a string list into 1 long \r\n delimited string.
- *
- * Parameters  :
- *          1  :  h = pointer to list 'dummy' header
- *
- * Returns     :  NULL on malloc error, else new long string.
- *
- *********************************************************************/
-static char *list_to_text(struct list *h)
-{
-   struct list *p;
-   char *ret = NULL;
-   char *s;
-   int size;
-
-   size = 0;
-
-   for (p = h->next; p ; p = p->next)
-   {
-      if (p->str)
-      {
-         size += strlen(p->str) + 2;
-      }
-   }
-
-   if ((ret = (char *)malloc(size + 1)) == NULL)
-   {
-      return(NULL);
-   }
-
-   ret[size] = '\0';
-
-   s = ret;
-
-   for (p = h->next; p ; p = p->next)
-   {
-      if (p->str)
-      {
-         strcpy(s, p->str);
-         s += strlen(s);
-         *s++ = '\r'; *s++ = '\n';
-      }
-   }
-
-   return(ret);
-
-}
-
-
 /*********************************************************************
  *
  * Function    :  sed
@@ -481,17 +457,22 @@ char *sed(const struct parsers pats[], void (* const more_headers[])(struct clie
    char *hdr;
    void (* const *f)();
 
-   for (p = csp->headers->next; p ; p = p->next)
+   for (v = pats; v->str ; v++)
    {
-      log_error(LOG_LEVEL_HEADER, "scan: %s", p->str);
-
-      if ((v = match(p->str, pats)))
+      for (p = csp->headers->next; p ; p = p->next)
       {
-         hdr = v->parser(v, p->str, csp);
-         freez(p->str);
-         p->str = hdr;
-      }
+         /* Header crunch()ed in previous run? -> ignore */
+         if (p->str == NULL) continue;
 
+         if (v == pats) log_error(LOG_LEVEL_HEADER, "scan: %s", p->str);
+
+         if (strncmpic(p->str, v->str, v->len) == 0)
+         {
+            hdr = v->parser(v, p->str, csp);
+            freez(p->str);
+            p->str = hdr;
+         }
+      }
    }
 
    /* place any additional headers on the csp->headers list */
@@ -500,8 +481,13 @@ char *sed(const struct parsers pats[], void (* const more_headers[])(struct clie
       (*f)(csp);
    }
 
-   /* add the blank line at the end of the header */
-   enlist(csp->headers, "");
+   /* add the blank line at the end of the header, if necessary */
+   if ( (csp->headers->last == NULL)
+     || (csp->headers->last->str == NULL)
+     || (*csp->headers->last->str != '\0') )
+   {
+      enlist(csp->headers, "");
+   }
 
    hdr = list_to_text(csp->headers);
 
@@ -707,13 +693,13 @@ char *crumble(const struct parsers *v, char *s, struct client_state *csp)
 }
 
 
-#ifdef PCRS
+#if defined(PCRS) || defined(KILLPOPUPS)
 
 /*********************************************************************
  *
  * Function    :  content_type
  *
- * Description :  Is this a text/* or javascript MIME Type?
+ * Description :  Is this a text/.* or javascript MIME Type?
  *
  * Parameters  :
  *          1  :  v = ignored
@@ -733,6 +719,39 @@ char *content_type(const struct parsers *v, char *s, struct client_state *csp)
    return(strdup(s));
 
 }
+#endif /* defined(PCRS) || defined(KILLPOPUPS) */
+
+
+#ifdef PCRS
+/*********************************************************************
+ *
+ * Function    :  content_length
+ *
+ * Description :  Crunch Content-Length header if & only if we are
+ *                filtering this page through PCRS.
+ *
+ * Parameters  :
+ *          1  :  v = ignored
+ *          2  :  s = header string we are "considering"
+ *          3  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  A duplicate string pointer to this header (ie. pass thru)
+ *
+ *********************************************************************/
+char *content_length(const struct parsers *v, char *s, struct client_state *csp)
+{
+   if (csp->content_length != 0) /* Content has been modified */
+       {
+          s = (char *) zalloc(100);
+          sprintf(s, "Content-Length: %d", csp->content_length);
+               log_error(LOG_LEVEL_HEADER, "Adjust Content-Length to %d", csp->content_length);
+          return(s);
+       }
+   else
+   {
+      return(strdup(s));
+   }
+}
 
 #endif /* def PCRS */
 
@@ -755,6 +774,7 @@ char *content_type(const struct parsers *v, char *s, struct client_state *csp)
  *********************************************************************/
 char *client_referrer(const struct parsers *v, char *s, struct client_state *csp)
 {
+   const char * newval;
 #ifdef FORCE_LOAD
    /* Since the referrer can include the prefix even
     * even if the request itself is non-forced, we must
@@ -763,60 +783,77 @@ char *client_referrer(const struct parsers *v, char *s, struct client_state *csp
    strclean(s, FORCE_PREFIX);
 #endif /* def FORCE_LOAD */
 
+#ifdef TRUST_FILES
    csp->referrer = strdup(s);
+#endif /* def TRUST_FILES */
 
-   if (referrer == NULL)
+   /*
+    * Are we sending referer?
+    */
+   if ((csp->action->flags & ACTION_HIDE_REFERER) == 0)
    {
-      log_error(LOG_LEVEL_HEADER, "crunch!");
-      return(NULL);
+      return(strdup(s));
    }
 
-   if (*referrer == '.')
+   newval = csp->action->string[ACTION_STRING_REFERER];
+
+   /*
+    * Are we blocking referer?
+    */
+   if ((newval == NULL) || (0 == strcmpic(newval, "block")) )
    {
-      return(strdup(s));
+      log_error(LOG_LEVEL_HEADER, "crunch!");
+      return(NULL);
    }
 
-   if (*referrer == '@')
+   /*
+    * Are we forging referer?
+    */
+   if (0 == strcmpic(newval, "forge"))
    {
-      if (csp->send_user_cookie)
-      {
-         return(strdup(s));
-      }
-      else
-      {
-         log_error(LOG_LEVEL_HEADER, "crunch!");
-         return(NULL);
-      }
+      /*
+       * Forge a referer as http://[hostname:port of REQUEST]/
+       * to fool stupid checks for in-site links
+       */
+      log_error(LOG_LEVEL_HEADER, "crunch+forge!");
+      s = strsav(NULL, "Referer: ");
+      s = strsav(s, "http://");
+      s = strsav(s, csp->http->hostport);
+      s = strsav(s, "/");
+      return(s);
    }
 
    /*
-    * New option § or L: Forge a referer as http://[hostname:port of REQUEST]/
-    * to fool stupid checks for in-site links
+    * Have we got a fixed referer?
     */
-
-   if (*referrer == '§' || *referrer == 'L')
+   if (0 == strncmpic(newval, "http://", 7))
    {
-      if (csp->send_user_cookie)
-      {
-         return(strdup(s));
-      }
-      else
-      {
-         log_error(LOG_LEVEL_HEADER, "crunch+forge!");
-         s = strsav(NULL, "Referer: ");
-         s = strsav(s, "http://");
-         s = strsav(s, csp->http->hostport);
-         s = strsav(s, "/");
-         return(s);
-      }
+      /*
+       * We have a specific (fixed) referer we want to send.
+       */
+
+      log_error(LOG_LEVEL_HEADER, "modified");
+
+      s = strsav( NULL, "Referer: " );
+      s = strsav( s, newval );
+      return(s);
    }
 
-   log_error(LOG_LEVEL_HEADER, "modified");
+   /* Should never get here! */
+   log_error(LOG_LEVEL_ERROR, "Bad parameter: +referer{%s}", newval);
 
-   s = strsav( NULL, "Referer: " );
-   s = strsav( s, referrer );
+   /*
+    * Forge is probably the best default.
+    *
+    * Forge a referer as http://[hostname:port of REQUEST]/
+    * to fool stupid checks for in-site links
+    */
+   log_error(LOG_LEVEL_HEADER, "crunch+forge!");
+   s = strsav(NULL, "Referer: ");
+   s = strsav(s, "http://");
+   s = strsav(s, csp->http->hostport);
+   s = strsav(s, "/");
    return(s);
-
 }
 
 
@@ -838,6 +875,8 @@ char *client_referrer(const struct parsers *v, char *s, struct client_state *csp
  *********************************************************************/
 char *client_uagent(const struct parsers *v, char *s, struct client_state *csp)
 {
+   const char * newval;
+
 #ifdef DETECT_MSIE_IMAGES
    if (strstr (s, "MSIE "))
    {
@@ -848,34 +887,21 @@ char *client_uagent(const struct parsers *v, char *s, struct client_state *csp)
    }
 #endif /* def DETECT_MSIE_IMAGES */
 
-   if (uagent == NULL)
-   {
-      log_error(LOG_LEVEL_HEADER, "default");
-      return(strdup(DEFAULT_USER_AGENT));
-   }
-
-   if (*uagent == '.')
+   if ((csp->action->flags & ACTION_HIDE_USER_AGENT) == 0)
    {
       return(strdup(s));
    }
 
-   if (*uagent == '@')
+   newval = csp->action->string[ACTION_STRING_USER_AGENT];
+   if (newval == NULL)
    {
-      if (csp->send_user_cookie)
-      {
-         return(strdup(s));
-      }
-      else
-      {
-         log_error(LOG_LEVEL_HEADER, "default");
-         return(strdup(DEFAULT_USER_AGENT));
-      }
+      return(strdup(s));
    }
 
    log_error(LOG_LEVEL_HEADER, "modified");
 
    s = strsav( NULL, "User-Agent: " );
-   s = strsav( s, uagent );
+   s = strsav( s, newval );
    return(s);
 
 }
@@ -897,33 +923,15 @@ char *client_uagent(const struct parsers *v, char *s, struct client_state *csp)
  *********************************************************************/
 char *client_ua(const struct parsers *v, char *s, struct client_state *csp)
 {
-   if (uagent == NULL)
-   {
-      log_error(LOG_LEVEL_HEADER, "crunch!");
-      return(NULL);
-   }
-
-   if (*uagent == '.')
+   if ((csp->action->flags & ACTION_HIDE_USER_AGENT) == 0)
    {
       return(strdup(s));
    }
-
-   if (*uagent == '@')
+   else
    {
-      if (csp->send_user_cookie)
-      {
-         return(strdup(s));
-      }
-      else
-      {
-         log_error(LOG_LEVEL_HEADER, "crunch!");
-         return(NULL);
-      }
+      log_error(LOG_LEVEL_HEADER, "crunch!");
+      return(NULL);
    }
-
-   log_error(LOG_LEVEL_HEADER, "crunch!");
-   return(NULL);
-
 }
 
 
@@ -945,22 +953,28 @@ char *client_ua(const struct parsers *v, char *s, struct client_state *csp)
  *********************************************************************/
 char *client_from(const struct parsers *v, char *s, struct client_state *csp)
 {
-   /* if not set, zap it */
-   if (from == NULL)
+   const char * newval;
+
+   if ((csp->action->flags & ACTION_HIDE_FROM) == 0)
    {
-      log_error(LOG_LEVEL_HEADER, "crunch!");
-      return(NULL);
+      return(strdup(s));
    }
 
-   if (*from == '.')
+   newval = csp->action->string[ACTION_STRING_FROM];
+
+   /*
+    * Are we blocking referer?
+    */
+   if ((newval == NULL) || (0 == strcmpic(newval, "block")) )
    {
-      return(strdup(s));
+      log_error(LOG_LEVEL_HEADER, "crunch!");
+      return(NULL);
    }
 
    log_error(LOG_LEVEL_HEADER, " modified");
 
    s = strsav( NULL, "From: " );
-   s = strsav( s, from );
+   s = strsav( s, newval );
    return(s);
 
 }
@@ -984,7 +998,7 @@ char *client_from(const struct parsers *v, char *s, struct client_state *csp)
  *********************************************************************/
 char *client_send_cookie(const struct parsers *v, char *s, struct client_state *csp)
 {
-   if (csp->send_user_cookie)
+   if ((csp->action->flags & ACTION_NO_COOKIE_READ) == 0)
    {
       enlist(csp->cookie_list, s + v->len + 1);
    }
@@ -1019,8 +1033,9 @@ char *client_send_cookie(const struct parsers *v, char *s, struct client_state *
  *********************************************************************/
 char *client_x_forwarded(const struct parsers *v, char *s, struct client_state *csp)
 {
-   if (add_forwarded)
+   if ((csp->action->flags & ACTION_HIDE_FORWARDED) == 0)
    {
+      /* Save it so we can re-add it later */
       csp->x_forwarded = strdup(s);
    }
 
@@ -1091,27 +1106,27 @@ char *client_accept(const struct parsers *v, char *s, struct client_state *csp)
  *********************************************************************/
 void client_cookie_adder(struct client_state *csp)
 {
-   struct list *l;
+   struct list *lst;
    char *tmp = NULL;
    char *e;
 
-   for (l = csp->cookie_list->next; l ; l = l->next)
+   for (lst = csp->cookie_list->next; lst ; lst = lst->next)
    {
       if (tmp)
       {
          tmp = strsav(tmp, "; ");
       }
-      tmp = strsav(tmp, l->str);
+      tmp = strsav(tmp, lst->str);
    }
 
-   for (l = wafer_list->next;  l ; l = l->next)
+   for (lst = csp->action->multi[ACTION_MULTI_WAFER]->next;  lst ; lst = lst->next)
    {
       if (tmp)
       {
          tmp = strsav(tmp, "; ");
       }
 
-      if ((e = cookie_encode(l->str)))
+      if ((e = cookie_encode(lst->str)))
       {
          tmp = strsav(tmp, e);
          freez(e);
@@ -1147,12 +1162,12 @@ void client_cookie_adder(struct client_state *csp)
  *********************************************************************/
 void client_xtra_adder(struct client_state *csp)
 {
-   struct list *l;
+   struct list *lst = csp->action->multi[ACTION_MULTI_ADD_HEADER];
 
-   for (l = xtra_list->next; l ; l = l->next)
+   for (lst = lst->next; lst ; lst = lst->next)
    {
-      log_error(LOG_LEVEL_HEADER, "addh: %s", l->str);
-      enlist(csp->headers, l->str);
+      log_error(LOG_LEVEL_HEADER, "addh: %s", lst->str);
+      enlist(csp->headers, lst->str);
    }
 
 }
@@ -1174,7 +1189,10 @@ void client_x_forwarded_adder(struct client_state *csp)
 {
    char *p = NULL;
 
-   if (add_forwarded == 0) return;
+   if ((csp->action->flags & ACTION_HIDE_FORWARDED) != 0)
+   {
+      return;
+   }
 
    if (csp->x_forwarded)
    {
@@ -1213,13 +1231,13 @@ void client_x_forwarded_adder(struct client_state *csp)
 char *server_set_cookie(const struct parsers *v, char *s, struct client_state *csp)
 {
 #ifdef JAR_FILES
-   if (jar)
+   if (csp->config->jar)
    {
-      fprintf(jar, "%s\t%s\n", csp->http->host, (s + v->len + 1));
+      fprintf(csp->config->jar, "%s\t%s\n", csp->http->host, (s + v->len + 1));
    }
 #endif /* def JAR_FILES */
 
-   if (csp->accept_server_cookie == 0)
+   if ((csp->action->flags & ACTION_NO_COOKIE_SET) != 0)
    {
       return(crumble(v, s, csp));
    }