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 2055
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 2055
}
72
73
/**********************************************************************/
74
75
static int v_matchproto_(vdp_bytes)
76 228
h2_bytes(struct req *req, enum vdp_action act, void **priv,
77
    const void *ptr, ssize_t len)
78
{
79
        struct h2_req *r2;
80
81 228
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
82 228
        CAST_OBJ_NOTNULL(r2, req->transport_priv, H2_REQ_MAGIC);
83
        (void)priv;
84
85 228
        if (act == VDP_INIT)
86 72
                return (0);
87 156
        if (r2->error && act != VDP_FINI)
88 12
                return (-1);
89 144
        H2_Send_Get(req->wrk, r2->h2sess, r2);
90 144
        H2_Send(req->wrk, r2,
91
            H2_F_DATA,
92
            act == VDP_FINI ? H2FF_DATA_END_STREAM : H2FF_NONE,
93
            len, ptr);
94 144
        H2_Send_Rel(r2->h2sess, r2);
95 144
        req->acct.resp_bodybytes += len;
96 144
        return (0);
97
}
98
99
static const struct vdp h2_vdp = {
100
        .name =         "H2B",
101
        .func =         h2_bytes,
102
};
103
104
static inline size_t
105 156
h2_status(uint8_t *p, uint16_t status) {
106 156
        size_t l = 1;
107
108 156
        switch (status) {
109 120
        case 200: *p = 0x80 |  8; break;
110 0
        case 204: *p = 0x80 |  9; break;
111 3
        case 206: *p = 0x80 | 10; break;
112 9
        case 304: *p = 0x80 | 11; break;
113 0
        case 400: *p = 0x80 | 12; break;
114 3
        case 404: *p = 0x80 | 13; break;
115 3
        case 500: *p = 0x80 | 14; break;
116
        default:
117 18
                *p++ = 0x18;
118 18
                *p++ = 0x03;
119 18
                l = 2;
120
121 18
                l += snprintf((char*)p, 4, "%03d", status);
122 18
                assert(l == 5);
123 18
                break;
124
        }
125
126 156
        return (l);
127
}
128
129
int v_matchproto_(vtr_minimal_response_f)
130 6
h2_minimal_response(struct req *req, uint16_t status)
131
{
132
        struct h2_req *r2;
133
        size_t l;
134
        uint8_t buf[6];
135
136 6
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
137 6
        CAST_OBJ_NOTNULL(r2, req->transport_priv, H2_REQ_MAGIC);
138
139 6
        assert(status >= 100);
140 6
        assert(status < 1000);
141
142 6
        l = h2_status(buf, status);
143 6
        assert(l < sizeof(buf));
144
145 6
        VSLb(req->vsl, SLT_RespProtocol, "HTTP/2.0");
146 6
        VSLb(req->vsl, SLT_RespStatus, "%03d", status);
147 6
        VSLb(req->vsl, SLT_RespReason, "%s", http_Status2Reason(status, NULL));
148
149 6
        if (status >= 400)
150 0
                req->err_code = status;
151
152
        /* XXX return code checking once H2_Send returns anything but 0 */
153 6
        H2_Send_Get(req->wrk, r2->h2sess, r2);
154 12
        H2_Send(req->wrk, r2,
155
            H2_F_HEADERS,
156 6
            H2FF_HEADERS_END_HEADERS |
157
                (status < 200 ? 0 : H2FF_HEADERS_END_STREAM),
158
            l, buf);
159 6
        H2_Send_Rel(r2->h2sess, r2);
160 6
        return (0);
161
}
162
163
static uint8_t *
164 1938
h2_enc_len(uint8_t *p, unsigned bits, unsigned val)
165
{
166 1938
        assert(bits < 8);
167 1938
        unsigned mask = (1U << bits) - 1U;
168
169 1938
        if (val >= mask) {
170 804
                *p++ |= (uint8_t)mask;
171 804
                val -= mask;
172 1620
                while (val >= 128) {
173 12
                        *p++ = 0x80 | ((uint8_t)val & 0x7f);
174 12
                        val >>= 7;
175
                }
176
        }
177 1938
        *p++ = (uint8_t)val;
178 1938
        return (p);
179
}
180
181
void v_matchproto_(vtr_deliver_f)
182 150
h2_deliver(struct req *req, struct boc *boc, int sendbody)
183
{
184
        ssize_t sz, sz1;
185
        uint8_t *p;
186
        unsigned u;
187
        const char *r;
188
        struct http *hp;
189
        struct sess *sp;
190
        struct h2_req *r2;
191
        int i, err;
192
        const struct hpack_static *hps;
193
194 150
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
195 150
        CHECK_OBJ_ORNULL(boc, BOC_MAGIC);
196 150
        CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC);
