varnish-cache/bin/varnishd/http2/cache_http2_session.c
0
/*-
1
 * Copyright (c) 2016 Varnish Software AS
2
 * All rights reserved.
3
 *
4
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
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 <stdio.h>
36
37
#include "cache/cache_transport.h"
38
#include "http2/cache_http2.h"
39
40
#include "vend.h"
41
#include "vtcp.h"
42 6750
43
static const char h2_resp_101[] =
44
        "HTTP/1.1 101 Switching Protocols\r\n"
45
        "Connection: Upgrade\r\n"
46
        "Upgrade: h2c\r\n"
47
        "\r\n";
48
49
static const char H2_prism[24] = {
50
        0x50, 0x52, 0x49, 0x20, 0x2a, 0x20, 0x48, 0x54,
51
        0x54, 0x50, 0x2f, 0x32, 0x2e, 0x30, 0x0d, 0x0a,
52
        0x0d, 0x0a, 0x53, 0x4d, 0x0d, 0x0a, 0x0d, 0x0a
53 3325
};
54
55
static size_t
56 3325
h2_enc_settings(const struct h2_settings *h2s, uint8_t *buf, ssize_t n)
57
{
58 3325
        uint8_t *p = buf;
59
60
#define H2_SETTING(U,l,v,d,...)                         \
61
        if (h2s->l != d) {                              \
62
                n -= 6;                                 \
63
                assert(n >= 0);                         \
64 6750
                vbe16enc(p, v);                         \
65
                p += 2;                                 \
66
                vbe32enc(p, h2s->l);                    \
67
                p += 4;                                 \
68
        }
69
#include "tbl/h2_settings.h"
70 3325
        return (p - buf);
71
}
72
73
static const struct h2_settings H2_proto_settings = {
74 6750
#define H2_SETTING(U,l,v,d,...) . l = d,
75
#include "tbl/h2_settings.h"
76
};
77
78
static void
79 3425
h2_local_settings(struct h2_settings *h2s)
80
{
81 3425
        *h2s = H2_proto_settings;
82
#define H2_SETTINGS_PARAM_ONLY
83
#define H2_SETTING(U, l, ...)                   \
84 6750
        h2s->l = cache_param->h2_##l;
85
#include "tbl/h2_settings.h"
86
#undef H2_SETTINGS_PARAM_ONLY
87 3425
}
88
89
/**********************************************************************
90
 * The h2_sess struct needs many of the same things as a request,
91
 * WS, VSL, HTC &c,  but rather than implement all that stuff over, we
92
 * grab an actual struct req, and mirror the relevant fields into
93
 * struct h2_sess.
94 6750
 */
95
96
static struct h2_sess *
97 3425
h2_init_sess(struct sess *sp,
98
    struct h2_sess *h2s, struct req *srq, struct h2h_decode *decode)
99
{
100
        uintptr_t *up;
101
        struct h2_sess *h2;
102
103
        /* proto_priv session attribute will always have been set up by H1
104
         * before reaching here. */
105 3425
        AZ(SES_Get_proto_priv(sp, &up));
106 3425
        assert(*up == 0);
107
108 3425
        if (srq == NULL)
109 150
                srq = Req_New(sp);
110 3425
        AN(srq);
111 3425
        h2 = h2s;
112 3425
        AN(h2);
113 3425
        INIT_OBJ(h2, H2_SESS_MAGIC);
114 3425
        h2->srq = srq;
115 3425
        h2->htc = srq->htc;
116 3425
        h2->ws = srq->ws;
117 3425
        h2->vsl = srq->vsl;
118 3425
        VSL_Flush(h2->vsl, 0);
119 3425
        h2->vsl->wid = sp->vxid;
120 3425
        h2->htc->rfd = &sp->fd;
121 3425
        h2->sess = sp;
122 3425
        h2->rxthr = pthread_self();
123 3425
        PTOK(pthread_cond_init(h2->winupd_cond, NULL));
124 3425
        VTAILQ_INIT(&h2->streams);
125 3425
        VTAILQ_INIT(&h2->txqueue);
126 3425
        h2_local_settings(&h2->local_settings);
127 3425
        h2->remote_settings = H2_proto_settings;
128 3425
        h2->decode = decode;
129
130 3425
        h2->rapid_reset = cache_param->h2_rapid_reset;
131 3425
        h2->rapid_reset_limit = cache_param->h2_rapid_reset_limit;
132 3425
        h2->rapid_reset_period = cache_param->h2_rapid_reset_period;
133
134 3425
        h2->rst_budget = h2->rapid_reset_limit;
135 3425
        h2->last_rst = sp->t_open;
136 3425
        AZ(isnan(h2->last_rst));
137
138 3425
        AZ(VHT_Init(h2->dectbl, h2->local_settings.header_table_size));
139
140 3425
        *up = (uintptr_t)h2;
141
142 3425
        return (h2);
143
}
144
145
static void
146 3217
h2_del_sess(struct worker *wrk, struct h2_sess *h2, stream_close_t reason)
147
{
148
        struct sess *sp;
149
        struct req *req;
150
151 3217
        CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
152 3217
        AZ(h2->refcnt);
153 3217
        assert(VTAILQ_EMPTY(&h2->streams));
154 3217
        AN(reason);
155
156 3217
        VHT_Fini(h2->dectbl);
157 3217
        PTOK(pthread_cond_destroy(h2->winupd_cond));
158 3217
        TAKE_OBJ_NOTNULL(req, &h2->srq, REQ_MAGIC);
159 3217
        assert(!WS_IsReserved(req->ws));
160 3217
        sp = h2->sess;
161 3217
        Req_Cleanup(sp, wrk, req);
162 3217
        Req_Release(req);
163 3217
        SES_Delete(sp, reason, NAN);
164 3217
}
165
166
/**********************************************************************/
167
168
enum htc_status_e v_matchproto_(htc_complete_f)
169 220775
H2_prism_complete(struct http_conn *htc)
170
{
171
        size_t sz;
172
173 220775
        CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
174 220775
        sz = sizeof(H2_prism);
175 220775
        if (htc->rxbuf_b + sz > htc->rxbuf_e)
176 4749
                sz = htc->rxbuf_e - htc->rxbuf_b;
177 220775
        if (memcmp(htc->rxbuf_b, H2_prism, sz))
178 207226
                return (HTC_S_JUNK);
179 13549
        return (sz == sizeof(H2_prism) ? HTC_S_COMPLETE : HTC_S_MORE);
180 220775
}
181
182
183
/**********************************************************************
184
 * Deal with the base64url (NB: ...url!) encoded SETTINGS in the H1 req
185
 * of a H2C upgrade.
186
 */
