X-Git-Url: http://www.privoxy.org/gitweb/?a=blobdiff_plain;f=jcc.c;h=c1a3a6e795deb39108c60bf34ed5e52c5adaee4a;hb=b14150078393effcdaf37c436b789919e2ea12af;hp=a5e561f5e69bd9b9c166077014cd6a45642e3fd4;hpb=aa5ec3cea82a006dbc031c8fdde5a26fcefa2c18;p=privoxy.git diff --git a/jcc.c b/jcc.c index a5e561f5..c1a3a6e7 100644 --- a/jcc.c +++ b/jcc.c @@ -228,64 +228,64 @@ static const char CHEADER[] = "HTTP/1.1 400 Invalid header received from client\r\n" "Content-Type: text/plain\r\n" "Connection: close\r\n\r\n" - "Invalid header received from client.\r\n"; + "Invalid header received from client.\n"; static const char FTP_RESPONSE[] = "HTTP/1.1 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"; + "Invalid request. Privoxy doesn't support FTP.\n"; static const char GOPHER_RESPONSE[] = "HTTP/1.1 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"; + "Invalid request. Privoxy doesn't support gopher.\n"; /* XXX: should be a template */ static const char MISSING_DESTINATION_RESPONSE[] = "HTTP/1.1 400 Bad request received from client\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"; + "Bad request. Privoxy was unable to extract the destination.\n"; /* XXX: should be a template */ static const char INVALID_SERVER_HEADERS_RESPONSE[] = "HTTP/1.1 502 Server or forwarder response invalid\r\n" "Content-Type: text/plain\r\n" "Connection: close\r\n\r\n" - "Bad response. The server or forwarder response doesn't look like HTTP.\r\n"; + "Bad response. The server or forwarder response doesn't look like HTTP.\n"; /* XXX: should be a template */ static const char MESSED_UP_REQUEST_RESPONSE[] = "HTTP/1.1 400 Malformed request after rewriting\r\n" "Content-Type: text/plain\r\n" "Connection: close\r\n\r\n" - "Bad request. Messed up with header filters.\r\n"; + "Bad request. Messed up with header filters.\n"; static const char TOO_MANY_CONNECTIONS_RESPONSE[] = "HTTP/1.1 503 Too many open connections\r\n" "Content-Type: text/plain\r\n" "Connection: close\r\n\r\n" - "Maximum number of open connections reached.\r\n"; + "Maximum number of open connections reached.\n"; static const char CLIENT_CONNECTION_TIMEOUT_RESPONSE[] = "HTTP/1.1 504 Connection timeout\r\n" "Content-Type: text/plain\r\n" "Connection: close\r\n\r\n" - "The connection timed out because the client request didn't arrive in time.\r\n"; + "The connection timed out because the client request didn't arrive in time.\n"; static const char CLIENT_BODY_PARSE_ERROR_RESPONSE[] = "HTTP/1.1 400 Failed reading client body\r\n" "Content-Type: text/plain\r\n" "Connection: close\r\n\r\n" - "Failed parsing or buffering the chunk-encoded client body.\r\n"; + "Failed parsing or buffering the chunk-encoded client body.\n"; static const char UNSUPPORTED_CLIENT_EXPECTATION_ERROR_RESPONSE[] = "HTTP/1.1 417 Expecting too much\r\n" "Content-Type: text/plain\r\n" "Connection: close\r\n\r\n" - "Privoxy detected an unsupported Expect header value.\r\n"; + "Privoxy detected an unsupported Expect header value.\n"; /* A function to crunch a response */ typedef struct http_response *(*crunch_func_ptr)(struct client_state *); @@ -376,7 +376,8 @@ static void sig_handler(int the_signal) * We shouldn't be here, unless we catch signals * in main() that we can't handle here! */ - log_error(LOG_LEVEL_FATAL, "sig_handler: exiting on unexpected signal %d", the_signal); + log_error(LOG_LEVEL_FATAL, + "sig_handler: exiting on unexpected signal %d", the_signal); } return; @@ -1044,6 +1045,16 @@ static jb_err change_request_destination(struct client_state *csp) log_error(LOG_LEVEL_ERROR, "Couldn't parse rewritten request: %s.", jb_err_to_string(err)); } + if (http->ssl && strcmpic(csp->http->gpc, "CONNECT")) + { + /* + * A client header filter changed the request URL from + * http:// to https:// which we currently don't support. + */ + log_error(LOG_LEVEL_ERROR, "Changing the request destination from http " + "to https behind the client's back currently isn't supported."); + return JB_ERR_PARSE; + } return err; } @@ -1542,7 +1553,8 @@ static jb_err receive_chunked_client_request_body(struct client_state *csp) len = read_socket(csp->cfd, buf, sizeof(buf) - 1); if (len <= 0) { - log_error(LOG_LEVEL_ERROR, "Read the client body failed: %E"); + log_error(LOG_LEVEL_ERROR, + "Reading the client body failed: %E"); break; } if (add_to_iob(csp->client_iob, csp->config->buffer_limit, buf, len)) @@ -1850,7 +1862,7 @@ static jb_err receive_client_request(struct client_state *csp) * elsewhere failed or Privoxy is configured * to only accept proxy requests. * - * An error response has already been send + * An error response has already been sent * and we're done here. */ return JB_ERR_PARSE; @@ -1971,7 +1983,7 @@ static jb_err parse_client_request(struct client_state *csp) strlen(MESSED_UP_REQUEST_RESPONSE), get_write_delay(csp)); /* XXX: Use correct size */ log_error(LOG_LEVEL_CLF, - "%s - - [%T] \"Invalid request generated\" 500 0", csp->ip_addr_str); + "%s - - [%T] \"Invalid request generated\" 400 0", csp->ip_addr_str); log_error(LOG_LEVEL_ERROR, "Invalid request line after applying header filters."); free_http_request(http); @@ -2022,7 +2034,7 @@ static int read_http_request_body(struct client_state *csp) size_t max_bytes_to_read = to_read < sizeof(buf) ? to_read : sizeof(buf); log_error(LOG_LEVEL_CONNECT, - "Waiting for up to %d bytes of request body from the client.", + "Waiting for up to %lu bytes of request body from the client.", max_bytes_to_read); len = read_socket(csp->cfd, buf, (int)max_bytes_to_read); if (len <= -1) @@ -2039,11 +2051,11 @@ static int read_http_request_body(struct client_state *csp) if (to_read != 0) { - log_error(LOG_LEVEL_CONNECT, "Not enough request body has been read: expected %d more bytes", + log_error(LOG_LEVEL_CONNECT, "Not enough request body has been read: expected %llu more bytes", csp->expected_client_content_length); return 1; } - log_error(LOG_LEVEL_CONNECT, "The last %d bytes of the request body have been read", + log_error(LOG_LEVEL_CONNECT, "The last %llu bytes of the request body have been read", csp->expected_client_content_length); return 0; } @@ -2116,8 +2128,8 @@ static int can_filter_request_body(const struct client_state *csp) csp->expected_client_content_length)) { log_error(LOG_LEVEL_INFO, - "Not filtering request body from %s: buffer limit %d will be exceeded " - "(content length %d)", csp->ip_addr_str, csp->config->buffer_limit, + "Not filtering request body from %s: buffer limit %lu will be exceeded " + "(content length %lluu)", csp->ip_addr_str, csp->config->buffer_limit, csp->expected_client_content_length); return FALSE; } @@ -2249,7 +2261,7 @@ static int read_https_request_body(struct client_state *csp) size_t max_bytes_to_read = to_read < sizeof(buf) ? to_read : sizeof(buf); log_error(LOG_LEVEL_CONNECT, - "Waiting for up to %d bytes of request body from the client.", + "Waiting for up to %lu bytes of request body from the client.", max_bytes_to_read); len = ssl_recv_data(&(csp->ssl_client_attr), buf, (unsigned)max_bytes_to_read); @@ -2267,11 +2279,14 @@ static int read_https_request_body(struct client_state *csp) if (to_read != 0) { - log_error(LOG_LEVEL_CONNECT, "Not enough request body has been read: expected %d more bytes", to_read); + log_error(LOG_LEVEL_CONNECT, + "Not enough request body has been read: expected %lu more bytes", + to_read); return 1; } - log_error(LOG_LEVEL_CONNECT, "The last %d bytes of the request body have been read", + log_error(LOG_LEVEL_CONNECT, + "The last %llu bytes of the request body have been read", csp->expected_client_content_length); return 0; } @@ -2546,6 +2561,7 @@ static jb_err change_encrypted_request_destination(struct client_state *csp) { jb_err err; char *original_host = csp->http->host; + int original_port = csp->http->port; log_error(LOG_LEVEL_REDIRECTS, "Rewrite detected: %s", csp->https_headers->first->str); @@ -2556,27 +2572,38 @@ static jb_err change_encrypted_request_destination(struct client_state *csp) { log_error(LOG_LEVEL_ERROR, "Couldn't parse rewritten request: %s.", jb_err_to_string(err)); + freez(original_host); return err; } if (csp->http->host == NULL) { + char port_string[10]; /* * The rewritten request line did not specify a host * which means we can use the original host specified * by the client. */ csp->http->host = original_host; + csp->http->port = original_port; log_error(LOG_LEVEL_REDIRECTS, "Keeping the original host: %s", csp->http->host); /* * If the rewritten request line didn't contain a host * it also didn't contain a port so we can reuse the host - * and set the port to 443. + * port. */ freez(csp->http->hostport); csp->http->hostport = strdup_or_die(csp->http->host); - csp->http->port = 443; + snprintf(port_string, sizeof(port_string), ":%d", original_port); + err = string_append(&csp->http->hostport, port_string); + if (err != JB_ERR_OK) + { + log_error(LOG_LEVEL_ERROR, "Failed to rebuild hostport: %s.", + jb_err_to_string(err)); + return err; + } + /* * While the request line didn't mention it, * we're https-inspecting and want to speak TLS @@ -2802,10 +2829,15 @@ static jb_err process_encrypted_request(struct client_state *csp) || (strcmp(csp->http->cmd, csp->https_headers->first->str) && (JB_ERR_OK != change_encrypted_request_destination(csp)))) { - log_error(LOG_LEVEL_ERROR, - "Failed to get the request destination in the rewritten headers"); ssl_send_data_delayed(&(csp->ssl_client_attr), - (const unsigned char *)CHEADER, strlen(CHEADER), get_write_delay(csp)); + (const unsigned char *)MESSED_UP_REQUEST_RESPONSE, + strlen(MESSED_UP_REQUEST_RESPONSE), get_write_delay(csp)); + log_error(LOG_LEVEL_ERROR, + "Invalid request line after applying header filters."); + /* XXX: Use correct size */ + log_error(LOG_LEVEL_CLF, + "%s - - [%T] \"Invalid request generated\" 400 0", csp->ip_addr_str); + return JB_ERR_PARSE; } @@ -2878,6 +2910,7 @@ static void continue_https_chat(struct client_state *csp) if (JB_ERR_OK != process_encrypted_request(csp)) { + csp->flags &= ~CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE; return; } @@ -3912,8 +3945,8 @@ static void handle_established_connection(struct client_state *csp) if ((ssl_send_data_delayed(&(csp->ssl_client_attr), (const unsigned char *)hdr, strlen(hdr), get_write_delay(csp)) < 0) - || (len = ssl_flush_socket(&(csp->ssl_client_attr), - csp->iob) < 0)) + || ((len = ssl_flush_socket(&(csp->ssl_client_attr), + csp->iob)) < 0)) { log_error(LOG_LEVEL_CONNECT, "Write header to client failed"); @@ -6155,14 +6188,9 @@ static void listen_loop(void) /* NOTREACHED unless FEATURE_GRACEFUL_TERMINATION is defined */ -#ifdef FEATURE_HTTPS_INSPECTION - /* Clean up. Aim: free all memory (no leaks) */ - ssl_release(); -#endif - #ifdef FEATURE_GRACEFUL_TERMINATION - log_error(LOG_LEVEL_INFO, "Graceful termination requested"); + log_error(LOG_LEVEL_INFO, "Graceful termination requested."); unload_current_config_file(); unload_current_actions_file(); @@ -6182,7 +6210,8 @@ static void listen_loop(void) if (i <= 0) { - log_error(LOG_LEVEL_ERROR, "Graceful termination failed - still some live clients after 1 minute wait."); + log_error(LOG_LEVEL_ERROR, "Graceful termination failed " + "- still some live clients after 1 minute wait."); } } sweep(); @@ -6192,6 +6221,19 @@ static void listen_loop(void) freez(basedir); #endif +#ifdef FEATURE_HTTPS_INSPECTION + /* + * Only release TLS backed resources if there + * are no active connections left. + */ + if (clients->next == NULL) + { + ssl_release(); + } +#endif + + log_error(LOG_LEVEL_INFO, "Exiting gracefully."); + #if defined(_WIN32) && !defined(_WIN_CONSOLE) /* Cleanup - remove taskbar icon etc. */ TermLogWindow();