also provide developer and faq docs.
[privoxy.git] / filters.c
index 9ba1605..e30a24c 100644 (file)
--- a/filters.c
+++ b/filters.c
@@ -1,4 +1,4 @@
-const char filters_rcs[] = "$Id: filters.c,v 1.33 2001/09/16 17:05:14 jongfoster Exp $";
+const char filters_rcs[] = "$Id: filters.c,v 1.35 2001/10/07 15:41:23 oes Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/filters.c,v $
@@ -38,6 +38,23 @@ const char filters_rcs[] = "$Id: filters.c,v 1.33 2001/09/16 17:05:14 jongfoster
  *
  * Revisions   :
  *    $Log: filters.c,v $
+ *    Revision 1.35  2001/10/07 15:41:23  oes
+ *    Replaced 6 boolean members of csp with one bitmap (csp->flags)
+ *
+ *    New function remove_chunked_transfer_coding that strips chunked
+ *      transfer coding to plain and is called by pcrs_filter_response
+ *      and gif_deanimate_response if neccessary
+ *
+ *    Improved handling of zero-change re_filter runs
+ *
+ *    pcrs_filter_response and gif_deanimate_response now remove
+ *      chunked transfer codeing before processing the body.
+ *
+ *    Revision 1.34  2001/09/20 15:49:36  steudten
+ *
+ *    Fix BUG: Change int size to size_t size in pcrs_filter_response().
+ *    See cgi.c fill_template().
+ *
  *    Revision 1.33  2001/09/16 17:05:14  jongfoster
  *    Removing unused #include showarg.h
  *
@@ -286,6 +303,7 @@ const char filters_rcs[] = "$Id: filters.c,v 1.33 2001/09/16 17:05:14 jongfoster
 #include <stdlib.h>
 #include <ctype.h>
 #include <string.h>
+#include <assert.h>
 
 #ifndef _WIN32
 #include <unistd.h>
@@ -460,6 +478,86 @@ int acl_addr(char *aspec, struct access_control_addr *aca)
 #endif /* def FEATURE_ACL */
 
 
+/*********************************************************************
+ *
+ * Function    :  match_portlist
+ *
+ * Description :  Check if a given number is covered by a comma
+ *                separated list of numbers and ranges (a,b-c,d,..)
+ *
+ * Parameters  :
+ *          1  :  portlist = String with list
+ *          2  :  port = port to check
+ *
+ * Returns     :  0 => no match
+ *                1 => match
+ *
+ *********************************************************************/
+int match_portlist(const char *portlist, int port)
+{
+   char *min, *max, *next, *portlist_copy;
+
+   min = next = portlist_copy = strdup(portlist);
+
+   /*
+    * Zero-terminate first item and remember offset for next
+    */
+   if (NULL != (next = strchr(portlist_copy, (int) ',')))
+   {
+      *next++ = '\0';
+   }
+   
+   /*
+    * Loop through all items, checking for match
+    */
+   while(min)
+   {
+      if (NULL == (max = strchr(min, (int) '-')))
+      {
+         /*
+          * No dash, check for equality
+          */
+         if (port == atoi(min))
+         {
+            free(portlist_copy);
+            return(1);
+         }
+      }
+      else
+      {
+         /*
+          * This is a range, so check if between min and max,
+          * or, if max was omitted, between min and 65K
+          */
+         *max++ = '\0';
+         if(port >= atoi(min) && port <= (atoi(max) ? atoi(max) : 65535))
+         {
+            free(portlist_copy);
+            return(1);
+         }
+           
+      }      
+
+      /*
+       * Jump to next item
+       */
+      min = next;
+
+      /*
+       * Zero-terminate next item and remember offset for n+1
+       */
+      if ((NULL != next) && (NULL != (next = strchr(next, (int) ','))))
+      {
+         *next++ = '\0';
+      }
+   }
+   
+   free(portlist_copy);
+   return 0;
+
+}
+
+
 /*********************************************************************
  *
  * Function    :  block_url
@@ -953,7 +1051,7 @@ int is_untrusted_url(struct client_state *csp)
  * Description :  Apply all the pcrs jobs from the joblist (re_filterfile)
  *                to the text buffer that's been accumulated in 
  *                csp->iob->buf and set csp->content_length to the modified
- *                size.
+ *                size and raise the CSP_FLAG_MODIFIED flag if appropriate.
  *
  * Parameters  :
  *          1  :  csp = Current client state (buffers, headers, etc...)
@@ -973,13 +1071,28 @@ char *pcrs_filter_response(struct client_state *csp)
    struct file_list *fl;
    struct re_filterfile_spec *b;
 
-   /* Sanity first ;-) */
+   /* Sanity first */
    if (csp->iob->cur >= csp->iob->eod)
    {
       return(NULL);
    }
    size = csp->iob->eod - csp->iob->cur;
 
