| | varnish-cache/bin/varnishd/http2/cache_http2_deliver.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 |
22194 |
* are met: |
11 |
22194 |
* 1. Redistributions of source code must retain the above copyright |
12 |
22194 |
* notice, this list of conditions and the following disclaimer. |
13 |
22194 |
* 2. Redistributions in binary form must reproduce the above copyright |
14 |
22194 |
* notice, this list of conditions and the following disclaimer in the |
15 |
22194 |
* documentation and/or other materials provided with the distribution. |
16 |
22194 |
* |
17 |
22194 |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
18 |
22194 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
19 |
22194 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
20 |
22194 |
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE |
21 |
22194 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
22 |
22194 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
23 |
22194 |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
24 |
22194 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
25 |
22194 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
26 |
22194 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
27 |
22194 |
* SUCH DAMAGE. |
28 |
22194 |
* |
29 |
22194 |
*/ |
30 |
22194 |
|
31 |
22194 |
#include "config.h" |
32 |
22194 |
|
33 |
22194 |
#include "cache/cache_varnishd.h" |
34 |
22194 |
|
35 |
22194 |
#include <ctype.h> |
36 |
22194 |
#include <stdio.h> |
37 |
22194 |
|
38 |
22194 |
#include "cache/cache_filter.h" |
39 |
22194 |
#include "cache/cache_transport.h" |
40 |
22194 |
|
41 |
22194 |
#include "http2/cache_http2.h" |
42 |
22194 |
|
43 |
22194 |
#include "vct.h" |
44 |
22194 |
|
45 |
22194 |
/**********************************************************************/ |
46 |
22194 |
|
47 |
22194 |
struct hpack_static { |
48 |
22194 |
uint8_t idx; |
49 |
22194 |
const char * name; |
50 |
22194 |
const char * val; |
51 |
22194 |
}; |
52 |
22194 |
|
53 |
22194 |
static const struct hpack_static hp_static[] = { |
54 |
22194 |
#define HPS(I,N,V) [I] = { I, N ":", V }, |
55 |
22194 |
#include "tbl/vhp_static.h" |
56 |
22194 |
{ 0, "\377:", ""} // Terminator |
57 |
22194 |
}; |
58 |
22194 |
|
59 |
22194 |
static const struct hpack_static *hp_idx[256]; |
60 |
22194 |
|
61 |
22194 |
void |
62 |
44388 |
V2D_Init(void) |
63 |
22194 |
{ |
64 |
22194 |
int i; |
65 |
22194 |
#define HPS(I,N,V) \ |
66 |
22194 |
i = hp_static[I].name[0]; \ |
67 |
22194 |
if (hp_idx[i] == NULL) hp_idx[i] = &hp_static[I]; |
68 |
22194 |
#include "tbl/vhp_static.h" |
69 |
22194 |
#undef HPS |
70 |
22194 |
} |
71 |
|
|
72 |
|
/**********************************************************************/ |
73 |
|
|
74 |
|
static int v_matchproto_(vdp_init_f) |
75 |
900 |
h2_init(VRT_CTX, struct vdp_ctx *vdc, void **priv, struct objcore *oc) |
76 |
|
{ |
77 |
|
struct h2_req *r2; |
78 |
|
|
79 |
900 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
80 |
900 |
CHECK_OBJ_NOTNULL(vdc, VDP_CTX_MAGIC); |
81 |
900 |
AN(priv); |
82 |
900 |
CAST_OBJ_NOTNULL(r2, *priv, H2_REQ_MAGIC); |
83 |
900 |
(void)r2; |
84 |
900 |
(void)oc; |
85 |
900 |
return (0); |
86 |
|
} |
87 |
|
|
88 |
|
static int v_matchproto_(vdp_fini_f) |
89 |
900 |
h2_fini(struct vdp_ctx *vdc, void **priv) |
90 |
|
{ |
91 |
|
struct h2_req *r2; |
92 |
|
|
93 |
900 |
CHECK_OBJ_NOTNULL(vdc, VDP_CTX_MAGIC); |
94 |
900 |
CHECK_OBJ_NOTNULL(vdc->wrk, WORKER_MAGIC); |
95 |
900 |
TAKE_OBJ_NOTNULL(r2, priv, H2_REQ_MAGIC); |
96 |
|
|
97 |
900 |
if (r2->error) |
98 |
175 |
return (0); |
99 |
|
|
100 |
725 |
if (vdc->retval < 0) { |
101 |
25 |
r2->error = H2SE_INTERNAL_ERROR; /* XXX: proper error? */ |
102 |
25 |
H2_Send_Get(vdc->wrk, r2->h2sess, r2); |
103 |
25 |
H2_Send_RST(vdc->wrk, r2->h2sess, r2, r2->stream, r2->error); |
104 |
25 |
H2_Send_Rel(r2->h2sess, r2); |
105 |
25 |
return (0); |
106 |
|
} |
107 |
|
|
108 |
700 |
H2_Send_Get(vdc->wrk, r2->h2sess, r2); |
109 |
700 |
H2_Send(vdc->wrk, r2, H2_F_DATA, H2FF_DATA_END_STREAM, 0, "", NULL); |
110 |
700 |
H2_Send_Rel(r2->h2sess, r2); |
111 |
700 |
return (0); |
112 |
900 |
} |
113 |
|
|
114 |
|
static int v_matchproto_(vdp_bytes_f) |
115 |
1500 |
h2_bytes(struct vdp_ctx *vdc, enum vdp_action act, void **priv, |
116 |
|
const void *ptr, ssize_t len) |
117 |
|
{ |
118 |
|
struct h2_req *r2; |
119 |
|
|
120 |
1500 |
CHECK_OBJ_NOTNULL(vdc, VDP_CTX_MAGIC); |
121 |
1500 |
CAST_OBJ_NOTNULL(r2, *priv, H2_REQ_MAGIC); |
122 |
1500 |
(void)act; |
123 |
|
|
124 |
1500 |
if ((r2->h2sess->error || r2->error)) |
125 |
125 |
return (-1); |
126 |
1375 |
if (len == 0) |
127 |
475 |
return (0); |
128 |
900 |
H2_Send_Get(vdc->wrk, r2->h2sess, r2); |
129 |
900 |
vdc->bytes_done = 0; |
130 |
900 |
H2_Send(vdc->wrk, r2, H2_F_DATA, H2FF_NONE, len, ptr, &vdc->bytes_done); |
131 |
900 |
H2_Send_Rel(r2->h2sess, r2); |
132 |
900 |
return (0); |
133 |
1500 |
} |
134 |
|
|
135 |
|
static const struct vdp h2_vdp = { |
136 |
|
.name = "H2B", |
137 |
|
.init = h2_init, |
138 |
|
.bytes = h2_bytes, |
139 |
|
.fini = h2_fini, |
140 |
|
}; |
141 |
|
|
142 |
|
static inline size_t |
143 |
2725 |
h2_status(uint8_t *p, uint16_t status) { |
144 |
2725 |
size_t l = 1; |
145 |
|
|
146 |
2725 |
switch (status) { |
147 |
1775 |
case 200: *p = 0x80 | 8; break; |
148 |
0 |
case 204: *p = 0x80 | 9; break; |
149 |
50 |
case 206: *p = 0x80 | 10; break; |
150 |
75 |
case 304: *p = 0x80 | 11; break; |
151 |
25 |
case 400: *p = 0x80 | 12; break; |
152 |
25 |
case 404: *p = 0x80 | 13; break; |
153 |
25 |
case 500: *p = 0x80 | 14; break; |
154 |
|
default: |
155 |
750 |
*p++ = 0x18; |
156 |
750 |
*p++ = 0x03; |
157 |
750 |
l = 2; |
158 |
|
|
159 |
750 |
l += snprintf((char*)p, 4, "%03d", status); |
160 |
750 |
assert(l == 5); |
161 |
750 |
break; |
162 |
|
} |
163 |
|
|
164 |
2725 |
return (l); |
165 |
|
} |
166 |
|
|
167 |
|
int v_matchproto_(vtr_minimal_response_f) |
168 |
600 |
h2_minimal_response(struct req *req, uint16_t status) |
169 |
|
{ |
170 |
|
struct h2_req *r2; |
171 |
|
size_t l; |
172 |
|
uint8_t buf[6]; |
173 |
|
|
174 |
600 |
CHECK_OBJ_NOTNULL(req, REQ_MAGIC); |
175 |
600 |
CAST_OBJ_NOTNULL(r2, req->transport_priv, H2_REQ_MAGIC); |
176 |
|
|
177 |
600 |
assert(status >= 100); |
178 |
600 |
assert(status < 1000); |
179 |
|
|
180 |
600 |
l = h2_status(buf, status); |
181 |
600 |
assert(l < sizeof(buf)); |
182 |
|
|
183 |
600 |
VSLb(req->vsl, SLT_RespProtocol, "HTTP/2.0"); |
184 |
600 |
VSLb(req->vsl, SLT_RespStatus, "%03d", status); |
185 |
1200 |
VSLbs(req->vsl, SLT_RespReason, |
186 |
600 |
TOSTRAND(http_Status2Reason(status, NULL))); |
187 |
|
|
188 |
600 |
if (status >= 400) |
189 |
550 |
req->err_code = status; |
190 |
|
|
191 |
|
/* XXX return code checking once H2_Send returns anything but 0 */ |
192 |
600 |
H2_Send_Get(req->wrk, r2->h2sess, r2); |
193 |
1200 |
H2_Send(req->wrk, r2, |
194 |
|
H2_F_HEADERS, |
195 |
1200 |
H2FF_HEADERS_END_HEADERS | |
196 |
600 |
(status < 200 ? 0 : H2FF_HEADERS_END_STREAM), |
197 |
600 |
l, buf, NULL); |
198 |
600 |
H2_Send_Rel(r2->h2sess, r2); |
199 |
600 |
return (0); |
200 |
|
} |
201 |
|
|
202 |
|
static void |
203 |
29328 |
h2_enc_len(struct vsb *vsb, unsigned bits, unsigned val, uint8_t b0) |
204 |
|
{ |
205 |
29328 |
assert(bits < 8); |
206 |
29328 |
unsigned mask = (1U << bits) - 1U; |
207 |
|
|
208 |
29328 |
if (val >= mask) { |
209 |
12174 |
VSB_putc(vsb, b0 | (uint8_t)mask); |
210 |
12174 |
val -= mask; |
211 |
12299 |
while (val >= 128) { |
212 |
125 |
VSB_putc(vsb, 0x80 | ((uint8_t)val & 0x7f)); |
213 |
125 |
val >>= 7; |
214 |
|
} |
215 |
12174 |
} |
216 |
29328 |
VSB_putc(vsb, (uint8_t)val); |
217 |
29328 |
} |
218 |
|
|
219 |
|
/* |
220 |
|
* Hand-crafted-H2-HEADERS-R-Us: |
221 |
|
* |
222 |
|
* This is a handbuilt HEADERS frame for when we run out of workspace |
223 |
|
* during delivery. |
224 |
|
*/ |
225 |
|
|
226 |
|
static const uint8_t h2_500_resp[] = { |
227 |
|
// :status 500 |
228 |
|
0x8e, |
229 |
|
|
230 |
|
// content-length 0 |
231 |
|
0x1f, 0x0d, 0x01, 0x30, |
232 |
|
|
233 |
|
// server Varnish |
234 |
|
0x1f, 0x27, 0x07, 'V', 'a', 'r', 'n', 'i', 's', 'h', |
235 |
|
}; |
236 |
|
|
237 |
|
static void |
238 |
2125 |
h2_build_headers(struct vsb *resp, struct req *req) |
239 |
|
{ |
240 |
|
unsigned u, l; |
241 |
|
int i; |
242 |
|
struct http *hp; |
243 |
|
const char *r; |
244 |
|
const struct hpack_static *hps; |
245 |
|
uint8_t buf[6]; |
246 |
|
ssize_t sz, sz1; |
247 |
|
|
248 |
2125 |
assert(req->resp->status % 1000 >= 100); |
249 |
2125 |
l = h2_status(buf, req->resp->status % 1000); |
250 |
2125 |
VSB_bcat(resp, buf, l); |
251 |
|
|
252 |
2125 |
hp = req->resp; |
253 |
16866 |
for (u = HTTP_HDR_FIRST; u < hp->nhd && !VSB_error(resp); u++) { |
254 |
14741 |
r = strchr(hp->hd[u].b, ':'); |
255 |
14741 |
AN(r); |
256 |
|
|
257 |
14741 |
if (http_IsFiltered(hp, u, HTTPH_C_SPECIFIC)) |
258 |
75 |
continue; //rfc7540,l,2999,3006 |
259 |
|
|
260 |
14666 |
hps = hp_idx[tolower(*hp->hd[u].b)]; |
261 |
14666 |
sz = 1 + r - hp->hd[u].b; |
262 |
14666 |
assert(sz > 0); |
263 |
43620 |
while (hps != NULL && hps->idx > 0) { |
264 |
41420 |
i = strncasecmp(hps->name, hp->hd[u].b, sz); |
265 |
41420 |
if (i < 0) { |
266 |
28954 |
hps++; |
267 |
28954 |
continue; |
268 |
|
} |
269 |
12466 |
if (i > 0) |
270 |
425 |
hps = NULL; |
271 |
12466 |
break; |
272 |
|
} |
273 |
14666 |
if (hps != NULL) { |
274 |
24082 |
VSLb(req->vsl, SLT_Debug, |
275 |
|
"HP {%d, \"%s\", \"%s\"} <%s>", |
276 |
12041 |
hps->idx, hps->name, hps->val, hp->hd[u].b); |
277 |
12041 |
h2_enc_len(resp, 4, hps->idx, 0x10); |
278 |
12041 |
} else { |
279 |
2625 |
VSB_putc(resp, 0x10); |
280 |
2625 |
sz--; |
281 |
2625 |
h2_enc_len(resp, 7, sz, 0); |
282 |
39374 |
for (sz1 = 0; sz1 < sz; sz1++) |
283 |
36749 |
VSB_putc(resp, tolower(hp->hd[u].b[sz1])); |
284 |
|
|
285 |
|
} |
286 |
|
|
287 |
29337 |
while (vct_islws(*++r)) |
288 |
14671 |
continue; |
289 |
14666 |
sz = hp->hd[u].e - r; |
290 |
14666 |
h2_enc_len(resp, 7, sz, 0); |
291 |
14666 |
VSB_bcat(resp, r, sz); |
292 |
14666 |
} |
293 |
2125 |
} |
294 |
|
|
295 |
|
void v_matchproto_(vtr_deliver_f) |
296 |
2125 |
h2_deliver(struct req *req, struct boc *boc, int sendbody) |
297 |
|
{ |
298 |
|
size_t sz; |
299 |
|
const char *r; |
300 |
|
struct sess *sp; |
301 |
|
struct h2_req *r2; |
302 |
|
struct vsb resp[1]; |
303 |
|
struct vrt_ctx ctx[1]; |
304 |
|
uintptr_t ss; |
305 |
|
|
306 |
2125 |
CHECK_OBJ_NOTNULL(req, REQ_MAGIC); |
307 |
2125 |
CHECK_OBJ_ORNULL(boc, BOC_MAGIC); |
308 |
2125 |
CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC); |
309 |
2125 |
CAST_OBJ_NOTNULL(r2, req->transport_priv, H2_REQ_MAGIC); |
310 |
2125 |
sp = req->sp; |
311 |
2125 |
CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); |
312 |
|
|
313 |
2125 |
VSLb(req->vsl, SLT_RespProtocol, "HTTP/2.0"); |
314 |
|
|
315 |
2125 |
(void)http_DoConnection(req->resp, SC_RESP_CLOSE); |
316 |
|
|
317 |
2125 |
ss = WS_Snapshot(req->ws); |
318 |
|
|
319 |
2125 |
WS_VSB_new(resp, req->ws); |
320 |
2125 |
h2_build_headers(resp, req); |
321 |
2125 |
r = WS_VSB_finish(resp, req->ws, &sz); |
322 |
|
|
323 |
2125 |
if (r == NULL) { |
324 |
25 |
VSLb(req->vsl, SLT_Error, "workspace_client overflow"); |
325 |
25 |
VSLb(req->vsl, SLT_RespStatus, "500"); |
326 |
25 |
VSLb(req->vsl, SLT_RespReason, "Internal Server Error"); |
327 |
25 |
req->wrk->stats->client_resp_500++; |
328 |
|
|
329 |
25 |
r = (const char*)h2_500_resp; |
330 |
25 |
sz = sizeof h2_500_resp; |
331 |
25 |
sendbody = 0; |
332 |
25 |
} |
333 |
|
|
334 |
2125 |
AZ(req->wrk->v1l); |
335 |
|
|
336 |
2125 |
r2->t_send = req->t_prev; |
337 |
|
|
338 |
2125 |
H2_Send_Get(req->wrk, r2->h2sess, r2); |
339 |
4250 |
H2_Send(req->wrk, r2, H2_F_HEADERS, |
340 |
2125 |
(sendbody ? 0 : H2FF_HEADERS_END_STREAM) | H2FF_HEADERS_END_HEADERS, |
341 |
2125 |
sz, r, &req->acct.resp_hdrbytes); |
342 |
2125 |
H2_Send_Rel(r2->h2sess, r2); |
343 |
|
|
344 |
2125 |
WS_Reset(req->ws, ss); |
345 |
|
|
346 |
|
/* XXX someone into H2 please add appropriate error handling */ |
347 |
2125 |
if (sendbody) { |
348 |
900 |
INIT_OBJ(ctx, VRT_CTX_MAGIC); |
349 |
900 |
VCL_Req2Ctx(ctx, req); |
350 |
900 |
if (!VDP_Push(ctx, req->vdc, req->ws, &h2_vdp, r2)) |
351 |
900 |
(void)VDP_DeliverObj(req->vdc, req->objcore); |
352 |
900 |
} |
353 |
|
|
354 |
2125 |
AZ(req->wrk->v1l); |
355 |
2125 |
req->acct.resp_bodybytes += VDP_Close(req->vdc, req->objcore, boc); |
356 |
2125 |
} |