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