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
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
};
53
54
static size_t
55 1704
h2_enc_settings(const struct h2_settings *h2s, uint8_t *buf, size_t n)
56
{
57 1704
        size_t len = 0;
58
59
#define H2_SETTING(U,l,v,d,...)                         \
60
        if (h2s->l != d) {                              \
61
                len += 6;                               \
62
                assert(len <= n);                       \
63
                vbe16enc(buf, v);                       \
64
                buf += 2;                               \
65
                vbe32enc(buf, h2s->l);                  \
66
                buf += 4;                               \
67
        }
68
#include "tbl/h2_settings.h"
69 1704
        return (len);
70
}
71
72
static const struct h2_settings H2_proto_settings = {
73
#define H2_SETTING(U,l,v,d,...) . l = d,
74
#include "tbl/h2_settings.h"
75
};
76
77
static void
78 1776
h2_local_settings(struct h2_settings *h2s)
79
{
80 1776
        *h2s = H2_proto_settings;
81
#define H2_SETTINGS_PARAM_ONLY
82
#define H2_SETTING(U, l, ...)                   \
83
        h2s->l = cache_param->h2_##l;
84
#include "tbl/h2_settings.h"
85
#undef H2_SETTINGS_PARAM_ONLY
86 1776
}
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
 */
94
95
static struct h2_sess *
96 1775
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 1775
        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
        }
107 1776
        if (*up == 0) {
108 1776
                if (srq == NULL)
109 120
                        srq = Req_New(wrk, sp);
110 1776
                AN(srq);
111 1776
                h2 = h2s;
112 1776
                AN(h2);
113 1776
                INIT_OBJ(h2, H2_SESS_MAGIC);
114 1776
                h2->srq = srq;
115 1776
                h2->htc = srq->htc;
116 1776
                h2->ws = srq->ws;
117 1776
                h2->vsl = srq->vsl;
118 1776
                VSL_Flush(h2->vsl, 0);
119 1776
                h2->vsl->wid = sp->vxid;
120 1776
                h2->htc->rfd = &sp->fd;
121 1776
                h2->sess = sp;
122 1776
                h2->rxthr = pthread_self();
123 1776
                AZ(pthread_cond_init(h2->winupd_cond, NULL));
124 1776
                VTAILQ_INIT(&h2->streams);
125 1776
                VTAILQ_INIT(&h2->txqueue);
126 1776
                h2_local_settings(&h2->local_settings);
127 1776
                h2->remote_settings = H2_proto_settings;
128 1776
                h2->decode = decode;
129
130 1776
                AZ(VHT_Init(h2->dectbl,
131
                        h2->local_settings.header_table_size));
132
133 1776
                SES_Reserve_proto_priv(sp, &up);
134 1776
                *up = (uintptr_t)h2;
135
        }
136 1776
        AN(up);
137 1776
        CAST_OBJ_NOTNULL(h2, (void*)(*up), H2_SESS_MAGIC);
138 1776
        return (h2);
139
}
140
141
static void
142 1704
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 1704
        CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
148 1704
        AZ(h2->refcnt);
149 1704
        assert(VTAILQ_EMPTY(&h2->streams));
150
151 1704
        VHT_Fini(h2->dectbl);
152 1704
        AZ(pthread_cond_destroy(h2->winupd_cond));
153 1704
        req = h2->srq;
154 1704
        AZ(req->ws->r);
155 1704
        sp = h2->sess;
156 1704
        Req_Cleanup(sp, wrk, req);
157 1704
        Req_Release(req);
158 1704
        SES_Delete(sp, reason, NAN);
159 1704
}
160
161
/**********************************************************************/
162
163
enum htc_status_e v_matchproto_(htc_complete_f)
164 158081
H2_prism_complete(struct http_conn *htc)
165
{
166
        int l;
167
168 158081
        CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
169 158081
        l = htc->rxbuf_e - htc->rxbuf_b;
170 312655
        if (l >= sizeof(H2_prism) &&
171 154574
            !memcmp(htc->rxbuf_b, H2_prism, sizeof(H2_prism)))
172 5160
                return (HTC_S_COMPLETE);
173 152921
        if (l < sizeof(H2_prism) && !memcmp(htc->rxbuf_b, H2_prism, l))
174 1824
                return (HTC_S_MORE);
175 151097
        return (HTC_S_JUNK);
176
}
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 120
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 120
        if (!http_GetHdr(req->http, H_HTTP2_Settings, &p))
202 24
                return (-1);
203 96
        AN(p);
204 96
        VSLb(req->vsl, SLT_Debug, "H2CS %s", p);
205
206 96
        n = 0;
207 96
        x = 0;
208 96
        up = u;
