varnish-cache/bin/varnishd/http2/cache_http2_hpack.c
1
/*-
2
 * Copyright (c) 2016 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Martin Blix Grydeland <martin@varnish-software.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
30
#include "config.h"
31
32
#include "cache/cache_varnishd.h"
33
34
#include <ctype.h>
35
#include <stdio.h>
36
37
#include "http2/cache_http2.h"
38
#include "vct.h"
39
40
static h2_error
41 2200
h2h_checkhdr(const struct http *hp, const char *b, size_t namelen, size_t len)
42
{
43
        const char *p;
44
45 2200
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
46 2200
        AN(b);
47 2200
        assert(namelen >= 2);   /* 2 chars from the ': ' that we added */
48 2200
        assert(namelen <= len);
49
50 2200
        if (namelen == 2) {
51 0
                VSLb(hp->vsl, SLT_BogoHeader, "Empty name");
52 0
                return (H2SE_PROTOCOL_ERROR);
53
        }
54
55 30067
        for (p = b; p < b + len; p++) {
56 27862
                if (p < b + (namelen - 2)) {
57
                        /* Check valid name characters */
58 14876
                        if (p == b && *p == ':')
59 1920
                                continue; /* pseudo-header */
60 12959
                        if (isupper(*p)) {
61 16
                                VSLb(hp->vsl, SLT_BogoHeader,
62
                                    "Illegal header name (upper-case): %.*s",
63 8
                                    (int)(len > 20 ? 20 : len), b);
64 8
                                return (H2SE_PROTOCOL_ERROR);
65
                        }
66 12955
                        if (vct_istchar(*p)) {
67
                                /* XXX: vct should have a proper class for
68
                                   this avoiding two checks */
69 12946
                                continue;
70
                        }
71 16
                        VSLb(hp->vsl, SLT_BogoHeader,
72
                            "Illegal header name: %.*s",
73 8
                            (int)(len > 20 ? 20 : len), b);
74 8
                        return (H2SE_PROTOCOL_ERROR);
75 12996
                } else if (p < b + namelen) {
76
                        /* ': ' added by us */
77 4366
                        assert(*p == ':' || *p == ' ');
78 4366
                } else {
79
                        /* Check valid value characters */
80 8636
                        if (!vct_isctl(*p) || vct_issp(*p))
81 8636
                                continue;
82 0
                        VSLb(hp->vsl, SLT_BogoHeader,
83
                            "Illegal header value: %.*s",
84 0
                            (int)(len > 20 ? 20 : len), b);
85 0
                        return (H2SE_PROTOCOL_ERROR);
86
                }
87 4366
        }
88
89 2183
        return (0);
