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 <stdlib.h>
30
#include <string.h>
31
#include <stdio.h>
32
#include <stdint.h>
33
34
#include "vdef.h"
35
36
#include "vas.h"
37
38
#include "hpack.h"
39
#include "vtc_h2_priv.h"
40
41
/* TODO: fix that crazy workaround */
42
#define STAT_HDRS(i, k, v) \
43
        static char key_ ## i[] = k; \
44
        static char value_ ## i[] = v;
45
#include "vtc_h2_stattbl.h"
46
#undef STAT_HDRS
47
48
/*lint -save -e778 */
49
static const struct hpk_hdr sttbl[] = {
50
        {{NULL, 0, 0}, {NULL, 0, 0}, hpk_idx, 0},
51
#define STAT_HDRS(j, k, v) \
52
{ \
53
        .key = { \
54
                .ptr = key_ ## j, \
55
                .len = sizeof(k) - 1, \
56
                .huff = 0 \
57
        }, \
58
        .value = { \
59
                .ptr = value_ ## j, \
60
                .len = sizeof(v) - 1, \
61
                .huff = 0 \
62
        }, \
63
        .t = hpk_idx, \
64
        .i = j, \
65
},
66
#include "vtc_h2_stattbl.h"
67
#undef STAT_HDRS
68
};
69
/*lint -restore */
70
71
struct hpk_ctx {
72
        const struct hpk_hdr *sttbl;
73
        struct dynamic_table      dyntbl;
74
        uint32_t maxsize;
75
        uint32_t size;
76
};
77
78
79
struct hpk_iter *
80 490
HPK_NewIter(struct hpk_ctx *ctx, char *buf, int size)
81
{
82 490
        struct hpk_iter *iter = malloc(sizeof(*iter));
83 490
        assert(iter);
84 490
        assert(ctx);
85 490
        assert(buf);
86 490
        assert(size);
87 490
        iter->ctx = ctx;
88 490
        iter->orig = buf;
89 490
        iter->buf = buf;
90 490
        iter->end = buf + size;
91 490
        return (iter);
92
}
93
94
void
95 490
HPK_FreeIter(struct hpk_iter *iter)
96
{
97 490
        free(iter);
98 490
}
99
100
static void
101 80
pop_header(struct hpk_ctx *ctx)
102
{
103 80
        assert(!VTAILQ_EMPTY(&ctx->dyntbl));
104 80
        struct dynhdr *h = VTAILQ_LAST(&ctx->dyntbl, dynamic_table);
105 80
        VTAILQ_REMOVE(&ctx->dyntbl, h, list);
106 80
        ctx->size -= h->header.key.len + h->header.value.len + 32;
107 80
        free(h->header.key.ptr);
108 80
        free(h->header.value.ptr);
109 80
        free(h);
110 80
}
111
112
void
113 80
push_header (struct hpk_ctx *ctx, const struct hpk_hdr *oh)
114
{
115
        const struct hpk_hdr *ih;
116
        struct dynhdr *h;
117
        uint32_t len;
118
119 80
        assert(ctx->size <= ctx->maxsize);
120 80
        AN(oh);
121
122 80
        if (!ctx->maxsize)
123 80
                return;
124 80
        len = oh->value.len + 32;
125 80
        if (oh->key.ptr)
126 50
                len += oh->key.len;
127
        else {
128 30
                AN(oh->i);
129 30
                ih = HPK_GetHdr(ctx, oh->i);
130 30
                AN(ih);
131 30
                len += ih->key.len;
132
        }
133
134 180
        while (!VTAILQ_EMPTY(&ctx->dyntbl) && ctx->maxsize - ctx->size < len)
135 20
                pop_header(ctx);
136 80
        if (ctx->maxsize - ctx->size >= len) {
137 80
                h = malloc(sizeof(*h));
138 80
                AN(h);
139 80
                h->header.t = hpk_idx;
140
141 80
                if (oh->key.ptr) {
142 50
                        h->header.key.len = oh->key.len;
143 50
                        h->header.key.ptr = malloc(oh->key.len + 1L);
144 50
                        AN(h->header.key.ptr);
145 100
                        memcpy(h->header.key.ptr,
146 100
                            oh->key.ptr, oh->key.len + 1L);
147
                } else {
148 30
                        AN(oh->i);
149 30
                        ih = HPK_GetHdr(ctx, oh->i);
150 30
                        AN(ih);
151
152 30
                        h->header.key.len = ih->key.len;
153 30
                        h->header.key.ptr = malloc(ih->key.len + 1L);
154 30
                        AN(h->header.key.ptr);
155 60
                        memcpy(h->header.key.ptr,
156 60
                            ih->key.ptr, ih->key.len + 1L);
157
                }
158
159 80
                h->header.value.len = oh->value.len;
160 80
                h->header.value.ptr = malloc(oh->value.len + 1L);
161 80
                AN(h->header.value.ptr);
162 80
                memcpy(h->header.value.ptr, oh->value.ptr, oh->value.len + 1L);
163
164 80
                VTAILQ_INSERT_HEAD(&ctx->dyntbl, h, list);
165 80
                ctx->size += len;
166
        }
167
168
}
169
170
enum hpk_result
171 20
HPK_ResizeTbl(struct hpk_ctx *ctx, uint32_t num)
172
{
173 20
        ctx->maxsize = num;
174 50
        while (!VTAILQ_EMPTY(&ctx->dyntbl) && ctx->maxsize < ctx->size)
175 10
                pop_header(ctx);
176 20
        return (hpk_done);
177
}
178
179
static const struct txt *
180 630
tbl_get_field(const struct hpk_ctx *ctx, uint32_t idx, int key)
181
{
182
        struct dynhdr *dh;
183 630
        assert(ctx);
184 630
        if (idx > 61 + ctx->size)
185 4
                return (NULL);
186 626
        else if (idx <= 61) {
187 586
                if (key)
188 470
                        return (&ctx->sttbl[idx].key);
189
                else
190 116
                        return (&ctx->sttbl[idx].value);
191
        }
192
193 40
        idx -= 62;
194 92
        VTAILQ_FOREACH(dh, &ctx->dyntbl, list)
195 92
                if (!idx--)
196 40
                        break;
197 40
        if (idx && dh) {
198 40
                if (key)
199 20
                        return (&dh->header.key);
200
                else
201 20
                        return (&dh->header.value);
202
        } else
203 0
                return (NULL);
204
}
205
206
const struct txt *
207 494
tbl_get_key(const struct hpk_ctx *ctx, uint32_t idx)
208
{
209 494
        return (tbl_get_field(ctx, idx, 1));
210
}
211
212
const struct txt *
213 136
tbl_get_value(const struct hpk_ctx *ctx, uint32_t idx)
214
{
215 136
        return (tbl_get_field(ctx, idx, 0));
216
}
217
218
const struct hpk_hdr *
219 252
HPK_GetHdr(const struct hpk_ctx *ctx, uint32_t idx)
220
{
221 252
        uint32_t oi = idx;
222
        struct dynhdr *dh;
223 252
        assert(ctx);
224 252
        if (idx > 61 + ctx->size)
225 0
                return (NULL);
226 252
        else if (idx <= 61)
227 60
                return (&ctx->sttbl[idx]);
228
229 192
        idx -= 62;
230 376
        VTAILQ_FOREACH(dh, &ctx->dyntbl, list)
231 376
                if (!idx--)
232 192
                        break;
233 192
        if (idx && dh) {
234 192
                dh->header.i = oi;
235 192
                return (&dh->header);
236
        } else
237 0
                return (NULL);
238
}
239
240
uint32_t
241 52
HPK_GetTblSize(const struct hpk_ctx *ctx)
242
{
243 52
        return (ctx->size);
244
}
245
246
uint32_t
247 0
HPK_GetTblMaxSize(const struct hpk_ctx *ctx)
248
{
249 0
        return (ctx->maxsize);
250
}
251
252
uint32_t
253 2
HPK_GetTblLength(const struct hpk_ctx *ctx)
254
{
255
        struct dynhdr *dh;
256 2
        uint32_t l = 0;
257 4
        VTAILQ_FOREACH(dh, &ctx->dyntbl, list)
258 2
                l++;
259 2
        return (l);
260
}
261
262
#if 0
263
void
264
dump_dyn_tbl(const struct hpk_ctx *ctx)
265
{
266
        int i = 0;
267
        struct dynhdr *dh;
268
        printf("DUMPING %u/%u\n", ctx->size, ctx->maxsize);
269
        VTAILQ_FOREACH(dh, &ctx->dyntbl, list) {
270
                printf(" (%d) %s: %s\n",
271
                    i++, dh->header.key.ptr, dh->header.value.ptr);
272
        }
273
        printf("DONE\n");
274
}
275
#endif
276
277
struct hpk_ctx *
278 420
HPK_NewCtx(uint32_t maxsize)
279
{
280 420
        struct hpk_ctx *ctx = calloc(1, sizeof(*ctx));
281 420
        assert(ctx);
282 420
        ctx->sttbl = sttbl;
283 420
        ctx->maxsize = maxsize;
284 420
        ctx->size = 0;
285 420
        return (ctx);
286
}
287
288
void
289 420
HPK_FreeCtx(struct hpk_ctx *ctx)
290
{
291
292 890
        while (!VTAILQ_EMPTY(&ctx->dyntbl))
293 50
                pop_header(ctx);
294 420
        free(ctx);
295 420
}