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 5904
h2h_checkhdr(const struct http *hp, const char *b, size_t namelen, size_t len)
42
{
43
        const char *p;
44
45 5904
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
46 5904
        AN(b);
47 5904
        assert(namelen >= 2);   /* 2 chars from the ': ' that we added */
48 5904
        assert(namelen <= len);
49
50 5904
        if (namelen == 2) {
51 0
                VSLb(hp->vsl, SLT_BogoHeader, "Empty name");
52 0
                return (H2SE_PROTOCOL_ERROR);
53
        }
54
55 81336
        for (p = b; p < b + len; p++) {
56 75480
                if (p < b + (namelen - 2)) {
57
                        /* Check valid name characters */
58 40272
                        if (p == b && *p == ':')
59 5112
                                continue; /* pseudo-header */
60 35160
                        if (isupper(*p)) {
61 24
                                VSLb(hp->vsl, SLT_BogoHeader,
62
                                    "Illegal header name (upper-case): %.*s",
63
                                    (int)(len > 20 ? 20 : len), b);
64 24
                                return (H2SE_PROTOCOL_ERROR);
65
                        }
66 35136
                        if (vct_istchar(*p)) {
67
                                /* XXX: vct should have a proper class for
68
                                   this avoiding two checks */
69 35112
                                continue;
70
                        }
71 24
                        VSLb(hp->vsl, SLT_BogoHeader,
72
                            "Illegal header name: %.*s",
73
                            (int)(len > 20 ? 20 : len), b);
74 24
                        return (H2SE_PROTOCOL_ERROR);
75 35208
                } else if (p < b + namelen) {
76
                        /* ': ' added by us */
77 11712
                        assert(*p == ':' || *p == ' ');
78
                } else {
79
                        /* Check valid value characters */
80 23496
                        if (!vct_isctl(*p) || vct_issp(*p))
81 23496
                                continue;
82 0
                        VSLb(hp->vsl, SLT_BogoHeader,
83
                            "Illegal header value: %.*s",
84
                            (int)(len > 20 ? 20 : len), b);
85 0
                        return (H2SE_PROTOCOL_ERROR);
86
                }
87
        }
88
89 5856
        return (0);
90
}
91
92
static h2_error
93 5856
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 5856
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
99 5856
        AN(b);
100 5856
        assert(namelen >= 2);   /* 2 chars from the ': ' that we added */
101 5856
        assert(namelen <= len);
102
103 5856
        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 5856
        if (b[0] == ':') {
109
                /* Match H/2 pseudo headers */
110
                /* XXX: Should probably have some include tbl for
111
                   pseudo-headers */
112 5112
                if (!strncmp(b, ":method: ", namelen)) {
113 1608
                        b += namelen;
114 1608
                        len -= namelen;
115 1608
                        n = HTTP_HDR_METHOD;
116 3504
                } else if (!strncmp(b, ":path: ", namelen)) {
117 1656
                        b += namelen;
118 1656
                        len -= namelen;
119 1656
                        n = HTTP_HDR_URL;
120 1848
                } 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 1632
                        b++;
125 1632
                        len-=1;
126 1632
                        n = hp->nhd;
127 216
                } else if (!strncmp(b, ":authority: ", namelen)) {
128 192
                        b+=6;
129 192
                        len-=6;
130 192
                        memcpy(b, "host", 4);
131 192
                        n = hp->nhd;
132
                } else {
133
                        /* Unknown pseudo-header */
134 24
                        VSLb(hp->vsl, SLT_BogoHeader,
135
                            "Unknown pseudo-header: %.*s",
136
                            (int)(len > 20 ? 20 : len), b);
137 24
                        return (H2SE_PROTOCOL_ERROR);   // rfc7540,l,2990,2992
138
                }
139
        } else
140 744
                n = hp->nhd;
