Broadening scope of bwp.* ads.
[privoxy.git] / parsers.c
index 14ce3b6..df7538a 100644 (file)
--- a/parsers.c
+++ b/parsers.c
@@ -1,4 +1,4 @@
-const char parsers_rcs[] = "$Id: parsers.c,v 1.96 2007/04/12 12:53:58 fabiankeil Exp $";
+const char parsers_rcs[] = "$Id: parsers.c,v 1.103 2007/06/01 16:31:54 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/parsers.c,v $
@@ -44,6 +44,34 @@ const char parsers_rcs[] = "$Id: parsers.c,v 1.96 2007/04/12 12:53:58 fabiankeil
  *
  * Revisions   :
  *    $Log: parsers.c,v $
+ *    Revision 1.103  2007/06/01 16:31:54  fabiankeil
+ *    Change sed() to return a jb_err in preparation for forward-override{}.
+ *
+ *    Revision 1.102  2007/05/27 12:39:32  fabiankeil
+ *    Adjust "X-Filter: No" to disable dedicated header filters.
+ *
+ *    Revision 1.101  2007/05/14 10:16:41  fabiankeil
+ *    Streamline client_cookie_adder().
+ *
+ *    Revision 1.100  2007/04/30 15:53:11  fabiankeil
+ *    Make sure filters with dynamic jobs actually use them.
+ *
+ *    Revision 1.99  2007/04/30 15:06:26  fabiankeil
+ *    - Introduce dynamic pcrs jobs that can resolve variables.
+ *    - Remove unnecessary update_action_bits_for_all_tags() call.
+ *
+ *    Revision 1.98  2007/04/17 18:32:10  fabiankeil
+ *    - Make tagging based on tags set by earlier taggers
+ *      of the same kind possible.
+ *    - Log whether or not new tags cause action bits updates
+ *      (in which case a matching tag-pattern section exists).
+ *    - Log if the user tries to set a tag that is already set.
+ *
+ *    Revision 1.97  2007/04/15 16:39:21  fabiankeil
+ *    Introduce tags as alternative way to specify which
+ *    actions apply to a request. At the moment tags can be
+ *    created based on client and server headers.
+ *
  *    Revision 1.96  2007/04/12 12:53:58  fabiankeil
  *    Log a warning if the content is compressed, filtering is
  *    enabled and Privoxy was compiled without zlib support.
@@ -694,6 +722,7 @@ const char parsers_rcs[] = "$Id: parsers.c,v 1.96 2007/04/12 12:53:58 fabiankeil
 #include "miscutil.h"
 #include "list.h"
 #include "actions.h"
+#include "filters.h"
 
 #ifndef HAVE_STRPTIME
 #include "strptime.h"
@@ -1401,8 +1430,6 @@ jb_err scan_headers(struct client_state *csp)
       err = header_tagger(csp, h->str);
    }
 
-   update_action_bits(csp);
-
    return err;
 }
 
@@ -1425,13 +1452,13 @@ jb_err scan_headers(struct client_state *csp)
  *                headers (client or server)
  *          3  :  csp = Current client state (buffers, headers, etc...)
  *
- * Returns     :  Single pointer to a fully formed header, or NULL
- *                on out-of-memory error.
+ * Returns     :  JB_ERR_OK in case off success, or
+ *                JB_ERR_MEMORY on out-of-memory error.
  *
  *********************************************************************/
-char *sed(const struct parsers pats[],
-          const add_header_func_ptr more_headers[],
-          struct client_state *csp)
+jb_err sed(const struct parsers pats[],
+           const add_header_func_ptr more_headers[],
+           struct client_state *csp)
 {
    struct list_entry *p;
    const struct parsers *v;
@@ -1495,12 +1522,7 @@ char *sed(const struct parsers pats[],
       }
    }
 
-   if (err != JB_ERR_OK)
-   {
-      return NULL;
-   }
-
-   return list_to_text(csp->headers);
+   return err;
 }
 
 
@@ -1602,8 +1624,11 @@ jb_err header_tagger(struct client_state *csp, char *header)
                char *modified_tag = NULL;
                char *tag = header;
                size_t size = header_length;
+               pcrs_job *joblist = b->joblist;
 
-               if (NULL == b->joblist)
+               if (b->dynamic) joblist = compile_dynamic_pcrs_job_list(csp, b);
+
+               if (NULL == joblist)
                {
                   log_error(LOG_LEVEL_RE_FILTER,
                      "Tagger %s has empty joblist. Nothing to do.", b->name);
@@ -1611,7 +1636,7 @@ jb_err header_tagger(struct client_state *csp, char *header)
                }
 
                /* execute their pcrs_joblist on the header. */
