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