141
142 5832
        if (n < HTTP_HDR_FIRST) {
143
                /* Check for duplicate pseudo-header */
144 3264
                if (n < HTTP_HDR_FIRST && hp->hd[n].b != NULL) {
145 24
                        VSLb(hp->vsl, SLT_BogoHeader,
146
                            "Duplicate pseudo-header: %.*s",
147
                            (int)(len > 20 ? 20 : len), b);
148 24
                        return (H2SE_PROTOCOL_ERROR);   // rfc7540,l,3158,3162
149
                }
150
        } else {
151
                /* Check for space in struct http */
152 2568
                if (n >= hp->shd) {
153 0
                        VSLb(hp->vsl, SLT_LostHeader, "Too many headers: %.*s",
154
                            (int)(len > 20 ? 20 : len), b);
155 0
                        return (H2SE_ENHANCE_YOUR_CALM);
156
                }
157 2568
                hp->nhd++;
158
        }
159
160 5808
        hp->hd[n].b = b;
161 5808
        hp->hd[n].e = b + len;
162
163 5808
        return (0);
164
}
165
166
void
167 1848
h2h_decode_init(const struct h2_sess *h2)
168
{
169
        struct h2h_decode *d;
170
171 1848
        CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
172 1848
        CHECK_OBJ_NOTNULL(h2->new_req, REQ_MAGIC);
173 1848
        CHECK_OBJ_NOTNULL(h2->new_req->http, HTTP_MAGIC);
174 1848
        AN(h2->decode);
175 1848
        d = h2->decode;
176 1848
        INIT_OBJ(d, H2H_DECODE_MAGIC);
177 1848
        VHD_Init(d->vhd);
178 1848
        d->out_l = WS_Reserve(h2->new_req->http->ws, 0);
179 1848
        assert(d->out_l > 0);   /* Can't do any work without any buffer
180
                                   space. Require non-zero size. */
181 1848
        d->out = h2->new_req->http->ws->f;
182 1848
        d->reset = d->out;
183 1848
}
184
185
/* Possible error returns:
186
 *
187
 * H2E_COMPRESSION_ERROR: Lost compression state due to incomplete header
188
 * block. This is a connection level error.
189
 *
190
 * H2E_ENHANCE_YOUR_CALM: Ran out of workspace or http header space. This
191
 * is a stream level error.
192
 */
193
h2_error
194 1848
h2h_decode_fini(const struct h2_sess *h2)
195
{
196
        h2_error ret;
197
        struct h2h_decode *d;
198
199 1848
        CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
200 1848
        d = h2->decode;
201 1848
        CHECK_OBJ_NOTNULL(h2->new_req, REQ_MAGIC);
202 1848
        CHECK_OBJ_NOTNULL(d, H2H_DECODE_MAGIC);
203 1848
        WS_ReleaseP(h2->new_req->http->ws, d->out);
204 1848
        if (d->vhd_ret != VHD_OK) {
205
                /* HPACK header block didn't finish at an instruction
206
                   boundary */
207 168
                VSLb(h2->new_req->http->vsl, SLT_BogoHeader,
208
                    "HPACK compression error/fini (%s)", VHD_Error(d->vhd_ret));
209 168
                ret = H2CE_COMPRESSION_ERROR;
210
        } else
211 1680
                ret = d->error;
212 1848
        d->magic = 0;
213 1848
        return (ret);
214
}
215
216
/* Possible error returns:
217
 *
218
 * H2E_COMPRESSION_ERROR: Lost compression state due to invalid header
219
 * block. This is a connection level error.
220
 *
221
 * H2E_PROTOCOL_ERROR: Malformed header or duplicate pseudo-header.
222
 */