197 150
        CAST_OBJ_NOTNULL(r2, req->transport_priv, H2_REQ_MAGIC);
198 150
        sp = req->sp;
199 150
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
200
201 150
        (void)WS_Reserve(req->ws, 0);
202 150
        p = (void*)req->ws->f;
203
204 150
        p += h2_status(p, req->resp->status);
205
206 150
        hp = req->resp;
207 1119
        for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
208 969
                assert(WS_Inside(req->ws, p, NULL));
209
210 969
                r = strchr(hp->hd[u].b, ':');
211 969
                AN(r);
212
213 969
                hps = hp_idx[tolower(*hp->hd[u].b)];
214 969
                sz = 1 + r - hp->hd[u].b;
215 969
                assert(sz > 0);
216 4143
                while (hps != NULL && hps->idx > 0) {
217 3018
                        i = strncasecmp(hps->name, hp->hd[u].b, sz);
218 3018
                        if (i < 0) {
219 2205
                                hps++;
220 2205
                                continue;
221
                        }
222 813
                        if (i > 0)
223 21
                                hps = NULL;
224 813
                        break;
225
                }
226 969
                if (hps != NULL) {
227 1584
                        VSLb(req->vsl, SLT_Debug,
228
                            "HP {%d, \"%s\", \"%s\"} <%s>",
229 1584
                            hps->idx, hps->name, hps->val, hp->hd[u].b);
230 792
                        *p = 0x10;
231 792
                        p = h2_enc_len(p, 4, hps->idx);
232
                } else {
233
234 177
                        *p++ = 0x10;
235 177
                        sz--;
236 177
                        p = h2_enc_len(p, 7, sz);
237 3234
                        for (sz1 = 0; sz1 < sz; sz1++)
238 3057
                                *p++ = (uint8_t)tolower(hp->hd[u].b[sz1]);
239
240
                }
241
242 2907
                while (vct_islws(*++r))
243 969
                        continue;
244 969
                sz = hp->hd[u].e - r;
245 969
                p = h2_enc_len(p, 7, sz);
246 969
                memcpy(p, r, sz);
247 969
                p += sz;
248 969
                assert(WS_Inside(req->ws, p, NULL));
249
        }
250 150
        sz = (char*)p - req->ws->f;
251
252 150
        AZ(req->wrk->v1l);
253
254 150
        if (sendbody && req->resp_len == 0)
255 69
                sendbody = 0;
256
257 150
        r2->t_send = req->t_prev;
258
259 150
        H2_Send_Get(req->wrk, r2->h2sess, r2);
260 300
        H2_Send(req->wrk, r2, H2_F_HEADERS,
261 150
            (sendbody ? 0 : H2FF_HEADERS_END_STREAM) | H2FF_HEADERS_END_HEADERS,
262 150
            sz, req->ws->f);
263 150
        H2_Send_Rel(r2->h2sess, r2);
264 150
        req->acct.resp_hdrbytes += sz;
265
266 150
        WS_Release(req->ws, 0);
267
268
        /* XXX someone into H2 please add appropriate error handling */
269 150
        if (sendbody) {
270 72
                err = VDP_push(req, &h2_vdp, NULL, 1);
271 72
                if (!err)
272 72
                        err = VDP_DeliverObj(req);
273
        }
274
275 150
        AZ(req->wrk->v1l);
276 150
        VDP_close(req);
277 150
}