Add limited hex notation support for the PCRS
[privoxy.git] / parsers.c
index 14ce3b6..950e9c2 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.102 2007/05/27 12:39:32 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/parsers.c,v $
@@ -44,6 +44,31 @@ const char parsers_rcs[] = "$Id: parsers.c,v 1.96 2007/04/12 12:53:58 fabiankeil
  *
  * Revisions   :
  *    $Log: parsers.c,v $
+ *    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 +719,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 +1427,6 @@ jb_err scan_headers(struct client_state *csp)
       err = header_tagger(csp, h->str);
    }
 
-   update_action_bits(csp);
-
    return err;
 }
 
@@ -1425,13 +1449,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 +1519,7 @@ char *sed(const struct parsers pats[],
       }
    }
 
-   if (err != JB_ERR_OK)
-   {
-      return NULL;
-   }
-
-   return list_to_text(csp->headers);
+   return err;
 }
 
 
@@ -1602,8 +1621,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 +1633,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 +1660,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 +1690,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 +1765,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 +1838,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 ( NULL == b->joblist )
+               if (b->dynamic) joblist = compile_dynamic_pcrs_job_list(csp, b);
+
+               if (NULL == joblist)
                {
                   log_error(LOG_LEVEL_RE_FILTER, "Filter %s has empty joblist. Nothing to do.", b->name);
                   continue;
@@ -1786,7 +1852,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 +1879,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;
             }
@@ -3307,9 +3376,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 +3445,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 +3457,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 +3470,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)