From: Ryan Bloom Date: Wed, 18 Apr 2001 03:53:34 +0000 (+0000) Subject: Move the keepalives field out of the conn_rec and into an HTTP specific X-Git-Tag: 2.0.18~210 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=70a67b2c260ccea7e840c819b4e156678713caa3;p=apache Move the keepalives field out of the conn_rec and into an HTTP specific connection record. This also moves some HTTP specific back out of the core and into the HTTP module. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@88881 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/include/httpd.h b/include/httpd.h index d1f00af5d8..75610b671e 100644 --- a/include/httpd.h +++ b/include/httpd.h @@ -860,14 +860,10 @@ 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/config.m4 b/modules/http/config.m4 index 6d581e586d..da29de1a79 100644 --- a/modules/http/config.m4 +++ b/modules/http/config.m4 @@ -7,5 +7,8 @@ http_objects="http_core.lo http_protocol.lo http_request.lo" APACHE_MODULE(http, HTTP protocol handling, $http_objects, , yes) APACHE_MODULE(mime, mapping of file-extension to MIME, , , yes) +if test "$enable_http" = "yes"; then + AC_DEFINE(AP_HTTP_ENABLED, 1, [HTTP is enabled on this server]) +fi APACHE_MODPATH_FINISH diff --git a/modules/http/http_core.c b/modules/http/http_core.c index f5948973ab..ce6df793f1 100644 --- a/modules/http/http_core.c +++ b/modules/http/http_core.c @@ -58,6 +58,7 @@ #include "apr_strings.h" #include "apr_thread_proc.h" /* for RLIMIT stuff */ +#include "apr_lib.h" #define APR_WANT_STRFUNC #include "apr_want.h" @@ -65,6 +66,7 @@ #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" @@ -295,6 +297,151 @@ 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, @@ -303,6 +450,7 @@ 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 9d765249d9..ebbcd22312 100644 --- a/modules/http/http_protocol.c +++ b/modules/http/http_protocol.c @@ -105,6 +105,7 @@ 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 @@ -146,7 +147,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 > r->connection->keepalives)) + || (r->server->keep_alive_max > hconn->keepalives)) && !ap_status_drops_connection(r->status) && !wimpy && !ap_find_token(r->pool, conn, "close") @@ -154,10 +155,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 - r->connection->keepalives; + int left = r->server->keep_alive_max - hconn->keepalives; r->connection->keepalive = 1; - r->connection->keepalives++; + hconn->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 e9ff827ed1..477b981754 100644 --- a/modules/http/mod_core.h +++ b/modules/http/mod_core.h @@ -70,6 +70,13 @@ 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. */ @@ -92,6 +99,8 @@ 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 module http_module; + #ifdef __cplusplus } #endif diff --git a/modules/loggers/mod_log_config.c b/modules/loggers/mod_log_config.c index fbe7ec1ca7..375da43115 100644 --- a/modules/loggers/mod_log_config.c +++ b/modules/loggers/mod_log_config.c @@ -191,6 +191,7 @@ #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 @@ -527,13 +528,19 @@ static const char *log_child_pid(request_rec *r, char *a) } static const char *log_connection_status(request_rec *r, char *a) { +#ifdef AP_HTTP_ENABLED + ap_http_conn_rec *hconn = ap_get_module_config(r->connection->conn_config, + &http_module); +#endif if (r->connection->aborted) return "X"; +#ifdef AP_HTTP_ENABLED if ((r->connection->keepalive) && - ((r->server->keep_alive_max - r->connection->keepalives) > 0)) { + ((r->server->keep_alive_max - hconn->keepalives) > 0)) { return "+"; } +#endif return "-"; } diff --git a/server/protocol.c b/server/protocol.c index 45395faabe..1e4aa6fc91 100644 --- a/server/protocol.c +++ b/server/protocol.c @@ -363,116 +363,6 @@ 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 */ @@ -556,9 +446,6 @@ 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; @@ -571,7 +458,9 @@ 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); - ap_run_create_request(r); + if (ap_run_create_request(r) != OK) { + return NULL; + } r->per_dir_config = r->server->lookup_defaults; r->sent_bodyct = 0; /* bytect isn't for body */ @@ -584,30 +473,10 @@ request_rec *ap_read_request(conn_rec *conn) 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) { @@ -646,8 +515,6 @@ 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"))) {