varnish-cache/bin/varnishd/http2/cache_http2_hpack.c
0
/*-
1
 * Copyright (c) 2016 Varnish Software AS
2
 * All rights reserved.
3
 *
4
 * Author: Martin Blix Grydeland <martin@varnish-software.com>
5
 *
6
 * SPDX-License-Identifier: BSD-2-Clause
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 *
29
 */
30
31
#include "config.h"
32
33
#include "cache/cache_varnishd.h"
34
35
#include <ctype.h>
36
#include <stdio.h>
37
38
#include "http2/cache_http2.h"
39
#include "vct.h"
40
41
// rfc9113,l,2493,2528
42
static h2_error
43 11400
h2h_checkhdr(const struct http *hp, const char *b, size_t namelen, size_t len)
44
{
45
        const char *p;
46
        enum {
47
                FLD_NAME_FIRST,
48
                FLD_NAME,
49
                FLD_VALUE_FIRST,
50
                FLD_VALUE
51
        } state;
52
53 11400
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
54 11400
        AN(b);
55 11400
        assert(namelen >= 2);   /* 2 chars from the ': ' that we added */
56 11400
        assert(namelen <= len);
57 11400
        assert(b[namelen - 2] == ':');
58 11400
        assert(b[namelen - 1] == ' ');
59
60 11400
        if (namelen == 2) {
61 0
                VSLb(hp->vsl, SLT_BogoHeader, "Empty name");
62 0
                return (H2SE_PROTOCOL_ERROR);
63
        }
64
65
        // VSLb(hp->vsl, SLT_Debug, "CHDR [%.*s] [%.*s]",
66
        //     (int)namelen, b, (int)(len - namelen), b + namelen);
67
68 11400
        state = FLD_NAME_FIRST;
69 88975
        for (p = b; p < b + namelen - 2; p++) {
70 77675
                switch(state) {
71
                case FLD_NAME_FIRST:
72 11400
                        state = FLD_NAME;
73 11400
                        if (*p == ':')
74 9700
                                break;
75
                        /* FALL_THROUGH */
76
                case FLD_NAME:
77 67975
                        if (isupper(*p)) {
78 50
                                VSLb(hp->vsl, SLT_BogoHeader,
79
                                    "Illegal field header name (upper-case): %.*s",
80 25
                                    (int)(len > 20 ? 20 : len), b);
81 25
                                return (H2SE_PROTOCOL_ERROR);
82
                        }
83 67950
                        if (!vct_istchar(*p) || *p == ':') {
84 150
                                VSLb(hp->vsl, SLT_BogoHeader,
85
                                    "Illegal field header name (non-token): %.*s",
86 75
                                    (int)(len > 20 ? 20 : len), b);
87 75
                                return (H2SE_PROTOCOL_ERROR);
88
                        }
89 67875
                        break;
90
                default:
91 0
                        WRONG("http2 field name validation state");
92 0
                }
93 77575
        }
94
95 11300
        state = FLD_VALUE_FIRST;
96 56000
        for (p = b + namelen; p < b + len; p++) {
97 44950
                switch(state) {
98
                case FLD_VALUE_FIRST:
99 11125
                        if (vct_issp(*p)) {
100 450
                                VSLb(hp->vsl, SLT_BogoHeader,
101
                                    "Illegal field value start %.*s",
102 225
                                    (int)(len > 20 ? 20 : len), b);
103 225
                                return (H2SE_PROTOCOL_ERROR);
104
                        }
105 10900
                        state = FLD_VALUE;
106
                        /* FALL_THROUGH */
107
                case FLD_VALUE:
108 44725
                        if (!vct_ishdrval(*p)) {
109 50
                                VSLb(hp->vsl, SLT_BogoHeader,
110
                                    "Illegal field value %.*s",
111 25
                                    (int)(len > 20 ? 20 : len), b);
112 25
                                return (H2SE_PROTOCOL_ERROR);
113
                        }
114 44700
                        break;
115
                default:
116 0
                        WRONG("http2 field value validation state");
117 0
                }
118 44700
        }
119 11050
        if (state == FLD_VALUE && vct_issp(b[len - 1])) {
120 100
                VSLb(hp->vsl, SLT_BogoHeader,
121
                    "Illegal field value (end) %.*s",
122 50
                    (int)(len > 20 ? 20 : len), b);
123 50
                return (H2SE_PROTOCOL_ERROR);
124
        }
125 11000
        return (0);
126 11400
}
127
128
static h2_error
129 11000
h2h_addhdr(struct h2h_decode *d, struct http *hp, char *b, size_t namelen,
130
    size_t len)
