X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=blobdiff_plain;f=parsers.c;h=c24b518a78d84f3bd81ca5f39861f64bc64d3225;hp=687f2c20629dc518741d69e21510f2ca1a58d682;hb=994e35d0510a22346d510eee39829f91a2f13387;hpb=bdadec585887d286302c690c9bc3bf4ece404594 diff --git a/parsers.c b/parsers.c index 687f2c20..c24b518a 100644 --- a/parsers.c +++ b/parsers.c @@ -1,4 +1,4 @@ -const char parsers_rcs[] = "$Id: parsers.c,v 1.190 2009/07/05 20:43:14 ler762 Exp $"; +const char parsers_rcs[] = "$Id: parsers.c,v 1.210 2009/12/25 11:39:26 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/parsers.c,v $ @@ -156,7 +156,9 @@ static jb_err server_content_disposition(struct client_state *csp, char **header #ifdef FEATURE_CONNECTION_KEEP_ALIVE static jb_err server_save_content_length(struct client_state *csp, char **header); static jb_err server_keep_alive(struct client_state *csp, char **header); +static jb_err server_proxy_connection(struct client_state *csp, char **header); static jb_err client_keep_alive(struct client_state *csp, char **header); +static jb_err client_save_content_length(struct client_state *csp, char **header); #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ static jb_err client_host_adder (struct client_state *csp); @@ -172,7 +174,6 @@ static jb_err create_forged_referrer(char **header, const char *hostport); static jb_err create_fake_referrer(char **header, const char *fake_referrer); static jb_err handle_conditional_hide_referrer_parameter(char **header, const char *host, const int parameter_conditional_block); -static const char *get_appropiate_connection_header(const struct client_state *csp); static void create_content_length_header(unsigned long long content_length, char *header, size_t buffer_length); @@ -204,6 +205,7 @@ static const struct parsers client_patterns[] = { { "if-modified-since:", 18, client_if_modified_since }, #ifdef FEATURE_CONNECTION_KEEP_ALIVE { "Keep-Alive:", 11, client_keep_alive }, + { "Content-Length:", 15, client_save_content_length }, #else { "Keep-Alive:", 11, crumble }, #endif @@ -231,6 +233,7 @@ static const struct parsers server_patterns[] = { #ifdef FEATURE_CONNECTION_KEEP_ALIVE { "Content-Length:", 15, server_save_content_length }, { "Keep-Alive:", 11, server_keep_alive }, + { "Proxy-Connection:", 17, server_proxy_connection }, #else { "Keep-Alive:", 11, crumble }, #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ @@ -585,7 +588,7 @@ jb_err decompress_iob(struct client_state *csp) assert(bufsize >= skip_size); memcpy(buf, csp->iob->buf, skip_size); - zstr.avail_out = bufsize - skip_size; + zstr.avail_out = (uInt)(bufsize - skip_size); zstr.next_out = (Bytef *)buf + skip_size; /* Try to decompress the whole stream in one shot. */ @@ -643,7 +646,7 @@ jb_err decompress_iob(struct client_state *csp) * buffer, which may be in a location different from * the old one. */ - zstr.avail_out += bufsize - oldbufsize; + zstr.avail_out += (uInt)(bufsize - oldbufsize); zstr.next_out = (Bytef *)tmpbuf + bufsize - zstr.avail_out; /* @@ -652,7 +655,6 @@ jb_err decompress_iob(struct client_state *csp) */ assert(zstr.avail_out == tmpbuf + bufsize - (char *)zstr.next_out); assert((char *)zstr.next_out == tmpbuf + ((char *)oldnext_out - buf)); - assert(zstr.avail_out > 0U); buf = tmpbuf; } @@ -1207,7 +1209,6 @@ static jb_err header_tagger(struct client_state *csp, char *header) struct re_filterfile_spec *b; struct list_entry *tag_name; - int found_filters = 0; const size_t header_length = strlen(header); if (csp->flags & CSP_FLAG_CLIENT_HEADER_PARSING_DONE) @@ -1221,21 +1222,7 @@ static jb_err header_tagger(struct client_state *csp, char *header) multi_action_index = ACTION_MULTI_CLIENT_HEADER_TAGGER; } - /* Check if there are any filters */ - for (i = 0; i < MAX_AF_FILES; i++) - { - fl = csp->rlist[i]; - if (NULL != fl) - { - if (NULL != fl->f) - { - found_filters = 1; - break; - } - } - } - - if (0 == found_filters) + if (filters_available(csp) == FALSE) { log_error(LOG_LEVEL_ERROR, "Inconsistent configuration: " "tagging enabled, but no taggers available."); @@ -1418,7 +1405,7 @@ static jb_err filter_header(struct client_state *csp, char **header) struct re_filterfile_spec *b; struct list_entry *filtername; - int i, found_filters = 0; + int i; int wanted_filter_type; int multi_action_index; @@ -1438,23 +1425,7 @@ static jb_err filter_header(struct client_state *csp, char **header) multi_action_index = ACTION_MULTI_CLIENT_HEADER_FILTER; } - /* - * Need to check the set of re_filterfiles... - */ - for (i = 0; i < MAX_AF_FILES; i++) - { - fl = csp->rlist[i]; - if (NULL != fl) - { - if (NULL != fl->f) - { - found_filters = 1; - break; - } - } - } - - if (0 == found_filters) + if (filters_available(csp) == FALSE) { log_error(LOG_LEVEL_ERROR, "Inconsistent configuration: " "header filtering enabled, but no matching filters available."); @@ -1665,12 +1636,37 @@ static jb_err server_keep_alive(struct client_state *csp, char **header) "Server keep-alive timeout is %u. Sticking with %u.", keep_alive_timeout, csp->server_connection.keep_alive_timeout); } + csp->flags |= CSP_FLAG_SERVER_KEEP_ALIVE_TIMEOUT_SET; } return JB_ERR_OK; } +/********************************************************************* + * + * Function : server_proxy_connection + * + * Description : Figures out whether or not we should add a + * Proxy-Connection header. + * + * 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 server_proxy_connection(struct client_state *csp, char **header) +{ + csp->flags |= CSP_FLAG_SERVER_PROXY_CONNECTION_HEADER_SET; + return JB_ERR_OK; +} + + /********************************************************************* * * Function : client_keep_alive @@ -1692,6 +1688,14 @@ static jb_err client_keep_alive(struct client_state *csp, char **header) unsigned int keep_alive_timeout; const char *timeout_position = strstr(*header, ": "); + if (!(csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)) + { + log_error(LOG_LEVEL_HEADER, + "keep-alive support is disabled. Crunching: %s.", *header); + freez(*header); + return JB_ERR_OK; + } + if ((NULL == timeout_position) || (1 != sscanf(timeout_position, ": %u", &keep_alive_timeout))) { @@ -1717,6 +1721,76 @@ static jb_err client_keep_alive(struct client_state *csp, char **header) return JB_ERR_OK; } + + +/********************************************************************* + * + * Function : get_content_length + * + * Description : Gets the content length specified in a + * Content-Length header. + * + * Parameters : + * 1 : header = The Content-Length header. + * 2 : length = Storage to return the value. + * + * Returns : JB_ERR_OK on success, or + * JB_ERR_PARSE if no value is recognized. + * + *********************************************************************/ +static jb_err get_content_length(const char *header, unsigned long long *length) +{ + assert(header[14] == ':'); + +#ifdef _WIN32 + assert(sizeof(unsigned long long) > 4); + if (1 != sscanf(header+14, ": %I64u", length)) +#else + if (1 != sscanf(header+14, ": %llu", length)) +#endif + { + return JB_ERR_PARSE; + } + + return JB_ERR_OK; +} + + +/********************************************************************* + * + * Function : client_save_content_length + * + * Description : Save the Content-Length sent by the client. + * + * 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_MEMORY on out-of-memory error. + * + *********************************************************************/ +static jb_err client_save_content_length(struct client_state *csp, char **header) +{ + unsigned long long content_length = 0; + + assert(*(*header+14) == ':'); + + if (JB_ERR_OK != get_content_length(*header, &content_length)) + { + log_error(LOG_LEVEL_ERROR, "Crunching invalid header: %s", *header); + freez(*header); + } + else + { + csp->expected_client_content_length = content_length; + } + + return JB_ERR_OK; +} #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ @@ -1742,43 +1816,64 @@ static jb_err client_keep_alive(struct client_state *csp, char **header) *********************************************************************/ static jb_err client_connection(struct client_state *csp, char **header) { - const char *wanted_header = get_appropiate_connection_header(csp); + static const char connection_close[] = "Connection: close"; - if (strcmpic(*header, wanted_header)) + if (!strcmpic(*header, connection_close)) { #ifdef FEATURE_CONNECTION_KEEP_ALIVE - if (!(csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_SHARING)) + if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_SHARING)) { - log_error(LOG_LEVEL_HEADER, - "Keeping the client header '%s' around. " - "The connection will not be kept alive.", - *header); + if (!strcmpic(csp->http->ver, "HTTP/1.1")) + { + log_error(LOG_LEVEL_HEADER, + "Removing \'%s\' to imply keep-alive.", *header); + freez(*header); + } + else + { + char *old_header = *header; + + *header = strdup("Connection: keep-alive"); + if (header == NULL) + { + return JB_ERR_MEMORY; + } + log_error(LOG_LEVEL_HEADER, + "Replaced: \'%s\' with \'%s\'", old_header, *header); + freez(old_header); + } } else -#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ { - char *old_header = *header; - - *header = strdup(wanted_header); - if (header == NULL) - { - return JB_ERR_MEMORY; - } log_error(LOG_LEVEL_HEADER, - "Replaced: \'%s\' with \'%s\'", old_header, *header); - freez(old_header); + "Keeping the client header '%s' around. " + "The connection will not be kept alive.", + *header); + csp->flags &= ~CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE; } } -#ifdef FEATURE_CONNECTION_KEEP_ALIVE - else + else if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)) { log_error(LOG_LEVEL_HEADER, "Keeping the client header '%s' around. " "The server connection will be kept alive if possible.", *header); csp->flags |= CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE; - } #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ + } + else + { + char *old_header = *header; + + *header = strdup(connection_close); + if (header == NULL) + { + return JB_ERR_MEMORY; + } + log_error(LOG_LEVEL_HEADER, + "Replaced: \'%s\' with \'%s\'", old_header, *header); + freez(old_header); + } /* Signal client_connection_adder() to return early. */ csp->flags |= CSP_FLAG_CLIENT_CONNECTION_HEADER_SET; @@ -2163,11 +2258,7 @@ static jb_err server_save_content_length(struct client_state *csp, char **header assert(*(*header+14) == ':'); -#ifdef _WIN32 - if (1 != sscanf(*header+14, ": %I64u", &content_length)) -#else - if (1 != sscanf(*header+14, ": %llu", &content_length)) -#endif + if (JB_ERR_OK != get_content_length(*header, &content_length)) { log_error(LOG_LEVEL_ERROR, "Crunching invalid header: %s", *header); freez(*header); @@ -3448,7 +3539,7 @@ static jb_err server_connection_adder(struct client_state *csp) { const unsigned int flags = csp->flags; const char *response_status_line = csp->headers->first->str; - const char *wanted_header = get_appropiate_connection_header(csp); + static const char connection_close[] = "Connection: close"; if ((flags & CSP_FLAG_CLIENT_HEADER_PARSING_DONE) && (flags & CSP_FLAG_SERVER_CONNECTION_HEADER_SET)) @@ -3466,25 +3557,17 @@ static jb_err server_connection_adder(struct client_state *csp) #ifdef FEATURE_CONNECTION_KEEP_ALIVE && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED) #endif - && (csp->http->status == 200) ) { - /* - * XXX: not doing this for status codes other than 200 works - * around problems with broken servers that will keep the - * connection open, but terminate the connection when the - * next request arrives. Once we are able to figure out which - * requests are safe to send again, this will probably no - * longer be necessary. - */ log_error(LOG_LEVEL_HEADER, "A HTTP/1.1 response " "without Connection header implies keep-alive."); csp->flags |= CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE; + return JB_ERR_OK; } - log_error(LOG_LEVEL_HEADER, "Adding: %s", wanted_header); + log_error(LOG_LEVEL_HEADER, "Adding: %s", connection_close); - return enlist(csp->headers, wanted_header); + return enlist(csp->headers, connection_close); } @@ -3510,7 +3593,8 @@ static jb_err server_proxy_connection_adder(struct client_state *csp) jb_err err = JB_ERR_OK; if ((csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE) - && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED)) + && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED) + && !(csp->flags & CSP_FLAG_SERVER_PROXY_CONNECTION_HEADER_SET)) { log_error(LOG_LEVEL_HEADER, "Adding: %s", proxy_connection_header); err = enlist(csp->headers, proxy_connection_header); @@ -3537,7 +3621,7 @@ static jb_err server_proxy_connection_adder(struct client_state *csp) *********************************************************************/ static jb_err client_connection_header_adder(struct client_state *csp) { - const char *wanted_header = get_appropiate_connection_header(csp); + static const char connection_close[] = "Connection: close"; if (!(csp->flags & CSP_FLAG_CLIENT_HEADER_PARSING_DONE) && (csp->flags & CSP_FLAG_CLIENT_CONNECTION_HEADER_SET)) @@ -3551,12 +3635,13 @@ static jb_err client_connection_header_adder(struct client_state *csp) && !strcmpic(csp->http->ver, "HTTP/1.1")) { csp->flags |= CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE; + return JB_ERR_OK; } #endif /* FEATURE_CONNECTION_KEEP_ALIVE */ - log_error(LOG_LEVEL_HEADER, "Adding: %s", wanted_header); + log_error(LOG_LEVEL_HEADER, "Adding: %s", connection_close); - return enlist(csp->headers, wanted_header); + return enlist(csp->headers, connection_close); } @@ -3617,8 +3702,7 @@ static jb_err server_http(struct client_state *csp, char **header) * Function : server_set_cookie * * Description : Handle the server "cookie" header properly. - * Log cookie to the jar file. Then "crunch", - * accept or rewrite it to a session cookie. + * Crunch, accept or rewrite it to a session cookie. * Called from `sed'. * * TODO: Allow the user to specify a new expiration @@ -3696,6 +3780,17 @@ static jb_err server_set_cookie(struct client_state *csp, char **header) { char *expiration_date = cur_tag + 8; /* Skip "[Ee]xpires=" */ + if ((expiration_date[0] == '"') + && (expiration_date[1] != '\0')) + { + /* + * Skip quotation mark. RFC 2109 10.1.2 seems to hint + * that the expiration date isn't supposed to be quoted, + * but some servers do it anyway. + */ + expiration_date++; + } + /* Did we detect the date properly? */ if (JB_ERR_OK != parse_header_time(expiration_date, &cookie_time)) { @@ -4101,37 +4196,6 @@ static jb_err handle_conditional_hide_referrer_parameter(char **header, } -/********************************************************************* - * - * Function : get_appropiate_connection_header - * - * Description : Returns an appropiate Connection header - * depending on whether or not we try to keep - * the connection to the server alive. - * - * Parameters : - * 1 : csp = Current client state (buffers, headers, etc...) - * - * Returns : Pointer to statically allocated header buffer. - * - *********************************************************************/ -static const char *get_appropiate_connection_header(const struct client_state *csp) -{ - static const char connection_keep_alive[] = "Connection: keep-alive"; - static const char connection_close[] = "Connection: close"; - - if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE) -#ifdef FEATURE_CONNECTION_KEEP_ALIVE - && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED) -#endif - && (csp->http->ssl == 0)) - { - return connection_keep_alive; - } - return connection_close; -} - - /********************************************************************* * * Function : create_content_length_header