-               for (job = b->joblist; NULL != job; job = job->next)
+               for (job = joblist; NULL != job; job = job->next)
                {
                   const int hits = pcrs_execute(job, tag, size, &modified_tag, &size);
 
@@ -1638,14 +1663,28 @@ jb_err header_tagger(struct client_state *csp, char *header)
                   }
                }
 
+               if (b->dynamic) pcrs_free_joblist(joblist);
+
                /* If this tagger matched */
                if (tag != header)
                {
-                  /* and there is something left to save, */
-                  if (0 < size)
+                  if (0 == size)
+                  {
+                     /*
+                      * There is to technical limitation which makes
+                      * it impossible to use empty tags, but I assume
+                      * no one would do it intentionally.
+                      */
+                     freez(tag);
+                     log_error(LOG_LEVEL_INFO,
+                        "Tagger \'%s\' created an empty tag. Ignored.",
+                        b->name);
+                     continue;
+                  }
+                  if (!list_contains_item(csp->tags, tag))
                   {
-                     /* enlist a unique version of it as tag. */
-                     if (JB_ERR_OK != enlist_unique(csp->tags, tag, 0))
+                     if (JB_ERR_OK != enlist(csp->tags, tag))
                      {
                         log_error(LOG_LEVEL_ERROR,
                            "Insufficient memory to add tag \'%s\', "
@@ -1654,13 +1693,35 @@ jb_err header_tagger(struct client_state *csp, char *header)
                      }
                      else
                      {
+                        char *action_message;
+                        /*
+                         * update the action bits right away, to make
+                         * tagging based on tags set by earlier taggers
+                         * of the same kind possible.
+                         */
+                        if (update_action_bits_for_tag(csp, tag))
+                        {
+                           action_message = "Action bits updated accordingly.";
+                        }
+                        else
+                        {
+                           action_message = "No action bits update necessary.";
+                        }
+
                         log_error(LOG_LEVEL_HEADER,
-                           "Adding tag \'%s\' created by header tagger \'%s\'",
-                           tag, b->name);
+                           "Tagger \'%s\' added tag \'%s\'. %s",
+                           b->name, tag, action_message);
                      }
                   }
+                  else
+                  {
+                     /* XXX: Is this log-worthy? */
+                     log_error(LOG_LEVEL_HEADER,
+                        "Tagger \'%s\' didn't add tag \'%s\'. "
+                        "Tag already present", b->name, tag);
+                  }
                   freez(tag);
-               }
+               } /* if the tagger matched */
             } /* if the tagger applies */
          } /* for every tagger that could apply */
       } /* for all filters */
@@ -1707,6 +1768,11 @@ jb_err filter_header(struct client_state *csp, char **header)
    int wanted_filter_type;
    int multi_action_index;
 
+   if (csp->flags & CSP_FLAG_NO_FILTERING)
+   {
+      return JB_ERR_OK;
+   }
+
    if (csp->flags & CSP_FLAG_CLIENT_HEADER_PARSING_DONE)
    {
       wanted_filter_type = FT_SERVER_HEADER_FILTER;
@@ -1775,8 +1841,11 @@ jb_err filter_header(struct client_state *csp, char **header)
             if (strcmp(b->name, filtername->str) == 0)
             {
                int current_hits = 0;
+               pcrs_job *joblist = b->joblist;
+
+               if (b->dynamic) joblist = compile_dynamic_pcrs_job_list(csp, b);
 
-               if ( NULL == b->joblist )
+               if (NULL == joblist)
                {
                   log_error(LOG_LEVEL_RE_FILTER, "Filter %s has empty joblist. Nothing to do.", b->name);
                   continue;
@@ -1786,7 +1855,7 @@ jb_err filter_header(struct client_state *csp, char **header)
                          *header, size, b->name);
 
                /* Apply all jobs from the joblist */
-               for (job = b->joblist; NULL != job; job = job->next)
+               for (job = joblist; NULL != job; job = job->next)
                {
                   matches = pcrs_execute(job, *header, size, &newheader, &size);
                   if ( 0 < matches )
@@ -1813,6 +1882,9 @@ jb_err filter_header(struct client_state *csp, char **header)
                      }
                   }
                }
+
+               if (b->dynamic) pcrs_free_joblist(joblist);
+
                log_error(LOG_LEVEL_RE_FILTER, "... produced %d hits (new size %d).", current_hits, size);
                hits += current_hits;
             }