90 2199
}
91
92
static h2_error
93 2183
h2h_addhdr(struct http *hp, char *b, size_t namelen, size_t len)
94
{
95
        /* XXX: This might belong in cache/cache_http.c */
96
        unsigned n;
97
98 2183
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
99 2183
        AN(b);
100 2184
        assert(namelen >= 2);   /* 2 chars from the ': ' that we added */
101 2183
        assert(namelen <= len);
102
103 2184
        if (len > UINT_MAX) {   /* XXX: cache_param max header size */
104 0
                VSLb(hp->vsl, SLT_BogoHeader, "Header too large: %.20s", b);
105 0
                return (H2SE_ENHANCE_YOUR_CALM);
106
        }
107
108 2184
        if (b[0] == ':') {
109
                /* Match H/2 pseudo headers */
110
                /* XXX: Should probably have some include tbl for
111
                   pseudo-headers */
112 1920
                if (!strncmp(b, ":method: ", namelen)) {
113 608
                        b += namelen;
114 608
                        len -= namelen;
115 608
                        n = HTTP_HDR_METHOD;
116 1919
                } else if (!strncmp(b, ":path: ", namelen)) {
117 624
                        b += namelen;
118 624
                        len -= namelen;
119 624
                        n = HTTP_HDR_URL;
120 1312
                } else if (!strncmp(b, ":scheme: ", namelen)) {
121
                        /* XXX: What to do about this one? (typically
122
                           "http" or "https"). For now set it as a normal
123
                           header, stripping the first ':'. */
124 616
                        b++;
125 616
                        len-=1;
126 616
                        n = hp->nhd;
127 688
                } else if (!strncmp(b, ":authority: ", namelen)) {
128 64
                        b+=6;
129 64
                        len-=6;
130 64
                        memcpy(b, "host", 4);
131 64
                        n = hp->nhd;
132 64
                } else {
133
                        /* Unknown pseudo-header */
134 16
                        VSLb(hp->vsl, SLT_BogoHeader,
135
                            "Unknown pseudo-header: %.*s",
136 8
                            (int)(len > 20 ? 20 : len), b);
137 8
                        return (H2SE_PROTOCOL_ERROR);   // rfc7540,l,2990,2992
138
                }
139 1911
        } else
140 264
                n = hp->nhd;
141
142 2175
        if (n < HTTP_HDR_FIRST) {
143
                /* Check for duplicate pseudo-header */
144 1231
                if (hp->hd[n].b != NULL) {
145 16
                        VSLb(hp->vsl, SLT_BogoHeader,
146
                            "Duplicate pseudo-header: %.*s",
147 8
                            (int)(len > 20 ? 20 : len), b);
148 8
                        return (H2SE_PROTOCOL_ERROR);   // rfc7540,l,3158,3162
149
                }
150 1224
        } else {
151
                /* Check for space in struct http */
152 944
                if (n >= hp->shd) {
153 0
                        VSLb(hp->vsl, SLT_LostHeader, "Too many headers: %.*s",
154 0
                            (int)(len > 20 ? 20 : len), b);
155 0
                        return (H2SE_ENHANCE_YOUR_CALM);
156
                }
157 944
                hp->nhd++;
158
        }
159
160 2167
        hp->hd[n].b = b;
161 2167
        hp->hd[n].e = b + len;
162
163 2167
        return (0);
164 2183
}
165
166
void
167 688
h2h_decode_init(const struct h2_sess *h2)
168
{
169
        struct h2h_decode *d;
170
171 688
        CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
172 688
        CHECK_OBJ_NOTNULL(h2->new_req, REQ_MAGIC);
173 688
        CHECK_OBJ_NOTNULL(h2->new_req->http, HTTP_MAGIC);
174 688
        AN(h2->decode);
175 688
        d = h2->decode;
176 688
        INIT_OBJ(d, H2H_DECODE_MAGIC);
177 688
        VHD_Init(d->vhd);
178 688
        d->out_l = WS_ReserveAll(h2->new_req->http->ws);
179
        /*
180
         * Can't do any work without any buffer
181
         * space. Require non-zero size.
182
         */
183 688
        XXXAN(d->out_l);
184 688
        d->out = h2->new_req->http->ws->f;
185 688
        d->reset = d->out;
186 688
}
187
188
/* Possible error returns:
189
 *
190
 * H2E_COMPRESSION_ERROR: Lost compression state due to incomplete header
191
 * block. This is a connection level error.
192
 *
193
 * H2E_ENHANCE_YOUR_CALM: Ran out of workspace or http header space. This
194
 * is a stream level error.
195
 */
196
h2_error
197 688
h2h_decode_fini(const struct h2_sess *h2)
198
{
199
        h2_error ret;
200
        struct h2h_decode *d;
201
202 688
        CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
203 688
        d = h2->decode;
204 688
        CHECK_OBJ_NOTNULL(h2->new_req, REQ_MAGIC);
205 688
        CHECK_OBJ_NOTNULL(d, H2H_DECODE_MAGIC);
206 688
        WS_ReleaseP(h2->new_req->http->ws, d->out);
207 688
        if (d->vhd_ret != VHD_OK) {
208
                /* HPACK header block didn't finish at an instruction
209
                   boundary */
210 112
                VSLb(h2->new_req->http->vsl, SLT_BogoHeader,
211 56
                    "HPACK compression error/fini (%s)", VHD_Error(d->vhd_ret));
212 56
                ret = H2CE_COMPRESSION_ERROR;
213 56
        } else
214 632
                ret = d->error;
215 688
        d->magic = 0;
216 688
        return (ret);
217
}
218
219
/* Possible error returns:
220
 *
221
 * H2E_COMPRESSION_ERROR: Lost compression state due to invalid header
222
 * block. This is a connection level error.
223
 *
224
 * H2E_PROTOCOL_ERROR: Malformed header or duplicate pseudo-header.
225
 */
