-const char parsers_rcs[] = "$Id: parsers.c,v 1.181 2009/06/17 14:51:23 fabiankeil Exp $";
+const char parsers_rcs[] = "$Id: parsers.c,v 1.189 2009/07/05 12:04:46 fabiankeil Exp $";
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/parsers.c,v $
#ifdef FEATURE_CONNECTION_KEEP_ALIVE
static jb_err server_save_content_length(struct client_state *csp, char **header);
static jb_err server_keep_alive(struct client_state *csp, char **header);
+static jb_err client_keep_alive(struct client_state *csp, char **header);
#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
static jb_err client_host_adder (struct client_state *csp);
{ "TE:", 3, client_te },
{ "Host:", 5, client_host },
{ "if-modified-since:", 18, client_if_modified_since },
-#ifndef FEATURE_CONNECTION_KEEP_ALIVE
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+ { "Keep-Alive:", 11, client_keep_alive },
+#else
{ "Keep-Alive:", 11, crumble },
#endif
{ "connection:", 11, client_connection },
*********************************************************************/
static jb_err server_connection(struct client_state *csp, char **header)
{
- if (!strcmpic(*header, "Connection: keep-alive"))
+ if (!strcmpic(*header, "Connection: keep-alive")
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+ && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED)
+#endif
+ )
{
#ifdef FEATURE_CONNECTION_KEEP_ALIVE
if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE))
*
* Function : server_keep_alive
*
- * Description : Stores the servers keep alive timeout.
+ * Description : Stores the server's keep alive timeout.
*
* Parameters :
* 1 : csp = Current client state (buffers, headers, etc...)
return JB_ERR_OK;
}
+
+
+/*********************************************************************
+ *
+ * Function : client_keep_alive
+ *
+ * Description : Stores the client's keep alive timeout.
+ *
+ * Parameters :
+ * 1 : csp = Current client state (buffers, headers, etc...)
+ * 2 : header = On input, pointer to header to modify.
+ * On output, pointer to the modified header, or NULL
+ * to remove the header. This function frees the
+ * original string if necessary.
+ *
+ * Returns : JB_ERR_OK.
+ *
+ *********************************************************************/
+static jb_err client_keep_alive(struct client_state *csp, char **header)
+{
+ unsigned int keep_alive_timeout;
+ const char *timeout_position = strstr(*header, ": ");
+
+ if ((NULL == timeout_position)
+ || (1 != sscanf(timeout_position, ": %u", &keep_alive_timeout)))
+ {
+ log_error(LOG_LEVEL_ERROR, "Couldn't parse: %s", *header);
+ }
+ else
+ {
+ if (keep_alive_timeout < csp->config->keep_alive_timeout)
+ {
+ log_error(LOG_LEVEL_HEADER,
+ "Reducing keep-alive timeout from %u to %u.",
+ csp->config->keep_alive_timeout, keep_alive_timeout);
+ csp->server_connection.keep_alive_timeout = keep_alive_timeout;
+ }
+ else
+ {
+ /* XXX: Is this log worthy? */
+ log_error(LOG_LEVEL_HEADER,
+ "Client keep-alive timeout is %u. Sticking with %u.",
+ keep_alive_timeout, csp->server_connection.keep_alive_timeout);
+ }
+ }
+
+ return JB_ERR_OK;
+}
#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
assert(*(*header+14) == ':');
+#ifdef _WIN32
+ if (1 != sscanf(*header+14, ": %I64u", &content_length))
+#else
if (1 != sscanf(*header+14, ": %llu", &content_length))
+#endif
{
log_error(LOG_LEVEL_ERROR, "Crunching invalid header: %s", *header);
freez(*header);
#else
timeptr = gmtime(&last_modified);
#endif
- if (!strftime(newheader, sizeof(newheader),
- "%a, %d %b %Y %H:%M:%S GMT", timeptr))
+ if ((NULL == timeptr) || !strftime(newheader,
+ sizeof(newheader), "%a, %d %b %Y %H:%M:%S GMT", timeptr))
{
log_error(LOG_LEVEL_ERROR,
- "Randomizing '%s' failed. Keeping the header unmodified.",
+ "Randomizing '%s' failed. Crunching the header without replacement.",
*header);
+ freez(*header);
return JB_ERR_OK;
}
#else
timeptr = gmtime(&tm);
#endif
- if (!strftime(newheader, sizeof(newheader),
- "%a, %d %b %Y %H:%M:%S GMT", timeptr))
+ if ((NULL == timeptr) || !strftime(newheader,
+ sizeof(newheader), "%a, %d %b %Y %H:%M:%S GMT", timeptr))
{
log_error(LOG_LEVEL_ERROR,
- "Randomizing '%s' failed. Keeping the header unmodified.",
+ "Randomizing '%s' failed. Crunching the header without replacement.",
*header);
+ freez(*header);
return JB_ERR_OK;
}
if ((csp->config->feature_flags &
RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)
&& (NULL != response_status_line)
- && !strncmpic(response_status_line, "HTTP/1.1", 8))
+ && !strncmpic(response_status_line, "HTTP/1.1", 8)
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+ && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED)
+#endif
+ && (csp->http->status == 200)
+ )
{
+ /*
+ * XXX: not doing this for status codes other than 200 works
+ * around problems with broken servers that will keep the
+ * connection open, but terminate the connection when the
+ * next request arrives. Once we are able to figure out which
+ * requests are safe to send again, this will probably no
+ * longer be necessary.
+ */
log_error(LOG_LEVEL_HEADER, "A HTTP/1.1 response "
"without Connection header implies keep-alive.");
csp->flags |= CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE;
static const char proxy_connection_header[] = "Proxy-Connection: keep-alive";
jb_err err = JB_ERR_OK;
- if ((csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE))
+ if ((csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE)
+ && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED))
{
log_error(LOG_LEVEL_HEADER, "Adding: %s", proxy_connection_header);
err = enlist(csp->headers, proxy_connection_header);
#ifdef FEATURE_CONNECTION_KEEP_ALIVE
if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)
- && (csp->http->ssl == 0))
+ && (csp->http->ssl == 0)
+ && !strcmpic(csp->http->ver, "HTTP/1.1"))
{
csp->flags |= CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE;
}
static const char connection_close[] = "Connection: close";
if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)
+#ifdef FEATURE_CONNECTION_KEEP_ALIVE
+ && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED)
+#endif
&& (csp->http->ssl == 0))
{
return connection_keep_alive;