187
188
static int
189 150
h2_b64url_settings(struct h2_sess *h2, struct req *req)
190
{
191
        const char *p, *q;
192
        uint8_t u[6], *up;
193
        unsigned x;
194
        int i, n;
195
        static const char s[] =
196
            "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
197
            "abcdefghijklmnopqrstuvwxyz"
198
            "0123456789"
199
            "-_=";
200
201
        /*
202
         * If there is trouble with this, we could reject the upgrade
203
         * but putting this on the H1 side is just plain wrong...
204
         */
205 150
        if (!http_GetHdr(req->http, H_HTTP2_Settings, &p))
206 25
                return (-1);
207 125
        AN(p);
208 125
        VSLb(req->vsl, SLT_Debug, "H2CS %s", p);
209
210 125
        n = 0;
211 125
        x = 0;
212 125
        up = u;
213 1725
        for (;*p; p++) {
214 1625
                q = strchr(s, *p);
215 1625
                if (q == NULL)
216 25
                        return (-1);
217 1600
                i = q - s;
218 1600
                assert(i >= 0 && i <= 64);
219 1600
                x <<= 6;
220 1600
                x |= i;
221 1600
                n += 6;
222 1600
                if (n < 8)
223 400
                        continue;
224 1200
                *up++ = (uint8_t)(x >> (n - 8));
225 1200
                n -= 8;
226 1200
                if (up == u + sizeof u) {
227 200
                        AZ(n);
228 200
                        if (h2_set_setting(h2, (void*)u))
229 0
                                return (-1);
230 200
                        up = u;
231 200
                }
232 1200
        }
233 100
        if (up != u)
234 0
                return (-1);
235 100
        return (0);
236 150
}
237
238
239
/**********************************************************************/
240
241
static int
242 50
h2_ou_rel(struct worker *wrk, struct req *req)
243
{
244 50
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
245 50
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
246 50
        AZ(req->vcl);
247 50
        Req_AcctLogCharge(wrk->stats, req);
248 50
        Req_Release(req);
249 50
        return (0);
250
}
251
252
static int
253 150
h2_ou_session(struct worker *wrk, struct h2_sess *h2,
254
    struct req *req)
