varnish-cache/bin/varnishtest/vtc_h2_tbl.c
0
/*-
1
 * Copyright (c) 2008-2016 Varnish Software AS
2
 * All rights reserved.
3
 *
4
 * Author: Guillaume Quintard <guillaume.quintard@gmail.com>
5
 *
6
 * SPDX-License-Identifier: BSD-2-Clause
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 */
29
30
#include <stdint.h>
31
#include <stdio.h>
32
#include <stdlib.h>
33
#include <string.h>
34
35
#include "vdef.h"
36
37
#include "vas.h"
38
#include "vqueue.h"
39
40
#include "hpack.h"
41
#include "vtc_h2_priv.h"
42
43
/* TODO: fix that crazy workaround */
44
#define STAT_HDRS(i, k, v) \
45
        static char key_ ## i[] = k; \
46
        static char value_ ## i[] = v;
47
#include "vtc_h2_stattbl.h"
48
#undef STAT_HDRS
49
50
/*lint -save -e778 */
51
static const struct hpk_hdr sttbl[] = {
52
        {{NULL, 0, 0}, {NULL, 0, 0}, hpk_idx, 0},
53
#define STAT_HDRS(j, k, v) \
54
{ \
55
        .key = { \
56
                .ptr = key_ ## j, \
57
                .len = sizeof(k) - 1, \
58
                .huff = 0 \
59
        }, \
60
        .value = { \
61
                .ptr = value_ ## j, \
62
                .len = sizeof(v) - 1, \
63
                .huff = 0 \
64
        }, \
65
        .t = hpk_idx, \
66
        .i = j, \
67
},
68
#include "vtc_h2_stattbl.h"
69
#undef STAT_HDRS
70
};
71
/*lint -restore */
72
73
struct hpk_ctx {
74
        const struct hpk_hdr *sttbl;
75
        struct dynamic_table      dyntbl;
76
        uint32_t maxsize;
77
        uint32_t size;
78
};
79
80
81
struct hpk_iter *
82 10925
HPK_NewIter(struct hpk_ctx *ctx, void *buf, int size)
83
{
84 10925
        struct hpk_iter *iter = malloc(sizeof(*iter));
85 10925
        assert(iter);
86 10925
        assert(ctx);
87 10925
        assert(buf);
88 10925
        assert(size);
89 10925
        iter->ctx = ctx;
90 10925
        iter->orig = buf;
91 10925
        iter->buf = buf;
92 10925
        iter->end = iter->buf + size;
93 10925
        return (iter);
94
}
95
96
void
97 10925
HPK_FreeIter(struct hpk_iter *iter)
98
{
99 10925
        free(iter);
100 10925
}
101
102
static void
103 1000
pop_header(struct hpk_ctx *ctx)
104
{
105 1000
        assert(!VTAILQ_EMPTY(&ctx->dyntbl));
106 1000
        struct dynhdr *h = VTAILQ_LAST(&ctx->dyntbl, dynamic_table);
107 1000
        VTAILQ_REMOVE(&ctx->dyntbl, h, list);
108 1000
        ctx->size -= h->header.key.len + h->header.value.len + 32;
109 1000
        free(h->header.key.ptr);
110 1000
        free(h->header.value.ptr);
111 1000
        free(h);
112 1000
}
113
114
void
115 1000
push_header (struct hpk_ctx *ctx, const struct hpk_hdr *oh)
116
{
117
        const struct hpk_hdr *ih;
118
        struct dynhdr *h;
119
        uint32_t len;
120
121 1000
        assert(ctx->size <= ctx->maxsize);
122 1000
        AN(oh);
123
124 1000
        if (!ctx->maxsize)
125 0
                return;
126 1000
        len = oh->value.len + 32;
127 1000
        if (oh->key.ptr)
128 625
                len += oh->key.len;
129
        else {
130 375
                AN(oh->i);
131 375
                ih = HPK_GetHdr(ctx, oh->i);
132 375
                AN(ih);
133 375
                len += ih->key.len;
134
        }
135
136 1250
        while (!VTAILQ_EMPTY(&ctx->dyntbl) && ctx->maxsize - ctx->size < len)
137 250
                pop_header(ctx);
138 1000
        if (ctx->maxsize - ctx->size >= len) {
139 1000
                h = malloc(sizeof(*h));
140 1000
                AN(h);
141 1000
                h->header.t = hpk_idx;
142
143 1000
                if (oh->key.ptr) {
144 625
                        h->header.key.len = oh->key.len;
145 625
                        h->header.key.ptr = malloc(oh->key.len + 1L);
146 625
                        AN(h->header.key.ptr);
147 1250
                        memcpy(h->header.key.ptr,
148 625
                            oh->key.ptr, oh->key.len + 1L);
149 625
                } else {
150 375
                        AN(oh->i);
151 375
                        ih = HPK_GetHdr(ctx, oh->i);
152 375
                        AN(ih);
153
154 375
                        h->header.key.len = ih->key.len;
155 375
                        h->header.key.ptr = malloc(ih->key.len + 1L);
156 375
                        AN(h->header.key.ptr);
157 750
                        memcpy(h->header.key.ptr,
158 375
                            ih->key.ptr, ih->key.len + 1L);
159
                }
160
161 1000
                h->header.value.len = oh->value.len;
162 1000
                h->header.value.ptr = malloc(oh->value.len + 1L);
163 1000
                AN(h->header.value.ptr);
164 1000
                memcpy(h->header.value.ptr, oh->value.ptr, oh->value.len + 1L);
165
166 1000
                VTAILQ_INSERT_HEAD(&ctx->dyntbl, h, list);
167 1000
                ctx->size += len;
168 1000
        }
169
170 1000
}
171
172
enum hpk_result
173 250
HPK_ResizeTbl(struct hpk_ctx *ctx, uint32_t num)
174
{
175 250
        ctx->maxsize = num;
176 375
        while (!VTAILQ_EMPTY(&ctx->dyntbl) && ctx->maxsize < ctx->size)
177 125
                pop_header(ctx);
178 250
        return (hpk_done);
179
}
180
181
static const struct hpk_txt *
182 17450
tbl_get_field(const struct hpk_ctx *ctx, uint32_t idx, int key)
183
{
184
        struct dynhdr *dh;
185 17450
        assert(ctx);
186 17450
        if (idx > 61 + ctx->size)
187 50
                return (NULL);
188 17400
        else if (idx <= 61) {
189 16900
                if (key)
190 14350
                        return (&ctx->sttbl[idx].key);
191
                else
192 2550
                        return (&ctx->sttbl[idx].value);
193
        }
194
195 500
        idx -= 62;
196 1150
        VTAILQ_FOREACH(dh, &ctx->dyntbl, list)
197 1150
                if (!idx--)
198 500
                        break;
199 500
        if (idx && dh) {
200 500
                if (key)
201 250
                        return (&dh->header.key);
202
                else
203 250
                        return (&dh->header.value);
204
        } else
205 0
                return (NULL);
206 17450
}
207
208
const struct hpk_txt *
209 14650
tbl_get_key(const struct hpk_ctx *ctx, uint32_t idx)
210
{
211 14650
        return (tbl_get_field(ctx, idx, 1));
212
}
213
214
const struct hpk_txt *
215 2800
tbl_get_value(const struct hpk_ctx *ctx, uint32_t idx)
216
{
217 2800
        return (tbl_get_field(ctx, idx, 0));
218
}
219
220
const struct hpk_hdr *
221 3150
HPK_GetHdr(const struct hpk_ctx *ctx, uint32_t idx)
222
{
223 3150
        uint32_t oi = idx;
224
        struct dynhdr *dh;
225 3150
        assert(ctx);
226 3150
        if (idx > 61 + ctx->size)
227 0
                return (NULL);
228 3150
        else if (idx <= 61)
229 750
                return (&ctx->sttbl[idx]);
230
231 2400
        idx -= 62;
232 4700
        VTAILQ_FOREACH(dh, &ctx->dyntbl, list)
233 4700
                if (!idx--)
234 2400
                        break;
235 2400
        if (idx && dh) {
236 2400
                dh->header.i = oi;
237 2400
                return (&dh->header);
238
        } else
239 0
                return (NULL);
240 3150
}
241
242
uint32_t
243 650
HPK_GetTblSize(const struct hpk_ctx *ctx)
244
{
245 650
        return (ctx->size);
246
}
247
248
uint32_t
249 0
HPK_GetTblMaxSize(const struct hpk_ctx *ctx)
250
{
251 0
        return (ctx->maxsize);
252
}
253
254
uint32_t
255 25
HPK_GetTblLength(const struct hpk_ctx *ctx)
256
{
257
        struct dynhdr *dh;
258 25
        uint32_t l = 0;
259 50
        VTAILQ_FOREACH(dh, &ctx->dyntbl, list)
260 25
                l++;
261 25
        return (l);
262
}
263
264
#if 0
265
void
266
dump_dyn_tbl(const struct hpk_ctx *ctx)
267
{
268
        int i = 0;
269
        struct dynhdr *dh;
270
        printf("DUMPING %u/%u\n", ctx->size, ctx->maxsize);
271
        VTAILQ_FOREACH(dh, &ctx->dyntbl, list) {
272
                printf(" (%d) %s: %s\n",
273
                    i++, dh->header.key.ptr, dh->header.value.ptr);
274
        }
275
        printf("DONE\n");
276
}
277
#endif
278
279
struct hpk_ctx *
280 9630
HPK_NewCtx(uint32_t maxsize)
281
{
282 9630
        struct hpk_ctx *ctx = calloc(1, sizeof(*ctx));
283 9630
        assert(ctx);
284 9630
        ctx->sttbl = sttbl;
285 9630
        ctx->maxsize = maxsize;
286 9630
        ctx->size = 0;
287 9630
        return (ctx);
288
}
289
290
void
291 9648
HPK_FreeCtx(struct hpk_ctx *ctx)
292
{
293
294 10273
        while (!VTAILQ_EMPTY(&ctx->dyntbl))
295 625
                pop_header(ctx);
296 9648
        free(ctx);
297 9648
}