X-Git-Url: http://www.privoxy.org/gitweb/?a=blobdiff_plain;f=filters.c;h=df89372a27c482937fdf8398e938540cfb869b23;hb=4b345bd3f2b9435a46013da7c4f770a70bfc4a57;hp=865c6d8077d7cdccd1cd02e6c763c71674e3730f;hpb=fb7262efc9773f80c6737da5f02efe3bade66873;p=privoxy.git diff --git a/filters.c b/filters.c index 865c6d80..df89372a 100644 --- a/filters.c +++ b/filters.c @@ -1,4 +1,4 @@ -const char filters_rcs[] = "$Id: filters.c,v 1.151 2011/10/30 16:17:57 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 $ @@ -1105,55 +1105,78 @@ char *get_last_url(char *subject, const char *redirect_mode) 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); + /* * Check each parameter in the URL separately. * Sectionize the URL at "?" and "&", - * then URL-decode each component, + * go backwards through the segments, URL-decode them * and look for a URL in the decoded result. - * Keep the last one we spot. + * 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 = NULL; - char *token = strtok(subject, "?&"); - 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); + log_error(LOG_LEVEL_ERROR, "Out of memory while decoding URL: %s", new_url); + freez(subject); + return NULL; + } + + segments = ssplit(subject, "?&", url_segments, max_segments, 1, 1); + + while (segments-- > 0) + { + char *dtoken = url_decode(url_segments[segments]); if (NULL == dtoken) { - log_error(LOG_LEVEL_ERROR, "Unable to decode \"%s\".", token); + log_error(LOG_LEVEL_ERROR, "Unable to decode \"%s\".", url_segments[segments]); continue; } - char *h1 = strstr(dtoken, "http://"); - char *h2 = strstr(dtoken, "https://"); - char *h = (h1 && h2 - ? (h1 < h2 ? h1 : h2) - : (h1 ? h1 : h2)); - if (h) + url_segment = strstr(dtoken, "http://"); + if (NULL == url_segment) + { + url_segment = strstr(dtoken, "https://"); + } + if (NULL != url_segment) { - freez(found); - found = strdup(h); - if (found == NULL) + 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); - token = strtok(NULL, "?&"); } freez(subject); + freez(url_segments); - return found; + 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 @@ -1285,6 +1308,21 @@ struct http_response *redirect_url(struct client_state *csp) /* 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, @@ -1302,8 +1340,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);