X-Git-Url: http://www.privoxy.org/gitweb/?a=blobdiff_plain;f=parsers.c;h=0e58c1157453ac91195ed4be49b7a5fc756b84ba;hb=17733b62b31ff476531e054b6fcf553eb8fb107b;hp=70a57a2e564d6ca785db6fc1afc0643b68d7038e;hpb=a8214172984f66ffd964e1e749ca2682dd958947;p=privoxy.git diff --git a/parsers.c b/parsers.c index 70a57a2e..0e58c115 100644 --- a/parsers.c +++ b/parsers.c @@ -1,4 +1,4 @@ -const char parsers_rcs[] = "$Id: parsers.c,v 1.268 2012/11/24 14:07:57 fabiankeil Exp $"; +const char parsers_rcs[] = "$Id: parsers.c,v 1.279 2013/08/06 12:59:34 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/parsers.c,v $ @@ -148,6 +148,7 @@ static jb_err server_connection_adder(struct client_state *csp); #ifdef FEATURE_CONNECTION_KEEP_ALIVE static jb_err server_proxy_connection_adder(struct client_state *csp); #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ +static jb_err proxy_authentication(struct client_state *csp, char **header); static jb_err create_forged_referrer(char **header, const char *hostport); static jb_err create_fake_referrer(char **header, const char *fake_referrer); @@ -198,6 +199,10 @@ static const struct parsers client_patterns[] = { { "Request-Range:", 14, client_range }, { "If-Range:", 9, client_range }, { "X-Filter:", 9, client_x_filter }, + { "Proxy-Authorization:", 20, proxy_authentication }, +#if 0 + { "Transfer-Encoding:", 18, client_transfer_encoding }, +#endif { "*", 0, crunch_client_header }, { "*", 0, filter_header }, { NULL, 0, NULL } @@ -220,6 +225,7 @@ static const struct parsers server_patterns[] = { { "Transfer-Encoding:", 18, server_transfer_coding }, { "content-disposition:", 20, server_content_disposition }, { "Last-Modified:", 14, server_last_modified }, + { "Proxy-Authenticate:", 19, proxy_authentication }, { "*", 0, crunch_server_header }, { "*", 0, filter_header }, { NULL, 0, NULL } @@ -1091,6 +1097,7 @@ static void enforce_header_order(struct list *headers, const struct list *ordere return; } + /********************************************************************* * * Function : sed @@ -1120,19 +1127,21 @@ jb_err sed(struct client_state *csp, int filter_server_headers) const add_header_func_ptr *f; jb_err err = JB_ERR_OK; + scan_headers(csp); + if (filter_server_headers) { v = server_patterns; f = add_server_headers; + check_negative_tag_patterns(csp, PATTERN_SPEC_NO_RESPONSE_TAG_PATTERN); } else { v = client_patterns; f = add_client_headers; + check_negative_tag_patterns(csp, PATTERN_SPEC_NO_REQUEST_TAG_PATTERN); } - scan_headers(csp); - while ((err == JB_ERR_OK) && (v->str != NULL)) { for (p = csp->headers->first; (err == JB_ERR_OK) && (p != NULL); p = p->next) @@ -1290,10 +1299,10 @@ static jb_err header_tagger(struct client_state *csp, char *header) multi_action_index = ACTION_MULTI_CLIENT_HEADER_TAGGER; } - if (filters_available(csp) == FALSE) + if (list_is_empty(csp->action->multi[multi_action_index]) + || filters_available(csp) == FALSE) { - log_error(LOG_LEVEL_ERROR, "Inconsistent configuration: " - "tagging enabled, but no taggers available."); + /* Return early if no taggers apply or if none are available. */ return JB_ERR_OK; } @@ -1380,7 +1389,7 @@ static jb_err header_tagger(struct client_state *csp, char *header) if (0 == size) { /* - * There is to technical limitation which makes + * There is no technical limitation which makes * it impossible to use empty tags, but I assume * no one would do it intentionally. */ @@ -1493,10 +1502,10 @@ static jb_err filter_header(struct client_state *csp, char **header) multi_action_index = ACTION_MULTI_CLIENT_HEADER_FILTER; } - if (filters_available(csp) == FALSE) + if (list_is_empty(csp->action->multi[multi_action_index]) + || filters_available(csp) == FALSE) { - log_error(LOG_LEVEL_ERROR, "Inconsistent configuration: " - "header filtering enabled, but no matching filters available."); + /* Return early if no filters apply or if none are available. */ return JB_ERR_OK; } @@ -1730,6 +1739,36 @@ static jb_err server_proxy_connection(struct client_state *csp, char **header) } +/********************************************************************* + * + * Function : proxy_authentication + * + * Description : Removes headers that are relevant for proxy + * authentication unless forwarding them has + * been explicitly requested. + * + * Parameters : + * 1 : csp = Current client state (buffers, headers, etc...) + * 2 : header = On input, pointer to header to modify. + * On output, pointer to the modified header, or NULL + * to remove the header. This function frees the + * original string if necessary. + * + * Returns : JB_ERR_OK. + * + *********************************************************************/ +static jb_err proxy_authentication(struct client_state *csp, char **header) +{ + if ((csp->config->feature_flags & + RUNTIME_FEATURE_FORWARD_PROXY_AUTHENTICATION_HEADERS) == 0) { + log_error(LOG_LEVEL_HEADER, + "Forwarding proxy authentication headers is disabled. Crunching: %s", *header); + freez(*header); + } + return JB_ERR_OK; +} + + /********************************************************************* * * Function : client_keep_alive @@ -1979,6 +2018,38 @@ static jb_err client_proxy_connection(struct client_state *csp, char **header) #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ +/********************************************************************* + * + * Function : client_transfer_encoding + * + * Description : Raise the CSP_FLAG_CHUNKED_CLIENT_BODY flag if + * the request body is "chunked" + * + * XXX: Currently not called through sed() as we + * need the flag earlier on. Should be fixed. + * + * Parameters : + * 1 : csp = Current client state (buffers, headers, etc...) + * 2 : header = On input, pointer to header to modify. + * On output, pointer to the modified header, or NULL + * to remove the header. This function frees the + * original string if necessary. + * + * Returns : JB_ERR_OK on success, or + * + *********************************************************************/ +jb_err client_transfer_encoding(struct client_state *csp, char **header) +{ + if (strstr(*header, "chunked")) + { + csp->flags |= CSP_FLAG_CHUNKED_CLIENT_BODY; + log_error(LOG_LEVEL_HEADER, "Expecting chunked client body"); + } + + return JB_ERR_OK; +} + + /********************************************************************* * * Function : crumble @@ -2070,17 +2141,25 @@ static jb_err server_content_type(struct client_state *csp, char **header) /* Remove header if it isn't the first Content-Type header */ if ((csp->content_type & CT_DECLARED)) { - /* - * Another, slightly slower, way to see if - * we already parsed another Content-Type header. - */ - assert(NULL != get_header_value(csp->headers, "Content-Type:")); - - log_error(LOG_LEVEL_ERROR, - "Multiple Content-Type headers. Removing and ignoring: \'%s\'", - *header); - freez(*header); - + if (content_filters_enabled(csp->action)) + { + /* + * Making sure the client interprets the content the same way + * Privoxy did is only relevant if Privoxy modified it. + * + * Checking for this is "hard" as it's not yet known when + * this function is called, thus go shopping and and just + * check if Privoxy could filter it. + * + * The main thing is that we don't mess with the headers + * unless the user signalled that it's acceptable. + */ + log_error(LOG_LEVEL_HEADER, + "Multiple Content-Type headers detected. " + "Removing and ignoring: %s", + *header); + freez(*header); + } return JB_ERR_OK; } @@ -3192,9 +3271,6 @@ static jb_err client_max_forwards(struct client_state *csp, char **header) * port information, parse and evaluate the Host * header field. * - * Also, kill ill-formed HOST: headers as sent by - * Apple's iTunes software when used with a proxy. - * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : header = On input, pointer to header to modify. @@ -3210,18 +3286,6 @@ static jb_err client_host(struct client_state *csp, char **header) { char *p, *q; - /* - * If the header field name is all upper-case, chances are that it's - * an ill-formed one from iTunes. BTW, killing innocent headers here is - * not a problem -- they are regenerated later. - */ - if ((*header)[1] == 'O') - { - log_error(LOG_LEVEL_HEADER, "Killed all-caps Host header line: %s", *header); - freez(*header); - return JB_ERR_OK; - } - if (!csp->http->hostport || (*csp->http->hostport == '*') || *csp->http->hostport == ' ' || *csp->http->hostport == '\0') { @@ -3925,7 +3989,7 @@ static jb_err server_set_cookie(struct client_state *csp, char **header) { log_error(LOG_LEVEL_FATAL, "Invalid cookie lifetime limit: %s", param); } - cookie_lifetime *= 60U; + cookie_lifetime *= 60; } /* Loop through each tag in the cookie */ @@ -4177,6 +4241,44 @@ static jb_err parse_header_time(const char *header_time, time_t *result) continue; } *result = timegm(&gmt); + +#ifdef FEATURE_STRPTIME_SANITY_CHECKS + /* + * Verify that parsing the date recreated from the first + * parse operation gets the previous result. If it doesn't, + * either strptime() or strftime() are malfunctioning. + * + * We could string-compare the recreated date with the original + * header date, but this leads to false positives as strptime() + * may let %a accept all day formats while strftime() will only + * create one. + */ + { + char recreated_date[100]; + struct tm *tm; + time_t result2; + + tm = gmtime(result); + strftime(recreated_date, sizeof(recreated_date), time_formats[i], tm); + memset(&gmt, 0, sizeof(gmt)); + if (NULL == strptime(recreated_date, time_formats[i], &gmt)) + { + log_error(LOG_LEVEL_ERROR, + "Failed to parse '%s' generated with '%s' to recreate '%s'.", + recreated_date, time_formats[i], header_time); + continue; + } + result2 = timegm(&gmt); + if (*result != result2) + { + log_error(LOG_LEVEL_ERROR, "strftime() and strptime() disagree. " + "Format: '%s'. In: '%s', out: '%s'. %d != %d. Rejecting.", + time_formats[i], header_time, recreated_date, *result, result2); + continue; + } + } +#endif + return JB_ERR_OK; } }