Skip to content
This repository was archived by the owner on Jun 9, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
176 changes: 0 additions & 176 deletions mod_http2/h2_push.c
Original file line number Diff line number Diff line change
Expand Up @@ -699,179 +699,3 @@ apr_array_header_t *h2_push_collect_update(struct h2_stream *stream,
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;
}

15 changes: 0 additions & 15 deletions mod_http2/h2_push.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,19 +140,4 @@ apr_array_header_t *h2_push_collect_update(struct h2_stream *stream,
const struct h2_headers *res);
#endif

/**
* 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 authority the authority to get the data for, use NULL/"*" for all
* @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 *p,
int maxP, const char *authority,
const char **pdata, apr_size_t *plen);

#endif /* defined(__mod_h2__h2_push__) */
Loading