226
h2_error
227 704
h2h_decode_bytes(struct h2_sess *h2, const uint8_t *in, size_t in_l)
228
{
229
        struct http *hp;
230
        struct h2h_decode *d;
231 704
        size_t in_u = 0;
232
233 704
        CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
234 704
        CHECK_OBJ_NOTNULL(h2->new_req, REQ_MAGIC);
235 704
        hp = h2->new_req->http;
236 704
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
237 704
        CHECK_OBJ_NOTNULL(hp->ws, WS_MAGIC);
238 704
        AN(hp->ws->r);
239 704
        d = h2->decode;
240 704
        CHECK_OBJ_NOTNULL(d, H2H_DECODE_MAGIC);
241
242
        /* Only H2E_ENHANCE_YOUR_CALM indicates that we should continue
243
           processing. Other errors should have been returned and handled
244
           by the caller. */
245 704
        assert(d->error == 0 || d->error == H2SE_ENHANCE_YOUR_CALM);
246
247 5079
        while (1) {
248 5079
                AN(d->out);
249 5080
                assert(d->out_u <= d->out_l);
250 10160
                d->vhd_ret = VHD_Decode(d->vhd, h2->dectbl, in, in_l, &in_u,
251 5080
                    d->out, d->out_l, &d->out_u);
252
253 5080
                if (d->vhd_ret < 0) {
254 32
                        VSLb(hp->vsl, SLT_BogoHeader,
255
                            "HPACK compression error (%s)",
256 16
                            VHD_Error(d->vhd_ret));
257 16
                        d->error = H2CE_COMPRESSION_ERROR;
258 16
                        break;
259 5064
                } else if (d->vhd_ret == VHD_OK || d->vhd_ret == VHD_MORE) {
260 656
                        assert(in_u == in_l);
261 656
                        break;
262
                }
263
264 4408
                if (d->error == H2SE_ENHANCE_YOUR_CALM) {
265 0
                        d->out_u = 0;
266 0
                        assert(d->out_u < d->out_l);
267 0
                        continue;
268
                }
269
270 4408
                switch (d->vhd_ret) {
271
                case VHD_NAME_SEC:
272
                        /* XXX: header flag for never-indexed header */
273
                case VHD_NAME:
274 2208
                        assert(d->namelen == 0);
275 2208
                        if (d->out_l - d->out_u < 2) {
276 0
                                d->error = H2SE_ENHANCE_YOUR_CALM;
277 0
                                break;
278
                        }
279 2208
                        d->out[d->out_u++] = ':';
280 2208
                        d->out[d->out_u++] = ' ';
281 2208
                        d->namelen = d->out_u;
282 2208
                        break;
283
284
                case VHD_VALUE_SEC:
285
                        /* XXX: header flag for never-indexed header */
286
                case VHD_VALUE:
287 2200
                        assert(d->namelen > 0);
288 2200
                        if (d->out_l - d->out_u < 1) {
289 0
                                d->error = H2SE_ENHANCE_YOUR_CALM;
290 0
                                break;
291
                        }
292 4400
                        d->error = h2h_checkhdr(hp, d->out, d->namelen,
293 2200
                            d->out_u);
294 2200
                        if (d->error)
295 16
                                break;
296 2183
                        d->error = h2h_addhdr(hp, d->out, d->namelen, d->out_u);
297 2183
                        if (d->error)
298 16
                                break;
299 2167
                        d->out[d->out_u++] = '\0'; /* Zero guard */
300 2167
                        d->out += d->out_u;
301 2167
                        d->out_l -= d->out_u;
302 2167
                        d->out_u = 0;
303 2167
                        d->namelen = 0;
304 2167
                        break;
305
306
                case VHD_BUF:
307 0
                        d->error = H2SE_ENHANCE_YOUR_CALM;
308 0
                        break;
309
310
                default:
311 0
                        WRONG("Unhandled return value");
312 0
                        break;
313
                }
314
315 4407
                if (d->error == H2SE_ENHANCE_YOUR_CALM) {
316 0
                        d->out = d->reset;
317 0
                        d->out_l = hp->ws->r - d->out;
318 0
                        d->out_u = 0;
319 0
                        assert(d->out_u < d->out_l);
320 4407
                } else if (d->error)
321 32
                        break;
322
        }
323
324 704
        if (d->error == H2SE_ENHANCE_YOUR_CALM)
325 0
                return (0); /* Stream error, delay reporting until
326
                               h2h_decode_fini so that we can process the
327
                               complete header block */
328 704
        return (d->error);
329 704
}