X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=blobdiff_plain;f=filters.c;h=df89372a27c482937fdf8398e938540cfb869b23;hp=7251a1dcbfff0af6a24bc54fd743afc488a8fc1c;hb=958862cb4198088d59c98be6f927b7eee2cb957c;hpb=89014be0c53220a901e9cd54c77422cd99406d20 diff --git a/filters.c b/filters.c index 7251a1dc..df89372a 100644 --- a/filters.c +++ b/filters.c @@ -1,4 +1,4 @@ -const char filters_rcs[] = "$Id: filters.c,v 1.138 2011/02/19 13:53:14 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 $ @@ -485,7 +485,7 @@ int acl_addr(const char *aspec, struct access_control_addr *aca) * of octets (128-bit CPU could do it in one iteration). */ /* - * Octets after prefix can be ommitted because of + * Octets after prefix can be omitted because of * previous initialization to zeros. */ for (i = 0; (i < addr_len) && masklength; i++) @@ -574,7 +574,7 @@ struct http_response *block_url(struct client_state *csp) } if (csp->action->flags & ACTION_REDIRECT) { - log_error(LOG_LEVEL_ERROR, "redirect{} overruled by block."); + log_error(LOG_LEVEL_ERROR, "redirect{} overruled by block."); } /* * Else, prepare a response @@ -668,7 +668,7 @@ struct http_response *block_url(struct client_state *csp) if(csp->action->flags & ACTION_HANDLE_AS_EMPTY_DOCUMENT) { /* - * Send empty document. + * Send empty document. */ new_content_type = csp->action->string[ACTION_STRING_CONTENT_TYPE]; @@ -714,27 +714,8 @@ struct http_response *block_url(struct client_state *csp) { jb_err err; struct map * exports; - char *p; - - /* - * Workaround for stupid Netscape bug which prevents - * pages from being displayed if loading a referenced - * JavaScript or style sheet fails. So make it appear - * as if it succeeded. - */ - if ( NULL != (p = get_header_value(csp->headers, "User-Agent:")) - && !strncmpic(p, "mozilla", 7) /* Catch Netscape but */ - && !strstr(p, "Gecko") /* save Mozilla, */ - && !strstr(p, "compatible") /* MSIE */ - && !strstr(p, "Opera")) /* and Opera. */ - { - rsp->status = strdup("200 Request blocked by Privoxy"); - } - else - { - rsp->status = strdup("403 Request blocked by Privoxy"); - } + rsp->status = strdup("403 Request blocked by Privoxy"); if (rsp->status == NULL) { free_http_response(rsp); @@ -855,7 +836,7 @@ struct http_response *trust_url(struct client_state *csp) * Export the protocol, host, port, and referrer information */ err = map(exports, "hostport", 1, csp->http->hostport, 1); - if (!err) err = map(exports, "protocol", 1, csp->http->ssl ? "https://" : "http://", 1); + if (!err) err = map(exports, "protocol", 1, csp->http->ssl ? "https://" : "http://", 1); if (!err) err = map(exports, "path", 1, csp->http->path, 1); if (NULL != (p = get_header_value(csp->headers, "Referer:"))) @@ -975,7 +956,7 @@ struct http_response *trust_url(struct client_state *csp) * 2 : b = The filter list to compile * * Returns : NULL in case of errors, otherwise the - * pcrs job list. + * pcrs job list. * *********************************************************************/ pcrs_job *compile_dynamic_pcrs_job_list(const struct client_state *csp, const struct re_filterfile_spec *b) @@ -1003,8 +984,8 @@ pcrs_job *compile_dynamic_pcrs_job_list(const struct client_state *csp, const st if (NULL == dummy) { log_error(LOG_LEVEL_ERROR, - "Adding filter job \'%s\' to dynamic filter %s failed: %s", - pattern->str, b->name, pcrs_strerror(error)); + "Compiling dynamic pcrs job '%s' for '%s' failed with error code %d: %s", + pattern->str, b->name, error, pcrs_strerror(error)); continue; } else @@ -1044,7 +1025,7 @@ pcrs_job *compile_dynamic_pcrs_job_list(const struct client_state *csp, const st * 2 : pcrs_command = pcrs command formatted as string (s@foo@bar@) * * - * Returns : NULL if the pcrs_command didn't change the url, or + * Returns : NULL if the pcrs_command didn't change the url, or * the result of the modification. * *********************************************************************/ @@ -1103,7 +1084,7 @@ char *rewrite_url(char *old_url, const char *pcrs_command) * * Parameters : * 1 : subject = the string to check - * 2 : redirect_mode = +fast-redirect{} mode + * 2 : redirect_mode = +fast-redirect{} mode * * Returns : NULL if no URL was found, or * the last URL found. @@ -1124,22 +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, "Decoding \"%s\" if necessary.", subject); - new_url = url_decode(subject); - if (new_url != NULL) + 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. + */ + size_t max_segments = strlen(subject) / 2; + char **url_segments = malloc(max_segments * sizeof(char *)); + int segments; + + if (NULL == url_segments) { + log_error(LOG_LEVEL_ERROR, "Out of memory while decoding URL: %s", new_url); freez(subject); - subject = new_url; + return NULL; } - else + + 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\".", 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); + + if (url_segment == NULL) { - log_error(LOG_LEVEL_ERROR, "Unable to decode \"%s\".", subject); + 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); } - - log_error(LOG_LEVEL_REDIRECTS, "Checking \"%s\" for redirects.", subject); /* * Find the last URL encoded in the request @@ -1162,7 +1199,7 @@ char *get_last_url(char *subject, const char *redirect_mode) )) { /* - * Return new URL if we found a redirect + * Return new URL if we found a redirect * or if the subject already was a URL. * * The second case makes sure that we can @@ -1268,9 +1305,24 @@ struct http_response *redirect_url(struct client_state *csp) #endif /* def FEATURE_FAST_REDIRECTS */ csp->action->flags &= ~ACTION_REDIRECT; - /* Did any redirect action trigger? */ + /* 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, @@ -1288,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); @@ -1522,7 +1574,7 @@ static char *pcrs_filter_response(struct client_state *csp) struct re_filterfile_spec *b; struct list_entry *filtername; - /* + /* * Sanity first */ if (csp->iob->cur >= csp->iob->eod) @@ -1827,7 +1879,7 @@ static jb_err remove_chunked_transfer_coding(char *buffer, size_t *size) break; } } - + /* XXX: Should get its own loglevel. */ log_error(LOG_LEVEL_RE_FILTER, "De-chunking successful. Shrunk from %d to %d", *size, newsize); @@ -2206,7 +2258,7 @@ const struct forward_spec *forward_url(struct client_state *csp, /********************************************************************* * - * Function : direct_response + * Function : direct_response * * Description : Check if Max-Forwards == 0 for an OPTIONS or TRACE * request and if so, return a HTTP 501 to the client. @@ -2215,7 +2267,7 @@ const struct forward_spec *forward_url(struct client_state *csp, * requests properly. Still, what we do here is rfc- * compliant, whereas ignoring or forwarding are not. * - * Parameters : + * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * * Returns : http_response if , NULL if nonmatch or handler fail @@ -2231,7 +2283,7 @@ struct http_response *direct_response(struct client_state *csp) { for (p = csp->headers->first; (p != NULL) ; p = p->next) { - if (!strncmpic("Max-Forwards:", p->str, 13)) + if (!strncmpic(p->str, "Max-Forwards:", 13)) { unsigned int max_forwards; @@ -2255,7 +2307,7 @@ struct http_response *direct_response(struct client_state *csp) { return cgi_error_memory(); } - + if (NULL == (rsp->status = strdup("501 Not Implemented"))) { free_http_response(rsp); @@ -2356,7 +2408,7 @@ int content_requires_filtering(struct client_state *csp) * Description : Checks whether there are any content filters * enabled for the current request. * - * Parameters : + * Parameters : * 1 : action = Action spec to check. * * Returns : TRUE for yes, FALSE otherwise