summaryrefslogtreecommitdiffstats
path: root/modules/http2/h2_util.c
diff options
context:
space:
mode:
authorStefan Eissing <icing@apache.org>2016-04-15 15:50:46 +0200
committerStefan Eissing <icing@apache.org>2016-04-15 15:50:46 +0200
commit52cdae53be08ed37e5d73eac20a39d76f7617bcb (patch)
treee383ea1324254aee627932931ee9dd5250f0444f /modules/http2/h2_util.c
parenthttp: Respond with "408 Request Timeout" when a timeout occurs while (diff)
downloadapache2-52cdae53be08ed37e5d73eac20a39d76f7617bcb.tar.xz
apache2-52cdae53be08ed37e5d73eac20a39d76f7617bcb.zip
mod_http2: new bucket beams for tranporting buckets across threads without buffer copy. Code cleanup
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1739303 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'modules/http2/h2_util.c')
-rw-r--r--modules/http2/h2_util.c796
1 files changed, 437 insertions, 359 deletions
diff --git a/modules/http2/h2_util.c b/modules/http2/h2_util.c
index 06472425f2..9beaeae048 100644
--- a/modules/http2/h2_util.c
+++ b/modules/http2/h2_util.c
@@ -332,6 +332,301 @@ void h2_ihash_clear(h2_ihash_t *ih)
}
/*******************************************************************************
+ * ilist - sorted list for structs with int identifier
+ ******************************************************************************/
+
+#define h2_ilist_IDX(list, i) ((int**)(list)->elts)[i]
+
+struct h2_ilist_t {
+ apr_array_header_t *l;
+};
+
+h2_ilist_t *h2_ilist_create(apr_pool_t *pool)
+{
+ h2_ilist_t *list = apr_pcalloc(pool, sizeof(h2_ilist_t));
+ if (list) {
+ list->l = apr_array_make(pool, 100, sizeof(int*));
+ if (!list->l) {
+ return NULL;
+ }
+ }
+ return list;
+}
+
+static int h2_ilist_cmp(const void *s1, const void *s2)
+{
+ int **pi1 = (int **)s1;
+ int **pi2 = (int **)s2;
+ return *(*pi1) - *(*pi2);
+}
+
+void *h2_ilist_get(h2_ilist_t *list, int id)
+{
+ /* we keep the array sorted by id, so lookup can be done
+ * by bsearch.
+ */
+ int **pi;
+ int *pkey = &id;
+
+ pi = bsearch(&pkey, list->l->elts, list->l->nelts,
+ list->l->elt_size, h2_ilist_cmp);
+ return pi? *pi : NULL;
+}
+
+static void h2_ilist_sort(h2_ilist_t *list)
+{
+ qsort(list->l->elts, list->l->nelts, list->l->elt_size, h2_ilist_cmp);
+}
+
+apr_status_t h2_ilist_add(h2_ilist_t *list, void *val)
+{
+ int *pi = val;
+ void *existing = h2_ilist_get(list, *pi);
+ if (!existing) {
+ int last;
+ APR_ARRAY_PUSH(list->l, void*) = val;
+ /* Often, values get added in ascending order of id. We
+ * keep the array sorted, so we just need to check if the newly
+ * appended stream has a lower id than the last one. if not,
+ * sorting is not necessary.
+ */
+ last = list->l->nelts - 1;
+ if (last > 0
+ && *h2_ilist_IDX(list->l, last) < *h2_ilist_IDX(list->l, last-1)) {
+ h2_ilist_sort(list);
+ }
+ }
+ return APR_SUCCESS;
+}
+
+static void remove_idx(h2_ilist_t *list, int idx)
+{
+ int n;
+ --list->l->nelts;
+ n = list->l->nelts - idx;
+ if (n > 0) {
+ /* There are n h2_io* behind idx. Move the rest down */
+ int **selts = (int**)list->l->elts;
+ memmove(selts + idx, selts + idx + 1, n * sizeof(int*));
+ }
+}
+
+void *h2_ilist_remove(h2_ilist_t *list, int id)
+{
+ int i;
+ for (i = 0; i < list->l->nelts; ++i) {
+ int *e = h2_ilist_IDX(list->l, i);
+ if (id == *e) {
+ remove_idx(list, i);
+ return e;
+ }
+ }
+ return NULL;
+}
+
+void *h2_ilist_shift(h2_ilist_t *list)
+{
+ if (list->l->nelts > 0) {
+ int *pi = h2_ilist_IDX(list->l, 0);
+ remove_idx(list, 0);
+ return pi;
+ }
+ return NULL;
+}
+
+int h2_ilist_empty(h2_ilist_t *list)
+{
+ return list->l->nelts == 0;
+}
+
+int h2_ilist_iter(h2_ilist_t *list, h2_ilist_iter_t *iter, void *ctx)
+{
+ int i;
+ for (i = 0; i < list->l->nelts; ++i) {
+ int *pi = h2_ilist_IDX(list->l, i);
+ if (!iter(ctx, pi)) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+apr_size_t h2_ilist_count(h2_ilist_t *list)
+{
+ return list->l->nelts;
+}
+
+/*******************************************************************************
+ * iqueue - sorted list of int
+ ******************************************************************************/
+
+static void iq_grow(h2_iqueue *q, int nlen);
+static void iq_swap(h2_iqueue *q, int i, int j);
+static int iq_bubble_up(h2_iqueue *q, int i, int top,
+ h2_iq_cmp *cmp, void *ctx);
+static int iq_bubble_down(h2_iqueue *q, int i, int bottom,
+ h2_iq_cmp *cmp, void *ctx);
+
+h2_iqueue *h2_iq_create(apr_pool_t *pool, int capacity)
+{
+ h2_iqueue *q = apr_pcalloc(pool, sizeof(h2_iqueue));
+ if (q) {
+ q->pool = pool;
+ iq_grow(q, capacity);
+ q->nelts = 0;
+ }
+ return q;
+}
+
+int h2_iq_empty(h2_iqueue *q)
+{
+ return q->nelts == 0;
+}
+
+int h2_iq_count(h2_iqueue *q)
+{
+ return q->nelts;
+}
+
+
+void h2_iq_add(h2_iqueue *q, int sid, h2_iq_cmp *cmp, void *ctx)
+{
+ int i;
+
+ if (q->nelts >= q->nalloc) {
+ iq_grow(q, q->nalloc * 2);
+ }
+
+ i = (q->head + q->nelts) % q->nalloc;
+ q->elts[i] = sid;
+ ++q->nelts;
+
+ if (cmp) {
+ /* bubble it to the front of the queue */
+ iq_bubble_up(q, i, q->head, cmp, ctx);
+ }
+}
+
+int h2_iq_remove(h2_iqueue *q, int sid)
+{
+ int i;
+ for (i = 0; i < q->nelts; ++i) {
+ if (sid == q->elts[(q->head + i) % q->nalloc]) {
+ break;
+ }
+ }
+
+ if (i < q->nelts) {
+ ++i;
+ for (; i < q->nelts; ++i) {
+ q->elts[(q->head+i-1)%q->nalloc] = q->elts[(q->head+i)%q->nalloc];
+ }
+ --q->nelts;
+ return 1;
+ }
+ return 0;
+}
+
+void h2_iq_clear(h2_iqueue *q)
+{
+ q->nelts = 0;
+}
+
+void h2_iq_sort(h2_iqueue *q, h2_iq_cmp *cmp, void *ctx)
+{
+ /* Assume that changes in ordering are minimal. This needs,
+ * best case, q->nelts - 1 comparisions to check that nothing
+ * changed.
+ */
+ if (q->nelts > 0) {
+ int i, ni, prev, last;
+
+ /* Start at the end of the queue and create a tail of sorted
+ * entries. Make that tail one element longer in each iteration.
+ */
+ last = i = (q->head + q->nelts - 1) % q->nalloc;
+ while (i != q->head) {
+ prev = (q->nalloc + i - 1) % q->nalloc;
+
+ ni = iq_bubble_up(q, i, prev, cmp, ctx);
+ if (ni == prev) {
+ /* i bubbled one up, bubble the new i down, which
+ * keeps all tasks below i sorted. */
+ iq_bubble_down(q, i, last, cmp, ctx);
+ }
+ i = prev;
+ };
+ }
+}
+
+
+int h2_iq_shift(h2_iqueue *q)
+{
+ int sid;
+
+ if (q->nelts <= 0) {
+ return 0;
+ }
+
+ sid = q->elts[q->head];
+ q->head = (q->head + 1) % q->nalloc;
+ q->nelts--;
+
+ return sid;
+}
+
+static void iq_grow(h2_iqueue *q, int nlen)
+{
+ if (nlen > q->nalloc) {
+ int *nq = apr_pcalloc(q->pool, sizeof(int) * nlen);
+ if (q->nelts > 0) {
+ int l = ((q->head + q->nelts) % q->nalloc) - q->head;
+
+ memmove(nq, q->elts + q->head, sizeof(int) * l);
+ if (l < q->nelts) {
+ /* elts wrapped, append elts in [0, remain] to nq */
+ int remain = q->nelts - l;
+ memmove(nq + l, q->elts, sizeof(int) * remain);
+ }
+ }
+ q->elts = nq;
+ q->nalloc = nlen;
+ q->head = 0;
+ }
+}
+
+static void iq_swap(h2_iqueue *q, int i, int j)
+{
+ int x = q->elts[i];
+ q->elts[i] = q->elts[j];
+ q->elts[j] = x;
+}
+
+static int iq_bubble_up(h2_iqueue *q, int i, int top,
+ h2_iq_cmp *cmp, void *ctx)
+{
+ int prev;
+ while (((prev = (q->nalloc + i - 1) % q->nalloc), i != top)
+ && (*cmp)(q->elts[i], q->elts[prev], ctx) < 0) {
+ iq_swap(q, prev, i);
+ i = prev;
+ }
+ return i;
+}
+
+static int iq_bubble_down(h2_iqueue *q, int i, int bottom,
+ h2_iq_cmp *cmp, void *ctx)
+{
+ int next;
+ while (((next = (q->nalloc + i + 1) % q->nalloc), i != bottom)
+ && (*cmp)(q->elts[i], q->elts[next], ctx) > 0) {
+ iq_swap(q, next, i);
+ i = next;
+ }
+ return i;
+}
+
+/*******************************************************************************
* h2_util for apt_table_t
******************************************************************************/
@@ -368,15 +663,6 @@ apr_size_t h2_util_table_bytes(apr_table_t *t, apr_size_t pair_extra)
* h2_util for bucket brigades
******************************************************************************/
-/* DEEP_COPY==0 crashes under load. I think the setaside is fine,
- * however buckets moved to another thread will still be
- * free'd against the old bucket_alloc. *And* if the old
- * pool gets destroyed too early, the bucket disappears while
- * still needed.
- */
-static const int DEEP_COPY = 1;
-static const int FILE_MOVE = 1;
-
static apr_status_t last_not_included(apr_bucket_brigade *bb,
apr_off_t maxlen,
int same_alloc,
@@ -434,200 +720,95 @@ static apr_status_t last_not_included(apr_bucket_brigade *bb,
return status;
}
-#define LOG_BUCKETS 0
-#define LOG_LEVEL APLOG_INFO
-
-apr_status_t h2_util_move(apr_bucket_brigade *to, apr_bucket_brigade *from,
- apr_off_t maxlen, apr_size_t *pfile_buckets_allowed,
- const char *msg)
+apr_status_t h2_brigade_concat_length(apr_bucket_brigade *dest,
+ apr_bucket_brigade *src,
+ apr_off_t length)
{
+ apr_bucket *b, *next;
+ apr_off_t remain = length;
apr_status_t status = APR_SUCCESS;
- int same_alloc;
- AP_DEBUG_ASSERT(to);
- AP_DEBUG_ASSERT(from);
- same_alloc = (to->bucket_alloc == from->bucket_alloc
- || to->p == from->p);
-
- if (!FILE_MOVE) {
- pfile_buckets_allowed = NULL;
- }
-
- if (!APR_BRIGADE_EMPTY(from)) {
- apr_bucket *b, *end;
+ for (b = APR_BRIGADE_FIRST(src);
+ b != APR_BRIGADE_SENTINEL(src);
+ b = next) {
+ next = APR_BUCKET_NEXT(b);
- status = last_not_included(from, maxlen, same_alloc,
- pfile_buckets_allowed, &end);
- if (status != APR_SUCCESS) {
- return status;
+ if (APR_BUCKET_IS_METADATA(b)) {
+ /* fall through */
}
-
- while (!APR_BRIGADE_EMPTY(from) && status == APR_SUCCESS) {
- b = APR_BRIGADE_FIRST(from);
- if (b == end) {
- break;
+ else {
+ if (remain == b->length) {
+ /* fall through */
}
-
- if (same_alloc || (b->list == to->bucket_alloc)) {
- /* both brigades use the same bucket_alloc and auto-cleanups
- * have the same life time. It's therefore safe to just move
- * directly. */
- APR_BUCKET_REMOVE(b);
- APR_BRIGADE_INSERT_TAIL(to, b);
-#if LOG_BUCKETS
- ap_log_perror(APLOG_MARK, LOG_LEVEL, 0, to->p, APLOGNO(03205)
- "h2_util_move: %s, passed bucket(same bucket_alloc) "
- "%ld-%ld, type=%s",
- msg, (long)b->start, (long)b->length,
- APR_BUCKET_IS_METADATA(b)?
- (APR_BUCKET_IS_EOS(b)? "EOS":
- (APR_BUCKET_IS_FLUSH(b)? "FLUSH" : "META")) :
- (APR_BUCKET_IS_FILE(b)? "FILE" : "DATA"));
-#endif
+ else if (remain <= 0) {
+ return status;
}
- else if (DEEP_COPY) {
- /* we have not managed the magic of passing buckets from
- * one thread to another. Any attempts result in
- * cleanup of pools scrambling memory.
- */
- if (APR_BUCKET_IS_METADATA(b)) {
- if (APR_BUCKET_IS_EOS(b)) {
- APR_BRIGADE_INSERT_TAIL(to, apr_bucket_eos_create(to->bucket_alloc));
- }
- else {
- /* ignore */
- }
- }
- else if (pfile_buckets_allowed
- && *pfile_buckets_allowed > 0
- && APR_BUCKET_IS_FILE(b)) {
- /* We do not want to read files when passing buckets, if
- * we can avoid it. However, what we've come up so far
- * is not working corrently, resulting either in crashes or
- * too many open file descriptors.
- */
- apr_bucket_file *f = (apr_bucket_file *)b->data;
- apr_file_t *fd = f->fd;
- int setaside = (f->readpool != to->p);
-#if LOG_BUCKETS
- ap_log_perror(APLOG_MARK, LOG_LEVEL, 0, to->p, APLOGNO(03206)
- "h2_util_move: %s, moving FILE bucket %ld-%ld "
- "from=%lx(p=%lx) to=%lx(p=%lx), setaside=%d",
- msg, (long)b->start, (long)b->length,
- (long)from, (long)from->p,
- (long)to, (long)to->p, setaside);
-#endif
- if (setaside) {
- status = apr_file_setaside(&fd, fd, to->p);
- if (status != APR_SUCCESS) {
- ap_log_perror(APLOG_MARK, APLOG_ERR, status, to->p,
- APLOGNO(02947) "h2_util: %s, setaside FILE",
- msg);
- return status;
- }
+ else {
+ if (b->length == ((apr_size_t)-1)) {
+ const char *ign;
+ apr_size_t ilen;
+ status = apr_bucket_read(b, &ign, &ilen, APR_BLOCK_READ);
+ if (status != APR_SUCCESS) {
+ return status;
}
- apr_brigade_insert_file(to, fd, b->start, b->length,
- to->p);
- --(*pfile_buckets_allowed);
}
- else {
- const char *data;
- apr_size_t len;
-
- status = apr_bucket_read(b, &data, &len, APR_BLOCK_READ);
- if (status == APR_SUCCESS && len > 0) {
- status = apr_brigade_write(to, NULL, NULL, data, len);
-#if LOG_BUCKETS
- ap_log_perror(APLOG_MARK, LOG_LEVEL, 0, to->p, APLOGNO(03207)
- "h2_util_move: %s, copied bucket %ld-%ld "
- "from=%lx(p=%lx) to=%lx(p=%lx)",
- msg, (long)b->start, (long)b->length,
- (long)from, (long)from->p,
- (long)to, (long)to->p);
-#endif
- }
+
+ if (remain < b->length) {
+ apr_bucket_split(b, remain);
}
- apr_bucket_delete(b);
- }
- else {
- apr_bucket_setaside(b, to->p);
- APR_BUCKET_REMOVE(b);
- APR_BRIGADE_INSERT_TAIL(to, b);
-#if LOG_BUCKETS
- ap_log_perror(APLOG_MARK, LOG_LEVEL, 0, to->p, APLOGNO(03208)
- "h2_util_move: %s, passed setaside bucket %ld-%ld "
- "from=%lx(p=%lx) to=%lx(p=%lx)",
- msg, (long)b->start, (long)b->length,
- (long)from, (long)from->p,
- (long)to, (long)to->p);
-#endif
}
}
+ APR_BUCKET_REMOVE(b);
+ APR_BRIGADE_INSERT_TAIL(dest, b);
+ remain -= b->length;
}
-
return status;
}
-apr_status_t h2_util_copy(apr_bucket_brigade *to, apr_bucket_brigade *from,
- apr_off_t maxlen, const char *msg)
+apr_status_t h2_brigade_copy_length(apr_bucket_brigade *dest,
+ apr_bucket_brigade *src,
+ apr_off_t length)
{
+ apr_bucket *b, *next;
+ apr_off_t remain = length;
apr_status_t status = APR_SUCCESS;
- int same_alloc;
-
- (void)msg;
- AP_DEBUG_ASSERT(to);
- AP_DEBUG_ASSERT(from);
- same_alloc = (to->bucket_alloc == from->bucket_alloc);
-
- if (!APR_BRIGADE_EMPTY(from)) {
- apr_bucket *b, *end, *cpy;
+
+ for (b = APR_BRIGADE_FIRST(src);
+ b != APR_BRIGADE_SENTINEL(src);
+ b = next) {
+ next = APR_BUCKET_NEXT(b);
- status = last_not_included(from, maxlen, 0, 0, &end);
- if (status != APR_SUCCESS) {
- return status;
+ if (APR_BUCKET_IS_METADATA(b)) {
+ /* fall through */
}
-
- for (b = APR_BRIGADE_FIRST(from);
- b != APR_BRIGADE_SENTINEL(from) && b != end;
- b = APR_BUCKET_NEXT(b))
- {
- if (same_alloc) {
- status = apr_bucket_copy(b, &cpy);
- if (status != APR_SUCCESS) {
- break;
- }
- APR_BRIGADE_INSERT_TAIL(to, cpy);
+ else {
+ if (remain == b->length) {
+ /* fall through */
+ }
+ else if (remain <= 0) {
+ return status;
}
else {
- if (APR_BUCKET_IS_METADATA(b)) {
- if (APR_BUCKET_IS_EOS(b)) {
- APR_BRIGADE_INSERT_TAIL(to, apr_bucket_eos_create(to->bucket_alloc));
- }
- else if (APR_BUCKET_IS_FLUSH(b)) {
- APR_BRIGADE_INSERT_TAIL(to, apr_bucket_flush_create(to->bucket_alloc));
- }
- else {
- /* ignore */
+ if (b->length == ((apr_size_t)-1)) {
+ const char *ign;
+ apr_size_t ilen;
+ status = apr_bucket_read(b, &ign, &ilen, APR_BLOCK_READ);
+ if (status != APR_SUCCESS) {
+ return status;
}
}
- else {
- const char *data;
- apr_size_t len;
- status = apr_bucket_read(b, &data, &len, APR_BLOCK_READ);
- if (status == APR_SUCCESS && len > 0) {
- status = apr_brigade_write(to, NULL, NULL, data, len);
-#if LOG_BUCKETS
- ap_log_perror(APLOG_MARK, LOG_LEVEL, 0, to->p, APLOGNO(03209)
- "h2_util_copy: %s, copied bucket %ld-%ld "
- "from=%lx(p=%lx) to=%lx(p=%lx)",
- msg, (long)b->start, (long)b->length,
- (long)from, (long)from->p,
- (long)to, (long)to->p);
-#endif
- }
+
+ if (remain < b->length) {
+ apr_bucket_split(b, remain);
}
}
}
+ status = apr_bucket_copy(b, &b);
+ if (status != APR_SUCCESS) {
+ return status;
+ }
+ APR_BRIGADE_INSERT_TAIL(dest, b);
+ remain -= b->length;
}
return status;
}
@@ -666,25 +847,6 @@ int h2_util_bb_has_data(apr_bucket_brigade *bb)
return 0;
}
-int h2_util_bb_has_data_or_eos(apr_bucket_brigade *bb)
-{
- apr_bucket *b;
- for (b = APR_BRIGADE_FIRST(bb);
- b != APR_BRIGADE_SENTINEL(bb);
- b = APR_BUCKET_NEXT(b))
- {
- if (APR_BUCKET_IS_METADATA(b)) {
- if (APR_BUCKET_IS_EOS(b)) {
- return 1;
- }
- }
- else {
- return 1;
- }
- }
- return 0;
-}
-
apr_status_t h2_util_bb_avail(apr_bucket_brigade *bb,
apr_off_t *plen, int *peos)
{
@@ -789,186 +951,102 @@ apr_status_t h2_util_bb_readx(apr_bucket_brigade *bb,
return status;
}
-void h2_util_bb_log(conn_rec *c, int stream_id, int level,
- const char *tag, apr_bucket_brigade *bb)
+apr_size_t h2_util_bucket_print(char *buffer, apr_size_t bmax,
+ apr_bucket *b, const char *sep)
{
- char buffer[16 * 1024];
- const char *line = "(null)";
- apr_size_t bmax = sizeof(buffer)/sizeof(buffer[0]);
- int off = 0;
- apr_bucket *b;
+ apr_size_t off = 0;
+ if (sep && *sep) {
+ off += apr_snprintf(buffer+off, bmax-off, "%s", sep);
+ }
- 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";
- }
-#if APR_HAS_MMAP
- else if (APR_BUCKET_IS_MMAP(b)) {
- btype = "mmap";
- }
-#endif
- 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));
- }
+ 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)");
}
- 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);
-
-}
-
-apr_status_t h2_ltransfer_brigade(apr_bucket_brigade *to,
- apr_bucket_brigade *from,
- apr_pool_t *p,
- apr_off_t *plen,
- int *peos)
-{
- apr_bucket *e;
- apr_off_t len = 0, remain = *plen;
- apr_status_t rv;
-
- *peos = 0;
-
- while (!APR_BRIGADE_EMPTY(from)) {
- e = APR_BRIGADE_FIRST(from);
-
- if (APR_BUCKET_IS_METADATA(e)) {
- if (APR_BUCKET_IS_EOS(e)) {
- *peos = 1;
- }
+ else {
+ const char *btype = "data";
+ if (APR_BUCKET_IS_FILE(b)) {
+ btype = "file";
}
- else {
- if (remain > 0 && e->length == ((apr_size_t)-1)) {
- const char *ign;
- apr_size_t ilen;
- rv = apr_bucket_read(e, &ign, &ilen, APR_BLOCK_READ);
- if (rv != APR_SUCCESS) {
- return rv;
- }
- }
-
- if (remain < e->length) {
- if (remain <= 0) {
- return APR_SUCCESS;
- }
- apr_bucket_split(e, remain);
- }
+ else if (APR_BUCKET_IS_PIPE(b)) {
+ btype = "pipe";
}
-
- rv = apr_bucket_setaside(e, p);
-
- /* If the bucket type does not implement setaside, then
- * (hopefully) morph it into a bucket type which does, and set
- * *that* aside... */
- if (rv == APR_ENOTIMPL) {
- const char *s;
- apr_size_t n;
-
- rv = apr_bucket_read(e, &s, &n, APR_BLOCK_READ);
- if (rv == APR_SUCCESS) {
- rv = apr_bucket_setaside(e, p);
- }
+ else if (APR_BUCKET_IS_SOCKET(b)) {
+ btype = "socket";
}
-
- if (rv != APR_SUCCESS) {
- /* Return an error but still save the brigade if
- * ->setaside() is really not implemented. */
- if (rv != APR_ENOTIMPL) {
- return rv;
- }
+ 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";
+ }
+#if APR_HAS_MMAP
+ else if (APR_BUCKET_IS_MMAP(b)) {
+ btype = "mmap";
+ }
+#endif
+ else if (APR_BUCKET_IS_POOL(b)) {
+ btype = "pool";
}
- APR_BUCKET_REMOVE(e);
- APR_BRIGADE_INSERT_TAIL(to, e);
- len += e->length;
- remain -= e->length;
+ off += apr_snprintf(buffer+off, bmax-off, "%s[%ld]",
+ btype,
+ (long)(b->length == ((apr_size_t)-1)?
+ -1 : b->length));
}
-
- *plen = len;
- return APR_SUCCESS;
+ return off;
}
-apr_status_t h2_transfer_brigade(apr_bucket_brigade *to,
- apr_bucket_brigade *from,
- apr_pool_t *p)
+apr_size_t h2_util_bb_print(char *buffer, apr_size_t bmax,
+ const char *tag, const char *sep,
+ apr_bucket_brigade *bb)
{
- apr_bucket *e;
- apr_status_t rv;
-
- while (!APR_BRIGADE_EMPTY(from)) {
- e = APR_BRIGADE_FIRST(from);
-
- rv = apr_bucket_setaside(e, p);
-
- /* If the bucket type does not implement setaside, then
- * (hopefully) morph it into a bucket type which does, and set
- * *that* aside... */
- if (rv == APR_ENOTIMPL) {
- const char *s;
- apr_size_t n;
+ apr_size_t off = 0;
+ const char *sp = "";
+ apr_bucket *b;
+
+ if (bb) {
+ memset(buffer, 0, bmax--);
+ off += apr_snprintf(buffer+off, bmax-off, "%s(", tag);
+ for (b = APR_BRIGADE_FIRST(bb);
+ bmax && (b != APR_BRIGADE_SENTINEL(bb));
+ b = APR_BUCKET_NEXT(b)) {
- rv = apr_bucket_read(e, &s, &n, APR_BLOCK_READ);
- if (rv == APR_SUCCESS) {
- rv = apr_bucket_setaside(e, p);
- }
- }
-
- if (rv != APR_SUCCESS) {
- /* Return an error but still save the brigade if
- * ->setaside() is really not implemented. */
- if (rv != APR_ENOTIMPL) {
- return rv;
- }
+ off += h2_util_bucket_print(buffer+off, bmax-off, b, sp);
+ sp = " ";
}
-
- APR_BUCKET_REMOVE(e);
- APR_BRIGADE_INSERT_TAIL(to, e);
+ off += apr_snprintf(buffer+off, bmax-off, ")%s", sep);
}
- return APR_SUCCESS;
+ else {
+ off += apr_snprintf(buffer+off, bmax-off, "%s(null)%s", tag, sep);
+ }
+ return off;
+}
+
+void h2_util_bb_log(conn_rec *c, int stream_id, int level,
+ const char *tag, apr_bucket_brigade *bb)
+{
+ char buffer[4 * 1024];
+ const char *line = "(null)";
+ apr_size_t len, bmax = sizeof(buffer)/sizeof(buffer[0]);
+
+ len = h2_util_bb_print(buffer, bmax, tag, "", bb);
+ /* Intentional no APLOGNO */
+ ap_log_cerror(APLOG_MARK, level, 0, c, "bb_dump(%ld-%d): %s",
+ c->id, stream_id, len? buffer : line);
}
apr_status_t h2_append_brigade(apr_bucket_brigade *to,