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 2015/10/09 16:24:48 UTC

svn commit: r1707735 - in /httpd/httpd/trunk/modules/http2: h2_io.c h2_io.h h2_mplx.c h2_mplx.h h2_session.c h2_stream.c h2_stream.h h2_util.c h2_util.h h2_version.h

Author: icing
Date: Fri Oct  9 14:24:46 2015
New Revision: 1707735

URL: http://svn.apache.org/viewvc?rev=1707735&view=rev
Log:
avoid double eos buckets on stream output brigades, add stream rst infrstructure, bump to 1.0.1-DEV

Modified:
    httpd/httpd/trunk/modules/http2/h2_io.c
    httpd/httpd/trunk/modules/http2/h2_io.h
    httpd/httpd/trunk/modules/http2/h2_mplx.c
    httpd/httpd/trunk/modules/http2/h2_mplx.h
    httpd/httpd/trunk/modules/http2/h2_session.c
    httpd/httpd/trunk/modules/http2/h2_stream.c
    httpd/httpd/trunk/modules/http2/h2_stream.h
    httpd/httpd/trunk/modules/http2/h2_util.c
    httpd/httpd/trunk/modules/http2/h2_util.h
    httpd/httpd/trunk/modules/http2/h2_version.h

Modified: httpd/httpd/trunk/modules/http2/h2_io.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_io.c?rev=1707735&r1=1707734&r2=1707735&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_io.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_io.c Fri Oct  9 14:24:46 2015
@@ -47,6 +47,12 @@ void h2_io_destroy(h2_io *io)
     h2_io_cleanup(io);
 }
 
