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 4338
HPK_NewIter(struct hpk_ctx *ctx, void *buf, int size)
83
{
84 4338
        struct hpk_iter *iter = malloc(sizeof(*iter));
85 4338
        assert(iter);
86 4338
        assert(ctx);
87 4338
        assert(buf);
88 4338
        assert(size);
89 4338
        iter->ctx = ctx;
90 4338
        iter->orig = buf;
91 4338
        iter->buf = buf;
92 4338
        iter->end = iter->buf + size;
93 4338
        return (iter);
94
}
95
96
void
97 4338
HPK_FreeIter(struct hpk_iter *iter)
98
{
99 4338
        free(iter);
100 4338
}
101
102
static void
103 120
pop_header(struct hpk_ctx *ctx)
104
{
105 120
        assert(!VTAILQ_EMPTY(&ctx->dyntbl));
106 120
        struct dynhdr *h = VTAILQ_LAST(&ctx->dyntbl, dynamic_table);
107 120
        VTAILQ_REMOVE(&ctx->dyntbl, h, list);
108 120
        ctx->size -= h->header.key.len + h->header.value.len + 32;
109 120
        free(h->header.key.ptr);
110 120
        free(h->header.value.ptr);
111 120
        free(h);
112 120
}
113
114
void
115 120
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 120
        assert(ctx->size <= ctx->maxsize);
122 120
        AN(oh);
123
124 120
        if (!ctx->maxsize)
125 0
                return;
126 120
        len = oh->value.len + 32;
127 120
        if (oh->key.ptr)
128 75
                len += oh->key.len;
129
        else {
130 45
                AN(oh->i);
131 45
                ih = HPK_GetHdr(ctx, oh->i);
132 45
                AN(ih);
133 45
                len += ih->key.len;
134
        }
135
136 150
        while (!VTAILQ_EMPTY(&ctx->dyntbl) && ctx->maxsize - ctx->size < len)
137 30
                pop_header(ctx);
138 120
        if (ctx->maxsize - ctx->size >= len) {
139 120
                h = malloc(sizeof(*h));
140 120
                AN(h);
141 120
                h->header.t = hpk_idx;
142
143 120
                if (oh->key.ptr) {
144 75
                        h->header.key.len = oh->key.len;
145 75
                        h->header.key.ptr = malloc(oh->key.len + 1L);
146 75
                        AN(h->header.key.ptr);
147 150
                        memcpy(h->header.key.ptr,
148 75
                            oh->key.ptr, oh->key.len + 1L);
149 75
                } else {
150 45
                        AN(oh->i);
151 45
                        ih = HPK_GetHdr(ctx, oh->i);
152 45
                        AN(ih);
153
154 45
                        h->header.key.len = ih->key.len;
155 45
                        h->header.key.ptr = malloc(ih->key.len + 1L);
156 45
                        AN(h->header.key.ptr);
157 90
                        memcpy(h->header.key.ptr,
158 45
                            ih->key.ptr, ih->key.len + 1L);
159
                }
160
161 120
                h->header.value.len = oh->value.len;
162 120
                h->header.value.ptr = malloc(oh->value.len + 1L);
163 120
                AN(h->header.value.ptr);
164 120
                memcpy(h->header.value.ptr, oh->value.ptr, oh->value.len + 1L);
165
166 120
                VTAILQ_INSERT_HEAD(&ctx->dyntbl, h, list);
167 120
                ctx->size += len;
168 120
        }
169
170 120
}
171
172
enum hpk_result
173 30
HPK_ResizeTbl(struct hpk_ctx *ctx, uint32_t num)
174
{
175 30
        ctx->maxsize = num;
176 45
        while (!VTAILQ_EMPTY(&ctx->dyntbl) && ctx->maxsize < ctx->size)
177 15
                pop_header(ctx);
178 30
        return (hpk_done);
179
}
180
181
static const struct hpk_txt *
182 2118
tbl_get_field(const struct hpk_ctx *ctx, uint32_t idx, int key)
183
{
184
        struct dynhdr *dh;
185 2118
        assert(ctx);
186 2118
        if (idx > 61 + ctx->size)
187 6
                return (NULL);
188 2112
        else if (idx <= 61) {
189 2052
                if (key)
190 1743
                        return (&ctx->sttbl[idx].key);
191
                else
192 309
                        return (&ctx->sttbl[idx].value);
193
        }
194
195 60
        idx -= 62;
196 138
        VTAILQ_FOREACH(dh, &ctx->dyntbl, list)
197 138
                if (!idx--)
198 60
                        break;
199 60
        if (idx && dh) {
200 60
                if (key)
201 30
                        return (&dh->header.key);
202
                else
203 30
                        return (&dh->header.value);
204
        } else
205 0
                return (NULL);
206 2118
}
207
208
const struct hpk_txt *
209 1779
tbl_get_key(const struct hpk_ctx *ctx, uint32_t idx)
210
{
211 1779
        return (tbl_get_field(ctx, idx, 1));
212
}
213
214
const struct hpk_txt *
215 339
tbl_get_value(const struct hpk_ctx *ctx, uint32_t idx)
216
{
217 339
        return (tbl_get_field(ctx, idx, 0));
218
}
219
220
const struct hpk_hdr *
221 378
HPK_GetHdr(const struct hpk_ctx *ctx, uint32_t idx)
222
{
223 378
        uint32_t oi = idx;
224
        struct dynhdr *dh;
225 378
        assert(ctx);
226 378
        if (idx > 61 + ctx->size)
227 0
                return (NULL);
228 378
        else if (idx <= 61)
229 90
                return (&ctx->sttbl[idx]);
230
231 288
        idx -= 62;
232 564
        VTAILQ_FOREACH(dh, &ctx->dyntbl, list)
233 564
                if (!idx--)
234 288
                        break;
235 288
        if (idx && dh) {
236 288
                dh->header.i = oi;
237 288
                return (&dh->header);
238
        } else
239 0
                return (NULL);
240 378
}
241
242
uint32_t
243 78
HPK_GetTblSize(const struct hpk_ctx *ctx)
244
{
245 78
        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 3
HPK_GetTblLength(const struct hpk_ctx *ctx)
256
{
257
        struct dynhdr *dh;
258 3
        uint32_t l = 0;
259 6
        VTAILQ_FOREACH(dh, &ctx->dyntbl, list)
260 3
                l++;
261 3
        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 1188
HPK_NewCtx(uint32_t maxsize)
281
{
282 1188
        struct hpk_ctx *ctx = calloc(1, sizeof(*ctx));
283 1188
        assert(ctx);
284 1188
        ctx->sttbl = sttbl;
285 1188
        ctx->maxsize = maxsize;
286 1188
        ctx->size = 0;
287 1188
        return (ctx);
288
}
289
290
void
291 1188
HPK_FreeCtx(struct hpk_ctx *ctx)
292
{
293
294 1263
        while (!VTAILQ_EMPTY(&ctx->dyntbl))
295 75
                pop_header(ctx);
296 1188
        free(ctx);
297 1188
}