255
{
256
        ssize_t sz;
257
        enum htc_status_e hs;
258
        struct h2_req *r2;
259
260 150
        if (h2_b64url_settings(h2, req)) {
261 50
                VSLb(h2->vsl, SLT_Debug, "H2: Bad HTTP-Settings");
262 50
                return (h2_ou_rel(wrk, req));
263
        }
264
265 100
        sz = write(h2->sess->fd, h2_resp_101, strlen(h2_resp_101));
266 100
        VTCP_Assert(sz);
267 100
        if (sz != strlen(h2_resp_101)) {
268 0
                VSLb(h2->vsl, SLT_Debug, "H2: Upgrade: Error writing 101"
269 0
                    " response: %s\n", VAS_errtxt(errno));
270 0
                return (h2_ou_rel(wrk, req));
271
        }
272
273 100
        http_Unset(req->http, H_Upgrade);
274 100
        http_Unset(req->http, H_HTTP2_Settings);
275
276
        /* Steal pipelined read-ahead, if any */
277 100
        h2->htc->pipeline_b = req->htc->pipeline_b;
278 100
        h2->htc->pipeline_e = req->htc->pipeline_e;
279 100
        req->htc->pipeline_b = NULL;
280 100
        req->htc->pipeline_e = NULL;
281
        /* XXX: This call may assert on buffer overflow if the pipelined
282
           data exceeds the available space in the ws workspace. What to
283
           do about the overflowing data is an open issue. */
284 100
        HTC_RxInit(h2->htc, h2->ws);
285
286
        /* Start req thread */
287 100
        r2 = h2_new_req(h2, 1, req);
288 100
        req->transport = &HTTP2_transport;
289 100
        assert(req->req_step == R_STP_TRANSPORT);
290 100
        req->task->func = h2_do_req;
291 100
        req->task->priv = req;
292 100
        r2->scheduled = 1;
293 100
        r2->state = H2_S_CLOS_REM; // rfc7540,l,489,491
294 100
        req->err_code = 0;
295 100
        http_SetH(req->http, HTTP_HDR_PROTO, "HTTP/2.0");
296
297
        /* Wait for PRISM response */
298 200
        hs = HTC_RxStuff(h2->htc, H2_prism_complete,
299 100
            NULL, NULL, NAN, h2->sess->t_idle + cache_param->timeout_idle, NAN,
300
            sizeof H2_prism);
301 100
        if (hs != HTC_S_COMPLETE) {
302 25
                VSLb(h2->vsl, SLT_Debug, "H2: No/Bad OU PRISM (hs=%d)", hs);
303 25
                r2->scheduled = 0;
304 25
                h2_del_req(wrk, r2);
305 25
                return (0);
306
        }
307 75
        if (Pool_Task(wrk->pool, req->task, TASK_QUEUE_REQ)) {
308 25
                r2->scheduled = 0;
309 25
                h2_del_req(wrk, r2);
310 25
                VSLb(h2->vsl, SLT_Debug, "H2: No Worker-threads");
311 25
                return (0);
312
        }
313 50
        return (1);
314 150
}
315
316
/**********************************************************************
317
 */
