*/
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
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;
}
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
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;
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);