X-Git-Url: http://www.privoxy.org/gitweb/?a=blobdiff_plain;f=parsers.c;h=536d57d9769a78ac100868f6e664e80f4ca7b0a5;hb=c651e1b8313ce78d42ff1be458bcba5852d6cdcb;hp=e29c451d195fac613d02869daeddac5d9fd3e44b;hpb=963066a492296d381f6dcd5a9c0eedcac98a9ea3;p=privoxy.git diff --git a/parsers.c b/parsers.c index e29c451d..536d57d9 100644 --- a/parsers.c +++ b/parsers.c @@ -1,4 +1,4 @@ -const char parsers_rcs[] = "$Id: parsers.c,v 1.245 2012/04/06 15:17:10 fabiankeil Exp $"; +const char parsers_rcs[] = "$Id: parsers.c,v 1.252 2012/09/18 17:39:29 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/parsers.c,v $ @@ -1025,6 +1025,79 @@ static jb_err scan_headers(struct client_state *csp) } +/********************************************************************* + * + * Function : enforce_header_order + * + * Description : Enforces a given header order. + * + * Parameters : + * 1 : headers = List of headers to order. + * 2 : ordered_headers = List of ordered header names. + * + * Returns : N/A + * + *********************************************************************/ +static void enforce_header_order(struct list *headers, const struct list *ordered_headers) +{ + struct list_entry *sorted_header; + struct list new_headers[1]; + struct list_entry *header; + + init_list(new_headers); + + /* The request line is always the first "header" */ + + assert(NULL != headers->first->str); + enlist(new_headers, headers->first->str); + freez(headers->first->str) + + /* Enlist the specified headers in the given order */ + + for (sorted_header = ordered_headers->first; sorted_header != NULL; + sorted_header = sorted_header->next) + { + const size_t sorted_header_length = strlen(sorted_header->str); + for (header = headers->first; header != NULL; header = header->next) + { + /* Header enlisted in previous run? -> ignore */ + if (header->str == NULL) continue; + + if (0 == strncmpic(sorted_header->str, header->str, sorted_header_length) + && (header->str[sorted_header_length] == ':')) + { + log_error(LOG_LEVEL_HEADER, "Enlisting sorted header %s", header->str); + if (JB_ERR_OK != enlist(new_headers, header->str)) + { + log_error(LOG_LEVEL_HEADER, "Failed to enlist %s", header->str); + } + freez(header->str); + } + } + } + + /* Enlist the rest of the headers behind the ordered ones */ + for (header = headers->first; header != NULL; header = header->next) + { + /* Header enlisted in previous run? -> ignore */ + if (header->str == NULL) continue; + + log_error(LOG_LEVEL_HEADER, + "Enlisting left-over header %s", header->str); + if (JB_ERR_OK != enlist(new_headers, header->str)) + { + log_error(LOG_LEVEL_HEADER, "Failed to enlist %s", header->str); + } + freez(header->str); + } + + list_remove_all(headers); + list_duplicate(headers, new_headers); + list_remove_all(new_headers); + + return; +} + /********************************************************************* * * Function : sed @@ -1091,6 +1164,11 @@ jb_err sed(struct client_state *csp, int filter_server_headers) f++; } + if (!filter_server_headers && !list_is_empty(csp->config->ordered_client_headers)) + { + enforce_header_order(csp->headers, csp->config->ordered_client_headers); + } + return err; } @@ -1722,22 +1800,20 @@ static jb_err client_keep_alive(struct client_state *csp, char **header) * Content-Length header. * * Parameters : - * 1 : header = The Content-Length header. + * 1 : header_value = The Content-Length header value. * 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) +static jb_err get_content_length(const char *header_value, unsigned long long *length) { - assert(header[14] == ':'); - #ifdef _WIN32 assert(sizeof(unsigned long long) > 4); - if (1 != sscanf(header+14, ": %I64u", length)) + if (1 != sscanf(header_value, "%I64u", length)) #else - if (1 != sscanf(header+14, ": %llu", length)) + if (1 != sscanf(header_value, "%llu", length)) #endif { return JB_ERR_PARSE; @@ -1767,10 +1843,12 @@ static jb_err get_content_length(const char *header, unsigned long long *length) static jb_err client_save_content_length(struct client_state *csp, char **header) { unsigned long long content_length = 0; + const char *header_value; assert(*(*header+14) == ':'); - if (JB_ERR_OK != get_content_length(*header, &content_length)) + header_value = *header + 15; + if (JB_ERR_OK != get_content_length(header_value, &content_length)) { log_error(LOG_LEVEL_ERROR, "Crunching invalid header: %s", *header); freez(*header); @@ -1811,7 +1889,8 @@ static jb_err client_connection(struct client_state *csp, char **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) + && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED)) { if (!strcmpic(csp->http->ver, "HTTP/1.1")) { @@ -1843,7 +1922,8 @@ static jb_err client_connection(struct client_state *csp, char **header) csp->flags &= ~CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE; } } - else if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)) + else if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE) + && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED)) { log_error(LOG_LEVEL_HEADER, "Keeping the client header '%s' around. " @@ -1862,7 +1942,7 @@ static jb_err client_connection(struct client_state *csp, char **header) freez(old_header); } - /* Signal client_connection_adder() to return early. */ + /* Signal client_connection_header_adder() to return early. */ csp->flags |= CSP_FLAG_CLIENT_CONNECTION_HEADER_SET; return JB_ERR_OK; @@ -2300,10 +2380,12 @@ static jb_err server_adjust_content_length(struct client_state *csp, char **head static jb_err server_save_content_length(struct client_state *csp, char **header) { unsigned long long content_length = 0; + const char *header_value; assert(*(*header+14) == ':'); - if (JB_ERR_OK != get_content_length(*header, &content_length)) + header_value = *header + 15; + if (JB_ERR_OK != get_content_length(header_value, &content_length)) { log_error(LOG_LEVEL_ERROR, "Crunching invalid header: %s", *header); freez(*header); @@ -3585,8 +3667,7 @@ static jb_err server_connection_adder(struct client_state *csp) * Function : server_proxy_connection_adder * * Description : Adds a "Proxy-Connection: keep-alive" header to - * csp->headers if the client asked for keep-alive. - * XXX: We should reuse existent ones. + * csp->headers when appropriate. * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) @@ -3639,6 +3720,7 @@ static jb_err client_connection_header_adder(struct client_state *csp) #ifdef FEATURE_CONNECTION_KEEP_ALIVE if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE) + && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED) && (csp->http->ssl == 0) && !strcmpic(csp->http->ver, "HTTP/1.1")) { @@ -4225,6 +4307,39 @@ static void create_content_length_header(unsigned long long content_length, } +/********************************************************************* + * + * Function : get_expected_content_length + * + * Description : Figures out the content length from a list of headers. + * + * Parameters : + * 1 : headers = List of headers + * + * Returns : Number of bytes to expect + * + *********************************************************************/ +unsigned long long get_expected_content_length(struct list *headers) +{ + const char *content_length_header; + unsigned long long content_length = 0; + + content_length_header = get_header_value(headers, "Content-Length:"); + if (content_length_header != NULL) + { + if (JB_ERR_OK != get_content_length(content_length_header, &content_length)) + { + log_error(LOG_LEVEL_ERROR, + "Failed to get the Content-Length in %s", content_length_header); + /* XXX: The header will be removed later on */ + return 0; + } + } + + return content_length; +} + + /* Local Variables: tab-width: 3