Apache HTTPD
h2_util.c
Go to the documentation of this file.
1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <assert.h>
18#include <apr_strings.h>
19#include <apr_thread_mutex.h>
20#include <apr_thread_cond.h>
21
22#include <httpd.h>
23#include <http_core.h>
24#include <http_log.h>
25#include <http_protocol.h>
26#include <http_request.h>
27
28#include <nghttp2/nghttp2.h>
29
30#include "h2.h"
31#include "h2_headers.h"
32#include "h2_util.h"
33
34/* h2_log2(n) iff n is a power of 2 */
35unsigned char h2_log2(int n)
36{
37 int lz = 0;
38 if (!n) {
39 return 0;
40 }
41 if (!(n & 0xffff0000u)) {
42 lz += 16;
43 n = (n << 16);
44 }
45 if (!(n & 0xff000000u)) {
46 lz += 8;
47 n = (n << 8);
48 }
49 if (!(n & 0xf0000000u)) {
50 lz += 4;
51 n = (n << 4);
52 }
53 if (!(n & 0xc0000000u)) {
54 lz += 2;
55 n = (n << 2);
56 }
57 if (!(n & 0x80000000u)) {
58 lz += 1;
59 }
60
61 return 31 - lz;
62}
63
64size_t h2_util_hex_dump(char *buffer, size_t maxlen,
65 const char *data, size_t datalen)
66{
67 size_t offset = 0;
68 size_t maxoffset = (maxlen-4);
69 size_t i;
70 for (i = 0; i < datalen && offset < maxoffset; ++i) {
71 const char *sep = (i && i % 16 == 0)? "\n" : " ";
73 "%2x%s", ((unsigned int)data[i]&0xff), sep);
74 offset += n;
75 }
76 strcpy(buffer+offset, (i<datalen)? "..." : "");
77 return strlen(buffer);
78}
79
80void h2_util_camel_case_header(char *s, size_t len)
81{
82 size_t start = 1;
83 size_t i;
84 for (i = 0; i < len; ++i) {
85 if (start) {
86 if (s[i] >= 'a' && s[i] <= 'z') {
87 s[i] -= 'a' - 'A';
88 }
89
90 start = 0;
91 }
92 else if (s[i] == '-') {
93 start = 1;
94 }
95 }
96}
97
98/* base64 url encoding */
99
100#define N6 (unsigned int)-1
101
102static const unsigned int BASE64URL_UINT6[] = {
103/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
104 N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, /* 0 */
105 N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, /* 1 */
106 N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, 62, N6, N6, /* 2 */
107 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, N6, N6, N6, N6, N6, N6, /* 3 */
108 N6, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 4 */
109 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, N6, N6, N6, N6, 63, /* 5 */
110 N6, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 6 */
111 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, N6, N6, N6, N6, N6, /* 7 */
112 N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, /* 8 */
113 N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, /* 9 */
114 N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, /* a */
115 N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, /* b */
116 N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, /* c */
117 N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, /* d */
118 N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, /* e */
119 N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6 /* f */
120};
121static const unsigned char BASE64URL_CHARS[] = {
122 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', /* 0 - 9 */
123 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', /* 10 - 19 */
124 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', /* 20 - 29 */
125 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', /* 30 - 39 */
126 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', /* 40 - 49 */
127 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', /* 50 - 59 */
128 '8', '9', '-', '_', ' ', ' ', ' ', ' ', ' ', ' ', /* 60 - 69 */
129};
130
131#define BASE64URL_CHAR(x) BASE64URL_CHARS[ (unsigned int)(x) & 0x3fu ]
132
133apr_size_t h2_util_base64url_decode(const char **decoded, const char *encoded,
135{
136 const unsigned char *e = (const unsigned char *)encoded;
137 const unsigned char *p = e;
138 unsigned char *d;
139 unsigned int n;
140 long len, mlen, remain, i;
141
142 while (*p && BASE64URL_UINT6[ *p ] != N6) {
143 ++p;
144 }
145 len = (int)(p - e);
146 mlen = (len/4)*4;
148
149 i = 0;
150 d = (unsigned char*)*decoded;
151 for (; i < mlen; i += 4) {
152 n = ((BASE64URL_UINT6[ e[i+0] ] << 18) +
153 (BASE64URL_UINT6[ e[i+1] ] << 12) +
154 (BASE64URL_UINT6[ e[i+2] ] << 6) +
155 (BASE64URL_UINT6[ e[i+3] ]));
156 *d++ = (unsigned char)(n >> 16);
157 *d++ = (unsigned char)(n >> 8 & 0xffu);
158 *d++ = (unsigned char)(n & 0xffu);
159 }
160 remain = len - mlen;
161 switch (remain) {
162 case 2:
163 n = ((BASE64URL_UINT6[ e[mlen+0] ] << 18) +
164 (BASE64URL_UINT6[ e[mlen+1] ] << 12));
165 *d++ = (unsigned char)(n >> 16);
166 remain = 1;
167 break;
168 case 3:
169 n = ((BASE64URL_UINT6[ e[mlen+0] ] << 18) +
170 (BASE64URL_UINT6[ e[mlen+1] ] << 12) +
171 (BASE64URL_UINT6[ e[mlen+2] ] << 6));
172 *d++ = (unsigned char)(n >> 16);
173 *d++ = (unsigned char)(n >> 8 & 0xffu);
174 remain = 2;
175 break;
176 default: /* do nothing */
177 break;
178 }
179 return (apr_size_t)(mlen/4*3 + remain);
180}
181
182const char *h2_util_base64url_encode(const char *data,
184{
185 int i, len = (int)dlen;
186 apr_size_t slen = ((dlen+2)/3)*4 + 1; /* 0 terminated */
187 const unsigned char *udata = (const unsigned char*)data;
188 unsigned char *enc, *p = apr_pcalloc(pool, slen);
189
190 enc = p;
191 for (i = 0; i < len-2; i+= 3) {
192 *p++ = BASE64URL_CHAR( (udata[i] >> 2) );
193 *p++ = BASE64URL_CHAR( (udata[i] << 4) + (udata[i+1] >> 4) );
194 *p++ = BASE64URL_CHAR( (udata[i+1] << 2) + (udata[i+2] >> 6) );
195 *p++ = BASE64URL_CHAR( (udata[i+2]) );
196 }
197
198 if (i < len) {
199 *p++ = BASE64URL_CHAR( (udata[i] >> 2) );
200 if (i == (len - 1)) {
201 *p++ = BASE64URL_CHARS[ ((unsigned int)udata[i] << 4) & 0x3fu ];
202 }
203 else {
204 *p++ = BASE64URL_CHAR( (udata[i] << 4) + (udata[i+1] >> 4) );
205 *p++ = BASE64URL_CHAR( (udata[i+1] << 2) );
206 }
207 }
208 *p++ = '\0';
209 return (char *)enc;
210}
211
212/*******************************************************************************
213 * ihash - hash for structs with int identifier
214 ******************************************************************************/
217 size_t ioff;
218};
219
220static unsigned int ihash(const char *key, apr_ssize_t *klen)
221{
222 return (unsigned int)(*((int*)key));
223}
224
226{
227 h2_ihash_t *ih = apr_pcalloc(pool, sizeof(h2_ihash_t));
229 ih->ioff = offset_of_int;
230 return ih;
231}
232
233unsigned int h2_ihash_count(h2_ihash_t *ih)
234{
235 return apr_hash_count(ih->hash);
236}
237
239{
240 return apr_hash_count(ih->hash) == 0;
241}
242
243void *h2_ihash_get(h2_ihash_t *ih, int id)
244{
245 return apr_hash_get(ih->hash, &id, sizeof(id));
246}
247
248typedef struct {
250 void *ctx;
251} iter_ctx;
252
253static int ihash_iter(void *ctx, const void *key, apr_ssize_t klen,
254 const void *val)
255{
256 iter_ctx *ictx = ctx;
257 return ictx->iter(ictx->ctx, (void*)val); /* why is this passed const?*/
258}
259
261{
263 ictx.iter = fn;
264 ictx.ctx = ctx;
265 return apr_hash_do(ihash_iter, &ictx, ih->hash);
266}
267
269{
270 apr_hash_set(ih->hash, ((char *)val + ih->ioff), sizeof(int), val);
271}
272
274{
275 apr_hash_set(ih->hash, &id, sizeof(id), NULL);
276}
277
279{
280 int id = *((int*)((char *)val + ih->ioff));
281 apr_hash_set(ih->hash, &id, sizeof(id), NULL);
282}
283
284
286{
287 apr_hash_clear(ih->hash);
288}
289
290typedef struct {
292 void **buffer;
293 size_t max;
294 size_t len;
296
297static int collect_iter(void *x, void *val)
298{
299 collect_ctx *ctx = x;
300 if (ctx->len < ctx->max) {
301 ctx->buffer[ctx->len++] = val;
302 return 1;
303 }
304 return 0;
305}
306
307size_t h2_ihash_shift(h2_ihash_t *ih, void **buffer, size_t max)
308{
310 size_t i;
311
312 ctx.ih = ih;
313 ctx.buffer = buffer;
314 ctx.max = max;
315 ctx.len = 0;
317 for (i = 0; i < ctx.len; ++i) {
319 }
320 return ctx.len;
321}
322
323/*******************************************************************************
324 * iqueue - sorted list of int
325 ******************************************************************************/
326
327static void iq_grow(h2_iqueue *q, int nlen);
328static void iq_swap(h2_iqueue *q, int i, int j);
329static int iq_bubble_up(h2_iqueue *q, int i, int top,
330 h2_iq_cmp *cmp, void *ctx);
331static int iq_bubble_down(h2_iqueue *q, int i, int bottom,
332 h2_iq_cmp *cmp, void *ctx);
333
335{
336 h2_iqueue *q = apr_pcalloc(pool, sizeof(h2_iqueue));
337 q->pool = pool;
338 iq_grow(q, capacity);
339 q->nelts = 0;
340 return q;
341}
342
344{
345 return q->nelts == 0;
346}
347
349{
350 return q->nelts;
351}
352
353
354int h2_iq_add(h2_iqueue *q, int sid, h2_iq_cmp *cmp, void *ctx)
355{
356 int i;
357
358 if (h2_iq_contains(q, sid)) {
359 return 0;
360 }
361 if (q->nelts >= q->nalloc) {
362 iq_grow(q, q->nalloc * 2);
363 }
364 i = (q->head + q->nelts) % q->nalloc;
365 q->elts[i] = sid;
366 ++q->nelts;
367
368 if (cmp) {
369 /* bubble it to the front of the queue */
370 iq_bubble_up(q, i, q->head, cmp, ctx);
371 }
372 return 1;
373}
374
376{
377 return h2_iq_add(q, sid, NULL, NULL);
378}
379
381{
382 int i;
383 for (i = 0; i < q->nelts; ++i) {
384 if (sid == q->elts[(q->head + i) % q->nalloc]) {
385 break;
386 }
387 }
388
389 if (i < q->nelts) {
390 ++i;
391 for (; i < q->nelts; ++i) {
392 q->elts[(q->head+i-1)%q->nalloc] = q->elts[(q->head+i)%q->nalloc];
393 }
394 --q->nelts;
395 return 1;
396 }
397 return 0;
398}
399
401{
402 q->nelts = 0;
403}
404
406{
407 /* Assume that changes in ordering are minimal. This needs,
408 * best case, q->nelts - 1 comparisons to check that nothing
409 * changed.
410 */
411 if (q->nelts > 0) {
412 int i, ni, prev, last;
413
414 /* Start at the end of the queue and create a tail of sorted
415 * entries. Make that tail one element longer in each iteration.
416 */
417 last = i = (q->head + q->nelts - 1) % q->nalloc;
418 while (i != q->head) {
419 prev = (q->nalloc + i - 1) % q->nalloc;
420
421 ni = iq_bubble_up(q, i, prev, cmp, ctx);
422 if (ni == prev) {
423 /* i bubbled one up, bubble the new i down, which
424 * keeps all ints below i sorted. */
425 iq_bubble_down(q, i, last, cmp, ctx);
426 }
427 i = prev;
428 };
429 }
430}
431
432
434{
435 int sid;
436
437 if (q->nelts <= 0) {
438 return 0;
439 }
440
441 sid = q->elts[q->head];
442 q->head = (q->head + 1) % q->nalloc;
443 q->nelts--;
444
445 return sid;
446}
447
448size_t h2_iq_mshift(h2_iqueue *q, int *pint, size_t max)
449{
450 size_t i;
451 for (i = 0; i < max; ++i) {
452 pint[i] = h2_iq_shift(q);
453 if (pint[i] == 0) {
454 break;
455 }
456 }
457 return i;
458}
459
460static void iq_grow(h2_iqueue *q, int nlen)
461{
462 if (nlen > q->nalloc) {
463 int *nq = apr_pcalloc(q->pool, sizeof(int) * nlen);
464 if (q->nelts > 0) {
465 int l = ((q->head + q->nelts) % q->nalloc) - q->head;
466
467 memmove(nq, q->elts + q->head, sizeof(int) * l);
468 if (l < q->nelts) {
469 /* elts wrapped, append elts in [0, remain] to nq */
470 int remain = q->nelts - l;
471 memmove(nq + l, q->elts, sizeof(int) * remain);
472 }
473 }
474 q->elts = nq;
475 q->nalloc = nlen;
476 q->head = 0;
477 }
478}
479
480static void iq_swap(h2_iqueue *q, int i, int j)
481{
482 int x = q->elts[i];
483 q->elts[i] = q->elts[j];
484 q->elts[j] = x;
485}
486
487static int iq_bubble_up(h2_iqueue *q, int i, int top,
488 h2_iq_cmp *cmp, void *ctx)
489{
490 int prev;
491 while (((prev = (q->nalloc + i - 1) % q->nalloc), i != top)
492 && (*cmp)(q->elts[i], q->elts[prev], ctx) < 0) {
493 iq_swap(q, prev, i);
494 i = prev;
495 }
496 return i;
497}
498
499static int iq_bubble_down(h2_iqueue *q, int i, int bottom,
500 h2_iq_cmp *cmp, void *ctx)
501{
502 int next;
503 while (((next = (q->nalloc + i + 1) % q->nalloc), i != bottom)
504 && (*cmp)(q->elts[i], q->elts[next], ctx) > 0) {
505 iq_swap(q, next, i);
506 i = next;
507 }
508 return i;
509}
510
512{
513 int i;
514 for (i = 0; i < q->nelts; ++i) {
515 if (sid == q->elts[(q->head + i) % q->nalloc]) {
516 return 1;
517 }
518 }
519 return 0;
520}
521
522/*******************************************************************************
523 * FIFO queue
524 ******************************************************************************/
525
538
540{
541 h2_fifo *fifo = data;
542
543 apr_thread_cond_destroy(fifo->not_empty);
544 apr_thread_cond_destroy(fifo->not_full);
546
547 return APR_SUCCESS;
548}
549
550static int index_of(h2_fifo *fifo, void *elem)
551{
552 int i;
553
554 for (i = fifo->out; i != fifo->in; i = (i + 1) % fifo->capacity) {
555 if (elem == fifo->elems[i]) {
556 return i;
557 }
558 }
559 return -1;
560}
561
563 int capacity, int as_set)
564{
565 apr_status_t rv;
566 h2_fifo *fifo;
567
568 fifo = apr_pcalloc(pool, sizeof(*fifo));
569 if (fifo == NULL) {
570 return APR_ENOMEM;
571 }
572
573 rv = apr_thread_mutex_create(&fifo->lock,
575 if (rv != APR_SUCCESS) {
576 return rv;
577 }
578
579 rv = apr_thread_cond_create(&fifo->not_empty, pool);
580 if (rv != APR_SUCCESS) {
581 return rv;
582 }
583
584 rv = apr_thread_cond_create(&fifo->not_full, pool);
585 if (rv != APR_SUCCESS) {
586 return rv;
587 }
588
589 fifo->elems = apr_pcalloc(pool, capacity * sizeof(void*));
590 if (fifo->elems == NULL) {
591 return APR_ENOMEM;
592 }
593 fifo->capacity = capacity;
594 fifo->set = as_set;
595
596 *pfifo = fifo;
598
599 return APR_SUCCESS;
600}
601
603{
604 return create_int(pfifo, pool, capacity, 0);
605}
606
608{
609 return create_int(pfifo, pool, capacity, 1);
610}
611
613{
614 apr_status_t rv;
615 if ((rv = apr_thread_mutex_lock(fifo->lock)) == APR_SUCCESS) {
616 fifo->aborted = 1;
620 }
621 return rv;
622}
623
625{
626 int n;
627
629 n = fifo->count;
631 return n;
632}
633
635{
636 while (fifo->count == 0) {
637 if (!block) {
638 return APR_EAGAIN;
639 }
640 if (fifo->aborted) {
641 return APR_EOF;
642 }
643 apr_thread_cond_wait(fifo->not_empty, fifo->lock);
644 }
645 return APR_SUCCESS;
646}
647
649{
650 if (fifo->aborted) {
651 return APR_EOF;
652 }
653
654 if (fifo->set && index_of(fifo, elem) >= 0) {
655 /* set mode, elem already member */
656 return APR_EEXIST;
657 }
658 else if (fifo->count == fifo->capacity) {
659 if (block) {
660 while (fifo->count == fifo->capacity) {
661 if (fifo->aborted) {
662 return APR_EOF;
663 }
664 apr_thread_cond_wait(fifo->not_full, fifo->lock);
665 }
666 }
667 else {
668 return APR_EAGAIN;
669 }
670 }
671
672 fifo->elems[fifo->in++] = elem;
673 if (fifo->in >= fifo->capacity) {
674 fifo->in -= fifo->capacity;
675 }
676 ++fifo->count;
677 if (fifo->count == 1) {
678 apr_thread_cond_signal(fifo->not_empty);
679 }
680 return APR_SUCCESS;
681}
682
684{
685 apr_status_t rv;
686
687 if ((rv = apr_thread_mutex_lock(fifo->lock)) == APR_SUCCESS) {
690 }
691 return rv;
692}
693
695{
696 return fifo_push(fifo, elem, 1);
697}
698
700{
701 return fifo_push(fifo, elem, 0);
702}
703
705{
706 apr_status_t rv;
707 int was_full;
708
709 if ((rv = check_not_empty(fifo, block)) != APR_SUCCESS) {
710 *pelem = NULL;
711 return rv;
712 }
713 *pelem = fifo->elems[fifo->out++];
714 if (fifo->out >= fifo->capacity) {
715 fifo->out -= fifo->capacity;
716 }
717 was_full = (fifo->count == fifo->capacity);
718 --fifo->count;
719 if (was_full) {
721 }
722 return APR_SUCCESS;
723}
724
726{
727 apr_status_t rv;
728
729 if ((rv = apr_thread_mutex_lock(fifo->lock)) == APR_SUCCESS) {
730 rv = pull_head(fifo, pelem, block);
732 }
733 return rv;
734}
735
737{
738 return fifo_pull(fifo, pelem, 1);
739}
740
742{
743 return fifo_pull(fifo, pelem, 0);
744}
745
747{
748 apr_status_t rv;
749 void *elem;
750
751 if (fifo->aborted) {
752 return APR_EOF;
753 }
754
755 if (APR_SUCCESS == (rv = apr_thread_mutex_lock(fifo->lock))) {
756 if (APR_SUCCESS == (rv = pull_head(fifo, &elem, block))) {
757 switch (fn(elem, ctx)) {
758 case H2_FIFO_OP_PULL:
759 break;
762 break;
763 }
764 }
766 }
767 return rv;
768}
769
771{
772 return fifo_peek(fifo, fn, ctx, 1);
773}
774
776{
777 return fifo_peek(fifo, fn, ctx, 0);
778}
779
781{
782 apr_status_t rv;
783
784 if (fifo->aborted) {
785 return APR_EOF;
786 }
787
788 if ((rv = apr_thread_mutex_lock(fifo->lock)) == APR_SUCCESS) {
789 int i, last_count = fifo->count;
790
791 for (i = fifo->out; i != fifo->in; i = (i + 1) % fifo->capacity) {
792 if (fifo->elems[i] == elem) {
793 --fifo->count;
794 if (fifo->count == 0) {
795 fifo->out = fifo->in = 0;
796 }
797 else if (i == fifo->out) {
798 /* first element */
799 ++fifo->out;
800 if (fifo->out >= fifo->capacity) {
801 fifo->out -= fifo->capacity;
802 }
803 }
804 else if (((i + 1) % fifo->capacity) == fifo->in) {
805 /* last element */
806 --fifo->in;
807 if (fifo->in < 0) {
808 fifo->in += fifo->capacity;
809 }
810 }
811 else if (i > fifo->out) {
812 /* between out and in/capacity, move elements below up */
813 memmove(&fifo->elems[fifo->out+1], &fifo->elems[fifo->out],
814 (i - fifo->out) * sizeof(void*));
815 ++fifo->out;
816 if (fifo->out >= fifo->capacity) {
817 fifo->out -= fifo->capacity;
818 }
819 }
820 else {
821 /* we wrapped around, move elements above down */
822 AP_DEBUG_ASSERT((fifo->in - i - 1) > 0);
823 AP_DEBUG_ASSERT((fifo->in - i - 1) < fifo->capacity);
824 memmove(&fifo->elems[i], &fifo->elems[i + 1],
825 (fifo->in - i - 1) * sizeof(void*));
826 --fifo->in;
827 if (fifo->in < 0) {
828 fifo->in += fifo->capacity;
829 }
830 }
831 }
832 }
833 if (fifo->count != last_count) {
834 if (last_count == fifo->capacity) {
836 }
837 rv = APR_SUCCESS;
838 }
839 else {
840 rv = APR_EAGAIN;
841 }
842
844 }
845 return rv;
846}
847
848/*******************************************************************************
849 * FIFO int queue
850 ******************************************************************************/
851
863
864static int inth_index(h2_ififo *fifo, int n)
865{
866 return (fifo->head + n) % fifo->capacity;
867}
868
870{
871 h2_ififo *fifo = data;
872
873 apr_thread_cond_destroy(fifo->not_empty);
874 apr_thread_cond_destroy(fifo->not_full);
876
877 return APR_SUCCESS;
878}
879
880static int iindex_of(h2_ififo *fifo, int id)
881{
882 int i;
883
884 for (i = 0; i < fifo->count; ++i) {
885 if (id == fifo->elems[inth_index(fifo, i)]) {
886 return i;
887 }
888 }
889 return -1;
890}
891
893 int capacity, int as_set)
894{
895 apr_status_t rv;
896 h2_ififo *fifo;
897
898 fifo = apr_pcalloc(pool, sizeof(*fifo));
899 if (fifo == NULL) {
900 return APR_ENOMEM;
901 }
902
903 rv = apr_thread_mutex_create(&fifo->lock,
905 if (rv != APR_SUCCESS) {
906 return rv;
907 }
908
909 rv = apr_thread_cond_create(&fifo->not_empty, pool);
910 if (rv != APR_SUCCESS) {
911 return rv;
912 }
913
914 rv = apr_thread_cond_create(&fifo->not_full, pool);
915 if (rv != APR_SUCCESS) {
916 return rv;
917 }
918
919 fifo->elems = apr_pcalloc(pool, capacity * sizeof(int));
920 if (fifo->elems == NULL) {
921 return APR_ENOMEM;
922 }
923 fifo->capacity = capacity;
924 fifo->set = as_set;
925
926 *pfifo = fifo;
928
929 return APR_SUCCESS;
930}
931
933{
934 return icreate_int(pfifo, pool, capacity, 0);
935}
936
938{
939 return icreate_int(pfifo, pool, capacity, 1);
940}
941
943{
944 apr_status_t rv;
945 if ((rv = apr_thread_mutex_lock(fifo->lock)) == APR_SUCCESS) {
946 fifo->aborted = 1;
950 }
951 return rv;
952}
953
955{
956 return fifo->count;
957}
958
960{
961 while (fifo->count == 0) {
962 if (!block) {
963 return APR_EAGAIN;
964 }
965 if (fifo->aborted) {
966 return APR_EOF;
967 }
968 apr_thread_cond_wait(fifo->not_empty, fifo->lock);
969 }
970 return APR_SUCCESS;
971}
972
974{
975 if (fifo->aborted) {
976 return APR_EOF;
977 }
978
979 if (fifo->set && iindex_of(fifo, id) >= 0) {
980 /* set mode, elem already member */
981 return APR_EEXIST;
982 }
983 else if (fifo->count == fifo->capacity) {
984 if (block) {
985 while (fifo->count == fifo->capacity) {
986 if (fifo->aborted) {
987 return APR_EOF;
988 }
989 apr_thread_cond_wait(fifo->not_full, fifo->lock);
990 }
991 }
992 else {
993 return APR_EAGAIN;
994 }
995 }
996
997 ap_assert(fifo->count < fifo->capacity);
998 fifo->elems[inth_index(fifo, fifo->count)] = id;
999 ++fifo->count;
1000 if (fifo->count == 1) {
1001 apr_thread_cond_broadcast(fifo->not_empty);
1002 }
1003 return APR_SUCCESS;
1004}
1005
1007{
1008 apr_status_t rv;
1009
1010 if ((rv = apr_thread_mutex_lock(fifo->lock)) == APR_SUCCESS) {
1011 rv = ififo_push_int(fifo, id, block);
1013 }
1014 return rv;
1015}
1016
1018{
1019 return ififo_push(fifo, id, 1);
1020}
1021
1023{
1024 return ififo_push(fifo, id, 0);
1025}
1026
1028{
1029 apr_status_t rv;
1030
1031 if ((rv = icheck_not_empty(fifo, block)) != APR_SUCCESS) {
1032 *pi = 0;
1033 return rv;
1034 }
1035 *pi = fifo->elems[fifo->head];
1036 --fifo->count;
1037 if (fifo->count > 0) {
1038 fifo->head = inth_index(fifo, 1);
1039 if (fifo->count+1 == fifo->capacity) {
1041 }
1042 }
1043 return APR_SUCCESS;
1044}
1045
1047{
1048 apr_status_t rv;
1049
1050 if ((rv = apr_thread_mutex_lock(fifo->lock)) == APR_SUCCESS) {
1051 rv = ipull_head(fifo, pi, block);
1053 }
1054 return rv;
1055}
1056
1058{
1059 return ififo_pull(fifo, pi, 1);
1060}
1061
1063{
1064 return ififo_pull(fifo, pi, 0);
1065}
1066
1068{
1069 apr_status_t rv;
1070 int id;
1071
1072 if (APR_SUCCESS == (rv = apr_thread_mutex_lock(fifo->lock))) {
1073 if (APR_SUCCESS == (rv = ipull_head(fifo, &id, block))) {
1074 switch (fn(id, ctx)) {
1075 case H2_FIFO_OP_PULL:
1076 break;
1077 case H2_FIFO_OP_REPUSH:
1078 rv = ififo_push_int(fifo, id, block);
1079 break;
1080 }
1081 }
1083 }
1084 return rv;
1085}
1086
1088{
1089 return ififo_peek(fifo, fn, ctx, 1);
1090}
1091
1093{
1094 return ififo_peek(fifo, fn, ctx, 0);
1095}
1096
1098{
1099 int rc, i;
1100
1101 if (fifo->aborted) {
1102 return APR_EOF;
1103 }
1104
1105 rc = 0;
1106 for (i = 0; i < fifo->count; ++i) {
1107 int e = fifo->elems[inth_index(fifo, i)];
1108 if (e == id) {
1109 ++rc;
1110 }
1111 else if (rc) {
1112 fifo->elems[inth_index(fifo, i-rc)] = e;
1113 }
1114 }
1115 if (!rc) {
1116 return APR_EAGAIN;
1117 }
1118 fifo->count -= rc;
1119 if (fifo->count + rc == fifo->capacity) {
1121 }
1122 return APR_SUCCESS;
1123}
1124
1126{
1127 apr_status_t rv;
1128
1129 if ((rv = apr_thread_mutex_lock(fifo->lock)) == APR_SUCCESS) {
1130 rv = ififo_remove(fifo, id);
1132 }
1133 return rv;
1134}
1135
1136/*******************************************************************************
1137 * h2_util for apt_table_t
1138 ******************************************************************************/
1139
1144
1145static int count_bytes(void *x, const char *key, const char *value)
1146{
1147 table_bytes_ctx *ctx = x;
1148 if (key) {
1149 ctx->bytes += strlen(key);
1150 }
1151 if (value) {
1152 ctx->bytes += strlen(value);
1153 }
1154 ctx->bytes += ctx->pair_extra;
1155 return 1;
1156}
1157
1159{
1161
1162 ctx.bytes = 0;
1163 ctx.pair_extra = pair_extra;
1165 return ctx.bytes;
1166}
1167
1168
1169/*******************************************************************************
1170 * h2_util for bucket brigades
1171 ******************************************************************************/
1172
1174{
1175 /* signed apr_off_t is at least as large as unsigned apr_size_t.
1176 * Problems may arise when they are both the same size. Then
1177 * the bucket length *may* be larger than a value we can hold
1178 * in apr_off_t. Before casting b->length to apr_off_t we must
1179 * check the limitations.
1180 * After we resized the bucket, it is safe to cast and substract.
1181 */
1182 if ((sizeof(apr_off_t) == sizeof(apr_int64_t)
1183 && b->length > APR_INT64_MAX)
1184 || (sizeof(apr_off_t) == sizeof(apr_int32_t)
1185 && b->length > APR_INT32_MAX)
1186 || *plen < (apr_off_t)b->length) {
1187 /* bucket is longer the *plen */
1189 }
1190 *plen -= (apr_off_t)b->length;
1191}
1192
1196{
1197 apr_bucket *b;
1200
1201 while (!APR_BRIGADE_EMPTY(src)) {
1203
1207 }
1208 else {
1209 if (remain <= 0) {
1210 return status;
1211 }
1212 if (b->length == ((apr_size_t)-1)) {
1213 const char *ign;
1216 if (status != APR_SUCCESS) {
1217 return status;
1218 }
1219 }
1223 }
1224 }
1225 return status;
1226}
1227
1231{
1232 apr_bucket *b, *next;
1235
1236 for (b = APR_BRIGADE_FIRST(src);
1238 b = next) {
1239 next = APR_BUCKET_NEXT(b);
1240
1242 /* fall through */
1243 }
1244 else {
1245 if (remain <= 0) {
1246 return status;
1247 }
1248 if (b->length == ((apr_size_t)-1)) {
1249 const char *ign;
1252 if (status != APR_SUCCESS) {
1253 return status;
1254 }
1255 }
1257 }
1259 if (status != APR_SUCCESS) {
1260 return status;
1261 }
1263 }
1264 return status;
1265}
1266
1268 apr_bucket *b, const char *sep)
1269{
1270 apr_size_t off = 0;
1271 if (sep && *sep) {
1272 off += apr_snprintf(buffer+off, bmax-off, "%s", sep);
1273 }
1274
1275 if (bmax <= off) {
1276 return off;
1277 }
1278 else if (APR_BUCKET_IS_METADATA(b)) {
1279 off += apr_snprintf(buffer+off, bmax-off, "%s", b->type->name);
1280 }
1281 else if (bmax > off) {
1282 off += apr_snprintf(buffer+off, bmax-off, "%s[%ld]",
1283 b->type->name,
1284 (b->length == ((apr_size_t)-1)?
1285 -1 : (long)b->length));
1286 }
1287 return off;
1288}
1289
1291 const char *tag, const char *sep,
1293{
1294 apr_size_t off = 0;
1295 const char *sp = "";
1296 apr_bucket *b;
1297
1298 if (bmax > 1) {
1299 if (bb) {
1300 memset(buffer, 0, bmax--);
1301 off += apr_snprintf(buffer+off, bmax-off, "%s(", tag);
1302 for (b = APR_BRIGADE_FIRST(bb);
1303 (bmax > off) && (b != APR_BRIGADE_SENTINEL(bb));
1304 b = APR_BUCKET_NEXT(b)) {
1305
1307 sp = " ";
1308 }
1309 if (bmax > off) {
1310 off += apr_snprintf(buffer+off, bmax-off, ")%s", sep);
1311 }
1312 }
1313 else {
1314 off += apr_snprintf(buffer+off, bmax-off, "%s(null)%s", tag, sep);
1315 }
1316 }
1317 return off;
1318}
1319
1321 apr_bucket_brigade *from,
1322 apr_off_t *plen,
1323 int *peos,
1325{
1326 apr_bucket *e;
1328 apr_status_t rv;
1329
1330 *peos = 0;
1331 start = remain = *plen;
1332
1333 while (!APR_BRIGADE_EMPTY(from)) {
1334 e = APR_BRIGADE_FIRST(from);
1335
1336 if (!should_append(e)) {
1337 goto leave;
1338 }
1339 else if (APR_BUCKET_IS_METADATA(e)) {
1340 if (APR_BUCKET_IS_EOS(e)) {
1341 *peos = 1;
1343 continue;
1344 }
1345 }
1346 else {
1347 if (remain <= 0) {
1348 goto leave;
1349 }
1350 if (e->length == ((apr_size_t)-1)) {
1351 const char *ign;
1354 if (rv != APR_SUCCESS) {
1355 return rv;
1356 }
1357 }
1359 }
1362 }
1363leave:
1364 *plen = start - remain;
1365 return APR_SUCCESS;
1366}
1367
1369{
1370 apr_bucket *b;
1371 apr_off_t total = 0;
1372
1373 for (b = APR_BRIGADE_FIRST(bb);
1374 b != APR_BRIGADE_SENTINEL(bb);
1375 b = APR_BUCKET_NEXT(b))
1376 {
1377 total += sizeof(*b);
1378 if (b->length > 0) {
1380 || APR_BUCKET_IS_POOL(b)) {
1381 total += b->length;
1382 }
1383 }
1384 }
1385 return total;
1386}
1387
1388
1389/*******************************************************************************
1390 * h2_ngheader
1391 ******************************************************************************/
1392
1393static int count_header(void *ctx, const char *key, const char *value)
1394{
1396 (*((size_t*)ctx))++;
1397 }
1398 return 1;
1399}
1400
1401static const char *inv_field_name_chr(const char *token)
1402{
1403 const char *p = ap_scan_http_token(token);
1404 if (p == token && *p == ':') {
1405 p = ap_scan_http_token(++p);
1406 }
1407 return (p && *p)? p : NULL;
1408}
1409
1410static const char *inv_field_value_chr(const char *token)
1411{
1412 const char *p = ap_scan_http_field_content(token);
1413 return (p && *p)? p : NULL;
1414}
1415
1417{
1418 while(nv->valuelen && (nv->value[0] == ' ' || nv->value[0] == '\t')) {
1419 nv->value++; nv->valuelen--;
1420 }
1421 while(nv->valuelen && (nv->value[nv->valuelen-1] == ' '
1422 || nv->value[nv->valuelen-1] == '\t')) {
1423 nv->valuelen--;
1424 }
1425}
1426
1433
1434static int add_header(ngh_ctx *ctx, const char *key, const char *value)
1435{
1436 nghttp2_nv *nv = &(ctx->ngh)->nv[(ctx->ngh)->nvlen++];
1437 const char *p;
1438
1439 if (!ctx->unsafe) {
1440 if ((p = inv_field_name_chr(key))) {
1442 "h2_request: head field '%s: %s' has invalid char %s",
1443 key, value, p);
1444 ctx->status = APR_EINVAL;
1445 return 0;
1446 }
1447 if ((p = inv_field_value_chr(value))) {
1449 "h2_request: head field '%s: %s' has invalid char %s",
1450 key, value, p);
1451 ctx->status = APR_EINVAL;
1452 return 0;
1453 }
1454 }
1455 nv->name = (uint8_t*)key;
1456 nv->namelen = strlen(key);
1457 nv->value = (uint8_t*)value;
1458 nv->valuelen = strlen(value);
1460
1461 return 1;
1462}
1463
1464static int add_table_header(void *ctx, const char *key, const char *value)
1465{
1468 }
1469 return 1;
1470}
1471
1473 int unsafe, size_t key_count,
1474 const char *keys[], const char *values[],
1475 apr_table_t *headers)
1476{
1477 ngh_ctx ctx;
1478 size_t n, i;
1479
1480 ctx.p = p;
1481 ctx.unsafe = unsafe;
1482
1483 n = key_count;
1484 apr_table_do(count_header, &n, headers, NULL);
1485
1486 *ph = ctx.ngh = apr_pcalloc(p, sizeof(h2_ngheader));
1487 if (!ctx.ngh) {
1488 return APR_ENOMEM;
1489 }
1490
1491 ctx.ngh->nv = apr_pcalloc(p, n * sizeof(nghttp2_nv));
1492 if (!ctx.ngh->nv) {
1493 return APR_ENOMEM;
1494 }
1495
1496 ctx.status = APR_SUCCESS;
1497 for (i = 0; i < key_count; ++i) {
1498 if (!add_header(&ctx, keys[i], values[i])) {
1499 return ctx.status;
1500 }
1501 }
1502
1504
1505 return ctx.status;
1506}
1507
1508#if AP_HAS_RESPONSE_BUCKETS
1509
1510static int is_unsafe(ap_bucket_response *h)
1511{
1512 const char *v = h->notes? apr_table_get(h->notes, H2_HDR_CONFORMANCE) : NULL;
1513 return (v && !strcmp(v, H2_HDR_CONFORMANCE_UNSAFE));
1514}
1515
1517 ap_bucket_headers *headers)
1518{
1519 return ngheader_create(ph, p, 0,
1520 0, NULL, NULL, headers->headers);
1521}
1522
1524 ap_bucket_response *response)
1525{
1526 const char *keys[] = {
1527 ":status"
1528 };
1529 const char *values[] = {
1530 apr_psprintf(p, "%d", response->status)
1531 };
1532 return ngheader_create(ph, p, is_unsafe(response),
1533 H2_ALEN(keys), keys, values, response->headers);
1534}
1535
1536#else /* AP_HAS_RESPONSE_BUCKETS */
1537
1539{
1540 const char *v = h->notes? apr_table_get(h->notes, H2_HDR_CONFORMANCE) : NULL;
1541 return (v && !strcmp(v, H2_HDR_CONFORMANCE_UNSAFE));
1542}
1543
1545 h2_headers *headers)
1546{
1547 return ngheader_create(ph, p, is_unsafe(headers),
1548 0, NULL, NULL, headers->headers);
1549}
1550
1552 h2_headers *headers)
1553{
1554 const char *keys[] = {
1555 ":status"
1556 };
1557 const char *values[] = {
1558 apr_psprintf(p, "%d", headers->status)
1559 };
1560 return ngheader_create(ph, p, is_unsafe(headers),
1561 H2_ALEN(keys), keys, values, headers->headers);
1562}
1563
1564#endif /* else AP_HAS_RESPONSE_BUCKETS */
1565
1567 const struct h2_request *req)
1568{
1569
1570 const char *keys[] = {
1571 ":scheme",
1572 ":authority",
1573 ":path",
1574 ":method",
1575 };
1576 const char *values[] = {
1577 req->scheme,
1578 req->authority,
1579 req->path,
1580 req->method,
1581 };
1582
1583 ap_assert(req->scheme);
1584 ap_assert(req->authority);
1585 ap_assert(req->path);
1586 ap_assert(req->method);
1587
1588 return ngheader_create(ph, p, 0, H2_ALEN(keys), keys, values, req->headers);
1589}
1590
1591/*******************************************************************************
1592 * header HTTP/1 <-> HTTP/2 conversions
1593 ******************************************************************************/
1594
1595
1596typedef struct {
1597 const char *name;
1598 size_t len;
1599} literal;
1600
1601#define H2_DEF_LITERAL(n) { (n), (sizeof(n)-1) }
1602#define H2_LIT_ARGS(a) (a),H2_ALEN(a)
1603
1605 H2_DEF_LITERAL("upgrade"),
1606 H2_DEF_LITERAL("connection"),
1607 H2_DEF_LITERAL("keep-alive"),
1608 H2_DEF_LITERAL("http2-settings"),
1609 H2_DEF_LITERAL("proxy-connection"),
1610 H2_DEF_LITERAL("transfer-encoding"),
1611};
1612static literal IgnoredRequestTrailers[] = { /* Ignore, see rfc7230, ch. 4.1.2 */
1613 H2_DEF_LITERAL("te"),
1614 H2_DEF_LITERAL("host"),
1615 H2_DEF_LITERAL("range"),
1616 H2_DEF_LITERAL("cookie"),
1617 H2_DEF_LITERAL("expect"),
1618 H2_DEF_LITERAL("pragma"),
1619 H2_DEF_LITERAL("max-forwards"),
1620 H2_DEF_LITERAL("cache-control"),
1621 H2_DEF_LITERAL("authorization"),
1622 H2_DEF_LITERAL("content-length"),
1623 H2_DEF_LITERAL("proxy-authorization"),
1624};
1626 H2_DEF_LITERAL("upgrade"),
1627 H2_DEF_LITERAL("connection"),
1628 H2_DEF_LITERAL("keep-alive"),
1629 H2_DEF_LITERAL("transfer-encoding"),
1630};
1632 H2_DEF_LITERAL("age"),
1633 H2_DEF_LITERAL("date"),
1634 H2_DEF_LITERAL("vary"),
1635 H2_DEF_LITERAL("cookie"),
1636 H2_DEF_LITERAL("expires"),
1637 H2_DEF_LITERAL("warning"),
1638 H2_DEF_LITERAL("location"),
1639 H2_DEF_LITERAL("retry-after"),
1640 H2_DEF_LITERAL("cache-control"),
1641 H2_DEF_LITERAL("www-authenticate"),
1642 H2_DEF_LITERAL("proxy-authenticate"),
1643};
1644
1645static int contains_name(const literal *lits, size_t llen, nghttp2_nv *nv)
1646{
1647 const literal *lit;
1648 size_t i;
1649
1650 for (i = 0; i < llen; ++i) {
1651 lit = &lits[i];
1652 if (lit->len == nv->namelen
1653 && !ap_cstr_casecmp(lit->name, (const char *)nv->name)) {
1654 return 1;
1655 }
1656 }
1657 return 0;
1658}
1659
1661{
1662 nghttp2_nv nv;
1663
1664 nv.name = (uint8_t*)name;
1665 nv.namelen = strlen(name);
1667}
1668
1669
1674
1675int h2_ignore_req_trailer(const char *name, size_t len)
1676{
1677 nghttp2_nv nv;
1678
1679 nv.name = (uint8_t*)name;
1680 nv.namelen = strlen(name);
1681 return (h2_req_ignore_header(&nv)
1683}
1684
1685int h2_ignore_resp_trailer(const char *name, size_t len)
1686{
1687 nghttp2_nv nv;
1688
1689 nv.name = (uint8_t*)name;
1690 nv.namelen = strlen(name);
1693}
1694
1696 nghttp2_nv *nv, size_t max_field_len,
1697 int *pwas_added)
1698{
1699 char *hname, *hvalue;
1700 const char *existing;
1701
1702 *pwas_added = 0;
1704
1705 if (h2_req_ignore_header(nv)) {
1706 return APR_SUCCESS;
1707 }
1708 else if (nv->namelen == sizeof("cookie")-1
1709 && !ap_cstr_casecmp("cookie", (const char *)nv->name)) {
1710 existing = apr_table_get(headers, "cookie");
1711 if (existing) {
1712 /* Cookie header come separately in HTTP/2, but need
1713 * to be merged by "; " (instead of default ", ")
1714 */
1715 if (max_field_len
1716 && strlen(existing) + nv->valuelen + nv->namelen + 4
1717 > max_field_len) {
1718 /* "key: oldval, nval" is too long */
1719 return APR_EINVAL;
1720 }
1721 hvalue = apr_pstrndup(pool, (const char*)nv->value, nv->valuelen);
1722 apr_table_setn(headers, "Cookie",
1723 apr_psprintf(pool, "%s; %s", existing, hvalue));
1724 return APR_SUCCESS;
1725 }
1726 }
1727 else if (nv->namelen == sizeof("host")-1
1728 && !ap_cstr_casecmp("host", (const char *)nv->name)) {
1729 if (apr_table_get(headers, "Host")) {
1730 return APR_SUCCESS; /* ignore duplicate */
1731 }
1732 }
1733
1734 hname = apr_pstrndup(pool, (const char*)nv->name, nv->namelen);
1736 existing = apr_table_get(headers, hname);
1737 if (max_field_len) {
1738 if ((existing? strlen(existing)+2 : 0) + nv->valuelen + nv->namelen + 2
1739 > max_field_len) {
1740 /* "key: (oldval, )?nval" is too long */
1741 return APR_EINVAL;
1742 }
1743 }
1744 if (!existing) *pwas_added = 1;
1745 hvalue = apr_pstrndup(pool, (const char*)nv->value, nv->valuelen);
1746 apr_table_mergen(headers, hname, hvalue);
1747
1748 return APR_SUCCESS;
1749}
1750
1752 const char *name, size_t nlen,
1753 const char *value, size_t vlen,
1754 size_t max_field_len, int *pwas_added)
1755{
1756 nghttp2_nv nv;
1757
1758 nv.name = (uint8_t*)name;
1759 nv.namelen = nlen;
1760 nv.value = (uint8_t*)value;
1761 nv.valuelen = vlen;
1762 return req_add_header(headers, pool, &nv, max_field_len, pwas_added);
1763}
1764
1765/*******************************************************************************
1766 * frame logging
1767 ******************************************************************************/
1768
1769int h2_util_frame_print(const nghttp2_frame *frame, char *buffer, size_t maxlen)
1770{
1771 char scratch[128];
1772 size_t s_len = sizeof(scratch)/sizeof(scratch[0]);
1773
1774 switch (frame->hd.type) {
1775 case NGHTTP2_DATA: {
1776 return apr_snprintf(buffer, maxlen,
1777 "DATA[length=%d, flags=%d, stream=%d, padlen=%d]",
1778 (int)frame->hd.length, frame->hd.flags,
1779 frame->hd.stream_id, (int)frame->data.padlen);
1780 }
1781 case NGHTTP2_HEADERS: {
1782 return apr_snprintf(buffer, maxlen,
1783 "HEADERS[length=%d, hend=%d, stream=%d, eos=%d]",
1784 (int)frame->hd.length,
1785 !!(frame->hd.flags & NGHTTP2_FLAG_END_HEADERS),
1786 frame->hd.stream_id,
1787 !!(frame->hd.flags & NGHTTP2_FLAG_END_STREAM));
1788 }
1789 case NGHTTP2_PRIORITY: {
1790 return apr_snprintf(buffer, maxlen,
1791 "PRIORITY[length=%d, flags=%d, stream=%d]",
1792 (int)frame->hd.length,
1793 frame->hd.flags, frame->hd.stream_id);
1794 }
1795 case NGHTTP2_RST_STREAM: {
1796 return apr_snprintf(buffer, maxlen,
1797 "RST_STREAM[length=%d, flags=%d, stream=%d]",
1798 (int)frame->hd.length,
1799 frame->hd.flags, frame->hd.stream_id);
1800 }
1801 case NGHTTP2_SETTINGS: {
1802 if (frame->hd.flags & NGHTTP2_FLAG_ACK) {
1803 return apr_snprintf(buffer, maxlen,
1804 "SETTINGS[ack=1, stream=%d]",
1805 frame->hd.stream_id);
1806 }
1807 return apr_snprintf(buffer, maxlen,
1808 "SETTINGS[length=%d, stream=%d]",
1809 (int)frame->hd.length, frame->hd.stream_id);
1810 }
1811 case NGHTTP2_PUSH_PROMISE: {
1812 return apr_snprintf(buffer, maxlen,
1813 "PUSH_PROMISE[length=%d, hend=%d, stream=%d]",
1814 (int)frame->hd.length,
1815 !!(frame->hd.flags & NGHTTP2_FLAG_END_HEADERS),
1816 frame->hd.stream_id);
1817 }
1818 case NGHTTP2_PING: {
1819 return apr_snprintf(buffer, maxlen,
1820 "PING[length=%d, ack=%d, stream=%d]",
1821 (int)frame->hd.length,
1822 frame->hd.flags&NGHTTP2_FLAG_ACK,
1823 frame->hd.stream_id);
1824 }
1825 case NGHTTP2_GOAWAY: {
1826 size_t len = (frame->goaway.opaque_data_len < s_len)?
1827 frame->goaway.opaque_data_len : s_len-1;
1828 if (len)
1829 memcpy(scratch, frame->goaway.opaque_data, len);
1830 scratch[len] = '\0';
1831 return apr_snprintf(buffer, maxlen, "GOAWAY[error=%d, reason='%s', "
1832 "last_stream=%d]", frame->goaway.error_code,
1833 scratch, frame->goaway.last_stream_id);
1834 }
1835 case NGHTTP2_WINDOW_UPDATE: {
1836 return apr_snprintf(buffer, maxlen,
1837 "WINDOW_UPDATE[stream=%d, incr=%d]",
1838 frame->hd.stream_id,
1839 frame->window_update.window_size_increment);
1840 }
1841 default:
1842 return apr_snprintf(buffer, maxlen,
1843 "type=%d[length=%d, flags=%d, stream=%d]",
1844 frame->hd.type, (int)frame->hd.length,
1845 frame->hd.flags, frame->hd.stream_id);
1846 }
1847}
1848
1849/*******************************************************************************
1850 * push policy
1851 ******************************************************************************/
1853{
1855 if (push_enabled) {
1856 const char *val = apr_table_get(headers, "accept-push-policy");
1857 if (val) {
1858 if (ap_find_token(p, val, "fast-load")) {
1860 }
1861 else if (ap_find_token(p, val, "head")) {
1863 }
1864 else if (ap_find_token(p, val, "default")) {
1866 }
1867 else if (ap_find_token(p, val, "none")) {
1869 }
1870 else {
1871 /* nothing known found in this header, go by default */
1873 }
1874 }
1875 else {
1877 }
1878 }
1879 return policy;
1880}
1881
1883{
1884 char rb[512];
1885 apr_size_t nr = sizeof(rb);
1888
1889 /* Make the pipe non-blocking if we can */
1891 if (trv == APR_SUCCESS)
1893
1894 while (apr_file_read(pipe, rb, &nr) == APR_SUCCESS) {
1895 /* Although we write just one byte to the other end of the pipe
1896 * during wakeup, multiple threads could call the wakeup.
1897 * So simply drain out from the input side of the pipe all
1898 * the data.
1899 */
1900 if (nr != sizeof(rb))
1901 break;
1902 }
1903 if (trv == APR_SUCCESS)
1905}
1906
1908{
1909 char rb[512];
1910 apr_size_t nr = sizeof(rb);
1911
1912 return apr_file_read(pipe, rb, &nr);
1913}
1914
1915#if AP_HAS_RESPONSE_BUCKETS
1916
1917static int add_header_lengths(void *ctx, const char *name, const char *value)
1918{
1919 apr_size_t *plen = ctx;
1920 *plen += strlen(name) + strlen(value);
1921 return 1;
1922}
1923
1925{
1926 apr_size_t len = 0;
1927 apr_table_do(add_header_lengths, &len, hdrs->headers, NULL);
1928 return len;
1929}
1930
1932{
1933 apr_size_t len = 3 + 1 + 8 + (resp->reason? strlen(resp->reason) : 10);
1935 return len;
1936}
1937
1938#endif /* AP_HAS_RESPONSE_BUCKETS */
int n
Definition ap_regex.h:278
const char apr_size_t len
Definition ap_regex.h:187
apr_size_t const unsigned char unsigned int unsigned int d
Definition apr_siphash.h:72
APR Strings library.
APR Condition Variable Routines.
APR Thread Mutex Routines.
#define APLOG_MARK
Definition http_log.h:283
#define ap_log_perror
Definition http_log.h:412
#define APLOG_TRACE1
Definition http_log.h:72
#define APR_EAGAIN
Definition apr_errno.h:730
#define APR_EOF
Definition apr_errno.h:461
#define APR_ENOMEM
Definition apr_errno.h:683
#define APR_EINVAL
Definition apr_errno.h:711
#define APR_EEXIST
Definition apr_errno.h:648
#define APR_BUCKET_REMOVE(e)
#define APR_BUCKET_IS_HEAP(e)
#define APR_BUCKET_IS_METADATA(e)
#define APR_BRIGADE_INSERT_TAIL(b, e)
#define apr_bucket_split(e, point)
apr_file_t apr_off_t start
#define APR_BUCKET_NEXT(e)
apr_bucket * e
#define APR_BRIGADE_EMPTY(b)
#define APR_BRIGADE_SENTINEL(b)
#define apr_bucket_delete(e)
#define APR_BUCKET_IS_EOS(e)
apr_brigade_flush void * ctx
#define apr_bucket_copy(e, c)
#define APR_BRIGADE_FIRST(b)
#define APR_BUCKET_IS_POOL(e)
#define apr_bucket_read(e, str, len, block)
int apr_off_t * length
@ APR_BLOCK_READ
Definition apr_buckets.h:58
const char * src
Definition apr_encode.h:167
const char apr_ssize_t slen
Definition apr_encode.h:168
const char apr_int32_t apr_uint32_t * nv
const char apr_hash_t ** values
apr_redis_t * rc
Definition apr_redis.h:173
const char * ap_scan_http_token(const char *ptr)
Definition util.c:1664
int ap_cstr_casecmp(const char *s1, const char *s2)
Definition util.c:3542
#define AP_DEBUG_ASSERT(exp)
Definition httpd.h:2283
int ap_find_token(apr_pool_t *p, const char *line, const char *tok)
Definition util.c:1726
const char * ap_scan_http_field_content(const char *ptr)
Definition util.c:1654
#define ap_assert(exp)
Definition httpd.h:2271
apr_size_t size
apr_uint32_t apr_uint32_t cmp
Definition apr_atomic.h:106
apr_uint32_t val
Definition apr_atomic.h:66
const char int apr_pool_t * pool
Definition apr_cstr.h:84
const char * value
Definition apr_env.h:51
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
const char * key
apr_seek_where_t apr_off_t * offset
void * data
char * buffer
#define memmove(a, b, c)
const apr_hash_t * h
Definition apr_hash.h:97
apr_ssize_t * klen
Definition apr_hash.h:71
apr_interval_time_t t
const char apr_uint32_t * id
apr_pool_t * b
Definition apr_pools.h:529
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
int to
const char * sep
const char char ** last
const char * s
Definition apr_strings.h:95
int nelts
Definition apr_tables.h:122
int int status
apr_int64_t apr_interval_time_t
Definition apr_time.h:55
apr_size_t apr_size_t max
Definition apr_time.h:220
h2_push_policy
Definition h2.h:114
@ H2_PUSH_FAST_LOAD
Definition h2.h:118
@ H2_PUSH_NONE
Definition h2.h:115
@ H2_PUSH_HEAD
Definition h2.h:117
@ H2_PUSH_DEFAULT
Definition h2.h:116
#define H2_ALEN(a)
Definition h2.h:98
#define H2_HDR_CONFORMANCE_UNSAFE
Definition h2.h:199
#define H2_HDR_CONFORMANCE
Definition h2.h:198
static int add_header_lengths(void *ctx, const char *name, const char *value)
Definition h2_headers.c:132
static apr_status_t fifo_pull(h2_fifo *fifo, void **pelem, int block)
Definition h2_util.c:725
void h2_iq_sort(h2_iqueue *q, h2_iq_cmp *cmp, void *ctx)
Definition h2_util.c:405
static const char * inv_field_value_chr(const char *token)
Definition h2_util.c:1410
void h2_ihash_clear(h2_ihash_t *ih)
Definition h2_util.c:285
size_t h2_util_hex_dump(char *buffer, size_t maxlen, const char *data, size_t datalen)
Definition h2_util.c:64
static literal IgnoredResponseTrailers[]
Definition h2_util.c:1631
void h2_ihash_add(h2_ihash_t *ih, void *val)
Definition h2_util.c:268
static void fit_bucket_into(apr_bucket *b, apr_off_t *plen)
Definition h2_util.c:1173
static apr_status_t ififo_push(h2_ififo *fifo, int id, int block)
Definition h2_util.c:1006
static apr_status_t ififo_peek(h2_ififo *fifo, h2_ififo_peek_fn *fn, void *ctx, int block)
Definition h2_util.c:1067
apr_status_t h2_append_brigade(apr_bucket_brigade *to, apr_bucket_brigade *from, apr_off_t *plen, int *peos, h2_bucket_gate *should_append)
Definition h2_util.c:1320
apr_status_t h2_util_wait_on_pipe(apr_file_t *pipe)
Definition h2_util.c:1907
apr_status_t h2_fifo_peek(h2_fifo *fifo, h2_fifo_peek_fn *fn, void *ctx)
Definition h2_util.c:770
int h2_iq_add(h2_iqueue *q, int sid, h2_iq_cmp *cmp, void *ctx)
Definition h2_util.c:354
apr_status_t h2_ififo_try_peek(h2_ififo *fifo, h2_ififo_peek_fn *fn, void *ctx)
Definition h2_util.c:1092
h2_iqueue * h2_iq_create(apr_pool_t *pool, int capacity)
Definition h2_util.c:334
apr_status_t h2_brigade_copy_length(apr_bucket_brigade *dest, apr_bucket_brigade *src, apr_off_t length)
Definition h2_util.c:1228
apr_status_t h2_res_create_ngheader(h2_ngheader **ph, apr_pool_t *p, h2_headers *headers)
Definition h2_util.c:1551
static apr_status_t ififo_pull(h2_ififo *fifo, int *pi, int block)
Definition h2_util.c:1046
static literal IgnoredRequestTrailers[]
Definition h2_util.c:1612
int h2_ignore_req_trailer(const char *name, size_t len)
Definition h2_util.c:1675
static int inth_index(h2_ififo *fifo, int n)
Definition h2_util.c:864
apr_status_t h2_ififo_term(h2_ififo *fifo)
Definition h2_util.c:942
void h2_util_drain_pipe(apr_file_t *pipe)
Definition h2_util.c:1882
static apr_status_t fifo_push_int(h2_fifo *fifo, void *elem, int block)
Definition h2_util.c:648
static int collect_iter(void *x, void *val)
Definition h2_util.c:297
#define N6
Definition h2_util.c:100
#define H2_DEF_LITERAL(n)
Definition h2_util.c:1601
static const unsigned int BASE64URL_UINT6[]
Definition h2_util.c:102
#define BASE64URL_CHAR(x)
Definition h2_util.c:131
int h2_util_ignore_resp_header(const char *name)
Definition h2_util.c:1660
void h2_ihash_remove_val(h2_ihash_t *ih, void *val)
Definition h2_util.c:278
size_t h2_iq_mshift(h2_iqueue *q, int *pint, size_t max)
Definition h2_util.c:448
apr_status_t h2_fifo_try_pull(h2_fifo *fifo, void **pelem)
Definition h2_util.c:741
void h2_ihash_remove(h2_ihash_t *ih, int id)
Definition h2_util.c:273
static int add_header(ngh_ctx *ctx, const char *key, const char *value)
Definition h2_util.c:1434
static int iq_bubble_down(h2_iqueue *q, int i, int bottom, h2_iq_cmp *cmp, void *ctx)
Definition h2_util.c:499
int h2_iq_contains(h2_iqueue *q, int sid)
Definition h2_util.c:511
static literal IgnoredRequestHeaders[]
Definition h2_util.c:1604
apr_status_t h2_ififo_try_push(h2_ififo *fifo, int id)
Definition h2_util.c:1022
h2_ihash_t * h2_ihash_create(apr_pool_t *pool, size_t offset_of_int)
Definition h2_util.c:225
apr_status_t h2_fifo_create(h2_fifo **pfifo, apr_pool_t *pool, int capacity)
Definition h2_util.c:602
int h2_iq_empty(h2_iqueue *q)
Definition h2_util.c:343
static apr_status_t fifo_destroy(void *data)
Definition h2_util.c:539
static apr_status_t fifo_peek(h2_fifo *fifo, h2_fifo_peek_fn *fn, void *ctx, int block)
Definition h2_util.c:746
apr_status_t h2_ififo_peek(h2_ififo *fifo, h2_ififo_peek_fn *fn, void *ctx)
Definition h2_util.c:1087
const char * h2_util_base64url_encode(const char *data, apr_size_t dlen, apr_pool_t *pool)
Definition h2_util.c:182
static apr_status_t ififo_remove(h2_ififo *fifo, int id)
Definition h2_util.c:1097
int h2_iq_append(h2_iqueue *q, int sid)
Definition h2_util.c:375
static int count_bytes(void *x, const char *key, const char *value)
Definition h2_util.c:1145
apr_size_t h2_util_bucket_print(char *buffer, apr_size_t bmax, apr_bucket *b, const char *sep)
Definition h2_util.c:1267
apr_status_t h2_fifo_set_create(h2_fifo **pfifo, apr_pool_t *pool, int capacity)
Definition h2_util.c:607
apr_status_t h2_brigade_concat_length(apr_bucket_brigade *dest, apr_bucket_brigade *src, apr_off_t length)
Definition h2_util.c:1193
apr_status_t h2_res_create_ngtrailer(h2_ngheader **ph, apr_pool_t *p, h2_headers *headers)
Definition h2_util.c:1544
static apr_status_t fifo_push(h2_fifo *fifo, void *elem, int block)
Definition h2_util.c:683
static int count_header(void *ctx, const char *key, const char *value)
Definition h2_util.c:1393
void h2_util_camel_case_header(char *s, size_t len)
Definition h2_util.c:80
static apr_status_t check_not_empty(h2_fifo *fifo, int block)
Definition h2_util.c:634
void * h2_ihash_get(h2_ihash_t *ih, int id)
Definition h2_util.c:243
static void iq_grow(h2_iqueue *q, int nlen)
Definition h2_util.c:460
apr_status_t h2_fifo_try_peek(h2_fifo *fifo, h2_fifo_peek_fn *fn, void *ctx)
Definition h2_util.c:775
static int index_of(h2_fifo *fifo, void *elem)
Definition h2_util.c:550
apr_status_t h2_ififo_remove(h2_ififo *fifo, int id)
Definition h2_util.c:1125
static int h2_req_ignore_header(nghttp2_nv *nv)
Definition h2_util.c:1670
static const char * inv_field_name_chr(const char *token)
Definition h2_util.c:1401
static apr_status_t req_add_header(apr_table_t *headers, apr_pool_t *pool, nghttp2_nv *nv, size_t max_field_len, int *pwas_added)
Definition h2_util.c:1695
static int contains_name(const literal *lits, size_t llen, nghttp2_nv *nv)
Definition h2_util.c:1645
static apr_status_t ipull_head(h2_ififo *fifo, int *pi, int block)
Definition h2_util.c:1027
static int ihash_iter(void *ctx, const void *key, apr_ssize_t klen, const void *val)
Definition h2_util.c:253
static int is_unsafe(h2_headers *h)
Definition h2_util.c:1538
apr_status_t h2_ififo_create(h2_ififo **pfifo, apr_pool_t *pool, int capacity)
Definition h2_util.c:932
int h2_fifo_count(h2_fifo *fifo)
Definition h2_util.c:624
apr_status_t h2_fifo_term(h2_fifo *fifo)
Definition h2_util.c:612
int h2_util_frame_print(const nghttp2_frame *frame, char *buffer, size_t maxlen)
Definition h2_util.c:1769
int h2_ignore_resp_trailer(const char *name, size_t len)
Definition h2_util.c:1685
apr_status_t h2_req_add_header(apr_table_t *headers, apr_pool_t *pool, const char *name, size_t nlen, const char *value, size_t vlen, size_t max_field_len, int *pwas_added)
Definition h2_util.c:1751
static void strip_field_value_ws(nghttp2_nv *nv)
Definition h2_util.c:1416
int h2_ihash_iter(h2_ihash_t *ih, h2_ihash_iter_t *fn, void *ctx)
Definition h2_util.c:260
static unsigned int ihash(const char *key, apr_ssize_t *klen)
Definition h2_util.c:220
apr_status_t h2_fifo_pull(h2_fifo *fifo, void **pelem)
Definition h2_util.c:736
int h2_iq_remove(h2_iqueue *q, int sid)
Definition h2_util.c:380
size_t h2_ihash_shift(h2_ihash_t *ih, void **buffer, size_t max)
Definition h2_util.c:307
static apr_status_t ififo_push_int(h2_ififo *fifo, int id, int block)
Definition h2_util.c:973
static literal IgnoredResponseHeaders[]
Definition h2_util.c:1625
unsigned int h2_ihash_count(h2_ihash_t *ih)
Definition h2_util.c:233
apr_status_t h2_req_create_ngheader(h2_ngheader **ph, apr_pool_t *p, const struct h2_request *req)
Definition h2_util.c:1566
int h2_ififo_count(h2_ififo *fifo)
Definition h2_util.c:954
int h2_push_policy_determine(apr_table_t *headers, apr_pool_t *p, int push_enabled)
Definition h2_util.c:1852
static void iq_swap(h2_iqueue *q, int i, int j)
Definition h2_util.c:480
apr_status_t h2_fifo_push(h2_fifo *fifo, void *elem)
Definition h2_util.c:694
apr_status_t h2_fifo_remove(h2_fifo *fifo, void *elem)
Definition h2_util.c:780
apr_size_t h2_util_base64url_decode(const char **decoded, const char *encoded, apr_pool_t *pool)
Definition h2_util.c:133
static const unsigned char BASE64URL_CHARS[]
Definition h2_util.c:121
unsigned char h2_log2(int n)
Definition h2_util.c:35
static apr_status_t pull_head(h2_fifo *fifo, void **pelem, int block)
Definition h2_util.c:704
apr_off_t h2_brigade_mem_size(apr_bucket_brigade *bb)
Definition h2_util.c:1368
apr_size_t h2_util_table_bytes(apr_table_t *t, apr_size_t pair_extra)
Definition h2_util.c:1158
static int iindex_of(h2_ififo *fifo, int id)
Definition h2_util.c:880
static apr_status_t icheck_not_empty(h2_ififo *fifo, int block)
Definition h2_util.c:959
static int iq_bubble_up(h2_iqueue *q, int i, int top, h2_iq_cmp *cmp, void *ctx)
Definition h2_util.c:487
apr_status_t h2_ififo_set_create(h2_ififo **pfifo, apr_pool_t *pool, int capacity)
Definition h2_util.c:937
apr_status_t h2_ififo_push(h2_ififo *fifo, int id)
Definition h2_util.c:1017
static apr_status_t ififo_destroy(void *data)
Definition h2_util.c:869
void h2_iq_clear(h2_iqueue *q)
Definition h2_util.c:400
int h2_ihash_empty(h2_ihash_t *ih)
Definition h2_util.c:238
apr_status_t h2_ififo_try_pull(h2_ififo *fifo, int *pi)
Definition h2_util.c:1062
static apr_status_t icreate_int(h2_ififo **pfifo, apr_pool_t *pool, int capacity, int as_set)
Definition h2_util.c:892
static int add_table_header(void *ctx, const char *key, const char *value)
Definition h2_util.c:1464
static apr_status_t ngheader_create(h2_ngheader **ph, apr_pool_t *p, int unsafe, size_t key_count, const char *keys[], const char *values[], apr_table_t *headers)
Definition h2_util.c:1472
int h2_iq_shift(h2_iqueue *q)
Definition h2_util.c:433
int h2_iq_count(h2_iqueue *q)
Definition h2_util.c:348
apr_status_t h2_fifo_try_push(h2_fifo *fifo, void *elem)
Definition h2_util.c:699
apr_status_t h2_ififo_pull(h2_ififo *fifo, int *pi)
Definition h2_util.c:1057
static apr_status_t create_int(h2_fifo **pfifo, apr_pool_t *pool, int capacity, int as_set)
Definition h2_util.c:562
apr_size_t h2_util_bb_print(char *buffer, apr_size_t bmax, const char *tag, const char *sep, apr_bucket_brigade *bb)
Definition h2_util.c:1290
#define H2_LIT_ARGS(a)
Definition h2_util.c:1602
@ H2_FIFO_OP_REPUSH
Definition h2_util.h:230
@ H2_FIFO_OP_PULL
Definition h2_util.h:229
int h2_iq_cmp(int i1, int i2, void *ctx)
Definition h2_util.h:95
int h2_bucket_gate(apr_bucket *b)
Definition h2_util.h:469
int h2_ihash_iter_t(void *ctx, void *val)
Definition h2_util.h:43
h2_fifo_op_t h2_ififo_peek_fn(int head, void *ctx)
Definition h2_util.h:298
h2_fifo_op_t h2_fifo_peek_fn(void *head, void *ctx)
Definition h2_util.h:233
CORE HTTP Daemon.
Apache Logging library.
HTTP protocol handling.
Apache Request library.
HTTP Daemon routines.
apr_pool_t * p
Definition md_event.c:32
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
char * name
apr_size_t length
h2_ihash_t * ih
Definition h2_util.c:291
h2_proxy_ihash_t * ih
int aborted
Definition h2_util.c:533
int set
Definition h2_util.c:529
apr_thread_cond_t * not_empty
Definition h2_util.c:535
int out
Definition h2_util.c:531
apr_thread_mutex_t * lock
Definition h2_util.c:534
int count
Definition h2_util.c:532
void ** elems
Definition h2_util.c:527
int in
Definition h2_util.c:530
int capacity
Definition h2_util.c:528
apr_thread_cond_t * not_full
Definition h2_util.c:536
apr_table_t * headers
Definition h2_headers.h:29
int head
Definition h2_util.c:856
int set
Definition h2_util.c:855
int capacity
Definition h2_util.c:854
apr_thread_cond_t * not_empty
Definition h2_util.c:860
int aborted
Definition h2_util.c:858
apr_thread_mutex_t * lock
Definition h2_util.c:859
int * elems
Definition h2_util.c:853
apr_thread_cond_t * not_full
Definition h2_util.c:861
int count
Definition h2_util.c:857
size_t ioff
Definition h2_util.c:217
apr_hash_t * hash
Definition h2_util.c:216
int nelts
Definition h2_util.h:79
int head
Definition h2_util.h:78
apr_pool_t * pool
Definition h2_util.h:81
int * elts
Definition h2_util.h:77
int nalloc
Definition h2_util.h:80
const char * method
Definition h2.h:170
const char * authority
Definition h2.h:172
const char * scheme
Definition h2.h:171
const char * path
Definition h2.h:173
apr_table_t * headers
Definition h2.h:175
h2_ihash_iter_t * iter
Definition h2_util.c:249
h2_proxy_ihash_iter_t * iter
const char * name
apr_status_t status
Definition h2_util.c:1431
apr_pool_t * p
Definition h2_util.c:1428
h2_ngheader * ngh
Definition h2_util.c:1430
int unsafe
Definition h2_util.c:1429
apr_size_t bytes
Definition h2_util.c:1141
apr_size_t pair_extra
Definition h2_util.c:1142
IN ULONG IN INT timeout
typedef int(WSAAPI *apr_winapi_fpt_WSAPoll)(IN OUT LPWSAPOLLFD fdArray