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