Apache HTTPD
h2_push.c
Go to the documentation of this file.
1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <assert.h>
18#include <stdio.h>
19
20#include <apr_lib.h>
21#include <apr_strings.h>
22#include <apr_hash.h>
23#include <apr_time.h>
24
25#ifdef H2_OPENSSL
26#include <openssl/evp.h>
27#endif
28
29#include <httpd.h>
30#include <http_core.h>
31#include <http_log.h>
32#include <http_protocol.h>
33
34#include "h2_private.h"
35#include "h2_protocol.h"
36#include "h2_util.h"
37#include "h2_push.h"
38#include "h2_request.h"
39#include "h2_session.h"
40#include "h2_stream.h"
41
42/*******************************************************************************
43 * link header handling
44 ******************************************************************************/
45
46static const char *policy_str(h2_push_policy policy)
47{
48 switch (policy) {
49 case H2_PUSH_NONE:
50 return "none";
52 return "fast-load";
53 case H2_PUSH_HEAD:
54 return "head";
55 default:
56 return "default";
57 }
58}
59
60typedef struct {
65 const char *s;
66 size_t slen;
67 size_t i;
68
69 const char *link;
71 char b[4096];
72} link_ctx;
73
74static int attr_char(char c)
75{
76 switch (c) {
77 case '!':
78 case '#':
79 case '$':
80 case '&':
81 case '+':
82 case '-':
83 case '.':
84 case '^':
85 case '_':
86 case '`':
87 case '|':
88 case '~':
89 return 1;
90 default:
91 return apr_isalnum(c);
92 }
93}
94
95static int ptoken_char(char c)
96{
97 switch (c) {
98 case '!':
99 case '#':
100 case '$':
101 case '&':
102 case '\'':
103 case '(':
104 case ')':
105 case '*':
106 case '+':
107 case '-':
108 case '.':
109 case '/':
110 case ':':
111 case '<':
112 case '=':
113 case '>':
114 case '?':
115 case '@':
116 case '[':
117 case ']':
118 case '^':
119 case '_':
120 case '`':
121 case '{':
122 case '|':
123 case '}':
124 case '~':
125 return 1;
126 default:
127 return apr_isalnum(c);
128 }
129}
130
131static int skip_ws(link_ctx *ctx)
132{
133 char c;
134 while (ctx->i < ctx->slen
135 && (((c = ctx->s[ctx->i]) == ' ') || (c == '\t'))) {
136 ++ctx->i;
137 }
138 return (ctx->i < ctx->slen);
139}
140
141static int find_chr(link_ctx *ctx, char c, size_t *pidx)
142{
143 size_t j;
144 for (j = ctx->i; j < ctx->slen; ++j) {
145 if (ctx->s[j] == c) {
146 *pidx = j;
147 return 1;
148 }
149 }
150 return 0;
151}
152
153static int read_chr(link_ctx *ctx, char c)
154{
155 if (ctx->i < ctx->slen && ctx->s[ctx->i] == c) {
156 ++ctx->i;
157 return 1;
158 }
159 return 0;
160}
161
162static char *mk_str(link_ctx *ctx, size_t end)
163{
164 if (ctx->i < end) {
165 return apr_pstrndup(ctx->pool, ctx->s + ctx->i, end - ctx->i);
166 }
167 return (char*)"";
168}
169
170static int read_qstring(link_ctx *ctx, const char **ps)
171{
172 if (skip_ws(ctx) && read_chr(ctx, '\"')) {
173 size_t end;
174 if (find_chr(ctx, '\"', &end)) {
175 *ps = mk_str(ctx, end);
176 ctx->i = end + 1;
177 return 1;
178 }
179 }
180 return 0;
181}
182
183static int read_ptoken(link_ctx *ctx, const char **ps)
184{
185 if (skip_ws(ctx)) {
186 size_t i;
187 for (i = ctx->i; i < ctx->slen && ptoken_char(ctx->s[i]); ++i) {
188 /* nop */
189 }
190 if (i > ctx->i) {
191 *ps = mk_str(ctx, i);
192 ctx->i = i;
193 return 1;
194 }
195 }
196 return 0;
197}
198
199
201{
202 if (skip_ws(ctx) && read_chr(ctx, '<')) {
203 size_t end;
204 if (find_chr(ctx, '>', &end)) {
205 ctx->link = mk_str(ctx, end);
206 ctx->i = end + 1;
207 return 1;
208 }
209 }
210 return 0;
211}
212
213static int read_pname(link_ctx *ctx, const char **pname)
214{
215 if (skip_ws(ctx)) {
216 size_t i;
217 for (i = ctx->i; i < ctx->slen && attr_char(ctx->s[i]); ++i) {
218 /* nop */
219 }
220 if (i > ctx->i) {
221 *pname = mk_str(ctx, i);
222 ctx->i = i;
223 return 1;
224 }
225 }
226 return 0;
227}
228
229static int read_pvalue(link_ctx *ctx, const char **pvalue)
230{
231 if (skip_ws(ctx) && read_chr(ctx, '=')) {
233 return 1;
234 }
235 }
236 return 0;
237}
238
240{
241 if (skip_ws(ctx) && read_chr(ctx, ';')) {
242 const char *name, *value = "";
243 if (read_pname(ctx, &name)) {
244 read_pvalue(ctx, &value); /* value is optional */
245 apr_table_setn(ctx->params, name, value);
246 return 1;
247 }
248 }
249 return 0;
250}
251
253{
254 if (skip_ws(ctx) && read_chr(ctx, ',')) {
255 return 1;
256 }
257 return 0;
258}
259
261{
262 if (!ctx->params) {
263 ctx->params = apr_table_make(ctx->pool, 5);
264 }
265 else {
266 apr_table_clear(ctx->params);
267 }
268}
269
270static int same_authority(const h2_request *req, const apr_uri_t *uri)
271{
272 if (uri->scheme != NULL && strcmp(uri->scheme, req->scheme)) {
273 return 0;
274 }
275 if (uri->hostinfo != NULL && strcmp(uri->hostinfo, req->authority)) {
276 return 0;
277 }
278 return 1;
279}
280
281static int set_push_header(void *ctx, const char *key, const char *value)
282{
283 size_t klen = strlen(key);
284 if (H2_HD_MATCH_LIT("User-Agent", key, klen)
285 || H2_HD_MATCH_LIT("Accept", key, klen)
286 || H2_HD_MATCH_LIT("Accept-Encoding", key, klen)
287 || H2_HD_MATCH_LIT("Accept-Language", key, klen)
288 || H2_HD_MATCH_LIT("Cache-Control", key, klen)) {
290 }
291 return 1;
292}
293
294static int has_param(link_ctx *ctx, const char *param)
295{
296 const char *p = apr_table_get(ctx->params, param);
297 return !!p;
298}
299
300static int has_relation(link_ctx *ctx, const char *rel)
301{
302 const char *s, *val = apr_table_get(ctx->params, "rel");
303 if (val) {
304 if (!strcmp(rel, val)) {
305 return 1;
306 }
307 s = ap_strstr_c(val, rel);
308 if (s && (s == val || s[-1] == ' ')) {
309 s += strlen(rel);
310 if (!*s || *s == ' ') {
311 return 1;
312 }
313 }
314 }
315 return 0;
316}
317
319{
320 /* so, we have read a Link header and need to decide
321 * if we transform it into a push.
322 */
323 if (has_relation(ctx, "preload") && !has_param(ctx, "nopush")) {
325 if (apr_uri_parse(ctx->pool, ctx->link, &uri) == APR_SUCCESS) {
326 if (uri.path && same_authority(ctx->req, &uri)) {
327 char *path;
328 const char *method;
329 apr_table_t *headers;
330 h2_request *req;
331 h2_push *push;
332
333 /* We only want to generate pushes for resources in the
334 * same authority than the original request.
335 * icing: i think that is wise, otherwise we really need to
336 * check that the vhost/server is available and uses the same
337 * TLS (if any) parameters.
338 */
340 push = apr_pcalloc(ctx->pool, sizeof(*push));
341 switch (ctx->push_policy) {
342 case H2_PUSH_HEAD:
343 method = "HEAD";
344 break;
345 default:
346 method = "GET";
347 break;
348 }
349 headers = apr_table_make(ctx->pool, 5);
350 apr_table_do(set_push_header, headers, ctx->req->headers, NULL);
351 req = h2_request_create(0, ctx->pool, method, ctx->req->scheme,
352 ctx->req->authority, path, headers);
353 /* atm, we do not push on pushes */
354 h2_request_end_headers(req, ctx->pool, 0);
355 push->req = req;
356 if (has_param(ctx, "critical")) {
357 h2_priority *prio = apr_pcalloc(ctx->pool, sizeof(*prio));
358 prio->dependency = H2_DEPENDANT_BEFORE;
359 push->priority = prio;
360 }
361 if (!ctx->pushes) {
362 ctx->pushes = apr_array_make(ctx->pool, 5, sizeof(h2_push*));
363 }
364 APR_ARRAY_PUSH(ctx->pushes, h2_push*) = push;
365 }
366 }
367 }
368 return 0;
369}
370
371static void inspect_link(link_ctx *ctx, const char *s, size_t slen)
372{
373 /* RFC 5988 <https://tools.ietf.org/html/rfc5988#section-6.2.1>
374 Link = "Link" ":" #link-value
375 link-value = "<" URI-Reference ">" *( ";" link-param )
376 link-param = ( ( "rel" "=" relation-types )
377 | ( "anchor" "=" <"> URI-Reference <"> )
378 | ( "rev" "=" relation-types )
379 | ( "hreflang" "=" Language-Tag )
380 | ( "media" "=" ( MediaDesc | ( <"> MediaDesc <"> ) ) )
381 | ( "title" "=" quoted-string )
382 | ( "title*" "=" ext-value )
383 | ( "type" "=" ( media-type | quoted-mt ) )
384 | ( link-extension ) )
385 link-extension = ( parmname [ "=" ( ptoken | quoted-string ) ] )
386 | ( ext-name-star "=" ext-value )
387 ext-name-star = parmname "*" ; reserved for RFC2231-profiled
388 ; extensions. Whitespace NOT
389 ; allowed in between.
390 ptoken = 1*ptokenchar
391 ptokenchar = "!" | "#" | "$" | "%" | "&" | "'" | "("
392 | ")" | "*" | "+" | "-" | "." | "/" | DIGIT
393 | ":" | "<" | "=" | ">" | "?" | "@" | ALPHA
394 | "[" | "]" | "^" | "_" | "`" | "{" | "|"
395 | "}" | "~"
396 media-type = type-name "/" subtype-name
397 quoted-mt = <"> media-type <">
398 relation-types = relation-type
399 | <"> relation-type *( 1*SP relation-type ) <">
400 relation-type = reg-rel-type | ext-rel-type
401 reg-rel-type = LOALPHA *( LOALPHA | DIGIT | "." | "-" )
402 ext-rel-type = URI
403
404 and from <https://tools.ietf.org/html/rfc5987>
405 parmname = 1*attr-char
406 attr-char = ALPHA / DIGIT
407 / "!" / "#" / "$" / "&" / "+" / "-" / "."
408 / "^" / "_" / "`" / "|" / "~"
409 */
410
411 ctx->s = s;
412 ctx->slen = slen;
413 ctx->i = 0;
414
415 while (read_link(ctx)) {
417 while (read_param(ctx)) {
418 /* nop */
419 }
420 add_push(ctx);
421 if (!read_sep(ctx)) {
422 break;
423 }
424 }
425}
426
427static int head_iter(void *ctx, const char *key, const char *value)
428{
429 if (!ap_cstr_casecmp("link", key)) {
430 inspect_link(ctx, value, strlen(value));
431 }
432 return 1;
433}
434
435#if AP_HAS_RESPONSE_BUCKETS
437 const struct h2_request *req,
438 apr_uint32_t push_policy,
439 const ap_bucket_response *res)
440#else
442 const struct h2_request *req,
443 apr_uint32_t push_policy,
444 const struct h2_headers *res)
445#endif
446{
447 if (req && push_policy != H2_PUSH_NONE) {
448 /* Collect push candidates from the request/response pair.
449 *
450 * One source for pushes are "rel=preload" link headers
451 * in the response.
452 *
453 * TODO: This may be extended in the future by hooks or callbacks
454 * where other modules can provide push information directly.
455 */
456 if (res->headers) {
458
459 memset(&ctx, 0, sizeof(ctx));
460 ctx.req = req;
461 ctx.push_policy = push_policy;
462 ctx.pool = p;
463
464 apr_table_do(head_iter, &ctx, res->headers, NULL);
465 if (ctx.pushes) {
466 apr_table_setn(res->headers, "push-policy",
467 policy_str(push_policy));
468 }
469 return ctx.pushes;
470 }
471 }
472 return NULL;
473}
474
475#define GCSLOG_LEVEL APLOG_TRACE1
476
480
481
482#ifdef H2_OPENSSL
483static void sha256_update(EVP_MD_CTX *ctx, const char *s)
484{
485 EVP_DigestUpdate(ctx, s, strlen(s));
486}
487
489{
490 EVP_MD_CTX *md;
492 unsigned char hash[EVP_MAX_MD_SIZE];
493 unsigned len, i;
494
495 md = EVP_MD_CTX_create();
496 ap_assert(md != NULL);
497
499 ap_assert(i == 1);
500 sha256_update(md, push->req->scheme);
501 sha256_update(md, "://");
502 sha256_update(md, push->req->authority);
503 sha256_update(md, push->req->path);
504 EVP_DigestFinal(md, hash, &len);
506
507 val = 0;
508 for (i = 0; i != len; ++i)
509 val = val * 256 + hash[i];
510 *phash = val >> (64 - diary->mask_bits);
511}
512#endif
513
514
515static unsigned int val_apr_hash(const char *str)
516{
517 apr_ssize_t len = (apr_ssize_t)strlen(str);
518 return apr_hashfunc_default(str, &len);
519}
520
522{
524 (void)diary;
525#if APR_UINT64_MAX > UINT_MAX
526 val = ((apr_uint64_t)(val_apr_hash(push->req->scheme)) << 32);
527 val ^= ((apr_uint64_t)(val_apr_hash(push->req->authority)) << 16);
528 val ^= val_apr_hash(push->req->path);
529#else
530 val = val_apr_hash(push->req->scheme);
531 val ^= val_apr_hash(push->req->authority);
532 val ^= val_apr_hash(push->req->path);
533#endif
534 *phash = val;
535}
536
538{
539 if (n <= 2) return 2;
540 --n;
541 n |= n >> 1;
542 n |= n >> 2;
543 n |= n >> 4;
544 n |= n >> 8;
545 n |= n >> 16;
546 return ++n;
547}
548
550 int N)
551{
552 h2_push_diary *diary = NULL;
553
554 if (N > 0) {
555 diary = apr_pcalloc(p, sizeof(*diary));
556
557 diary->NMax = ceil_power_of_2(N);
558 diary->N = diary->NMax;
559 /* the mask we use in value comparison depends on where we got
560 * the values from. If we calculate them ourselves, we can use
561 * the full 64 bits.
562 * If we set the diary via a compressed golomb set, we have less
563 * relevant bits and need to use a smaller mask. */
564 diary->mask_bits = 64;
565 /* grows by doubling, start with a power of 2 */
566 diary->entries = apr_array_make(p, 16, sizeof(h2_push_diary_entry));
567
568 switch (dtype) {
569#ifdef H2_OPENSSL
572 diary->dcalc = calc_sha256_hash;
573 break;
574#endif /* ifdef H2_OPENSSL */
575 default:
577 diary->dcalc = calc_apr_hash;
578 break;
579 }
580 }
581
582 return diary;
583}
584
589
591{
592 if (diary) {
594 int i;
595
596 /* search from the end, where the last accessed digests are */
597 for (i = diary->entries->nelts-1; i >= 0; --i) {
599 if (e->hash == hash) {
600 return i;
601 }
602 }
603 }
604 return -1;
605}
606
608{
612
613 /* Move an existing entry to the last place */
614 if (diary->entries->nelts <= 0)
615 return;
616
617 /* move entry[idx] to the end */
618 lastidx = diary->entries->nelts - 1;
619 if (idx < lastidx) {
620 e = entries[idx];
621 memmove(entries+idx, entries+idx+1, sizeof(h2_push_diary_entry) * (lastidx - idx));
622 entries[lastidx] = e;
623 }
624}
625
626static void remove_first(h2_push_diary *diary)
627{
629 int lastidx;
630
631 /* move remaining entries to index 0 */
632 lastidx = diary->entries->nelts - 1;
633 if (lastidx > 0) {
634 --diary->entries->nelts;
635 memmove(entries, entries+1, sizeof(h2_push_diary_entry) * diary->entries->nelts);
636 }
637}
638
640{
641 while (diary->entries->nelts >= diary->N) {
642 remove_first(diary);
643 }
644 /* append a new diary entry at the end */
646 /* Intentional no APLOGNO */
648 "push_diary_append: %"APR_UINT64_T_HEX_FMT, e->hash);
649}
650
652{
653 apr_array_header_t *npushes = pushes;
655 int i, idx;
656
657 if (session->push_diary && pushes) {
658 npushes = NULL;
659
660 for (i = 0; i < pushes->nelts; ++i) {
661 h2_push *push;
662
663 push = APR_ARRAY_IDX(pushes, i, h2_push*);
664 session->push_diary->dcalc(session->push_diary, &e.hash, push);
665 idx = h2_push_diary_find(session->push_diary, e.hash);
666 if (idx >= 0) {
667 /* Intentional no APLOGNO */
669 "push_diary_update: already there PUSH %s", push->req->path);
671 }
672 else {
673 /* Intentional no APLOGNO */
675 "push_diary_update: adding PUSH %s", push->req->path);
676 if (!npushes) {
677 npushes = apr_array_make(pushes->pool, 5, sizeof(h2_push_diary_entry*));
678 }
681 }
682 }
683 }
684 return npushes;
685}
686
687#if AP_HAS_RESPONSE_BUCKETS
689 const struct h2_request *req,
690 const ap_bucket_response *res)
691#else
693 const struct h2_request *req,
694 const struct h2_headers *res)
695#endif
696{
697 apr_array_header_t *pushes;
698
699 pushes = h2_push_collect(stream->pool, req, stream->push_policy, res);
700 return h2_push_diary_update(stream->session, pushes);
701}
702
717
718static int cmp_puint64(const void *p1, const void *p2)
719{
720 const apr_uint64_t *pu1 = p1, *pu2 = p2;
721 return (*pu1 > *pu2)? 1 : ((*pu1 == *pu2)? 0 : -1);
722}
723
724/* in golomb bit stream encoding, bit 0 is the 8th of the first char, or
725 * more generally:
726 * char(bit/8) & cbit_mask[(bit % 8)]
727 */
728static unsigned char cbit_mask[] = {
729 0x80u,
730 0x40u,
731 0x20u,
732 0x10u,
733 0x08u,
734 0x04u,
735 0x02u,
736 0x01u,
737};
738
740{
741 if (++encoder->bit >= 8) {
742 if (++encoder->offset >= encoder->datalen) {
744 unsigned char *ndata = apr_pcalloc(encoder->pool, nlen);
745 if (!ndata) {
746 return APR_ENOMEM;
747 }
748 memcpy(ndata, encoder->data, encoder->datalen);
749 encoder->data = ndata;
750 encoder->datalen = nlen;
751 }
752 encoder->bit = 0;
753 encoder->data[encoder->offset] = 0xffu;
754 }
755 if (!bit) {
756 encoder->data[encoder->offset] &= ~cbit_mask[encoder->bit];
757 }
758 return APR_SUCCESS;
759}
760
762{
765 int i;
766
767 delta = pval - encoder->last;
768 encoder->last = pval;
769 flex_bits = (delta >> encoder->fixed_bits);
770 /* Intentional no APLOGNO */
772 "h2_push_diary_enc: val=%"APR_UINT64_T_HEX_FMT", delta=%"
774 ", fixed_bits=%d, fixed_val=%"APR_UINT64_T_HEX_FMT,
775 pval, delta, flex_bits, encoder->fixed_bits, delta&encoder->fixed_mask);
776 for (; flex_bits != 0; --flex_bits) {
778 if (status != APR_SUCCESS) {
779 return status;
780 }
781 }
783 if (status != APR_SUCCESS) {
784 return status;
785 }
786
787 for (i = encoder->fixed_bits-1; i >= 0; --i) {
788 status = gset_encode_bit(encoder, (delta >> i) & 1);
789 if (status != APR_SUCCESS) {
790 return status;
791 }
792 }
793 return APR_SUCCESS;
794}
795
807 int maxP, const char *authority,
808 const char **pdata, apr_size_t *plen)
809{
810 int nelts, N;
811 unsigned char log2n, log2pmax;
815
816 nelts = diary->entries->nelts;
818 log2n = h2_log2(N);
819
820 /* Now log2p is the max number of relevant bits, so that
821 * log2p + log2n == mask_bits. We can use a lower log2p
822 * and have a shorter set encoding...
823 */
825
826 memset(&encoder, 0, sizeof(encoder));
827 encoder.diary = diary;
828 encoder.log2p = H2MIN(diary->mask_bits - log2n, log2pmax);
829 encoder.mask_bits = log2n + encoder.log2p;
830 encoder.delta_bits = diary->mask_bits - encoder.mask_bits;
831 encoder.fixed_bits = encoder.log2p;
832 encoder.fixed_mask = 1;
833 encoder.fixed_mask = (encoder.fixed_mask << encoder.fixed_bits) - 1;
834 encoder.pool = pool;
835 encoder.datalen = 512;
836 encoder.data = apr_pcalloc(encoder.pool, encoder.datalen);
837
838 encoder.data[0] = log2n;
839 encoder.data[1] = encoder.log2p;
840 encoder.offset = 1;
841 encoder.bit = 8;
842 encoder.last = 0;
843
844 /* Intentional no APLOGNO */
846 "h2_push_diary_digest_get: %d entries, N=%d, log2n=%d, "
847 "mask_bits=%d, enc.mask_bits=%d, delta_bits=%d, enc.log2p=%d, authority=%s",
848 (int)nelts, (int)N, (int)log2n, diary->mask_bits,
849 (int)encoder.mask_bits, (int)encoder.delta_bits,
850 (int)encoder.log2p, authority);
851
852 if (!authority || !diary->authority
853 || !strcmp("*", authority) || !strcmp(diary->authority, authority)) {
854 hash_count = diary->entries->nelts;
856 for (i = 0; i < hash_count; ++i) {
858 >> encoder.delta_bits);
859 }
860
862 for (i = 0; i < hash_count; ++i) {
863 if (!i || (hashes[i] != hashes[i-1])) {
865 }
866 }
867 /* Intentional no APLOGNO */
869 "h2_push_diary_digest_get: golomb compressed hashes, %d bytes",
870 (int)encoder.offset + 1);
871 }
872 *pdata = (const char *)encoder.data;
873 *plen = encoder.offset + 1;
874
875 return APR_SUCCESS;
876}
877
int n
Definition ap_regex.h:278
const char apr_size_t len
Definition ap_regex.h:187
APR Hash Tables.
APR general purpose library routines.
#define hash(h, r, b, n)
Definition apr_random.c:51
APR Strings library.
APR Time Library.
request_rec int int apr_table_t const char * path
const char server_rec server_rec ** ps
#define ap_log_cerror
Definition http_log.h:498
#define APLOG_MARK
Definition http_log.h:283
#define ap_log_perror
Definition http_log.h:412
#define APR_ENOMEM
Definition apr_errno.h:683
apr_bucket * e
apr_brigade_flush void * ctx
apr_pool_t apr_dbd_t apr_dbd_results_t ** res
Definition apr_dbd.h:287
apr_datum_t apr_datum_t * pvalue
Definition apr_dbm.h:128
const char apr_ssize_t slen
Definition apr_encode.h:168
const char * uri
Definition apr_uri.h:159
#define APR_URI_UNP_OMITSITEPART
Definition apr_uri.h:64
int ap_cstr_casecmp(const char *s1, const char *s2)
Definition util.c:3542
#define ap_strstr_c(s, c)
Definition httpd.h:2361
#define ap_assert(exp)
Definition httpd.h:2271
apr_size_t size
apr_uint32_t val
Definition apr_atomic.h:66
const char int apr_pool_t * pool
Definition apr_cstr.h:84
#define apr_isalnum(c)
Definition apr_lib.h:203
const char * value
Definition apr_env.h:51
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
const char * key
#define memmove(a, b, c)
apr_ssize_t * klen
Definition apr_hash.h:71
apr_vformatter_buff_t * c
Definition apr_lib.h:175
apr_uint32_t apr_pool_t apr_uint32_t apr_pollset_method_e method
Definition apr_poll.h:195
apr_pool_t * b
Definition apr_pools.h:529
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
const char char ** end
const char * s
Definition apr_strings.h:95
#define APR_ARRAY_PUSH(ary, type)
Definition apr_tables.h:150
int nelts
Definition apr_tables.h:122
#define APR_ARRAY_IDX(ary, i, type)
Definition apr_tables.h:141
int int status
h2_push_policy
Definition h2.h:114
@ H2_PUSH_FAST_LOAD
Definition h2.h:118
@ H2_PUSH_NONE
Definition h2.h:115
@ H2_PUSH_HEAD
Definition h2.h:117
@ H2_DEPENDANT_BEFORE
Definition h2.h:106
#define H2MIN(x, y)
Definition h2.h:101
#define H2_HD_MATCH_LIT(l, name, nlen)
static int add_push(link_ctx *ctx)
Definition h2_push.c:318
apr_array_header_t * h2_push_collect(apr_pool_t *p, const struct h2_request *req, apr_uint32_t push_policy, const struct h2_headers *res)
Definition h2_push.c:441
static apr_int32_t ceil_power_of_2(apr_int32_t n)
Definition h2_push.c:537
static int skip_ws(link_ctx *ctx)
Definition h2_push.c:131
static int read_link(link_ctx *ctx)
Definition h2_push.c:200
apr_array_header_t * h2_push_collect_update(struct h2_stream *stream, const struct h2_request *req, const struct h2_headers *res)
Definition h2_push.c:692
static int read_chr(link_ctx *ctx, char c)
Definition h2_push.c:153
static int same_authority(const h2_request *req, const apr_uri_t *uri)
Definition h2_push.c:270
static int read_param(link_ctx *ctx)
Definition h2_push.c:239
static apr_status_t gset_encode_bit(gset_encoder *encoder, int bit)
Definition h2_push.c:739
static int read_qstring(link_ctx *ctx, const char **ps)
Definition h2_push.c:170
static void remove_first(h2_push_diary *diary)
Definition h2_push.c:626
static unsigned int val_apr_hash(const char *str)
Definition h2_push.c:515
static int attr_char(char c)
Definition h2_push.c:74
static void move_to_last(h2_push_diary *diary, apr_size_t idx)
Definition h2_push.c:607
apr_status_t h2_push_diary_digest_get(h2_push_diary *diary, apr_pool_t *pool, int maxP, const char *authority, const char **pdata, apr_size_t *plen)
Definition h2_push.c:806
static int find_chr(link_ctx *ctx, char c, size_t *pidx)
Definition h2_push.c:141
static void inspect_link(link_ctx *ctx, const char *s, size_t slen)
Definition h2_push.c:371
static int set_push_header(void *ctx, const char *key, const char *value)
Definition h2_push.c:281
static int h2_push_diary_find(h2_push_diary *diary, apr_uint64_t hash)
Definition h2_push.c:590
static void h2_push_diary_append(h2_push_diary *diary, h2_push_diary_entry *e)
Definition h2_push.c:639
static int read_pname(link_ctx *ctx, const char **pname)
Definition h2_push.c:213
static int has_param(link_ctx *ctx, const char *param)
Definition h2_push.c:294
static int has_relation(link_ctx *ctx, const char *rel)
Definition h2_push.c:300
static int read_sep(link_ctx *ctx)
Definition h2_push.c:252
static char * mk_str(link_ctx *ctx, size_t end)
Definition h2_push.c:162
apr_array_header_t * h2_push_diary_update(h2_session *session, apr_array_header_t *pushes)
Definition h2_push.c:651
static void calc_apr_hash(h2_push_diary *diary, apr_uint64_t *phash, h2_push *push)
Definition h2_push.c:521
static unsigned char cbit_mask[]
Definition h2_push.c:728
h2_push_diary * h2_push_diary_create(apr_pool_t *p, int N)
Definition h2_push.c:585
static int head_iter(void *ctx, const char *key, const char *value)
Definition h2_push.c:427
#define GCSLOG_LEVEL
Definition h2_push.c:475
static apr_status_t gset_encode_next(gset_encoder *encoder, apr_uint64_t pval)
Definition h2_push.c:761
static int ptoken_char(char c)
Definition h2_push.c:95
static const char * policy_str(h2_push_policy policy)
Definition h2_push.c:46
static void init_params(link_ctx *ctx)
Definition h2_push.c:260
static int read_ptoken(link_ctx *ctx, const char **ps)
Definition h2_push.c:183
static int read_pvalue(link_ctx *ctx, const char **pvalue)
Definition h2_push.c:229
static h2_push_diary * diary_create(apr_pool_t *p, h2_push_digest_type dtype, int N)
Definition h2_push.c:549
static int cmp_puint64(const void *p1, const void *p2)
Definition h2_push.c:718
h2_push_digest_type
Definition h2_push.h:35
@ H2_PUSH_DIGEST_SHA256
Definition h2_push.h:37
@ H2_PUSH_DIGEST_APR_HASH
Definition h2_push.h:36
h2_request * h2_request_create(int id, apr_pool_t *pool, const char *method, const char *scheme, const char *authority, const char *path, apr_table_t *header)
Definition h2_request.c:47
apr_status_t h2_request_end_headers(h2_request *req, apr_pool_t *pool, size_t raw_bytes)
Definition h2_request.c:194
unsigned char h2_log2(int n)
Definition h2_util.c:35
CORE HTTP Daemon.
Apache Logging library.
HTTP protocol handling.
HTTP Daemon routines.
apr_pool_t * p
Definition md_event.c:32
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
char * name
apr_pool_t * pool
Definition apr_tables.h:64
unsigned int bit
Definition h2_push.c:714
apr_size_t datalen
Definition h2_push.c:712
int mask_bits
Definition h2_push.c:706
apr_uint64_t last
Definition h2_push.c:715
apr_uint64_t fixed_mask
Definition h2_push.c:709
h2_push_diary * diary
Definition h2_push.c:704
int fixed_bits
Definition h2_push.c:708
apr_pool_t * pool
Definition h2_push.c:710
unsigned char * data
Definition h2_push.c:711
unsigned char log2p
Definition h2_push.c:705
int delta_bits
Definition h2_push.c:707
apr_size_t offset
Definition h2_push.c:713
Definition h2_push.c:477
apr_uint64_t hash
Definition h2_push.c:478
h2_push_digest_type dtype
Definition h2_push.h:89
unsigned int mask_bits
Definition h2_push.h:87
h2_push_digest_calc * dcalc
Definition h2_push.h:90
apr_array_header_t * entries
Definition h2_push.h:83
const char * authority
Definition h2_push.h:88
const char * authority
Definition h2.h:172
const char * scheme
Definition h2.h:171
struct h2_push_diary * push_diary
Definition h2_session.h:89
conn_rec * c1
Definition h2_session.h:67
unsigned int push_policy
Definition h2_stream.h:114
apr_pool_t * pool
Definition h2_stream.h:84
struct h2_session * session
Definition h2_stream.h:85
#define str