131
{
132
        /* XXX: This might belong in cache/cache_http.c */
133
        const char *b0;
134
        int disallow_empty;
135
        unsigned n;
136
        char *p;
137
        unsigned u;
138
139 11000
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
140 11000
        AN(b);
141 11000
        assert(namelen >= 2);   /* 2 chars from the ': ' that we added */
142 11000
        assert(namelen <= len);
143
144 11000
        disallow_empty = 0;
145
146 11000
        if (len > UINT_MAX) {   /* XXX: cache_param max header size */
147 0
                VSLb(hp->vsl, SLT_BogoHeader, "Header too large: %.20s", b);
148 0
                return (H2SE_ENHANCE_YOUR_CALM);
149
        }
150
151 11000
        b0 = b;
152 11000
        if (b[0] == ':') {
153
                /* Match H/2 pseudo headers */
154
                /* XXX: Should probably have some include tbl for
155
                   pseudo-headers */
156 9550
                if (!strncmp(b, ":method: ", namelen)) {
157 3000
                        b += namelen;
158 3000
                        len -= namelen;
159 3000
                        n = HTTP_HDR_METHOD;
160 3000
                        disallow_empty = 1;
161
162
                        /* First field cannot contain SP or CTL */
163 12750
                        for (p = b, u = 0; u < len; p++, u++) {
164 9750
                                if (vct_issp(*p) || vct_isctl(*p))
165 0
                                        return (H2SE_PROTOCOL_ERROR);
166 9750
                        }
167 9550
                } else if (!strncmp(b, ":path: ", namelen)) {
168 3100
                        b += namelen;
169 3100
                        len -= namelen;
170 3100
                        n = HTTP_HDR_URL;
171 3100
                        disallow_empty = 1;
172
173
                        // rfc9113,l,2693,2705
174 3100
                        if (len > 0 && *b != '/' &&
175 150
                            strncmp(b, "*", len) != 0) {
176 100
                                VSLb(hp->vsl, SLT_BogoHeader,
177
                                    "Illegal :path pseudo-header %.*s",
178 50
                                    (int)len, b);
179 50
                                return (H2SE_PROTOCOL_ERROR);
180
                        }
181
182
                        /* Second field cannot contain LWS or CTL */
183 9600
                        for (p = b, u = 0; u < len; p++, u++) {
184 6550
                                if (vct_islws(*p) || vct_isctl(*p))
185 0
                                        return (H2SE_PROTOCOL_ERROR);
186 6550
                        }
187 6500
                } else if (!strncmp(b, ":scheme: ", namelen)) {
188
                        /* XXX: What to do about this one? (typically
189
                           "http" or "https"). For now set it as a normal
190
                           header, stripping the first ':'. */
191 3025
                        if (d->has_scheme) {
192 50
                                VSLb(hp->vsl, SLT_BogoHeader,
193
                                    "Duplicate pseudo-header %.*s%.*s",
194 25
                                    (int)namelen, b0,
195 25
                                    (int)(len > 20 ? 20 : len), b);
196 25
                                return (H2SE_PROTOCOL_ERROR);
197
                        }
198
199 3000
                        b++;
200 3000
                        len-=1;
201 3000
                        n = hp->nhd;
202 3000
                        d->has_scheme = 1;
203
204 11850
                        for (p = b + namelen, u = 0; u < len-namelen;
205 8850
                            p++, u++) {
206 8900
                                if (vct_issp(*p) || vct_isctl(*p))
207 50
                                        return (H2SE_PROTOCOL_ERROR);
208 8850
                        }
209
210 2950
                        if (!u)
211 0
                                return (H2SE_PROTOCOL_ERROR);
212 3375
                } else if (!strncmp(b, ":authority: ", namelen)) {
213 375
                        b+=6;
214 375
                        len-=6;
215 375
                        memcpy(b, "host", 4);
216 375
                        n = hp->nhd;
217 375
                } else {
218
                        /* Unknown pseudo-header */
219 100
                        VSLb(hp->vsl, SLT_BogoHeader,
220
                            "Unknown pseudo-header: %.*s",
221 50
                            (int)(len > 20 ? 20 : len), b);
222 50
                        return (H2SE_PROTOCOL_ERROR);   // rfc7540,l,2990,2992
223
                }
224 9375
        } else
225 1450
                n = hp->nhd;
226
227 10825
        if (n < HTTP_HDR_FIRST) {
228
                /* Check for duplicate pseudo-header */
229 6050
                if (hp->hd[n].b != NULL) {
230 150
                        VSLb(hp->vsl, SLT_BogoHeader,
231
                            "Duplicate pseudo-header %.*s%.*s",
232 75
                            (int)namelen, b0, (int)(len > 20 ? 20 : len), b);
233 75
                        return (H2SE_PROTOCOL_ERROR);   // rfc7540,l,3158,3162
234
                }
235 5975
        } else {
236
                /* Check for space in struct http */
237 4775
                if (n >= hp->shd) {
238 0
                        VSLb(hp->vsl, SLT_LostHeader, "Too many headers: %.*s",
239 0
                            (int)(len > 20 ? 20 : len), b);
240 0
                        return (H2SE_ENHANCE_YOUR_CALM);
241
                }
242 4775
                hp->nhd++;
243
        }
244
245 10750
        hp->hd[n].b = b;
246 10750
        hp->hd[n].e = b + len;
247
248 10750
        if (disallow_empty && !Tlen(hp->hd[n])) {
249 200
                VSLb(hp->vsl, SLT_BogoHeader,
250
                    "Empty pseudo-header %.*s",
251 100
                    (int)namelen, b0);
252 100
                return (H2SE_PROTOCOL_ERROR);
253
        }
254
255 10650
        return (0);
256 11000
}
257
258
void
259 3800
h2h_decode_init(const struct h2_sess *h2)
260
{
261
        struct h2h_decode *d;
262
263 3800
        CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
264 3800
        CHECK_OBJ_NOTNULL(h2->new_req, REQ_MAGIC);
265 3800
        CHECK_OBJ_NOTNULL(h2->new_req->http, HTTP_MAGIC);
266 3800
        AN(h2->decode);
267 3800
        d = h2->decode;
268 3800
        INIT_OBJ(d, H2H_DECODE_MAGIC);
269 3800
        VHD_Init(d->vhd);
270 3800
        d->out_l = WS_ReserveAll(h2->new_req->http->ws);
271
        /*
272
         * Can't do any work without any buffer
273
         * space. Require non-zero size.
274
         */
275 3800
        XXXAN(d->out_l);
276 3800
        d->out = WS_Reservation(h2->new_req->http->ws);
277 3800
        d->reset = d->out;
278 3800
}
279
280
/* Possible error returns:
281
 *
282
 * H2E_COMPRESSION_ERROR: Lost compression state due to incomplete header
283
 * block. This is a connection level error.
284
 *
285
 * H2E_ENHANCE_YOUR_CALM: Ran out of workspace or http header space. This
286
 * is a stream level error.
287
 */
