varnish-cache/bin/varnishd/http2/cache_http2_deliver.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 <netinet/in.h>
35
36
#include <ctype.h>
37
#include <stdio.h>
38
39
#include "cache/cache_filter.h"
40
#include "cache/cache_transport.h"
41
42
#include "http2/cache_http2.h"
43
44
#include "vct.h"
45
46
/**********************************************************************/
47
48
struct hpack_static {
49
        uint8_t                 idx;
50
        const char *            name;
51
        const char *            val;
52
};
53
54
static const struct hpack_static hp_static[] = {
55
#define HPS(I,N,V) [I] = { I, N ":", V },
56
#include "tbl/vhp_static.h"
57
        { 0, "\377:", ""}               // Terminator
58
};
59
60
static const struct hpack_static *hp_idx[256];
61
62
void
63 1376
V2D_Init(void)
64
{
65
        int i;
66
#define HPS(I,N,V)                                              \
67
        i = hp_static[I].name[0];                               \
68
        if (hp_idx[i] == NULL) hp_idx[i] = &hp_static[I];
69
#include "tbl/vhp_static.h"
70
#undef HPS
71 1376
}
72
73
/**********************************************************************/
74
75
static int v_matchproto_(vdp_fini_f)
76 46
h2_fini(struct req *req, void **priv)
77
{
78
        struct h2_req *r2;
79
80 46
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
81
        (void)priv;
82 46
        CAST_OBJ_NOTNULL(r2, req->transport_priv, H2_REQ_MAGIC);
83 46
        H2_Send_Get(req->wrk, r2->h2sess, r2);
84 46
        H2_Send(req->wrk, r2, H2_F_DATA, H2FF_DATA_END_STREAM, 0, "");
85 46
        H2_Send_Rel(r2->h2sess, r2);
86 46
        return (0);
87
}
88
89
static int v_matchproto_(vdp_bytes_f)
90 54
h2_bytes(struct req *req, enum vdp_action act, void **priv,
91
    const void *ptr, ssize_t len)
92
{
93
        struct h2_req *r2;
94
95 54
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
96 54
        CAST_OBJ_NOTNULL(r2, req->transport_priv, H2_REQ_MAGIC);
97
        (void)act;
98
        (void)priv;
99
100 54
        if ((r2->h2sess->error || r2->error))
101 8
                return (-1);
102 46
        H2_Send_Get(req->wrk, r2->h2sess, r2);
103 46
        H2_Send(req->wrk, r2, H2_F_DATA, H2FF_NONE, len, ptr);
104 46
        H2_Send_Rel(r2->h2sess, r2);
105 46
        req->acct.resp_bodybytes += len;
106 46
        return (0);
107
}
108
109
static const struct vdp h2_vdp = {
110
        .name =         "H2B",
111
        .bytes =        h2_bytes,
112
        .fini =         h2_fini,
113
};
114
115
static inline size_t
116 122
h2_status(uint8_t *p, uint16_t status) {
117 122
        size_t l = 1;
118
119 122
        switch (status) {
120 98
        case 200: *p = 0x80 |  8; break;
121 0
        case 204: *p = 0x80 |  9; break;
122 2
        case 206: *p = 0x80 | 10; break;
123 6
        case 304: *p = 0x80 | 11; break;
124 0
        case 400: *p = 0x80 | 12; break;
125 2
        case 404: *p = 0x80 | 13; break;
126 2
        case 500: *p = 0x80 | 14; break;
127
        default:
128 12
                *p++ = 0x18;
129 12
                *p++ = 0x03;
130 12
                l = 2;
131
132 12
                l += snprintf((char*)p, 4, "%03d", status);
133 12
                assert(l == 5);
134 12
                break;
135
        }
136
137 122
        return (l);
138
}
139
140
int v_matchproto_(vtr_minimal_response_f)
141 4
h2_minimal_response(struct req *req, uint16_t status)
142
{
143
        struct h2_req *r2;
144
        size_t l;
145
        uint8_t buf[6];
146
147 4
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
148 4
        CAST_OBJ_NOTNULL(r2, req->transport_priv, H2_REQ_MAGIC);
149
150 4
        assert(status >= 100);
151 4
        assert(status < 1000);
152
153 4
        l = h2_status(buf, status);
154 4
        assert(l < sizeof(buf));
155
156 4
        VSLb(req->vsl, SLT_RespProtocol, "HTTP/2.0");
157 4
        VSLb(req->vsl, SLT_RespStatus, "%03d", status);
158 4
        VSLb(req->vsl, SLT_RespReason, "%s", http_Status2Reason(status, NULL));
159
160 4
        if (status >= 400)
161 0
                req->err_code = status;
162
163
        /* XXX return code checking once H2_Send returns anything but 0 */
164 4
        H2_Send_Get(req->wrk, r2->h2sess, r2);
165 8
        H2_Send(req->wrk, r2,
166
            H2_F_HEADERS,
167 4
            H2FF_HEADERS_END_HEADERS |
168
                (status < 200 ? 0 : H2FF_HEADERS_END_STREAM),
169
            l, buf);
170 4
        H2_Send_Rel(r2->h2sess, r2);
171 4
        return (0);
172
}
173
174
static int
175 1486
h2_enc_len(struct vsb *vsb, unsigned bits, unsigned val, uint8_t b0)
176
{
177 1486
        assert(bits < 8);
178 1486
        unsigned mask = (1U << bits) - 1U;
179
180 1486
        if (val >= mask) {
181 618
                VSB_putc(vsb, b0 | (uint8_t)mask);
182 618
                val -= mask;
183 1246
                while (val >= 128) {
184 10
                        VSB_putc(vsb, 0x80 | ((uint8_t)val & 0x7f));
185 10
                        val >>= 7;
186
                }
187
        }
188 1486
        VSB_putc(vsb, (uint8_t)val);
189 1486
        return (0);
190
}
191
192
/*
193
 * Hand-crafted-H2-HEADERS-R-Us:
194
 *
195
 * This is a handbuilt HEADERS frame for when we run out of workspace
196
 * during delivery.
197
 */
