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