You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by jo...@apache.org on 2016/11/14 10:26:34 UTC
svn commit: r1769588 [11/17] - in
/httpd/httpd/branches/2.4.x-openssl-1.1.0-compat: ./ docs/conf/
docs/manual/ docs/manual/howto/ docs/manual/mod/ docs/manual/platform/
docs/manual/programs/ docs/manual/rewrite/ include/ modules/ modules/aaa/
modules/a...
Modified: httpd/httpd/branches/2.4.x-openssl-1.1.0-compat/modules/http2/h2_bucket_beam.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x-openssl-1.1.0-compat/modules/http2/h2_bucket_beam.c?rev=1769588&r1=1769587&r2=1769588&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x-openssl-1.1.0-compat/modules/http2/h2_bucket_beam.c (original)
+++ httpd/httpd/branches/2.4.x-openssl-1.1.0-compat/modules/http2/h2_bucket_beam.c Mon Nov 14 10:26:31 2016
@@ -21,6 +21,7 @@
#include <apr_thread_cond.h>
#include <httpd.h>
+#include <http_protocol.h>
#include <http_log.h>
#include "h2_private.h"
@@ -138,25 +139,6 @@ static apr_bucket *h2_beam_bucket_create
return h2_beam_bucket_make(b, beam, bred, n);
}
-/*static apr_status_t beam_bucket_setaside(apr_bucket *b, apr_pool_t *pool)
-{
- apr_status_t status = APR_SUCCESS;
- h2_beam_proxy *d = b->data;
- if (d->bred) {
- const char *data;
- apr_size_t len;
-
- status = apr_bucket_read(d->bred, &data, &len, APR_BLOCK_READ);
- if (status == APR_SUCCESS) {
- b = apr_bucket_heap_make(b, (char *)data + b->start, b->length, NULL);
- if (b == NULL) {
- return APR_ENOMEM;
- }
- }
- }
- return status;
-}*/
-
const apr_bucket_type_t h2_bucket_type_beam = {
"BEAM", 5, APR_BUCKET_DATA,
beam_bucket_destroy,
@@ -169,7 +151,36 @@ const apr_bucket_type_t h2_bucket_type_b
/*******************************************************************************
* h2_blist, a brigade without allocations
******************************************************************************/
+
+static apr_array_header_t *beamers;
+void h2_register_bucket_beamer(h2_bucket_beamer *beamer)
+{
+ if (!beamers) {
+ beamers = apr_array_make(apr_hook_global_pool, 10,
+ sizeof(h2_bucket_beamer*));
+ }
+ APR_ARRAY_PUSH(beamers, h2_bucket_beamer*) = beamer;
+}
+
+static apr_bucket *h2_beam_bucket(h2_bucket_beam *beam,
+ apr_bucket_brigade *dest,
+ const apr_bucket *src)
+{
+ apr_bucket *b = NULL;
+ int i;
+ if (beamers) {
+ for (i = 0; i < beamers->nelts && b == NULL; ++i) {
+ h2_bucket_beamer *beamer;
+
+ beamer = APR_ARRAY_IDX(beamers, i, h2_bucket_beamer*);
+ b = beamer(beam, dest, src);
+ }
+ }
+ return b;
+}
+
+
apr_size_t h2_util_bl_print(char *buffer, apr_size_t bmax,
const char *tag, const char *sep,
h2_blist *bl)
@@ -223,12 +234,34 @@ static void leave_yellow(h2_bucket_beam
}
}
-static apr_off_t calc_buffered(h2_bucket_beam *beam)
+static void report_consumption(h2_bucket_beam *beam, int force)
{
- apr_off_t len = 0;
+ if (force || beam->received_bytes != beam->reported_consumed_bytes) {
+ if (beam->consumed_fn) {
+ beam->consumed_fn(beam->consumed_ctx, beam, beam->received_bytes
+ - beam->reported_consumed_bytes);
+ }
+ beam->reported_consumed_bytes = beam->received_bytes;
+ }
+}
+
+static void report_production(h2_bucket_beam *beam, int force)
+{
+ if (force || beam->sent_bytes != beam->reported_produced_bytes) {
+ if (beam->produced_fn) {
+ beam->produced_fn(beam->produced_ctx, beam, beam->sent_bytes
+ - beam->reported_produced_bytes);
+ }
+ beam->reported_produced_bytes = beam->sent_bytes;
+ }
+}
+
+static apr_size_t calc_buffered(h2_bucket_beam *beam)
+{
+ apr_size_t len = 0;
apr_bucket *b;
- for (b = H2_BLIST_FIRST(&beam->red);
- b != H2_BLIST_SENTINEL(&beam->red);
+ for (b = H2_BLIST_FIRST(&beam->send_list);
+ b != H2_BLIST_SENTINEL(&beam->send_list);
b = APR_BUCKET_NEXT(b)) {
if (b->length == ((apr_size_t)-1)) {
/* do not count */
@@ -243,14 +276,14 @@ static apr_off_t calc_buffered(h2_bucket
return len;
}
-static void r_purge_reds(h2_bucket_beam *beam)
+static void r_purge_sent(h2_bucket_beam *beam)
{
- apr_bucket *bred;
- /* delete all red buckets in purge brigade, needs to be called
- * from red thread only */
- while (!H2_BLIST_EMPTY(&beam->purge)) {
- bred = H2_BLIST_FIRST(&beam->purge);
- apr_bucket_delete(bred);
+ apr_bucket *b;
+ /* delete all sender buckets in purge brigade, needs to be called
+ * from sender thread only */
+ while (!H2_BLIST_EMPTY(&beam->purge_list)) {
+ b = H2_BLIST_FIRST(&beam->purge_list);
+ apr_bucket_delete(b);
}
}
@@ -274,16 +307,18 @@ static apr_status_t wait_cond(h2_bucket_
}
static apr_status_t r_wait_space(h2_bucket_beam *beam, apr_read_type_e block,
- h2_beam_lock *pbl, apr_off_t *premain)
+ h2_beam_lock *pbl, apr_size_t *premain)
{
*premain = calc_space_left(beam);
while (!beam->aborted && *premain <= 0
&& (block == APR_BLOCK_READ) && pbl->mutex) {
- apr_status_t status = wait_cond(beam, pbl->mutex);
+ apr_status_t status;
+ report_production(beam, 1);
+ status = wait_cond(beam, pbl->mutex);
if (APR_STATUS_IS_TIMEUP(status)) {
return status;
}
- r_purge_reds(beam);
+ r_purge_sent(beam);
*premain = calc_space_left(beam);
}
return beam->aborted? APR_ECONNABORTED : APR_SUCCESS;
@@ -298,34 +333,34 @@ static void h2_beam_emitted(h2_bucket_be
/* even when beam buckets are split, only the one where
* refcount drops to 0 will call us */
H2_BPROXY_REMOVE(proxy);
- /* invoked from green thread, the last beam bucket for the red
- * bucket bred is about to be destroyed.
+ /* invoked from receiver thread, the last beam bucket for the send
+ * bucket is about to be destroyed.
* remove it from the hold, where it should be now */
if (proxy->bred) {
- for (b = H2_BLIST_FIRST(&beam->hold);
- b != H2_BLIST_SENTINEL(&beam->hold);
+ for (b = H2_BLIST_FIRST(&beam->hold_list);
+ b != H2_BLIST_SENTINEL(&beam->hold_list);
b = APR_BUCKET_NEXT(b)) {
if (b == proxy->bred) {
break;
}
}
- if (b != H2_BLIST_SENTINEL(&beam->hold)) {
+ if (b != H2_BLIST_SENTINEL(&beam->hold_list)) {
/* bucket is in hold as it should be, mark this one
* and all before it for purging. We might have placed meta
* buckets without a green proxy into the hold before it
* and schedule them for purging now */
- for (b = H2_BLIST_FIRST(&beam->hold);
- b != H2_BLIST_SENTINEL(&beam->hold);
+ for (b = H2_BLIST_FIRST(&beam->hold_list);
+ b != H2_BLIST_SENTINEL(&beam->hold_list);
b = next) {
next = APR_BUCKET_NEXT(b);
if (b == proxy->bred) {
APR_BUCKET_REMOVE(b);
- H2_BLIST_INSERT_TAIL(&beam->purge, b);
+ H2_BLIST_INSERT_TAIL(&beam->purge_list, b);
break;
}
else if (APR_BUCKET_IS_METADATA(b)) {
APR_BUCKET_REMOVE(b);
- H2_BLIST_INSERT_TAIL(&beam->purge, b);
+ H2_BLIST_INSERT_TAIL(&beam->purge_list, b);
}
else {
/* another data bucket before this one in hold. this
@@ -338,16 +373,16 @@ static void h2_beam_emitted(h2_bucket_be
}
else {
/* it should be there unless we screwed up */
- ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, beam->red_pool,
+ ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, beam->send_pool,
APLOGNO(03384) "h2_beam(%d-%s): emitted bucket not "
"in hold, n=%d", beam->id, beam->tag,
(int)proxy->n);
- AP_DEBUG_ASSERT(!proxy->bred);
+ ap_assert(!proxy->bred);
}
}
/* notify anyone waiting on space to become available */
if (!bl.mutex) {
- r_purge_reds(beam);
+ r_purge_sent(beam);
}
else if (beam->m_cond) {
apr_thread_cond_broadcast(beam->m_cond);
@@ -356,28 +391,6 @@ static void h2_beam_emitted(h2_bucket_be
}
}
-static void report_consumption(h2_bucket_beam *beam, int force)
-{
- if (force || beam->received_bytes != beam->reported_consumed_bytes) {
- if (beam->consumed_fn) {
- beam->consumed_fn(beam->consumed_ctx, beam, beam->received_bytes
- - beam->reported_consumed_bytes);
- }
- beam->reported_consumed_bytes = beam->received_bytes;
- }
-}
-
-static void report_production(h2_bucket_beam *beam, int force)
-{
- if (force || beam->sent_bytes != beam->reported_produced_bytes) {
- if (beam->produced_fn) {
- beam->produced_fn(beam->produced_ctx, beam, beam->sent_bytes
- - beam->reported_produced_bytes);
- }
- beam->reported_produced_bytes = beam->sent_bytes;
- }
-}
-
static void h2_blist_cleanup(h2_blist *bl)
{
apr_bucket *e;
@@ -399,13 +412,38 @@ static apr_status_t beam_close(h2_bucket
return APR_SUCCESS;
}
-static apr_status_t beam_cleanup(void *data)
+static void beam_set_send_pool(h2_bucket_beam *beam, apr_pool_t *pool);
+static void beam_set_recv_pool(h2_bucket_beam *beam, apr_pool_t *pool);
+
+static apr_status_t beam_recv_cleanup(void *data)
{
h2_bucket_beam *beam = data;
-
- beam_close(beam);
- r_purge_reds(beam);
- h2_blist_cleanup(&beam->red);
+ /* receiver pool has gone away, clear references */
+ beam->recv_buffer = NULL;
+ beam->recv_pool = NULL;
+ return APR_SUCCESS;
+}
+
+static void beam_set_recv_pool(h2_bucket_beam *beam, apr_pool_t *pool)
+{
+ /* if the beam owner is the sender, monitor receiver pool lifetime */
+ if (beam->owner == H2_BEAM_OWNER_SEND && beam->recv_pool != pool) {
+ if (beam->recv_pool) {
+ apr_pool_cleanup_kill(beam->recv_pool, beam, beam_recv_cleanup);
+ }
+ beam->recv_pool = pool;
+ if (beam->recv_pool) {
+ apr_pool_pre_cleanup_register(beam->recv_pool, beam, beam_recv_cleanup);
+ }
+ }
+}
+
+static apr_status_t beam_send_cleanup(void *data)
+{
+ h2_bucket_beam *beam = data;
+ /* sender has gone away, clear up all references to its memory */
+ r_purge_sent(beam);
+ h2_blist_cleanup(&beam->send_list);
report_consumption(beam, 0);
while (!H2_BPROXY_LIST_EMPTY(&beam->proxies)) {
h2_beam_proxy *proxy = H2_BPROXY_LIST_FIRST(&beam->proxies);
@@ -413,40 +451,101 @@ static apr_status_t beam_cleanup(void *d
proxy->beam = NULL;
proxy->bred = NULL;
}
- h2_blist_cleanup(&beam->purge);
- h2_blist_cleanup(&beam->hold);
-
+ h2_blist_cleanup(&beam->purge_list);
+ h2_blist_cleanup(&beam->hold_list);
+ beam->send_pool = NULL;
return APR_SUCCESS;
}
+static void beam_set_send_pool(h2_bucket_beam *beam, apr_pool_t *pool)
+{
+ /* if the beam owner is the receiver, monitor sender pool lifetime */
+ if (beam->owner == H2_BEAM_OWNER_RECV && beam->send_pool != pool) {
+ if (beam->send_pool) {
+ apr_pool_cleanup_kill(beam->send_pool, beam, beam_send_cleanup);
+ }
+ beam->send_pool = pool;
+ if (beam->send_pool) {
+ apr_pool_pre_cleanup_register(beam->send_pool, beam, beam_send_cleanup);
+ }
+ }
+}
+
+static apr_status_t beam_cleanup(void *data)
+{
+ h2_bucket_beam *beam = data;
+ apr_status_t status = APR_SUCCESS;
+ /* owner of the beam is going away, depending on its role, cleanup
+ * strategies differ. */
+ beam_close(beam);
+ switch (beam->owner) {
+ case H2_BEAM_OWNER_SEND:
+ status = beam_send_cleanup(beam);
+ beam->recv_buffer = NULL;
+ beam->recv_pool = NULL;
+ break;
+ case H2_BEAM_OWNER_RECV:
+ if (beam->recv_buffer) {
+ apr_brigade_destroy(beam->recv_buffer);
+ }
+ beam->recv_buffer = NULL;
+ beam->recv_pool = NULL;
+ if (!H2_BLIST_EMPTY(&beam->send_list)) {
+ ap_assert(beam->send_pool);
+ }
+ if (beam->send_pool) {
+ /* sender has not cleaned up, its pool still lives.
+ * this is normal if the sender uses cleanup via a bucket
+ * such as the BUCKET_EOR for requests. In that case, the
+ * beam should have lost its mutex protection, meaning
+ * it is no longer used multi-threaded and we can safely
+ * purge all remaining sender buckets. */
+ apr_pool_cleanup_kill(beam->send_pool, beam, beam_send_cleanup);
+ ap_assert(!beam->m_enter);
+ beam_send_cleanup(beam);
+ }
+ ap_assert(H2_BPROXY_LIST_EMPTY(&beam->proxies));
+ ap_assert(H2_BLIST_EMPTY(&beam->send_list));
+ ap_assert(H2_BLIST_EMPTY(&beam->hold_list));
+ ap_assert(H2_BLIST_EMPTY(&beam->purge_list));
+ break;
+ default:
+ ap_assert(NULL);
+ break;
+ }
+ return status;
+}
+
apr_status_t h2_beam_destroy(h2_bucket_beam *beam)
{
- apr_pool_cleanup_kill(beam->red_pool, beam, beam_cleanup);
+ apr_pool_cleanup_kill(beam->pool, beam, beam_cleanup);
return beam_cleanup(beam);
}
-apr_status_t h2_beam_create(h2_bucket_beam **pbeam, apr_pool_t *red_pool,
+apr_status_t h2_beam_create(h2_bucket_beam **pbeam, apr_pool_t *pool,
int id, const char *tag,
+ h2_beam_owner_t owner,
apr_size_t max_buf_size)
{
h2_bucket_beam *beam;
apr_status_t status = APR_SUCCESS;
- beam = apr_pcalloc(red_pool, sizeof(*beam));
+ beam = apr_pcalloc(pool, sizeof(*beam));
if (!beam) {
return APR_ENOMEM;
}
beam->id = id;
beam->tag = tag;
- H2_BLIST_INIT(&beam->red);
- H2_BLIST_INIT(&beam->hold);
- H2_BLIST_INIT(&beam->purge);
+ beam->pool = pool;
+ beam->owner = owner;
+ H2_BLIST_INIT(&beam->send_list);
+ H2_BLIST_INIT(&beam->hold_list);
+ H2_BLIST_INIT(&beam->purge_list);
H2_BPROXY_LIST_INIT(&beam->proxies);
- beam->red_pool = red_pool;
beam->max_buf_size = max_buf_size;
+ apr_pool_pre_cleanup_register(pool, beam, beam_cleanup);
- apr_pool_pre_cleanup_register(red_pool, beam, beam_cleanup);
*pbeam = beam;
return status;
@@ -516,10 +615,12 @@ void h2_beam_abort(h2_bucket_beam *beam)
h2_beam_lock bl;
if (enter_yellow(beam, &bl) == APR_SUCCESS) {
- r_purge_reds(beam);
- h2_blist_cleanup(&beam->red);
- beam->aborted = 1;
- report_consumption(beam, 0);
+ if (!beam->aborted) {
+ beam->aborted = 1;
+ r_purge_sent(beam);
+ h2_blist_cleanup(&beam->send_list);
+ report_consumption(beam, 0);
+ }
if (beam->m_cond) {
apr_thread_cond_broadcast(beam->m_cond);
}
@@ -532,7 +633,7 @@ apr_status_t h2_beam_close(h2_bucket_bea
h2_beam_lock bl;
if (enter_yellow(beam, &bl) == APR_SUCCESS) {
- r_purge_reds(beam);
+ r_purge_sent(beam);
beam_close(beam);
report_consumption(beam, 0);
leave_yellow(beam, &bl);
@@ -540,22 +641,15 @@ apr_status_t h2_beam_close(h2_bucket_bea
return beam->aborted? APR_ECONNABORTED : APR_SUCCESS;
}
-apr_status_t h2_beam_shutdown(h2_bucket_beam *beam, apr_read_type_e block,
- int clear_buffers)
+apr_status_t h2_beam_wait_empty(h2_bucket_beam *beam, apr_read_type_e block)
{
apr_status_t status;
h2_beam_lock bl;
if ((status = enter_yellow(beam, &bl)) == APR_SUCCESS) {
- if (clear_buffers) {
- r_purge_reds(beam);
- h2_blist_cleanup(&beam->red);
- }
- beam_close(beam);
-
- while (status == APR_SUCCESS
- && (!H2_BPROXY_LIST_EMPTY(&beam->proxies)
- || (beam->green && !APR_BRIGADE_EMPTY(beam->green)))) {
+ while (status == APR_SUCCESS
+ && !H2_BLIST_EMPTY(&beam->send_list)
+ && !H2_BPROXY_LIST_EMPTY(&beam->proxies)) {
if (block == APR_NONBLOCK_READ || !bl.mutex) {
status = APR_EAGAIN;
break;
@@ -570,39 +664,49 @@ apr_status_t h2_beam_shutdown(h2_bucket_
return status;
}
+static void move_to_hold(h2_bucket_beam *beam,
+ apr_bucket_brigade *red_brigade)
+{
+ apr_bucket *b;
+ while (red_brigade && !APR_BRIGADE_EMPTY(red_brigade)) {
+ b = APR_BRIGADE_FIRST(red_brigade);
+ APR_BUCKET_REMOVE(b);
+ H2_BLIST_INSERT_TAIL(&beam->send_list, b);
+ }
+}
+
static apr_status_t append_bucket(h2_bucket_beam *beam,
- apr_bucket *bred,
+ apr_bucket *b,
apr_read_type_e block,
- apr_pool_t *pool,
h2_beam_lock *pbl)
{
const char *data;
apr_size_t len;
- apr_off_t space_left = 0;
+ apr_size_t space_left = 0;
apr_status_t status;
- if (APR_BUCKET_IS_METADATA(bred)) {
- if (APR_BUCKET_IS_EOS(bred)) {
+ if (APR_BUCKET_IS_METADATA(b)) {
+ if (APR_BUCKET_IS_EOS(b)) {
beam->closed = 1;
}
- APR_BUCKET_REMOVE(bred);
- H2_BLIST_INSERT_TAIL(&beam->red, bred);
+ APR_BUCKET_REMOVE(b);
+ H2_BLIST_INSERT_TAIL(&beam->send_list, b);
return APR_SUCCESS;
}
- else if (APR_BUCKET_IS_FILE(bred)) {
+ else if (APR_BUCKET_IS_FILE(b)) {
/* file bucket lengths do not really count */
}
else {
space_left = calc_space_left(beam);
- if (space_left > 0 && bred->length == ((apr_size_t)-1)) {
+ if (space_left > 0 && b->length == ((apr_size_t)-1)) {
const char *data;
- status = apr_bucket_read(bred, &data, &len, APR_BLOCK_READ);
+ status = apr_bucket_read(b, &data, &len, APR_BLOCK_READ);
if (status != APR_SUCCESS) {
return status;
}
}
- if (space_left < bred->length) {
+ if (space_left < b->length) {
status = r_wait_space(beam, block, pbl, &space_left);
if (status != APR_SUCCESS) {
return status;
@@ -620,33 +724,30 @@ static apr_status_t append_bucket(h2_buc
* its pool/bucket_alloc from a foreign thread and that will
* corrupt. */
status = APR_ENOTIMPL;
- if (beam->closed && bred->length > 0) {
- status = APR_EOF;
- }
- else if (APR_BUCKET_IS_TRANSIENT(bred)) {
+ if (APR_BUCKET_IS_TRANSIENT(b)) {
/* this takes care of transient buckets and converts them
* into heap ones. Other bucket types might or might not be
* affected by this. */
- status = apr_bucket_setaside(bred, pool);
+ status = apr_bucket_setaside(b, beam->send_pool);
}
- else if (APR_BUCKET_IS_HEAP(bred)) {
+ else if (APR_BUCKET_IS_HEAP(b)) {
/* For heap buckets read from a green thread is fine. The
* data will be there and live until the bucket itself is
* destroyed. */
status = APR_SUCCESS;
}
- else if (APR_BUCKET_IS_POOL(bred)) {
+ else if (APR_BUCKET_IS_POOL(b)) {
/* pool buckets are bastards that register at pool cleanup
* to morph themselves into heap buckets. That may happen anytime,
* even after the bucket data pointer has been read. So at
* any time inside the green thread, the pool bucket memory
* may disappear. yikes. */
- status = apr_bucket_read(bred, &data, &len, APR_BLOCK_READ);
+ status = apr_bucket_read(b, &data, &len, APR_BLOCK_READ);
if (status == APR_SUCCESS) {
- apr_bucket_heap_make(bred, data, len, NULL);
+ apr_bucket_heap_make(b, data, len, NULL);
}
}
- else if (APR_BUCKET_IS_FILE(bred)) {
+ else if (APR_BUCKET_IS_FILE(b)) {
/* For file buckets the problem is their internal readpool that
* is used on the first read to allocate buffer/mmap.
* Since setting aside a file bucket will de-register the
@@ -656,14 +757,14 @@ static apr_status_t append_bucket(h2_buc
* handles across. The use case for this is to limit the number
* of open file handles and rather use a less efficient beam
* transport. */
- apr_file_t *fd = ((apr_bucket_file *)bred->data)->fd;
+ apr_file_t *fd = ((apr_bucket_file *)b->data)->fd;
int can_beam = 1;
if (beam->last_beamed != fd && beam->can_beam_fn) {
can_beam = beam->can_beam_fn(beam->can_beam_ctx, beam, fd);
}
if (can_beam) {
beam->last_beamed = fd;
- status = apr_bucket_setaside(bred, pool);
+ status = apr_bucket_setaside(b, beam->send_pool);
}
/* else: enter ENOTIMPL case below */
}
@@ -678,12 +779,12 @@ static apr_status_t append_bucket(h2_buc
if (space_left < APR_BUCKET_BUFF_SIZE) {
space_left = APR_BUCKET_BUFF_SIZE;
}
- if (space_left < bred->length) {
- apr_bucket_split(bred, space_left);
+ if (space_left < b->length) {
+ apr_bucket_split(b, space_left);
}
- status = apr_bucket_read(bred, &data, &len, APR_BLOCK_READ);
+ status = apr_bucket_read(b, &data, &len, APR_BLOCK_READ);
if (status == APR_SUCCESS) {
- status = apr_bucket_setaside(bred, pool);
+ status = apr_bucket_setaside(b, beam->send_pool);
}
}
@@ -691,9 +792,9 @@ static apr_status_t append_bucket(h2_buc
return status;
}
- APR_BUCKET_REMOVE(bred);
- H2_BLIST_INSERT_TAIL(&beam->red, bred);
- beam->sent_bytes += bred->length;
+ APR_BUCKET_REMOVE(b);
+ H2_BLIST_INSERT_TAIL(&beam->send_list, b);
+ beam->sent_bytes += b->length;
return APR_SUCCESS;
}
@@ -702,23 +803,27 @@ apr_status_t h2_beam_send(h2_bucket_beam
apr_bucket_brigade *red_brigade,
apr_read_type_e block)
{
- apr_bucket *bred;
+ apr_bucket *b;
apr_status_t status = APR_SUCCESS;
h2_beam_lock bl;
/* Called from the red thread to add buckets to the beam */
if (enter_yellow(beam, &bl) == APR_SUCCESS) {
- r_purge_reds(beam);
+ r_purge_sent(beam);
+ if (red_brigade) {
+ beam_set_send_pool(beam, red_brigade->p);
+ }
if (beam->aborted) {
+ move_to_hold(beam, red_brigade);
status = APR_ECONNABORTED;
}
else if (red_brigade) {
int force_report = !APR_BRIGADE_EMPTY(red_brigade);
while (!APR_BRIGADE_EMPTY(red_brigade)
&& status == APR_SUCCESS) {
- bred = APR_BRIGADE_FIRST(red_brigade);
- status = append_bucket(beam, bred, block, beam->red_pool, &bl);
+ b = APR_BRIGADE_FIRST(red_brigade);
+ status = append_bucket(beam, b, block, &bl);
}
report_production(beam, force_report);
if (beam->m_cond) {
@@ -746,18 +851,19 @@ apr_status_t h2_beam_receive(h2_bucket_b
if (enter_yellow(beam, &bl) == APR_SUCCESS) {
transfer:
if (beam->aborted) {
- if (beam->green && !APR_BRIGADE_EMPTY(beam->green)) {
- apr_brigade_cleanup(beam->green);
+ if (beam->recv_buffer && !APR_BRIGADE_EMPTY(beam->recv_buffer)) {
+ apr_brigade_cleanup(beam->recv_buffer);
}
status = APR_ECONNABORTED;
goto leave;
}
/* transfer enough buckets from our green brigade, if we have one */
- while (beam->green
- && !APR_BRIGADE_EMPTY(beam->green)
+ beam_set_recv_pool(beam, bb->p);
+ while (beam->recv_buffer
+ && !APR_BRIGADE_EMPTY(beam->recv_buffer)
&& (readbytes <= 0 || remain >= 0)) {
- bgreen = APR_BRIGADE_FIRST(beam->green);
+ bgreen = APR_BRIGADE_FIRST(beam->recv_buffer);
if (readbytes > 0 && bgreen->length > 0 && remain <= 0) {
break;
}
@@ -769,8 +875,8 @@ transfer:
/* transfer from our red brigade, transforming red buckets to
* green ones until we have enough */
- while (!H2_BLIST_EMPTY(&beam->red) && (readbytes <= 0 || remain >= 0)) {
- bred = H2_BLIST_FIRST(&beam->red);
+ while (!H2_BLIST_EMPTY(&beam->send_list) && (readbytes <= 0 || remain >= 0)) {
+ bred = H2_BLIST_FIRST(&beam->send_list);
bgreen = NULL;
if (readbytes > 0 && bred->length > 0 && remain <= 0) {
@@ -785,8 +891,10 @@ transfer:
else if (APR_BUCKET_IS_FLUSH(bred)) {
bgreen = apr_bucket_flush_create(bb->bucket_alloc);
}
- else {
- /* put red into hold, no green sent out */
+ else if (AP_BUCKET_IS_ERROR(bred)) {
+ ap_bucket_error *eb = (ap_bucket_error *)bred;
+ bgreen = ap_bucket_error_create(eb->status, eb->data,
+ bb->p, bb->bucket_alloc);
}
}
else if (APR_BUCKET_IS_FILE(bred)) {
@@ -815,7 +923,7 @@ transfer:
remain -= bred->length;
++transferred;
APR_BUCKET_REMOVE(bred);
- H2_BLIST_INSERT_TAIL(&beam->hold, bred);
+ H2_BLIST_INSERT_TAIL(&beam->hold_list, bred);
++transferred;
continue;
}
@@ -832,13 +940,21 @@ transfer:
/* Place the red bucket into our hold, to be destroyed when no
* green bucket references it any more. */
APR_BUCKET_REMOVE(bred);
- H2_BLIST_INSERT_TAIL(&beam->hold, bred);
+ H2_BLIST_INSERT_TAIL(&beam->hold_list, bred);
beam->received_bytes += bred->length;
if (bgreen) {
APR_BRIGADE_INSERT_TAIL(bb, bgreen);
remain -= bgreen->length;
++transferred;
}
+ else {
+ bgreen = h2_beam_bucket(beam, bb, bred);
+ while (bgreen && bgreen != APR_BRIGADE_SENTINEL(bb)) {
+ ++transferred;
+ remain -= bgreen->length;
+ bgreen = APR_BUCKET_NEXT(bgreen);
+ }
+ }
}
if (readbytes > 0 && remain < 0) {
@@ -850,17 +966,17 @@ transfer:
remain -= bgreen->length;
if (remain < 0) {
apr_bucket_split(bgreen, bgreen->length+remain);
- beam->green = apr_brigade_split_ex(bb,
+ beam->recv_buffer = apr_brigade_split_ex(bb,
APR_BUCKET_NEXT(bgreen),
- beam->green);
+ beam->recv_buffer);
break;
}
}
}
if (beam->closed
- && (!beam->green || APR_BRIGADE_EMPTY(beam->green))
- && H2_BLIST_EMPTY(&beam->red)) {
+ && (!beam->recv_buffer || APR_BRIGADE_EMPTY(beam->recv_buffer))
+ && H2_BLIST_EMPTY(&beam->send_list)) {
/* beam is closed and we have nothing more to receive */
if (!beam->close_sent) {
apr_bucket *b = apr_bucket_eos_create(bb->bucket_alloc);
@@ -872,6 +988,9 @@ transfer:
}
if (transferred) {
+ if (beam->m_cond) {
+ apr_thread_cond_broadcast(beam->m_cond);
+ }
status = APR_SUCCESS;
}
else if (beam->closed) {
@@ -885,6 +1004,9 @@ transfer:
goto transfer;
}
else {
+ if (beam->m_cond) {
+ apr_thread_cond_broadcast(beam->m_cond);
+ }
status = APR_EAGAIN;
}
leave:
@@ -937,8 +1059,8 @@ apr_off_t h2_beam_get_buffered(h2_bucket
h2_beam_lock bl;
if (enter_yellow(beam, &bl) == APR_SUCCESS) {
- for (b = H2_BLIST_FIRST(&beam->red);
- b != H2_BLIST_SENTINEL(&beam->red);
+ for (b = H2_BLIST_FIRST(&beam->send_list);
+ b != H2_BLIST_SENTINEL(&beam->send_list);
b = APR_BUCKET_NEXT(b)) {
/* should all have determinate length */
l += b->length;
@@ -955,8 +1077,8 @@ apr_off_t h2_beam_get_mem_used(h2_bucket
h2_beam_lock bl;
if (enter_yellow(beam, &bl) == APR_SUCCESS) {
- for (b = H2_BLIST_FIRST(&beam->red);
- b != H2_BLIST_SENTINEL(&beam->red);
+ for (b = H2_BLIST_FIRST(&beam->send_list);
+ b != H2_BLIST_SENTINEL(&beam->send_list);
b = APR_BUCKET_NEXT(b)) {
if (APR_BUCKET_IS_FILE(b)) {
/* do not count */
@@ -977,16 +1099,23 @@ int h2_beam_empty(h2_bucket_beam *beam)
h2_beam_lock bl;
if (enter_yellow(beam, &bl) == APR_SUCCESS) {
- empty = (H2_BLIST_EMPTY(&beam->red)
- && (!beam->green || APR_BRIGADE_EMPTY(beam->green)));
+ empty = (H2_BLIST_EMPTY(&beam->send_list)
+ && (!beam->recv_buffer || APR_BRIGADE_EMPTY(beam->recv_buffer)));
leave_yellow(beam, &bl);
}
return empty;
}
-int h2_beam_closed(h2_bucket_beam *beam)
+int h2_beam_holds_proxies(h2_bucket_beam *beam)
{
- return beam->closed;
+ int has_proxies = 1;
+ h2_beam_lock bl;
+
+ if (enter_yellow(beam, &bl) == APR_SUCCESS) {
+ has_proxies = !H2_BPROXY_LIST_EMPTY(&beam->proxies);
+ leave_yellow(beam, &bl);
+ }
+ return has_proxies;
}
int h2_beam_was_received(h2_bucket_beam *beam)
Modified: httpd/httpd/branches/2.4.x-openssl-1.1.0-compat/modules/http2/h2_bucket_beam.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x-openssl-1.1.0-compat/modules/http2/h2_bucket_beam.h?rev=1769588&r1=1769587&r2=1769588&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x-openssl-1.1.0-compat/modules/http2/h2_bucket_beam.h (original)
+++ httpd/httpd/branches/2.4.x-openssl-1.1.0-compat/modules/http2/h2_bucket_beam.h Mon Nov 14 10:26:31 2016
@@ -88,7 +88,7 @@ apr_size_t h2_util_bl_print(char *buffer
* Care needs to be taken when terminating the beam. The beam registers at
* the pool it was created with and will cleanup after itself. However, if
* received buckets do still exist, already freed memory might be accessed.
- * The beam does a AP_DEBUG_ASSERT on this condition.
+ * The beam does a assertion on this condition.
*
* The proper way of shutting down a beam is to first make sure there are no
* more green buckets out there, then cleanup the beam to purge eventually
@@ -163,6 +163,11 @@ typedef struct {
typedef int h2_beam_can_beam_callback(void *ctx, h2_bucket_beam *beam,
apr_file_t *file);
+typedef enum {
+ H2_BEAM_OWNER_SEND,
+ H2_BEAM_OWNER_RECV
+} h2_beam_owner_t;
+
/**
* Will deny all transfer of apr_file_t across the beam and force
* a data copy instead.
@@ -172,12 +177,15 @@ int h2_beam_no_files(void *ctx, h2_bucke
struct h2_bucket_beam {
int id;
const char *tag;
- h2_blist red;
- h2_blist hold;
- h2_blist purge;
- apr_bucket_brigade *green;
+ apr_pool_t *pool;
+ h2_beam_owner_t owner;
+ h2_blist send_list;
+ h2_blist hold_list;
+ h2_blist purge_list;
+ apr_bucket_brigade *recv_buffer;
h2_bproxy_list proxies;
- apr_pool_t *red_pool;
+ apr_pool_t *send_pool;
+ apr_pool_t *recv_pool;
apr_size_t max_buf_size;
apr_interval_time_t timeout;
@@ -214,22 +222,23 @@ struct h2_bucket_beam {
* mutex and will be used in multiple threads. It needs a pool allocator
* that is only used inside that same mutex.
*
- * @param pbeam will hold the created beam on return
- * @param red_pool pool usable on red side, beam lifeline
+ * @param pbeam will hold the created beam on return
+ * @param pool pool owning the beam, beam will cleanup when pool released
+ * @param id identifier of the beam
+ * @param tag tag identifying beam for logging
+ * @param owner if the beam is owned by the sender or receiver, e.g. if
+ * the pool owner is using this beam for sending or receiving
* @param buffer_size maximum memory footprint of buckets buffered in beam, or
* 0 for no limitation
- *
- * Call from the red side only.
*/
apr_status_t h2_beam_create(h2_bucket_beam **pbeam,
- apr_pool_t *red_pool,
- int id, const char *tag,
+ apr_pool_t *pool,
+ int id, const char *tag,
+ h2_beam_owner_t owner,
apr_size_t buffer_size);
/**
* Destroys the beam immediately without cleanup.
- *
- * Call from the red side only.
*/
apr_status_t h2_beam_destroy(h2_bucket_beam *beam);
@@ -239,10 +248,10 @@ apr_status_t h2_beam_destroy(h2_bucket_b
* All accepted buckets are removed from the given brigade. Will return with
* APR_EAGAIN on non-blocking sends when not all buckets could be accepted.
*
- * Call from the red side only.
+ * Call from the sender side only.
*/
apr_status_t h2_beam_send(h2_bucket_beam *beam,
- apr_bucket_brigade *red_buckets,
+ apr_bucket_brigade *bb,
apr_read_type_e block);
/**
@@ -251,7 +260,7 @@ apr_status_t h2_beam_send(h2_bucket_beam
* available or the beam has been closed. Non-blocking calls return APR_EAGAIN
* if no data is available.
*
- * Call from the green side only.
+ * Call from the receiver side only.
*/
apr_status_t h2_beam_receive(h2_bucket_beam *beam,
apr_bucket_brigade *green_buckets,
@@ -259,31 +268,27 @@ apr_status_t h2_beam_receive(h2_bucket_b
apr_off_t readbytes);
/**
- * Determine if beam is closed. May still contain buffered data.
- *
- * Call from red or green side.
+ * Determine if beam is empty.
*/
-int h2_beam_closed(h2_bucket_beam *beam);
+int h2_beam_empty(h2_bucket_beam *beam);
/**
- * Determine if beam is empty.
- *
- * Call from red or green side.
+ * Determine if beam has handed out proxy buckets that are not destroyed.
*/
-int h2_beam_empty(h2_bucket_beam *beam);
+int h2_beam_holds_proxies(h2_bucket_beam *beam);
/**
* Abort the beam. Will cleanup any buffered buckets and answer all send
* and receives with APR_ECONNABORTED.
*
- * Call from the red side only.
+ * Call from the sender side only.
*/
void h2_beam_abort(h2_bucket_beam *beam);
/**
* Close the beam. Sending an EOS bucket serves the same purpose.
*
- * Call from the red side only.
+ * Call from the sender side only.
*/
apr_status_t h2_beam_close(h2_bucket_beam *beam);
@@ -295,10 +300,9 @@ apr_status_t h2_beam_close(h2_bucket_bea
* If a timeout is set on the beam, waiting might also time out and
* return APR_ETIMEUP.
*
- * Call from the red side only.
+ * Call from the sender side only.
*/
-apr_status_t h2_beam_shutdown(h2_bucket_beam *beam, apr_read_type_e block,
- int clear_buffers);
+apr_status_t h2_beam_wait_empty(h2_bucket_beam *beam, apr_read_type_e block);
void h2_beam_mutex_set(h2_bucket_beam *beam,
h2_beam_mutex_enter m_enter,
@@ -321,27 +325,27 @@ void h2_beam_buffer_size_set(h2_bucket_b
apr_size_t h2_beam_buffer_size_get(h2_bucket_beam *beam);
/**
- * Register a callback to be invoked on the red side with the
- * amount of bytes that have been consumed by the red side, since the
+ * Register a callback to be invoked on the sender side with the
+ * amount of bytes that have been consumed by the receiver, since the
* last callback invocation or reset.
* @param beam the beam to set the callback on
* @param cb the callback or NULL
* @param ctx the context to use in callback invocation
*
- * Call from the red side, callbacks invoked on red side.
+ * Call from the sender side, callbacks invoked on sender side.
*/
void h2_beam_on_consumed(h2_bucket_beam *beam,
h2_beam_io_callback *cb, void *ctx);
/**
- * Register a callback to be invoked on the red side with the
- * amount of bytes that have been consumed by the red side, since the
+ * Register a callback to be invoked on the receiver side with the
+ * amount of bytes that have been produces by the sender, since the
* last callback invocation or reset.
* @param beam the beam to set the callback on
* @param cb the callback or NULL
* @param ctx the context to use in callback invocation
*
- * Call from the red side, callbacks invoked on red side.
+ * Call from the receiver side, callbacks invoked on receiver side.
*/
void h2_beam_on_produced(h2_bucket_beam *beam,
h2_beam_io_callback *cb, void *ctx);
@@ -366,4 +370,10 @@ int h2_beam_was_received(h2_bucket_beam
apr_size_t h2_beam_get_files_beamed(h2_bucket_beam *beam);
+typedef apr_bucket *h2_bucket_beamer(h2_bucket_beam *beam,
+ apr_bucket_brigade *dest,
+ const apr_bucket *src);
+
+void h2_register_bucket_beamer(h2_bucket_beamer *beamer);
+
#endif /* h2_bucket_beam_h */
Modified: httpd/httpd/branches/2.4.x-openssl-1.1.0-compat/modules/http2/h2_config.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x-openssl-1.1.0-compat/modules/http2/h2_config.c?rev=1769588&r1=1769587&r2=1769588&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x-openssl-1.1.0-compat/modules/http2/h2_config.c (original)
+++ httpd/httpd/branches/2.4.x-openssl-1.1.0-compat/modules/http2/h2_config.c Mon Nov 14 10:26:31 2016
@@ -198,7 +198,7 @@ const h2_config *h2_config_sget(server_r
{
h2_config *cfg = (h2_config *)ap_get_module_config(s->module_config,
&http2_module);
- AP_DEBUG_ASSERT(cfg);
+ ap_assert(cfg);
return cfg;
}
Modified: httpd/httpd/branches/2.4.x-openssl-1.1.0-compat/modules/http2/h2_conn.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x-openssl-1.1.0-compat/modules/http2/h2_conn.c?rev=1769588&r1=1769587&r2=1769588&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x-openssl-1.1.0-compat/modules/http2/h2_conn.c (original)
+++ httpd/httpd/branches/2.4.x-openssl-1.1.0-compat/modules/http2/h2_conn.c Mon Nov 14 10:26:31 2016
@@ -14,6 +14,7 @@
*/
#include <assert.h>
+#include <apr_strings.h>
#include <ap_mpm.h>
@@ -240,14 +241,14 @@ apr_status_t h2_conn_pre_close(struct h2
return status;
}
-conn_rec *h2_slave_create(conn_rec *master, apr_pool_t *parent,
- apr_allocator_t *allocator)
+conn_rec *h2_slave_create(conn_rec *master, int slave_id, apr_pool_t *parent)
{
+ apr_allocator_t *allocator;
apr_pool_t *pool;
conn_rec *c;
void *cfg;
- AP_DEBUG_ASSERT(master);
+ ap_assert(master);
ap_log_cerror(APLOG_MARK, APLOG_TRACE3, 0, master,
"h2_conn(%ld): create slave", master->id);
@@ -256,9 +257,7 @@ conn_rec *h2_slave_create(conn_rec *mast
* independant of its parent pool in the sense that it can work in
* another thread.
*/
- if (!allocator) {
- apr_allocator_create(&allocator);
- }
+ apr_allocator_create(&allocator);
apr_pool_create_ex(&pool, parent, NULL, allocator);
apr_pool_tag(pool, "h2_slave_conn");
apr_allocator_owner_set(allocator, pool);
@@ -271,8 +270,7 @@ conn_rec *h2_slave_create(conn_rec *mast
}
memcpy(c, master, sizeof(conn_rec));
-
- /* Replace these */
+
c->master = master;
c->pool = pool;
c->conn_config = ap_create_conn_config(pool);
@@ -284,7 +282,8 @@ conn_rec *h2_slave_create(conn_rec *mast
c->data_in_output_filters = 0;
c->clogging_input_filters = 1;
c->log = NULL;
- c->log_id = NULL;
+ c->log_id = apr_psprintf(pool, "%ld-%d",
+ master->id, slave_id);
/* Simulate that we had already a request on this connection. */
c->keepalives = 1;
/* We cannot install the master connection socket on the slaves, as
@@ -304,24 +303,17 @@ conn_rec *h2_slave_create(conn_rec *mast
ap_set_module_config(c->conn_config, h2_conn_mpm_module(), cfg);
}
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c,
+ "h2_task: creating conn, master=%ld, sid=%ld, logid=%s",
+ master->id, c->id, c->log_id);
return c;
}
-void h2_slave_destroy(conn_rec *slave, apr_allocator_t **pallocator)
+void h2_slave_destroy(conn_rec *slave)
{
- apr_pool_t *parent;
- apr_allocator_t *allocator = apr_pool_allocator_get(slave->pool);
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, slave,
"h2_slave_conn(%ld): destroy (task=%s)", slave->id,
apr_table_get(slave->notes, H2_TASK_ID_NOTE));
- /* Attache the allocator to the parent pool and return it for
- * reuse, otherwise the own is still the slave pool and it will
- * get destroyed with it. */
- parent = apr_pool_parent_get(slave->pool);
- if (pallocator && parent) {
- apr_allocator_owner_set(allocator, parent);
- *pallocator = allocator;
- }
apr_pool_destroy(slave->pool);
}
Modified: httpd/httpd/branches/2.4.x-openssl-1.1.0-compat/modules/http2/h2_conn.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x-openssl-1.1.0-compat/modules/http2/h2_conn.h?rev=1769588&r1=1769587&r2=1769588&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x-openssl-1.1.0-compat/modules/http2/h2_conn.h (original)
+++ httpd/httpd/branches/2.4.x-openssl-1.1.0-compat/modules/http2/h2_conn.h Mon Nov 14 10:26:31 2016
@@ -31,7 +31,7 @@ apr_status_t h2_conn_setup(struct h2_ctx
/**
* Run the HTTP/2 connection in synchronous fashion.
* Return when the HTTP/2 session is done
- * and the connection will close or a fatal error occured.
+ * and the connection will close or a fatal error occurred.
*
* @param ctx the http2 context to run
* @return APR_SUCCESS when session is done.
@@ -66,9 +66,8 @@ typedef enum {
h2_mpm_type_t h2_conn_mpm_type(void);
-conn_rec *h2_slave_create(conn_rec *master, apr_pool_t *parent,
- apr_allocator_t *allocator);
-void h2_slave_destroy(conn_rec *slave, apr_allocator_t **pallocator);
+conn_rec *h2_slave_create(conn_rec *master, int slave_id, apr_pool_t *parent);
+void h2_slave_destroy(conn_rec *slave);
apr_status_t h2_slave_run_pre_connection(conn_rec *slave, apr_socket_t *csd);
void h2_slave_run_connection(conn_rec *slave);
Modified: httpd/httpd/branches/2.4.x-openssl-1.1.0-compat/modules/http2/h2_conn_io.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x-openssl-1.1.0-compat/modules/http2/h2_conn_io.c?rev=1769588&r1=1769587&r2=1769588&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x-openssl-1.1.0-compat/modules/http2/h2_conn_io.c (original)
+++ httpd/httpd/branches/2.4.x-openssl-1.1.0-compat/modules/http2/h2_conn_io.c Mon Nov 14 10:26:31 2016
@@ -120,8 +120,8 @@ static void h2_conn_io_bb_log(conn_rec *
line = *buffer? buffer : "(empty)";
}
/* Intentional no APLOGNO */
- ap_log_cerror(APLOG_MARK, level, 0, c, "bb_dump(%ld-%d)-%s: %s",
- c->id, stream_id, tag, line);
+ ap_log_cerror(APLOG_MARK, level, 0, c, "bb_dump(%s)-%s: %s",
+ c->log_id, tag, line);
}
@@ -132,7 +132,7 @@ apr_status_t h2_conn_io_init(h2_conn_io
io->output = apr_brigade_create(c->pool, c->bucket_alloc);
io->is_tls = h2_h2_is_tls(c);
io->buffer_output = io->is_tls;
- io->pass_threshold = h2_config_geti64(cfg, H2_CONF_STREAM_MAX_MEM) / 2;
+ io->pass_threshold = (apr_size_t)h2_config_geti64(cfg, H2_CONF_STREAM_MAX_MEM) / 2;
if (io->is_tls) {
/* This is what we start with,
@@ -206,7 +206,7 @@ static apr_status_t read_to_scratch(h2_c
return APR_SUCCESS;
}
- AP_DEBUG_ASSERT(b->length <= (io->ssize - io->slen));
+ ap_assert(b->length <= (io->ssize - io->slen));
if (APR_BUCKET_IS_FILE(b)) {
apr_bucket_file *f = (apr_bucket_file *)b->data;
apr_file_t *fd = f->fd;
@@ -269,9 +269,11 @@ static void check_write_size(h2_conn_io
}
}
-static apr_status_t pass_output(h2_conn_io *io, int flush, int eoc)
+static apr_status_t pass_output(h2_conn_io *io, int flush,
+ h2_session *session_eoc)
{
conn_rec *c = io->c;
+ apr_bucket_brigade *bb = io->output;
apr_bucket *b;
apr_off_t bblen;
apr_status_t status;
@@ -279,28 +281,37 @@ static apr_status_t pass_output(h2_conn_
append_scratch(io);
if (flush) {
b = apr_bucket_flush_create(c->bucket_alloc);
- APR_BRIGADE_INSERT_TAIL(io->output, b);
+ APR_BRIGADE_INSERT_TAIL(bb, b);
}
- if (APR_BRIGADE_EMPTY(io->output)) {
+ if (APR_BRIGADE_EMPTY(bb)) {
return APR_SUCCESS;
}
ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, c, "h2_conn_io: pass_output");
ap_update_child_status(c->sbh, SERVER_BUSY_WRITE, NULL);
- apr_brigade_length(io->output, 0, &bblen);
+ apr_brigade_length(bb, 0, &bblen);
- h2_conn_io_bb_log(c, 0, APLOG_TRACE2, "master conn pass", io->output);
- status = ap_pass_brigade(c->output_filters, io->output);
+ h2_conn_io_bb_log(c, 0, APLOG_TRACE2, "master conn pass", bb);
+ status = ap_pass_brigade(c->output_filters, bb);
+ if (status == APR_SUCCESS) {
+ io->bytes_written += (apr_size_t)bblen;
+ io->last_write = apr_time_now();
+ }
+ apr_brigade_cleanup(bb);
- /* careful with access after this, as we might have flushed an EOC bucket
- * that de-allocated us all. */
- if (!eoc) {
- apr_brigade_cleanup(io->output);
+ if (session_eoc) {
+ apr_status_t tmp;
+ b = h2_bucket_eoc_create(c->bucket_alloc, session_eoc);
+ APR_BRIGADE_INSERT_TAIL(bb, b);
+ h2_conn_io_bb_log(c, 0, APLOG_TRACE2, "master conn pass", bb);
+ tmp = ap_pass_brigade(c->output_filters, bb);
if (status == APR_SUCCESS) {
- io->bytes_written += (apr_size_t)bblen;
- io->last_write = apr_time_now();
+ status = tmp;
}
+ /* careful with access to io after this, we have flushed an EOC bucket
+ * that de-allocated us all. */
+ apr_brigade_cleanup(bb);
}
if (status != APR_SUCCESS) {
@@ -313,14 +324,12 @@ static apr_status_t pass_output(h2_conn_
apr_status_t h2_conn_io_flush(h2_conn_io *io)
{
- return pass_output(io, 1, 0);
+ return pass_output(io, 1, NULL);
}
apr_status_t h2_conn_io_write_eoc(h2_conn_io *io, h2_session *session)
{
- apr_bucket *b = h2_bucket_eoc_create(io->c->bucket_alloc, session);
- APR_BRIGADE_INSERT_TAIL(io->output, b);
- return pass_output(io, 1, 1);
+ return pass_output(io, 1, session);
}
apr_status_t h2_conn_io_write(h2_conn_io *io, const char *data, size_t length)
@@ -413,7 +422,7 @@ apr_status_t h2_conn_io_pass(h2_conn_io
if (!APR_BRIGADE_EMPTY(io->output)) {
apr_off_t len = h2_brigade_mem_size(io->output);
if (len >= io->pass_threshold) {
- return pass_output(io, 0, 0);
+ return pass_output(io, 0, NULL);
}
}
}
Modified: httpd/httpd/branches/2.4.x-openssl-1.1.0-compat/modules/http2/h2_ctx.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x-openssl-1.1.0-compat/modules/http2/h2_ctx.c?rev=1769588&r1=1769587&r2=1769588&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x-openssl-1.1.0-compat/modules/http2/h2_ctx.c (original)
+++ httpd/httpd/branches/2.4.x-openssl-1.1.0-compat/modules/http2/h2_ctx.c Mon Nov 14 10:26:31 2016
@@ -27,7 +27,7 @@
static h2_ctx *h2_ctx_create(const conn_rec *c)
{
h2_ctx *ctx = apr_pcalloc(c->pool, sizeof(h2_ctx));
- AP_DEBUG_ASSERT(ctx);
+ ap_assert(ctx);
ap_set_module_config(c->conn_config, &http2_module, ctx);
h2_ctx_server_set(ctx, c->base_server);
return ctx;
@@ -35,7 +35,7 @@ static h2_ctx *h2_ctx_create(const conn_
void h2_ctx_clear(const conn_rec *c)
{
- AP_DEBUG_ASSERT(c);
+ ap_assert(c);
ap_set_module_config(c->conn_config, &http2_module, NULL);
}
Modified: httpd/httpd/branches/2.4.x-openssl-1.1.0-compat/modules/http2/h2_filter.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x-openssl-1.1.0-compat/modules/http2/h2_filter.c?rev=1769588&r1=1769587&r2=1769588&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x-openssl-1.1.0-compat/modules/http2/h2_filter.c (original)
+++ httpd/httpd/branches/2.4.x-openssl-1.1.0-compat/modules/http2/h2_filter.c Mon Nov 14 10:26:31 2016
@@ -15,14 +15,17 @@
#include <assert.h>
+#include <apr_strings.h>
#include <httpd.h>
#include <http_core.h>
+#include <http_protocol.h>
#include <http_log.h>
#include <http_connection.h>
#include <scoreboard.h>
#include "h2_private.h"
#include "h2.h"
+#include "h2_config.h"
#include "h2_conn_io.h"
#include "h2_ctx.h"
#include "h2_mplx.h"
@@ -30,7 +33,8 @@
#include "h2_task.h"
#include "h2_stream.h"
#include "h2_request.h"
-#include "h2_response.h"
+#include "h2_headers.h"
+#include "h2_stream.h"
#include "h2_session.h"
#include "h2_util.h"
#include "h2_version.h"
@@ -171,30 +175,92 @@ apr_status_t h2_filter_core_input(ap_fil
* http2 connection status handler + stream out source
******************************************************************************/
-static const char *H2_SOS_H2_STATUS = "http2-status";
+typedef struct {
+ apr_bucket_refcount refcount;
+ h2_bucket_event_cb *cb;
+ void *ctx;
+} h2_bucket_observer;
+
+static apr_status_t bucket_read(apr_bucket *b, const char **str,
+ apr_size_t *len, apr_read_type_e block)
+{
+ (void)b;
+ (void)block;
+ *str = NULL;
+ *len = 0;
+ return APR_SUCCESS;
+}
-int h2_filter_h2_status_handler(request_rec *r)
+static void bucket_destroy(void *data)
{
- h2_ctx *ctx = h2_ctx_rget(r);
- h2_task *task;
-
- if (strcmp(r->handler, "http2-status")) {
- return DECLINED;
+ h2_bucket_observer *h = data;
+ if (apr_bucket_shared_destroy(h)) {
+ if (h->cb) {
+ h->cb(h->ctx, H2_BUCKET_EV_BEFORE_DESTROY, NULL);
+ }
+ apr_bucket_free(h);
}
- if (r->method_number != M_GET) {
- return DECLINED;
+}
+
+apr_bucket * h2_bucket_observer_make(apr_bucket *b, h2_bucket_event_cb *cb,
+ void *ctx)
+{
+ h2_bucket_observer *br;
+
+ br = apr_bucket_alloc(sizeof(*br), b->list);
+ br->cb = cb;
+ br->ctx = ctx;
+
+ b = apr_bucket_shared_make(b, br, 0, 0);
+ b->type = &h2_bucket_type_observer;
+ return b;
+}
+
+apr_bucket * h2_bucket_observer_create(apr_bucket_alloc_t *list,
+ h2_bucket_event_cb *cb, void *ctx)
+{
+ apr_bucket *b = apr_bucket_alloc(sizeof(*b), list);
+
+ APR_BUCKET_INIT(b);
+ b->free = apr_bucket_free;
+ b->list = list;
+ b = h2_bucket_observer_make(b, cb, ctx);
+ return b;
+}
+
+apr_status_t h2_bucket_observer_fire(apr_bucket *b, h2_bucket_event event)
+{
+ if (H2_BUCKET_IS_OBSERVER(b)) {
+ h2_bucket_observer *l = (h2_bucket_observer *)b->data;
+ return l->cb(l->ctx, event, b);
}
+ return APR_EINVAL;
+}
- task = ctx? h2_ctx_get_task(ctx) : NULL;
- if (task) {
- /* We need to handle the actual output on the main thread, as
- * we need to access h2_session information. */
- apr_table_setn(r->notes, H2_RESP_SOS_NOTE, H2_SOS_H2_STATUS);
- apr_table_setn(r->headers_out, "Content-Type", "application/json");
- r->status = 200;
- return DONE;
+const apr_bucket_type_t h2_bucket_type_observer = {
+ "H2OBS", 5, APR_BUCKET_METADATA,
+ bucket_destroy,
+ bucket_read,
+ apr_bucket_setaside_noop,
+ apr_bucket_split_notimpl,
+ apr_bucket_shared_copy
+};
+
+apr_bucket *h2_bucket_observer_beam(struct h2_bucket_beam *beam,
+ apr_bucket_brigade *dest,
+ const apr_bucket *src)
+{
+ if (H2_BUCKET_IS_OBSERVER(src)) {
+ h2_bucket_observer *l = (h2_bucket_observer *)src->data;
+ apr_bucket *b = h2_bucket_observer_create(dest->bucket_alloc,
+ l->cb, l->ctx);
+ APR_BRIGADE_INSERT_TAIL(dest, b);
+ l->cb = NULL;
+ l->ctx = NULL;
+ h2_bucket_observer_fire(b, H2_BUCKET_EV_BEFORE_MASTER_SEND);
+ return b;
}
- return DECLINED;
+ return NULL;
}
static apr_status_t bbout(apr_bucket_brigade *bb, const char *fmt, ...)
@@ -209,82 +275,257 @@ static apr_status_t bbout(apr_bucket_bri
return rv;
}
-static apr_status_t h2_status_stream_filter(h2_stream *stream)
+static void add_settings(apr_bucket_brigade *bb, h2_session *s, int last)
{
- h2_session *session = stream->session;
- h2_mplx *mplx = session->mplx;
- conn_rec *c = session->c;
- h2_push_diary *diary;
- apr_bucket_brigade *bb;
- apr_status_t status;
+ h2_mplx *m = s->mplx;
- if (!stream->response) {
- return APR_EINVAL;
- }
-
- if (!stream->buffer) {
- stream->buffer = apr_brigade_create(stream->pool, c->bucket_alloc);
- }
- bb = stream->buffer;
+ bbout(bb, " \"settings\": {\n");
+ bbout(bb, " \"SETTINGS_MAX_CONCURRENT_STREAMS\": %d,\n", m->max_streams);
+ bbout(bb, " \"SETTINGS_MAX_FRAME_SIZE\": %d,\n", 16*1024);
+ bbout(bb, " \"SETTINGS_INITIAL_WINDOW_SIZE\": %d,\n",
+ h2_config_geti(s->config, H2_CONF_WIN_SIZE));
+ bbout(bb, " \"SETTINGS_ENABLE_PUSH\": %d\n", h2_session_push_enabled(s));
+ bbout(bb, " }%s\n", last? "" : ",");
+}
+
+static void add_peer_settings(apr_bucket_brigade *bb, h2_session *s, int last)
+{
+ bbout(bb, " \"peerSettings\": {\n");
+ bbout(bb, " \"SETTINGS_MAX_CONCURRENT_STREAMS\": %d,\n",
+ nghttp2_session_get_remote_settings(s->ngh2, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS));
+ bbout(bb, " \"SETTINGS_MAX_FRAME_SIZE\": %d,\n",
+ nghttp2_session_get_remote_settings(s->ngh2, NGHTTP2_SETTINGS_MAX_FRAME_SIZE));
+ bbout(bb, " \"SETTINGS_INITIAL_WINDOW_SIZE\": %d,\n",
+ nghttp2_session_get_remote_settings(s->ngh2, NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE));
+ bbout(bb, " \"SETTINGS_ENABLE_PUSH\": %d,\n",
+ nghttp2_session_get_remote_settings(s->ngh2, NGHTTP2_SETTINGS_ENABLE_PUSH));
+ bbout(bb, " \"SETTINGS_HEADER_TABLE_SIZE\": %d,\n",
+ nghttp2_session_get_remote_settings(s->ngh2, NGHTTP2_SETTINGS_HEADER_TABLE_SIZE));
+ bbout(bb, " \"SETTINGS_MAX_HEADER_LIST_SIZE\": %d\n",
+ nghttp2_session_get_remote_settings(s->ngh2, NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE));
+ bbout(bb, " }%s\n", last? "" : ",");
+}
+
+typedef struct {
+ apr_bucket_brigade *bb;
+ h2_session *s;
+ int idx;
+} stream_ctx_t;
+
+static int add_stream(h2_stream *stream, void *ctx)
+{
+ stream_ctx_t *x = ctx;
+ int32_t flowIn, flowOut;
- apr_table_unset(stream->response->headers, "Content-Length");
- stream->response->content_length = -1;
+ flowIn = nghttp2_session_get_stream_effective_local_window_size(x->s->ngh2, stream->id);
+ flowOut = nghttp2_session_get_stream_remote_window_size(x->s->ngh2, stream->id);
+ bbout(x->bb, "%s\n \"%d\": {\n", (x->idx? "," : ""), stream->id);
+ bbout(x->bb, " \"state\": \"%s\",\n", h2_stream_state_str(stream));
+ bbout(x->bb, " \"created\": %f,\n", ((double)stream->created)/APR_USEC_PER_SEC);
+ bbout(x->bb, " \"flowIn\": %d,\n", flowIn);
+ bbout(x->bb, " \"flowOut\": %d,\n", flowOut);
+ bbout(x->bb, " \"dataIn\": %"APR_UINT64_T_FMT",\n", stream->in_data_octets);
+ bbout(x->bb, " \"dataOut\": %"APR_UINT64_T_FMT"\n", stream->out_data_octets);
+ bbout(x->bb, " }");
+
+ ++x->idx;
+ return 1;
+}
+
+static void add_streams(apr_bucket_brigade *bb, h2_session *s, int last)
+{
+ stream_ctx_t x;
- bbout(bb, "{\n");
- bbout(bb, " \"HTTP2\": \"on\",\n");
- bbout(bb, " \"H2PUSH\": \"%s\",\n", h2_session_push_enabled(session)? "on" : "off");
- bbout(bb, " \"mod_http2_version\": \"%s\",\n", MOD_HTTP2_VERSION);
- bbout(bb, " \"session_id\": %ld,\n", (long)session->id);
- bbout(bb, " \"streams_max\": %d,\n", (int)session->max_stream_count);
- bbout(bb, " \"this_stream\": %d,\n", stream->id);
- bbout(bb, " \"streams_open\": %d,\n", (int)h2_ihash_count(session->streams));
- bbout(bb, " \"max_stream_started\": %d,\n", mplx->max_stream_started);
- bbout(bb, " \"requests_received\": %d,\n", session->remote.emitted_count);
- bbout(bb, " \"responses_submitted\": %d,\n", session->responses_submitted);
- bbout(bb, " \"streams_reset\": %d, \n", session->streams_reset);
- bbout(bb, " \"pushes_promised\": %d,\n", session->pushes_promised);
- bbout(bb, " \"pushes_submitted\": %d,\n", session->pushes_submitted);
- bbout(bb, " \"pushes_reset\": %d,\n", session->pushes_reset);
+ x.bb = bb;
+ x.s = s;
+ x.idx = 0;
+ bbout(bb, " \"streams\": {");
+ h2_mplx_stream_do(s->mplx, add_stream, &x);
+ bbout(bb, "\n }%s\n", last? "" : ",");
+}
+
+static void add_push(apr_bucket_brigade *bb, h2_session *s,
+ h2_stream *stream, int last)
+{
+ h2_push_diary *diary;
+ apr_status_t status;
- diary = session->push_diary;
+ bbout(bb, " \"push\": {\n");
+ diary = s->push_diary;
if (diary) {
const char *data;
const char *base64_digest;
apr_size_t len;
- status = h2_push_diary_digest_get(diary, stream->pool, 256,
- stream->request->authority, &data, &len);
+ status = h2_push_diary_digest_get(diary, bb->p, 256,
+ stream->request->authority,
+ &data, &len);
if (status == APR_SUCCESS) {
- base64_digest = h2_util_base64url_encode(data, len, stream->pool);
- bbout(bb, " \"cache_digest\": \"%s\",\n", base64_digest);
- }
-
- /* try the reverse for testing purposes */
- status = h2_push_diary_digest_set(diary, stream->request->authority, data, len);
- if (status == APR_SUCCESS) {
- status = h2_push_diary_digest_get(diary, stream->pool, 256,
- stream->request->authority, &data, &len);
- if (status == APR_SUCCESS) {
- base64_digest = h2_util_base64url_encode(data, len, stream->pool);
- bbout(bb, " \"cache_digest^2\": \"%s\",\n", base64_digest);
- }
+ base64_digest = h2_util_base64url_encode(data, len, bb->p);
+ bbout(bb, " \"cacheDigest\": \"%s\",\n", base64_digest);
}
}
- bbout(bb, " \"frames_received\": %ld,\n", (long)session->frames_received);
- bbout(bb, " \"frames_sent\": %ld,\n", (long)session->frames_sent);
- bbout(bb, " \"bytes_received\": %"APR_UINT64_T_FMT",\n", session->io.bytes_read);
- bbout(bb, " \"bytes_sent\": %"APR_UINT64_T_FMT"\n", session->io.bytes_written);
+ bbout(bb, " \"promises\": %d,\n", s->pushes_promised);
+ bbout(bb, " \"submits\": %d,\n", s->pushes_submitted);
+ bbout(bb, " \"resets\": %d\n", s->pushes_reset);
+ bbout(bb, " }%s\n", last? "" : ",");
+}
+
+static void add_in(apr_bucket_brigade *bb, h2_session *s, int last)
+{
+ bbout(bb, " \"in\": {\n");
+ bbout(bb, " \"requests\": %d,\n", s->remote.emitted_count);
+ bbout(bb, " \"resets\": %d, \n", s->streams_reset);
+ bbout(bb, " \"frames\": %ld,\n", (long)s->frames_received);
+ bbout(bb, " \"octets\": %"APR_UINT64_T_FMT"\n", s->io.bytes_read);
+ bbout(bb, " }%s\n", last? "" : ",");
+}
+
+static void add_out(apr_bucket_brigade *bb, h2_session *s, int last)
+{
+ bbout(bb, " \"out\": {\n");
+ bbout(bb, " \"responses\": %d,\n", s->responses_submitted);
+ bbout(bb, " \"frames\": %ld,\n", (long)s->frames_sent);
+ bbout(bb, " \"octets\": %"APR_UINT64_T_FMT"\n", s->io.bytes_written);
+ bbout(bb, " }%s\n", last? "" : ",");
+}
+
+static void add_stats(apr_bucket_brigade *bb, h2_session *s,
+ h2_stream *stream, int last)
+{
+ bbout(bb, " \"stats\": {\n");
+ add_in(bb, s, 0);
+ add_out(bb, s, 0);
+ add_push(bb, s, stream, 1);
+ bbout(bb, " }%s\n", last? "" : ",");
+}
+
+static apr_status_t h2_status_insert(h2_task *task, apr_bucket *b)
+{
+ h2_mplx *m = task->mplx;
+ h2_stream *stream = h2_mplx_stream_get(m, task->stream_id);
+ h2_session *s;
+ conn_rec *c;
+
+ apr_bucket_brigade *bb;
+ apr_bucket *e;
+ int32_t connFlowIn, connFlowOut;
+
+ if (!stream) {
+ /* stream already done */
+ return APR_SUCCESS;
+ }
+ s = stream->session;
+ c = s->c;
+
+ bb = apr_brigade_create(stream->pool, c->bucket_alloc);
+
+ connFlowIn = nghttp2_session_get_effective_local_window_size(s->ngh2);
+ connFlowOut = nghttp2_session_get_remote_window_size(s->ngh2);
+
+ bbout(bb, "{\n");
+ bbout(bb, " \"version\": \"draft-01\",\n");
+ add_settings(bb, s, 0);
+ add_peer_settings(bb, s, 0);
+ bbout(bb, " \"connFlowIn\": %d,\n", connFlowIn);
+ bbout(bb, " \"connFlowOut\": %d,\n", connFlowOut);
+ bbout(bb, " \"sentGoAway\": %d,\n", s->local.shutdown);
+
+ add_streams(bb, s, 0);
+
+ add_stats(bb, s, stream, 1);
bbout(bb, "}\n");
+ while ((e = APR_BRIGADE_FIRST(bb)) != APR_BRIGADE_SENTINEL(bb)) {
+ APR_BUCKET_REMOVE(e);
+ APR_BUCKET_INSERT_AFTER(b, e);
+ b = e;
+ }
+ apr_brigade_destroy(bb);
+
return APR_SUCCESS;
}
-apr_status_t h2_stream_filter(h2_stream *stream)
+static apr_status_t status_event(void *ctx, h2_bucket_event event,
+ apr_bucket *b)
{
- const char *fname = stream->response? stream->response->sos_filter : NULL;
- if (fname && !strcmp(H2_SOS_H2_STATUS, fname)) {
- return h2_status_stream_filter(stream);
+ h2_task *task = ctx;
+
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE3, 0, task->c->master,
+ "status_event(%s): %d", task->id, event);
+ switch (event) {
+ case H2_BUCKET_EV_BEFORE_MASTER_SEND:
+ h2_status_insert(task, b);
+ break;
+ default:
+ break;
}
return APR_SUCCESS;
}
+int h2_filter_h2_status_handler(request_rec *r)
+{
+ h2_ctx *ctx = h2_ctx_rget(r);
+ conn_rec *c = r->connection;
+ h2_task *task;
+ apr_bucket_brigade *bb;
+ apr_bucket *b;
+ apr_status_t status;
+
+ if (strcmp(r->handler, "http2-status")) {
+ return DECLINED;
+ }
+ if (r->method_number != M_GET && r->method_number != M_POST) {
+ return DECLINED;
+ }
+
+ task = ctx? h2_ctx_get_task(ctx) : NULL;
+ if (task) {
+
+ if ((status = ap_discard_request_body(r)) != OK) {
+ return status;
+ }
+
+ /* We need to handle the actual output on the main thread, as
+ * we need to access h2_session information. */
+ r->status = 200;
+ r->clength = -1;
+ r->chunked = 1;
+ apr_table_unset(r->headers_out, "Content-Length");
+ ap_set_content_type(r, "application/json");
+ apr_table_setn(r->notes, H2_FILTER_DEBUG_NOTE, "on");
+
+ bb = apr_brigade_create(r->pool, c->bucket_alloc);
+ b = h2_bucket_observer_create(c->bucket_alloc, status_event, task);
+ APR_BRIGADE_INSERT_TAIL(bb, b);
+ b = apr_bucket_eos_create(c->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(bb, b);
+
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
+ "status_handler(%s): checking for incoming trailers",
+ task->id);
+ if (r->trailers_in && !apr_is_empty_table(r->trailers_in)) {
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
+ "status_handler(%s): seeing incoming trailers",
+ task->id);
+ apr_table_setn(r->trailers_out, "h2-trailers-in",
+ apr_itoa(r->pool, 1));
+ }
+
+ status = ap_pass_brigade(r->output_filters, bb);
+ if (status == APR_SUCCESS
+ || r->status != HTTP_OK
+ || c->aborted) {
+ return OK;
+ }
+ else {
+ /* no way to know what type of error occurred */
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE1, status, r,
+ "status_handler(%s): ap_pass_brigade failed",
+ task->id);
+ return AP_FILTER_ERROR;
+ }
+ }
+ return DECLINED;
+}
+
Modified: httpd/httpd/branches/2.4.x-openssl-1.1.0-compat/modules/http2/h2_filter.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x-openssl-1.1.0-compat/modules/http2/h2_filter.h?rev=1769588&r1=1769587&r2=1769588&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x-openssl-1.1.0-compat/modules/http2/h2_filter.h (original)
+++ httpd/httpd/branches/2.4.x-openssl-1.1.0-compat/modules/http2/h2_filter.h Mon Nov 14 10:26:31 2016
@@ -16,6 +16,8 @@
#ifndef __mod_h2__h2_filter__
#define __mod_h2__h2_filter__
+struct h2_bucket_beam;
+struct h2_headers;
struct h2_stream;
struct h2_session;
@@ -43,9 +45,33 @@ apr_status_t h2_filter_core_input(ap_fil
apr_read_type_e block,
apr_off_t readbytes);
-#define H2_RESP_SOS_NOTE "h2-sos-filter"
+/******* observer bucket ******************************************************/
+
+typedef enum {
+ H2_BUCKET_EV_BEFORE_DESTROY,
+ H2_BUCKET_EV_BEFORE_MASTER_SEND
+} h2_bucket_event;
+
+extern const apr_bucket_type_t h2_bucket_type_observer;
+
+typedef apr_status_t h2_bucket_event_cb(void *ctx, h2_bucket_event event, apr_bucket *b);
+
+#define H2_BUCKET_IS_OBSERVER(e) (e->type == &h2_bucket_type_observer)
+
+apr_bucket * h2_bucket_observer_make(apr_bucket *b, h2_bucket_event_cb *cb,
+ void *ctx);
+
+apr_bucket * h2_bucket_observer_create(apr_bucket_alloc_t *list,
+ h2_bucket_event_cb *cb, void *ctx);
+
+apr_status_t h2_bucket_observer_fire(apr_bucket *b, h2_bucket_event event);
+
+apr_bucket *h2_bucket_observer_beam(struct h2_bucket_beam *beam,
+ apr_bucket_brigade *dest,
+ const apr_bucket *src);
+
+/******* /.well-known/h2/state handler ****************************************/
-apr_status_t h2_stream_filter(struct h2_stream *stream);
int h2_filter_h2_status_handler(request_rec *r);
#endif /* __mod_h2__h2_filter__ */