209 1248
        for (;*p; p++) {
210 1176
                q = strchr(s, *p);
211 1176
                if (q == NULL)
212 24
                        return (-1);
213 1152
                i = q - s;
214 1152
                assert(i >= 0 && i <= 64);
215 1152
                x <<= 6;
216 1152
                x |= i;
217 1152
                n += 6;
218 1152
                if (n < 8)
219 288
                        continue;
220 864
                *up++ = (uint8_t)(x >> (n - 8));
221 864
                n -= 8;
222 864
                if (up == u + sizeof u) {
223 144
                        AZ(n);
224 144
                        if (h2_set_setting(h2, (void*)u))
225 0
                                return (-1);
226 144
                        up = u;
227
                }
228
        }
229 72
        if (up != u)
230 0
                return (-1);
231 72
        return (0);
232
}
233
234
235
/**********************************************************************/
236
237
static int
238 48
h2_ou_rel(struct worker *wrk, struct req *req)
239
{
240 48
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
241 48
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
242 48
        AZ(req->vcl);
243 48
        Req_AcctLogCharge(wrk->stats, req);
244 48
        Req_Release(req);
245 48
        return (0);
246
}
247
248
static int
249 120
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 120
        if (h2_b64url_settings(h2, req)) {
257 48
                VSLb(h2->vsl, SLT_Debug, "H2: Bad HTTP-Settings");
258 48
                return (h2_ou_rel(wrk, req));
259
        }
260
261 72
        sz = write(h2->sess->fd, h2_resp_101, strlen(h2_resp_101));
262 72
        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 72
        http_Unset(req->http, H_Upgrade);
269 72
        http_Unset(req->http, H_HTTP2_Settings);
270
271
        /* Steal pipelined read-ahead, if any */
272 72
        h2->htc->pipeline_b = req->htc->pipeline_b;
273 72
        h2->htc->pipeline_e = req->htc->pipeline_e;
274 72
        req->htc->pipeline_b = NULL;
275 72
        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 72
        HTC_RxInit(h2->htc, h2->ws);
280
281
        /* Start req thread */
282 72
        r2 = h2_new_req(wrk, h2, 1, req);
283 72
        req->transport = &H2_transport;
284 72
        req->req_step = R_STP_TRANSPORT;
285 72
        req->task.func = h2_do_req;
286 72
        req->task.priv = req;
287 72
        r2->scheduled = 1;
288 72
        r2->state = H2_S_CLOS_REM; // rfc7540,l,489,491
289 72
        req->err_code = 0;
290 72
        http_SetH(req->http, HTTP_HDR_PROTO, "HTTP/2.0");
291
292
        /* Wait for PRISM response */
293 72
        hs = HTC_RxStuff(h2->htc, H2_prism_complete,
294 72
            NULL, NULL, NAN, h2->sess->t_idle + cache_param->timeout_idle,
295
            sizeof H2_prism);
296 72
        if (hs != HTC_S_COMPLETE) {
297 24
                VSLb(h2->vsl, SLT_Debug, "H2: No/Bad OU PRISM (hs=%d)", hs);
298 24
                r2->scheduled = 0;
299 24
                h2_del_req(wrk, r2);
300 24
                return (0);
301
        }
302 48
        XXXAZ(Pool_Task(wrk->pool, &req->task, TASK_QUEUE_REQ));
303 48
        return (1);
304
}
305
306
/**********************************************************************
307
 */