+void h2_io_rst(h2_io *io, int error)
+{
+    io->rst_error = error;
+    io->eos_in = 1;
+}
+
 int h2_io_in_has_eos_for(h2_io *io)
 {
     return io->eos_in || (io->bbin && h2_util_has_eos(io->bbin, 0));
@@ -124,16 +130,52 @@ apr_status_t h2_io_out_readx(h2_io *io,
                              h2_io_data_cb *cb, void *ctx, 
                              apr_size_t *plen, int *peos)
 {
+    apr_status_t status;
+    
+    if (io->eos_out) {
+        *plen = 0;
+        *peos = 1;
+        return APR_SUCCESS;
+    }
+    
     if (cb == NULL) {
         /* just checking length available */
-        return h2_util_bb_avail(io->bbout, plen, peos);
+        status = h2_util_bb_avail(io->bbout, plen, peos);
     }
-    return h2_util_bb_readx(io->bbout, cb, ctx, plen, peos);
+    else {
+        status = h2_util_bb_readx(io->bbout, cb, ctx, plen, peos);
+        if (status == APR_SUCCESS) {
+            io->eos_out = *peos;
+        }
+    }
+    
+    return status;
 }
 
 apr_status_t h2_io_out_write(h2_io *io, apr_bucket_brigade *bb, 
                              apr_size_t maxlen, int *pfile_handles_allowed)
 {
+    apr_status_t status;
+    int start_allowed;
+    
+    if (io->eos_out) {
+        apr_off_t len;
+        /* We have already delivered an EOS bucket to a reader, no
+         * sense in storing anything more here.
+         */
+        status = apr_brigade_length(bb, 1, &len);
+        if (status == APR_SUCCESS) {
+            if (len > 0) {
+                /* someone tries to write real data after EOS, that
+                 * does not look right. */
+                status = APR_EOF;
+            }
+            /* cleanup, as if we had moved the data */
+            apr_brigade_cleanup(bb);
+        }
+        return status;
+    }
+    
     /* Let's move the buckets from the request processing in here, so
      * that the main thread can read them when it has time/capacity.
      *
@@ -144,8 +186,11 @@ apr_status_t h2_io_out_write(h2_io *io,
      * many open files already buffered. Otherwise we will run out of
      * file handles.
      */
-    int start_allowed = *pfile_handles_allowed;
-    apr_status_t status;
+    start_allowed = *pfile_handles_allowed;
+
+    if (io->rst_error) {
+        return APR_ECONNABORTED;
+    }
     status = h2_util_move(io->bbout, bb, maxlen, pfile_handles_allowed, 
                           "h2_io_out_write");
     /* track # file buckets moved into our pool */
@@ -158,7 +203,9 @@ apr_status_t h2_io_out_write(h2_io *io,
 
 apr_status_t h2_io_out_close(h2_io *io)
 {
-    APR_BRIGADE_INSERT_TAIL(io->bbout, 
-                            apr_bucket_eos_create(io->bbout->bucket_alloc));
+    if (!io->eos_out && !h2_util_has_eos(io->bbout, 0)) {
+        APR_BRIGADE_INSERT_TAIL(io->bbout, 
+                                apr_bucket_eos_create(io->bbout->bucket_alloc));
+    }
     return APR_SUCCESS;
 }

Modified: httpd/httpd/trunk/modules/http2/h2_io.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_io.h?rev=1707735&r1=1707734&r2=1707735&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_io.h (original)
+++ httpd/httpd/trunk/modules/http2/h2_io.h Fri Oct  9 14:24:46 2015
@@ -33,11 +33,13 @@ struct h2_io {
     apr_bucket_brigade *bbin;    /* input data for stream */
     int eos_in;
     int task_done;
+    int rst_error;
     
     apr_size_t input_consumed;   /* how many bytes have been read */
     struct apr_thread_cond_t *input_arrived; /* block on reading */
     
     apr_bucket_brigade *bbout;   /* output data from stream */
+    int eos_out;
     struct apr_thread_cond_t *output_drained; /* block on writing */
     
     struct h2_response *response;/* submittable response created */
@@ -59,6 +61,11 @@ h2_io *h2_io_create(int id, apr_pool_t *
 void h2_io_destroy(h2_io *io);
 
 /**
+ * Reset the stream with the given error code.
+ */
+void h2_io_rst(h2_io *io, int error);
+
+/**
  * The input data is completely queued. Blocked reads will return immediately
  * and give either data or EOF.
  */

Modified: httpd/httpd/trunk/modules/http2/h2_mplx.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_mplx.c?rev=1707735&r1=1707734&r2=1707735&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_mplx.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_mplx.c Fri Oct  9 14:24:46 2015
@@ -41,6 +41,7 @@
 #include "h2_task_output.h"
 #include "h2_task_queue.h"
 #include "h2_workers.h"
+#include "h2_util.h"
 
 
 static int is_aborted(h2_mplx *m, apr_status_t *pstatus) {
@@ -454,6 +455,13 @@ apr_status_t h2_mplx_in_update_windows(h
     return status;
 }
 
+#define H2_MPLX_IO_OUT(lvl,m,io,msg) \
+    do { \
+        if (APLOG_C_IS_LEVEL((m)->c,lvl)) \
+        h2_util_bb_log((m)->c,(io)->id,lvl,msg,(io)->bbout); \
+    } while(0)
+
+
 apr_status_t h2_mplx_out_readx(h2_mplx *m, int stream_id, 
                                h2_io_data_cb *cb, void *ctx, 
                                apr_size_t *plen, int *peos)
@@ -467,8 +475,12 @@ apr_status_t h2_mplx_out_readx(h2_mplx *
     if (APR_SUCCESS == status) {
         h2_io *io = h2_io_set_get(m->stream_ios, stream_id);
         if (io) {
+            H2_MPLX_IO_OUT(APLOG_TRACE2, m, io, "h2_mplx_out_readx_pre");
+            
             status = h2_io_out_readx(io, cb, ctx, plen, peos);
-            if (status == APR_SUCCESS && io->output_drained) {
+            
+            H2_MPLX_IO_OUT(APLOG_TRACE2, m, io, "h2_mplx_out_readx_post");
+            if (status == APR_SUCCESS && cb && io->output_drained) {
                 apr_thread_cond_signal(io->output_drained);
             }
         }
@@ -492,14 +504,18 @@ h2_stream *h2_mplx_next_submit(h2_mplx *
     if (APR_SUCCESS == status) {
         h2_io *io = h2_io_set_get_highest_prio(m->ready_ios);
         if (io) {
-            h2_response *response = io->response;
-            
-            AP_DEBUG_ASSERT(response);
-            h2_io_set_remove(m->ready_ios, io);
             
-            stream = h2_stream_set_get(streams, response->stream_id);
+            stream = h2_stream_set_get(streams, io->id);
             if (stream) {
-                h2_stream_set_response(stream, response, io->bbout);
+                if (io->rst_error) {
+                    h2_stream_rst(stream, io->rst_error);
+                }
+                else {
+                    AP_DEBUG_ASSERT(io->response);
+                    h2_stream_set_response(stream, io->response, io->bbout);
+                }
+                
+                h2_io_set_remove(m->ready_ios, io);
                 if (io->output_drained) {
                     apr_thread_cond_signal(io->output_drained);
                 }
@@ -507,7 +523,7 @@ h2_stream *h2_mplx_next_submit(h2_mplx *
             else {
                 ap_log_cerror(APLOG_MARK, APLOG_WARNING, APR_NOTFOUND, m->c,
                               APLOGNO(02953) "h2_mplx(%ld): stream for response %d",
-                              m->id, response->stream_id);
+                              m->id, io->id);
             }
         }
         apr_thread_mutex_unlock(m->lock);
@@ -531,7 +547,6 @@ static apr_status_t out_write(h2_mplx *m
         
         status = h2_io_out_write(io, bb, m->stream_max_mem, 
                                  &m->file_handles_allowed);
-        
         /* Wait for data to drain until there is room again */
         while (!APR_BRIGADE_EMPTY(bb) 
                && iowait
@@ -549,6 +564,7 @@ static apr_status_t out_write(h2_mplx *m
         }
     }
     apr_brigade_cleanup(bb);
+    
     return status;
 }
 
@@ -592,6 +608,9 @@ apr_status_t h2_mplx_out_open(h2_mplx *m
     status = apr_thread_mutex_lock(m->lock);
     if (APR_SUCCESS == status) {
         status = out_open(m, stream_id, response, f, bb, iowait);
+        if (APLOGctrace1(m->c)) {
+            h2_util_bb_log(m->c, stream_id, APLOG_TRACE1, "h2_mplx_out_open", bb);
+        }
         if (m->aborted) {
             return APR_ECONNABORTED;
         }
@@ -616,6 +635,8 @@ apr_status_t h2_mplx_out_write(h2_mplx *
             h2_io *io = h2_io_set_get(m->stream_ios, stream_id);
             if (io) {
                 status = out_write(m, io, f, bb, iowait);
+                H2_MPLX_IO_OUT(APLOG_TRACE2, m, io, "h2_mplx_out_write");
+                
                 have_out_data_for(m, stream_id);
                 if (m->aborted) {
                     return APR_ECONNABORTED;
@@ -645,7 +666,7 @@ apr_status_t h2_mplx_out_close(h2_mplx *
         if (!m->aborted) {
             h2_io *io = h2_io_set_get(m->stream_ios, stream_id);
             if (io) {
-                if (!io->response || !io->response->ngheader) {
+                if (!io->response && !io->rst_error) {
                     /* In case a close comes before a response was created,
                      * insert an error one so that our streams can properly
                      * reset.
@@ -653,8 +674,48 @@ apr_status_t h2_mplx_out_close(h2_mplx *
                     h2_response *r = h2_response_create(stream_id, 
                                                         "500", NULL, m->pool);
                     status = out_open(m, stream_id, r, NULL, NULL, NULL);
+                    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, m->c,
+                                  "h2_mplx(%ld-%d): close, no response, no rst", 
+                                  m->id, io->id);
                 }
                 status = h2_io_out_close(io);
+                H2_MPLX_IO_OUT(APLOG_TRACE2, m, io, "h2_mplx_out_close");
+                
+                have_out_data_for(m, stream_id);
+                if (m->aborted) {
+                    /* if we were the last output, the whole session might
+                     * have gone down in the meantime.
+                     */
+                    return APR_SUCCESS;
+                }
+            }
+            else {
+                status = APR_ECONNABORTED;
+            }
+        }
+        apr_thread_mutex_unlock(m->lock);
+    }
+    return status;
+}
+
+apr_status_t h2_mplx_out_rst(h2_mplx *m, int stream_id, int error)
+{
+    apr_status_t status;
+    AP_DEBUG_ASSERT(m);
+    if (m->aborted) {
+        return APR_ECONNABORTED;
+    }
+    status = apr_thread_mutex_lock(m->lock);
+    if (APR_SUCCESS == status) {
+        if (!m->aborted) {
+            h2_io *io = h2_io_set_get(m->stream_ios, stream_id);
+            if (io && !io->rst_error) {
+                h2_io_rst(io, error);
+                if (!io->response) {
+                        h2_io_set_add(m->ready_ios, io);
+                }
+                H2_MPLX_IO_OUT(APLOG_TRACE2, m, io, "h2_mplx_out_rst");
+                
                 have_out_data_for(m, stream_id);
                 if (m->aborted) {
                     /* if we were the last output, the whole session might

Modified: httpd/httpd/trunk/modules/http2/h2_mplx.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_mplx.h?rev=1707735&r1=1707734&r2=1707735&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_mplx.h (original)
+++ httpd/httpd/trunk/modules/http2/h2_mplx.h Fri Oct  9 14:24:46 2015
@@ -96,6 +96,7 @@ void h2_mplx_reference(h2_mplx *m);
  * Decreases the reference counter of this mplx.
  */
 void h2_mplx_release(h2_mplx *m);
+
 /**
  * Decreases the reference counter of this mplx and waits for it
  * to reached 0, destroy the mplx afterwards.
@@ -247,6 +248,8 @@ apr_status_t h2_mplx_out_write(h2_mplx *
  */
 apr_status_t h2_mplx_out_close(h2_mplx *m, int stream_id);
 
+apr_status_t h2_mplx_out_rst(h2_mplx *m, int stream_id, int error);
+
 /*******************************************************************************
  * h2_mplx list Manipulation.
  ******************************************************************************/

Modified: httpd/httpd/trunk/modules/http2/h2_session.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_session.c?rev=1707735&r1=1707734&r2=1707735&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_session.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_session.c Fri Oct  9 14:24:46 2015
@@ -1062,6 +1062,10 @@ static ssize_t stream_data_cb(nghttp2_se
         case APR_SUCCESS:
             break;
             
+        case APR_ECONNRESET:
+            return nghttp2_submit_rst_stream(ng2s, NGHTTP2_FLAG_NONE,
+                stream->id, stream->rst_error);
+            
         case APR_EAGAIN:
             /* If there is no data available, our session will automatically
              * suspend this stream and not ask for more data until we resume
@@ -1141,11 +1145,15 @@ apr_status_t h2_session_handle_response(
     int rv = 0;
     AP_DEBUG_ASSERT(session);
     AP_DEBUG_ASSERT(stream);
-    AP_DEBUG_ASSERT(stream->response);
+    AP_DEBUG_ASSERT(stream->response || stream->rst_error);
     
-    if (stream->response->ngheader) {
+    if (stream->response && stream->response->ngheader) {
         rv = submit_response(session, stream->response);
     }
+    else if (stream->rst_error) {
+        rv = nghttp2_submit_rst_stream(session->ngh2, NGHTTP2_FLAG_NONE,
+                                       stream->id, stream->rst_error);
+    }
     else {
         rv = nghttp2_submit_rst_stream(session->ngh2, NGHTTP2_FLAG_NONE,
                                        stream->id, NGHTTP2_PROTOCOL_ERROR);

Modified: httpd/httpd/trunk/modules/http2/h2_stream.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_stream.c?rev=1707735&r1=1707734&r2=1707735&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_stream.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_stream.c Fri Oct  9 14:24:46 2015
@@ -86,11 +86,6 @@ apr_status_t h2_stream_destroy(h2_stream
     return APR_SUCCESS;
 }
 
-void h2_stream_attach_pool(h2_stream *stream, apr_pool_t *pool)
-{
-    stream->pool = pool;
-}
-
 apr_pool_t *h2_stream_detach_pool(h2_stream *stream)
 {
     apr_pool_t *pool = stream->pool;
@@ -98,25 +93,41 @@ apr_pool_t *h2_stream_detach_pool(h2_str
     return pool;
 }
 
-void h2_stream_abort(h2_stream *stream)
+void h2_stream_rst(h2_stream *stream, int error_code)
 {
-    AP_DEBUG_ASSERT(stream);
-    stream->aborted = 1;
+    stream->rst_error = error_code;
+    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, stream->m->c,
+                  "h2_stream(%ld-%d): reset, error=%d", 
+                  stream->m->id, stream->id, error_code);
 }
 
 apr_status_t h2_stream_set_response(h2_stream *stream, h2_response *response,
                                     apr_bucket_brigade *bb)
 {
+    apr_status_t status = APR_SUCCESS;
+    
     stream->response = response;
     if (bb && !APR_BRIGADE_EMPTY(bb)) {
         if (!stream->bbout) {
             stream->bbout = apr_brigade_create(stream->pool, 
                                                stream->m->c->bucket_alloc);
         }
-        return h2_util_move(stream->bbout, bb, 16 * 1024, NULL,  
-                            "h2_stream_set_response");
+        status = h2_util_move(stream->bbout, bb, 16 * 1024, NULL,  
+                              "h2_stream_set_response");
     }
-    return APR_SUCCESS;
+    if (APLOGctrace1(stream->m->c)) {
+        apr_size_t len = 0;
+        int eos = 0;
+        if (stream->bbout) {
+            h2_util_bb_avail(stream->bbout, &len, &eos);
+        }
+        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, stream->m->c,
+                      "h2_stream(%ld-%d): set_response(%s), brigade=%s, "
+                      "len=%ld, eos=%d", 
+                      stream->m->id, stream->id, response->status,
+                      (stream->bbout? "yes" : "no"), (long)len, (int)eos);
+    }
+    return status;
 }
 
 static int set_closed(h2_stream *stream) 
@@ -141,6 +152,9 @@ apr_status_t h2_stream_rwrite(h2_stream
 {
     apr_status_t status;
     AP_DEBUG_ASSERT(stream);
+    if (stream->rst_error) {
+        return APR_ECONNRESET;
+    }
     set_state(stream, H2_STREAM_ST_OPEN);
     status = h2_request_rwrite(stream->request, r, stream->m);
     return status;
@@ -151,6 +165,9 @@ apr_status_t h2_stream_write_eoh(h2_stre
     apr_status_t status;
     AP_DEBUG_ASSERT(stream);
     
+    if (stream->rst_error) {
+        return APR_ECONNRESET;
+    }
     /* Seeing the end-of-headers, we have everything we need to 
      * start processing it.
      */
@@ -180,6 +197,9 @@ apr_status_t h2_stream_write_eos(h2_stre
     ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, stream->m->c,
                   "h2_stream(%ld-%d): closing input",
                   stream->m->id, stream->id);
+    if (stream->rst_error) {
+        return APR_ECONNRESET;
+    }
     if (set_closed(stream)) {
         return h2_request_close(stream->request);
     }
@@ -191,6 +211,9 @@ apr_status_t h2_stream_write_header(h2_s
                                     const char *value, size_t vlen)
 {
     AP_DEBUG_ASSERT(stream);
+    if (stream->rst_error) {
+        return APR_ECONNRESET;
+    }
     switch (stream->state) {
         case H2_STREAM_ST_IDLE:
             set_state(stream, H2_STREAM_ST_OPEN);
@@ -208,7 +231,9 @@ apr_status_t h2_stream_write_data(h2_str
                                   const char *data, size_t len)
 {
     AP_DEBUG_ASSERT(stream);
-    AP_DEBUG_ASSERT(stream);
+    if (stream->rst_error) {
+        return APR_ECONNRESET;
+    }
     switch (stream->state) {
         case H2_STREAM_ST_OPEN:
             break;
@@ -224,6 +249,9 @@ apr_status_t h2_stream_prep_read(h2_stre
     apr_status_t status = APR_SUCCESS;
     const char *src;
     
+    if (stream->rst_error) {
+        return APR_ECONNRESET;
+    }
     if (stream->bbout && !APR_BRIGADE_EMPTY(stream->bbout)) {
         src = "stream";
         status = h2_util_bb_avail(stream->bbout, plen, peos);
@@ -251,6 +279,9 @@ apr_status_t h2_stream_readx(h2_stream *
                              h2_io_data_cb *cb, void *ctx,
                              apr_size_t *plen, int *peos)
 {
+    if (stream->rst_error) {
+        return APR_ECONNRESET;
+    }
     if (stream->bbout && !APR_BRIGADE_EMPTY(stream->bbout)) {
         return h2_util_bb_readx(stream->bbout, cb, ctx, plen, peos);
     }

Modified: httpd/httpd/trunk/modules/http2/h2_stream.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_stream.h?rev=1707735&r1=1707734&r2=1707735&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_stream.h (original)
+++ httpd/httpd/trunk/modules/http2/h2_stream.h Fri Oct  9 14:24:46 2015
@@ -66,6 +66,7 @@ struct h2_stream {
     struct h2_task *task;       /* task created for this stream */
     struct h2_response *response; /* the response, once ready */
     apr_bucket_brigade *bbout;  /* output DATA */
+    int rst_error;              /* stream error for RST_STREAM */
 };
 
 
@@ -73,10 +74,9 @@ h2_stream *h2_stream_create(int id, apr_
 
 apr_status_t h2_stream_destroy(h2_stream *stream);
 
-apr_pool_t *h2_stream_detach_pool(h2_stream *stream);
-void h2_stream_attach_pool(h2_stream *stream, apr_pool_t *pool);
+void h2_stream_rst(h2_stream *streamm, int error_code);
 
-void h2_stream_abort(h2_stream *stream);
+apr_pool_t *h2_stream_detach_pool(h2_stream *stream);
 
 apr_status_t h2_stream_rwrite(h2_stream *stream, request_rec *r);
 

Modified: httpd/httpd/trunk/modules/http2/h2_util.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_util.c?rev=1707735&r1=1707734&r2=1707735&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_util.c (original)
+++ httpd/httpd/trunk/modules/http2/h2_util.c Fri Oct  9 14:24:46 2015
@@ -20,6 +20,7 @@
 #include <httpd.h>
 #include <http_core.h>
 #include <http_log.h>
+#include <http_request.h>
 
 #include <nghttp2/nghttp2.h>
 
@@ -647,3 +648,71 @@ apr_status_t h2_util_bb_readx(apr_bucket
     return status;
 }
 
+void h2_util_bb_log(conn_rec *c, int stream_id, int level, 
+                    const char *tag, apr_bucket_brigade *bb)
+{
+    char buffer[16 * 1024];
+    const char *line = "(null)";
+    apr_size_t bmax = sizeof(buffer)/sizeof(buffer[0]);
+    int off = 0;
+    apr_bucket *b;
+    
+    if (bb) {
+        memset(buffer, 0, bmax--);
+        for (b = APR_BRIGADE_FIRST(bb); 
+             bmax && (b != APR_BRIGADE_SENTINEL(bb));
+             b = APR_BUCKET_NEXT(b)) {
+            
+            if (APR_BUCKET_IS_METADATA(b)) {
+                if (APR_BUCKET_IS_EOS(b)) {
+                    off += apr_snprintf(buffer+off, bmax-off, "eos ");
+                }
+                else if (APR_BUCKET_IS_FLUSH(b)) {
+                    off += apr_snprintf(buffer+off, bmax-off, "flush ");
+                }
+                else if (AP_BUCKET_IS_EOR(b)) {
+                    off += apr_snprintf(buffer+off, bmax-off, "eor ");
+                }
+                else {
+                    off += apr_snprintf(buffer+off, bmax-off, "meta(unknown) ");
+                }
+            }
+            else {
+                const char *btype = "data";
+                if (APR_BUCKET_IS_FILE(b)) {
+                    btype = "file";
+                }
+                else if (APR_BUCKET_IS_PIPE(b)) {
+                    btype = "pipe";
+                }
+                else if (APR_BUCKET_IS_SOCKET(b)) {
+                    btype = "socket";
+                }
+                else if (APR_BUCKET_IS_HEAP(b)) {
+                    btype = "heap";
+                }
+                else if (APR_BUCKET_IS_TRANSIENT(b)) {
+                    btype = "transient";
+                }
+                else if (APR_BUCKET_IS_IMMORTAL(b)) {
+                    btype = "immortal";
+                }
+                else if (APR_BUCKET_IS_MMAP(b)) {
+                    btype = "mmap";
+                }
+                else if (APR_BUCKET_IS_POOL(b)) {
+                    btype = "pool";
+                }
+                
+                off += apr_snprintf(buffer+off, bmax-off, "%s[%ld] ", 
+                                    btype, 
+                                    (long)(b->length == ((apr_size_t)-1)? 
+                                           -1 : b->length));
+            }
+        }
+        line = *buffer? buffer : "(empty)";
+    }
+    ap_log_cerror(APLOG_MARK, level, 0, c, "bb_dump(%ld-%d)-%s: %s", 
+                  c->id, stream_id, tag, line);
+
+}

Modified: httpd/httpd/trunk/modules/http2/h2_util.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_util.h?rev=1707735&r1=1707734&r2=1707735&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_util.h (original)
+++ httpd/httpd/trunk/modules/http2/h2_util.h Fri Oct  9 14:24:46 2015
@@ -117,8 +117,32 @@ apr_status_t h2_util_bb_avail(apr_bucket
 typedef apr_status_t h2_util_pass_cb(void *ctx, 
                                        const char *data, apr_size_t len);
 
+/**
+ * Read at most *plen bytes from the brigade and pass them into the
+ * given callback. If cb is NULL, just return the amount of data that
+ * could have been read.
+ * If an EOS was/would be encountered, set *peos != 0.
+ * @param bb the brigade to read from
+ * @param cb the callback to invoke for the read data
+ * @param ctx optional data passed to callback
+ * @param plen inout, as input gives the maximum number of bytes to read,
+ *    on return specifies the actual/would be number of bytes
+ * @param peos != 0 iff an EOS bucket was/would be encountered.
+ */
 apr_status_t h2_util_bb_readx(apr_bucket_brigade *bb, 
                               h2_util_pass_cb *cb, void *ctx, 
                               apr_size_t *plen, int *peos);
 
+/**
+ * Logs the bucket brigade (which bucket types with what length)
+ * to the log at the given level.
+ * @param c the connection to log for
+ * @param stream_id the stream identifier this brigade belongs to
+ * @param level the log level (as in APLOG_*)
+ * @param tag a short message text about the context
+ * @param bb the brigade to log
+ */
+void h2_util_bb_log(conn_rec *c, int stream_id, int level, 
+                    const char *tag, apr_bucket_brigade *bb);
+
 #endif /* defined(__mod_h2__h2_util__) */

Modified: httpd/httpd/trunk/modules/http2/h2_version.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/http2/h2_version.h?rev=1707735&r1=1707734&r2=1707735&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/http2/h2_version.h (original)
+++ httpd/httpd/trunk/modules/http2/h2_version.h Fri Oct  9 14:24:46 2015
@@ -20,7 +20,7 @@
  * @macro
  * Version number of the h2 module as c string
  */
-#define MOD_HTTP2_VERSION "1.0.0"
+#define MOD_HTTP2_VERSION "1.0.1-DEV"
 
 /**
  * @macro
@@ -28,7 +28,7 @@
  * release. This is a 24 bit number with 8 bits for major number, 8 bits
  * for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.
  */
-#define MOD_HTTP2_VERSION_NUM 0x010000
+#define MOD_HTTP2_VERSION_NUM 0x010001
 
 
 #endif /* mod_h2_h2_version_h */