-const char filters_rcs[] = "$Id: filters.c,v 1.145 2011/09/04 11:10:56 fabiankeil Exp $";
+const char filters_rcs[] = "$Id: filters.c,v 1.159 2011/11/06 11:52:36 fabiankeil Exp $";
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/filters.c,v $
return NULL;
}
- if (0 == strcmpic(redirect_mode, "check-decoded-url"))
+ if (0 == strcmpic(redirect_mode, "check-decoded-url") && strchr(subject, '%'))
{
- log_error(LOG_LEVEL_REDIRECTS, "Checking \"%s\" for encoded redirects.",
- subject);
-
- /* jwz: 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.
+ log_error(LOG_LEVEL_REDIRECTS,
+ "Checking \"%s\" for encoded redirects.", subject);
+
+ /*
+ * Check each parameter in the URL separately.
+ * Sectionize the URL at "?" and "&",
+ * go backwards through the segments, URL-decode them
+ * and look for a URL in the decoded result.
+ * Stop the search after the first match.
+ */
+ char *url_segment = NULL;
+ /*
+ * XXX: This estimate is guaranteed to be high enough as we
+ * let ssplit() ignore empty fields, but also a bit wasteful.
*/
- char *found = 0;
- char *s = strdup (subject);
- char *token = strtok (s, "?&");
- while (token)
+ size_t max_segments = strlen(subject) / 2;
+ char **url_segments = malloc(max_segments * sizeof(char *));
+ int segments;
+
+ if (NULL == url_segments)
{
- char *dtoken = url_decode (token);
- if (!dtoken) continue;
- char *h1 = strstr (dtoken, "http://");
- char *h2 = strstr (dtoken, "https://");
- char *h = (h1 && h2
- ? (h1 < h2 ? h1 : h2)
- : (h1 ? h1 : h2));
- if (h)
- {
- freez(found);
- found = strdup (h);
- }
- token = strtok (0, "?&");
+ log_error(LOG_LEVEL_ERROR, "Out of memory while decoding URL: %s", new_url);
+ freez(subject);
+ return NULL;
}
- freez(s);
- if (found)
+ segments = ssplit(subject, "?&", url_segments, max_segments, 1, 1);
+
+ while (segments-- > 0)
{
- freez(subject);
- return found;
+ char *dtoken = url_decode(url_segments[segments]);
+ if (NULL == dtoken)
+ {
+ log_error(LOG_LEVEL_ERROR, "Unable to decode \"%s\".", url_segments[segments]);
+ continue;
+ }
+ url_segment = strstr(dtoken, "http://");
+ if (NULL == url_segment)
+ {
+ url_segment = strstr(dtoken, "https://");
+ }
+ if (NULL != url_segment)
+ {
+ url_segment = strdup(url_segment);
+ freez(dtoken);
+ if (url_segment == NULL)
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "Out of memory while searching for redirects.");
+ return NULL;
+ }
+ break;
+ }
+ freez(dtoken);
}
+ freez(subject);
+ freez(url_segments);
- freez (subject);
- return NULL;
+ if (url_segment == NULL)
+ {
+ return NULL;
+ }
+ subject = url_segment;
+ }
+ else
+ {
+ /* Look for a URL inside this one, without decoding anything. */
+ log_error(LOG_LEVEL_REDIRECTS,
+ "Checking \"%s\" for unencoded 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
/* Did any redirect action trigger? */
if (new_url)
{
+ if (url_requires_percent_encoding(new_url))
+ {
+ char *encoded_url;
+ log_error(LOG_LEVEL_REDIRECTS, "Percent-encoding redirect URL: %N",
+ strlen(new_url), new_url);
+ encoded_url = percent_encode_url(new_url);
+ freez(new_url);
+ if (encoded_url == NULL)
+ {
+ return cgi_error_memory();
+ }
+ new_url = encoded_url;
+ assert(FALSE == url_requires_percent_encoding(new_url));
+ }
+
if (0 == strcmpic(new_url, csp->http->url))
{
log_error(LOG_LEVEL_ERROR,
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);