198
199
static const uint8_t h2_500_resp[] = {
200
        // :status 500
201
        0x8e,
202
203
        // content-length 0
204
        0x1f, 0x0d, 0x01, 0x30,
205
206
        // server Varnish
207
        0x1f, 0x27, 0x07, 'V', 'a', 'r', 'n', 'i', 's', 'h',
208
};
209
210
void v_matchproto_(vtr_deliver_f)
211 118
h2_deliver(struct req *req, struct boc *boc, int sendbody)
212
{
213
        ssize_t sz, sz1;
214
        unsigned u, l;
215
        uint8_t buf[6];
216
        const char *r;
217
        struct http *hp;
218
        struct sess *sp;
219
        struct h2_req *r2;
220
        struct vsb resp;
221
        int i;
222
        const struct hpack_static *hps;
223
224 118
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
225 118
        CHECK_OBJ_ORNULL(boc, BOC_MAGIC);
226 118
        CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC);
227 118
        CAST_OBJ_NOTNULL(r2, req->transport_priv, H2_REQ_MAGIC);
228 118
        sp = req->sp;
229 118
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
230
231 118
        l = WS_Reserve(req->ws, 0);
232 118
        AN(VSB_new(&resp, req->ws->f, l, VSB_FIXEDLEN));
233
234 118
        l = h2_status(buf, req->resp->status);
235 118
        VSB_bcat(&resp, buf, l);
236
237 118
        hp = req->resp;
238 862
        for (u = HTTP_HDR_FIRST; u < hp->nhd && !VSB_error(&resp); u++) {
239 744
                r = strchr(hp->hd[u].b, ':');
240 744
                AN(r);
241
242 744
                hps = hp_idx[tolower(*hp->hd[u].b)];
243 744
                sz = 1 + r - hp->hd[u].b;
244 744
                assert(sz > 0);
245 3178
                while (hps != NULL && hps->idx > 0) {
246 2314
                        i = strncasecmp(hps->name, hp->hd[u].b, sz);
247 2314
                        if (i < 0) {
248 1690
                                hps++;
249 1690
                                continue;
250
                        }
251 624
                        if (i > 0)
252 16
                                hps = NULL;
253 624
                        break;
254
                }
255 744
                if (hps != NULL) {
256 1216
                        VSLb(req->vsl, SLT_Debug,
257
                            "HP {%d, \"%s\", \"%s\"} <%s>",
258 1216
                            hps->idx, hps->name, hps->val, hp->hd[u].b);
259 608
                        h2_enc_len(&resp, 4, hps->idx, 0x10);
260
                } else {
261 136
                        VSB_putc(&resp, 0x10);
262 136
                        sz--;
263 136
                        h2_enc_len(&resp, 7, sz, 0);
264 2319
                        for (sz1 = 0; sz1 < sz; sz1++)
265 2183
                                VSB_putc(&resp, tolower(hp->hd[u].b[sz1]));
266
267
                }
268
269 2232
                while (vct_islws(*++r))
270 744
                        continue;
271 744
                sz = hp->hd[u].e - r;
272 744
                h2_enc_len(&resp, 7, sz, 0);
273 744
                VSB_bcat(&resp, r, sz);
274
        }
275 118
        if (VSB_finish(&resp)) {
276 2
                WS_MarkOverflow(req->ws);
277
                // We ran out of workspace, return minimal 500
278 2
                VSLb(req->vsl, SLT_Error, "workspace_client overflow");
279 2
                VSLb(req->vsl, SLT_RespStatus, "500");
280 2
                VSLb(req->vsl, SLT_RespReason, "Internal Server Error");
281 2
                req->wrk->stats->client_resp_500++;
282
283 2
                r = (const char*)h2_500_resp;
284 2
                sz = sizeof h2_500_resp;
285 2
                sendbody = 0;
286
        } else {
287 116
                sz = VSB_len(&resp);
288 116
                r = req->ws->f;
289
        }
290
291 118
        AZ(req->wrk->v1l);
292
293 118
        r2->t_send = req->t_prev;
294
295 118
        H2_Send_Get(req->wrk, r2->h2sess, r2);
296 236
        H2_Send(req->wrk, r2, H2_F_HEADERS,
297 118
            (sendbody ? 0 : H2FF_HEADERS_END_STREAM) | H2FF_HEADERS_END_HEADERS,
298
            sz, r);
299 118
        H2_Send_Rel(r2->h2sess, r2);
300 118
        req->acct.resp_hdrbytes += sz;
301
302 118
        WS_Release(req->ws, 0);
303
304
        /* XXX someone into H2 please add appropriate error handling */
305 118
        if (sendbody) {
306 46
                if (!VDP_Push(req, &h2_vdp, NULL))
307 46
                        (void)VDP_DeliverObj(req);
308
        }
309
310 118
        AZ(req->wrk->v1l);
311 118
        VDP_close(req);
312 118
}