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