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