X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=blobdiff_plain;f=filters.c;h=6dd679eee3159cc9c337ac50a2beaba61d8b3555;hp=84ea1d5b99d5cd83b10ca301958ad77281df9932;hb=3789d801f6b08697f16edd034108a544f183ef31;hpb=95a30d7f7a289d0f5261927639808e490330616c diff --git a/filters.c b/filters.c index 84ea1d5b..6dd679ee 100644 --- a/filters.c +++ b/filters.c @@ -1,4 +1,4 @@ -const char filters_rcs[] = "$Id: filters.c,v 1.74 2006/12/24 17:37:38 fabiankeil Exp $"; +const char filters_rcs[] = "$Id: filters.c,v 1.84 2007/03/20 15:16:34 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/filters.c,v $ @@ -13,7 +13,7 @@ const char filters_rcs[] = "$Id: filters.c,v 1.74 2006/12/24 17:37:38 fabiankeil * `jpeg_inspect_response', `execute_single_pcrs_command', * `rewrite_url', `get_last_url' * - * Copyright : Written by and Copyright (C) 2001, 2004-2006 the SourceForge + * Copyright : Written by and Copyright (C) 2001, 2004-2007 the SourceForge * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written @@ -40,6 +40,50 @@ const char filters_rcs[] = "$Id: filters.c,v 1.74 2006/12/24 17:37:38 fabiankeil * * Revisions : * $Log: filters.c,v $ + * Revision 1.84 2007/03/20 15:16:34 fabiankeil + * Use dedicated header filter actions instead of abusing "filter". + * Replace "filter-client-headers" and "filter-client-headers" + * with "server-header-filter" and "client-header-filter". + * + * Revision 1.83 2007/03/17 15:20:05 fabiankeil + * New config option: enforce-blocks. + * + * Revision 1.82 2007/03/13 11:28:43 fabiankeil + * - Fix port handling in acl_addr() and use a temporary acl spec + * copy so error messages don't contain a truncated version. + * - Log size of iob before and after decompression. + * + * Revision 1.81 2007/03/05 14:40:53 fabiankeil + * - Cosmetical changes for LOG_LEVEL_RE_FILTER messages. + * - Hide the "Go there anyway" link for blocked CONNECT + * requests where going there anyway doesn't work anyway. + * + * Revision 1.80 2007/02/07 10:55:20 fabiankeil + * - Save the reason for generating http_responses. + * - Block (+block) with status code 403 instead of 404. + * - Use a different kludge to remember a failed decompression. + * + * Revision 1.79 2007/01/31 16:21:38 fabiankeil + * Search for Max-Forwards headers case-insensitive, + * don't generate the "501 unsupported" message for invalid + * Max-Forwards values and don't increase negative ones. + * + * Revision 1.78 2007/01/28 13:41:18 fabiankeil + * - Add HEAD support to finish_http_response. + * - Add error favicon to internal HTML error messages. + * + * Revision 1.77 2007/01/12 15:36:44 fabiankeil + * Mark *csp as immutable for is_untrusted_url() + * and is_imageurl(). Closes FR 1237736. + * + * Revision 1.76 2007/01/01 19:36:37 fabiankeil + * Integrate a modified version of Wil Mahan's + * zlib patch (PR #895531). + * + * Revision 1.75 2006/12/29 18:30:46 fabiankeil + * Fixed gcc43 conversion warnings, + * changed sprintf calls to snprintf. + * * Revision 1.74 2006/12/24 17:37:38 fabiankeil * Adjust comment in pcrs_filter_response() * to recent pcrs changes. Hohoho. @@ -624,20 +668,33 @@ int block_acl(struct access_control_addr *dst, struct client_state *csp) * Returns : 0 => Ok, everything else is an error. * *********************************************************************/ -int acl_addr(char *aspec, struct access_control_addr *aca) +int acl_addr(const char *aspec, struct access_control_addr *aca) { - int i, masklength, port; + int i, masklength; + long port; char *p; + char *acl_spec = NULL; masklength = 32; port = 0; - if ((p = strchr(aspec, '/')) != NULL) + /* + * Use a temporary acl spec copy so we can log + * the unmodified original in case of parse errors. + */ + acl_spec = strdup(aspec); + if (acl_spec == NULL) { - *p++ = '\0'; + /* XXX: This will be logged as parse error. */ + return(-1); + } + if ((p = strchr(acl_spec, '/')) != NULL) + { + *p++ = '\0'; if (ijb_isdigit(*p) == 0) { + free(acl_spec); return(-1); } masklength = atoi(p); @@ -645,26 +702,32 @@ int acl_addr(char *aspec, struct access_control_addr *aca) if ((masklength < 0) || (masklength > 32)) { + free(acl_spec); return(-1); } - if ((p = strchr(aspec, ':')) != NULL) + if ((p = strchr(acl_spec, ':')) != NULL) { + char *endptr; + *p++ = '\0'; + port = strtol(p, &endptr, 10); - if (ijb_isdigit(*p) == 0) + if (port <= 0 || port > 65535 || *endptr != '\0') { + free(acl_spec); return(-1); } - port = atoi(p); } - aca->port = port; + aca->port = (unsigned long)port; - aca->addr = ntohl(resolve_hostname_to_ip(aspec)); + aca->addr = ntohl(resolve_hostname_to_ip(acl_spec)); + free(acl_spec); if (aca->addr == INADDR_NONE) { + /* XXX: This will be logged as parse error. */ return(-1); } @@ -934,7 +997,6 @@ struct http_response *block_url(struct client_state *csp) return cgi_error_memory(); } } - } else #endif /* def FEATURE_IMAGE_BLOCKING */ @@ -963,7 +1025,7 @@ struct http_response *block_url(struct client_state *csp) } else { - rsp->status = strdup("404 Request for blocked URL"); + rsp->status = strdup("403 Request for blocked URL"); } if (rsp->status == NULL) @@ -981,7 +1043,15 @@ struct http_response *block_url(struct client_state *csp) #ifdef FEATURE_FORCE_LOAD err = map(exports, "force-prefix", 1, FORCE_PREFIX, 1); - if (csp->http->ssl != 0) + /* + * Export the force conditional block killer if + * + * - Privoxy was compiled without FEATURE_FORCE_LOAD, or + * - Privoxy is configured to enforce blocks, or + * - it's a CONNECT request and enforcing wouldn't work anyway. + */ + if ((csp->config->feature_flags & RUNTIME_FEATURE_ENFORCE_BLOCKS) + || (0 == strcmpic(csp->http->gpc, "connect"))) #endif /* ndef FEATURE_FORCE_LOAD */ { err = map_block_killer(exports, "force-support"); @@ -1006,8 +1076,9 @@ struct http_response *block_url(struct client_state *csp) return cgi_error_memory(); } } + rsp->reason = RSP_REASON_BLOCKED; - return finish_http_response(rsp); + return finish_http_response(csp, rsp); } @@ -1129,10 +1200,22 @@ struct http_response *trust_url(struct client_state *csp) } /* - * Export the force prefix or the force conditional block killer + * Export the force conditional block killer if + * + * - Privoxy was compiled without FEATURE_FORCE_LOAD, or + * - Privoxy is configured to enforce blocks, or + * - it's a CONNECT request and enforcing wouldn't work anyway. */ #ifdef FEATURE_FORCE_LOAD - err = map(exports, "force-prefix", 1, FORCE_PREFIX, 1); + if ((csp->config->feature_flags & RUNTIME_FEATURE_ENFORCE_BLOCKS) + || (0 == strcmpic(csp->http->gpc, "connect"))) + { + err = map_block_killer(exports, "force-support"); + } + else + { + err = map(exports, "force-prefix", 1, FORCE_PREFIX, 1); + } #else /* ifndef FEATURE_FORCE_LOAD */ err = map_block_killer(exports, "force-support"); #endif /* ndef FEATURE_FORCE_LOAD */ @@ -1153,8 +1236,9 @@ struct http_response *trust_url(struct client_state *csp) free_http_response(rsp); return cgi_error_memory(); } + rsp->reason = RSP_REASON_UNTRUSTED; - return finish_http_response(rsp); + return finish_http_response(csp, rsp); } #endif /* def FEATURE_TRUST */ @@ -1422,7 +1506,7 @@ struct http_response *redirect_url(struct client_state *csp) * If it exists, use the previously rewritten URL as input * otherwise just use the old path. */ - old_url = new_url ? new_url : strdup(csp->http->path); + old_url = (new_url != NULL) ? new_url : strdup(csp->http->path); new_url = get_last_url(old_url, redirect_mode); freez(old_url); } @@ -1455,8 +1539,10 @@ struct http_response *redirect_url(struct client_state *csp) free_http_response(rsp); return cgi_error_memory(); } + rsp->reason = RSP_REASON_REDIRECTED; freez(new_url); - return finish_http_response(rsp); + + return finish_http_response(csp, rsp); } } @@ -1484,7 +1570,7 @@ struct http_response *redirect_url(struct client_state *csp) * otherwise * *********************************************************************/ -int is_imageurl(struct client_state *csp) +int is_imageurl(const struct client_state *csp) { #ifdef FEATURE_IMAGE_DETECT_MSIE char *tmp; @@ -1531,7 +1617,7 @@ int is_imageurl(struct client_state *csp) * Returns : 0 => trusted, 1 => untrusted * *********************************************************************/ -int is_untrusted_url(struct client_state *csp) +int is_untrusted_url(const struct client_state *csp) { struct file_list *fl; struct block_spec *b; @@ -1645,6 +1731,7 @@ int is_untrusted_url(struct client_state *csp) return 0; } } + return 1; } #endif /* def FEATURE_TRUST */ @@ -1660,6 +1747,11 @@ int is_untrusted_url(struct client_state *csp) * csp->content_length to the modified size and raise the * CSP_FLAG_MODIFIED flag. * + * XXX: Currently pcrs_filter_response is also responsible + * for dechunking and decompressing. Both should be + * done in separate functions so other content modifiers + * profit as well, even if pcrs filtering is disabled. + * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * @@ -1709,7 +1801,7 @@ char *pcrs_filter_response(struct client_state *csp) if (0 == found_filters) { log_error(LOG_LEVEL_ERROR, "Unable to get current state of regexp filtering."); - return(NULL); + return(NULL); } /* @@ -1727,6 +1819,45 @@ char *pcrs_filter_response(struct client_state *csp) csp->flags |= CSP_FLAG_MODIFIED; } +#ifdef FEATURE_ZLIB + /* + * If the body has a compressed transfer-encoding, + * uncompress it first, adjusting size and iob->eod. + * Note that decompression occurs after de-chunking. + */ + if (csp->content_type & (CT_GZIP | CT_DEFLATE)) + { + /* Notice that we at least tried to decompress. */ + if (JB_ERR_OK != decompress_iob(csp)) + { + /* + * We failed to decompress the data; there's no point + * in continuing since we can't filter. + * + * XXX: Actually the Accept-Encoding header may + * just be incorrect in which case we could continue + * with filtering. + * + * Unset CT_GZIP and CT_DEFLATE to remember not + * to modify the Content-Encoding header later. + */ + csp->content_type &= ~CT_GZIP; + csp->content_type &= ~CT_DEFLATE; + return(NULL); + } + + /* + * Decompression gives us a completely new iob, + * so we need to update. + */ + size = (size_t)(csp->iob->eod - csp->iob->cur); + old = csp->iob->cur; + + csp->flags |= CSP_FLAG_MODIFIED; + csp->content_type &= ~CT_TABOO; + } +#endif + for (i = 0; i < MAX_AF_FILES; i++) { fl = csp->rlist[i]; @@ -1750,6 +1881,12 @@ char *pcrs_filter_response(struct client_state *csp) */ for (b = fl->f; b; b = b->next) { + if (b->type != FT_CONTENT_FILTER) + { + /* Skip header filters */ + continue; + } + for (filtername = csp->action->multi[ACTION_MULTI_FILTER]->first; filtername ; filtername = filtername->next) { @@ -1811,7 +1948,7 @@ char *pcrs_filter_response(struct client_state *csp) } log_error(LOG_LEVEL_RE_FILTER, - "re_filtering %s%s (size %d) with filter %s produced %d hits (new size %d).", + "filtering %s%s (size %d) with \'%s\' produced %d hits (new size %d).", csp->http->hostport, csp->http->path, prev_size, b->name, current_hits, size); hits += current_hits; @@ -2190,29 +2327,42 @@ struct http_response *direct_response(struct client_state *csp) { for (p = csp->headers->first; (p != NULL) ; p = p->next) { - if (!strncmp("Max-Forwards:", p->str, 13) - && (*(p->str+13) != '\0') && (atoi(p->str+13) == 0)) + if (!strncmpic("Max-Forwards:", p->str, 13)) { - /* FIXME: We could handle at least TRACE here, - but that would require a verbatim copy of - the request which we don't have anymore */ + unsigned int max_forwards; - log_error(LOG_LEVEL_HEADER, "Found Max-Forwards:0 in OPTIONS or TRACE request -- Returning 501"); - - /* Get mem for response or fail*/ - if (NULL == (rsp = alloc_http_response())) + /* + * If it's a Max-Forwards value of zero, + * we have to intercept the request. + */ + if (1 == sscanf(p->str+12, ": %u", &max_forwards) && max_forwards == 0) { - return cgi_error_memory(); - } + /* + * FIXME: We could handle at least TRACE here, + * but that would require a verbatim copy of + * the request which we don't have anymore + */ + log_error(LOG_LEVEL_HEADER, + "Detected header \'%s\' in OPTIONS or TRACE request. Returning 501.", + p->str); + + /* Get mem for response or fail*/ + if (NULL == (rsp = alloc_http_response())) + { + return cgi_error_memory(); + } - if (NULL == (rsp->status = strdup("501 Not Implemented"))) - { - free_http_response(rsp); - return cgi_error_memory(); - } + if (NULL == (rsp->status = strdup("501 Not Implemented"))) + { + free_http_response(rsp); + return cgi_error_memory(); + } + + rsp->is_static = 1; + rsp->reason = RSP_REASON_UNSUPPORTED; - rsp->is_static = 1; - return(finish_http_response(rsp)); + return(finish_http_response(csp, rsp)); + } } } }