@@ -1972,7 +2044,7 @@ jb_err crunch_server_header(struct client_state *csp, char **header)
 jb_err server_content_type(struct client_state *csp, char **header)
 {
    /* Remove header if it isn't the first Content-Type header */
-   if(csp->content_type && (csp->content_type != CT_TABOO))
+   if ((csp->content_type & CT_DECLARED))
    {
      /*
       * Another, slightly slower, way to see if
@@ -1988,6 +2060,11 @@ jb_err server_content_type(struct client_state *csp, char **header)
       return JB_ERR_OK;
    }
 
+   /*
+    * Signal that the Content-Type has been set.
+    */
+   csp->content_type |= CT_DECLARED;
+
    if (!(csp->content_type & CT_TABOO))
    {
       if ((strstr(*header, " text/") && !strstr(*header, "plain"))
@@ -2004,29 +2081,8 @@ jb_err server_content_type(struct client_state *csp, char **header)
       {
          csp->content_type |= CT_JPEG;
       }
-      else
-      {
-         csp->content_type = 0;
-      }
-   }
-   /*
-    * Are we enabling text mode by force?
-    */
-   if (csp->action->flags & ACTION_FORCE_TEXT_MODE)
-   {
-      /*
-       * Do we really have to?
-       */
-      if (csp->content_type & CT_TEXT)
-      {
-         log_error(LOG_LEVEL_HEADER, "Text mode is already enabled.");   
-      }
-      else
-      {
-         csp->content_type |= CT_TEXT;
-         log_error(LOG_LEVEL_HEADER, "Text mode enabled by force. Take cover!");   
-      }
    }
+
    /*
     * Are we messing with the content type?
     */ 
@@ -2055,6 +2111,7 @@ jb_err server_content_type(struct client_state *csp, char **header)
             "Enable force-text-mode if you know what you're doing.", *header);   
       }
    }  
+
    return JB_ERR_OK;
 }
 
@@ -3307,9 +3364,8 @@ jb_err client_x_filter(struct client_state *csp, char **header)
          }
          else
          {  
-            csp->content_type = CT_TABOO;
-            csp->action->flags &= ~ACTION_FILTER_SERVER_HEADERS;
-            csp->action->flags &= ~ACTION_FILTER_CLIENT_HEADERS;
+            csp->content_type = CT_TABOO; /* XXX: This hack shouldn't be necessary */
+            csp->flags |= CSP_FLAG_NO_FILTERING;
             log_error(LOG_LEVEL_HEADER, "Accepted the client's request to fetch without filtering.");
          }
          log_error(LOG_LEVEL_HEADER, "Crunching %s", *header);
@@ -3377,9 +3433,8 @@ jb_err client_host_adder(struct client_state *csp)
  *
  * Function    :  client_cookie_adder
  *
- * Description :  Used in the add_client_headers list.  Called from `sed'.
- *
- *                XXX: Remove csp->cookie_list which is no longer used.
+ * Description :  Used in the add_client_headers list to add "wafers".
+ *                Called from `sed'.
  *
  * Parameters  :
  *          1  :  csp = Current client state (buffers, headers, etc...)
@@ -3390,14 +3445,12 @@ jb_err client_host_adder(struct client_state *csp)
  *********************************************************************/
 jb_err client_cookie_adder(struct client_state *csp)
 {
-   struct list_entry *lst;
    char *tmp;
-   struct list_entry *list1 = csp->cookie_list->first;
-   struct list_entry *list2 = csp->action->multi[ACTION_MULTI_WAFER]->first;
-   int first_cookie = 1;
+   struct list_entry *wafer;
+   struct list_entry *wafer_list = csp->action->multi[ACTION_MULTI_WAFER]->first;
    jb_err err;
 
-   if ((list1 == NULL) && (list2 == NULL))
+   if (NULL == wafer_list)
    {
       /* Nothing to do */
       return JB_ERR_OK;
@@ -3405,30 +3458,14 @@ jb_err client_cookie_adder(struct client_state *csp)
 
    tmp = strdup("Cookie: ");
 
-   for (lst = list1; lst ; lst = lst->next)
-   {
-      if (first_cookie)
-      {
-         first_cookie = 0;
-      }
-      else
-      {
-         string_append(&tmp, "; ");
-      }
-      string_append(&tmp, lst->str);
-   }
-
-   for (lst = list2;  lst ; lst = lst->next)
+   for (wafer = wafer_list; (NULL != tmp) && (NULL != wafer); wafer = wafer->next)
    {
-      if (first_cookie)
-      {
-         first_cookie = 0;
-      }
-      else
+      if (wafer != wafer_list)
       {
+         /* As this isn't the first wafer, we need a delimiter. */
          string_append(&tmp, "; ");
       }
-      string_join(&tmp, cookie_encode(lst->str));
+      string_join(&tmp, cookie_encode(wafer->str));
    }
 
    if (tmp == NULL)