1 /* Copyright 2015 greenbytes GmbH (https://www.greenbytes.de)
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
17 #include <apr_strings.h>
18 #include <apr_thread_mutex.h>
19 #include <apr_thread_cond.h>
22 #include <http_core.h>
24 #include <http_request.h>
26 #include <nghttp2/nghttp2.h>
31 /* h2_log2(n) iff n is a power of 2 */
32 unsigned char h2_log2(int n)
38 if (!(n & 0xffff0000u)) {
42 if (!(n & 0xff000000u)) {
46 if (!(n & 0xf0000000u)) {
50 if (!(n & 0xc0000000u)) {
54 if (!(n & 0x80000000u)) {
61 size_t h2_util_hex_dump(char *buffer, size_t maxlen,
62 const char *data, size_t datalen)
65 size_t maxoffset = (maxlen-4);
67 for (i = 0; i < datalen && offset < maxoffset; ++i) {
68 const char *sep = (i && i % 16 == 0)? "\n" : " ";
69 int n = apr_snprintf(buffer+offset, maxoffset-offset,
70 "%2x%s", ((unsigned int)data[i]&0xff), sep);
73 strcpy(buffer+offset, (i<datalen)? "..." : "");
74 return strlen(buffer);
77 size_t h2_util_header_print(char *buffer, size_t maxlen,
78 const char *name, size_t namelen,
79 const char *value, size_t valuelen)
83 for (i = 0; i < namelen && offset < maxlen; ++i, ++offset) {
84 buffer[offset] = name[i];
86 for (i = 0; i < 2 && offset < maxlen; ++i, ++offset) {
87 buffer[offset] = ": "[i];
89 for (i = 0; i < valuelen && offset < maxlen; ++i, ++offset) {
90 buffer[offset] = value[i];
92 buffer[offset] = '\0';
97 void h2_util_camel_case_header(char *s, size_t len)
101 for (i = 0; i < len; ++i) {
103 if (s[i] >= 'a' && s[i] <= 'z') {
109 else if (s[i] == '-') {
115 static const int BASE64URL_UINT6[] = {
116 /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
117 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0 */
118 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 1 */
119 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, /* 2 */
120 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, /* 3 */
121 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 4 */
122 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63, /* 5 */
123 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 6 */
124 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, /* 7 */
125 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 8 */
126 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 9 */
127 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* a */
128 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* b */
129 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* c */
130 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* d */
131 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* e */
132 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* f */
134 static const char BASE64URL_CHARS[] = {
135 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', /* 0 - 9 */
136 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', /* 10 - 19 */
137 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', /* 20 - 29 */
138 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', /* 30 - 39 */
139 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', /* 40 - 49 */
140 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', /* 50 - 59 */
141 '8', '9', '-', '_', ' ', ' ', ' ', ' ', ' ', ' ', /* 60 - 69 */
144 apr_size_t h2_util_base64url_decode(const char **decoded, const char *encoded,
147 const unsigned char *e = (const unsigned char *)encoded;
148 const unsigned char *p = e;
151 apr_size_t len, mlen, remain, i;
153 while (*p && BASE64URL_UINT6[ *p ] != -1) {
158 *decoded = apr_pcalloc(pool, len+1);
161 d = (unsigned char*)*decoded;
162 for (; i < mlen; i += 4) {
163 n = ((BASE64URL_UINT6[ e[i+0] ] << 18) +
164 (BASE64URL_UINT6[ e[i+1] ] << 12) +
165 (BASE64URL_UINT6[ e[i+2] ] << 6) +
166 (BASE64URL_UINT6[ e[i+3] ]));
168 *d++ = n >> 8 & 0xffu;
174 n = ((BASE64URL_UINT6[ e[mlen+0] ] << 18) +
175 (BASE64URL_UINT6[ e[mlen+1] ] << 12));
179 n = ((BASE64URL_UINT6[ e[mlen+0] ] << 18) +
180 (BASE64URL_UINT6[ e[mlen+1] ] << 12) +
181 (BASE64URL_UINT6[ e[mlen+2] ] << 6));
183 *d++ = n >> 8 & 0xffu;
185 default: /* do nothing */
188 return mlen/4*3 + remain;
191 const char *h2_util_base64url_encode(const char *data,
192 apr_size_t len, apr_pool_t *pool)
194 apr_size_t mlen = ((len+2)/3)*3;
195 apr_size_t slen = (mlen/3)*4;
197 const unsigned char *udata = (const unsigned char*)data;
198 char *enc, *p = apr_pcalloc(pool, slen+1); /* 0 terminated */
201 for (i = 0; i < mlen; i+= 3) {
202 *p++ = BASE64URL_CHARS[ (udata[i] >> 2) & 0x3fu ];
203 *p++ = BASE64URL_CHARS[ ((udata[i] << 4) +
204 ((i+1 < len)? (udata[i+1] >> 4) : 0)) & 0x3fu ];
205 *p++ = BASE64URL_CHARS[ ((udata[i+1] << 2) +
206 ((i+2 < len)? (udata[i+2] >> 6) : 0)) & 0x3fu ];
208 *p++ = BASE64URL_CHARS[ udata[i+2] & 0x3fu ];
215 int h2_util_contains_token(apr_pool_t *pool, const char *s, const char *token)
219 if (!apr_strnatcasecmp(s, token)) { /* the simple life */
223 for (c = ap_get_token(pool, &s, 0); c && *c;
224 c = *s? ap_get_token(pool, &s, 0) : NULL) {
225 if (!apr_strnatcasecmp(c, token)) { /* seeing the token? */
228 while (*s++ == ';') { /* skip parameters */
229 ap_get_token(pool, &s, 0);
231 if (*s++ != ',') { /* need comma separation */
239 const char *h2_util_first_token_match(apr_pool_t *pool, const char *s,
240 const char *tokens[], apr_size_t len)
245 for (c = ap_get_token(pool, &s, 0); c && *c;
246 c = *s? ap_get_token(pool, &s, 0) : NULL) {
247 for (i = 0; i < len; ++i) {
248 if (!apr_strnatcasecmp(c, tokens[i])) {
252 while (*s++ == ';') { /* skip parameters */
253 ap_get_token(pool, &s, 0);
255 if (*s++ != ',') { /* need comma separation */
264 /*******************************************************************************
265 * ihash - hash for structs with int identifier
266 ******************************************************************************/
272 static unsigned int ihash(const char *key, apr_ssize_t *klen)
274 return (unsigned int)(*((int*)key));
277 h2_ihash_t *h2_ihash_create(apr_pool_t *pool, size_t offset_of_int)
279 h2_ihash_t *ih = apr_pcalloc(pool, sizeof(h2_ihash_t));
280 ih->hash = apr_hash_make_custom(pool, ihash);
281 ih->ioff = offset_of_int;
285 size_t h2_ihash_count(h2_ihash_t *ih)
287 return apr_hash_count(ih->hash);
290 int h2_ihash_empty(h2_ihash_t *ih)
292 return apr_hash_count(ih->hash) == 0;
295 void *h2_ihash_get(h2_ihash_t *ih, int id)
297 return apr_hash_get(ih->hash, &id, sizeof(id));
301 h2_ihash_iter_t *iter;
305 static int ihash_iter(void *ctx, const void *key, apr_ssize_t klen,
308 iter_ctx *ictx = ctx;
309 return ictx->iter(ictx->ctx, (void*)val); /* why is this passed const?*/
312 int h2_ihash_iter(h2_ihash_t *ih, h2_ihash_iter_t *fn, void *ctx)
317 return apr_hash_do(ihash_iter, &ictx, ih->hash);
320 void h2_ihash_add(h2_ihash_t *ih, void *val)
322 apr_hash_set(ih->hash, ((char *)val + ih->ioff), sizeof(int), val);
325 void h2_ihash_remove(h2_ihash_t *ih, int id)
327 apr_hash_set(ih->hash, &id, sizeof(id), NULL);
330 void h2_ihash_remove_val(h2_ihash_t *ih, void *val)
332 int id = *((int*)((char *)val + ih->ioff));
333 apr_hash_set(ih->hash, &id, sizeof(id), NULL);
337 void h2_ihash_clear(h2_ihash_t *ih)
339 apr_hash_clear(ih->hash);
349 static int collect_iter(void *x, void *val)
351 collect_ctx *ctx = x;
352 if (ctx->len < ctx->max) {
353 ctx->buffer[ctx->len++] = val;
359 size_t h2_ihash_shift(h2_ihash_t *ih, void **buffer, size_t max)
368 h2_ihash_iter(ih, collect_iter, &ctx);
369 for (i = 0; i < ctx.len; ++i) {
370 h2_ihash_remove_val(ih, buffer[i]);
382 static int icollect_iter(void *x, void *val)
384 icollect_ctx *ctx = x;
385 if (ctx->len < ctx->max) {
386 ctx->buffer[ctx->len++] = *((int*)((char *)val + ctx->ih->ioff));
392 size_t h2_ihash_ishift(h2_ihash_t *ih, int *buffer, size_t max)
401 h2_ihash_iter(ih, icollect_iter, &ctx);
402 for (i = 0; i < ctx.len; ++i) {
403 h2_ihash_remove(ih, buffer[i]);
408 /*******************************************************************************
409 * iqueue - sorted list of int
410 ******************************************************************************/
412 static void iq_grow(h2_iqueue *q, int nlen);
413 static void iq_swap(h2_iqueue *q, int i, int j);
414 static int iq_bubble_up(h2_iqueue *q, int i, int top,
415 h2_iq_cmp *cmp, void *ctx);
416 static int iq_bubble_down(h2_iqueue *q, int i, int bottom,
417 h2_iq_cmp *cmp, void *ctx);
419 h2_iqueue *h2_iq_create(apr_pool_t *pool, int capacity)
421 h2_iqueue *q = apr_pcalloc(pool, sizeof(h2_iqueue));
424 iq_grow(q, capacity);
430 int h2_iq_empty(h2_iqueue *q)
432 return q->nelts == 0;
435 int h2_iq_count(h2_iqueue *q)
441 void h2_iq_add(h2_iqueue *q, int sid, h2_iq_cmp *cmp, void *ctx)
445 if (h2_iq_contains(q, sid)) {
448 if (q->nelts >= q->nalloc) {
449 iq_grow(q, q->nalloc * 2);
451 i = (q->head + q->nelts) % q->nalloc;
456 /* bubble it to the front of the queue */
457 iq_bubble_up(q, i, q->head, cmp, ctx);
461 void h2_iq_append(h2_iqueue *q, int sid)
463 h2_iq_add(q, sid, NULL, NULL);
466 int h2_iq_remove(h2_iqueue *q, int sid)
469 for (i = 0; i < q->nelts; ++i) {
470 if (sid == q->elts[(q->head + i) % q->nalloc]) {
477 for (; i < q->nelts; ++i) {
478 q->elts[(q->head+i-1)%q->nalloc] = q->elts[(q->head+i)%q->nalloc];
486 void h2_iq_clear(h2_iqueue *q)
491 void h2_iq_sort(h2_iqueue *q, h2_iq_cmp *cmp, void *ctx)
493 /* Assume that changes in ordering are minimal. This needs,
494 * best case, q->nelts - 1 comparisions to check that nothing
498 int i, ni, prev, last;
500 /* Start at the end of the queue and create a tail of sorted
501 * entries. Make that tail one element longer in each iteration.
503 last = i = (q->head + q->nelts - 1) % q->nalloc;
504 while (i != q->head) {
505 prev = (q->nalloc + i - 1) % q->nalloc;
507 ni = iq_bubble_up(q, i, prev, cmp, ctx);
509 /* i bubbled one up, bubble the new i down, which
510 * keeps all tasks below i sorted. */
511 iq_bubble_down(q, i, last, cmp, ctx);
519 int h2_iq_shift(h2_iqueue *q)
527 sid = q->elts[q->head];
528 q->head = (q->head + 1) % q->nalloc;
534 size_t h2_iq_mshift(h2_iqueue *q, int *pint, size_t max)
537 for (i = 0; i < max; ++i) {
538 pint[i] = h2_iq_shift(q);
546 static void iq_grow(h2_iqueue *q, int nlen)
548 if (nlen > q->nalloc) {
549 int *nq = apr_pcalloc(q->pool, sizeof(int) * nlen);
551 int l = ((q->head + q->nelts) % q->nalloc) - q->head;
553 memmove(nq, q->elts + q->head, sizeof(int) * l);
555 /* elts wrapped, append elts in [0, remain] to nq */
556 int remain = q->nelts - l;
557 memmove(nq + l, q->elts, sizeof(int) * remain);
566 static void iq_swap(h2_iqueue *q, int i, int j)
569 q->elts[i] = q->elts[j];
573 static int iq_bubble_up(h2_iqueue *q, int i, int top,
574 h2_iq_cmp *cmp, void *ctx)
577 while (((prev = (q->nalloc + i - 1) % q->nalloc), i != top)
578 && (*cmp)(q->elts[i], q->elts[prev], ctx) < 0) {
585 static int iq_bubble_down(h2_iqueue *q, int i, int bottom,
586 h2_iq_cmp *cmp, void *ctx)
589 while (((next = (q->nalloc + i + 1) % q->nalloc), i != bottom)
590 && (*cmp)(q->elts[i], q->elts[next], ctx) > 0) {
597 int h2_iq_contains(h2_iqueue *q, int sid)
600 for (i = 0; i < q->nelts; ++i) {
601 if (sid == q->elts[(q->head + i) % q->nalloc]) {
608 /*******************************************************************************
610 ******************************************************************************/
618 apr_thread_mutex_t *lock;
619 apr_thread_cond_t *not_empty;
620 apr_thread_cond_t *not_full;
623 static int nth_index(h2_fifo *fifo, int n)
625 return (fifo->head + n) % fifo->nelems;
628 static apr_status_t fifo_destroy(void *data)
630 h2_fifo *fifo = data;
632 apr_thread_cond_destroy(fifo->not_empty);
633 apr_thread_cond_destroy(fifo->not_full);
634 apr_thread_mutex_destroy(fifo->lock);
639 apr_status_t h2_fifo_create(h2_fifo **pfifo, apr_pool_t *pool, int capacity)
644 fifo = apr_pcalloc(pool, sizeof(*fifo));
649 rv = apr_thread_mutex_create(&fifo->lock,
650 APR_THREAD_MUTEX_UNNESTED, pool);
651 if (rv != APR_SUCCESS) {
655 rv = apr_thread_cond_create(&fifo->not_empty, pool);
656 if (rv != APR_SUCCESS) {
660 rv = apr_thread_cond_create(&fifo->not_full, pool);
661 if (rv != APR_SUCCESS) {
665 fifo->elems = apr_pcalloc(pool, capacity * sizeof(void*));
666 if (fifo->elems == NULL) {
669 fifo->nelems = capacity;
672 apr_pool_cleanup_register(pool, fifo, fifo_destroy, apr_pool_cleanup_null);
677 apr_status_t h2_fifo_term(h2_fifo *fifo)
680 if ((rv = apr_thread_mutex_lock(fifo->lock)) == APR_SUCCESS) {
682 apr_thread_mutex_unlock(fifo->lock);
687 apr_status_t h2_fifo_interrupt(h2_fifo *fifo)
690 if ((rv = apr_thread_mutex_lock(fifo->lock)) == APR_SUCCESS) {
691 apr_thread_cond_broadcast(fifo->not_empty);
692 apr_thread_cond_broadcast(fifo->not_full);
693 apr_thread_mutex_unlock(fifo->lock);
698 int h2_fifo_count(h2_fifo *fifo)
703 static apr_status_t check_not_empty(h2_fifo *fifo, int block)
705 if (fifo->count == 0) {
709 while (fifo->count == 0) {
713 apr_thread_cond_wait(fifo->not_empty, fifo->lock);
719 static apr_status_t fifo_push(h2_fifo *fifo, void *elem, int block)
727 if ((rv = apr_thread_mutex_lock(fifo->lock)) == APR_SUCCESS) {
728 if (fifo->count == fifo->nelems) {
730 while (fifo->count == fifo->nelems) {
732 apr_thread_mutex_unlock(fifo->lock);
735 apr_thread_cond_wait(fifo->not_full, fifo->lock);
739 apr_thread_mutex_unlock(fifo->lock);
744 ap_assert(fifo->count < fifo->nelems);
745 fifo->elems[nth_index(fifo, fifo->count)] = elem;
747 if (fifo->count == 1) {
748 apr_thread_cond_broadcast(fifo->not_empty);
750 apr_thread_mutex_unlock(fifo->lock);
755 apr_status_t h2_fifo_push(h2_fifo *fifo, void *elem)
757 return fifo_push(fifo, elem, 1);
760 apr_status_t h2_fifo_try_push(h2_fifo *fifo, void *elem)
762 return fifo_push(fifo, elem, 0);
765 static apr_status_t fifo_pull(h2_fifo *fifo, void **pelem, int block)
773 if ((rv = apr_thread_mutex_lock(fifo->lock)) == APR_SUCCESS) {
774 if ((rv = check_not_empty(fifo, block)) != APR_SUCCESS) {
775 apr_thread_mutex_unlock(fifo->lock);
780 ap_assert(fifo->count > 0);
781 *pelem = fifo->elems[fifo->head];
783 if (fifo->count > 0) {
784 fifo->head = nth_index(fifo, 1);
785 if (fifo->count+1 == fifo->nelems) {
786 apr_thread_cond_broadcast(fifo->not_full);
789 apr_thread_mutex_unlock(fifo->lock);
794 apr_status_t h2_fifo_pull(h2_fifo *fifo, void **pelem)
796 return fifo_pull(fifo, pelem, 1);
799 apr_status_t h2_fifo_try_pull(h2_fifo *fifo, void **pelem)
801 return fifo_pull(fifo, pelem, 0);
804 static apr_status_t fifo_peek(h2_fifo *fifo, h2_fifo_peek_fn *fn, void *ctx, int block)
813 if ((rv = apr_thread_mutex_lock(fifo->lock)) == APR_SUCCESS) {
814 if ((rv = check_not_empty(fifo, block)) != APR_SUCCESS) {
815 apr_thread_mutex_unlock(fifo->lock);
819 ap_assert(fifo->count > 0);
820 elem = fifo->elems[fifo->head];
822 switch (fn(elem, ctx)) {
823 case H2_FIFO_OP_PULL:
825 if (fifo->count > 0) {
826 fifo->head = nth_index(fifo, 1);
827 if (fifo->count+1 == fifo->nelems) {
828 apr_thread_cond_broadcast(fifo->not_full);
832 case H2_FIFO_OP_REPUSH:
833 if (fifo->count > 1) {
834 fifo->head = nth_index(fifo, 1);
835 if (fifo->count < fifo->nelems) {
836 fifo->elems[nth_index(fifo, fifo->count-1)] = elem;
842 apr_thread_mutex_unlock(fifo->lock);
847 apr_status_t h2_fifo_peek(h2_fifo *fifo, h2_fifo_peek_fn *fn, void *ctx)
849 return fifo_peek(fifo, fn, ctx, 0);
852 apr_status_t h2_fifo_try_peek(h2_fifo *fifo, h2_fifo_peek_fn *fn, void *ctx)
854 return fifo_peek(fifo, fn, ctx, 0);
857 apr_status_t h2_fifo_remove(h2_fifo *fifo, void *elem)
865 if ((rv = apr_thread_mutex_lock(fifo->lock)) == APR_SUCCESS) {
870 for (i = 0; i < fifo->count; ++i) {
871 e = fifo->elems[nth_index(fifo, i)];
876 fifo->elems[nth_index(fifo, i-rc)] = e;
881 if (fifo->count + rc == fifo->nelems) {
882 apr_thread_cond_broadcast(fifo->not_full);
890 apr_thread_mutex_unlock(fifo->lock);
896 /*******************************************************************************
897 * h2_util for apt_table_t
898 ******************************************************************************/
902 apr_size_t pair_extra;
905 static int count_bytes(void *x, const char *key, const char *value)
907 table_bytes_ctx *ctx = x;
909 ctx->bytes += strlen(key);
912 ctx->bytes += strlen(value);
914 ctx->bytes += ctx->pair_extra;
918 apr_size_t h2_util_table_bytes(apr_table_t *t, apr_size_t pair_extra)
923 ctx.pair_extra = pair_extra;
924 apr_table_do(count_bytes, &ctx, t, NULL);
929 /*******************************************************************************
930 * h2_util for bucket brigades
931 ******************************************************************************/
933 static apr_status_t last_not_included(apr_bucket_brigade *bb,
936 apr_size_t *pfile_buckets_allowed,
940 apr_status_t status = APR_SUCCESS;
941 int files_allowed = pfile_buckets_allowed? (int)*pfile_buckets_allowed : 0;
944 /* Find the bucket, up to which we reach maxlen/mem bytes */
945 for (b = APR_BRIGADE_FIRST(bb);
946 (b != APR_BRIGADE_SENTINEL(bb));
947 b = APR_BUCKET_NEXT(b)) {
949 if (APR_BUCKET_IS_METADATA(b)) {
953 if (b->length == ((apr_size_t)-1)) {
956 status = apr_bucket_read(b, &ign, &ilen, APR_BLOCK_READ);
957 if (status != APR_SUCCESS) {
962 if (maxlen == 0 && b->length > 0) {
967 if (same_alloc && APR_BUCKET_IS_FILE(b)) {
968 /* we like it move it, always */
970 else if (files_allowed > 0 && APR_BUCKET_IS_FILE(b)) {
971 /* this has no memory footprint really unless
972 * it is read, disregard it in length count,
973 * unless we do not move the file buckets */
976 else if (maxlen < (apr_off_t)b->length) {
977 apr_bucket_split(b, (apr_size_t)maxlen);
986 *pend = APR_BRIGADE_SENTINEL(bb);
990 apr_status_t h2_brigade_concat_length(apr_bucket_brigade *dest,
991 apr_bucket_brigade *src,
994 apr_bucket *b, *next;
995 apr_off_t remain = length;
996 apr_status_t status = APR_SUCCESS;
998 for (b = APR_BRIGADE_FIRST(src);
999 b != APR_BRIGADE_SENTINEL(src);
1001 next = APR_BUCKET_NEXT(b);
1003 if (APR_BUCKET_IS_METADATA(b)) {
1007 if (remain == b->length) {
1010 else if (remain <= 0) {
1014 if (b->length == ((apr_size_t)-1)) {
1017 status = apr_bucket_read(b, &ign, &ilen, APR_BLOCK_READ);
1018 if (status != APR_SUCCESS) {
1023 if (remain < b->length) {
1024 apr_bucket_split(b, remain);
1028 APR_BUCKET_REMOVE(b);
1029 APR_BRIGADE_INSERT_TAIL(dest, b);
1030 remain -= b->length;
1035 apr_status_t h2_brigade_copy_length(apr_bucket_brigade *dest,
1036 apr_bucket_brigade *src,
1039 apr_bucket *b, *next;
1040 apr_off_t remain = length;
1041 apr_status_t status = APR_SUCCESS;
1043 for (b = APR_BRIGADE_FIRST(src);
1044 b != APR_BRIGADE_SENTINEL(src);
1046 next = APR_BUCKET_NEXT(b);
1048 if (APR_BUCKET_IS_METADATA(b)) {
1052 if (remain == b->length) {
1055 else if (remain <= 0) {
1059 if (b->length == ((apr_size_t)-1)) {
1062 status = apr_bucket_read(b, &ign, &ilen, APR_BLOCK_READ);
1063 if (status != APR_SUCCESS) {
1068 if (remain < b->length) {
1069 apr_bucket_split(b, remain);
1073 status = apr_bucket_copy(b, &b);
1074 if (status != APR_SUCCESS) {
1077 APR_BRIGADE_INSERT_TAIL(dest, b);
1078 remain -= b->length;
1083 int h2_util_has_eos(apr_bucket_brigade *bb, apr_off_t len)
1085 apr_bucket *b, *end;
1087 apr_status_t status = last_not_included(bb, len, 0, 0, &end);
1088 if (status != APR_SUCCESS) {
1092 for (b = APR_BRIGADE_FIRST(bb);
1093 b != APR_BRIGADE_SENTINEL(bb) && b != end;
1094 b = APR_BUCKET_NEXT(b))
1096 if (APR_BUCKET_IS_EOS(b)) {
1103 apr_status_t h2_util_bb_avail(apr_bucket_brigade *bb,
1104 apr_off_t *plen, int *peos)
1106 apr_status_t status;
1109 /* test read to determine available length */
1110 status = apr_brigade_length(bb, 1, &blen);
1111 if (status != APR_SUCCESS) {
1114 else if (blen == 0) {
1115 /* brigade without data, does it have an EOS bucket somwhere? */
1117 *peos = h2_util_has_eos(bb, -1);
1120 /* data in the brigade, limit the length returned. Check for EOS
1121 * bucket only if we indicate data. This is required since plen == 0
1122 * means "the whole brigade" for h2_util_hash_eos()
1124 if (blen < *plen || *plen < 0) {
1127 *peos = h2_util_has_eos(bb, *plen);
1132 apr_status_t h2_util_bb_readx(apr_bucket_brigade *bb,
1133 h2_util_pass_cb *cb, void *ctx,
1134 apr_off_t *plen, int *peos)
1136 apr_status_t status = APR_SUCCESS;
1137 int consume = (cb != NULL);
1138 apr_off_t written = 0;
1139 apr_off_t avail = *plen;
1140 apr_bucket *next, *b;
1142 /* Pass data in our brigade through the callback until the length
1143 * is satisfied or we encounter an EOS.
1146 for (b = APR_BRIGADE_FIRST(bb);
1147 (status == APR_SUCCESS) && (b != APR_BRIGADE_SENTINEL(bb));
1150 if (APR_BUCKET_IS_METADATA(b)) {
1151 if (APR_BUCKET_IS_EOS(b)) {
1158 else if (avail <= 0) {
1162 const char *data = NULL;
1163 apr_size_t data_len;
1165 if (b->length == ((apr_size_t)-1)) {
1166 /* read to determine length */
1167 status = apr_bucket_read(b, &data, &data_len, APR_NONBLOCK_READ);
1170 data_len = b->length;
1173 if (data_len > avail) {
1174 apr_bucket_split(b, avail);
1175 data_len = (apr_size_t)avail;
1180 status = apr_bucket_read(b, &data, &data_len,
1183 if (status == APR_SUCCESS) {
1184 status = cb(ctx, data, data_len);
1188 data_len = b->length;
1191 written += data_len;
1194 next = APR_BUCKET_NEXT(b);
1196 apr_bucket_delete(b);
1201 if (status == APR_SUCCESS && !*peos && !*plen) {
1207 apr_size_t h2_util_bucket_print(char *buffer, apr_size_t bmax,
1208 apr_bucket *b, const char *sep)
1212 off += apr_snprintf(buffer+off, bmax-off, "%s", sep);
1218 if (APR_BUCKET_IS_METADATA(b)) {
1219 if (APR_BUCKET_IS_EOS(b)) {
1220 off += apr_snprintf(buffer+off, bmax-off, "eos");
1222 else if (APR_BUCKET_IS_FLUSH(b)) {
1223 off += apr_snprintf(buffer+off, bmax-off, "flush");
1225 else if (AP_BUCKET_IS_EOR(b)) {
1226 off += apr_snprintf(buffer+off, bmax-off, "eor");
1229 off += apr_snprintf(buffer+off, bmax-off, "%s", b->type->name);
1233 const char *btype = b->type->name;
1234 if (APR_BUCKET_IS_FILE(b)) {
1237 else if (APR_BUCKET_IS_PIPE(b)) {
1240 else if (APR_BUCKET_IS_SOCKET(b)) {
1243 else if (APR_BUCKET_IS_HEAP(b)) {
1246 else if (APR_BUCKET_IS_TRANSIENT(b)) {
1247 btype = "transient";
1249 else if (APR_BUCKET_IS_IMMORTAL(b)) {
1253 else if (APR_BUCKET_IS_MMAP(b)) {
1257 else if (APR_BUCKET_IS_POOL(b)) {
1262 off += apr_snprintf(buffer+off, bmax-off, "%s[%ld]",
1264 (long)(b->length == ((apr_size_t)-1)?
1271 apr_size_t h2_util_bb_print(char *buffer, apr_size_t bmax,
1272 const char *tag, const char *sep,
1273 apr_bucket_brigade *bb)
1276 const char *sp = "";
1281 memset(buffer, 0, bmax--);
1282 off += apr_snprintf(buffer+off, bmax-off, "%s(", tag);
1283 for (b = APR_BRIGADE_FIRST(bb);
1284 (bmax > off) && (b != APR_BRIGADE_SENTINEL(bb));
1285 b = APR_BUCKET_NEXT(b)) {
1287 off += h2_util_bucket_print(buffer+off, bmax-off, b, sp);
1291 off += apr_snprintf(buffer+off, bmax-off, ")%s", sep);
1295 off += apr_snprintf(buffer+off, bmax-off, "%s(null)%s", tag, sep);
1301 apr_status_t h2_append_brigade(apr_bucket_brigade *to,
1302 apr_bucket_brigade *from,
1305 h2_bucket_gate *should_append)
1308 apr_off_t len = 0, remain = *plen;
1313 while (!APR_BRIGADE_EMPTY(from)) {
1314 e = APR_BRIGADE_FIRST(from);
1316 if (!should_append(e)) {
1319 else if (APR_BUCKET_IS_METADATA(e)) {
1320 if (APR_BUCKET_IS_EOS(e)) {
1322 apr_bucket_delete(e);
1327 if (remain > 0 && e->length == ((apr_size_t)-1)) {
1330 rv = apr_bucket_read(e, &ign, &ilen, APR_BLOCK_READ);
1331 if (rv != APR_SUCCESS) {
1336 if (remain < e->length) {
1340 apr_bucket_split(e, (apr_size_t)remain);
1344 APR_BUCKET_REMOVE(e);
1345 APR_BRIGADE_INSERT_TAIL(to, e);
1347 remain -= e->length;
1354 apr_off_t h2_brigade_mem_size(apr_bucket_brigade *bb)
1357 apr_off_t total = 0;
1359 for (b = APR_BRIGADE_FIRST(bb);
1360 b != APR_BRIGADE_SENTINEL(bb);
1361 b = APR_BUCKET_NEXT(b))
1363 total += sizeof(*b);
1364 if (b->length > 0) {
1365 if (APR_BUCKET_IS_HEAP(b)
1366 || APR_BUCKET_IS_POOL(b)) {
1375 /*******************************************************************************
1377 ******************************************************************************/
1379 int h2_util_ignore_header(const char *name)
1381 /* never forward, ch. 8.1.2.2 */
1382 return (H2_HD_MATCH_LIT_CS("connection", name)
1383 || H2_HD_MATCH_LIT_CS("proxy-connection", name)
1384 || H2_HD_MATCH_LIT_CS("upgrade", name)
1385 || H2_HD_MATCH_LIT_CS("keep-alive", name)
1386 || H2_HD_MATCH_LIT_CS("transfer-encoding", name));
1389 static int count_header(void *ctx, const char *key, const char *value)
1391 if (!h2_util_ignore_header(key)) {
1392 (*((size_t*)ctx))++;
1397 #define NV_ADD_LIT_CS(nv, k, v) add_header(nv, k, sizeof(k) - 1, v, strlen(v))
1398 #define NV_ADD_CS_CS(nv, k, v) add_header(nv, k, strlen(k), v, strlen(v))
1400 static int add_header(h2_ngheader *ngh,
1401 const char *key, size_t key_len,
1402 const char *value, size_t val_len)
1404 nghttp2_nv *nv = &ngh->nv[ngh->nvlen++];
1406 nv->name = (uint8_t*)key;
1407 nv->namelen = key_len;
1408 nv->value = (uint8_t*)value;
1409 nv->valuelen = val_len;
1413 static int add_table_header(void *ctx, const char *key, const char *value)
1415 if (!h2_util_ignore_header(key)) {
1416 add_header(ctx, key, strlen(key), value, strlen(value));
1422 h2_ngheader *h2_util_ngheader_make(apr_pool_t *p, apr_table_t *header)
1428 apr_table_do(count_header, &n, header, NULL);
1430 ngh = apr_pcalloc(p, sizeof(h2_ngheader));
1431 ngh->nv = apr_pcalloc(p, n * sizeof(nghttp2_nv));
1432 apr_table_do(add_table_header, ngh, header, NULL);
1437 h2_ngheader *h2_util_ngheader_make_res(apr_pool_t *p,
1439 apr_table_t *header)
1445 apr_table_do(count_header, &n, header, NULL);
1447 ngh = apr_pcalloc(p, sizeof(h2_ngheader));
1448 ngh->nv = apr_pcalloc(p, n * sizeof(nghttp2_nv));
1449 NV_ADD_LIT_CS(ngh, ":status", apr_psprintf(p, "%d", http_status));
1450 apr_table_do(add_table_header, ngh, header, NULL);
1455 h2_ngheader *h2_util_ngheader_make_req(apr_pool_t *p,
1456 const struct h2_request *req)
1463 ap_assert(req->scheme);
1464 ap_assert(req->authority);
1465 ap_assert(req->path);
1466 ap_assert(req->method);
1469 apr_table_do(count_header, &n, req->headers, NULL);
1471 ngh = apr_pcalloc(p, sizeof(h2_ngheader));
1472 ngh->nv = apr_pcalloc(p, n * sizeof(nghttp2_nv));
1473 NV_ADD_LIT_CS(ngh, ":scheme", req->scheme);
1474 NV_ADD_LIT_CS(ngh, ":authority", req->authority);
1475 NV_ADD_LIT_CS(ngh, ":path", req->path);
1476 NV_ADD_LIT_CS(ngh, ":method", req->method);
1477 apr_table_do(add_table_header, ngh, req->headers, NULL);
1482 /*******************************************************************************
1483 * header HTTP/1 <-> HTTP/2 conversions
1484 ******************************************************************************/
1492 #define H2_DEF_LITERAL(n) { (n), (sizeof(n)-1) }
1493 #define H2_LIT_ARGS(a) (a),H2_ALEN(a)
1495 static literal IgnoredRequestHeaders[] = {
1496 /*H2_DEF_LITERAL("expect"),*/
1497 H2_DEF_LITERAL("upgrade"),
1498 H2_DEF_LITERAL("connection"),
1499 H2_DEF_LITERAL("keep-alive"),
1500 H2_DEF_LITERAL("http2-settings"),
1501 H2_DEF_LITERAL("proxy-connection"),
1502 H2_DEF_LITERAL("transfer-encoding"),
1504 static literal IgnoredRequestTrailers[] = { /* Ignore, see rfc7230, ch. 4.1.2 */
1505 H2_DEF_LITERAL("te"),
1506 H2_DEF_LITERAL("host"),
1507 H2_DEF_LITERAL("range"),
1508 H2_DEF_LITERAL("cookie"),
1509 H2_DEF_LITERAL("expect"),
1510 H2_DEF_LITERAL("pragma"),
1511 H2_DEF_LITERAL("max-forwards"),
1512 H2_DEF_LITERAL("cache-control"),
1513 H2_DEF_LITERAL("authorization"),
1514 H2_DEF_LITERAL("content-length"),
1515 H2_DEF_LITERAL("proxy-authorization"),
1517 static literal IgnoredResponseTrailers[] = {
1518 H2_DEF_LITERAL("age"),
1519 H2_DEF_LITERAL("date"),
1520 H2_DEF_LITERAL("vary"),
1521 H2_DEF_LITERAL("cookie"),
1522 H2_DEF_LITERAL("expires"),
1523 H2_DEF_LITERAL("warning"),
1524 H2_DEF_LITERAL("location"),
1525 H2_DEF_LITERAL("retry-after"),
1526 H2_DEF_LITERAL("cache-control"),
1527 H2_DEF_LITERAL("www-authenticate"),
1528 H2_DEF_LITERAL("proxy-authenticate"),
1531 static int ignore_header(const literal *lits, size_t llen,
1532 const char *name, size_t nlen)
1537 for (i = 0; i < llen; ++i) {
1539 if (lit->len == nlen && !apr_strnatcasecmp(lit->name, name)) {
1546 int h2_req_ignore_header(const char *name, size_t len)
1548 return ignore_header(H2_LIT_ARGS(IgnoredRequestHeaders), name, len);
1551 int h2_req_ignore_trailer(const char *name, size_t len)
1553 return (h2_req_ignore_header(name, len)
1554 || ignore_header(H2_LIT_ARGS(IgnoredRequestTrailers), name, len));
1557 int h2_res_ignore_trailer(const char *name, size_t len)
1559 return ignore_header(H2_LIT_ARGS(IgnoredResponseTrailers), name, len);
1562 apr_status_t h2_headers_add_h1(apr_table_t *headers, apr_pool_t *pool,
1563 const char *name, size_t nlen,
1564 const char *value, size_t vlen)
1566 char *hname, *hvalue;
1568 if (h2_req_ignore_header(name, nlen)) {
1571 else if (H2_HD_MATCH_LIT("cookie", name, nlen)) {
1572 const char *existing = apr_table_get(headers, "cookie");
1576 /* Cookie header come separately in HTTP/2, but need
1577 * to be merged by "; " (instead of default ", ")
1579 hvalue = apr_pstrndup(pool, value, vlen);
1580 nval = apr_psprintf(pool, "%s; %s", existing, hvalue);
1581 apr_table_setn(headers, "Cookie", nval);
1585 else if (H2_HD_MATCH_LIT("host", name, nlen)) {
1586 if (apr_table_get(headers, "Host")) {
1587 return APR_SUCCESS; /* ignore duplicate */
1591 hname = apr_pstrndup(pool, name, nlen);
1592 hvalue = apr_pstrndup(pool, value, vlen);
1593 h2_util_camel_case_header(hname, nlen);
1594 apr_table_mergen(headers, hname, hvalue);
1599 /*******************************************************************************
1600 * h2 request handling
1601 ******************************************************************************/
1603 h2_request *h2_req_create(int id, apr_pool_t *pool, const char *method,
1604 const char *scheme, const char *authority,
1605 const char *path, apr_table_t *header, int serialize)
1607 h2_request *req = apr_pcalloc(pool, sizeof(h2_request));
1609 req->method = method;
1610 req->scheme = scheme;
1611 req->authority = authority;
1613 req->headers = header? header : apr_table_make(pool, 10);
1614 req->request_time = apr_time_now();
1615 req->serialize = serialize;
1620 /*******************************************************************************
1622 ******************************************************************************/
1624 int h2_util_frame_print(const nghttp2_frame *frame, char *buffer, size_t maxlen)
1627 size_t s_len = sizeof(scratch)/sizeof(scratch[0]);
1629 switch (frame->hd.type) {
1630 case NGHTTP2_DATA: {
1631 return apr_snprintf(buffer, maxlen,
1632 "DATA[length=%d, flags=%d, stream=%d, padlen=%d]",
1633 (int)frame->hd.length, frame->hd.flags,
1634 frame->hd.stream_id, (int)frame->data.padlen);
1636 case NGHTTP2_HEADERS: {
1637 return apr_snprintf(buffer, maxlen,
1638 "HEADERS[length=%d, hend=%d, stream=%d, eos=%d]",
1639 (int)frame->hd.length,
1640 !!(frame->hd.flags & NGHTTP2_FLAG_END_HEADERS),
1641 frame->hd.stream_id,
1642 !!(frame->hd.flags & NGHTTP2_FLAG_END_STREAM));
1644 case NGHTTP2_PRIORITY: {
1645 return apr_snprintf(buffer, maxlen,
1646 "PRIORITY[length=%d, flags=%d, stream=%d]",
1647 (int)frame->hd.length,
1648 frame->hd.flags, frame->hd.stream_id);
1650 case NGHTTP2_RST_STREAM: {
1651 return apr_snprintf(buffer, maxlen,
1652 "RST_STREAM[length=%d, flags=%d, stream=%d]",
1653 (int)frame->hd.length,
1654 frame->hd.flags, frame->hd.stream_id);
1656 case NGHTTP2_SETTINGS: {
1657 if (frame->hd.flags & NGHTTP2_FLAG_ACK) {
1658 return apr_snprintf(buffer, maxlen,
1659 "SETTINGS[ack=1, stream=%d]",
1660 frame->hd.stream_id);
1662 return apr_snprintf(buffer, maxlen,
1663 "SETTINGS[length=%d, stream=%d]",
1664 (int)frame->hd.length, frame->hd.stream_id);
1666 case NGHTTP2_PUSH_PROMISE: {
1667 return apr_snprintf(buffer, maxlen,
1668 "PUSH_PROMISE[length=%d, hend=%d, stream=%d]",
1669 (int)frame->hd.length,
1670 !!(frame->hd.flags & NGHTTP2_FLAG_END_HEADERS),
1671 frame->hd.stream_id);
1673 case NGHTTP2_PING: {
1674 return apr_snprintf(buffer, maxlen,
1675 "PING[length=%d, ack=%d, stream=%d]",
1676 (int)frame->hd.length,
1677 frame->hd.flags&NGHTTP2_FLAG_ACK,
1678 frame->hd.stream_id);
1680 case NGHTTP2_GOAWAY: {
1681 size_t len = (frame->goaway.opaque_data_len < s_len)?
1682 frame->goaway.opaque_data_len : s_len-1;
1683 memcpy(scratch, frame->goaway.opaque_data, len);
1684 scratch[len] = '\0';
1685 return apr_snprintf(buffer, maxlen, "GOAWAY[error=%d, reason='%s', "
1686 "last_stream=%d]", frame->goaway.error_code,
1687 scratch, frame->goaway.last_stream_id);
1689 case NGHTTP2_WINDOW_UPDATE: {
1690 return apr_snprintf(buffer, maxlen,
1691 "WINDOW_UPDATE[stream=%d, incr=%d]",
1692 frame->hd.stream_id,
1693 frame->window_update.window_size_increment);
1696 return apr_snprintf(buffer, maxlen,
1697 "type=%d[length=%d, flags=%d, stream=%d]",
1698 frame->hd.type, (int)frame->hd.length,
1699 frame->hd.flags, frame->hd.stream_id);
1703 /*******************************************************************************
1705 ******************************************************************************/
1706 int h2_push_policy_determine(apr_table_t *headers, apr_pool_t *p, int push_enabled)
1708 h2_push_policy policy = H2_PUSH_NONE;
1710 const char *val = apr_table_get(headers, "accept-push-policy");
1712 if (ap_find_token(p, val, "fast-load")) {
1713 policy = H2_PUSH_FAST_LOAD;
1715 else if (ap_find_token(p, val, "head")) {
1716 policy = H2_PUSH_HEAD;
1718 else if (ap_find_token(p, val, "default")) {
1719 policy = H2_PUSH_DEFAULT;
1721 else if (ap_find_token(p, val, "none")) {
1722 policy = H2_PUSH_NONE;
1725 /* nothing known found in this header, go by default */
1726 policy = H2_PUSH_DEFAULT;
1730 policy = H2_PUSH_DEFAULT;