288
h2_error
289 3800
h2h_decode_fini(const struct h2_sess *h2)
290
{
291
        h2_error ret;
292
        struct h2h_decode *d;
293
294 3800
        CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
295 3800
        d = h2->decode;
296 3800
        CHECK_OBJ_NOTNULL(h2->new_req, REQ_MAGIC);
297 3800
        CHECK_OBJ_NOTNULL(d, H2H_DECODE_MAGIC);
298 3800
        WS_ReleaseP(h2->new_req->http->ws, d->out);
299 3800
        if (d->vhd_ret != VHD_OK) {
300
                /* HPACK header block didn't finish at an instruction
301
                   boundary */
302 1650
                VSLb(h2->new_req->http->vsl, SLT_BogoHeader,
303 825
                    "HPACK compression error/fini (%s)", VHD_Error(d->vhd_ret));
304 825
                ret = H2CE_COMPRESSION_ERROR;
305 3800
        } else if (d->error == NULL && !d->has_scheme) {
306 100
                VSLb(h2->vsl, SLT_Debug, "Missing :scheme");
307 100
                ret = H2SE_MISSING_SCHEME; //rfc7540,l,3087,3090
308 100
        } else
309 2875
                ret = d->error;
310 3800
        FINI_OBJ(d);
311 3800
        return (ret);
312
}
313
314
/* Possible error returns:
315
 *
316
 * H2E_COMPRESSION_ERROR: Lost compression state due to invalid header
317
 * block. This is a connection level error.
318
 *
319
 * H2E_PROTOCOL_ERROR: Malformed header or duplicate pseudo-header.
320
 *                     Violation of field name/value charsets
321
 */
