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