ap_send_error_response(r_1st_err, recursive_error);
}
-static void check_pipeline_flush(request_rec *r)
+/* Check whether there's another request ready to be read
+ */
+static void check_pipeline(conn_rec *c)
{
- apr_bucket *e;
- apr_bucket_brigade *bb;
- conn_rec *c = r->connection;
- /* ### if would be nice if we could PEEK without a brigade. that would
- ### allow us to defer creation of the brigade to when we actually
- ### need to send a FLUSH. */
- bb = apr_brigade_create(r->pool, c->bucket_alloc);
-
- /* Flush the filter contents if:
- *
- * 1) the connection will be closed
- * 2) there isn't a request ready to be read
- */
- /* ### shouldn't this read from the connection input filters? */
/* ### is zero correct? that means "read one line" */
- if (r->connection->keepalive != AP_CONN_CLOSE) {
- if (ap_get_brigade(r->input_filters, bb, AP_MODE_EATCRLF,
+ if (c->keepalive != AP_CONN_CLOSE) {
+ apr_bucket_brigade *bb = apr_brigade_create(c->pool, c->bucket_alloc);
+ if (ap_get_brigade(c->input_filters, bb, AP_MODE_EATCRLF,
APR_NONBLOCK_READ, 0) != APR_SUCCESS) {
c->data_in_input_filters = 0; /* we got APR_EOF or an error */
}
else {
c->data_in_input_filters = 1;
- return; /* don't flush */
}
}
-
- e = apr_bucket_flush_create(c->bucket_alloc);
-
- /* We just send directly to the connection based filters. At
- * this point, we know that we have seen all of the data
- * (request finalization sent an EOS bucket, which empties all
- * of the request filters). We just want to flush the buckets
- * if something hasn't been sent to the network yet.
- */
- APR_BRIGADE_INSERT_HEAD(bb, e);
- ap_pass_brigade(r->connection->output_filters, bb);
}
-void ap_process_request(request_rec *r)
+void ap_process_async_request(request_rec *r)
{
int access_status;
apr_bucket_brigade *bb;
apr_bucket *b;
+ conn_rec *c = r->connection;
/* Give quick handlers a shot at serving the request on the fast
* path, bypassing all of the other Apache hooks.
b = ap_bucket_eor_create(r->connection->bucket_alloc, r);
APR_BRIGADE_INSERT_HEAD(bb, b);
ap_pass_brigade(r->connection->output_filters, bb);
+ c->cs->state = CONN_STATE_WRITE_COMPLETION;
+ check_pipeline(c);
+}
- /*
- * We want to flush the last packet if this isn't a pipelining connection
- * *before* we start into logging. Suppose that the logging causes a DNS
- * lookup to occur, which may have a high latency. If we hold off on
- * this packet, then it'll appear like the link is stalled when really
- * it's the application that's stalled.
- */
- check_pipeline_flush(r);
- ap_update_child_status(r->connection->sbh, SERVER_BUSY_LOG, r);
- if (ap_extended_status)
+void ap_process_request(request_rec *r)
+{
+ apr_bucket_brigade *bb;
+ apr_bucket *b;
+ conn_rec *c = r->connection;
+
+ ap_process_async_request(r);
+
+ if (!c->data_in_input_filters) {
+ bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
+ b = apr_bucket_flush_create(c->bucket_alloc);
+ APR_BRIGADE_INSERT_HEAD(bb, b);
+ ap_pass_brigade(r->connection->output_filters, bb);
+ ap_update_child_status(r->connection->sbh, SERVER_BUSY_LOG, r);
+ }
+ if (ap_extended_status) {
ap_time_process_request(r->connection->sbh, STOP_PREQUEST);
+ }
}
static apr_table_t *rename_original_env(apr_pool_t *p, apr_table_t *t)
cs->state = CONN_STATE_LINGER;
}
}
+
+ if (cs->state == CONN_STATE_WRITE_COMPLETION) {
+ /* For now, do blocking writes in this thread to transfer the
+ * rest of the response. TODO: Hand off this connection to a
+ * pollset for asynchronous write completion.
+ */
+ apr_bucket_brigade *bb = apr_brigade_create(c->pool, c->bucket_alloc);
+ apr_bucket *b = apr_bucket_flush_create(c->bucket_alloc);
+ APR_BRIGADE_INSERT_HEAD(bb, b);
+ ap_pass_brigade(c->output_filters, bb);
+ if (c->keepalive != AP_CONN_KEEPALIVE || c->aborted ||
+ ap_graceful_stop_signalled()) {
+ c->cs->state = CONN_STATE_LINGER;
+ }
+ else if (c->data_in_input_filters) {
+ cs->state = CONN_STATE_READ_REQUEST_LINE;
+ }
+ else {
+ cs->state = CONN_STATE_CHECK_REQUEST_LINE_READABLE;
+ }
+ }
if (cs->state == CONN_STATE_LINGER) {
ap_lingering_close(c);