*/
#define WRITE_SIZE_MAX (TLS_DATA_MAX - 100)
-#define WRITE_BUFFER_SIZE (8*WRITE_SIZE_MAX)
+#define WRITE_BUFFER_SIZE (5*WRITE_SIZE_MAX)
apr_status_t h2_conn_io_init(h2_conn_io *io, conn_rec *c,
const h2_config *cfg,
"h2_conn_io: buffering %ld bytes", (long)length);
if (!APR_BRIGADE_EMPTY(io->output)) {
- status = h2_conn_io_flush_int(io, 0, 0);
+ status = h2_conn_io_pass(io, 0);
}
while (length > 0 && (status == APR_SUCCESS)) {
apr_size_t avail = io->bufsize - io->buflen;
if (avail <= 0) {
- h2_conn_io_flush_int(io, 1, 0);
+ h2_conn_io_pass(io, 0);
}
else if (length > avail) {
memcpy(io->buffer + io->buflen, buf, avail);
return APR_SUCCESS;
}
-static apr_status_t h2_session_read(h2_session *session, int block, int loops)
+static apr_status_t h2_session_read(h2_session *session, int block)
{
apr_status_t status, rstatus = APR_EAGAIN;
conn_rec *c = session->c;
- int i;
+ apr_off_t read_start = session->io.bytes_read;
- for (i = 0; i < loops; ++i) {
+ while (1) {
/* H2_IN filter handles all incoming data against the session.
* We just pull at the filter chain to make it happen */
status = ap_get_brigade(c->input_filters,
case APR_TIMEUP:
return status;
default:
- if (!i) {
+ if (session->io.bytes_read == read_start) {
/* first attempt failed */
if (APR_STATUS_IS_ETIMEDOUT(status)
|| APR_STATUS_IS_ECONNABORTED(status)
if (!is_accepting_streams(session)) {
break;
}
+ if ((session->io.bytes_read - read_start) > (64*1024)) {
+ /* read enough in one go, give write a chance */
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE2, status, c,
+ "h2_session(%ld): read 64k, returning", session->id);
+ break;
+ }
}
return rstatus;
}
/* When we have no streams, no task event are possible,
* switch to blocking reads */
transit(session, "no io", H2_SESSION_ST_IDLE);
- session->idle_until = apr_time_now() + session->s->keep_alive_timeout;
+ session->idle_until = (session->requests_received?
+ session->s->keep_alive_timeout :
+ session->s->timeout) + apr_time_now();
}
}
else if (!h2_stream_set_has_unsubmitted(session->streams)
no_streams = h2_stream_set_is_empty(session->streams);
update_child_status(session, (no_streams? SERVER_BUSY_KEEPALIVE
: SERVER_BUSY_READ), "idle");
- if (async && !session->r) {
+ if (async && !session->r && session->requests_received && no_streams) {
ap_log_cerror( APLOG_MARK, APLOG_TRACE1, status, c,
"h2_session(%ld): async idle, nonblock read", session->id);
/* We do not return to the async mpm immediately, since under
* time here for the next frame to arrive, before handing
* it to keep_alive processing of the mpm.
*/
- if (no_streams) {
- status = h2_session_read(session, 0, 20);
- }
- else {
- h2_filter_cin_timeout_set(session->cin, session->s->timeout);
- status = h2_session_read(session, 1, 20);
- }
+ status = h2_session_read(session, 0);
if (status == APR_SUCCESS) {
have_read = 1;
/* We wait in smaller increments, using a 1 second timeout.
* That gives us the chance to check for MPMQ_STOPPING often. */
h2_filter_cin_timeout_set(session->cin, apr_time_from_sec(1));
- status = h2_session_read(session, 1, 10);
+ status = h2_session_read(session, 1);
if (status == APR_SUCCESS) {
have_read = 1;
dispatch_event(session, H2_SESSION_EV_DATA_READ, 0, NULL);
case H2_SESSION_ST_REMOTE_SHUTDOWN:
if (nghttp2_session_want_read(session->ngh2)) {
h2_filter_cin_timeout_set(session->cin, session->s->timeout);
- status = h2_session_read(session, 0, 20);
+ status = h2_session_read(session, 0);
if (status == APR_SUCCESS) {
have_read = 1;
dispatch_event(session, H2_SESSION_EV_DATA_READ, 0, NULL);