From 63728b12fd2e66db3f948a2ef5422b007825944c Mon Sep 17 00:00:00 2001 From: Fabian Keil Date: Sun, 28 Jun 2009 14:31:43 +0000 Subject: [PATCH] If we think we already got a complete request, don't try to read from the client until we're ready again. If we notice that we got more than a single request, mark the server socket tainted and only serve the first request. --- jcc.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++-- parsers.c | 20 ++++++++++++++++---- project.h | 17 ++++++++++++++++- 3 files changed, 79 insertions(+), 7 deletions(-) diff --git a/jcc.c b/jcc.c index 932f7a4c..867a5c98 100644 --- a/jcc.c +++ b/jcc.c @@ -1,4 +1,4 @@ -const char jcc_rcs[] = "$Id: jcc.c,v 1.257 2009/06/12 13:39:02 fabiankeil Exp $"; +const char jcc_rcs[] = "$Id: jcc.c,v 1.258 2009/06/27 11:22:52 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/jcc.c,v $ @@ -1143,6 +1143,7 @@ static void mark_server_socket_tainted(struct client_state *csp) { log_error(LOG_LEVEL_CONNECT, "Unsetting keep-alive flag."); csp->flags &= ~CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE; + csp->flags |= CSP_FLAG_SERVER_SOCKET_TAINTED; } } @@ -1442,6 +1443,39 @@ static jb_err parse_client_request(struct client_state *csp) return JB_ERR_PARSE; } +#ifdef FEATURE_CONNECTION_KEEP_ALIVE + if ((csp->flags & CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE)) + { + if (csp->iob->cur[0] != '\0') + { + csp->flags |= CSP_FLAG_SERVER_SOCKET_TAINTED; + if (!strcmpic(csp->http->gpc, "POST")) + { + /* XXX: this is an incomplete hack */ + csp->flags &= ~CSP_FLAG_CLIENT_REQUEST_COMPLETELY_READ; + log_error(LOG_LEVEL_CONNECT, + "POST request detected. The connection will not be kept alive."); + } + else + { + /* XXX: and so is this */ + csp->flags |= CSP_FLAG_CLIENT_REQUEST_COMPLETELY_READ; + log_error(LOG_LEVEL_CONNECT, + "Possible pipeline attempt detected. The connection will not " + "be kept alive and we will only serve the first request."); + /* Nuke the pipelined requests from orbit, just to be sure. */ + csp->iob->buf[0] = '\0'; + csp->iob->eod = csp->iob->cur = csp->iob->buf; + } + } + else + { + csp->flags |= CSP_FLAG_CLIENT_REQUEST_COMPLETELY_READ; + log_error(LOG_LEVEL_CONNECT, "Complete client request received."); + } + } +#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ + return JB_ERR_OK; } @@ -1727,7 +1761,17 @@ static void chat(struct client_state *csp) #else FD_ZERO(&rfds); #endif - FD_SET(csp->cfd, &rfds); +#ifdef FEATURE_CONNECTION_KEEP_ALIVE + if ((csp->flags & CSP_FLAG_CLIENT_REQUEST_COMPLETELY_READ)) + { + maxfd = csp->sfd; + } + else +#endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ + { + FD_SET(csp->cfd, &rfds); + } + FD_SET(csp->sfd, &rfds); #ifdef FEATURE_CONNECTION_KEEP_ALIVE @@ -2279,6 +2323,7 @@ static void serve(struct client_state *csp) continue_chatting = (csp->config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE) && (csp->flags & CSP_FLAG_SERVER_CONNECTION_KEEP_ALIVE) + && !(csp->flags & CSP_FLAG_SERVER_SOCKET_TAINTED) && (csp->cfd != JB_INVALID_SOCKET) && (csp->sfd != JB_INVALID_SOCKET) && socket_is_still_usable(csp->sfd); diff --git a/parsers.c b/parsers.c index f3d82745..a8d36838 100644 --- a/parsers.c +++ b/parsers.c @@ -1,4 +1,4 @@ -const char parsers_rcs[] = "$Id: parsers.c,v 1.184 2009/06/18 17:10:16 fabiankeil Exp $"; +const char parsers_rcs[] = "$Id: parsers.c,v 1.185 2009/06/27 11:25:33 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/parsers.c,v $ @@ -1580,7 +1580,11 @@ static jb_err filter_header(struct client_state *csp, char **header) *********************************************************************/ 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)) @@ -3403,7 +3407,11 @@ static jb_err server_connection_adder(struct client_state *csp) 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 + ) { log_error(LOG_LEVEL_HEADER, "A HTTP/1.1 response " "without Connection header implies keep-alive."); @@ -3437,7 +3445,8 @@ static jb_err server_proxy_connection_adder(struct client_state *csp) 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); @@ -4048,6 +4057,9 @@ static const char *get_appropiate_connection_header(const struct client_state *c 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; diff --git a/project.h b/project.h index 4d0d9863..0353de77 100644 --- a/project.h +++ b/project.h @@ -1,7 +1,7 @@ #ifndef PROJECT_H_INCLUDED #define PROJECT_H_INCLUDED /** Version string. */ -#define PROJECT_H_VERSION "$Id: project.h,v 1.141 2009/06/11 11:46:22 fabiankeil Exp $" +#define PROJECT_H_VERSION "$Id: project.h,v 1.142 2009/06/11 11:49:11 fabiankeil Exp $" /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/project.h,v $ @@ -755,8 +755,23 @@ struct reusable_connection * the connection alive. */ #define CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE 0x00008000U + +/** + * Flag for csp->flags: Set if we think we got the whole + * client request and shouldn't read any additional data + * coming from the client until the current request has + * been dealt with. + */ +#define CSP_FLAG_CLIENT_REQUEST_COMPLETELY_READ 0x00010000U + #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */ +/** + * Flag for csp->flags: Set if we think we can't reuse + * the server socket. + */ +#define CSP_FLAG_SERVER_SOCKET_TAINTED 0x00020000U + /* * Flags for use in return codes of child processes */ -- 2.39.2