From 4647e5f71a4b2d1d62238b9bce854a501b5477fb Mon Sep 17 00:00:00 2001 From: "Roy T. Fielding" Date: Sat, 21 Apr 2001 12:23:37 +0000 Subject: [PATCH] Revert the change that moved keepalives out of conn_rec. That variable controls the number of requests per connection, regardless of the protocol used by the request. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@88908 13f79535-47bb-0310-9956-ffa450edef68 --- include/httpd.h | 4 + modules/http/http_core.c | 148 ------------------------------- modules/http/http_protocol.c | 7 +- modules/http/mod_core.h | 9 -- modules/loggers/mod_log_config.c | 1 - server/protocol.c | 140 ++++++++++++++++++++++++++++- 6 files changed, 144 insertions(+), 165 deletions(-) diff --git a/include/httpd.h b/include/httpd.h index 75610b671e..d1f00af5d8 100644 --- a/include/httpd.h +++ b/include/httpd.h @@ -860,10 +860,14 @@ struct conn_rec { unsigned aborted:1; /** Are we using HTTP Keep-Alive? -1 fatal error, 0 undecided, 1 yes */ signed int keepalive:2; + /** Did we use HTTP Keep-Alive? */ + unsigned keptalive:1; /** have we done double-reverse DNS? -1 yes/failure, 0 not yet, * 1 yes/success */ signed int double_reverse:2; + /** How many times have we used it? */ + int keepalives; /** server IP address */ char *local_ip; /** used for ap_get_server_name when UseCanonicalName is set to DNS diff --git a/modules/http/http_core.c b/modules/http/http_core.c index ce6df793f1..f5948973ab 100644 --- a/modules/http/http_core.c +++ b/modules/http/http_core.c @@ -58,7 +58,6 @@ #include "apr_strings.h" #include "apr_thread_proc.h" /* for RLIMIT stuff */ -#include "apr_lib.h" #define APR_WANT_STRFUNC #include "apr_want.h" @@ -66,7 +65,6 @@ #define CORE_PRIVATE #include "httpd.h" #include "http_config.h" -#include "http_log.h" #include "http_connection.h" #include "http_protocol.h" /* For index_of_response(). Grump. */ #include "http_request.h" @@ -297,151 +295,6 @@ static int ap_process_http_connection(conn_rec *c) return OK; } -static int read_request_line(request_rec *r) -{ - char l[DEFAULT_LIMIT_REQUEST_LINE + 2]; /* getline's two extra for \n\0 */ - const char *ll = l; - const char *uri; - const char *pro; - - int major = 1, minor = 0; /* Assume HTTP/1.0 if non-"HTTP" protocol */ - int len; - - /* Read past empty lines until we get a real request line, - * a read error, the connection closes (EOF), or we timeout. - * - * We skip empty lines because browsers have to tack a CRLF on to the end - * of POSTs to support old CERN webservers. But note that we may not - * have flushed any previous response completely to the client yet. - * We delay the flush as long as possible so that we can improve - * performance for clients that are pipelining requests. If a request - * is pipelined then we won't block during the (implicit) read() below. - * If the requests aren't pipelined, then the client is still waiting - * for the final buffer flush from us, and we will block in the implicit - * read(). B_SAFEREAD ensures that the BUFF layer flushes if it will - * have to block during a read. - */ - - while ((len = ap_getline(l, sizeof(l), r, 0)) <= 0) { - if (len < 0) { /* includes EOF */ - /* this is a hack to make sure that request time is set, - * it's not perfect, but it's better than nothing - */ - r->request_time = apr_time_now(); - return 0; - } - } - /* we've probably got something to do, ignore graceful restart requests */ - - /* XXX - sigwait doesn't work if the signal has been SIG_IGNed (under - * linux 2.0 w/ glibc 2.0, anyway), and this step isn't necessary when - * we're running a sigwait thread anyway. If/when unthreaded mode is - * put back in, we should make sure to ignore this signal iff a sigwait - * thread isn't used. - mvsk - -#ifdef SIGWINCH - apr_signal(SIGWINCH, SIG_IGN); -#endif - */ - - r->request_time = apr_time_now(); - r->the_request = apr_pstrdup(r->pool, l); - r->method = ap_getword_white(r->pool, &ll); - -#if 0 -/* XXX If we want to keep track of the Method, the protocol module should do - * it. That support isn't in the scoreboard yet. Hopefully next week - * sometime. rbb */ - ap_update_connection_status(AP_CHILD_THREAD_FROM_ID(conn->id), "Method", r->method); -#endif - uri = ap_getword_white(r->pool, &ll); - - /* Provide quick information about the request method as soon as known */ - - r->method_number = ap_method_number_of(r->method); - if (r->method_number == M_GET && r->method[0] == 'H') { - r->header_only = 1; - } - - ap_parse_uri(r, uri); - - /* ap_getline returns (size of max buffer - 1) if it fills up the - * buffer before finding the end-of-line. This is only going to - * happen if it exceeds the configured limit for a request-line. - */ - if (len > r->server->limit_req_line) { - r->status = HTTP_REQUEST_URI_TOO_LARGE; - r->proto_num = HTTP_VERSION(1,0); - r->protocol = apr_pstrdup(r->pool, "HTTP/1.0"); - return 0; - } - - if (ll[0]) { - r->assbackwards = 0; - pro = ll; - len = strlen(ll); - } else { - r->assbackwards = 1; - pro = "HTTP/0.9"; - len = 8; - } - r->protocol = apr_pstrndup(r->pool, pro, len); - - /* XXX ap_update_connection_status(conn->id, "Protocol", r->protocol); */ - - /* Avoid sscanf in the common case */ - if (len == 8 && - pro[0] == 'H' && pro[1] == 'T' && pro[2] == 'T' && pro[3] == 'P' && - pro[4] == '/' && apr_isdigit(pro[5]) && pro[6] == '.' && - apr_isdigit(pro[7])) { - r->proto_num = HTTP_VERSION(pro[5] - '0', pro[7] - '0'); - } else if (2 == sscanf(r->protocol, "HTTP/%u.%u", &major, &minor) - && minor < HTTP_VERSION(1,0)) /* don't allow HTTP/0.1000 */ - r->proto_num = HTTP_VERSION(major, minor); - else - r->proto_num = HTTP_VERSION(1,0); - - return 1; -} - -static int http_create_request(request_rec *r) -{ - ap_http_conn_rec *hconn = ap_get_module_config(r->connection->conn_config, &http_module); - int keptalive; - - hconn = apr_pcalloc(r->pool, sizeof(*hconn)); - ap_set_module_config(r->connection->conn_config, &http_module, hconn); - - if (!r->main && !r->prev && !r->next) { - keptalive = r->connection->keepalive == 1; - r->connection->keepalive = 0; - - /* XXX can we optimize these timeouts at all? gstein */ - apr_setsocketopt(r->connection->client_socket, APR_SO_TIMEOUT, - (int)(keptalive - ? r->server->keep_alive_timeout * APR_USEC_PER_SEC - : r->server->timeout * APR_USEC_PER_SEC)); - - /* Get the request... */ - if (!read_request_line(r)) { - if (r->status == HTTP_REQUEST_URI_TOO_LARGE) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "request failed: URI too long"); - ap_send_error_response(r, 0); - ap_run_log_transaction(r); - return OK; - } - return DONE; - } - if (keptalive) { - apr_setsocketopt(r->connection->client_socket, - APR_SO_TIMEOUT, - (int)(r->server->timeout * APR_USEC_PER_SEC)); - } - } - return OK; -} - static void register_hooks(apr_pool_t *p) { ap_hook_pre_connection(ap_pre_http_connection,NULL,NULL, @@ -450,7 +303,6 @@ static void register_hooks(apr_pool_t *p) APR_HOOK_REALLY_LAST); ap_hook_http_method(http_method,NULL,NULL,APR_HOOK_REALLY_LAST); ap_hook_default_port(http_port,NULL,NULL,APR_HOOK_REALLY_LAST); - ap_hook_create_request(http_create_request, NULL, NULL, APR_HOOK_MIDDLE); ap_register_input_filter("HTTP_IN", ap_http_filter, AP_FTYPE_CONNECTION); ap_register_input_filter("DECHUNK", ap_dechunk_filter, AP_FTYPE_TRANSCODE); diff --git a/modules/http/http_protocol.c b/modules/http/http_protocol.c index ebbcd22312..9d765249d9 100644 --- a/modules/http/http_protocol.c +++ b/modules/http/http_protocol.c @@ -105,7 +105,6 @@ AP_DECLARE(int) ap_set_keepalive(request_rec *r) int ka_sent = 0; int wimpy = ap_find_token(r->pool, apr_table_get(r->headers_out, "Connection"), "close"); - ap_http_conn_rec *hconn = ap_get_module_config(r->connection->conn_config, &http_module); const char *conn = apr_table_get(r->headers_in, "Connection"); /* The following convoluted conditional determines whether or not @@ -147,7 +146,7 @@ AP_DECLARE(int) ap_set_keepalive(request_rec *r) && r->server->keep_alive && (r->server->keep_alive_timeout > 0) && ((r->server->keep_alive_max == 0) - || (r->server->keep_alive_max > hconn->keepalives)) + || (r->server->keep_alive_max > r->connection->keepalives)) && !ap_status_drops_connection(r->status) && !wimpy && !ap_find_token(r->pool, conn, "close") @@ -155,10 +154,10 @@ AP_DECLARE(int) ap_set_keepalive(request_rec *r) || apr_table_get(r->headers_in, "Via")) && ((ka_sent = ap_find_token(r->pool, conn, "keep-alive")) || (r->proto_num >= HTTP_VERSION(1,1)))) { - int left = r->server->keep_alive_max - hconn->keepalives; + int left = r->server->keep_alive_max - r->connection->keepalives; r->connection->keepalive = 1; - hconn->keepalives++; + r->connection->keepalives++; /* If they sent a Keep-Alive token, send one back */ if (ka_sent) { diff --git a/modules/http/mod_core.h b/modules/http/mod_core.h index 2caa038e7c..e9ff827ed1 100644 --- a/modules/http/mod_core.h +++ b/modules/http/mod_core.h @@ -70,13 +70,6 @@ extern "C" { * @package mod_core private header file */ -typedef struct ap_http_conn_rec ap_http_conn_rec; - -struct ap_http_conn_rec { - /** How many times have we used it? */ - int keepalives; -}; - /* * These (input) filters are internal to the mod_core operation. */ @@ -99,8 +92,6 @@ AP_DECLARE(void) ap_basic_http_header(request_rec *r, apr_bucket_brigade *bb); AP_DECLARE(int) ap_send_http_trace(request_rec *r); int ap_send_http_options(request_rec *r); -AP_DECLARE_DATA extern module http_module; - #ifdef __cplusplus } #endif diff --git a/modules/loggers/mod_log_config.c b/modules/loggers/mod_log_config.c index 13eb18b994..6e1ba13450 100644 --- a/modules/loggers/mod_log_config.c +++ b/modules/loggers/mod_log_config.c @@ -194,7 +194,6 @@ #include "http_core.h" /* For REMOTE_NAME */ #include "http_log.h" #include "http_protocol.h" -#include "mod_core.h" #if APR_HAVE_UNISTD_H #include diff --git a/server/protocol.c b/server/protocol.c index d6ed4d9829..45395faabe 100644 --- a/server/protocol.c +++ b/server/protocol.c @@ -363,6 +363,116 @@ AP_CORE_DECLARE(void) ap_parse_uri(request_rec *r, const char *uri) } } +static int read_request_line(request_rec *r) +{ + char l[DEFAULT_LIMIT_REQUEST_LINE + 2]; /* getline's two extra for \n\0 */ + const char *ll = l; + const char *uri; + const char *pro; + +#if 0 + conn_rec *conn = r->connection; +#endif + int major = 1, minor = 0; /* Assume HTTP/1.0 if non-"HTTP" protocol */ + int len; + + /* Read past empty lines until we get a real request line, + * a read error, the connection closes (EOF), or we timeout. + * + * We skip empty lines because browsers have to tack a CRLF on to the end + * of POSTs to support old CERN webservers. But note that we may not + * have flushed any previous response completely to the client yet. + * We delay the flush as long as possible so that we can improve + * performance for clients that are pipelining requests. If a request + * is pipelined then we won't block during the (implicit) read() below. + * If the requests aren't pipelined, then the client is still waiting + * for the final buffer flush from us, and we will block in the implicit + * read(). B_SAFEREAD ensures that the BUFF layer flushes if it will + * have to block during a read. + */ + + while ((len = ap_getline(l, sizeof(l), r, 0)) <= 0) { + if (len < 0) { /* includes EOF */ + /* this is a hack to make sure that request time is set, + * it's not perfect, but it's better than nothing + */ + r->request_time = apr_time_now(); + return 0; + } + } + /* we've probably got something to do, ignore graceful restart requests */ + + /* XXX - sigwait doesn't work if the signal has been SIG_IGNed (under + * linux 2.0 w/ glibc 2.0, anyway), and this step isn't necessary when + * we're running a sigwait thread anyway. If/when unthreaded mode is + * put back in, we should make sure to ignore this signal iff a sigwait + * thread isn't used. - mvsk + +#ifdef SIGWINCH + apr_signal(SIGWINCH, SIG_IGN); +#endif + */ + + r->request_time = apr_time_now(); + r->the_request = apr_pstrdup(r->pool, l); + r->method = ap_getword_white(r->pool, &ll); + +#if 0 +/* XXX If we want to keep track of the Method, the protocol module should do + * it. That support isn't in the scoreboard yet. Hopefully next week + * sometime. rbb */ + ap_update_connection_status(AP_CHILD_THREAD_FROM_ID(conn->id), "Method", r->method); +#endif + uri = ap_getword_white(r->pool, &ll); + + /* Provide quick information about the request method as soon as known */ + + r->method_number = ap_method_number_of(r->method); + if (r->method_number == M_GET && r->method[0] == 'H') { + r->header_only = 1; + } + + ap_parse_uri(r, uri); + + /* ap_getline returns (size of max buffer - 1) if it fills up the + * buffer before finding the end-of-line. This is only going to + * happen if it exceeds the configured limit for a request-line. + */ + if (len > r->server->limit_req_line) { + r->status = HTTP_REQUEST_URI_TOO_LARGE; + r->proto_num = HTTP_VERSION(1,0); + r->protocol = apr_pstrdup(r->pool, "HTTP/1.0"); + return 0; + } + + if (ll[0]) { + r->assbackwards = 0; + pro = ll; + len = strlen(ll); + } else { + r->assbackwards = 1; + pro = "HTTP/0.9"; + len = 8; + } + r->protocol = apr_pstrndup(r->pool, pro, len); + + /* XXX ap_update_connection_status(conn->id, "Protocol", r->protocol); */ + + /* Avoid sscanf in the common case */ + if (len == 8 && + pro[0] == 'H' && pro[1] == 'T' && pro[2] == 'T' && pro[3] == 'P' && + pro[4] == '/' && apr_isdigit(pro[5]) && pro[6] == '.' && + apr_isdigit(pro[7])) { + r->proto_num = HTTP_VERSION(pro[5] - '0', pro[7] - '0'); + } else if (2 == sscanf(r->protocol, "HTTP/%u.%u", &major, &minor) + && minor < HTTP_VERSION(1,0)) /* don't allow HTTP/0.1000 */ + r->proto_num = HTTP_VERSION(major, minor); + else + r->proto_num = HTTP_VERSION(1,0); + + return 1; +} + static void get_mime_headers(request_rec *r) { char field[DEFAULT_LIMIT_REQUEST_FIELDSIZE + 2]; /* getline's two extra */ @@ -446,6 +556,9 @@ request_rec *ap_read_request(conn_rec *conn) r->connection = conn; r->server = conn->base_server; + conn->keptalive = conn->keepalive == 1; + conn->keepalive = 0; + r->user = NULL; r->ap_auth_type = NULL; @@ -458,9 +571,7 @@ request_rec *ap_read_request(conn_rec *conn) r->notes = apr_table_make(r->pool, 5); r->request_config = ap_create_request_config(r->pool); - if (ap_run_create_request(r) != OK) { - return NULL; - } + ap_run_create_request(r); r->per_dir_config = r->server->lookup_defaults; r->sent_bodyct = 0; /* bytect isn't for body */ @@ -469,13 +580,34 @@ request_rec *ap_read_request(conn_rec *conn) r->read_body = REQUEST_NO_BODY; r->status = HTTP_REQUEST_TIME_OUT; /* Until we get a request */ + r->the_request = NULL; r->output_filters = conn->output_filters; r->input_filters = conn->input_filters; + apr_setsocketopt(conn->client_socket, APR_SO_TIMEOUT, + (int)(conn->keptalive + ? r->server->keep_alive_timeout * APR_USEC_PER_SEC + : r->server->timeout * APR_USEC_PER_SEC)); + ap_add_output_filter("BYTERANGE", NULL, r, r->connection); ap_add_output_filter("CONTENT_LENGTH", NULL, r, r->connection); ap_add_output_filter("HTTP_HEADER", NULL, r, r->connection); + /* Get the request... */ + if (!read_request_line(r)) { + if (r->status == HTTP_REQUEST_URI_TOO_LARGE) { + ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, + "request failed: URI too long"); + ap_send_error_response(r, 0); + ap_run_log_transaction(r); + return r; + } + return NULL; + } + if (r->connection->keptalive) { + apr_setsocketopt(r->connection->client_socket, APR_SO_TIMEOUT, + (int)(r->server->timeout * APR_USEC_PER_SEC)); + } if (!r->assbackwards) { get_mime_headers(r); if (r->status != HTTP_REQUEST_TIME_OUT) { @@ -514,6 +646,8 @@ request_rec *ap_read_request(conn_rec *conn) /* we may have switched to another server */ r->per_dir_config = r->server->lookup_defaults; + conn->keptalive = 0; /* We now have a request to play with */ + if ((!r->hostname && (r->proto_num >= HTTP_VERSION(1,1))) || ((r->proto_num == HTTP_VERSION(1,1)) && !apr_table_get(r->headers_in, "Host"))) { -- 2.50.1