pushes = h2_push_collect(stream->pool, req, stream->push_policy, res);
return h2_push_diary_update(stream->session, pushes);
}
-
-typedef struct {
- h2_push_diary *diary;
- unsigned char log2p;
- int mask_bits;
- int delta_bits;
- int fixed_bits;
- apr_uint64_t fixed_mask;
- apr_pool_t *pool;
- unsigned char *data;
- apr_size_t datalen;
- apr_size_t offset;
- unsigned int bit;
- apr_uint64_t last;
-} gset_encoder;
-
-static int cmp_puint64(const void *p1, const void *p2)
-{
- const apr_uint64_t *pu1 = p1, *pu2 = p2;
- return (*pu1 > *pu2)? 1 : ((*pu1 == *pu2)? 0 : -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)]
- */
-static unsigned char cbit_mask[] = {
- 0x80u,
- 0x40u,
- 0x20u,
- 0x10u,
- 0x08u,
- 0x04u,
- 0x02u,
- 0x01u,
-};
-
-static apr_status_t gset_encode_bit(gset_encoder *encoder, int bit)
-{
- if (++encoder->bit >= 8) {
- if (++encoder->offset >= encoder->datalen) {
- apr_size_t nlen = encoder->datalen*2;
- unsigned char *ndata = apr_pcalloc(encoder->pool, nlen);
- if (!ndata) {
- return APR_ENOMEM;
- }
- memcpy(ndata, encoder->data, encoder->datalen);
- encoder->data = ndata;
- encoder->datalen = nlen;
- }
- encoder->bit = 0;
- encoder->data[encoder->offset] = 0xffu;
- }
- if (!bit) {
- encoder->data[encoder->offset] &= ~cbit_mask[encoder->bit];
- }
- return APR_SUCCESS;
-}
-
-static apr_status_t gset_encode_next(gset_encoder *encoder, apr_uint64_t pval)
-{
- apr_uint64_t delta, flex_bits;
- apr_status_t status = APR_SUCCESS;
- int i;
-
- delta = pval - encoder->last;
- encoder->last = pval;
- flex_bits = (delta >> encoder->fixed_bits);
- /* Intentional no APLOGNO */
- ap_log_perror(APLOG_MARK, GCSLOG_LEVEL, 0, encoder->pool,
- "h2_push_diary_enc: val=%"APR_UINT64_T_HEX_FMT", delta=%"
- APR_UINT64_T_HEX_FMT" flex_bits=%"APR_UINT64_T_FMT", "
- ", fixed_bits=%d, fixed_val=%"APR_UINT64_T_HEX_FMT,
- pval, delta, flex_bits, encoder->fixed_bits, delta&encoder->fixed_mask);
- for (; flex_bits != 0; --flex_bits) {
- status = gset_encode_bit(encoder, 1);
- if (status != APR_SUCCESS) {
- return status;
- }
- }
- status = gset_encode_bit(encoder, 0);
- if (status != APR_SUCCESS) {
- return status;
- }
-
- 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, const char *authority,
- const char **pdata, apr_size_t *plen)
-{
- int nelts, N;
- unsigned char 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));
-
- memset(&encoder, 0, sizeof(encoder));
- encoder.diary = diary;
- encoder.log2p = H2MIN(diary->mask_bits - log2n, log2pmax);
- encoder.mask_bits = log2n + encoder.log2p;
- encoder.delta_bits = diary->mask_bits - encoder.mask_bits;
- encoder.fixed_bits = encoder.log2p;
- encoder.fixed_mask = 1;
- encoder.fixed_mask = (encoder.fixed_mask << encoder.fixed_bits) - 1;
- encoder.pool = pool;
- encoder.datalen = 512;
- encoder.data = apr_pcalloc(encoder.pool, encoder.datalen);
-
- encoder.data[0] = log2n;
- encoder.data[1] = encoder.log2p;
- encoder.offset = 1;
- encoder.bit = 8;
- encoder.last = 0;
-
- /* Intentional no APLOGNO */
- ap_log_perror(APLOG_MARK, GCSLOG_LEVEL, 0, pool,
- "h2_push_diary_digest_get: %d entries, N=%d, log2n=%d, "
- "mask_bits=%d, enc.mask_bits=%d, delta_bits=%d, enc.log2p=%d, authority=%s",
- (int)nelts, (int)N, (int)log2n, diary->mask_bits,
- (int)encoder.mask_bits, (int)encoder.delta_bits,
- (int)encoder.log2p, authority);
-
- if (!authority || !diary->authority
- || !strcmp("*", authority) || !strcmp(diary->authority, authority)) {
- hash_count = diary->entries->nelts;
- hashes = apr_pcalloc(encoder.pool, hash_count);
- for (i = 0; i < hash_count; ++i) {
- hashes[i] = ((&APR_ARRAY_IDX(diary->entries, i, h2_push_diary_entry))->hash
- >> encoder.delta_bits);
- }
-
- qsort(hashes, hash_count, sizeof(apr_uint64_t), cmp_puint64);
- for (i = 0; i < hash_count; ++i) {
- if (!i || (hashes[i] != hashes[i-1])) {
- gset_encode_next(&encoder, hashes[i]);
- }
- }
- /* Intentional no APLOGNO */
- ap_log_perror(APLOG_MARK, GCSLOG_LEVEL, 0, pool,
- "h2_push_diary_digest_get: golomb compressed hashes, %d bytes",
- (int)encoder.offset + 1);
- }
- *pdata = (const char *)encoder.data;
- *plen = encoder.offset + 1;
-
- return APR_SUCCESS;
-}
-