Did a bit of consolidation by moving code into remove_connection_headers()
and added the get_content_length() function. The process_server_headers() function was rewritten to remove the Connection header correctly, and also retrieve the Content-Length value. This value is needed in the relay_connection() function since there are some remote machines which do not properly close down the connection once the body has been retrieved. Thanks to James Flemer for finding a test case for this problem.
This commit is contained in:
parent
ce06f27a35
commit
85a82af5f5
147
src/reqs.c
147
src/reqs.c
@ -1,4 +1,4 @@
|
|||||||
/* $Id: reqs.c,v 1.54 2002-04-09 20:06:24 rjkaes Exp $
|
/* $Id: reqs.c,v 1.55 2002-04-11 20:44:15 rjkaes Exp $
|
||||||
*
|
*
|
||||||
* This is where all the work in tinyproxy is actually done. Incoming
|
* This is where all the work in tinyproxy is actually done. Incoming
|
||||||
* connections have a new thread created for them. The thread then
|
* connections have a new thread created for them. The thread then
|
||||||
@ -520,9 +520,16 @@ get_all_headers(int fd, hashmap_t hashofheaders)
|
|||||||
* header sent via the client (which is stored in data right now.)
|
* header sent via the client (which is stored in data right now.)
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
remove_connection_headers(hashmap_t hashofheaders, char* data, ssize_t len)
|
remove_connection_headers(hashmap_t hashofheaders)
|
||||||
{
|
{
|
||||||
|
char *data;
|
||||||
char* ptr;
|
char* ptr;
|
||||||
|
ssize_t len;
|
||||||
|
|
||||||
|
/* Look for the connection header. If it's not found, return. */
|
||||||
|
len = hashmap_search(hashofheaders, "connection", (void **)&data);
|
||||||
|
if (len <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Go through the data line and replace any special characters with
|
* Go through the data line and replace any special characters with
|
||||||
@ -548,9 +555,31 @@ remove_connection_headers(hashmap_t hashofheaders, char* data, ssize_t len)
|
|||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Now remove the connection header it self. */
|
||||||
|
hashmap_remove(hashofheaders, "connection");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If there is a Content-Length header, then return the value; otherwise, return
|
||||||
|
* a negative number.
|
||||||
|
*/
|
||||||
|
static long
|
||||||
|
get_content_length(hashmap_t hashofheaders)
|
||||||
|
{
|
||||||
|
ssize_t len;
|
||||||
|
char *data;
|
||||||
|
long content_length = -1;
|
||||||
|
|
||||||
|
len = hashmap_search(hashofheaders, "content-length", (void **)&data);
|
||||||
|
if (len > 0) {
|
||||||
|
content_length = atol(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return content_length;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Number of buckets to use internally in the hashmap.
|
* Number of buckets to use internally in the hashmap.
|
||||||
*/
|
*/
|
||||||
@ -609,28 +638,17 @@ process_client_headers(struct conn_s *connptr)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* See if there is a "Connection" header. If so, we need to do a bit
|
|
||||||
* of processing. :)
|
|
||||||
*/
|
|
||||||
len = hashmap_search(hashofheaders, "connection", (void **)&data);
|
|
||||||
if (len > 0) {
|
|
||||||
/*
|
|
||||||
* Go through the tokens in the connection header and
|
|
||||||
* remove the headers from the hash.
|
|
||||||
*/
|
|
||||||
remove_connection_headers(hashofheaders, data, len);
|
|
||||||
hashmap_remove(hashofheaders, "connection");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* See if there is a "Content-Length" header. If so, again we need
|
* See if there is a "Content-Length" header. If so, again we need
|
||||||
* to do a bit of processing.
|
* to do a bit of processing.
|
||||||
*/
|
*/
|
||||||
len = hashmap_search(hashofheaders, "content-length", (void **)&data);
|
content_length = get_content_length(hashofheaders);
|
||||||
if (len > 0) {
|
|
||||||
content_length = atol(data);
|
/*
|
||||||
}
|
* See if there is a "Connection" header. If so, we need to do a bit
|
||||||
|
* of processing. :)
|
||||||
|
*/
|
||||||
|
remove_connection_headers(hashofheaders);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* See if there is a "Via" header. If so, again we need to do a bit
|
* See if there is a "Via" header. If so, again we need to do a bit
|
||||||
@ -712,28 +730,70 @@ process_client_headers(struct conn_s *connptr)
|
|||||||
static int
|
static int
|
||||||
process_server_headers(struct conn_s *connptr)
|
process_server_headers(struct conn_s *connptr)
|
||||||
{
|
{
|
||||||
char *header;
|
char *response_line;
|
||||||
|
|
||||||
|
hashmap_t hashofheaders;
|
||||||
|
vector_t listofheaders;
|
||||||
|
char *data, *header;
|
||||||
ssize_t len;
|
ssize_t len;
|
||||||
|
int i;
|
||||||
|
|
||||||
while (1) {
|
/* FIXME: Remember to handle a "simple_req" type */
|
||||||
if ((len = readline(connptr->server_fd, &header)) <= 0) {
|
|
||||||
DEBUG2("Server (file descriptor %d) closed connection.",
|
|
||||||
connptr->server_fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (safe_write(connptr->client_fd, header, len) < 0) {
|
/* Get the response line from the remote server. */
|
||||||
safefree(header);
|
if ((len = readline(connptr->server_fd, &response_line)) <= 0)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
if (CHECK_CRLF(header, len))
|
hashofheaders = hashmap_create(HEADER_BUCKETS);
|
||||||
break;
|
if (!hashofheaders) {
|
||||||
|
safefree(response_line);
|
||||||
safefree(header);
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
safefree(header);
|
/*
|
||||||
|
* Get all the headers from the remote server in a big hash
|
||||||
|
*/
|
||||||
|
if (get_all_headers(connptr->server_fd, hashofheaders) < 0) {
|
||||||
|
log_message(LOG_WARNING, "Could not retrieve all the headers from the remote server.");
|
||||||
|
hashmap_delete(hashofheaders);
|
||||||
|
safefree(response_line);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If there is a "Content-Length" header, retrieve the information
|
||||||
|
* from it for later use.
|
||||||
|
*/
|
||||||
|
connptr->remote_content_length = get_content_length(hashofheaders);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See if there is a connection header. If so, we need to to a bit of
|
||||||
|
* processing.
|
||||||
|
*/
|
||||||
|
remove_connection_headers(hashofheaders);
|
||||||
|
|
||||||
|
/* Send the saved response line first */
|
||||||
|
safe_write(connptr->client_fd, response_line, strlen(response_line));
|
||||||
|
safefree(response_line);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Okay, output all the remaining headers to the client.
|
||||||
|
*/
|
||||||
|
listofheaders = hashmap_keys(hashofheaders);
|
||||||
|
for (i = 0; i < vector_length(listofheaders); ++i) {
|
||||||
|
len = vector_getentry(listofheaders, i, (void **)&data);
|
||||||
|
hashmap_search(hashofheaders, data, (void **)&header);
|
||||||
|
|
||||||
|
write_message(connptr->client_fd,
|
||||||
|
"%s: %s\r\n",
|
||||||
|
data, header);
|
||||||
|
}
|
||||||
|
vector_delete(listofheaders);
|
||||||
|
hashmap_delete(hashofheaders);
|
||||||
|
|
||||||
|
/* Write the final blank line to signify the end of the headers */
|
||||||
|
safe_write(connptr->client_fd, "\r\n", 2);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -754,6 +814,7 @@ relay_connection(struct conn_s *connptr)
|
|||||||
int ret;
|
int ret;
|
||||||
double tdiff;
|
double tdiff;
|
||||||
int maxfd = max(connptr->client_fd, connptr->server_fd) + 1;
|
int maxfd = max(connptr->client_fd, connptr->server_fd) + 1;
|
||||||
|
ssize_t bytes_received;
|
||||||
|
|
||||||
socket_nonblocking(connptr->client_fd);
|
socket_nonblocking(connptr->client_fd);
|
||||||
socket_nonblocking(connptr->server_fd);
|
socket_nonblocking(connptr->server_fd);
|
||||||
@ -802,9 +863,14 @@ relay_connection(struct conn_s *connptr)
|
|||||||
last_access = time(NULL);
|
last_access = time(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FD_ISSET(connptr->server_fd, &rset)
|
if (FD_ISSET(connptr->server_fd, &rset)) {
|
||||||
&& read_buffer(connptr->server_fd, connptr->sbuffer) < 0) {
|
bytes_received = read_buffer(connptr->server_fd, connptr->sbuffer);
|
||||||
break;
|
if (bytes_received < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
connptr->remote_content_length -= bytes_received;
|
||||||
|
if (connptr->remote_content_length == 0)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (FD_ISSET(connptr->client_fd, &rset)
|
if (FD_ISSET(connptr->client_fd, &rset)
|
||||||
&& read_buffer(connptr->client_fd, connptr->cbuffer) < 0) {
|
&& read_buffer(connptr->client_fd, connptr->cbuffer) < 0) {
|
||||||
@ -1054,6 +1120,9 @@ handle_connection(int fd)
|
|||||||
relay_proxy:
|
relay_proxy:
|
||||||
relay_connection(connptr);
|
relay_connection(connptr);
|
||||||
|
|
||||||
|
log_message(LOG_INFO, "Closed connection between local client (fd:%d) and remote client (fd:%d)",
|
||||||
|
connptr->client_fd, connptr->server_fd);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* All done... close everything and go home... :)
|
* All done... close everything and go home... :)
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user