322
h2_error
323 3850
h2h_decode_bytes(struct h2_sess *h2, const uint8_t *in, size_t in_l)
324
{
325
        struct http *hp;
326
        struct h2h_decode *d;
327 3850
        size_t in_u = 0;
328
        const char *r, *e;
329
330 3850
        CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
331 3850
        CHECK_OBJ_NOTNULL(h2->new_req, REQ_MAGIC);
332 3850
        hp = h2->new_req->http;
333 3850
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
334 3850
        CHECK_OBJ_NOTNULL(hp->ws, WS_MAGIC);
335 3850
        r = WS_Reservation(hp->ws);
336 3850
        AN(r);
337 3850
        e = r + WS_ReservationSize(hp->ws);
338 3850
        d = h2->decode;
339 3850
        CHECK_OBJ_NOTNULL(d, H2H_DECODE_MAGIC);
340
341
        /* Only H2E_ENHANCE_YOUR_CALM indicates that we should continue
342
           processing. Other errors should have been returned and handled
343
           by the caller. */
344 3850
        assert(d->error == 0 || d->error == H2SE_ENHANCE_YOUR_CALM);
345
346 25925
        while (1) {
347 25925
                AN(d->out);
348 25925
                assert(d->out_u <= d->out_l);
349 51850
                d->vhd_ret = VHD_Decode(d->vhd, h2->dectbl, in, in_l, &in_u,
350 25925
                    d->out, d->out_l, &d->out_u);
351
352 25925
                if (d->vhd_ret < 0) {
353 100
                        VSLb(hp->vsl, SLT_BogoHeader,
354
                            "HPACK compression error (%s)",
355 50
                            VHD_Error(d->vhd_ret));
356 50
                        d->error = H2CE_COMPRESSION_ERROR;
357 50
                        break;
358 25875
                } else if (d->vhd_ret == VHD_OK || d->vhd_ret == VHD_MORE) {
359 3050
                        assert(in_u == in_l);
360 3050
                        break;
361
                }
362
363 22825
                if (d->error == H2SE_ENHANCE_YOUR_CALM) {
364 0
                        d->out_u = 0;
365 0
                        assert(d->out_u < d->out_l);
366 0
                        continue;
367
                }
368
369 22825
                switch (d->vhd_ret) {
370
                case VHD_NAME_SEC:
371
                        /* XXX: header flag for never-indexed header */
372
                case VHD_NAME:
373 11425
                        assert(d->namelen == 0);
374 11425
                        if (d->out_l - d->out_u < 2) {
375 0
                                d->error = H2SE_ENHANCE_YOUR_CALM;
376 0
                                break;
377
                        }
378 11425
                        d->out[d->out_u++] = ':';
379 11425
                        d->out[d->out_u++] = ' ';
380 11425
                        d->namelen = d->out_u;
381 11425
                        break;
382
383
                case VHD_VALUE_SEC:
384
                        /* XXX: header flag for never-indexed header */
385
                case VHD_VALUE:
386 11400
                        assert(d->namelen > 0);
387 11400
                        if (d->out_l - d->out_u < 1) {
388 0
                                d->error = H2SE_ENHANCE_YOUR_CALM;
389 0
                                break;
390
                        }
391 22800
                        d->error = h2h_checkhdr(hp, d->out, d->namelen,
392 11400
                            d->out_u);
393 11400
                        if (d->error)
394 400
                                break;
395 22000
                        d->error = h2h_addhdr(d, hp, d->out,
396 11000
                            d->namelen, d->out_u);
397 11000
                        if (d->error)
398 350
                                break;
399 10650
                        d->out[d->out_u++] = '\0'; /* Zero guard */
400 10650
                        d->out += d->out_u;
401 10650
                        d->out_l -= d->out_u;
402 10650
                        d->out_u = 0;
403 10650
                        d->namelen = 0;
404 10650
                        break;
405
406
                case VHD_BUF:
407 0
                        d->error = H2SE_ENHANCE_YOUR_CALM;
408 0
                        break;
409
410
                default:
411 0
                        WRONG("Unhandled return value");
412 0
                        break;
413
                }
414
415 22825
                if (d->error == H2SE_ENHANCE_YOUR_CALM) {
416 0
                        d->out = d->reset;
417 0
                        d->out_l = e - d->out;
418 0
                        d->out_u = 0;
419 0
                        assert(d->out_l > 0);
420 22825
                } else if (d->error)
421 750
                        break;
422
        }
423
424 3850
        if (d->error == H2SE_ENHANCE_YOUR_CALM)
425 0
                return (0); /* Stream error, delay reporting until
426
                               h2h_decode_fini so that we can process the
427
                               complete header block */
428 3850
        return (d->error);
429 3850
}