/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License.
*/
staticint has_relation(link_ctx *ctx, constchar *rel)
{ constchar *s, *val = apr_table_get(ctx->params, "rel"); if (val) { if (!strcmp(rel, val)) { return 1;
}
s = ap_strstr_c(val, rel); if (s && (s == val || s[-1] == ' ')) {
s += strlen(rel); if (!*s || *s == ' ') { return 1;
}
}
} return 0;
}
staticint add_push(link_ctx *ctx)
{ /* so, we have read a Link header and need to decide * if we transform it into a push.
*/ if (has_relation(ctx, "preload") && !has_param(ctx, "nopush")) {
apr_uri_t uri; if (apr_uri_parse(ctx->pool, ctx->link, &uri) == APR_SUCCESS) { if (uri.path && same_authority(ctx->req, &uri)) { char *path; constchar *method;
apr_table_t *headers;
h2_request *req;
h2_push *push;
/* We only want to generate pushes for resources in the * same authority than the original request. * icing: i think that is wise, otherwise we really need to * check that the vhost/server is available and uses the same * TLS (if any) parameters.
*/
path = apr_uri_unparse(ctx->pool, &uri, APR_URI_UNP_OMITSITEPART);
push = apr_pcalloc(ctx->pool, sizeof(*push)); switch (ctx->push_policy) { case H2_PUSH_HEAD:
method = "HEAD"; break; default:
method = "GET"; break;
}
headers = apr_table_make(ctx->pool, 5);
apr_table_do(set_push_header, headers, ctx->req->headers, NULL);
req = h2_request_create(0, ctx->pool, method, ctx->req->scheme,
ctx->req->authority, path, headers); /* atm, we do not push on pushes */
h2_request_end_headers(req, ctx->pool, 0);
push->req = req; if (has_param(ctx, "critical")) {
h2_priority *prio = apr_pcalloc(ctx->pool, sizeof(*prio));
prio->dependency = H2_DEPENDANT_BEFORE;
push->priority = prio;
} if (!ctx->pushes) {
ctx->pushes = apr_array_make(ctx->pool, 5, sizeof(h2_push*));
}
APR_ARRAY_PUSH(ctx->pushes, h2_push*) = push;
}
}
} return 0;
}
#if AP_HAS_RESPONSE_BUCKETS
apr_array_header_t *h2_push_collect(apr_pool_t *p, conststruct h2_request *req,
apr_uint32_t push_policy, const ap_bucket_response *res) #else
apr_array_header_t *h2_push_collect(apr_pool_t *p, conststruct h2_request *req,
apr_uint32_t push_policy, conststruct h2_headers *res) #endif
{ if (req && push_policy != H2_PUSH_NONE) { /* Collect push candidates from the request/response pair. * * One source for pushes are "rel=preload" link headers * in the response. * * TODO: This may be extended in the future by hooks or callbacks * where other modules can provide push information directly.
*/ if (res->headers) {
link_ctx ctx;
staticvoid calc_apr_hash(h2_push_diary *diary, apr_uint64_t *phash, h2_push *push)
{
apr_uint64_t val;
(void)diary; #if APR_UINT64_MAX > UINT_MAX
val = ((apr_uint64_t)(val_apr_hash(push->req->scheme)) << 32);
val ^= ((apr_uint64_t)(val_apr_hash(push->req->authority)) << 16);
val ^= val_apr_hash(push->req->path); #else
val = val_apr_hash(push->req->scheme);
val ^= val_apr_hash(push->req->authority);
val ^= val_apr_hash(push->req->path); #endif
*phash = val;
}
static apr_int32_t ceil_power_of_2(apr_int32_t n)
{ if (n <= 2) return 2;
--n;
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16; return ++n;
}
if (N > 0) {
diary = apr_pcalloc(p, sizeof(*diary));
diary->NMax = ceil_power_of_2(N);
diary->N = diary->NMax; /* the mask we use in value comparison depends on where we got * the values from. If we calculate them ourselves, we can use * the full 64 bits. * If we set the diary via a compressed golomb set, we have less
* relevant bits and need to use a smaller mask. */
diary->mask_bits = 64; /* grows by doubling, start with a power of 2 */
diary->entries = apr_array_make(p, 16, sizeof(h2_push_diary_entry));
staticint h2_push_diary_find(h2_push_diary *diary, apr_uint64_t hash)
{ if (diary) {
h2_push_diary_entry *e; int i;
/* search from the end, where the last accessed digests are */ for (i = diary->entries->nelts-1; i >= 0; --i) {
e = &APR_ARRAY_IDX(diary->entries, i, h2_push_diary_entry); if (e->hash == hash) { return i;
}
}
} return -1;
}
/* in golomb bit stream encoding, bit 0 is the 8th of the first char, or * more generally: * char(bit/8) & cbit_mask[(bit % 8)]
*/ staticunsignedchar cbit_mask[] = {
0x80u,
0x40u,
0x20u,
0x10u,
0x08u,
0x04u,
0x02u,
0x01u,
};
for (i = encoder->fixed_bits-1; i >= 0; --i) {
status = gset_encode_bit(encoder, (delta >> i) & 1); if (status != APR_SUCCESS) { return status;
}
} return APR_SUCCESS;
}
/** * Get a cache digest as described in * https://datatracker.ietf.org/doc/draft-kazuho-h2-cache-digest/ * from the contents of the push diary. * * @param diary the diary to calculdate the digest from * @param p the pool to use * @param pdata on successful return, the binary cache digest * @param plen on successful return, the length of the binary data
*/
apr_status_t h2_push_diary_digest_get(h2_push_diary *diary, apr_pool_t *pool, int maxP, constchar *authority, constchar **pdata, apr_size_t *plen)
{ int nelts, N; unsignedchar log2n, log2pmax;
gset_encoder encoder;
apr_uint64_t *hashes;
apr_size_t hash_count, i;
nelts = diary->entries->nelts;
N = ceil_power_of_2(nelts);
log2n = h2_log2(N);
/* Now log2p is the max number of relevant bits, so that * log2p + log2n == mask_bits. We can use a lower log2p * and have a shorter set encoding...
*/
log2pmax = h2_log2(ceil_power_of_2(maxP));
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.