318
319
#define H2_PU_MARKER    1
320
#define H2_OU_MARKER    2
321
322
void
323 3275
H2_PU_Sess(struct worker *wrk, struct sess *sp, struct req *req)
324
{
325 3275
        VSLb(req->vsl, SLT_Debug, "H2 Prior Knowledge Upgrade");
326 3275
        req->err_code = H2_PU_MARKER;
327 3275
        SES_SetTransport(wrk, sp, req, &HTTP2_transport);
328 3275
}
329
330
void
331 150
H2_OU_Sess(struct worker *wrk, struct sess *sp, struct req *req)
332
{
333 150
        VSLb(req->vsl, SLT_Debug, "H2 Optimistic Upgrade");
334 150
        req->err_code = H2_OU_MARKER;
335 150
        SES_SetTransport(wrk, sp, req, &HTTP2_transport);
336 150
}
337
338
static void v_matchproto_(task_func_t)
339 3425
h2_new_session(struct worker *wrk, void *arg)
340
{
341
        struct req *req;
342
        struct sess *sp;
343
        struct h2_sess h2s;
344
        struct h2_sess *h2;
345
        struct h2_req *r2, *r22;
346
        int again;
347
        uint8_t settings[48];
348
        struct h2h_decode decode;
349
        size_t l;
350
351 3425
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
352 3425
        CAST_OBJ_NOTNULL(req, arg, REQ_MAGIC);
353 3425
        sp = req->sp;
354 3425
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
355
356 3425
        if (wrk->wpriv->vcl)
357 412
                VCL_Rel(&wrk->wpriv->vcl);
358
359 3425
        assert(req->transport == &HTTP2_transport);
360
361 3425
        assert (req->err_code == H2_PU_MARKER || req->err_code == H2_OU_MARKER);
362
363 6850
        h2 = h2_init_sess(sp, &h2s,
364 3425
            req->err_code == H2_PU_MARKER ? req : NULL, &decode);
365 3425
        h2->req0 = h2_new_req(h2, 0, NULL);
366 3425
        AZ(h2->htc->priv);
367 3425
        h2->htc->priv = h2;
368
369 3425
        AZ(wrk->vsl);
370 3425
        wrk->vsl = h2->vsl;
371
372 3425
        if (req->err_code == H2_OU_MARKER && !h2_ou_session(wrk, h2, req)) {
373 100
                assert(h2->refcnt == 1);
374 100
                h2_del_req(wrk, h2->req0);
375 100
                h2_del_sess(wrk, h2, SC_RX_JUNK);
376 100
                wrk->vsl = NULL;
377 100
                return;
378
        }
379 3325
        assert(HTC_S_COMPLETE == H2_prism_complete(h2->htc));
380 3325
        HTC_RxPipeline(h2->htc, h2->htc->rxbuf_b + sizeof(H2_prism));
381 3325
        HTC_RxInit(h2->htc, h2->ws);
382 3325
        AN(WS_Reservation(h2->ws));
383 3325
        VSLb(h2->vsl, SLT_Debug, "H2: Got pu PRISM");
384
385 3325
        THR_SetRequest(h2->srq);
386 3325
        AN(WS_Reservation(h2->ws));
387
388 3325
        l = h2_enc_settings(&h2->local_settings, settings, sizeof (settings));
389 3325
        AN(WS_Reservation(h2->ws));
390 3325
        H2_Send_Get(wrk, h2, h2->req0);
391 3325
        AN(WS_Reservation(h2->ws));
392 6650
        H2_Send_Frame(wrk, h2,
393 3325
            H2_F_SETTINGS, H2FF_NONE, l, 0, settings);
394 3325
        AN(WS_Reservation(h2->ws));
395 3325
        H2_Send_Rel(h2, h2->req0);
396 3325
        AN(WS_Reservation(h2->ws));
397
398
        /* and off we go... */
399 3325
        h2->cond = &wrk->cond;
400
401 22612
        while (h2_rxframe(wrk, h2)) {
402 19287
                HTC_RxInit(h2->htc, h2->ws);
403 19287
                if (WS_Overflowed(h2->ws)) {
404 0
                        VSLb(h2->vsl, SLT_Debug, "H2: Empty Rx Workspace");
405 0
                        h2->error = H2CE_INTERNAL_ERROR;
406 0
                        break;
407
                }
408 19287
                AN(WS_Reservation(h2->ws));
409
        }
410
411 3325
        AN(h2->error);
412
413
        /* Delete all idle streams */
414 3325
        VSLb(h2->vsl, SLT_Debug, "H2 CLEANUP %s", h2->error->name);
415 3325
        Lck_Lock(&h2->sess->mtx);
416 8949
        VTAILQ_FOREACH(r2, &h2->streams, list) {
417 5624
                if (r2->error == 0)
418 5149
                        r2->error = h2->error;
419 5624
                if (r2->cond != NULL)
420 100
                        PTOK(pthread_cond_signal(r2->cond));
421 5624
        }
422 3325
        PTOK(pthread_cond_broadcast(h2->winupd_cond));
423 3325
        Lck_Unlock(&h2->sess->mtx);
424 5611
        while (1) {
425 5611
                again = 0;
426 14350
                VTAILQ_FOREACH_SAFE(r2, &h2->streams, list, r22) {
427 8739
                        if (r2 != h2->req0) {
428 3336
                                h2_kill_req(wrk, h2, r2, h2->error);
429 3336
                                again++;
430 3336
                        }
431 8739
                }
432 5611
                if (!again)
433 3325
                        break;
434 2286
                Lck_Lock(&h2->sess->mtx);
435 5584
                VTAILQ_FOREACH(r2, &h2->streams, list)
436 6596
                        VSLb(h2->vsl, SLT_Debug, "ST %u %d",
437 3298
                            r2->stream, r2->state);
438 2286
                (void)Lck_CondWaitTimeout(h2->cond, &h2->sess->mtx, .1);
439 2286
                Lck_Unlock(&h2->sess->mtx);
440
        }
441 3325
        h2->cond = NULL;
442 3325
        assert(h2->refcnt == 1);
443 3325
        h2_del_req(wrk, h2->req0);
444 3325
        h2_del_sess(wrk, h2, h2->error->reason);
445 3325
        wrk->vsl = NULL;
446 3425
}
447
448
static int v_matchproto_(vtr_poll_f)
449 9299
h2_poll(struct req *req)
450
{
451
        struct h2_req *r2;
452
453 9299
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
454 9299
        CAST_OBJ_NOTNULL(r2, req->transport_priv, H2_REQ_MAGIC);
455 9299
        return (r2->error ? -1 : 1);
456
}
457
458
struct transport HTTP2_transport = {
459
        .name =                 "HTTP/2",
460
        .magic =                TRANSPORT_MAGIC,
461
        .deliver =              h2_deliver,
462
        .minimal_response =     h2_minimal_response,
463
        .new_session =          h2_new_session,
464
        .req_body =             h2_req_body,
465
        .req_fail =             h2_req_fail,
466
        .sess_panic =           h2_sess_panic,
467
        .poll =                 h2_poll,
468
};