308
309
#define H2_PU_MARKER    1
310
#define H2_OU_MARKER    2
311
312
void
313 1656
H2_PU_Sess(struct worker *wrk, struct sess *sp, struct req *req)
314
{
315 1656
        VSLb(req->vsl, SLT_Debug, "H2 Prior Knowledge Upgrade");
316 1655
        req->err_code = H2_PU_MARKER;
317 1655
        SES_SetTransport(wrk, sp, req, &H2_transport);
318 1656
}
319
320
void
321 120
H2_OU_Sess(struct worker *wrk, struct sess *sp, struct req *req)
322
{
323 120
        VSLb(req->vsl, SLT_Debug, "H2 Optimistic Upgrade");
324 120
        req->err_code = H2_OU_MARKER;
325 120
        SES_SetTransport(wrk, sp, req, &H2_transport);
326 120
}
327
328
static void v_matchproto_(task_func_t)
329 1771
h2_new_session(struct worker *wrk, void *arg)
330
{
331
        struct req *req;
332
        struct sess *sp;
333
        struct h2_sess h2s;
334
        struct h2_sess *h2;
335
        struct h2_req *r2, *r22;
336
        int again;
337
        uint8_t settings[48];
338
        struct h2h_decode decode;
339
        size_t l;
340
341 1771
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
342 1771
        CAST_OBJ_NOTNULL(req, arg, REQ_MAGIC);
343 1771
        sp = req->sp;
344 1771
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
345
346 1771
        if (wrk->vcl)
347 263
                VCL_Rel(&wrk->vcl);
348
349 1776
        assert(req->transport == &H2_transport);
350
351 1776
        assert (req->err_code == H2_PU_MARKER || req->err_code == H2_OU_MARKER);
352
353 1776
        h2 = h2_init_sess(wrk, sp, &h2s,
354 1776
            req->err_code == H2_PU_MARKER ? req : NULL, &decode);
355 1776
        h2->req0 = h2_new_req(wrk, h2, 0, NULL);
356 1776
        AZ(h2->htc->priv);
357 1776
        h2->htc->priv = h2;
358
359 1776
        if (req->err_code == H2_OU_MARKER && !h2_ou_session(wrk, h2, req)) {
360 72
                assert(h2->refcnt == 1);
361 72
                h2_del_req(wrk, h2->req0);
362 72
                h2_del_sess(wrk, h2, SC_RX_JUNK);
363 72
                return;
364
        }
365 1704
        assert(HTC_S_COMPLETE == H2_prism_complete(h2->htc));
366 1704
        HTC_RxPipeline(h2->htc, h2->htc->rxbuf_b + sizeof(H2_prism));
367 1704
        WS_Reset(h2->ws, 0);
368 1704
        HTC_RxInit(h2->htc, h2->ws);
369 1704
        AN(h2->ws->r);
370 1704
        VSLb(h2->vsl, SLT_Debug, "H2: Got pu PRISM");
371
372 1704
        THR_SetRequest(h2->srq);
373 1704
        AN(h2->ws->r);
374
375 1704
        l = h2_enc_settings(&h2->local_settings, settings, sizeof (settings));
376 1704
        AN(h2->ws->r);
377 1704
        H2_Send_Get(wrk, h2, h2->req0);
378 1704
        AN(h2->ws->r);
379 1704
        H2_Send_Frame(wrk, h2,
380
            H2_F_SETTINGS, H2FF_NONE, l, 0, settings);
381 1704
        AN(h2->ws->r);
382 1704
        H2_Send_Rel(h2, h2->req0);
383 1704
        AN(h2->ws->r);
384
385
        /* and off we go... */
386 1704
        h2->cond = &wrk->cond;
387
388 9769
        while (h2_rxframe(wrk, h2)) {
389 6361
                WS_Reset(h2->ws, 0);
390 6361
                HTC_RxInit(h2->htc, h2->ws);
391 6361
                if (WS_Overflowed(h2->ws)) {
392 0
                        VSLb(h2->vsl, SLT_Debug, "H2: Empty Rx Workspace");
393 0
                        h2->error = H2CE_INTERNAL_ERROR;
394 0
                        break;
395
                }
396 6361
                AN(h2->ws->r);
397
        }
398
399 1680
        AN(h2->error);
400
401
        /* Delete all idle streams */
402 1680
        VSLb(h2->vsl, SLT_Debug, "H2 CLEANUP %s", h2->error->name);
403 1680
        Lck_Lock(&h2->sess->mtx);
404 4560
        VTAILQ_FOREACH(r2, &h2->streams, list) {
405 2880
                if (r2->error == 0)
406 2856
                        r2->error = h2->error;
407 2880
                if (r2->cond != NULL)
408 97
                        AZ(pthread_cond_signal(r2->cond));
409
        }
410 1680
        AZ(pthread_cond_broadcast(h2->winupd_cond));
411 1679
        Lck_Unlock(&h2->sess->mtx);
412
        while (1) {
413 8894
                again = 0;
414 14441
                VTAILQ_FOREACH_SAFE(r2, &h2->streams, list, r22) {
415 9157
                        if (r2 != h2->req0) {
416 3870
                                h2_kill_req(wrk, h2, r2, h2->error);
417 3867
                                again++;
418
                        }
419
                }
420 5284
                if (!again)
421 1632
                        break;
422 3652
                Lck_Lock(&h2->sess->mtx);
423 10023
                VTAILQ_FOREACH(r2, &h2->streams, list)
424 6367
                        VSLb(h2->vsl, SLT_Debug, "ST %u %d",
425 6367
                            r2->stream, r2->state);
426 3656
                (void)Lck_CondWait(h2->cond, &h2->sess->mtx, VTIM_real() + .1);
427 3608
                Lck_Unlock(&h2->sess->mtx);
428
        }
429 1632
        h2->cond = NULL;
430 1632
        assert(h2->refcnt == 1);
431 1632
        h2_del_req(wrk, h2->req0);
432
        /* TODO: proper sess close reason */
433 1632
        h2_del_sess(wrk, h2, SC_RX_JUNK);
434
}
435
436
struct transport H2_transport = {
437
        .name =                 "H2",
438
        .magic =                TRANSPORT_MAGIC,
439
        .deliver =              h2_deliver,
440
        .minimal_response =     h2_minimal_response,
441
        .new_session =          h2_new_session,
442
        .req_body =             h2_req_body,
443
        .req_fail =             h2_req_fail,
444
        .sess_panic =           h2_sess_panic,
445
};