Temporarily disable the server-side-only keep-alive code.
-const char gateway_rcs[] = "$Id: gateway.c,v 1.47 2008/12/24 17:06:19 fabiankeil Exp $";
+const char gateway_rcs[] = "$Id: gateway.c,v 1.48 2009/02/13 17:20:36 fabiankeil Exp $";
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/gateway.c,v $
*
* Revisions :
* $Log: gateway.c,v $
+ * Revision 1.48 2009/02/13 17:20:36 fabiankeil
+ * Reword keep-alive support warning and only show
+ * it #if !defined(HAVE_POLL) && !defined(_WIN32).
+ *
* Revision 1.47 2008/12/24 17:06:19 fabiankeil
* Keep a thread around to timeout alive connections
* even if no new requests are coming in.
#define MAX_REUSABLE_CONNECTIONS 100
static int keep_alive_timeout = DEFAULT_KEEP_ALIVE_TIMEOUT;
-struct reusable_connection
-{
- jb_socket sfd;
- int in_use;
- char *host;
- int port;
- time_t timestamp;
-
- int forwarder_type;
- char *gateway_host;
- int gateway_port;
- char *forward_host;
- int forward_port;
-};
-
static struct reusable_connection reusable_connection[MAX_REUSABLE_CONNECTIONS];
-
static int mark_connection_unused(jb_socket sfd);
-static void mark_connection_closed(struct reusable_connection *closed_connection);
-static int socket_is_still_usable(jb_socket sfd);
-
/*********************************************************************
*
* Function : mark_connection_closed
*
* Description : Marks a reused connection closed.
- * Must be called with connection_reuse_mutex locked.
*
* Parameters :
* 1 : closed_connection = The connection to mark as closed.
* Returns : void
*
*********************************************************************/
-static void mark_connection_closed(struct reusable_connection *closed_connection)
+void mark_connection_closed(struct reusable_connection *closed_connection)
{
closed_connection->in_use = FALSE;
closed_connection->sfd = JB_INVALID_SOCKET;
* Returns : TRUE for yes, FALSE otherwise.
*
*********************************************************************/
-static int connection_destination_matches(const struct reusable_connection *connection,
- const struct http_request *http,
- const struct forward_spec *fwd)
+int connection_destination_matches(const struct reusable_connection *connection,
+ const struct http_request *http,
+ const struct forward_spec *fwd)
{
if ((connection->forwarder_type != fwd->type)
|| (connection->gateway_port != fwd->gateway_port)
}
-/*********************************************************************
- *
- * Function : socket_is_still_usable
- *
- * Description : Decides whether or not an open socket is still usable.
- *
- * Parameters :
- * 1 : sfd = The socket to check.
- *
- * Returns : TRUE for yes, otherwise FALSE.
- *
- *********************************************************************/
-static int socket_is_still_usable(jb_socket sfd)
-{
-#ifdef HAVE_POLL
- int poll_result;
- struct pollfd poll_fd[1];
-
- memset(poll_fd, 0, sizeof(poll_fd));
- poll_fd[0].fd = sfd;
- poll_fd[0].events = POLLIN;
-
- poll_result = poll(poll_fd, 1, 0);
-
- if (-1 != poll_result)
- {
- return !(poll_fd[0].revents & POLLIN);
- }
- else
- {
- log_error(LOG_LEVEL_CONNECT, "Polling socket %d failed.", sfd);
- return FALSE;
- }
-#else
- fd_set readable_fds;
- struct timeval timeout;
- int ret;
- int socket_is_alive = 0;
-
- memset(&timeout, '\0', sizeof(timeout));
- FD_ZERO(&readable_fds);
- FD_SET(sfd, &readable_fds);
-
- ret = select((int)sfd+1, &readable_fds, NULL, NULL, &timeout);
- if (ret < 0)
- {
- log_error(LOG_LEVEL_ERROR, "select() failed!: %E");
- }
-
- /*
- * XXX: I'm not sure why !FD_ISSET() works,
- * but apparently it does.
- */
- socket_is_alive = !FD_ISSET(sfd, &readable_fds);
-
- return socket_is_alive;
-#endif /* def HAVE_POLL */
-}
-
-
/*********************************************************************
*
* Function : get_reusable_connection
#ifndef GATEWAY_H_INCLUDED
#define GATEWAY_H_INCLUDED
-#define GATEWAY_H_VERSION "$Id: gateway.h,v 1.11 2008/11/13 09:08:42 fabiankeil Exp $"
+#define GATEWAY_H_VERSION "$Id: gateway.h,v 1.12 2008/12/24 17:06:19 fabiankeil Exp $"
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/gateway.h,v $
*
* Revisions :
* $Log: gateway.h,v $
+ * Revision 1.12 2008/12/24 17:06:19 fabiankeil
+ * Keep a thread around to timeout alive connections
+ * even if no new requests are coming in.
+ *
* Revision 1.11 2008/11/13 09:08:42 fabiankeil
* Add new config option: keep-alive-timeout.
*
const struct http_request *http,
const struct forward_spec *fwd);
extern int close_unusable_connections(void);
+extern void mark_connection_closed(struct reusable_connection *closed_connection);
+extern int connection_destination_matches(const struct reusable_connection *connection,
+ const struct http_request *http,
+ const struct forward_spec *fwd);
#endif /* FEATURE_CONNECTION_KEEP_ALIVE */
-const char jbsockets_rcs[] = "$Id: jbsockets.c,v 1.53 2009/04/17 11:39:52 fabiankeil Exp $";
+const char jbsockets_rcs[] = "$Id: jbsockets.c,v 1.54 2009/04/17 11:45:19 fabiankeil Exp $";
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/jbsockets.c,v $
* OS-independent. Contains #ifdefs to make this work
* on many platforms.
*
- * Copyright : Written by and Copyright (C) 2001-2007 the SourceForge
+ * Copyright : Written by and Copyright (C) 2001-2009 the
* Privoxy team. http://www.privoxy.org/
*
* Based on the Internet Junkbuster originally written
*
* Revisions :
* $Log: jbsockets.c,v $
+ * Revision 1.54 2009/04/17 11:45:19 fabiankeil
+ * Replace HAVE_GETADDRINFO and HAVE_GETNAMEINFO macros
+ * with HAVE_RFC2553 macro. Original patch by Petr Pisar.
+ *
* Revision 1.53 2009/04/17 11:39:52 fabiankeil
* If the hostname is 'localhost' or not specified, request an AF_INET address.
*
#endif
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+#ifdef HAVE_POLL
+#ifdef __GLIBC__
+#include <sys/poll.h>
+#else
+#include <poll.h>
+#endif /* def __GLIBC__ */
+#endif /* HAVE_POLL */
+#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
+
#include "project.h"
#ifdef FEATURE_PTHREAD
}
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+/*********************************************************************
+ *
+ * Function : socket_is_still_usable
+ *
+ * Description : Decides whether or not an open socket is still usable.
+ *
+ * Parameters :
+ * 1 : sfd = The socket to check.
+ *
+ * Returns : TRUE for yes, otherwise FALSE.
+ *
+ *********************************************************************/
+int socket_is_still_usable(jb_socket sfd)
+{
+#ifdef HAVE_POLL
+ int poll_result;
+ struct pollfd poll_fd[1];
+
+ memset(poll_fd, 0, sizeof(poll_fd));
+ poll_fd[0].fd = sfd;
+ poll_fd[0].events = POLLIN;
+
+ poll_result = poll(poll_fd, 1, 0);
+
+ if (-1 != poll_result)
+ {
+ return !(poll_fd[0].revents & POLLIN);
+ }
+ else
+ {
+ log_error(LOG_LEVEL_CONNECT, "Polling socket %d failed.", sfd);
+ return FALSE;
+ }
+#else
+ fd_set readable_fds;
+ struct timeval timeout;
+ int ret;
+ int socket_is_alive = 0;
+
+ memset(&timeout, '\0', sizeof(timeout));
+ FD_ZERO(&readable_fds);
+ FD_SET(sfd, &readable_fds);
+
+ ret = select((int)sfd+1, &readable_fds, NULL, NULL, &timeout);
+ if (ret < 0)
+ {
+ log_error(LOG_LEVEL_ERROR, "select() failed!: %E");
+ }
+
+ /*
+ * XXX: I'm not sure why !FD_ISSET() works,
+ * but apparently it does.
+ */
+ socket_is_alive = !FD_ISSET(sfd, &readable_fds);
+
+ return socket_is_alive;
+#endif /* def HAVE_POLL */
+}
+#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
+
+
/*
Local Variables:
tab-width: 3
#ifndef JBSOCKETS_H_INCLUDED
#define JBSOCKETS_H_INCLUDED
-#define JBSOCKETS_H_VERSION "$Id: jbsockets.h,v 1.13 2008/03/21 11:13:59 fabiankeil Exp $"
+#define JBSOCKETS_H_VERSION "$Id: jbsockets.h,v 1.14 2008/12/20 14:53:55 fabiankeil Exp $"
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/jbsockets.h,v $
* OS-independent. Contains #ifdefs to make this work
* on many platforms.
*
- * Copyright : Written by and Copyright (C) 2001 the SourceForge
+ * Copyright : Written by and Copyright (C) 2001-2009 the
* Privoxy team. http://www.privoxy.org/
*
* Based on the Internet Junkbuster originally written
*
* Revisions :
* $Log: jbsockets.h,v $
+ * Revision 1.14 2008/12/20 14:53:55 fabiankeil
+ * Add config option socket-timeout to control the time
+ * Privoxy waits for data to arrive on a socket. Useful
+ * in case of stale ssh tunnels or when fuzz-testing.
+ *
* Revision 1.13 2008/03/21 11:13:59 fabiankeil
* Only gather host information if it's actually needed.
* Also move the code out of accept_connection() so it's less likely
extern unsigned long resolve_hostname_to_ip(const char *host);
+extern int socket_is_still_usable(jb_socket sfd);
+
/* Revision control strings from this header and associated .c file */
extern const char jbsockets_rcs[];
extern const char jbsockets_h_rcs[];
-const char jcc_rcs[] = "$Id: jcc.c,v 1.244 2009/04/17 11:34:34 fabiankeil Exp $";
+const char jcc_rcs[] = "$Id: jcc.c,v 1.245 2009/04/24 15:29:43 fabiankeil Exp $";
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/jcc.c,v $
*
* Revisions :
* $Log: jcc.c,v $
+ * Revision 1.245 2009/04/24 15:29:43 fabiankeil
+ * Allow to limit the number of of client connections.
+ *
* Revision 1.244 2009/04/17 11:34:34 fabiankeil
* Style cosmetics for the IPv6 code.
*
log_error(LOG_LEVEL_CONNECT, "No connections to wait for left.");
}
+
+
+/*********************************************************************
+ *
+ * Function : save_connection_destination
+ *
+ * Description : Remembers a connection for reuse later on.
+ *
+ * Parameters :
+ * 1 : sfd = Open socket to remember.
+ * 2 : http = The destination for the connection.
+ * 3 : fwd = The forwarder settings used.
+ * 3 : server_connection = storage.
+ *
+ * Returns : void
+ *
+ *********************************************************************/
+void save_connection_destination(jb_socket sfd,
+ const struct http_request *http,
+ const struct forward_spec *fwd,
+ struct reusable_connection *server_connection)
+{
+ assert(sfd != JB_INVALID_SOCKET);
+ assert(NULL != http->host);
+ server_connection->host = strdup(http->host);
+ if (NULL == server_connection->host)
+ {
+ log_error(LOG_LEVEL_FATAL, "Out of memory saving socket.");
+ }
+ server_connection->port = http->port;
+
+ assert(NULL != fwd);
+ assert(server_connection->gateway_host == NULL);
+ assert(server_connection->gateway_port == 0);
+ assert(server_connection->forwarder_type == 0);
+ assert(server_connection->forward_host == NULL);
+ assert(server_connection->forward_port == 0);
+
+ server_connection->forwarder_type = fwd->type;
+ if (NULL != fwd->gateway_host)
+ {
+ server_connection->gateway_host = strdup(fwd->gateway_host);
+ if (NULL == server_connection->gateway_host)
+ {
+ log_error(LOG_LEVEL_FATAL, "Out of memory saving gateway_host.");
+ }
+ }
+ else
+ {
+ server_connection->gateway_host = NULL;
+ }
+ server_connection->gateway_port = fwd->gateway_port;
+
+ if (NULL != fwd->forward_host)
+ {
+ server_connection->forward_host = strdup(fwd->forward_host);
+ if (NULL == server_connection->forward_host)
+ {
+ log_error(LOG_LEVEL_FATAL, "Out of memory saving forward_host.");
+ }
+ }
+ else
+ {
+ server_connection->forward_host = NULL;
+ }
+ server_connection->forward_port = fwd->forward_port;
+}
#endif /* FEATURE_CONNECTION_KEEP_ALIVE */
/* here we connect to the server, gateway, or the forwarder */
- while ((csp->sfd = forwarded_connect(fwd, http, csp))
- && (errno == EINVAL)
- && (forwarded_connect_retries++ < max_forwarded_connect_retries))
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+ if ((csp->sfd != JB_INVALID_SOCKET)
+ && socket_is_still_usable(csp->sfd)
+ && connection_destination_matches(&csp->server_connection, http, fwd))
{
- log_error(LOG_LEVEL_ERROR,
- "failed request #%u to connect to %s. Trying again.",
- forwarded_connect_retries, http->hostport);
+ log_error(LOG_LEVEL_CONNECT,
+ "Reusing server socket %u. Opened for %s.",
+ csp->sfd, csp->server_connection.host);
}
-
- if (csp->sfd == JB_INVALID_SOCKET)
+ else
{
- if (fwd->type != SOCKS_NONE)
- {
- /* Socks error. */
- rsp = error_response(csp, "forwarding-failed", errno);
- }
- else if (errno == EINVAL)
+ if (csp->sfd != JB_INVALID_SOCKET)
{
- rsp = error_response(csp, "no-such-domain", errno);
+ log_error(LOG_LEVEL_CONNECT,
+ "Closing server socket %u. Opened for %s.",
+ csp->sfd, csp->server_connection.host);
+ close_socket(csp->sfd);
+ mark_connection_closed(&csp->server_connection);
}
- else
+#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
+
+ while ((csp->sfd = forwarded_connect(fwd, http, csp))
+ && (errno == EINVAL)
+ && (forwarded_connect_retries++ < max_forwarded_connect_retries))
{
- rsp = error_response(csp, "connect-failed", errno);
- log_error(LOG_LEVEL_CONNECT, "connect to: %s failed: %E",
- http->hostport);
+ log_error(LOG_LEVEL_ERROR,
+ "failed request #%u to connect to %s. Trying again.",
+ forwarded_connect_retries, http->hostport);
}
- /* Write the answer to the client */
- if (rsp != NULL)
+ if (csp->sfd == JB_INVALID_SOCKET)
{
- send_crunch_response(csp, rsp);
- }
+ if (fwd->type != SOCKS_NONE)
+ {
+ /* Socks error. */
+ rsp = error_response(csp, "forwarding-failed", errno);
+ }
+ else if (errno == EINVAL)
+ {
+ rsp = error_response(csp, "no-such-domain", errno);
+ }
+ else
+ {
+ rsp = error_response(csp, "connect-failed", errno);
+ log_error(LOG_LEVEL_CONNECT, "connect to: %s failed: %E",
+ http->hostport);
+ }
- return;
+ /* Write the answer to the client */
+ if (rsp != NULL)
+ {
+ send_crunch_response(csp, rsp);
+ }
+
+ return;
+ }
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+ save_connection_destination(csp->sfd, http, fwd, &csp->server_connection);
}
+#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
hdr = list_to_text(csp->headers);
if (hdr == NULL)
/*
* This is the body of the browser's request,
* just read and write it.
+ *
+ * XXX: Make sure the client doesn't use pipelining
+ * behind Privoxy's back.
*/
if (FD_ISSET(csp->cfd, &rfds))
{
static void serve(struct client_state *csp)
#endif /* def AMIGA */
{
- chat(csp);
-
- if (csp->sfd != JB_INVALID_SOCKET)
- {
#ifdef FEATURE_CONNECTION_KEEP_ALIVE
- static int monitor_thread_running = 0;
+ int continue_chatting = 0;
+ do
+ {
+ chat(csp);
+
+ continue_chatting = (csp->config->feature_flags
+ & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)
+ && (csp->flags & CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE)
+ && (csp->cfd != JB_INVALID_SOCKET)
+ && (csp->sfd != JB_INVALID_SOCKET)
+ && socket_is_still_usable(csp->sfd);
- if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)
- && (csp->flags & CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE))
+ /*
+ * Get the csp in a mostly vergin state again.
+ * XXX: Should be done elsewhere.
+ */
+ csp->content_type = 0;
+ csp->content_length = 0;
+ csp->expected_content_length = 0;
+ list_remove_all(csp->headers);
+ freez(csp->iob->buf);
+ memset(csp->iob, 0, sizeof(csp->iob));
+ freez(csp->error_message);
+ free_http_request(csp->http);
+ destroy_list(csp->headers);
+ destroy_list(csp->tags);
+ free_current_action(csp->action);
+ if (NULL != csp->fwd)
{
- remember_connection(csp->sfd, csp->http, forward_url(csp, csp->http));
- close_socket(csp->cfd);
- csp->cfd = JB_INVALID_SOCKET;
- privoxy_mutex_lock(&connection_reuse_mutex);
- if (!monitor_thread_running)
+ unload_forward_spec(csp->fwd);
+ csp->fwd = NULL;
+ }
+
+ /* XXX: Store per-connection flags someplace else. */
+ csp->flags = CSP_FLAG_ACTIVE | (csp->flags & CSP_FLAG_TOGGLED_ON);
+
+ if (continue_chatting)
+ {
+ log_error(LOG_LEVEL_CONNECT,
+ "Waiting for the next client request. "
+ "Keeping the server socket %d to %s open.",
+ csp->sfd, csp->server_connection.host);
+
+ if ((csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE)
+ && data_is_available(csp->cfd, csp->config->keep_alive_timeout)
+ && socket_is_still_usable(csp->cfd))
{
- monitor_thread_running = 1;
- privoxy_mutex_unlock(&connection_reuse_mutex);
- wait_for_alive_connections();
- privoxy_mutex_lock(&connection_reuse_mutex);
- monitor_thread_running = 0;
+ log_error(LOG_LEVEL_CONNECT, "Client request arrived in "
+ "time or the client closed the connection.");
+ }
+ else
+ {
+ log_error(LOG_LEVEL_CONNECT,
+ "No additional client request received in time. "
+ "Closing server socket %d, initially opened for %s.",
+ csp->sfd, csp->server_connection.host);
+ break;
}
- privoxy_mutex_unlock(&connection_reuse_mutex);
}
- else
+ else if (csp->sfd != JB_INVALID_SOCKET)
{
- forget_connection(csp->sfd);
- close_socket(csp->sfd);
+ log_error(LOG_LEVEL_CONNECT,
+ "The connection on server socket %d to %s isn't reusable. "
+ "Closing.", csp->sfd, csp->server_connection.host);
}
+ } while (continue_chatting);
#else
- close_socket(csp->sfd);
+ chat(csp);
#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
+
+ if (csp->sfd != JB_INVALID_SOCKET)
+ {
+ close_socket(csp->sfd);
}
if (csp->cfd != JB_INVALID_SOCKET)
-const char loadcfg_rcs[] = "$Id: loadcfg.c,v 1.97 2009/04/17 11:45:19 fabiankeil Exp $";
+const char loadcfg_rcs[] = "$Id: loadcfg.c,v 1.98 2009/04/24 15:29:43 fabiankeil Exp $";
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/loadcfg.c,v $
*
* Revisions :
* $Log: loadcfg.c,v $
+ * Revision 1.98 2009/04/24 15:29:43 fabiankeil
+ * Allow to limit the number of of client connections.
+ *
* Revision 1.97 2009/04/17 11:45:19 fabiankeil
* Replace HAVE_GETADDRINFO and HAVE_GETNAMEINFO macros
* with HAVE_RFC2553 macro. Original patch by Petr Pisar.
unsigned long linenum = 0;
int i;
char *logfile = NULL;
-#ifdef FEATURE_CONNECTION_KEEP_ALIVE
- int keep_alive_timeout = DEFAULT_KEEP_ALIVE_TIMEOUT;
-#endif
if (!check_file_changed(current_configfile, configfile, &fs))
{
config->forwarded_connect_retries = 0;
config->max_client_connections = 0;
config->socket_timeout = 300; /* XXX: Should be a macro. */
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+ config->keep_alive_timeout = DEFAULT_KEEP_ALIVE_TIMEOUT;
+ config->feature_flags &= ~RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE;
+#endif
config->feature_flags &= ~RUNTIME_FEATURE_CGI_TOGGLE;
config->feature_flags &= ~RUNTIME_FEATURE_SPLIT_LARGE_FORMS;
config->feature_flags &= ~RUNTIME_FEATURE_ACCEPT_INTERCEPTED_REQUESTS;
if (0 <= timeout)
{
config->feature_flags |= RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE;
- keep_alive_timeout = timeout;
+ config->keep_alive_timeout = timeout;
}
else
{
{
if (config->multi_threaded)
{
- set_keep_alive_timeout(keep_alive_timeout);
+ set_keep_alive_timeout(config->keep_alive_timeout);
}
else
{
* if we didn't bother with enforcing the connection timeout,
* that might make Tor users sad, even though they shouldn't
* enable the single-threaded option anyway.
+ *
+ * XXX: We could still use Proxy-Connection: keep-alive.
*/
config->feature_flags &= ~RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE;
log_error(LOG_LEVEL_ERROR,
-const char parsers_rcs[] = "$Id: parsers.c,v 1.153 2009/03/07 13:09:17 fabiankeil Exp $";
+const char parsers_rcs[] = "$Id: parsers.c,v 1.154 2009/03/13 14:10:07 fabiankeil Exp $";
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/parsers.c,v $
*
* Revisions :
* $Log: parsers.c,v $
+ * Revision 1.154 2009/03/13 14:10:07 fabiankeil
+ * Fix some more harmless warnings on amd64.
+ *
* Revision 1.153 2009/03/07 13:09:17 fabiankeil
* Change csp->expected_content and_csp->expected_content_length from
* size_t to unsigned long long to reduce the likelihood of integer
static jb_err client_xtra_adder (struct client_state *csp);
static jb_err client_x_forwarded_for_adder(struct client_state *csp);
static jb_err client_connection_header_adder(struct client_state *csp);
-static jb_err server_connection_close_adder(struct client_state *csp);
+static jb_err server_connection_adder(struct client_state *csp);
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+static jb_err server_proxy_connection_adder(struct client_state *csp);
+#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
static jb_err create_forged_referrer(char **header, const char *hostport);
static jb_err create_fake_referrer(char **header, const char *fake_referrer);
{ "TE:", 3, client_te },
{ "Host:", 5, client_host },
{ "if-modified-since:", 18, client_if_modified_since },
+#ifndef FEATURE_CONNECTION_KEEP_ALIVE
{ "Keep-Alive:", 11, crumble },
+#endif
{ "connection:", 11, client_connection },
{ "proxy-connection:", 17, crumble },
{ "max-forwards:", 13, client_max_forwards },
{ "Content-Encoding:", 17, server_content_encoding },
#ifdef FEATURE_CONNECTION_KEEP_ALIVE
{ "Content-Length:", 15, server_save_content_length },
+#else
+ { "Keep-Alive:", 11, crumble },
#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
{ "Transfer-Encoding:", 18, server_transfer_coding },
- { "Keep-Alive:", 11, crumble },
{ "content-disposition:", 20, server_content_disposition },
{ "Last-Modified:", 14, server_last_modified },
{ "*", 0, crunch_server_header },
};
static const add_header_func_ptr add_server_headers[] = {
- server_connection_close_adder,
+ server_connection_adder,
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+ server_proxy_connection_adder,
+#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
NULL
};
*
* Function : server_connection
*
- * Description : Makes sure that the value of the Connection: header
- * is "close" and signals server_connection_close_adder
- * to do nothing.
+ * Description : Makes sure a proper "Connection:" header is
+ * set and signals connection_header_adder to
+ * do nothing.
*
* Parameters :
* 1 : csp = Current client state (buffers, headers, etc...)
*********************************************************************/
static jb_err server_connection(struct client_state *csp, char **header)
{
- char *old_header = *header;
-
/* Do we have a 'Connection: close' header? */
if (strcmpic(*header, "Connection: close"))
{
/* Remember to keep the connection alive. */
csp->flags |= CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE;
}
-#endif /* FEATURE_CONNECTION_KEEP_ALIVE */
+ log_error(LOG_LEVEL_HEADER,
+ "Keeping the server header '%s' around.", *header);
+#else
+ char *old_header = *header;
*header = strdup("Connection: close");
if (header == NULL)
}
log_error(LOG_LEVEL_HEADER, "Replaced: \'%s\' with \'%s\'", old_header, *header);
freez(old_header);
+#endif /* FEATURE_CONNECTION_KEEP_ALIVE */
}
- /* Signal server_connection_close_adder() to return early. */
- csp->flags |= CSP_FLAG_SERVER_CONNECTION_CLOSE_SET;
+ /* Signal server_connection_adder() to return early. */
+ csp->flags |= CSP_FLAG_SERVER_CONNECTION_HEADER_SET;
return JB_ERR_OK;
}
*********************************************************************/
static jb_err client_connection(struct client_state *csp, char **header)
{
- char *old_header = *header;
const char *wanted_header = get_appropiate_connection_header(csp);
if (strcmpic(*header, wanted_header))
{
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+ log_error(LOG_LEVEL_HEADER,
+ "Keeping the client header '%s' around. "
+ "The connection will not be kept alive.",
+ *header);
+#else
+ char *old_header = *header;
+
*header = strdup(wanted_header);
if (header == NULL)
{
log_error(LOG_LEVEL_HEADER,
"Replaced: \'%s\' with \'%s\'", old_header, *header);
freez(old_header);
+#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
}
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+ else
+ {
+ log_error(LOG_LEVEL_HEADER,
+ "Keeping the client header '%s' around. "
+ "The server connection will be kept alive if possible.",
+ *header);
+ csp->flags |= CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE;
+ }
+#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
- /* Signal client_connection_close_adder() to return early. */
+ /* Signal client_connection_adder() to return early. */
csp->flags |= CSP_FLAG_CLIENT_CONNECTION_HEADER_SET;
return JB_ERR_OK;
/*********************************************************************
*
- * Function : server_connection_close_adder
+ * Function : server_connection_adder
*
- * Description : "Temporary" fix for the needed but missing HTTP/1.1
- * support. Adds a "Connection: close" header to csp->headers
+ * Description : Adds an appropiate "Connection:" header to csp->headers
* unless the header was already present. Called from `sed'.
*
- * FIXME: This whole function shouldn't be neccessary!
- *
* Parameters :
* 1 : csp = Current client state (buffers, headers, etc...)
*
* JB_ERR_MEMORY on out-of-memory error.
*
*********************************************************************/
-static jb_err server_connection_close_adder(struct client_state *csp)
+static jb_err server_connection_adder(struct client_state *csp)
{
const unsigned int flags = csp->flags;
const char *response_status_line = csp->headers->first->str;
+ const char *wanted_header = get_appropiate_connection_header(csp);
if ((flags & CSP_FLAG_CLIENT_HEADER_PARSING_DONE)
- && (flags & CSP_FLAG_SERVER_CONNECTION_CLOSE_SET))
+ && (flags & CSP_FLAG_SERVER_CONNECTION_HEADER_SET))
{
return JB_ERR_OK;
}
csp->flags |= CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE;
}
- log_error(LOG_LEVEL_HEADER, "Adding: Connection: close");
+ log_error(LOG_LEVEL_HEADER, "Adding: %s", wanted_header);
+
+ return enlist(csp->headers, wanted_header);
+}
+
- return enlist(csp->headers, "Connection: close");
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+/*********************************************************************
+ *
+ * Function : server_proxy_connection_adder
+ *
+ * Description : Adds a "Proxy-Connection: keep-alive" header to
+ * csp->headers. XXX: We should reuse existant ones.
+ *
+ * Parameters :
+ * 1 : csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns : JB_ERR_OK on success, or
+ * JB_ERR_MEMORY on out-of-memory error.
+ *
+ *********************************************************************/
+static jb_err server_proxy_connection_adder(struct client_state *csp)
+{
+ static const char proxy_connection_header[] = "Proxy-Connection: keep-alive";
+ log_error(LOG_LEVEL_HEADER, "Adding: %s", proxy_connection_header);
+ return enlist(csp->headers, proxy_connection_header);
}
+#endif /* FEATURE_CONNECTION_KEEP_ALIVE */
/*********************************************************************
#ifndef PROJECT_H_INCLUDED
#define PROJECT_H_INCLUDED
/** Version string. */
-#define PROJECT_H_VERSION "$Id: project.h,v 1.132 2009/04/17 11:45:19 fabiankeil Exp $"
+#define PROJECT_H_VERSION "$Id: project.h,v 1.133 2009/04/24 15:29:43 fabiankeil Exp $"
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/project.h,v $
*
* Revisions :
* $Log: project.h,v $
+ * Revision 1.133 2009/04/24 15:29:43 fabiankeil
+ * Allow to limit the number of of client connections.
+ *
* Revision 1.132 2009/04/17 11:45:19 fabiankeil
* Replace HAVE_GETADDRINFO and HAVE_GETNAMEINFO macros
* with HAVE_RFC2553 macro. Original patch by Petr Pisar.
};
+/*
+ * Structure to make sure we only reuse the server socket
+ * if the host and forwarding settings are the same.
+ */
+struct reusable_connection
+{
+ jb_socket sfd;
+ int in_use;
+ time_t timestamp;
+
+ char *host;
+ int port;
+ int forwarder_type;
+ char *gateway_host;
+ int gateway_port;
+ char *forward_host;
+ int forward_port;
+};
+
+
/*
* Flags for use in csp->flags
*/
/**
* Flag for csp->flags: Set if an acceptable Connection header
- * is already set.
+ * has already been set by the client.
*/
#define CSP_FLAG_CLIENT_CONNECTION_HEADER_SET 0x00000040U
/**
- * Flag for csp->flags: Set if adding the 'Connection: close' header
- * for the server isn't necessary.
+ * Flag for csp->flags: Set if an acceptable Connection header
+ * has already been set by the server.
*/
-#define CSP_FLAG_SERVER_CONNECTION_CLOSE_SET 0x00000080U
+#define CSP_FLAG_SERVER_CONNECTION_HEADER_SET 0x00000080U
/**
* Flag for csp->flags: Signals header parsers whether they
* content length.
*/
#define CSP_FLAG_CONTENT_LENGTH_SET 0x00002000U
+
+/**
+ * Flag for csp->flags: Set if the client wants to keep
+ * the connection alive.
+ */
+#define CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE 0x00004000U
#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
/*
/** socket to talk to server (web server or proxy) */
jb_socket sfd;
+ /** current connection to the server (may go through a proxy) */
+ struct reusable_connection server_connection;
+
/** Multi-purpose flag container, see CSP_FLAG_* above */
unsigned int flags;
/* Timeout when waiting on sockets for data to become available. */
int socket_timeout;
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+ /* Number of seconds after which an open connection will no longer be reused. */
+ int keep_alive_timeout;
+#endif
+
/** All options from the config file, HTML-formatted. */
char *proxy_args;