-const char jcc_rcs[] = "$Id: jcc.c,v 1.189 2008/10/11 09:53:00 fabiankeil Exp $";
+const char jcc_rcs[] = "$Id: jcc.c,v 1.195 2008/10/13 16:04:37 fabiankeil Exp $";
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/jcc.c,v $
*
* Revisions :
* $Log: jcc.c,v $
+ * Revision 1.195 2008/10/13 16:04:37 fabiankeil
+ * Make sure we don't try to reuse tainted server sockets.
+ *
+ * Revision 1.194 2008/10/12 18:35:18 fabiankeil
+ * The last commit was a bit too ambitious, apparently the content
+ * length adjustment is only necessary if we aren't buffering.
+ *
+ * Revision 1.193 2008/10/12 15:57:35 fabiankeil
+ * Fix content length calculation if we read headers
+ * and the start of the body at once. Now that we have
+ * FEATURE_CONNECTION_KEEP_ALIVE, it actually matters.
+ *
+ * Revision 1.192 2008/10/11 18:19:14 fabiankeil
+ * Even more chat() cosmetics.
+ *
+ * Revision 1.191 2008/10/11 18:00:14 fabiankeil
+ * Reformat some comments in chat().
+ *
+ * Revision 1.190 2008/10/11 14:58:00 fabiankeil
+ * In case of chunk-encoded content, stop reading if
+ * the buffer looks like it ends with the last chunk.
+ *
* Revision 1.189 2008/10/11 09:53:00 fabiankeil
* Let server_response_is_complete() deal properly with
* content that is neither buffered nor read all at once.
http->hostport);
}
-
/* Write the answer to the client */
if (rsp != NULL)
{
if (fwd->forward_host || (http->ssl == 0))
{
- /* write the client's (modified) header to the server
+ /*
+ * Write the client's (modified) header to the server
* (along with anything else that may be in the buffer)
*/
-
if (write_socket(csp->sfd, hdr, strlen(hdr))
|| (flush_socket(csp->sfd, csp->iob) < 0))
{
- log_error(LOG_LEVEL_CONNECT, "write header to: %s failed: %E",
- http->hostport);
+ log_error(LOG_LEVEL_CONNECT,
+ "write header to: %s failed: %E", http->hostport);
rsp = error_response(csp, "connect-failed", errno);
-
- if(rsp)
+ if (rsp)
{
send_crunch_response(csp, rsp);
}
/* we're finished with the client's header */
freez(hdr);
- maxfd = ( csp->cfd > csp->sfd ) ? csp->cfd : csp->sfd;
+ maxfd = (csp->cfd > csp->sfd) ? csp->cfd : csp->sfd;
/* pass data between the client and server
* until one or the other shuts down the connection.
if (n < 0)
{
log_error(LOG_LEVEL_ERROR, "select() failed!: %E");
- return;
+ break;
}
- /* this is the body of the browser's request
- * just read it and write it.
+ /*
+ * This is the body of the browser's request,
+ * just read and write it.
*/
-
if (FD_ISSET(csp->cfd, &rfds))
{
len = read_socket(csp->cfd, buf, sizeof(buf) - 1);
if (write_socket(csp->sfd, buf, (size_t)len))
{
log_error(LOG_LEVEL_ERROR, "write to: %s failed: %E", http->host);
- return;
+ break;
}
continue;
}
/*
- * The server wants to talk. It could be the header or the body.
+ * The server wants to talk. It could be the header or the body.
* If `hdr' is null, then it's the header otherwise it's the body.
* FIXME: Does `hdr' really mean `host'? No.
*/
-
-
if (FD_ISSET(csp->sfd, &rfds))
{
- fflush( 0 );
+ fflush(0);
len = read_socket(csp->sfd, buf, sizeof(buf) - 1);
if (len < 0)
*/
log_error(LOG_LEVEL_ERROR, "Already forwarded the original headers. "
"Unable to tell the client about the problem.");
- return;
+ break;
}
rsp = error_response(csp, "connect-failed", errno);
-
if (rsp)
{
send_crunch_response(csp, rsp);
{
/* XXX: this is a temporary hack */
log_error(LOG_LEVEL_CONNECT,
- "Looks like we reached the end of the last chunk: "
- "%d %d %d %d %d. We better stop reading.",
- buf[len-5], buf[len-4], buf[len-3], buf[len-2], buf[len-1]);
- csp->expected_content_length = byte_count + len;
+ "Looks like we reached the end of the last chunk. "
+ "We better stop reading.");
+ csp->expected_content_length = byte_count + (size_t)len;
csp->flags |= CSP_FLAG_CONTENT_LENGTH_SET;
}
}
reading_done:
#endif /* FEATURE_CONNECTION_KEEP_ALIVE */
- /* Add a trailing zero. This lets filter_popups
- * use string operations.
+ /*
+ * Add a trailing zero to let be able to use string operations.
+ * XXX: do we still need this with filter_popups gone?
*/
buf[len] = '\0';
- /* Normally, this would indicate that we've read
+ /*
+ * Normally, this would indicate that we've read
* as much as the server has sent us and we can
* close the client connection. However, Microsoft
* in its wisdom has released IIS/5 with a bug that
log_error(LOG_LEVEL_ERROR, "write modified content to client failed: %E");
freez(hdr);
freez(p);
- return;
+ break;
}
freez(hdr);
* of the server document, just write it to the client,
* unless we need to buffer the body for later content-filtering
*/
-
if (server_body || http->ssl)
{
if (content_filter)
size_t hdrlen;
int flushed;
- log_error(LOG_LEVEL_INFO, "Flushing header and buffers. Stepping back from filtering.");
+ log_error(LOG_LEVEL_INFO,
+ "Flushing header and buffers. Stepping back from filtering.");
hdr = list_to_text(csp->headers);
if (hdr == NULL)
log_error(LOG_LEVEL_ERROR, "Out of memory while trying to flush.");
rsp = cgi_error_memory();
send_crunch_response(csp, rsp);
-
- return;
+ break;
}
hdrlen = strlen(hdr);
|| ((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");
-
+ log_error(LOG_LEVEL_CONNECT,
+ "Flush header and buffers to client failed: %E");
freez(hdr);
- return;
+ break;
}
/*
if (write_socket(csp->cfd, buf, (size_t)len))
{
log_error(LOG_LEVEL_ERROR, "write to client failed: %E");
- return;
+ break;
}
}
byte_count += (size_t)len;
}
else
{
- /* we're still looking for the end of the
- * server's header ... (does that make header
- * parsing an "out of body experience" ?
- */
-
- /*
- * buffer up the data we just read. If that fails,
- * there's little we can do but send our static
- * out-of-memory page.
+ const char *header_start;
+ /*
+ * We're still looking for the end of the server's header.
+ * Buffer up the data we just read. If that fails, there's
+ * little we can do but send our static out-of-memory page.
*/
if (add_to_iob(csp, buf, len))
{
log_error(LOG_LEVEL_ERROR, "Out of memory while looking for end of server headers.");
rsp = cgi_error_memory();
send_crunch_response(csp, rsp);
-
- return;
+ break;
}
+ header_start = csp->iob->cur;
+
/* Convert iob into something sed() can digest */
if (JB_ERR_PARSE == get_server_headers(csp))
{
if (ms_iis5_hack)
{
- /* Well, we tried our MS IIS/5
- * hack and it didn't work.
- * The header is incomplete
- * and there isn't anything
+ /*
+ * Well, we tried our MS IIS/5 hack and it didn't work.
+ * The header is incomplete and there isn't anything
* we can do about it.
*/
log_error(LOG_LEVEL_INFO,
}
else
{
- /* Since we have to wait for
- * more from the server before
- * we can parse the headers
- * we just continue here.
+ /*
+ * Since we have to wait for more from the server before
+ * we can parse the headers we just continue here.
*/
continue;
}
log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 502 0", csp->ip_addr_str, http->cmd);
write_socket(csp->cfd, NO_SERVER_DATA_RESPONSE, strlen(NO_SERVER_DATA_RESPONSE));
free_http_request(http);
- return;
+ break;
}
assert(csp->headers->first->str);
write_socket(csp->cfd, INVALID_SERVER_HEADERS_RESPONSE,
strlen(INVALID_SERVER_HEADERS_RESPONSE));
free_http_request(http);
- return;
+ break;
}
/*
* and are done here after cleaning up.
*/
freez(hdr);
- return;
+ break;
}
/* Buffer and pcrs filter this if appropriate. */
*/
if (!content_filter)
{
- /* write the server's (modified) header to
+ /*
+ * Write the server's (modified) header to
* the client (along with anything else that
* may be in the buffer)
*/
{
log_error(LOG_LEVEL_CONNECT, "write header to client failed: %E");
- /* the write failed, so don't bother
- * mentioning it to the client...
- * it probably can't hear us anyway.
+ /*
+ * The write failed, so don't bother mentioning it
+ * to the client... it probably can't hear us anyway.
*/
freez(hdr);
- return;
+ break;
}
byte_count += (size_t)len;
}
+ else
+ {
+ /*
+ * XXX: the header lenght should probably
+ * be calculated by get_server_headers().
+ */
+ int header_length = csp->iob->cur - header_start;
+ assert(csp->iob->cur > header_start);
+ byte_count += (size_t)len - header_length;
+ }
/* we're finished with the server's header */
freez(hdr);
server_body = 1;
- /* If this was a MS IIS/5 hack then it means
- * the server has already closed the
- * connection. Nothing more to read. Time
- * to bail.
+ /*
+ * If this was a MS IIS/5 hack then it means the server
+ * has already closed the connection. Nothing more to read.
+ * Time to bail.
*/
if (ms_iis5_hack)
{
}
continue;
}
-
- return; /* huh? we should never get here */
+ /*
+ * If we reach this point, the server socket is tainted
+ * (most likely because we didn't read everything the
+ * server sent us) and reusing it would lead to garbage.
+ */
+ if ((csp->flags & CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE))
+ {
+ log_error(LOG_LEVEL_CONNECT, "Unsetting keep-alive flag.");
+ csp->flags &= ~CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE;
+ }
+ return;
}
if (csp->content_length == 0)
{
/*
- * If Privoxy didn't recalculate the
- * Content-Lenght, byte_count is still
- * correct.
+ * If Privoxy didn't recalculate the Content-Lenght,
+ * byte_count is still correct.
*/
csp->content_length = byte_count;
}