+   /*
+    * If the body has a "chunked" transfer-encoding,
+    * get rid of it first, adjusting size and iob->eod
+    */
+   if (csp->flags & CSP_FLAG_CHUNKED)
+   {
+      log_error(LOG_LEVEL_RE_FILTER, "Need to de-chunk first");
+      if (0 == (size = remove_chunked_transfer_coding(csp->iob->cur, size)))
+      {
+         return(NULL);
+      }
+      csp->iob->eod = csp->iob->cur + size;
+      csp->flags |= CSP_FLAG_MODIFIED;
+   }
+
    if ( ( NULL == (fl = csp->rlist) ) || ( NULL == (b = fl->f) ) )
    {
       log_error(LOG_LEVEL_ERROR, "Unable to get current state of regexp filtering.");
@@ -1005,10 +1118,20 @@ char *pcrs_filter_response(struct client_state *csp)
 
    log_error(LOG_LEVEL_RE_FILTER, " produced %d hits (new size %d).", hits, size);
 
-   csp->content_length = size;
+   /* 
+    * If there were no hits, destroy our copy and let
+    * chat() use the original in csp->iob
+    */
+   if (!hits)
+   {
+      free(new);
+      return(NULL);
+   }
 
-   /* fwiw, reset the iob */
+   csp->flags |= CSP_FLAG_MODIFIED;
+   csp->content_length = size;
    IOB_RESET(csp);
+
    return(new);
 
 }
@@ -1019,8 +1142,8 @@ char *pcrs_filter_response(struct client_state *csp)
  * Function    :  gif_deanimate_response
  *
  * Description :  Deanimate the GIF image that has been accumulated in 
- *                csp->iob->buf and set csp->content_length to the modified
- *                size.
+ *                csp->iob->buf, set csp->content_length to the modified
+ *                size and raise the CSP_FLAG_MODIFIED flag.
  *
  * Parameters  :
  *          1  :  csp = Current client state (buffers, headers, etc...)
@@ -1035,6 +1158,21 @@ char *gif_deanimate_response(struct client_state *csp)
    char *p;
    int size = csp->iob->eod - csp->iob->cur;
 
+   /*
+    * If the body has a "chunked" transfer-encoding,
+    * get rid of it first, adjusting size and iob->eod
+    */
+   if (csp->flags & CSP_FLAG_CHUNKED)
+   {
+      log_error(LOG_LEVEL_DEANIMATE, "Need to de-chunk first");
+      if (0 == (size = remove_chunked_transfer_coding(csp->iob->cur, size)))
+      {
+         return(NULL);
+      }
+      csp->iob->eod = csp->iob->cur + size;
+      csp->flags |= CSP_FLAG_MODIFIED;
+   }
+
    if (  (NULL == (in =  (struct binbuffer *)zalloc(sizeof *in )))
       || (NULL == (out = (struct binbuffer *)zalloc(sizeof *out))) )
    {
@@ -1056,6 +1194,7 @@ char *gif_deanimate_response(struct client_state *csp)
    {
       log_error(LOG_LEVEL_DEANIMATE, "Success! GIF shrunk from %d bytes to %d.", size, out->offset);
       csp->content_length = out->offset;
+      csp->flags |= CSP_FLAG_MODIFIED;
       p = out->buffer;
       free(in);
       free(out);
@@ -1065,6 +1204,65 @@ char *gif_deanimate_response(struct client_state *csp)
 }
 
 
+/*********************************************************************
+ *
+ * Function    :  remove_chunked_transfer_coding
+ *
+ * Description :  In-situ remove the "chunked" transfer coding as defined
+ *                in rfc2616 from a buffer.
+ *
+ * Parameters  :
+ *          1  :  buffer = Pointer to the text buffer
+ *          2  :  size = Number of bytes to be processed
+ *
+ * Returns     :  The new size, i.e. the number of bytes from buffer which
+ *                are occupied by the stripped body, or 0 in case something
+ *                went wrong
+ *                
+ *********************************************************************/
+int remove_chunked_transfer_coding(char *buffer, const size_t size)
+{
+   size_t newsize = 0;
+   unsigned int chunksize = 0;
+   char *from_p, *to_p;
+
+   assert(buffer);
+   from_p = to_p = buffer;
+
+   if (sscanf(buffer, "%x", &chunksize) != 1)
+   {
+      log_error(LOG_LEVEL_ERROR, "Invalid first chunksize while stripping \"chunked\" transfer coding");
+      return(0);
+   }
+
+   while (chunksize > 0)
+   {
+      if (NULL == (from_p = strstr(from_p, "\r\n")))
+      {
+         log_error(LOG_LEVEL_ERROR, "Parse error while stripping \"chunked\" transfer coding");
+         return(0);
+      }
+      newsize += chunksize;
+      from_p += 2;
+      
+      memmove(to_p, from_p, (size_t) chunksize);
+      to_p = buffer + newsize;
+      from_p += chunksize + 2;
+
+      if (sscanf(from_p, "%x", &chunksize) != 1)
+      {
+         log_error(LOG_LEVEL_ERROR, "Parse error while stripping \"chunked\" transfer coding");
+         return(0);
+      }
+   }
+
+   /* FIXME: Should this get its own loglevel? */
+   log_error(LOG_LEVEL_RE_FILTER, "De-chunking successful. Shrunk from %d to %d\n", size, newsize);
+   return(newsize);
+
+}
+
+
 /*********************************************************************
  *
  * Function    :  url_actions