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