diff options
author | Stefan Eissing <icing@apache.org> | 2017-07-30 13:57:35 +0200 |
---|---|---|
committer | Stefan Eissing <icing@apache.org> | 2017-07-30 13:57:35 +0200 |
commit | e8a012377cfc2642a9ae6105adeb1935dfdac09e (patch) | |
tree | 04ed0965686e3248d960018f41778219d5f20f6d /modules/http2/h2_task.c | |
parent | Follow up to r1803396: CHANGES entry. (diff) | |
download | apache2-e8a012377cfc2642a9ae6105adeb1935dfdac09e.tar.xz apache2-e8a012377cfc2642a9ae6105adeb1935dfdac09e.zip |
mod_http2: version bump, partial fix for stream response getting stuck, see https://github.com/icing/mod_h2/issues/143
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1803420 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'modules/http2/h2_task.c')
-rw-r--r-- | modules/http2/h2_task.c | 67 |
1 files changed, 41 insertions, 26 deletions
diff --git a/modules/http2/h2_task.c b/modules/http2/h2_task.c index 1ef0d9a887..2ab4145586 100644 --- a/modules/http2/h2_task.c +++ b/modules/http2/h2_task.c @@ -129,7 +129,7 @@ static apr_status_t slave_out(h2_task *task, ap_filter_t* f, apr_bucket_brigade* bb) { apr_bucket *b; - apr_status_t status = APR_SUCCESS; + apr_status_t rv = APR_SUCCESS; int flush = 0, blocking; if (task->frozen) { @@ -148,17 +148,16 @@ static apr_status_t slave_out(h2_task *task, ap_filter_t* f, return APR_SUCCESS; } +send: /* we send block once we opened the output, so someone is there * reading it *and* the task is not assigned to a h2_req_engine */ blocking = (!task->assigned && task->output.opened); - if (!task->output.opened) { - for (b = APR_BRIGADE_FIRST(bb); - b != APR_BRIGADE_SENTINEL(bb); - b = APR_BUCKET_NEXT(b)) { - if (APR_BUCKET_IS_FLUSH(b)) { - flush = 1; - break; - } + for (b = APR_BRIGADE_FIRST(bb); + b != APR_BRIGADE_SENTINEL(bb); + b = APR_BUCKET_NEXT(b)) { + if (APR_BUCKET_IS_FLUSH(b) || APR_BUCKET_IS_EOS(b) || AP_BUCKET_IS_EOR(b)) { + flush = 1; + break; } } @@ -166,32 +165,48 @@ static apr_status_t slave_out(h2_task *task, ap_filter_t* f, /* still have data buffered from previous attempt. * setaside and append new data and try to pass the complete data */ if (!APR_BRIGADE_EMPTY(bb)) { - status = ap_save_brigade(f, &task->output.bb, &bb, task->pool); + if (APR_SUCCESS != (rv = ap_save_brigade(f, &task->output.bb, &bb, task->pool))) { + goto out; + } } - if (status == APR_SUCCESS) { - status = send_out(task, task->output.bb, blocking); - } + rv = send_out(task, task->output.bb, blocking); } else { - /* no data buffered here, try to pass the brigade directly */ - status = send_out(task, bb, blocking); - if (status == APR_SUCCESS && !APR_BRIGADE_EMPTY(bb)) { - /* could not write all, buffer the rest */ - ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, task->c, APLOGNO(03405) - "h2_slave_out(%s): saving brigade", - task->id); - status = ap_save_brigade(f, &task->output.bb, &bb, task->pool); - flush = 1; + /* no data buffered previously, pass brigade directly */ + rv = send_out(task, bb, blocking); + + if (APR_SUCCESS == rv && !APR_BRIGADE_EMPTY(bb)) { + /* output refused to buffer it all, time to open? */ + if (!task->output.opened && APR_SUCCESS == (rv = open_output(task))) { + /* Make another attempt to send the data. With the output open, + * the call might be blocking and send all data, so we do not need + * to save the brigade */ + goto send; + } + else if (blocking && flush) { + /* Need to keep on doing this. */ + goto send; + } + + if (APR_SUCCESS == rv) { + /* could not write all, buffer the rest */ + ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, task->c, APLOGNO(03405) + "h2_slave_out(%s): saving brigade", task->id); + ap_assert(NULL); + rv = ap_save_brigade(f, &task->output.bb, &bb, task->pool); + flush = 1; + } } } - if (status == APR_SUCCESS && !task->output.opened && flush) { + if (APR_SUCCESS == rv && !task->output.opened && flush) { /* got a flush or could not write all, time to tell someone to read */ - status = open_output(task); + rv = open_output(task); } - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, status, task->c, +out: + ap_log_cerror(APLOG_MARK, APLOG_TRACE2, rv, task->c, "h2_slave_out(%s): slave_out leave", task->id); - return status; + return rv; } static apr_status_t output_finish(h2_task *task) |