Add url_requires_percent_encoding()
[privoxy.git] / filters.c
index 1949b21..e2f490c 100644 (file)
--- a/filters.c
+++ b/filters.c
@@ -1,4 +1,4 @@
-const char filters_rcs[] = "$Id: filters.c,v 1.144 2011/07/30 15:15:25 fabiankeil Exp $";
+const char filters_rcs[] = "$Id: filters.c,v 1.154 2011/10/30 16:22:46 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/filters.c,v $
@@ -78,6 +78,11 @@ const char filters_rcs[] = "$Id: filters.c,v 1.144 2011/07/30 15:15:25 fabiankei
 #include "urlmatch.h"
 #include "loaders.h"
 
+#ifdef HAVE_STRTOK
+/* Only used for locks */
+#include "jcc.h"
+#endif /* def HAVE_STRTOK */
+
 #ifdef _WIN32
 #include "win32.h"
 #endif
@@ -1106,8 +1111,55 @@ char *get_last_url(char *subject, const char *redirect_mode)
    }
 
    if (0 == strcmpic(redirect_mode, "check-decoded-url"))
-   {
-      log_error(LOG_LEVEL_REDIRECTS, "Decoding \"%s\" if necessary.", subject);
+   {  
+      log_error(LOG_LEVEL_REDIRECTS,
+         "Checking \"%s\" for encoded redirects.", subject);
+
+#if defined(MUTEX_LOCKS_AVAILABLE) && defined(HAVE_STRTOK)
+      /*
+       * Check each parameter in the URL separately.
+       * Sectionize the URL at "?" and "&",
+       * then URL-decode each component,
+       * and look for a URL in the decoded result.
+       * Keep the last one we spot.
+       */
+      char *found = NULL;
+
+      privoxy_mutex_lock(&strtok_mutex);
+      char *token = strtok(subject, "?&");
+      while (token)
+      {
+         char *dtoken = url_decode(token);
+         if (NULL == dtoken)
+         {
+            log_error(LOG_LEVEL_ERROR, "Unable to decode \"%s\".", token);
+            continue;
+         }
+         char *http_url = strstr(dtoken, "http://");
+         char *https_url = strstr(dtoken, "https://");
+         char *last_url = (http_url && https_url
+                          ? (http_url < https_url ? http_url : https_url)
+                          : (http_url ? http_url : https_url));
+         if (last_url)
+         {
+            freez(found);
+            found = strdup(last_url);
+            if (found == NULL)
+            {
+               log_error(LOG_LEVEL_ERROR,
+                  "Out of memory while searching for redirects.");
+               privoxy_mutex_unlock(&strtok_mutex);
+               return NULL;
+            }
+         }
+         freez(dtoken);
+         token = strtok(NULL, "?&");
+      }
+      privoxy_mutex_unlock(&strtok_mutex);
+      freez(subject);
+
+      return found;
+#else
       new_url = url_decode(subject);
       if (new_url != NULL)
       {
@@ -1118,9 +1170,13 @@ char *get_last_url(char *subject, const char *redirect_mode)
       {
          log_error(LOG_LEVEL_ERROR, "Unable to decode \"%s\".", subject);
       }
+#endif /* defined(MUTEX_LOCKS_AVAILABLE) && defined(HAVE_STRTOK) */
    }
 
-   log_error(LOG_LEVEL_REDIRECTS, "Checking \"%s\" for redirects.", subject);
+   /* Else, just look for a URL inside this one, without decoding anything. */
+
+   log_error(LOG_LEVEL_REDIRECTS,
+      "Checking \"%s\" for unencoded redirects.", subject);
 
    /*
     * Find the last URL encoded in the request
@@ -1269,8 +1325,8 @@ struct http_response *redirect_url(struct client_state *csp)
             return cgi_error_memory();
          }
 
-         if ( enlist_unique_header(rsp->headers, "Location", new_url)
-           || (NULL == (rsp->status = strdup("302 Local Redirect from Privoxy"))) )
+         if (enlist_unique_header(rsp->headers, "Location", new_url)
+           || (NULL == (rsp->status = strdup("302 Local Redirect from Privoxy"))))
          {
             freez(new_url);
             free_http_response(rsp);