223
h2_error
224 1896
h2h_decode_bytes(struct h2_sess *h2, const uint8_t *in, size_t in_l)
225
{
226
        struct http *hp;
227
        struct h2h_decode *d;
228 1896
        size_t in_u = 0;
229
230 1896
        CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
231 1896
        CHECK_OBJ_NOTNULL(h2->new_req, REQ_MAGIC);
232 1896
        hp = h2->new_req->http;
233 1896
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
234 1896
        CHECK_OBJ_NOTNULL(hp->ws, WS_MAGIC);
235 1896
        AN(hp->ws->r);
236 1896
        d = h2->decode;
237 1896
        CHECK_OBJ_NOTNULL(d, H2H_DECODE_MAGIC);
238
239
        /* Only H2E_ENHANCE_YOUR_CALM indicates that we should continue
240
           processing. Other errors should have been returned and handled
241
           by the caller. */
242 1896
        assert(d->error == 0 || d->error == H2SE_ENHANCE_YOUR_CALM);
243
244
        while (1) {
245 25368
                AN(d->out);
246 13632
                assert(d->out_u <= d->out_l);
247 13632
                d->vhd_ret = VHD_Decode(d->vhd, h2->dectbl, in, in_l, &in_u,
248
                    d->out, d->out_l, &d->out_u);
249
250 13632
                if (d->vhd_ret < 0) {
251 48
                        VSLb(hp->vsl, SLT_BogoHeader,
252
                            "HPACK compression error (%s)",
253
                            VHD_Error(d->vhd_ret));
254 48
                        d->error = H2CE_COMPRESSION_ERROR;
255 48
                        break;
256 13584
                } else if (d->vhd_ret == VHD_OK || d->vhd_ret == VHD_MORE) {
257 1752
                        assert(in_u == in_l);
258 1752
                        break;
259
                }
260
261 11832
                if (d->error == H2SE_ENHANCE_YOUR_CALM) {
262 0
                        d->out_u = 0;
263 0
                        assert(d->out_u < d->out_l);
264 0
                        continue;
265
                }
266
267 11832
                switch (d->vhd_ret) {
268
                case VHD_NAME_SEC:
269
                        /* XXX: header flag for never-indexed header */
270
                case VHD_NAME:
271 5928
                        assert(d->namelen == 0);
272 5928
                        if (d->out_l - d->out_u < 2) {
273 0
                                d->error = H2SE_ENHANCE_YOUR_CALM;
274 0
                                break;
275
                        }
276 5928
                        d->out[d->out_u++] = ':';
277 5928
                        d->out[d->out_u++] = ' ';
278 5928
                        d->namelen = d->out_u;
279 5928
                        break;
280
281
                case VHD_VALUE_SEC:
282
                        /* XXX: header flag for never-indexed header */
283
                case VHD_VALUE:
284 5904
                        assert(d->namelen > 0);
285 5904
                        if (d->out_l - d->out_u < 1) {
286 0
                                d->error = H2SE_ENHANCE_YOUR_CALM;
287 0
                                break;
288
                        }
289 5904
                        d->error = h2h_checkhdr(hp, d->out, d->namelen,
290
                            d->out_u);
291 5904
                        if (d->error)
292 48
                                break;
293 5856
                        d->error = h2h_addhdr(hp, d->out, d->namelen, d->out_u);
294 5856
                        if (d->error)
295 48
                                break;
296 5808
                        d->out[d->out_u++] = '\0'; /* Zero guard */
297 5808
                        d->out += d->out_u;
298 5808
                        d->out_l -= d->out_u;
299 5808
                        d->out_u = 0;
300 5808
                        d->namelen = 0;
301 5808
                        break;
302
303
                case VHD_BUF:
304 0
                        d->error = H2SE_ENHANCE_YOUR_CALM;
305 0
                        break;
306
307
                default:
308 0
                        WRONG("Unhandled return value");
309
                        break;
310
                }
311
312 11832
                if (d->error == H2SE_ENHANCE_YOUR_CALM) {
313 0
                        d->out = d->reset;
314 0
                        d->out_l = hp->ws->r - d->out;
315 0
                        d->out_u = 0;
316 0
                        assert(d->out_u < d->out_l);
317 11832
                } else if (d->error)
318 96
                        break;
319
        }
320
321 1896
        if (d->error == H2SE_ENHANCE_YOUR_CALM)
322 0
                return (0); /* Stream error, delay reporting until
323
                               h2h_decode_fini so that we can process the
324
                               complete header block */
325 1896
        return (d->error);
326
}