-const char parsers_rcs[] = "$Id: parsers.c,v 1.189 2009/07/05 12:04:46 fabiankeil Exp $";
+const char parsers_rcs[] = "$Id: parsers.c,v 1.208 2009/09/06 14:10:07 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 server_proxy_connection(struct client_state *csp, char **header);
static jb_err client_keep_alive(struct client_state *csp, char **header);
+static jb_err client_save_content_length(struct client_state *csp, char **header);
#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
static jb_err client_host_adder (struct client_state *csp);
static jb_err create_fake_referrer(char **header, const char *fake_referrer);
static jb_err handle_conditional_hide_referrer_parameter(char **header,
const char *host, const int parameter_conditional_block);
-static const char *get_appropiate_connection_header(const struct client_state *csp);
static void create_content_length_header(unsigned long long content_length,
char *header, size_t buffer_length);
{ "if-modified-since:", 18, client_if_modified_since },
#ifdef FEATURE_CONNECTION_KEEP_ALIVE
{ "Keep-Alive:", 11, client_keep_alive },
+ { "Content-Length:", 15, client_save_content_length },
#else
{ "Keep-Alive:", 11, crumble },
#endif
#ifdef FEATURE_CONNECTION_KEEP_ALIVE
{ "Content-Length:", 15, server_save_content_length },
{ "Keep-Alive:", 11, server_keep_alive },
+ { "Proxy-Connection:", 17, server_proxy_connection },
#else
{ "Keep-Alive:", 11, crumble },
#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
assert(bufsize >= skip_size);
memcpy(buf, csp->iob->buf, skip_size);
- zstr.avail_out = bufsize - skip_size;
+ zstr.avail_out = (uInt)(bufsize - skip_size);
zstr.next_out = (Bytef *)buf + skip_size;
/* Try to decompress the whole stream in one shot. */
* buffer, which may be in a location different from
* the old one.
*/
- zstr.avail_out += bufsize - oldbufsize;
+ zstr.avail_out += (uInt)(bufsize - oldbufsize);
zstr.next_out = (Bytef *)tmpbuf + bufsize - zstr.avail_out;
/*
*/
assert(zstr.avail_out == tmpbuf + bufsize - (char *)zstr.next_out);
assert((char *)zstr.next_out == tmpbuf + ((char *)oldnext_out - buf));
- assert(zstr.avail_out > 0U);
buf = tmpbuf;
}
"Server keep-alive timeout is %u. Sticking with %u.",
keep_alive_timeout, csp->server_connection.keep_alive_timeout);
}
+ csp->flags |= CSP_FLAG_SERVER_KEEP_ALIVE_TIMEOUT_SET;
}
return JB_ERR_OK;
}
+/*********************************************************************
+ *
+ * Function : server_proxy_connection
+ *
+ * Description : Figures out whether or not we should add a
+ * Proxy-Connection header.
+ *
+ * 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 server_proxy_connection(struct client_state *csp, char **header)
+{
+ csp->flags |= CSP_FLAG_SERVER_PROXY_CONNECTION_HEADER_SET;
+ return JB_ERR_OK;
+}
+
+
/*********************************************************************
*
* Function : client_keep_alive
unsigned int keep_alive_timeout;
const char *timeout_position = strstr(*header, ": ");
+ if (!(csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE))
+ {
+ log_error(LOG_LEVEL_HEADER,
+ "keep-alive support is disabled. Crunching: %s.", *header);
+ freez(*header);
+ return JB_ERR_OK;
+ }
+
if ((NULL == timeout_position)
|| (1 != sscanf(timeout_position, ": %u", &keep_alive_timeout)))
{
/* 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);
+ keep_alive_timeout, csp->config->keep_alive_timeout);
}
}
return JB_ERR_OK;
}
+
+
+/*********************************************************************
+ *
+ * Function : get_content_length
+ *
+ * Description : Gets the content length specified in a
+ * Content-Length header.
+ *
+ * Parameters :
+ * 1 : header = The Content-Length header.
+ * 2 : length = Storage to return the value.
+ *
+ * Returns : JB_ERR_OK on success, or
+ * JB_ERR_PARSE if no value is recognized.
+ *
+ *********************************************************************/
+static jb_err get_content_length(const char *header, unsigned long long *length)
+{
+ assert(header[14] == ':');
+
+#ifdef _WIN32
+ assert(sizeof(unsigned long long) > 4);
+ if (1 != sscanf(header+14, ": %I64u", length))
+#else
+ if (1 != sscanf(header+14, ": %llu", length))
+#endif
+ {
+ return JB_ERR_PARSE;
+ }
+
+ return JB_ERR_OK;
+}
+
+
+/*********************************************************************
+ *
+ * Function : client_save_content_length
+ *
+ * Description : Save the Content-Length sent by the client.
+ *
+ * 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 on success, or
+ * JB_ERR_MEMORY on out-of-memory error.
+ *
+ *********************************************************************/
+static jb_err client_save_content_length(struct client_state *csp, char **header)
+{
+ unsigned long long content_length = 0;
+
+ assert(*(*header+14) == ':');
+
+ if (JB_ERR_OK != get_content_length(*header, &content_length))
+ {
+ log_error(LOG_LEVEL_ERROR, "Crunching invalid header: %s", *header);
+ freez(*header);
+ }
+ else
+ {
+ csp->expected_client_content_length = content_length;
+ }
+
+ return JB_ERR_OK;
+}
#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
*********************************************************************/
static jb_err client_connection(struct client_state *csp, char **header)
{
- const char *wanted_header = get_appropiate_connection_header(csp);
+ static const char connection_close[] = "Connection: close";
- if (strcmpic(*header, wanted_header))
+ if (!strcmpic(*header, connection_close))
{
#ifdef FEATURE_CONNECTION_KEEP_ALIVE
- if (!(csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_SHARING))
+ if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_SHARING))
{
- log_error(LOG_LEVEL_HEADER,
- "Keeping the client header '%s' around. "
- "The connection will not be kept alive.",
- *header);
+ if (!strcmpic(csp->http->ver, "HTTP/1.1"))
+ {
+ log_error(LOG_LEVEL_HEADER,
+ "Removing \'%s\' to imply keep-alive.", *header);
+ freez(*header);
+ }
+ else
+ {
+ char *old_header = *header;
+
+ *header = strdup("Connection: keep-alive");
+ if (header == NULL)
+ {
+ return JB_ERR_MEMORY;
+ }
+ log_error(LOG_LEVEL_HEADER,
+ "Replaced: \'%s\' with \'%s\'", old_header, *header);
+ freez(old_header);
+ }
}
else
-#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
{
- char *old_header = *header;
-
- *header = strdup(wanted_header);
- if (header == NULL)
- {
- return JB_ERR_MEMORY;
- }
log_error(LOG_LEVEL_HEADER,
- "Replaced: \'%s\' with \'%s\'", old_header, *header);
- freez(old_header);
+ "Keeping the client header '%s' around. "
+ "The connection will not be kept alive.",
+ *header);
+ csp->flags &= ~CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE;
}
}
-#ifdef FEATURE_CONNECTION_KEEP_ALIVE
- else
+ else if ((csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE))
{
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 */
+ }
+ else
+ {
+ char *old_header = *header;
+
+ *header = strdup(connection_close);
+ if (header == NULL)
+ {
+ return JB_ERR_MEMORY;
+ }
+ log_error(LOG_LEVEL_HEADER,
+ "Replaced: \'%s\' with \'%s\'", old_header, *header);
+ freez(old_header);
+ }
/* Signal client_connection_adder() to return early. */
csp->flags |= CSP_FLAG_CLIENT_CONNECTION_HEADER_SET;
assert(*(*header+14) == ':');
-#ifdef _WIN32
- if (1 != sscanf(*header+14, ": %I64u", &content_length))
-#else
- if (1 != sscanf(*header+14, ": %llu", &content_length))
-#endif
+ if (JB_ERR_OK != get_content_length(*header, &content_length))
{
log_error(LOG_LEVEL_ERROR, "Crunching invalid header: %s", *header);
freez(*header);
{
const unsigned int flags = csp->flags;
const char *response_status_line = csp->headers->first->str;
- const char *wanted_header = get_appropiate_connection_header(csp);
+ static const char connection_close[] = "Connection: close";
if ((flags & CSP_FLAG_CLIENT_HEADER_PARSING_DONE)
&& (flags & CSP_FLAG_SERVER_CONNECTION_HEADER_SET))
#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;
+ return JB_ERR_OK;
}
- log_error(LOG_LEVEL_HEADER, "Adding: %s", wanted_header);
+ log_error(LOG_LEVEL_HEADER, "Adding: %s", connection_close);
- return enlist(csp->headers, wanted_header);
+ return enlist(csp->headers, connection_close);
}
jb_err err = JB_ERR_OK;
if ((csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE)
- && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED))
+ && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED)
+ && !(csp->flags & CSP_FLAG_SERVER_PROXY_CONNECTION_HEADER_SET))
{
log_error(LOG_LEVEL_HEADER, "Adding: %s", proxy_connection_header);
err = enlist(csp->headers, proxy_connection_header);
*********************************************************************/
static jb_err client_connection_header_adder(struct client_state *csp)
{
- const char *wanted_header = get_appropiate_connection_header(csp);
+ static const char connection_close[] = "Connection: close";
if (!(csp->flags & CSP_FLAG_CLIENT_HEADER_PARSING_DONE)
&& (csp->flags & CSP_FLAG_CLIENT_CONNECTION_HEADER_SET))
&& !strcmpic(csp->http->ver, "HTTP/1.1"))
{
csp->flags |= CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE;
+ return JB_ERR_OK;
}
#endif /* FEATURE_CONNECTION_KEEP_ALIVE */
- log_error(LOG_LEVEL_HEADER, "Adding: %s", wanted_header);
+ log_error(LOG_LEVEL_HEADER, "Adding: %s", connection_close);
- return enlist(csp->headers, wanted_header);
+ return enlist(csp->headers, connection_close);
}
* Function : server_set_cookie
*
* Description : Handle the server "cookie" header properly.
- * Log cookie to the jar file. Then "crunch",
- * accept or rewrite it to a session cookie.
+ * Crunch, accept or rewrite it to a session cookie.
* Called from `sed'.
*
* TODO: Allow the user to specify a new expiration
}
-/*********************************************************************
- *
- * Function : get_appropiate_connection_header
- *
- * Description : Returns an appropiate Connection header
- * depending on whether or not we try to keep
- * the connection to the server alive.
- *
- * Parameters :
- * 1 : csp = Current client state (buffers, headers, etc...)
- *
- * Returns : Pointer to statically allocated header buffer.
- *
- *********************************************************************/
-static const char *get_appropiate_connection_header(const struct client_state *csp)
-{
- static const char connection_keep_alive[] = "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;
- }
- return connection_close;
-}
-
-
/*********************************************************************
*
* Function : create_content_length_header