X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=blobdiff_plain;f=jcc.c;h=03ee6f2f6a85cacd97a369218f0df67b7a5e1b3d;hp=408612bb309f23e27724676bf1b82ddb1a21a026;hb=c54228f0ef0172341cfe4f9acb7e955fa1e269b7;hpb=eb7d670180a9e22a4a1581c5b29825a5ece9d18f diff --git a/jcc.c b/jcc.c index 408612bb..03ee6f2f 100644 --- a/jcc.c +++ b/jcc.c @@ -1,4 +1,4 @@ -const char jcc_rcs[] = "$Id: jcc.c,v 1.139 2007/07/14 07:46:41 fabiankeil Exp $"; +const char jcc_rcs[] = "$Id: jcc.c,v 1.163 2007/12/13 01:47:11 david__schmidt Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/jcc.c,v $ @@ -33,6 +33,107 @@ const char jcc_rcs[] = "$Id: jcc.c,v 1.139 2007/07/14 07:46:41 fabiankeil Exp $" * * Revisions : * $Log: jcc.c,v $ + * Revision 1.163 2007/12/13 01:47:11 david__schmidt + * Make sure all console-mode apps get a usage() instance + * + * Revision 1.162 2007/12/06 17:54:57 fabiankeil + * Reword NO_SERVER_DATA_RESPONSE to make it harder + * to misunderstand what the message is all about. + * + * Revision 1.161 2007/12/04 19:44:22 fabiankeil + * Unbreak trustfile which previously didn't work without + * FEATURE_TOGGLE. Fixes BR#1843585, reported by Lee. + * + * Revision 1.160 2007/11/29 18:00:29 fabiankeil + * Plug memory leak. Spotted by Valgrind, triggered by + * Privoxy-Regression-Test feeding proxyfuzz.py. + * + * Revision 1.159 2007/11/24 14:34:09 fabiankeil + * In the HTTP snipplets, refer to the client as client. + * + * Revision 1.158 2007/11/11 16:44:17 fabiankeil + * Emit a log message when activating the MS IIS5 hack. + * + * Revision 1.157 2007/11/03 17:34:49 fabiankeil + * Log the "weak randomization factor" warning only + * once for mingw32 and provide some more details. + * + * Revision 1.156 2007/11/01 18:20:58 fabiankeil + * Initialize log module after initializing mutexes, future + * deadlocks in that code should now work cross-platform. + * + * Revision 1.155 2007/10/23 20:12:45 fabiankeil + * Fix first CSUCCEED line to end in \r\n as required by RFC1945. + * Reported by Bert van Leeuwen in BR#1818808. + * + * Revision 1.154 2007/10/19 17:00:08 fabiankeil + * Downgrade "Flushing header and buffers" message to LOG_LEVEL_INFO. + * + * Revision 1.153 2007/10/14 14:12:41 fabiankeil + * When in daemon mode, close stderr after the configuration file has been + * parsed the first time. If logfile isn't set, stop logging. Fixes BR#897436. + * + * Revision 1.152 2007/10/04 18:03:34 fabiankeil + * - Fix a crash when parsing invalid requests whose first header + * is rejected by get_header(). Regression (re?)introduced + * in r1.143 by yours truly. + * - Move ACTION_VANILLA_WAFER handling into parsers.c's + * client_cookie_adder() to make sure send-vanilla-wafer can be + * controlled through tags (and thus regression-tested). + * + * Revision 1.151 2007/09/29 10:21:16 fabiankeil + * - Move get_filter_function() from jcc.c to filters.c + * so the filter functions can be static. + * - Don't bother filtering body-less responses. + * + * Revision 1.150 2007/09/28 16:39:29 fabiankeil + * Execute content filters through execute_content_filter(). + * + * Revision 1.149 2007/09/04 15:08:48 fabiankeil + * Initialize req to NULL to make sure it's defined if the + * first read_socket() call fails. Reported by icmp30. + * + * Revision 1.148 2007/08/26 16:47:13 fabiankeil + * Add Stephen Gildea's --pre-chroot-nslookup patch [#1276666], + * extensive comments moved to user manual. + * + * Revision 1.147 2007/08/25 14:42:40 fabiankeil + * Don't crash if a broken header filter wiped out the request line. + * + * Revision 1.146 2007/08/20 17:09:32 fabiankeil + * Fix byte_count calculation in case of flushes + * and don't parse the server headers a second time. + * + * Revision 1.145 2007/08/19 13:13:31 fabiankeil + * - If there's a connection problem after we already forwarded + * parts of the original content, just hang up. Fixes BR#1776724. + * - Fix warnings about unused code on mingw32. + * - In case of flushes, calculate the byte count + * less incorrectly (I think). + * + * Revision 1.144 2007/08/11 14:43:22 fabiankeil + * Add some more prototypes for static functions. + * + * Revision 1.143 2007/08/05 13:58:19 fabiankeil + * Comment out request_contains_null_bytes() until it's used again. + * + * Revision 1.142 2007/08/05 13:50:26 fabiankeil + * #1763173 from Stefan Huehner: s@const static@static const@ + * and declare some more functions static. + * + * Revision 1.141 2007/08/04 09:56:23 fabiankeil + * - Log rejected CONNECT requests with LOG_LEVEL_INFO + * and explain why they were rejected in the first place. + * - Fix the LOG_LEVEL_CLF message for crunches of unallowed + * CONNECT requests. The request line was missing. + * - Add two more XXX reminders as we don't have enough already. + * + * Revision 1.140 2007/07/21 11:51:36 fabiankeil + * As Hal noticed, checking dispatch_cgi() as the last cruncher + * looks like a bug if CGI requests are blocked unintentionally, + * so don't do it unless the user enabled the new config option + * "allow-cgi-request-crunching". + * * Revision 1.139 2007/07/14 07:46:41 fabiankeil * - Allow to rewrite the request destination behind the client's back. * - Turn the weird-looking unconditional for loop that @@ -944,8 +1045,28 @@ int urls_rejected = 0; /* total nr of urls rejected */ int g_terminate = 0; #endif -static void listen_loop(void); +#if !defined(_WIN32) && !defined(__OS2__) && !defined(AMIGA) +static void sig_handler(int the_signal); +#endif +static int client_protocol_is_unsupported(const struct client_state *csp, char *req); +static jb_err get_request_destination_elsewhere(struct client_state *csp, struct list *headers); +static jb_err get_server_headers(struct client_state *csp); +static const char *crunch_reason(const struct http_response *rsp); +static void send_crunch_response(struct client_state *csp, struct http_response *rsp); +/* + * static int request_contains_null_bytes(const struct client_state *csp, char *buf, int len); + */ +static void build_request_line(struct client_state *csp, const struct forward_spec *fwd, char **request_line); +static jb_err change_request_destination(struct client_state *csp); static void chat(struct client_state *csp); +static void serve(struct client_state *csp); +#if !defined(_WIN32) || defined(_WIN_CONSOLE) +static void usage(const char *myname); +#endif +static void initialize_mutexes(void); +static jb_socket bind_port_helper(struct configuration_spec *config); +static void listen_loop(void); + #ifdef AMIGA void serve(struct client_state *csp); #else /* ifndef AMIGA */ @@ -992,73 +1113,65 @@ const char *pidfile = NULL; int received_hup_signal = 0; #endif /* defined unix */ -/* The vanilla wafer. */ -static const char VANILLA_WAFER[] = - "NOTICE=TO_WHOM_IT_MAY_CONCERN_" - "Do_not_send_me_any_copyrighted_information_other_than_the_" - "document_that_I_am_requesting_or_any_of_its_necessary_components._" - "In_particular_do_not_send_me_any_cookies_that_" - "are_subject_to_a_claim_of_copyright_by_anybody._" - "Take_notice_that_I_refuse_to_be_bound_by_any_license_condition_" - "(copyright_or_otherwise)_applying_to_any_cookie._"; - /* HTTP snipplets. */ -const static char CSUCCEED[] = - "HTTP/1.0 200 Connection established\n" +static const char CSUCCEED[] = + "HTTP/1.0 200 Connection established\r\n" "Proxy-Agent: Privoxy/" VERSION "\r\n\r\n"; -const static char CHEADER[] = - "HTTP/1.0 400 Invalid header received from browser\r\n" +static const char CHEADER[] = + "HTTP/1.0 400 Invalid header received from client\r\n" "Proxy-Agent: Privoxy " VERSION "\r\n" "Content-Type: text/plain\r\n" "Connection: close\r\n\r\n" - "Invalid header received from browser.\r\n"; + "Invalid header received from client.\r\n"; -const static char CFORBIDDEN[] = +static const char CFORBIDDEN[] = "HTTP/1.0 403 Connection not allowable\r\n" "Proxy-Agent: Privoxy " VERSION "\r\n" "X-Hint: If you read this message interactively, then you know why this happens ,-)\r\n" "Connection: close\r\n\r\n"; -const static char FTP_RESPONSE[] = - "HTTP/1.0 400 Invalid request received from browser\r\n" +static const char FTP_RESPONSE[] = + "HTTP/1.0 400 Invalid request received from client\r\n" "Content-Type: text/plain\r\n" "Connection: close\r\n\r\n" "Invalid request. Privoxy doesn't support FTP.\r\n"; -const static char GOPHER_RESPONSE[] = - "HTTP/1.0 400 Invalid request received from browser\r\n" +static const char GOPHER_RESPONSE[] = + "HTTP/1.0 400 Invalid request received from client\r\n" "Content-Type: text/plain\r\n" "Connection: close\r\n\r\n" "Invalid request. Privoxy doesn't support gopher.\r\n"; /* XXX: should be a template */ -const static char MISSING_DESTINATION_RESPONSE[] = - "HTTP/1.0 400 Bad request received from browser\r\n" +static const char MISSING_DESTINATION_RESPONSE[] = + "HTTP/1.0 400 Bad request received from client\r\n" "Proxy-Agent: Privoxy " VERSION "\r\n" "Content-Type: text/plain\r\n" "Connection: close\r\n\r\n" "Bad request. Privoxy was unable to extract the destination.\r\n"; /* XXX: should be a template */ -const static char NO_SERVER_DATA_RESPONSE[] = +static const char NO_SERVER_DATA_RESPONSE[] = "HTTP/1.0 502 Server or forwarder response empty\r\n" "Proxy-Agent: Privoxy " VERSION "\r\n" "Content-Type: text/plain\r\n" "Connection: close\r\n\r\n" "Empty server or forwarder response.\r\n" - "The connection was closed without sending any data.\r\n"; + "The connection has been closed but Privoxy didn't receive any data.\r\n"; +#if 0 /* XXX: should be a template */ -const static char NULL_BYTE_RESPONSE[] = - "HTTP/1.0 400 Bad request received from browser\r\n" +static const char NULL_BYTE_RESPONSE[] = + "HTTP/1.0 400 Bad request received from client\r\n" "Proxy-Agent: Privoxy " VERSION "\r\n" "Content-Type: text/plain\r\n" "Connection: close\r\n\r\n" "Bad request. Null byte(s) before end of request.\r\n"; +#endif /* XXX: should be a template */ -const static char MESSED_UP_REQUEST_RESPONSE[] = +static const char MESSED_UP_REQUEST_RESPONSE[] = "HTTP/1.0 400 Malformed request after rewriting\r\n" "Proxy-Agent: Privoxy " VERSION "\r\n" "Content-Type: text/plain\r\n" @@ -1068,8 +1181,6 @@ const static char MESSED_UP_REQUEST_RESPONSE[] = /* A function to crunch a response */ typedef struct http_response *(*crunch_func_ptr)(struct client_state *); -typedef char *(*filter_function_ptr)(); - /* Crunch function flags */ #define CF_NO_FLAGS 0 /* Cruncher applies to forced requests as well */ @@ -1084,8 +1195,10 @@ struct cruncher const int flags; }; +static int crunch_response_triggered(struct client_state *csp, const struct cruncher crunchers[]); + /* Complete list of cruncher functions */ -const static struct cruncher crunchers_all[] = { +static const struct cruncher crunchers_all[] = { { direct_response, CF_COUNT_AS_REJECT|CF_IGNORE_FORCE}, { block_url, CF_COUNT_AS_REJECT }, #ifdef FEATURE_TRUST @@ -1097,7 +1210,7 @@ const static struct cruncher crunchers_all[] = { }; /* Light version, used after tags are applied */ -const static struct cruncher crunchers_light[] = { +static const struct cruncher crunchers_light[] = { { block_url, CF_COUNT_AS_REJECT }, { redirect_url, CF_NO_FLAGS }, { NULL, 0 } @@ -1169,7 +1282,7 @@ static void sig_handler(int the_signal) * FALSE if the request doesn't look invalid. * *********************************************************************/ -int client_protocol_is_unsupported(const struct client_state *csp, char *req) +static int client_protocol_is_unsupported(const struct client_state *csp, char *req) { char buf[BUFFER_SIZE]; @@ -1238,7 +1351,7 @@ int client_protocol_is_unsupported(const struct client_state *csp, char *req) * JB_ERR_PARSE if it isn't. * *********************************************************************/ -jb_err get_request_destination_elsewhere(struct client_state *csp, struct list *headers) +static jb_err get_request_destination_elsewhere(struct client_state *csp, struct list *headers) { char *req; @@ -1305,7 +1418,7 @@ jb_err get_request_destination_elsewhere(struct client_state *csp, struct list * * JB_ERR_PARSE if the headers were incomplete. * *********************************************************************/ -jb_err get_server_headers(struct client_state *csp) +static jb_err get_server_headers(struct client_state *csp) { int continue_hack_in_da_house = 0; char * header; @@ -1391,7 +1504,7 @@ jb_err get_server_headers(struct client_state *csp) * Returns : A string with the crunch reason or an error description. * *********************************************************************/ -const char *crunch_reason(const struct http_response *rsp) +static const char *crunch_reason(const struct http_response *rsp) { char * reason = NULL; @@ -1454,7 +1567,7 @@ const char *crunch_reason(const struct http_response *rsp) * Returns : Nothing. * *********************************************************************/ -void send_crunch_response(struct client_state *csp, struct http_response *rsp) +static void send_crunch_response(struct client_state *csp, struct http_response *rsp) { const struct http_request *http = csp->http; char status_code[4]; @@ -1517,6 +1630,7 @@ void send_crunch_response(struct client_state *csp, struct http_response *rsp) } +#if 0 /********************************************************************* * * Function : request_contains_null_bytes @@ -1524,6 +1638,8 @@ void send_crunch_response(struct client_state *csp, struct http_response *rsp) * Description : Checks for NULL bytes in the request and sends * an error message to the client if any were found. * + * XXX: currently not used, see comment in chat(). + * * Parameters : * 1 : csp = Current client state (buffers, headers, etc...) * 2 : buf = Data from the client's request to check. @@ -1533,7 +1649,7 @@ void send_crunch_response(struct client_state *csp, struct http_response *rsp) * FALSE otherwise. * *********************************************************************/ -int request_contains_null_bytes(const struct client_state *csp, char *buf, int len) +static int request_contains_null_bytes(const struct client_state *csp, char *buf, int len) { size_t c_len; /* Request lenght when treated as C string */ @@ -1573,6 +1689,7 @@ int request_contains_null_bytes(const struct client_state *csp, char *buf, int l return FALSE; } +#endif /********************************************************************* @@ -1590,7 +1707,7 @@ int request_contains_null_bytes(const struct client_state *csp, char *buf, int l * FALSE otherwise. * *********************************************************************/ -int crunch_response_triggered(struct client_state *csp, const struct cruncher crunchers[]) +static int crunch_response_triggered(struct client_state *csp, const struct cruncher crunchers[]) { struct http_response *rsp = NULL; const struct cruncher *c; @@ -1658,7 +1775,7 @@ int crunch_response_triggered(struct client_state *csp, const struct cruncher cr * Returns : Nothing. Terminates in case of memory problems. * *********************************************************************/ -void build_request_line(struct client_state *csp, const struct forward_spec *fwd, char **request_line) +static void build_request_line(struct client_state *csp, const struct forward_spec *fwd, char **request_line) { struct http_request *http = csp->http; @@ -1720,7 +1837,7 @@ void build_request_line(struct client_state *csp, const struct forward_spec *fwd * Terminates in case of memory problems. * *********************************************************************/ -jb_err change_request_destination(struct client_state *csp) +static jb_err change_request_destination(struct client_state *csp) { struct http_request *http = csp->http; jb_err err; @@ -1743,87 +1860,6 @@ jb_err change_request_destination(struct client_state *csp) } -/********************************************************************* - * - * Function : get_filter_function - * - * Description : Decides which content filter function has - * to be applied (if any). - * - * XXX: Doesn't handle filter_popups() - * because of the different prototype. Probably - * we should ditch filter_popups() anyway, it's - * even less reliable than popup blocking based - * on pcrs filters. - * - * Parameters : - * 1 : csp = Current client state (buffers, headers, etc...) - * - * Returns : The content filter function to run, or - * NULL if no content filter is active - * - *********************************************************************/ -filter_function_ptr get_filter_function(struct client_state *csp) -{ - filter_function_ptr filter_function = NULL; - - /* - * Are we enabling text mode by force? - */ - if (csp->action->flags & ACTION_FORCE_TEXT_MODE) - { - /* - * Do we really have to? - */ - if (csp->content_type & CT_TEXT) - { - log_error(LOG_LEVEL_HEADER, "Text mode is already enabled."); - } - else - { - csp->content_type |= CT_TEXT; - log_error(LOG_LEVEL_HEADER, "Text mode enabled by force. Take cover!"); - } - } - - if (!(csp->content_type & CT_DECLARED)) - { - /* - * The server didn't bother to declare a MIME-Type. - * Assume it's text that can be filtered. - * - * This also regulary happens with 304 responses, - * therefore logging anything here would cause - * too much noise. - */ - csp->content_type |= CT_TEXT; - } - - - /* - * Choose the applying filter function based on - * the content type and action settings. - */ - if ((csp->content_type & CT_TEXT) && - (csp->rlist != NULL) && - (!list_is_empty(csp->action->multi[ACTION_MULTI_FILTER]))) - { - filter_function = pcrs_filter_response; - } - else if ((csp->content_type & CT_GIF) && - (csp->action->flags & ACTION_DEANIMATE)) - { - filter_function = gif_deanimate_response; - } - else if ((csp->content_type & CT_JPEG) && - (csp->action->flags & ACTION_JPEG_INSPECT)) - { - filter_function = jpeg_inspect_response; - } - - return filter_function; -} - /********************************************************************* * * Function : chat @@ -1848,7 +1884,7 @@ static void chat(struct client_state *csp) char buf[BUFFER_SIZE]; char *hdr; char *p; - char *req; + char *req = NULL; fd_set rfds; int n; jb_socket maxfd; @@ -1903,7 +1939,7 @@ static void chat(struct client_state *csp) } while ((NULL != req) && ('\0' == *req)); - if (NULL != req) + if ((NULL != req) && ('\0' != *req)) { /* Request received. Validate and parse it. */ @@ -1993,6 +2029,7 @@ static void chat(struct client_state *csp) if (len <= 0) { log_error(LOG_LEVEL_ERROR, "read from client failed: %E"); + destroy_list(headers); return; } @@ -2002,6 +2039,7 @@ static void chat(struct client_state *csp) */ if (add_to_iob(csp, buf, len)) { + destroy_list(headers); return; } continue; @@ -2031,7 +2069,7 @@ static void chat(struct client_state *csp) * An error response has already been send * and we're done here. */ - return; + return; } } @@ -2066,16 +2104,6 @@ static void chat(struct client_state *csp) list_append_list_unique(csp->headers, headers); destroy_list(headers); - /* - * If the user has not supplied any wafers, and the user has not - * told us to suppress the vanilla wafer, then send the vanilla wafer. - */ - if (list_is_empty(csp->action->multi[ACTION_MULTI_WAFER]) - && ((csp->action->flags & ACTION_VANILLA_WAFER) != 0)) - { - enlist(csp->action->multi[ACTION_MULTI_WAFER], VANILLA_WAFER); - } - err = sed(client_patterns, add_client_headers, csp); if (JB_ERR_OK != err) { @@ -2084,22 +2112,21 @@ static void chat(struct client_state *csp) } csp->flags |= CSP_FLAG_CLIENT_HEADER_PARSING_DONE; - if (strcmp(http->cmd, csp->headers->first->str)) + /* Check request line for rewrites. */ + if ((NULL == csp->headers->first->str) + || (strcmp(http->cmd, csp->headers->first->str) && + (JB_ERR_OK != change_request_destination(csp)))) { /* - * A header filter rewrote the request line, - * modify the http request accordingly. + * A header filter broke the request line - bail out. */ - if (JB_ERR_OK != change_request_destination(csp)) - { - write_socket(csp->cfd, MESSED_UP_REQUEST_RESPONSE, strlen(MESSED_UP_REQUEST_RESPONSE)); - /* XXX: Use correct size */ - log_error(LOG_LEVEL_CLF, "%s - - [%T] \"Invalid request generated\" 500 0", csp->ip_addr_str); - log_error(LOG_LEVEL_ERROR, "Invalid request line after applying header filters."); + write_socket(csp->cfd, MESSED_UP_REQUEST_RESPONSE, strlen(MESSED_UP_REQUEST_RESPONSE)); + /* XXX: Use correct size */ + log_error(LOG_LEVEL_CLF, "%s - - [%T] \"Invalid request generated\" 500 0", csp->ip_addr_str); + log_error(LOG_LEVEL_ERROR, "Invalid request line after applying header filters."); - free_http_request(http); - return; - } + free_http_request(http); + return; } /* decide how to route the HTTP request */ @@ -2109,7 +2136,8 @@ static void chat(struct client_state *csp) /* Never get here - LOG_LEVEL_FATAL causes program exit */ } - /* build the http request to send to the server + /* + * build the http request to send to the server * we have to do one of the following: * * create = use the original HTTP request to create a new @@ -2156,25 +2184,38 @@ static void chat(struct client_state *csp) || (csp->action->flags & ACTION_LIMIT_CONNECT && !match_portlist(csp->action->string[ACTION_STRING_LIMIT_CONNECT], csp->http->port)) ) { + const char *acceptable_connect_ports = + csp->action->string[ACTION_STRING_LIMIT_CONNECT] ? + csp->action->string[ACTION_STRING_LIMIT_CONNECT] : + "443 (implied default)"; if (csp->action->flags & ACTION_TREAT_FORBIDDEN_CONNECTS_LIKE_BLOCKS) { /* * The response may confuse some clients, * but makes unblocking easier. + * + * XXX: It seems to work with all major browsers, + * so we should consider returning a body by default someday ... */ - log_error(LOG_LEVEL_ERROR, "Marking suspicious CONNECT request from %s for blocking.", - csp->ip_addr_str); + log_error(LOG_LEVEL_INFO, "Request from %s marked for blocking. " + "limit-connect{%s} doesn't allow CONNECT requests to port %d.", + csp->ip_addr_str, acceptable_connect_ports, csp->http->port); csp->action->flags |= ACTION_BLOCK; http->ssl = 0; } else { write_socket(csp->cfd, CFORBIDDEN, strlen(CFORBIDDEN)); - log_error(LOG_LEVEL_CONNECT, "Denying suspicious CONNECT request from %s", csp->ip_addr_str); - log_error(LOG_LEVEL_CLF, "%s - - [%T] \" \" 403 0", csp->ip_addr_str); + log_error(LOG_LEVEL_INFO, "Request from %s denied. " + "limit-connect{%s} doesn't allow CONNECT requests to port %d.", + csp->ip_addr_str, acceptable_connect_ports, csp->http->port); + assert(NULL != csp->http->ocmd); + log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 403 0", csp->ip_addr_str, csp->http->ocmd); list_remove_all(csp->headers); - + /* + * XXX: For consistency we might want to log a crunch message here. + */ return; } } @@ -2389,10 +2430,23 @@ static void chat(struct client_state *csp) "CONNECT already confirmed. Unable to tell the client about the problem."); return; } + else if (byte_count) + { + /* + * Just hang up. We already transmitted the original headers + * and parts of the original content and therefore missed the + * chance to send an error message (without risking data corruption). + * + * XXX: we could retry with a fancy range request here. + */ + log_error(LOG_LEVEL_ERROR, "Already forwarded the original headers. " + "Unable to tell the client about the problem."); + return; + } rsp = error_response(csp, "connect-failed", errno); - if(rsp) + if (rsp) { send_crunch_response(csp, rsp); } @@ -2443,12 +2497,13 @@ static void chat(struct client_state *csp) */ if (content_filter) { + p = execute_content_filter(csp, content_filter); /* * If the content filter fails, use the original * buffer and length. * (see p != NULL ? p : csp->iob->cur below) */ - if (NULL == (p = (*content_filter)(csp))) + if (NULL == p) { csp->content_length = (size_t)(csp->iob->eod - csp->iob->cur); } @@ -2491,6 +2546,9 @@ static void chat(struct client_state *csp) * This is NOT the body, so * Let's pretend the server just sent us a blank line. */ + log_error(LOG_LEVEL_INFO, + "Malformerd HTTP headers detected and MS IIS5 hack enabled. " + "Expect an invalid response or even no response at all."); snprintf(buf, sizeof(buf), "\r\n"); len = (int)strlen(buf); @@ -2522,11 +2580,8 @@ static void chat(struct client_state *csp) size_t hdrlen; int flushed; - log_error(LOG_LEVEL_ERROR, "Flushing header and buffers. Stepping back from filtering."); - if (JB_ERR_OK != sed(server_patterns, add_server_headers, csp)) - { - log_error(LOG_LEVEL_FATAL, "Failed to parse server headers."); - } + log_error(LOG_LEVEL_INFO, "Flushing header and buffers. Stepping back from filtering."); + hdr = list_to_text(csp->headers); if (hdr == NULL) { @@ -2540,19 +2595,6 @@ static void chat(struct client_state *csp) return; } - - if (crunch_response_triggered(csp, crunchers_light)) - { - /* - * One of the tags created by a server-header - * tagger triggered a crunch. We already - * delivered the crunch response to the client - * and are done here after cleaning up. - */ - freez(hdr); - return; - } - hdrlen = strlen(hdr); if (write_socket(csp->cfd, hdr, hdrlen) @@ -2565,11 +2607,15 @@ static void chat(struct client_state *csp) return; } - byte_count += hdrlen + (size_t)flushed + (size_t)len; + /* + * Reset the byte_count to the amount of bytes + * we just flushed. len will be added a few lines below, + * hdrlen doesn't matter for LOG_LEVEL_CLF. + */ + byte_count = (size_t)flushed; freez(hdr); content_filter = NULL; server_body = 1; - } } else @@ -2799,6 +2845,7 @@ static int32 server_thread(void *data) #endif +#if !defined(_WIN32) || defined(_WIN_CONSOLE) /********************************************************************* * * Function : usage @@ -2810,7 +2857,7 @@ static int32 server_thread(void *data) * Returns : No. ,-) * *********************************************************************/ -void usage(const char *myname) +static void usage(const char *myname) { printf("Privoxy version " VERSION " (" HOME_PAGE_URL ")\n" "Usage: %s " @@ -2819,7 +2866,7 @@ void usage(const char *myname) #endif /* defined(unix) */ "[--help] " #if defined(unix) - "[--no-daemon] [--pidfile pidfile] [--user user[.group]] " + "[--no-daemon] [--pidfile pidfile] [--pre-chroot-nslookup hostname] [--user user[.group]] " #endif /* defined(unix) */ "[--version] [configfile]\n" "Aborting\n", myname); @@ -2827,6 +2874,7 @@ void usage(const char *myname) exit(2); } +#endif /* #if !defined(_WIN32) || defined(_WIN_CONSOLE) */ /********************************************************************* @@ -2840,7 +2888,7 @@ void usage(const char *myname) * Returns : Void, exits in case of errors. * *********************************************************************/ -void initialize_mutexes() +static void initialize_mutexes(void) { int err = 0; @@ -2931,6 +2979,7 @@ int main(int argc, const char *argv[]) struct group *grp = NULL; char *p; int do_chroot = 0; + char *pre_chroot_nslookup_to_load_resolver = NULL; #endif Argc = argc; @@ -3025,6 +3074,12 @@ int main(int argc, const char *argv[]) if (p != NULL) *--p = '\0'; } + else if (strcmp(argv[argc_pos], "--pre-chroot-nslookup" ) == 0) + { + if (++argc_pos == argc) usage(argv[0]); + pre_chroot_nslookup_to_load_resolver = strdup(argv[argc_pos]); + } + else if (strcmp(argv[argc_pos], "--chroot" ) == 0) { do_chroot = 1; @@ -3084,6 +3139,7 @@ int main(int argc, const char *argv[]) files->next = NULL; clients->next = NULL; + /* XXX: factor out initialising after the next stable release. */ #ifdef AMIGA InitAmiga(); #elif defined(_WIN32) @@ -3093,9 +3149,21 @@ int main(int argc, const char *argv[]) /* Prepare mutexes if supported and necessary. */ initialize_mutexes(); + /* Enable logging until further notice. */ + init_log_module(Argv[0]); + random_seed = (unsigned int)time(NULL); #ifdef HAVE_RANDOM srandom(random_seed); +#elif defined (_WIN32) + /* + * See pick_from_range() in miscutil.c for details. + */ + log_error(LOG_LEVEL_INFO, + "No thread-safe PRNG implemented for your platform. " + "Using weak \'randomization\' factor which will " + "limit the already questionable usefulness of " + "header-time-randomizing actions (disabled by default)."); #else srand(random_seed); #endif /* ifdef HAVE_RANDOM */ @@ -3203,10 +3271,9 @@ int main(int argc, const char *argv[]) close ( fd ); } #endif /* 1 */ - /* FIXME: should close stderr (fd 2) here too, but the test - * for existence - * and load config file is done in listen_loop() and puts - * some messages on stderr there. + /* + * stderr (fd 2) will be closed later on, when the + * log file has been parsed. */ close( 0 ); @@ -3233,6 +3300,14 @@ int main(int argc, const char *argv[]) { log_error(LOG_LEVEL_FATAL, "Home directory for %s undefined", pw->pw_name); } + /* Read the time zone file from /etc before doing chroot. */ + tzset(); + if (NULL != pre_chroot_nslookup_to_load_resolver + && '\0' != pre_chroot_nslookup_to_load_resolver[0]) + { + /* Initialize resolver library. */ + (void) resolve_hostname_to_ip(pre_chroot_nslookup_to_load_resolver); + } if (chroot(pw->pw_dir) < 0) { log_error(LOG_LEVEL_FATAL, "Cannot chroot to %s", pw->pw_dir); @@ -3437,7 +3512,7 @@ static void listen_loop(void) */ if (received_hup_signal) { - init_error_log(Argv[0], config->logfile, config->debug); + init_error_log(Argv[0], config->logfile); received_hup_signal = 0; } #endif @@ -3512,10 +3587,10 @@ static void listen_loop(void) #ifdef FEATURE_TOGGLE if (global_toggle_state) +#endif /* def FEATURE_TOGGLE */ { csp->flags |= CSP_FLAG_TOGGLED_ON; } -#endif /* def FEATURE_TOGGLE */ if (run_loader(csp)) {