From: Brian Pane Date: Sun, 4 Dec 2005 20:38:25 +0000 (+0000) Subject: Added ap_read_async_request()... X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fca35efc302dda363ee8e34c8ddf65c14c5a5ab8;p=thirdparty%2Fapache%2Fhttpd.git Added ap_read_async_request()... At the moment, asynchronous MPMs still read the request headers with the connection in blocking mode. To enable asynchronous read completion, we'll need to make some changes in the Event MPM. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/async-read-dev@353904 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/include/http_protocol.h b/include/http_protocol.h index c2c933e8588..9c2bb1b35c1 100644 --- a/include/http_protocol.h +++ b/include/http_protocol.h @@ -61,6 +61,16 @@ AP_DECLARE_DATA extern ap_filter_rec_t *ap_old_write_func; */ request_rec *ap_read_request(conn_rec *c); +/** + * Read part or all of a request and fill in the fields. + * @param c The current connection + * @return APR_SUCCESS if the request header is completely read, + * APR_EAGAIN if the caller should wait for readability on + * the connection and try again, arbirary other apr_status_t + * values if the read fails for any other reason + */ +apr_status_t ap_read_async_request(conn_rec *c); + /** * Read the mime-encoded headers. * @param r The current request diff --git a/include/httpd.h b/include/httpd.h index ef488238e1c..65468874fc7 100644 --- a/include/httpd.h +++ b/include/httpd.h @@ -1078,6 +1078,9 @@ struct conn_rec { int data_in_input_filters; /** Is there data pending in the output filters? */ int data_in_output_filters; + /** The request (possibly incomplete) currently being processed + * on this connection, or NULL if not applicable */ + request_rec *request; }; /** diff --git a/modules/http/http_core.c b/modules/http/http_core.c index 14d8a1b598b..fe291c85f78 100644 --- a/modules/http/http_core.c +++ b/modules/http/http_core.c @@ -108,42 +108,36 @@ static apr_port_t http_port(const request_rec *r) static int ap_process_http_async_connection(conn_rec *c) { - request_rec *r; + apr_status_t rv; conn_state_t *cs = c->cs; AP_DEBUG_ASSERT(cs->state == CONN_STATE_READ_REQUEST_LINE); - while (cs->state == CONN_STATE_READ_REQUEST_LINE) { - ap_update_child_status(c->sbh, SERVER_BUSY_READ, NULL); - - if ((r = ap_read_request(c))) { - - c->keepalive = AP_CONN_UNKNOWN; - /* process the request if it was read without error */ - - ap_update_child_status(c->sbh, SERVER_BUSY_WRITE, r); - if (r->status == HTTP_OK) { - cs->state = CONN_STATE_HANDLER; - ap_process_async_request(r); - /* After the call to ap_process_request, the - * request pool may have been deleted. We set - * r=NULL here to ensure that any dereference - * of r that might be added later in this function - * will result in a segfault immediately instead - * of nondeterministic failures later. - */ - r = NULL; - } - - if (cs->state != CONN_STATE_WRITE_COMPLETION) { - /* Something went wrong; close the connection */ - cs->state = CONN_STATE_LINGER; - } + ap_update_child_status(c->sbh, SERVER_BUSY_READ, NULL); + + rv = ap_read_async_request(c); + if (rv == APR_SUCCESS) { + c->keepalive = AP_CONN_UNKNOWN; + /* process the request if it was read without error */ + ap_update_child_status(c->sbh, SERVER_BUSY_WRITE, c->request); + if (c->request->status == HTTP_OK) { + cs->state = CONN_STATE_HANDLER; + ap_process_async_request(c->request); + c->request = NULL; } - else { /* ap_read_request failed - client may have closed */ + + if (cs->state != CONN_STATE_WRITE_COMPLETION) { + /* Something went wrong; close the connection */ cs->state = CONN_STATE_LINGER; } } + else if (!APR_STATUS_IS_EAGAIN(rv)) { + /* EAGAIN means that we've successfully read a partial request + * header, which is valid in an async server. For any other error, + * close the connection. + */ + cs->state = CONN_STATE_LINGER; + } return OK; } @@ -164,11 +158,12 @@ static int ap_process_http_connection(conn_rec *c) c->keepalive = AP_CONN_UNKNOWN; /* process the request if it was read without error */ - + c->request = r; ap_update_child_status(c->sbh, SERVER_BUSY_WRITE, r); if (r->status == HTTP_OK) { cs->state = CONN_STATE_HANDLER; ap_process_request(r); + c->request = NULL; /* After the call to ap_process_request, the * request pool will have been deleted. We set * r=NULL here to ensure that any dereference diff --git a/server/protocol.c b/server/protocol.c index 8425678ad90..0e741bbf849 100644 --- a/server/protocol.c +++ b/server/protocol.c @@ -1002,6 +1002,55 @@ static apr_status_t read_partial_request(request_rec *r) { return rv; } +AP_DECLARE(apr_status_t) ap_read_async_request(conn_rec *conn) +{ + apr_status_t rv; + request_rec *r; + + if (conn->request == NULL) { + conn->request = init_request(conn); + if (conn->request == NULL) { + return APR_EGENERAL; + } + } + + r = conn->request; + rv = read_partial_request(r); + if (APR_STATUS_IS_EAGAIN(rv)) { + return APR_EAGAIN; + } + if (r->status != HTTP_OK) { + ap_send_error_response(r, 0); + ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r); + ap_run_log_transaction(r); + return APR_EGENERAL; + } + + if (r->assbackwards && r->header_only) { + /* + * Client asked for headers only with HTTP/0.9, which doesn't send + * headers! Have to dink things just to make sure the error message + * comes through... + */ + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "client sent invalid HTTP/0.9 request: HEAD %s", + r->uri); + r->header_only = 0; + r->status = HTTP_BAD_REQUEST; + ap_send_error_response(r, 0); + ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r); + ap_run_log_transaction(r); + return APR_EGENERAL; + } + + if (request_post_read(r, conn) == NULL) { + return APR_EGENERAL; + } + else { + return APR_SUCCESS; + } +} + request_rec *ap_read_request(conn_rec *conn) { request_rec *r; @@ -1010,7 +1059,6 @@ request_rec *ap_read_request(conn_rec *conn) r = init_request(conn); rv = read_partial_request(r); - /* TODO poll if EAGAIN */ if (r->status != HTTP_OK) { ap_send_error_response(r, 0); ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r);