You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by ic...@apache.org on 2016/10/03 12:57:47 UTC

svn commit: r1763163 [2/3] - in /httpd/httpd/branches/2.4.x: ./ modules/http2/

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_from_h1.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_from_h1.h?rev=1763163&r1=1763162&r2=1763163&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_from_h1.h (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_from_h1.h Mon Oct  3 12:57:47 2016
@@ -30,44 +30,18 @@
  * we need to have all handlers and filters involved in request/response
  * processing, so this seems to be the way for now.
  */
+struct h2_headers;
+struct h2_task;
 
-typedef enum {
-    H2_RESP_ST_STATUS_LINE, /* parsing http/1 status line */
-    H2_RESP_ST_HEADERS,     /* parsing http/1 response headers */
-    H2_RESP_ST_BODY,        /* transferring response body */
-    H2_RESP_ST_DONE         /* complete response converted */
-} h2_from_h1_state_t;
+apr_status_t h2_headers_output_filter(ap_filter_t *f, apr_bucket_brigade *bb);
 
-struct h2_response;
+apr_status_t h2_filter_request_in(ap_filter_t* f,
+                                  apr_bucket_brigade* brigade,
+                                  ap_input_mode_t mode,
+                                  apr_read_type_e block,
+                                  apr_off_t readbytes);
 
-typedef struct h2_from_h1 h2_from_h1;
-
-struct h2_from_h1 {
-    int stream_id;
-    h2_from_h1_state_t state;
-    apr_pool_t *pool;
-    apr_bucket_brigade *bb;
-    
-    apr_off_t content_length;
-    int chunked;
-    
-    int http_status;
-    apr_array_header_t *hlines;
-    
-    struct h2_response *response;
-};
-
-
-h2_from_h1 *h2_from_h1_create(int stream_id, apr_pool_t *pool);
-
-apr_status_t h2_from_h1_read_response(h2_from_h1 *from_h1,
-                                      ap_filter_t* f, apr_bucket_brigade* bb);
-
-struct h2_response *h2_from_h1_get_response(h2_from_h1 *from_h1);
-
-apr_status_t h2_response_output_filter(ap_filter_t *f, apr_bucket_brigade *bb);
-
-apr_status_t h2_response_trailers_filter(ap_filter_t *f, apr_bucket_brigade *bb);
+apr_status_t h2_filter_trailers_out(ap_filter_t *f, apr_bucket_brigade *bb);
 
 void h2_from_h1_set_basic_http_header(apr_table_t *headers, request_rec *r,
                                       apr_pool_t *pool);

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_h2.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_h2.c?rev=1763163&r1=1763162&r2=1763163&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_h2.c (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_h2.c Mon Oct  3 12:57:47 2016
@@ -32,12 +32,15 @@
 #include "mod_http2.h"
 #include "h2_private.h"
 
+#include "h2_bucket_beam.h"
 #include "h2_stream.h"
 #include "h2_task.h"
 #include "h2_config.h"
 #include "h2_ctx.h"
 #include "h2_conn.h"
+#include "h2_filter.h"
 #include "h2_request.h"
+#include "h2_headers.h"
 #include "h2_session.h"
 #include "h2_util.h"
 #include "h2_h2.h"
@@ -569,6 +572,10 @@ void h2_h2_register_hooks(void)
      */
     ap_hook_post_read_request(h2_h2_post_read_req, NULL, NULL, APR_HOOK_REALLY_FIRST);
     ap_hook_fixups(h2_h2_late_fixups, NULL, NULL, APR_HOOK_LAST);
+
+    /* special bucket type transfer through a h2_bucket_beam */
+    ap_hook_beam_bucket(h2_bucket_observer_beam, NULL, NULL, APR_HOOK_MIDDLE);
+    ap_hook_beam_bucket(h2_bucket_headers_beam, NULL, NULL, APR_HOOK_MIDDLE);
 }
 
 int h2_h2_process_conn(conn_rec* c)
@@ -684,30 +691,23 @@ static int h2_h2_post_read_req(request_r
          * that we manipulate filters only once. */
         if (task && !task->filters_set) {
             ap_filter_t *f;
+            ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r, "adding request filters");
 
-            /* setup the correct output filters to process the response
-             * on the proper mod_http2 way. */
-            ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r, "adding task output filter");
-            if (task->ser_headers) {
-                ap_add_output_filter("H1_TO_H2_RESP", task, r, r->connection);
-            }
-            else {
-                /* replace the core http filter that formats response headers
-                 * in HTTP/1 with our own that collects status and headers */
-                ap_remove_output_filter_byhandle(r->output_filters, "HTTP_HEADER");
-                ap_add_output_filter("H2_RESPONSE", task, r, r->connection);
-            }
+            /* setup the correct filters to process the request for h2 */
+            ap_add_input_filter("H2_REQUEST", task, r, r->connection);
+            
+            /* replace the core http filter that formats response headers
+             * in HTTP/1 with our own that collects status and headers */
+            ap_remove_output_filter_byhandle(r->output_filters, "HTTP_HEADER");
+            ap_add_output_filter("H2_RESPONSE", task, r, r->connection);
             
-            /* trailers processing. Incoming trailers are added to this
-             * request via our h2 input filter, outgoing trailers
-             * in a special h2 out filter. */
             for (f = r->input_filters; f; f = f->next) {
-                if (!strcmp("H2_TO_H1", f->frec->name)) {
+                if (!strcmp("H2_SLAVE_IN", f->frec->name)) {
                     f->r = r;
                     break;
                 }
             }
-            ap_add_output_filter("H2_TRAILERS", task, r, r->connection);
+            ap_add_output_filter("H2_TRAILERS_OUT", task, r, r->connection);
             task->filters_set = 1;
         }
     }

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_mplx.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_mplx.c?rev=1763163&r1=1763162&r2=1763163&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_mplx.c (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_mplx.c Mon Oct  3 12:57:47 2016
@@ -28,13 +28,13 @@
 
 #include "mod_http2.h"
 
+#include "h2.h"
 #include "h2_private.h"
 #include "h2_bucket_beam.h"
 #include "h2_config.h"
 #include "h2_conn.h"
 #include "h2_ctx.h"
 #include "h2_h2.h"
-#include "h2_response.h"
 #include "h2_mplx.h"
 #include "h2_ngn_shed.h"
 #include "h2_request.h"
@@ -45,7 +45,7 @@
 #include "h2_util.h"
 
 
-static void h2_beam_log(h2_bucket_beam *beam, int id, const char *msg, 
+static void h2_beam_log(h2_bucket_beam *beam, apr_uint32_t id, const char *msg, 
                         conn_rec *c, int level)
 {
     if (beam && APLOG_C_IS_LEVEL(c,level)) {
@@ -297,7 +297,6 @@ h2_mplx *h2_mplx_create(conn_rec *c, apr
         m->spurge = h2_ihash_create(m->pool, offsetof(h2_stream,id));
         m->q = h2_iq_create(m->pool, m->max_streams);
         m->sready = h2_ihash_create(m->pool, offsetof(h2_stream,id));
-        m->sresume = h2_ihash_create(m->pool, offsetof(h2_stream,id));
         m->tasks = h2_ihash_create(m->pool, offsetof(h2_task,stream_id));
 
         m->stream_timeout = stream_timeout;
@@ -444,7 +443,6 @@ static void stream_done(h2_mplx *m, h2_s
      */
     h2_iq_remove(m->q, stream->id);
     h2_ihash_remove(m->sready, stream->id);
-    h2_ihash_remove(m->sresume, stream->id);
     h2_ihash_remove(m->streams, stream->id);
     if (stream->input) {
         m->tx_handles_reserved += h2_beam_get_files_beamed(stream->input);
@@ -512,16 +510,14 @@ static int task_print(void *ctx, void *v
     h2_mplx *m = ctx;
     h2_task *task = val;
 
-    if (task && task->request) {
+    if (task) {
         h2_stream *stream = h2_ihash_get(m->streams, task->stream_id);
 
         ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, m->c, /* NO APLOGNO */
-                      "->03198: h2_stream(%s): %s %s %s -> %s %d"
+                      "->03198: h2_stream(%s): %s %s %s"
                       "[orph=%d/started=%d/done=%d/frozen=%d]", 
                       task->id, task->request->method, 
                       task->request->authority, task->request->path,
-                      task->response? "http" : (task->rst_error? "reset" : "?"),
-                      task->response? task->response->http_status : task->rst_error,
                       (stream? 0 : 1), task->worker_started, 
                       task->worker_done, task->frozen);
     }
@@ -545,7 +541,7 @@ static int task_abort_connection(void *c
     if (task->input.beam) {
         h2_beam_abort(task->input.beam);
     }
-    if (task->worker_started && !task->worker_done && task->output.beam) {
+    if (task->output.beam) {
         h2_beam_abort(task->output.beam);
     }
     return 1;
@@ -556,9 +552,9 @@ static int report_stream_iter(void *ctx,
     h2_stream *stream = val;
     ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, m->c,
                   "h2_mplx(%ld-%d): exists, started=%d, scheduled=%d, "
-                  "submitted=%d, suspended=%d", 
+                  "ready=%d", 
                   m->id, stream->id, stream->started, stream->scheduled,
-                  stream->submitted, stream->suspended);
+                  h2_stream_is_ready(stream));
     return 1;
 }
 
@@ -575,9 +571,8 @@ apr_status_t h2_mplx_release_and_join(h2
         if (!h2_ihash_empty(m->streams) && APLOGctrace1(m->c)) {
             ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, m->c,
                           "h2_mplx(%ld): release_join with %d streams open, "
-                          "%d streams resume, %d streams ready, %d tasks", 
+                          "%d streams ready, %d tasks", 
                           m->id, (int)h2_ihash_count(m->streams),
-                          (int)h2_ihash_count(m->sresume), 
                           (int)h2_ihash_count(m->sready), 
                           (int)h2_ihash_count(m->tasks));
             h2_ihash_iter(m->streams, report_stream_iter, m);
@@ -707,6 +702,19 @@ apr_status_t h2_mplx_stream_done(h2_mplx
     return status;
 }
 
+h2_stream *h2_mplx_stream_get(h2_mplx *m, apr_uint32_t id)
+{
+    h2_stream *s = NULL;
+    int acquired;
+    
+    AP_DEBUG_ASSERT(m);
+    if ((enter_mutex(m, &acquired)) == APR_SUCCESS) {
+        s = h2_ihash_get(m->streams, id);
+        leave_mutex(m, acquired);
+    }
+    return s;
+}
+
 void h2_mplx_set_consumed_cb(h2_mplx *m, h2_mplx_consumed_cb *cb, void *ctx)
 {
     m->input_consumed = cb;
@@ -730,47 +738,47 @@ static void output_produced(void *ctx, h
     }
 }
 
-static apr_status_t out_open(h2_mplx *m, int stream_id, h2_response *response)
+static apr_status_t out_open(h2_mplx *m, int stream_id, h2_bucket_beam *beam)
 {
     apr_status_t status = APR_SUCCESS;
     h2_task *task = h2_ihash_get(m->tasks, stream_id);
     h2_stream *stream = h2_ihash_get(m->streams, stream_id);
+    apr_size_t beamed_count;
     
     if (!task || !stream) {
         return APR_ECONNABORTED;
     }
     
-    status = h2_task_add_response(task, response);
     ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, m->c,
-                  "h2_mplx(%s): add response: %d, rst=%d",
-                  task->id, response->http_status, response->rst_error);
-    if (status != APR_SUCCESS) {
-        return status;
-    }
-    
-    if (task->output.beam && !task->output.opened) {
-        h2_beam_buffer_size_set(task->output.beam, m->stream_max_mem);
-        h2_beam_timeout_set(task->output.beam, m->stream_timeout);
-        h2_beam_on_consumed(task->output.beam, stream_output_consumed, task);
-        h2_beam_on_produced(task->output.beam, output_produced, m);
-        m->tx_handles_reserved -= h2_beam_get_files_beamed(task->output.beam);
+                  "h2_mplx(%s): out open", task->id);
+                      
+    if (!stream->output) {
+        h2_beam_buffer_size_set(beam, m->stream_max_mem);
+        h2_beam_timeout_set(beam, m->stream_timeout);
+        h2_beam_on_consumed(beam, stream_output_consumed, task);
+        h2_beam_on_produced(beam, output_produced, m);
+        beamed_count = h2_beam_get_files_beamed(beam);
+        if (m->tx_handles_reserved >= beamed_count) {
+            m->tx_handles_reserved -= beamed_count;
+        }
+        else {
+            m->tx_handles_reserved = 0;
+        }
         if (!task->output.copy_files) {
-            h2_beam_on_file_beam(task->output.beam, can_beam_file, m);
+            h2_beam_on_file_beam(beam, can_beam_file, m);
         }
-        h2_beam_mutex_set(task->output.beam, beam_enter, task->cond, m);
-        task->output.opened = 1;
+        h2_beam_mutex_set(beam, beam_enter, task->cond, m);
+        stream->output = beam;
     }
     
-    if (response && response->http_status < 300) {
-        /* we might see some file buckets in the output, see
-         * if we have enough handles reserved. */
-        check_tx_reservation(m);
-    }
-    have_out_data_for(m, stream, 1);
+    /* we might see some file buckets in the output, see
+     * if we have enough handles reserved. */
+    check_tx_reservation(m);
+    have_out_data_for(m, stream, 0);
     return status;
 }
 
-apr_status_t h2_mplx_out_open(h2_mplx *m, int stream_id, h2_response *response)
+apr_status_t h2_mplx_out_open(h2_mplx *m, int stream_id, h2_bucket_beam *beam)
 {
     apr_status_t status;
     int acquired;
@@ -781,7 +789,7 @@ apr_status_t h2_mplx_out_open(h2_mplx *m
             status = APR_ECONNABORTED;
         }
         else {
-            status = out_open(m, stream_id, response);
+            status = out_open(m, stream_id, beam);
         }
         leave_mutex(m, acquired);
     }
@@ -802,16 +810,6 @@ static apr_status_t out_close(h2_mplx *m
         return APR_ECONNABORTED;
     }
 
-    if (!task->response && !task->rst_error) {
-        /* In case a close comes before a response was created,
-         * insert an error one so that our streams can properly reset.
-         */
-        h2_response *r = h2_response_die(task->stream_id, 500, 
-                                         task->request, m->pool);
-        status = out_open(m, task->stream_id, r);
-        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, m->c, APLOGNO(03393)
-                      "h2_mplx(%s): close, no response, no rst", task->id);
-    }
     ap_log_cerror(APLOG_MARK, APLOG_TRACE2, status, m->c,
                   "h2_mplx(%s): close", task->id);
     if (task->output.beam) {
@@ -835,7 +833,7 @@ apr_status_t h2_mplx_out_trywait(h2_mplx
         if (m->aborted) {
             status = APR_ECONNABORTED;
         }
-        else if (!h2_ihash_empty(m->sready) || !h2_ihash_empty(m->sresume)) {
+        else if (!h2_ihash_empty(m->sready)) {
             status = APR_SUCCESS;
         }
         else {
@@ -856,13 +854,10 @@ apr_status_t h2_mplx_out_trywait(h2_mplx
 
 static void have_out_data_for(h2_mplx *m, h2_stream *stream, int response)
 {
-    h2_ihash_t *set;
     ap_assert(m);
     ap_assert(stream);
-    
-    set = response?  m->sready : m->sresume;
-    if (!h2_ihash_get(set, stream->id)) {
-        h2_ihash_add(set, stream);
+    if (!h2_ihash_get(m->sready, stream->id)) {
+        h2_ihash_add(m->sready, stream);
         if (m->added_output) {
             apr_thread_cond_signal(m->added_output);
         }
@@ -903,25 +898,20 @@ apr_status_t h2_mplx_process(h2_mplx *m,
         }
         else {
             h2_ihash_add(m->streams, stream);
-            if (stream->response) {
-                /* already have a respone, schedule for submit */
+            if (h2_stream_is_ready(stream)) {
                 h2_ihash_add(m->sready, stream);
             }
             else {
-                h2_beam_create(&stream->input, stream->pool, stream->id, 
-                               "input", 0);
                 if (!m->need_registration) {
                     m->need_registration = h2_iq_empty(m->q);
                 }
                 if (m->workers_busy < m->workers_max) {
                     do_registration = m->need_registration;
                 }
-                h2_iq_add(m->q, stream->id, cmp, ctx);
-                
-                ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, m->c,
-                              "h2_mplx(%ld-%d): process, body=%d", 
-                              m->c->id, stream->id, stream->request->body);
+                h2_iq_add(m->q, stream->id, cmp, ctx);                
             }
+            ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, m->c,
+                          "h2_mplx(%ld-%d): process", m->c->id, stream->id);
         }
         leave_mutex(m, acquired);
     }
@@ -932,7 +922,7 @@ apr_status_t h2_mplx_process(h2_mplx *m,
     return status;
 }
 
-static h2_task *pop_task(h2_mplx *m)
+static h2_task *next_stream_task(h2_mplx *m)
 {
     h2_task *task = NULL;
     h2_stream *stream;
@@ -950,13 +940,13 @@ static h2_task *pop_task(h2_mplx *m)
                 slave = *pslave;
             }
             else {
-                slave = h2_slave_create(m->c, m->pool, NULL);
+                slave = h2_slave_create(m->c, stream->id, m->pool, NULL);
                 new_conn = 1;
             }
             
             slave->sbh = m->c->sbh;
             slave->aborted = 0;
-            task = h2_task_create(slave, stream->request, stream->input, m);
+            task = h2_task_create(slave, stream->id, stream->request, stream->input, m);
             h2_ihash_add(m->tasks, task);
             
             m->c->keepalives++;
@@ -996,7 +986,7 @@ h2_task *h2_mplx_pop_task(h2_mplx *m, in
             *has_more = 0;
         }
         else {
-            task = pop_task(m);
+            task = next_stream_task(m);
             *has_more = !h2_iq_empty(m->q);
         }
         
@@ -1015,9 +1005,6 @@ static void task_done(h2_mplx *m, h2_tas
          * and the original worker has finished. That means the 
          * engine may start processing now. */
         h2_task_thaw(task);
-        /* we do not want the task to block on writing response
-         * bodies into the mplx. */
-        h2_task_set_io_blocking(task, 0);
         apr_thread_cond_broadcast(m->task_thawed);
         return;
     }
@@ -1134,7 +1121,7 @@ void h2_mplx_task_done(h2_mplx *m, h2_ta
         --m->workers_busy;
         if (ptask) {
             /* caller wants another task */
-            *ptask = pop_task(m);
+            *ptask = next_stream_task(m);
         }
         leave_mutex(m, acquired);
     }
@@ -1147,15 +1134,19 @@ void h2_mplx_task_done(h2_mplx *m, h2_ta
 static int latest_repeatable_unsubmitted_iter(void *data, void *val)
 {
     task_iter_ctx *ctx = data;
+    h2_stream *stream;
     h2_task *task = val;
     if (!task->worker_done && h2_task_can_redo(task) 
         && !h2_ihash_get(ctx->m->redo_tasks, task->stream_id)) {
-        /* this task occupies a worker, the response has not been submitted yet,
-         * not been cancelled and it is a repeatable request
-         * -> it can be re-scheduled later */
-        if (!ctx->task || ctx->task->started_at < task->started_at) {
-            /* we did not have one or this one was started later */
-            ctx->task = task;
+        stream = h2_ihash_get(ctx->m->streams, task->stream_id);
+        if (stream && !h2_stream_is_ready(stream)) {
+            /* this task occupies a worker, the response has not been submitted 
+             * yet, not been cancelled and it is a repeatable request
+             * -> it can be re-scheduled later */
+            if (!ctx->task || ctx->task->started_at < task->started_at) {
+                /* we did not have one or this one was started later */
+                ctx->task = task;
+            }
         }
     }
     return 1;
@@ -1322,13 +1313,12 @@ apr_status_t h2_mplx_req_engine_push(con
         return APR_ECONNABORTED;
     }
     m = task->mplx;
-    task->r = r;
     
     if ((status = enter_mutex(m, &acquired)) == APR_SUCCESS) {
         h2_stream *stream = h2_ihash_get(m->streams, task->stream_id);
         
         if (stream) {
-            status = h2_ngn_shed_push_task(m->ngn_shed, ngn_type, task, einit);
+            status = h2_ngn_shed_push_request(m->ngn_shed, ngn_type, r, einit);
         }
         else {
             status = APR_ECONNABORTED;
@@ -1346,7 +1336,6 @@ apr_status_t h2_mplx_req_engine_pull(h2_
     h2_ngn_shed *shed = h2_ngn_shed_get_shed(ngn);
     h2_mplx *m = h2_ngn_shed_get_ctx(shed);
     apr_status_t status;
-    h2_task *task = NULL;
     int acquired;
     
     if ((status = enter_mutex(m, &acquired)) == APR_SUCCESS) {
@@ -1361,22 +1350,21 @@ apr_status_t h2_mplx_req_engine_pull(h2_
              * had and, if not, wait a short while before doing the
              * blocking, and if unsuccessful, terminating read.
              */
-            status = h2_ngn_shed_pull_task(shed, ngn, capacity, 1, &task);
+            status = h2_ngn_shed_pull_request(shed, ngn, capacity, 1, pr);
             if (APR_STATUS_IS_EAGAIN(status)) {
                 ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, m->c,
                               "h2_mplx(%ld): start block engine pull", m->id);
                 apr_thread_cond_timedwait(m->task_thawed, m->lock, 
                                           apr_time_from_msec(20));
-                status = h2_ngn_shed_pull_task(shed, ngn, capacity, 1, &task);
+                status = h2_ngn_shed_pull_request(shed, ngn, capacity, 1, pr);
             }
         }
         else {
-            status = h2_ngn_shed_pull_task(shed, ngn, capacity,
-                                           want_shutdown, &task);
+            status = h2_ngn_shed_pull_request(shed, ngn, capacity,
+                                              want_shutdown, pr);
         }
         leave_mutex(m, acquired);
     }
-    *pr = task? task->r : NULL;
     return status;
 }
  
@@ -1416,14 +1404,12 @@ static int update_window(void *ctx, void
 
 apr_status_t h2_mplx_dispatch_master_events(h2_mplx *m, 
                                             stream_ev_callback *on_resume, 
-                                            stream_ev_callback *on_response, 
                                             void *on_ctx)
 {
     apr_status_t status;
     int acquired;
     int streams[32];
     h2_stream *stream;
-    h2_task *task;
     size_t i, n;
     
     AP_DEBUG_ASSERT(m);
@@ -1433,8 +1419,7 @@ apr_status_t h2_mplx_dispatch_master_eve
                       
         /* update input windows for streams */
         h2_ihash_iter(m->streams, update_window, m);
-
-        if (on_response && !h2_ihash_empty(m->sready)) {
+        if (on_resume && !h2_ihash_empty(m->sready)) {
             n = h2_ihash_ishift(m->sready, streams, H2_ALEN(streams));
             for (i = 0; i < n; ++i) {
                 stream = h2_ihash_get(m->streams, streams[i]);
@@ -1442,53 +1427,9 @@ apr_status_t h2_mplx_dispatch_master_eve
                     continue;
                 }
                 ap_log_cerror(APLOG_MARK, APLOG_TRACE3, 0, m->c, 
-                              "h2_mplx(%ld-%d): on_response", 
-                              m->id, stream->id);
-                task = h2_ihash_get(m->tasks, stream->id);
-                if (task) {
-                    task->response_sent = 1;
-                    if (task->rst_error) {
-                        h2_stream_rst(stream, task->rst_error);
-                    }
-                    else {
-                        AP_DEBUG_ASSERT(task->response);
-                        status = h2_stream_add_response(stream, task->response, 
-                                                        task->output.beam);
-                        if (status != APR_SUCCESS) {
-                            h2_stream_rst(stream, H2_ERR_INTERNAL_ERROR);
-                        }
-                        if (!h2_response_get_final(task->response)) {
-                            /* the final response needs still to arrive */
-                            task->response = NULL;
-                        }
-                    }
-                }
-                else {
-                    /* We have the stream ready without a task. This happens
-                     * when we fail streams early. A response should already
-                     * be present.  */
-                    AP_DEBUG_ASSERT(stream->response || stream->rst_error);
-                }
-                status = on_response(on_ctx, stream->id);
-            }
-        }
-
-        if (on_resume && !h2_ihash_empty(m->sresume)) {
-            n = h2_ihash_ishift(m->sresume, streams, H2_ALEN(streams));
-            for (i = 0; i < n; ++i) {
-                stream = h2_ihash_get(m->streams, streams[i]);
-                if (!stream) {
-                    continue;
-                }
-                ap_log_cerror(APLOG_MARK, APLOG_TRACE3, 0, m->c, 
                               "h2_mplx(%ld-%d): on_resume", 
                               m->id, stream->id);
-                task = h2_ihash_get(m->tasks, stream->id);
-                if (task && task->rst_error) {
-                    h2_stream_rst(stream, task->rst_error);
-                }
-                h2_stream_set_suspended(stream, 0);
-                status = on_resume(on_ctx, stream->id);
+                on_resume(on_ctx, stream->id);
             }
         }
         
@@ -1497,42 +1438,36 @@ apr_status_t h2_mplx_dispatch_master_eve
     return status;
 }
 
-apr_status_t h2_mplx_suspend_stream(h2_mplx *m, int stream_id)
+apr_status_t h2_mplx_keep_active(h2_mplx *m, apr_uint32_t stream_id)
 {
     apr_status_t status;
-    h2_stream *stream;
-    h2_task *task;
     int acquired;
     
     AP_DEBUG_ASSERT(m);
     if ((status = enter_mutex(m, &acquired)) == APR_SUCCESS) {
-        stream = h2_ihash_get(m->streams, stream_id);
-        if (stream && !h2_ihash_get(m->sresume, stream->id)) {
-            /* not marked for resume again already */
-            h2_stream_set_suspended(stream, 1);
-            task = h2_ihash_get(m->tasks, stream->id);
-            if (stream->started && (!task || task->worker_done)) {
-                h2_ihash_add(m->sresume, stream);
-            }
+        h2_stream *s = h2_ihash_get(m->streams, stream_id);
+        if (s) {
+            h2_ihash_add(m->sready, s);
         }
         leave_mutex(m, acquired);
     }
     return status;
 }
 
-int h2_mplx_is_busy(h2_mplx *m)
+int h2_mplx_awaits_data(h2_mplx *m)
 {
     apr_status_t status;
-    int acquired, busy = 1;
-    
+    int acquired, waiting = 1;
+     
+    AP_DEBUG_ASSERT(m);
     if ((status = enter_mutex(m, &acquired)) == APR_SUCCESS) {
         if (h2_ihash_empty(m->streams)) {
-            busy = 0;
+            waiting = 0;
         }
         if (h2_iq_empty(m->q) && h2_ihash_empty(m->tasks)) {
-            busy = 0;
+            waiting = 0;
         }
         leave_mutex(m, acquired);
     }
-    return busy;
+    return waiting;
 }

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_mplx.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_mplx.h?rev=1763163&r1=1763162&r2=1763163&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_mplx.h (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_mplx.h Mon Oct  3 12:57:47 2016
@@ -40,7 +40,6 @@ struct apr_thread_cond_t;
 struct h2_bucket_beam;
 struct h2_config;
 struct h2_ihash_t;
-struct h2_response;
 struct h2_task;
 struct h2_stream;
 struct h2_request;
@@ -76,9 +75,8 @@ struct h2_mplx {
     struct h2_ihash_t *spurge;      /* all streams done, ready for destroy */
 
     struct h2_iqueue *q;            /* all stream ids that need to be started */
-    struct h2_ihash_t *sready;      /* all streams ready for response */
-    struct h2_ihash_t *sresume;     /* all streams that can be resumed */
-    
+    struct h2_ihash_t *sready;      /* all streams ready for output */
+        
     struct h2_ihash_t *tasks;       /* all tasks started and not destroyed */
     struct h2_ihash_t *redo_tasks;  /* all tasks that need to be redone */
     
@@ -105,8 +103,8 @@ struct h2_mplx {
     apr_array_header_t *spare_slaves; /* spare slave connections */
     
     struct h2_workers *workers;
-    int tx_handles_reserved;
-    apr_size_t tx_chunk_size;
+    apr_uint32_t tx_handles_reserved;
+    apr_uint32_t tx_chunk_size;
     
     h2_mplx_consumed_cb *input_consumed;
     void *input_consumed_ctx;
@@ -164,6 +162,8 @@ int h2_mplx_is_busy(h2_mplx *m);
  * IO lifetime of streams.
  ******************************************************************************/
 
+struct h2_stream *h2_mplx_stream_get(h2_mplx *m, apr_uint32_t id);
+
 /**
  * Notifies mplx that a stream has finished processing.
  * 
@@ -181,6 +181,8 @@ apr_status_t h2_mplx_stream_done(h2_mplx
 apr_status_t h2_mplx_out_trywait(h2_mplx *m, apr_interval_time_t timeout,
                                  struct apr_thread_cond_t *iowait);
 
+apr_status_t h2_mplx_keep_active(h2_mplx *m, apr_uint32_t stream_id);
+
 /*******************************************************************************
  * Stream processing.
  ******************************************************************************/
@@ -222,16 +224,15 @@ typedef apr_status_t stream_ev_callback(
 
 /**
  * Dispatch events for the master connection, such as
- * - resume: new output data has arrived for a suspended stream
- * - response: the response for a stream is ready
+ ± @param m the multiplexer
+ * @param on_resume new output data has arrived for a suspended stream 
+ * @param ctx user supplied argument to invocation.
  */
 apr_status_t h2_mplx_dispatch_master_events(h2_mplx *m, 
                                             stream_ev_callback *on_resume, 
-                                            stream_ev_callback *on_response, 
                                             void *ctx);
 
-apr_status_t h2_mplx_suspend_stream(h2_mplx *m, int stream_id);
-
+int h2_mplx_awaits_data(h2_mplx *m);
 
 typedef int h2_mplx_stream_cb(struct h2_stream *s, void *ctx);
 
@@ -245,7 +246,7 @@ apr_status_t h2_mplx_stream_do(h2_mplx *
  * Opens the output for the given stream with the specified response.
  */
 apr_status_t h2_mplx_out_open(h2_mplx *mplx, int stream_id,
-                              struct h2_response *response);
+                              struct h2_bucket_beam *beam);
 
 /*******************************************************************************
  * h2_mplx list Manipulation.

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_ngn_shed.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_ngn_shed.c?rev=1763163&r1=1763162&r2=1763163&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_ngn_shed.c (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_ngn_shed.c Mon Oct  3 12:57:47 2016
@@ -35,7 +35,6 @@
 #include "h2_ctx.h"
 #include "h2_h2.h"
 #include "h2_mplx.h"
-#include "h2_response.h"
 #include "h2_request.h"
 #include "h2_task.h"
 #include "h2_util.h"
@@ -46,6 +45,7 @@ typedef struct h2_ngn_entry h2_ngn_entry
 struct h2_ngn_entry {
     APR_RING_ENTRY(h2_ngn_entry) link;
     h2_task *task;
+    request_rec *r;
 };
 
 #define H2_NGN_ENTRY_NEXT(e)	APR_RING_NEXT((e), link)
@@ -144,26 +144,28 @@ void h2_ngn_shed_abort(h2_ngn_shed *shed
     shed->aborted = 1;
 }
 
-static void ngn_add_task(h2_req_engine *ngn, h2_task *task)
+static void ngn_add_task(h2_req_engine *ngn, h2_task *task, request_rec *r)
 {
     h2_ngn_entry *entry = apr_pcalloc(task->pool, sizeof(*entry));
     APR_RING_ELEM_INIT(entry, link);
     entry->task = task;
+    entry->r = r;
     H2_REQ_ENTRIES_INSERT_TAIL(&ngn->entries, entry);
 }
 
 
-apr_status_t h2_ngn_shed_push_task(h2_ngn_shed *shed, const char *ngn_type, 
-                                   h2_task *task, http2_req_engine_init *einit) 
+apr_status_t h2_ngn_shed_push_request(h2_ngn_shed *shed, const char *ngn_type, 
+                                      request_rec *r, 
+                                      http2_req_engine_init *einit) 
 {
     h2_req_engine *ngn;
+    h2_task *task = h2_ctx_rget_task(r);
 
-    AP_DEBUG_ASSERT(shed);
-    
+    ap_assert(task);
     ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, shed->c,
                   "h2_ngn_shed(%ld): PUSHing request (task=%s)", shed->c->id, 
                   task->id);
-    if (task->ser_headers) {
+    if (task->request->serialize) {
         /* Max compatibility, deny processing of this */
         return APR_EOF;
     }
@@ -184,7 +186,7 @@ apr_status_t h2_ngn_shed_push_task(h2_ng
         if (!h2_task_is_detached(task)) {
             h2_task_freeze(task);
         }
-        ngn_add_task(ngn, task);
+        ngn_add_task(ngn, task, r);
         ngn->no_assigned++;
         return APR_SUCCESS;
     }
@@ -207,7 +209,7 @@ apr_status_t h2_ngn_shed_push_task(h2_ng
         APR_RING_INIT(&newngn->entries, h2_ngn_entry, link);
         
         status = einit(newngn, newngn->id, newngn->type, newngn->pool,
-                       shed->req_buffer_size, task->r, 
+                       shed->req_buffer_size, r,
                        &newngn->out_consumed, &newngn->out_consumed_ctx);
         ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, task->c, APLOGNO(03395)
                       "h2_ngn_shed(%ld): create engine %s (%s)", 
@@ -242,16 +244,16 @@ static h2_ngn_entry *pop_detached(h2_req
     return NULL;
 }
 
-apr_status_t h2_ngn_shed_pull_task(h2_ngn_shed *shed, 
-                                   h2_req_engine *ngn, 
-                                   apr_uint32_t capacity, 
-                                   int want_shutdown,
-                                   h2_task **ptask)
+apr_status_t h2_ngn_shed_pull_request(h2_ngn_shed *shed, 
+                                      h2_req_engine *ngn, 
+                                      apr_uint32_t capacity, 
+                                      int want_shutdown,
+                                      request_rec **pr)
 {   
     h2_ngn_entry *entry;
     
     AP_DEBUG_ASSERT(ngn);
-    *ptask = NULL;
+    *pr = NULL;
     ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, shed->c, APLOGNO(03396)
                   "h2_ngn_shed(%ld): pull task for engine %s, shutdown=%d", 
                   shed->c->id, ngn->id, want_shutdown);
@@ -279,7 +281,7 @@ apr_status_t h2_ngn_shed_pull_task(h2_ng
                       "h2_ngn_shed(%ld): pulled request %s for engine %s", 
                       shed->c->id, entry->task->id, ngn->id);
         ngn->no_live++;
-        *ptask = entry->task;
+        *pr = entry->r;
         entry->task->assigned = ngn;
         /* task will now run in ngn's own thread. Modules like lua
          * seem to require the correct thread set in the conn_rec.

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_ngn_shed.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_ngn_shed.h?rev=1763163&r1=1763162&r2=1763163&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_ngn_shed.h (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_ngn_shed.h Mon Oct  3 12:57:47 2016
@@ -58,13 +58,13 @@ h2_ngn_shed *h2_ngn_shed_get_shed(struct
 
 void h2_ngn_shed_abort(h2_ngn_shed *shed);
 
-apr_status_t h2_ngn_shed_push_task(h2_ngn_shed *shed, const char *ngn_type, 
-                                  struct h2_task *task, 
-                                  h2_shed_ngn_init *init_cb);
+apr_status_t h2_ngn_shed_push_request(h2_ngn_shed *shed, const char *ngn_type, 
+                                      request_rec *r, 
+                                      h2_shed_ngn_init *init_cb);
 
-apr_status_t h2_ngn_shed_pull_task(h2_ngn_shed *shed, h2_req_engine *pub_ngn, 
-                                   apr_uint32_t capacity, 
-                                   int want_shutdown, struct h2_task **ptask);
+apr_status_t h2_ngn_shed_pull_request(h2_ngn_shed *shed, h2_req_engine *pub_ngn, 
+                                      apr_uint32_t capacity, 
+                                      int want_shutdown, request_rec **pr);
 
 apr_status_t h2_ngn_shed_done_task(h2_ngn_shed *shed, 
                                    struct h2_req_engine *ngn, 

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_proxy_util.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_proxy_util.c?rev=1763163&r1=1763162&r2=1763163&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_proxy_util.c (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_proxy_util.c Mon Oct  3 12:57:47 2016
@@ -566,7 +566,6 @@ static h2_request *h2_req_createn(int id
 {
     h2_request *req = apr_pcalloc(pool, sizeof(h2_request));
     
-    req->id             = id;
     req->method         = method;
     req->scheme         = scheme;
     req->authority      = authority;

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_push.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_push.c?rev=1763163&r1=1763162&r2=1763163&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_push.c (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_push.c Mon Oct  3 12:57:47 2016
@@ -34,7 +34,7 @@
 #include "h2_util.h"
 #include "h2_push.h"
 #include "h2_request.h"
-#include "h2_response.h"
+#include "h2_headers.h"
 #include "h2_session.h"
 #include "h2_stream.h"
 
@@ -58,6 +58,7 @@ static const char *policy_str(h2_push_po
 
 typedef struct {
     const h2_request *req;
+    int push_policy;
     apr_pool_t *pool;
     apr_array_header_t *pushes;
     const char *s;
@@ -336,7 +337,7 @@ static int add_push(link_ctx *ctx)
                  */
                 path = apr_uri_unparse(ctx->pool, &uri, APR_URI_UNP_OMITSITEPART);
                 push = apr_pcalloc(ctx->pool, sizeof(*push));
-                switch (ctx->req->push_policy) {
+                switch (ctx->push_policy) {
                     case H2_PUSH_HEAD:
                         method = "HEAD";
                         break;
@@ -346,11 +347,11 @@ static int add_push(link_ctx *ctx)
                 }
                 headers = apr_table_make(ctx->pool, 5);
                 apr_table_do(set_push_header, headers, ctx->req->headers, NULL);
-                req = h2_req_createn(0, ctx->pool, method, ctx->req->scheme,
-                                     ctx->req->authority, path, headers,
-                                     ctx->req->serialize);
+                req = h2_req_create(0, ctx->pool, method, ctx->req->scheme,
+                                    ctx->req->authority, path, headers,
+                                    ctx->req->serialize);
                 /* atm, we do not push on pushes */
-                h2_request_end_headers(req, ctx->pool, 1, 0);
+                h2_request_end_headers(req, ctx->pool, 1);
                 push->req = req;
                 
                 if (!ctx->pushes) {
@@ -427,10 +428,10 @@ static int head_iter(void *ctx, const ch
     return 1;
 }
 
-apr_array_header_t *h2_push_collect(apr_pool_t *p, const h2_request *req, 
-                                    const h2_response *res)
+apr_array_header_t *h2_push_collect(apr_pool_t *p, const h2_request *req,
+                                    int push_policy, const h2_headers *res)
 {
-    if (req && req->push_policy != H2_PUSH_NONE) {
+    if (req && push_policy != H2_PUSH_NONE) {
         /* Collect push candidates from the request/response pair.
          * 
          * One source for pushes are "rel=preload" link headers
@@ -444,11 +445,13 @@ apr_array_header_t *h2_push_collect(apr_
             
             memset(&ctx, 0, sizeof(ctx));
             ctx.req = req;
+            ctx.push_policy = push_policy;
             ctx.pool = p;
             
             apr_table_do(head_iter, &ctx, res->headers, NULL);
             if (ctx.pushes) {
-                apr_table_setn(res->headers, "push-policy", policy_str(req->push_policy));
+                apr_table_setn(res->headers, "push-policy", 
+                               policy_str(push_policy));
             }
             return ctx.pushes;
         }
@@ -681,7 +684,7 @@ apr_array_header_t *h2_push_diary_update
     
 apr_array_header_t *h2_push_collect_update(h2_stream *stream, 
                                            const struct h2_request *req, 
-                                           const struct h2_response *res)
+                                           const struct h2_headers *res)
 {
     h2_session *session = stream->session;
     const char *cache_digest = apr_table_get(req->headers, "Cache-Digest");
@@ -698,7 +701,7 @@ apr_array_header_t *h2_push_collect_upda
                           session->id, cache_digest);
         }
     }
-    pushes = h2_push_collect(stream->pool, req, res);
+    pushes = h2_push_collect(stream->pool, req, stream->push_policy, res);
     return h2_push_diary_update(stream->session, pushes);
 }
 

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_push.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_push.h?rev=1763163&r1=1763162&r2=1763163&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_push.h (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_push.h Mon Oct  3 12:57:47 2016
@@ -18,7 +18,7 @@
 #include "h2.h"
 
 struct h2_request;
-struct h2_response;
+struct h2_headers;
 struct h2_ngheader;
 struct h2_session;
 struct h2_stream;
@@ -38,8 +38,8 @@ typedef void h2_push_digest_calc(h2_push
 
 struct h2_push_diary {
     apr_array_header_t  *entries;
-    apr_size_t           NMax; /* Maximum for N, should size change be necessary */
-    apr_size_t           N;    /* Current maximum number of entries, power of 2 */
+    apr_uint32_t         NMax; /* Maximum for N, should size change be necessary */
+    apr_uint32_t         N;    /* Current maximum number of entries, power of 2 */
     apr_uint64_t         mask; /* mask for relevant bits */
     unsigned int         mask_bits; /* number of relevant bits */
     const char          *authority;
@@ -58,7 +58,8 @@ struct h2_push_diary {
  */
 apr_array_header_t *h2_push_collect(apr_pool_t *p, 
                                     const struct h2_request *req, 
-                                    const struct h2_response *res);
+                                    int push_policy, 
+                                    const struct h2_headers *res);
 
 /**
  * Create a new push diary for the given maximum number of entries.
@@ -81,7 +82,7 @@ apr_array_header_t *h2_push_diary_update
  */
 apr_array_header_t *h2_push_collect_update(struct h2_stream *stream, 
                                            const struct h2_request *req, 
-                                           const struct h2_response *res);
+                                           const struct h2_headers *res);
 /**
  * Get a cache digest as described in 
  * https://datatracker.ietf.org/doc/draft-kazuho-h2-cache-digest/

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_request.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_request.c?rev=1763163&r1=1763162&r2=1763163&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_request.c (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_request.c Mon Oct  3 12:57:47 2016
@@ -30,27 +30,44 @@
 #include <scoreboard.h>
 
 #include "h2_private.h"
+#include "h2_config.h"
 #include "h2_push.h"
 #include "h2_request.h"
 #include "h2_util.h"
 
 
-static apr_status_t inspect_clen(h2_request *req, const char *s)
+typedef struct {
+    apr_table_t *headers;
+    apr_pool_t *pool;
+} h1_ctx;
+
+static int set_h1_header(void *ctx, const char *key, const char *value)
 {
-    char *end;
-    req->content_length = apr_strtoi64(s, &end, 10);
-    return (s == end)? APR_EINVAL : APR_SUCCESS;
+    h1_ctx *x = ctx;
+    size_t klen = strlen(key);
+    if (!h2_req_ignore_header(key, klen)) {
+        h2_headers_add_h1(x->headers, x->pool, key, klen, value, strlen(value));
+    }
+    return 1;
 }
 
-apr_status_t h2_request_rwrite(h2_request *req, apr_pool_t *pool, 
-                               request_rec *r)
+apr_status_t h2_request_rcreate(h2_request **preq, apr_pool_t *pool, 
+                                request_rec *r)
 {
-    apr_status_t status;
-    const char *scheme, *authority;
+    h2_request *req;
+    const char *scheme, *authority, *path;
+    h1_ctx x;
     
+    *preq = NULL;
     scheme = apr_pstrdup(pool, r->parsed_uri.scheme? r->parsed_uri.scheme
               : ap_http_scheme(r));
-    authority = (r->hostname ? apr_pstrdup(pool, r->hostname) : "");
+    authority = apr_pstrdup(pool, r->hostname);
+    path = apr_uri_unparse(pool, &r->parsed_uri, APR_URI_UNP_OMITSITEPART);
+    
+    if (!r->method || !scheme || !r->hostname || !path) {
+        return APR_EINVAL;
+    }
+
     if (!ap_strchr_c(authority, ':') && r->server && r->server->port) {
         apr_port_t defport = apr_uri_port_of_scheme(scheme);
         if (defport != r->server->port) {
@@ -60,11 +77,23 @@ apr_status_t h2_request_rwrite(h2_reques
         }
     }
     
-    status = h2_req_make(req, pool, apr_pstrdup(pool, r->method), scheme, 
-                         authority, apr_uri_unparse(pool, &r->parsed_uri, 
-                                                    APR_URI_UNP_OMITSITEPART),
-                         r->headers_in);
-    return status;
+    req = apr_pcalloc(pool, sizeof(*req));
+    req->method    = apr_pstrdup(pool, r->method);
+    req->scheme    = scheme;
+    req->authority = authority;
+    req->path      = path;
+    req->headers   = apr_table_make(pool, 10);
+    if (r->server) {
+        req->serialize = h2_config_geti(h2_config_sget(r->server), 
+                                        H2_CONF_SER_HEADERS);
+    }
+
+    x.pool = pool;
+    x.headers = req->headers;
+    apr_table_do(set_h1_header, &x, r->headers_in, NULL);
+    
+    *preq = req;
+    return APR_SUCCESS;
 }
 
 apr_status_t h2_request_add_header(h2_request *req, apr_pool_t *pool, 
@@ -82,8 +111,7 @@ apr_status_t h2_request_add_header(h2_re
         if (!apr_is_empty_table(req->headers)) {
             ap_log_perror(APLOG_MARK, APLOG_ERR, 0, pool,
                           APLOGNO(02917) 
-                          "h2_request(%d): pseudo header after request start",
-                          req->id);
+                          "h2_request: pseudo header after request start");
             return APR_EGENERAL;
         }
         
@@ -109,8 +137,8 @@ apr_status_t h2_request_add_header(h2_re
             strncpy(buffer, name, (nlen > 31)? 31 : nlen);
             ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, pool,
                           APLOGNO(02954) 
-                          "h2_request(%d): ignoring unknown pseudo header %s",
-                          req->id, buffer);
+                          "h2_request: ignoring unknown pseudo header %s",
+                          buffer);
         }
     }
     else {
@@ -121,16 +149,10 @@ apr_status_t h2_request_add_header(h2_re
     return status;
 }
 
-apr_status_t h2_request_end_headers(h2_request *req, apr_pool_t *pool, 
-                                    int eos, int push)
+apr_status_t h2_request_end_headers(h2_request *req, apr_pool_t *pool, int eos)
 {
     const char *s;
     
-    if (req->eoh) {
-        /* already done */
-        return APR_SUCCESS;
-    }
-
     /* rfc7540, ch. 8.1.2.3:
      * - if we have :authority, it overrides any Host header 
      * - :authority MUST be ommited when converting h1->h2, so we
@@ -147,18 +169,8 @@ apr_status_t h2_request_end_headers(h2_r
     }
 
     s = apr_table_get(req->headers, "Content-Length");
-    if (s) {
-        if (inspect_clen(req, s) != APR_SUCCESS) {
-            ap_log_perror(APLOG_MARK, APLOG_WARNING, APR_EINVAL, pool,
-                          APLOGNO(02959) 
-                          "h2_request(%d): content-length value not parsed: %s",
-                          req->id, s);
-            return APR_EINVAL;
-        }
-    }
-    else {
+    if (!s) {
         /* no content-length given */
-        req->content_length = -1;
         if (!eos) {
             /* We have not seen a content-length and have no eos,
              * simulate a chunked encoding for our HTTP/1.1 infrastructure,
@@ -168,68 +180,16 @@ apr_status_t h2_request_end_headers(h2_r
             apr_table_mergen(req->headers, "Transfer-Encoding", "chunked");
         }
         else if (apr_table_get(req->headers, "Content-Type")) {
-            /* If we have a content-type, but already see eos, no more
+            /* If we have a content-type, but already seen eos, no more
              * data will come. Signal a zero content length explicitly.
              */
             apr_table_setn(req->headers, "Content-Length", "0");
         }
     }
 
-    req->eoh = 1;
-    h2_push_policy_determine(req, pool, push);
-    
-    /* In the presence of trailers, force behaviour of chunked encoding */
-    s = apr_table_get(req->headers, "Trailer");
-    if (s && s[0]) {
-        req->trailers = apr_table_make(pool, 5);
-        if (!req->chunked) {
-            req->chunked = 1;
-            apr_table_mergen(req->headers, "Transfer-Encoding", "chunked");
-        }
-    }
-    
-    return APR_SUCCESS;
-}
-
-static apr_status_t add_h1_trailer(h2_request *req, apr_pool_t *pool, 
-                                   const char *name, size_t nlen,
-                                   const char *value, size_t vlen)
-{
-    char *hname, *hvalue;
-    
-    if (h2_req_ignore_trailer(name, nlen)) {
-        return APR_SUCCESS;
-    }
-    
-    hname = apr_pstrndup(pool, name, nlen);
-    hvalue = apr_pstrndup(pool, value, vlen);
-    h2_util_camel_case_header(hname, nlen);
-
-    apr_table_mergen(req->trailers, hname, hvalue);
-    
     return APR_SUCCESS;
 }
 
-
-apr_status_t h2_request_add_trailer(h2_request *req, apr_pool_t *pool,
-                                    const char *name, size_t nlen,
-                                    const char *value, size_t vlen)
-{
-    if (!req->trailers) {
-        ap_log_perror(APLOG_MARK, APLOG_DEBUG, APR_EINVAL, pool, APLOGNO(03059)
-                      "h2_request(%d): unanounced trailers",
-                      req->id);
-        return APR_EINVAL;
-    }
-    if (nlen == 0 || name[0] == ':') {
-        ap_log_perror(APLOG_MARK, APLOG_DEBUG, APR_EINVAL, pool, APLOGNO(03060)
-                      "h2_request(%d): pseudo header in trailer",
-                      req->id);
-        return APR_EINVAL;
-    }
-    return add_h1_trailer(req, pool, name, nlen, value, vlen);
-}
-
 h2_request *h2_request_clone(apr_pool_t *p, const h2_request *src)
 {
     h2_request *dst = apr_pmemdup(p, src, sizeof(*dst));
@@ -238,27 +198,24 @@ h2_request *h2_request_clone(apr_pool_t
     dst->authority    = apr_pstrdup(p, src->authority);
     dst->path         = apr_pstrdup(p, src->path);
     dst->headers      = apr_table_clone(p, src->headers);
-    if (src->trailers) {
-        dst->trailers = apr_table_clone(p, src->trailers);
-    }
     return dst;
 }
 
-request_rec *h2_request_create_rec(const h2_request *req, conn_rec *conn)
+request_rec *h2_request_create_rec(const h2_request *req, conn_rec *c)
 {
-    request_rec *r;
-    apr_pool_t *p;
     int access_status = HTTP_OK;    
     const char *expect;
     const char *rpath;
+    apr_pool_t *p;
+    request_rec *r;
 
-    apr_pool_create(&p, conn->pool);
+    apr_pool_create(&p, c->pool);
     apr_pool_tag(p, "request");
     r = apr_pcalloc(p, sizeof(request_rec));
-    AP_READ_REQUEST_ENTRY((intptr_t)r, (uintptr_t)conn);
+    AP_READ_REQUEST_ENTRY((intptr_t)r, (uintptr_t)c);
     r->pool            = p;
-    r->connection      = conn;
-    r->server          = conn->base_server;
+    r->connection      = c;
+    r->server          = c->base_server;
     
     r->user            = NULL;
     r->ap_auth_type    = NULL;
@@ -276,9 +233,9 @@ request_rec *h2_request_create_rec(const
     r->request_config  = ap_create_request_config(r->pool);
     /* Must be set before we run create request hook */
     
-    r->proto_output_filters = conn->output_filters;
+    r->proto_output_filters = c->output_filters;
     r->output_filters  = r->proto_output_filters;
-    r->proto_input_filters = conn->input_filters;
+    r->proto_input_filters = c->input_filters;
     r->input_filters   = r->proto_input_filters;
     ap_run_create_request(r);
     r->per_dir_config  = r->server->lookup_defaults;
@@ -297,10 +254,10 @@ request_rec *h2_request_create_rec(const
      */
     r->used_path_info = AP_REQ_DEFAULT_PATH_INFO;
     
-    r->useragent_addr = conn->client_addr;
-    r->useragent_ip = conn->client_ip;
+    r->useragent_addr = c->client_addr;
+    r->useragent_ip = c->client_ip;
     
-    ap_run_pre_read_request(r, conn);
+    ap_run_pre_read_request(r, c);
     
     /* Time to populate r with the data we have. */
     r->request_time = req->request_time;
@@ -334,7 +291,7 @@ request_rec *h2_request_create_rec(const
         && (expect[0] != '\0')) {
         if (ap_cstr_casecmp(expect, "100-continue") == 0) {
             r->expecting_100 = 1;
-            ap_add_input_filter("H2_CONTINUE", NULL, r, conn);
+            ap_add_input_filter("H2_CONTINUE", NULL, r, c);
         }
         else {
             r->status = HTTP_EXPECTATION_FAILED;
@@ -356,11 +313,11 @@ request_rec *h2_request_create_rec(const
         /* Request check post hooks failed. An example of this would be a
          * request for a vhost where h2 is disabled --> 421.
          */
-        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, conn, APLOGNO()
-                      "h2_request(%d): access_status=%d, request_create failed",
-                      req->id, access_status);
+        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(03367)
+                      "h2_request: access_status=%d, request_create failed",
+                      access_status);
         ap_die(access_status, r);
-        ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r);
+        ap_update_child_status(c->sbh, SERVER_BUSY_LOG, r);
         ap_run_log_transaction(r);
         r = NULL;
         goto traceout;

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_request.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_request.h?rev=1763163&r1=1763162&r2=1763163&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_request.h (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_request.h Mon Oct  3 12:57:47 2016
@@ -18,8 +18,8 @@
 
 #include "h2.h"
 
-apr_status_t h2_request_rwrite(h2_request *req, apr_pool_t *pool, 
-                               request_rec *r);
+apr_status_t h2_request_rcreate(h2_request **preq, apr_pool_t *pool, 
+                                request_rec *r);
 
 apr_status_t h2_request_add_header(h2_request *req, apr_pool_t *pool,
                                    const char *name, size_t nlen,
@@ -29,8 +29,7 @@ apr_status_t h2_request_add_trailer(h2_r
                                     const char *name, size_t nlen,
                                     const char *value, size_t vlen);
 
-apr_status_t h2_request_end_headers(h2_request *req, apr_pool_t *pool, 
-                                    int eos, int push);
+apr_status_t h2_request_end_headers(h2_request *req, apr_pool_t *pool, int eos);
 
 h2_request *h2_request_clone(apr_pool_t *p, const h2_request *src);
 

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_session.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_session.c?rev=1763163&r1=1763162&r2=1763163&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_session.c (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_session.c Mon Oct  3 12:57:47 2016
@@ -38,9 +38,8 @@
 #include "h2_mplx.h"
 #include "h2_push.h"
 #include "h2_request.h"
-#include "h2_response.h"
+#include "h2_headers.h"
 #include "h2_stream.h"
-#include "h2_from_h1.h"
 #include "h2_task.h"
 #include "h2_session.h"
 #include "h2_util.h"
@@ -143,10 +142,14 @@ h2_stream *h2_session_open_stream(h2_ses
     apr_pool_tag(stream_pool, "h2_stream");
     
     stream = h2_stream_open(stream_id, stream_pool, session, 
-                            initiated_on, req);
+                            initiated_on);
     nghttp2_session_set_stream_user_data(session->ngh2, stream_id, stream);
     h2_ihash_add(session->streams, stream);
     
+    if (req) {
+        h2_stream_set_request(stream, req);
+    }
+    
     if (H2_STREAM_CLIENT_INITIATED(stream_id)) {
         if (stream_id > session->remote.emitted_max) {
             ++session->remote.emitted_count;
@@ -403,7 +406,7 @@ static int on_header_cb(nghttp2_session
     
     status = h2_stream_add_header(stream, (const char *)name, namelen,
                                   (const char *)value, valuelen);
-    if (status != APR_SUCCESS && !stream->response) {
+    if (status != APR_SUCCESS && !h2_stream_is_ready(stream)) {
         return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
     }
     return 0;
@@ -500,7 +503,7 @@ static int on_frame_recv_cb(nghttp2_sess
                           session->id, (int)frame->hd.stream_id,
                           (int)frame->rst_stream.error_code);
             stream = get_stream(session, frame->hd.stream_id);
-            if (stream && stream->request && stream->request->initiated_on) {
+            if (stream && stream->initiated_on) {
                 ++session->pushes_reset;
             }
             else {
@@ -1078,7 +1081,7 @@ static apr_status_t h2_session_start(h2_
             return status;
         }
         
-        status = h2_stream_set_request(stream, session->r);
+        status = h2_stream_set_request_rec(stream, session->r);
         if (status != APR_SUCCESS) {
             return status;
         }
@@ -1134,6 +1137,10 @@ static apr_status_t h2_session_start(h2_
     return status;
 }
 
+static apr_status_t on_stream_headers(h2_session *session, h2_stream *stream,  
+                                      h2_headers *headers, apr_off_t len,
+                                      int eos);
+
 static ssize_t stream_data_cb(nghttp2_session *ng2s,
                               int32_t stream_id,
                               uint8_t *buf,
@@ -1167,8 +1174,8 @@ static ssize_t stream_data_cb(nghttp2_se
                       session->id, (int)stream_id);
         return NGHTTP2_ERR_CALLBACK_FAILURE;
     }
-    
-    status = h2_stream_out_prepare(stream, &nread, &eos);
+
+    status = h2_stream_out_prepare(stream, &nread, &eos, NULL);
     if (nread) {
         *data_flags |=  NGHTTP2_DATA_FLAG_NO_COPY;
     }
@@ -1177,10 +1184,9 @@ static ssize_t stream_data_cb(nghttp2_se
         case APR_SUCCESS:
             break;
             
-        case APR_ECONNABORTED:
         case APR_ECONNRESET:
             return nghttp2_submit_rst_stream(ng2s, NGHTTP2_FLAG_NONE,
-                stream->id, H2_STREAM_RST(stream, H2_ERR_INTERNAL_ERROR));
+                stream->id, stream->rst_error);
             
         case APR_EAGAIN:
             /* If there is no data available, our session will automatically
@@ -1188,7 +1194,6 @@ static ssize_t stream_data_cb(nghttp2_se
              * it. Remember at our h2_stream that we need to do this.
              */
             nread = 0;
-            h2_mplx_suspend_stream(session->mplx, stream->id);
             ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, APLOGNO(03071)
                           "h2_stream(%ld-%d): suspending",
                           session->id, (int)stream_id);
@@ -1203,25 +1208,8 @@ static ssize_t stream_data_cb(nghttp2_se
     }
     
     if (eos) {
-        apr_table_t *trailers = h2_stream_get_trailers(stream);
-        if (trailers && !apr_is_empty_table(trailers)) {
-            h2_ngheader *nh;
-            int rv;
-            
-            nh = h2_util_ngheader_make(stream->pool, trailers);
-            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, APLOGNO(03072)
-                          "h2_stream(%ld-%d): submit %d trailers",
-                          session->id, (int)stream_id,(int) nh->nvlen);
-            rv = nghttp2_submit_trailer(ng2s, stream->id, nh->nv, nh->nvlen);
-            if (rv < 0) {
-                nread = rv;
-            }
-            *data_flags |= NGHTTP2_DATA_FLAG_NO_END_STREAM;
-        }
-        
         *data_flags |= NGHTTP2_DATA_FLAG_EOF;
     }
-    
     return (ssize_t)nread;
 }
 
@@ -1300,7 +1288,8 @@ apr_status_t h2_session_set_prio(h2_sess
     s_parent = nghttp2_stream_get_parent(s);
     if (s_parent) {
         nghttp2_priority_spec ps;
-        int id_parent, id_grandpa, w_parent, w, rv = 0;
+        apr_uint32_t id_parent, id_grandpa, w_parent, w;
+        int rv = 0;
         char *ptype = "AFTER";
         h2_dependency dep = prio->dependency;
         
@@ -1419,83 +1408,56 @@ static apr_status_t h2_session_send(h2_s
 }
 
 /**
- * A stream was resumed as new output data arrived.
+ * headers for the stream are ready.
  */
-static apr_status_t on_stream_resume(void *ctx, int stream_id)
+static apr_status_t on_stream_headers(h2_session *session, h2_stream *stream,  
+                                      h2_headers *headers, apr_off_t len,
+                                      int eos)
 {
-    h2_session *session = ctx;
-    h2_stream *stream = get_stream(session, stream_id);
     apr_status_t status = APR_SUCCESS;
-    
-    ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, session->c, 
-                  "h2_stream(%ld-%d): on_resume", session->id, stream_id);
-    if (stream) {
-        int rv;
-        if (stream->rst_error) {
-            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, APLOGNO()
-                          "h2_stream(%ld-%d): RST_STREAM, err=%d",
-                          session->id, stream->id, stream->rst_error);
-            rv = nghttp2_submit_rst_stream(session->ngh2, NGHTTP2_FLAG_NONE,
-                                           stream->id, stream->rst_error);
-        }
-        else {
-            rv = nghttp2_session_resume_data(session->ngh2, stream_id);
-        }
-        session->have_written = 1;
-        ap_log_cerror(APLOG_MARK, nghttp2_is_fatal(rv)?
-                      APLOG_ERR : APLOG_DEBUG, 0, session->c,
-                      APLOGNO(02936) 
-                      "h2_stream(%ld-%d): resuming %s",
-                      session->id, stream->id, rv? nghttp2_strerror(rv) : "");
-    }
-    return status;
-}
-
-/**
- * A response for the stream is ready.
- */
-static apr_status_t on_stream_response(void *ctx, int stream_id)
-{
-    h2_session *session = ctx;
-    h2_stream *stream = get_stream(session, stream_id);
-    apr_status_t status = APR_SUCCESS;
-    h2_response *response;
     int rv = 0;
 
-    AP_DEBUG_ASSERT(session);
+    ap_assert(session);
     ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, session->c, 
-                  "h2_stream(%ld-%d): on_response", session->id, stream_id);
-    if (!stream) {
-        return APR_NOTFOUND;
-    }
-    else if (stream->rst_error || !stream->response) {
+                  "h2_stream(%ld-%d): on_headers", session->id, stream->id);
+    if (!headers) {
         int err = H2_STREAM_RST(stream, H2_ERR_PROTOCOL_ERROR);
-        
-        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, APLOGNO(03074)
+        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, APLOGNO(03466)
                       "h2_stream(%ld-%d): RST_STREAM, err=%d",
                       session->id, stream->id, err);
-
         rv = nghttp2_submit_rst_stream(session->ngh2, NGHTTP2_FLAG_NONE,
                                        stream->id, err);
         goto leave;
     }
-    
-    while ((response = h2_stream_get_unsent_response(stream)) != NULL) {
+    else if (headers->status < 100) {
+        rv = nghttp2_submit_rst_stream(session->ngh2, NGHTTP2_FLAG_NONE,
+                                       stream->id, headers->status);
+        goto leave;
+    }
+    else if (stream->has_response) {
+        h2_ngheader *nh;
+        int rv;
+        
+        nh = h2_util_ngheader_make(stream->pool, headers->headers);
+        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, APLOGNO(03072)
+                      "h2_stream(%ld-%d): submit %d trailers",
+                      session->id, (int)stream->id,(int) nh->nvlen);
+        rv = nghttp2_submit_trailer(session->ngh2, stream->id, nh->nv, nh->nvlen);
+        goto leave;
+    }
+    else {
         nghttp2_data_provider provider, *pprovider = NULL;
         h2_ngheader *ngh;
+        apr_table_t *hout;
         const h2_priority *prio;
-        
-        if (stream->submitted) {
-            rv = NGHTTP2_PROTOCOL_ERROR;
-            goto leave;
-        }
+        const char *note;
         
         ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, APLOGNO(03073)
                       "h2_stream(%ld-%d): submit response %d, REMOTE_WINDOW_SIZE=%u",
-                      session->id, stream->id, response->http_status,
+                      session->id, stream->id, headers->status,
                       (unsigned int)nghttp2_session_get_stream_remote_window_size(session->ngh2, stream->id));
         
-        if (response->content_length != 0) {
+        if (!eos || len > 0) {
             memset(&provider, 0, sizeof(provider));
             provider.source.fd = stream->id;
             provider.read_callback = stream_data_cb;
@@ -1517,28 +1479,40 @@ static apr_status_t on_stream_response(v
          *    as the client, having this resource in its cache, might
          *    also have the pushed ones as well.
          */
-        if (stream->request 
-            && !stream->request->initiated_on
-            && h2_response_is_final(response)
-            && H2_HTTP_2XX(response->http_status)
+        if (!stream->initiated_on
+            && h2_headers_are_response(headers)
+            && H2_HTTP_2XX(headers->status)
             && h2_session_push_enabled(session)) {
             
-            h2_stream_submit_pushes(stream);
+            h2_stream_submit_pushes(stream, headers);
         }
         
-        prio = h2_stream_get_priority(stream);
+        prio = h2_stream_get_priority(stream, headers);
         if (prio) {
             h2_session_set_prio(session, stream, prio);
         }
         
-        ngh = h2_util_ngheader_make_res(stream->pool, response->http_status, 
-                                        response->headers);
-        rv = nghttp2_submit_response(session->ngh2, response->stream_id,
+        hout = headers->headers;
+        note = apr_table_get(headers->notes, H2_FILTER_DEBUG_NOTE);
+        if (note && !strcmp("on", note)) {
+            int32_t connFlowIn, connFlowOut;
+
+            connFlowIn = nghttp2_session_get_effective_local_window_size(session->ngh2); 
+            connFlowOut = nghttp2_session_get_remote_window_size(session->ngh2);
+            hout = apr_table_clone(stream->pool, hout);
+            apr_table_setn(hout, "conn-flow-in", 
+                           apr_itoa(stream->pool, connFlowIn));
+            apr_table_setn(hout, "conn-flow-out", 
+                           apr_itoa(stream->pool, connFlowOut));
+        }
+        
+        ngh = h2_util_ngheader_make_res(stream->pool, headers->status, hout);
+        rv = nghttp2_submit_response(session->ngh2, stream->id,
                                      ngh->nv, ngh->nvlen, pprovider);
-        stream->submitted = h2_response_is_final(response);
+        stream->has_response = h2_headers_are_response(headers);
         session->have_written = 1;
         
-        if (stream->request && stream->request->initiated_on) {
+        if (stream->initiated_on) {
             ++session->pushes_submitted;
         }
         else {
@@ -1571,6 +1545,48 @@ leave:
     return status;
 }
 
+/**
+ * A stream was resumed as new output data arrived.
+ */
+static apr_status_t on_stream_resume(void *ctx, int stream_id)
+{
+    h2_session *session = ctx;
+    h2_stream *stream = get_stream(session, stream_id);
+    apr_status_t status = APR_EAGAIN;
+    int rv;
+    
+    ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, session->c, 
+                  "h2_stream(%ld-%d): on_resume", session->id, stream_id);
+    if (stream) {
+        apr_off_t len = 0;
+        int eos = 0;
+        h2_headers *headers = NULL;
+        
+        send_headers:
+        status = h2_stream_out_prepare(stream, &len, &eos, &headers);
+        ap_log_cerror(APLOG_MARK, APLOG_TRACE2, status, session->c, 
+                      "h2_stream(%ld-%d): prepared len=%ld, eos=%d", 
+                      session->id, stream_id, (long)len, eos);
+        if (headers) {
+            status = on_stream_headers(session, stream, headers, len, eos);
+            if (status != APR_SUCCESS) {
+                return status;
+            }
+            goto send_headers;
+        }
+        else if (status != APR_EAGAIN) {
+            rv = nghttp2_session_resume_data(session->ngh2, stream_id);
+            session->have_written = 1;
+            ap_log_cerror(APLOG_MARK, nghttp2_is_fatal(rv)?
+                          APLOG_ERR : APLOG_DEBUG, 0, session->c,
+                          APLOGNO(02936) 
+                          "h2_stream(%ld-%d): resuming %s",
+                          session->id, stream->id, rv? nghttp2_strerror(rv) : "");
+        }
+    }
+    return status;
+}
+
 static apr_status_t h2_session_receive(void *ctx, const char *data, 
                                        apr_size_t len, apr_size_t *readlen)
 {
@@ -1805,7 +1821,7 @@ static void h2_session_ev_no_io(h2_sessi
                           session->id, session->open_streams);
             h2_conn_io_flush(&session->io);
             if (session->open_streams > 0) {
-                if (h2_mplx_is_busy(session->mplx)) {
+                if (h2_mplx_awaits_data(session->mplx)) {
                     /* waiting for at least one stream to produce data */
                     transit(session, "no io", H2_SESSION_ST_WAIT);
                 }
@@ -2169,7 +2185,6 @@ apr_status_t h2_session_process(h2_sessi
                 /* trigger window updates, stream resumes and submits */
                 status = h2_mplx_dispatch_master_events(session->mplx, 
                                                         on_stream_resume,
-                                                        on_stream_response, 
                                                         session);
                 if (status != APR_SUCCESS) {
                     ap_log_cerror(APLOG_MARK, APLOG_TRACE3, status, c,

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_session.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_session.h?rev=1763163&r1=1763162&r2=1763163&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_session.h (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_session.h Mon Oct  3 12:57:47 2016
@@ -49,7 +49,6 @@ struct h2_mplx;
 struct h2_priority;
 struct h2_push;
 struct h2_push_diary;
-struct h2_response;
 struct h2_session;
 struct h2_stream;
 struct h2_task;
@@ -187,11 +186,6 @@ void h2_session_abort(h2_session *sessio
  */
 void h2_session_close(h2_session *session);
 
-/* Start submitting the response to a stream request. This is possible
- * once we have all the response headers. */
-apr_status_t h2_session_handle_response(h2_session *session,
-                                        struct h2_stream *stream);
-
 /**
  * Create and register a new stream under the given id.
  *