X-Git-Url: http://www.privoxy.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=jcc.c;h=96302a19a48080ab4f7822ece34f734a25e83e7f;hb=9ef142653b0e898d489fbd701c0f0a4b2e8b8273;hp=61ee70a19332bd16a9ba66206d400654880b9164;hpb=f4107f65b676b63a199fe4230e58695757f9f199;p=privoxy.git diff --git a/jcc.c b/jcc.c index 61ee70a1..96302a19 100644 --- a/jcc.c +++ b/jcc.c @@ -1,4 +1,4 @@ -const char jcc_rcs[] = "$Id: jcc.c,v 1.170 2008/03/06 16:33:46 fabiankeil Exp $"; +const char jcc_rcs[] = "$Id: jcc.c,v 1.180 2008/05/21 15:26:32 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/jcc.c,v $ @@ -33,6 +33,43 @@ const char jcc_rcs[] = "$Id: jcc.c,v 1.170 2008/03/06 16:33:46 fabiankeil Exp $" * * Revisions : * $Log: jcc.c,v $ + * Revision 1.180 2008/05/21 15:26:32 fabiankeil + * - Mark csp as immutable for send_crunch_response(). + * - Fix comment spelling. + * + * Revision 1.179 2008/05/20 20:13:32 fabiankeil + * Factor update_server_headers() out of sed(), ditch the + * first_run hack and make server_patterns_light static. + * + * Revision 1.178 2008/05/10 13:23:38 fabiankeil + * Don't provide get_header() with the whole client state + * structure when it only needs access to csp->iob. + * + * Revision 1.177 2008/05/10 11:51:12 fabiankeil + * Make the "read the rest of the headers" loop a bit more readable. + * + * Revision 1.176 2008/05/10 11:37:57 fabiankeil + * - Instead of logging when the IIS5 hack is enabled, log when it fails. + * - Remove useless comment. + * + * Revision 1.175 2008/05/09 18:53:59 fabiankeil + * Fix comment grammar. + * + * Revision 1.174 2008/05/07 18:05:53 fabiankeil + * Remove the pointless buffer in client_protocol_is_unsupported(). + * + * Revision 1.173 2008/05/06 15:09:00 fabiankeil + * Least-effort fix for bug #1821930 (reported by Lee): + * If the response doesn't look like HTTP, + * tell the client and log the problem. + * + * Revision 1.172 2008/04/16 16:38:21 fabiankeil + * Don't pass the whole csp structure to flush_socket() + * when it only needs a file descriptor and a buffer. + * + * Revision 1.171 2008/03/27 18:27:25 fabiankeil + * Remove kill-popups action. + * * Revision 1.170 2008/03/06 16:33:46 fabiankeil * If limit-connect isn't used, don't limit CONNECT requests to port 443. * @@ -1079,7 +1116,7 @@ static int client_protocol_is_unsupported(const struct client_state *csp, char * 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 void send_crunch_response(const struct client_state *csp, struct http_response *rsp); /* * static int request_contains_null_bytes(const struct client_state *csp, char *buf, int len); */ @@ -1181,6 +1218,14 @@ static const char NO_SERVER_DATA_RESPONSE[] = "Empty server or forwarder response.\r\n" "The connection has been closed but Privoxy didn't receive any data.\r\n"; +/* XXX: should be a template */ +static const char INVALID_SERVER_HEADERS_RESPONSE[] = + "HTTP/1.0 502 Server or forwarder response invalid\r\n" + "Proxy-Agent: Privoxy " VERSION "\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"; + #if 0 /* XXX: should be a template */ static const char NULL_BYTE_RESPONSE[] = @@ -1305,8 +1350,6 @@ static void sig_handler(int the_signal) *********************************************************************/ static int client_protocol_is_unsupported(const struct client_state *csp, char *req) { - char buf[BUFFER_SIZE]; - /* * If it's a FTP or gopher request, we don't support it. * @@ -1322,21 +1365,26 @@ static int client_protocol_is_unsupported(const struct client_state *csp, char * */ if (!strncmpic(req, "GET ftp://", 10) || !strncmpic(req, "GET gopher://", 13)) { + const char *response = NULL; + const char *protocol = NULL; + if (!strncmpic(req, "GET ftp://", 10)) { - strlcpy(buf, FTP_RESPONSE, sizeof(buf)); - log_error(LOG_LEVEL_ERROR, "%s tried to use Privoxy as FTP proxy: %s", - csp->ip_addr_str, req); + response = FTP_RESPONSE; + protocol = "FTP"; } else { - strlcpy(buf, GOPHER_RESPONSE, sizeof(buf)); - log_error(LOG_LEVEL_ERROR, "%s tried to use Privoxy as gopher proxy: %s", - csp->ip_addr_str, req); + response = GOPHER_RESPONSE; + protocol = "GOPHER"; } - log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 400 0", csp->ip_addr_str, req); + log_error(LOG_LEVEL_ERROR, + "%s tried to use Privoxy as %s proxy: %s", + csp->ip_addr_str, protocol, req); + log_error(LOG_LEVEL_CLF, + "%s - - [%T] \"%s\" 400 0", csp->ip_addr_str, req); freez(req); - write_socket(csp->cfd, buf, strlen(buf)); + write_socket(csp->cfd, response, strlen(response)); return TRUE; } @@ -1444,7 +1492,7 @@ static jb_err get_server_headers(struct client_state *csp) int continue_hack_in_da_house = 0; char * header; - while (((header = get_header(csp)) != NULL) || continue_hack_in_da_house) + while (((header = get_header(csp->iob)) != NULL) || continue_hack_in_da_house) { if (header == NULL) { @@ -1461,7 +1509,7 @@ static jb_err get_server_headers(struct client_state *csp) { /* * It's a bodyless continue response, don't - * stop header parsing after reaching it's end. + * stop header parsing after reaching its end. * * As a result Privoxy will concatenate the * next response's head and parse and deliver @@ -1495,7 +1543,6 @@ static jb_err get_server_headers(struct client_state *csp) return JB_ERR_PARSE; } - /* Enlist header */ if (JB_ERR_MEMORY == enlist(csp->headers, header)) { /* @@ -1588,7 +1635,7 @@ static const char *crunch_reason(const struct http_response *rsp) * Returns : Nothing. * *********************************************************************/ -static void send_crunch_response(struct client_state *csp, struct http_response *rsp) +static void send_crunch_response(const struct client_state *csp, struct http_response *rsp) { const struct http_request *http = csp->http; char status_code[4]; @@ -1953,7 +2000,7 @@ static void chat(struct client_state *csp) return; } - req = get_header(csp); + req = get_header(csp->iob); } while ((NULL != req) && ('\0' == *req)); @@ -2041,8 +2088,20 @@ static void chat(struct client_state *csp) init_list(headers); for (;;) { - if ( ( ( p = get_header(csp) ) != NULL) && ( *p == '\0' ) ) + p = get_header(csp->iob); + + if (p == NULL) { + /* There are no additional headers to read. */ + break; + } + + if (*p == '\0') + { + /* + * We didn't receive a complete header + * line yet, get the rest of it. + */ len = read_socket(csp->cfd, buf, sizeof(buf) - 1); if (len <= 0) { @@ -2051,23 +2110,25 @@ static void chat(struct client_state *csp) return; } - /* - * If there is no memory left for buffering the - * request, there is nothing we can do but hang up - */ if (add_to_iob(csp, buf, len)) { + /* + * If there is no memory left for buffering the + * request, there is nothing we can do but hang up + */ destroy_list(headers); return; } - continue; } - - if (p == NULL) break; - - enlist(headers, p); - freez(p); - + else + { + /* + * We were able to read a complete + * header and can finaly enlist it. + */ + enlist(headers, p); + freez(p); + } } if (http->host == NULL) @@ -2122,7 +2183,7 @@ static void chat(struct client_state *csp) list_append_list_unique(csp->headers, headers); destroy_list(headers); - err = sed(client_patterns, add_client_headers, csp); + err = sed(csp, FILTER_CLIENT_HEADERS); if (JB_ERR_OK != err) { assert(err == JB_ERR_PARSE); @@ -2299,7 +2360,7 @@ static void chat(struct client_state *csp) */ if (write_socket(csp->sfd, hdr, strlen(hdr)) - || (flush_socket(csp->sfd, csp) < 0)) + || (flush_socket(csp->sfd, csp->iob) < 0)) { log_error(LOG_LEVEL_CONNECT, "write header to: %s failed: %E", http->hostport); @@ -2483,9 +2544,10 @@ static void chat(struct client_state *csp) csp->content_length = (size_t)(csp->iob->eod - csp->iob->cur); } - if (JB_ERR_OK != sed(server_patterns_light, NULL, csp)) + if (JB_ERR_OK != update_server_headers(csp)) { - log_error(LOG_LEVEL_FATAL, "Failed to parse server headers."); + log_error(LOG_LEVEL_FATAL, + "Failed to update server headers. after filtering."); } hdr = list_to_text(csp->headers); @@ -2495,12 +2557,6 @@ static void chat(struct client_state *csp) log_error(LOG_LEVEL_FATAL, "Out of memory parsing server header"); } - /* - * Shouldn't happen because this was the second sed run - * and tags are only created for the first one. - */ - assert(!crunch_response_triggered(csp, crunchers_all)); - if (write_socket(csp->cfd, hdr, strlen(hdr)) || write_socket(csp->cfd, p != NULL ? p : csp->iob->cur, csp->content_length)) { @@ -2521,9 +2577,6 @@ 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); @@ -2573,7 +2626,7 @@ static void chat(struct client_state *csp) hdrlen = strlen(hdr); if (write_socket(csp->cfd, hdr, hdrlen) - || ((flushed = flush_socket(csp->cfd, csp)) < 0) + || ((flushed = flush_socket(csp->cfd, csp->iob)) < 0) || (write_socket(csp->cfd, buf, (size_t)len))) { log_error(LOG_LEVEL_CONNECT, "Flush header and buffers to client failed: %E"); @@ -2636,6 +2689,8 @@ static void chat(struct client_state *csp) * and there isn't anything * we can do about it. */ + log_error(LOG_LEVEL_INFO, + "MS IIS5 hack didn't produce valid headers."); break; } else @@ -2659,10 +2714,34 @@ static void chat(struct client_state *csp) return; } - /* we have now received the entire header. + assert(csp->headers->first->str); + assert(!http->ssl); + if (strncmpic(csp->headers->first->str, "HTTP", 4)) + { + /* + * It doesn't look like a HTTP response: + * tell the client and log the problem. + */ + if (strlen(csp->headers->first->str) > 30) + { + csp->headers->first->str[30] = '\0'; + } + log_error(LOG_LEVEL_ERROR, + "Invalid server or forwarder response. Starts with: %s", + csp->headers->first->str); + log_error(LOG_LEVEL_CLF, + "%s - - [%T] \"%s\" 502 0", csp->ip_addr_str, http->cmd); + write_socket(csp->cfd, INVALID_SERVER_HEADERS_RESPONSE, + strlen(INVALID_SERVER_HEADERS_RESPONSE)); + free_http_request(http); + return; + } + + /* + * We have now received the entire server header, * filter it and send the result to the client */ - if (JB_ERR_OK != sed(server_patterns, add_server_headers, csp)) + if (JB_ERR_OK != sed(csp, FILTER_SERVER_HEADERS)) { log_error(LOG_LEVEL_FATAL, "Failed to parse server headers."); } @@ -2701,7 +2780,7 @@ static void chat(struct client_state *csp) */ if (write_socket(csp->cfd, hdr, strlen(hdr)) - || ((len = flush_socket(csp->cfd, csp)) < 0)) + || ((len = flush_socket(csp->cfd, csp->iob)) < 0)) { log_error(LOG_LEVEL_CONNECT, "write header to client failed: %E"); @@ -2728,6 +2807,8 @@ static void chat(struct client_state *csp) */ if (ms_iis5_hack) { + log_error(LOG_LEVEL_INFO, + "Closed server connection detected with MS IIS5 hack enabled."); break; } } @@ -2958,7 +3039,7 @@ int main(int argc, const char *argv[]) * Parse the command line arguments * * XXX: simply printing usage information in case of - * invalid arguments isn't particular user friendly. + * invalid arguments isn't particularly user friendly. */ while (++argc_pos < argc) {