| | varnish-cache/bin/varnishd/http2/cache_http2_session.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 |
|
* are met: |
11 |
|
* 1. Redistributions of source code must retain the above copyright |
12 |
|
* notice, this list of conditions and the following disclaimer. |
13 |
|
* 2. Redistributions in binary form must reproduce the above copyright |
14 |
|
* notice, this list of conditions and the following disclaimer in the |
15 |
|
* documentation and/or other materials provided with the distribution. |
16 |
|
* |
17 |
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
18 |
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
19 |
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
20 |
|
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE |
21 |
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
22 |
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
23 |
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
24 |
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
25 |
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
26 |
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
27 |
|
* SUCH DAMAGE. |
28 |
|
* |
29 |
|
*/ |
30 |
|
|
31 |
|
#include "config.h" |
32 |
|
|
33 |
|
#include "cache/cache_varnishd.h" |
34 |
|
|
35 |
|
#include <stdio.h> |
36 |
|
|
37 |
|
#include "cache/cache_transport.h" |
38 |
|
#include "http2/cache_http2.h" |
39 |
|
|
40 |
|
#include "vend.h" |
41 |
|
#include "vtcp.h" |
42 |
5520 |
|
43 |
|
static const char h2_resp_101[] = |
44 |
|
"HTTP/1.1 101 Switching Protocols\r\n" |
45 |
|
"Connection: Upgrade\r\n" |
46 |
|
"Upgrade: h2c\r\n" |
47 |
|
"\r\n"; |
48 |
|
|
49 |
|
static const char H2_prism[24] = { |
50 |
|
0x50, 0x52, 0x49, 0x20, 0x2a, 0x20, 0x48, 0x54, |
51 |
|
0x54, 0x50, 0x2f, 0x32, 0x2e, 0x30, 0x0d, 0x0a, |
52 |
|
0x0d, 0x0a, 0x53, 0x4d, 0x0d, 0x0a, 0x0d, 0x0a |
53 |
5520 |
}; |
54 |
|
|
55 |
|
static size_t |
56 |
5520 |
h2_enc_settings(const struct h2_settings *h2s, uint8_t *buf, ssize_t n) |
57 |
|
{ |
58 |
5520 |
uint8_t *p = buf; |
59 |
|
|
60 |
|
#define H2_SETTING(U,l,v,d,...) \ |
61 |
|
if (h2s->l != d) { \ |
62 |
|
n -= 6; \ |
63 |
|
assert(n >= 0); \ |
64 |
5520 |
vbe16enc(p, v); \ |
65 |
|
p += 2; \ |
66 |
|
vbe32enc(p, h2s->l); \ |
67 |
|
p += 4; \ |
68 |
|
} |
69 |
|
#include "tbl/h2_settings.h" |
70 |
|
return (p - buf); |
71 |
|
} |
72 |
|
|
73 |
|
static const struct h2_settings H2_proto_settings = { |
74 |
5520 |
#define H2_SETTING(U,l,v,d,...) . l = d, |
75 |
|
#include "tbl/h2_settings.h" |
76 |
|
}; |
77 |
|
|
78 |
|
static void |
79 |
5680 |
h2_local_settings(struct h2_settings *h2s) |
80 |
|
{ |
81 |
5680 |
*h2s = H2_proto_settings; |
82 |
|
#define H2_SETTINGS_PARAM_ONLY |
83 |
|
#define H2_SETTING(U, l, ...) \ |
84 |
5520 |
h2s->l = cache_param->h2_##l; |
85 |
|
#include "tbl/h2_settings.h" |
86 |
|
#undef H2_SETTINGS_PARAM_ONLY |
87 |
|
h2s->max_header_list_size = cache_param->http_req_size; |
88 |
|
} |
89 |
|
|
90 |
|
void |
91 |
9868 |
H2S_Lock_VSLb(const struct h2_sess *h2, enum VSL_tag_e tag, const char *fmt, ...) |
92 |
|
{ |
93 |
|
va_list ap; |
94 |
9868 |
int held = 0; |
95 |
5520 |
|
96 |
9868 |
AN(h2); |
97 |
|
|
98 |
9868 |
if (VSL_tag_is_masked(tag)) |
99 |
0 |
return; |
100 |
|
|
101 |
9868 |
if (h2->highest_stream > 0) { |
102 |
8948 |
held = 1; |
103 |
8948 |
Lck_Lock(&h2->sess->mtx); |
104 |
8948 |
} |
105 |
|
|
106 |
9868 |
va_start(ap, fmt); |
107 |
9868 |
VSLbv(h2->vsl, tag, fmt, ap); |
108 |
9868 |
va_end(ap); |
109 |
|
|
110 |
9868 |
if (held) |
111 |
8948 |
Lck_Unlock(&h2->sess->mtx); |
112 |
9868 |
} |
113 |
|
|
114 |
|
/********************************************************************** |
115 |
|
* The h2_sess struct needs many of the same things as a request, |
116 |
|
* WS, VSL, HTC &c, but rather than implement all that stuff over, we |
117 |
|
* grab an actual struct req, and mirror the relevant fields into |
118 |
|
* struct h2_sess. |
119 |
|
*/ |
120 |
|
|
121 |
|
static struct h2_sess * |
122 |
5680 |
h2_init_sess(struct sess *sp, |
123 |
|
struct h2_sess *h2s, struct req *srq, struct h2h_decode *decode) |
124 |
|
{ |
125 |
|
uintptr_t *up; |
126 |
|
struct h2_sess *h2; |
127 |
|
|
128 |
|
/* proto_priv session attribute will always have been set up by H1 |
129 |
|
* before reaching here. */ |
130 |
5680 |
AZ(SES_Get_proto_priv(sp, &up)); |
131 |
5680 |
assert(*up == 0); |
132 |
|
|
133 |
5680 |
if (srq == NULL) |
134 |
280 |
srq = Req_New(sp); |
135 |
5680 |
AN(srq); |
136 |
5680 |
h2 = h2s; |
137 |
5680 |
AN(h2); |
138 |
5680 |
INIT_OBJ(h2, H2_SESS_MAGIC); |
139 |
5680 |
h2->srq = srq; |
140 |
5680 |
h2->htc = srq->htc; |
141 |
5680 |
h2->ws = srq->ws; |
142 |
5680 |
h2->vsl = srq->vsl; |
143 |
5680 |
VSL_Flush(h2->vsl, 0); |
144 |
5680 |
h2->vsl->wid = sp->vxid; |
145 |
5680 |
h2->htc->rfd = &sp->fd; |
146 |
5680 |
h2->sess = sp; |
147 |
5680 |
h2->rxthr = pthread_self(); |
148 |
5680 |
PTOK(pthread_cond_init(h2->winupd_cond, NULL)); |
149 |
5680 |
VTAILQ_INIT(&h2->streams); |
150 |
5680 |
VTAILQ_INIT(&h2->txqueue); |
151 |
5680 |
h2_local_settings(&h2->local_settings); |
152 |
5680 |
h2->remote_settings = H2_proto_settings; |
153 |
5680 |
h2->decode = decode; |
154 |
|
|
155 |
5680 |
h2->rapid_reset = cache_param->h2_rapid_reset; |
156 |
5680 |
h2->rapid_reset_limit = cache_param->h2_rapid_reset_limit; |
157 |
5680 |
h2->rapid_reset_period = cache_param->h2_rapid_reset_period; |
158 |
|
|
159 |
5680 |
h2->rst_budget = h2->rapid_reset_limit; |
160 |
5680 |
h2->last_rst = sp->t_open; |
161 |
5680 |
AZ(isnan(h2->last_rst)); |
162 |
|
|
163 |
5680 |
AZ(VHT_Init(h2->dectbl, h2->local_settings.header_table_size)); |
164 |
|
|
165 |
5680 |
*up = (uintptr_t)h2; |
166 |
|
|
167 |
5680 |
return (h2); |
168 |
|
} |
169 |
|
|
170 |
|
static void |
171 |
5396 |
h2_del_sess(struct worker *wrk, struct h2_sess *h2, stream_close_t reason) |
172 |
|
{ |
173 |
|
struct sess *sp; |
174 |
|
struct req *req; |
175 |
|
|
176 |
5396 |
CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC); |
177 |
5396 |
AZ(h2->refcnt); |
178 |
5396 |
assert(VTAILQ_EMPTY(&h2->streams)); |
179 |
5396 |
AN(reason); |
180 |
|
|
181 |
5396 |
VHT_Fini(h2->dectbl); |
182 |
5396 |
PTOK(pthread_cond_destroy(h2->winupd_cond)); |
183 |
5396 |
TAKE_OBJ_NOTNULL(req, &h2->srq, REQ_MAGIC); |
184 |
5396 |
assert(!WS_IsReserved(req->ws)); |
185 |
5396 |
sp = h2->sess; |
186 |
5396 |
Req_Cleanup(sp, wrk, req); |
187 |
5396 |
Req_Release(req); |
188 |
5396 |
SES_Delete(sp, reason, NAN); |
189 |
5396 |
} |
190 |
|
|
191 |
|
/**********************************************************************/ |
192 |
|
|
193 |
|
enum htc_status_e v_matchproto_(htc_complete_f) |
194 |
365093 |
H2_prism_complete(struct http_conn *htc) |
195 |
|
{ |
196 |
|
size_t sz; |
197 |
|
|
198 |
365093 |
CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC); |
199 |
365093 |
sz = sizeof(H2_prism); |
200 |
365093 |
if (htc->rxbuf_b + sz > htc->rxbuf_e) |
201 |
7789 |
sz = htc->rxbuf_e - htc->rxbuf_b; |
202 |
365093 |
if (memcmp(htc->rxbuf_b, H2_prism, sz)) |
203 |
342614 |
return (HTC_S_JUNK); |
204 |
22479 |
return (sz == sizeof(H2_prism) ? HTC_S_COMPLETE : HTC_S_MORE); |
205 |
365093 |
} |
206 |
|
|
207 |
|
|
208 |
|
/********************************************************************** |
209 |
|
* Deal with the base64url (NB: ...url!) encoded SETTINGS in the H1 req |
210 |
|
* of a H2C upgrade. |
211 |
|
*/ |
212 |
|
|
213 |
|
static int |
214 |
280 |
h2_b64url_settings(struct h2_sess *h2, struct req *req) |
215 |
|
{ |
216 |
|
const char *p, *q; |
217 |
|
uint8_t u[6], *up; |
218 |
|
unsigned x; |
219 |
|
int i, n; |
220 |
|
static const char s[] = |
221 |
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
222 |
|
"abcdefghijklmnopqrstuvwxyz" |
223 |
|
"0123456789" |
224 |
|
"-_="; |
225 |
|
|
226 |
|
/* |
227 |
|
* If there is trouble with this, we could reject the upgrade |
228 |
|
* but putting this on the H1 side is just plain wrong... |
229 |
|
*/ |
230 |
280 |
if (!http_GetHdr(req->http, H_HTTP2_Settings, &p)) |
231 |
40 |
return (-1); |
232 |
240 |
AN(p); |
233 |
240 |
VSLb(req->vsl, SLT_Debug, "H2CS %s", p); |
234 |
|
|
235 |
240 |
n = 0; |
236 |
240 |
x = 0; |
237 |
240 |
up = u; |
238 |
3440 |
for (;*p; p++) { |
239 |
3240 |
q = strchr(s, *p); |
240 |
3240 |
if (q == NULL) |
241 |
40 |
return (-1); |
242 |
3200 |
i = q - s; |
243 |
3200 |
assert(i >= 0 && i <= 64); |
244 |
3200 |
x <<= 6; |
245 |
3200 |
x |= i; |
246 |
3200 |
n += 6; |
247 |
3200 |
if (n < 8) |
248 |
800 |
continue; |
249 |
2400 |
*up++ = (uint8_t)(x >> (n - 8)); |
250 |
2400 |
n -= 8; |
251 |
2400 |
if (up == u + sizeof u) { |
252 |
400 |
AZ(n); |
253 |
400 |
if (h2_set_setting(h2, (void*)u)) |
254 |
0 |
return (-1); |
255 |
400 |
up = u; |
256 |
400 |
} |
257 |
2400 |
} |
258 |
200 |
if (up != u) |
259 |
0 |
return (-1); |
260 |
200 |
return (0); |
261 |
280 |
} |
262 |
|
|
263 |
|
|
264 |
|
/**********************************************************************/ |
265 |
|
|
266 |
|
static int |
267 |
80 |
h2_ou_rel(struct worker *wrk, struct req *req) |
268 |
|
{ |
269 |
80 |
CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); |
270 |
80 |
CHECK_OBJ_NOTNULL(req, REQ_MAGIC); |
271 |
80 |
AZ(req->vcl); |
272 |
80 |
Req_AcctLogCharge(wrk->stats, req); |
273 |
80 |
Req_Release(req); |
274 |
80 |
return (0); |
275 |
|
} |
276 |
|
|
277 |
|
static int |
278 |
280 |
h2_ou_session(struct worker *wrk, struct h2_sess *h2, |
279 |
|
struct req *req) |
280 |
|
{ |
281 |
|
ssize_t sz; |
282 |
|
enum htc_status_e hs; |
283 |
|
struct h2_req *r2; |
284 |
|
|
285 |
280 |
if (h2_b64url_settings(h2, req)) { |
286 |
80 |
VSLb(h2->vsl, SLT_Debug, "H2: Bad HTTP-Settings"); |
287 |
80 |
return (h2_ou_rel(wrk, req)); |
288 |
|
} |
289 |
|
|
290 |
200 |
sz = write(h2->sess->fd, h2_resp_101, strlen(h2_resp_101)); |
291 |
200 |
VTCP_Assert(sz); |
292 |
200 |
if (sz != strlen(h2_resp_101)) { |
293 |
0 |
VSLb(h2->vsl, SLT_Debug, "H2: Upgrade: Error writing 101" |
294 |
0 |
" response: %s\n", VAS_errtxt(errno)); |
295 |
0 |
return (h2_ou_rel(wrk, req)); |
296 |
|
} |
297 |
|
|
298 |
200 |
http_Unset(req->http, H_Upgrade); |
299 |
200 |
http_Unset(req->http, H_HTTP2_Settings); |
300 |
|
|
301 |
|
/* Steal pipelined read-ahead, if any */ |
302 |
200 |
h2->htc->pipeline_b = req->htc->pipeline_b; |
303 |
200 |
h2->htc->pipeline_e = req->htc->pipeline_e; |
304 |
200 |
req->htc->pipeline_b = NULL; |
305 |
200 |
req->htc->pipeline_e = NULL; |
306 |
|
/* XXX: This call may assert on buffer overflow if the pipelined |
307 |
|
data exceeds the available space in the ws workspace. What to |
308 |
|
do about the overflowing data is an open issue. */ |
309 |
200 |
HTC_RxInit(h2->htc, h2->ws); |
310 |
|
|
311 |
|
/* Start req thread */ |
312 |
200 |
r2 = h2_new_req(h2, 1, req); |
313 |
200 |
AZ(h2->highest_stream); |
314 |
200 |
h2->highest_stream = r2->stream; |
315 |
200 |
req->transport = &HTTP2_transport; |
316 |
200 |
assert(req->req_step == R_STP_TRANSPORT); |
317 |
200 |
req->task->func = h2_do_req; |
318 |
200 |
req->task->priv = req; |
319 |
200 |
r2->scheduled = 1; |
320 |
200 |
r2->state = H2_S_CLOS_REM; // rfc7540,l,489,491 |
321 |
200 |
req->err_code = 0; |
322 |
200 |
http_SetH(req->http, HTTP_HDR_PROTO, "HTTP/2.0"); |
323 |
|
|
324 |
|
/* Wait for PRISM response */ |
325 |
400 |
hs = HTC_RxStuff(h2->htc, H2_prism_complete, |
326 |
200 |
NULL, NULL, NAN, h2->sess->t_idle + cache_param->timeout_idle, NAN, |
327 |
|
sizeof H2_prism); |
328 |
200 |
if (hs != HTC_S_COMPLETE) { |
329 |
40 |
VSLb(h2->vsl, SLT_Debug, "H2: No/Bad OU PRISM (hs=%d)", hs); |
330 |
40 |
r2->scheduled = 0; |
331 |
40 |
h2_del_req(wrk, r2); |
332 |
40 |
return (0); |
333 |
|
} |
334 |
160 |
if (Pool_Task(wrk->pool, req->task, TASK_QUEUE_REQ)) { |
335 |
40 |
r2->scheduled = 0; |
336 |
40 |
h2_del_req(wrk, r2); |
337 |
40 |
VSLb(h2->vsl, SLT_Debug, "H2: No Worker-threads"); |
338 |
40 |
return (0); |
339 |
|
} |
340 |
120 |
return (1); |
341 |
280 |
} |
342 |
|
|
343 |
|
/********************************************************************** |
344 |
|
*/ |
345 |
|
|
346 |
|
#define H2_PU_MARKER 1 |
347 |
|
#define H2_OU_MARKER 2 |
348 |
|
|
349 |
|
void |
350 |
5399 |
H2_PU_Sess(struct worker *wrk, struct sess *sp, struct req *req) |
351 |
|
{ |
352 |
5399 |
VSLb(req->vsl, SLT_Debug, "H2 Prior Knowledge Upgrade"); |
353 |
5399 |
req->err_code = H2_PU_MARKER; |
354 |
5399 |
SES_SetTransport(wrk, sp, req, &HTTP2_transport); |
355 |
5399 |
} |
356 |
|
|
357 |
|
void |
358 |
280 |
H2_OU_Sess(struct worker *wrk, struct sess *sp, struct req *req) |
359 |
|
{ |
360 |
280 |
VSLb(req->vsl, SLT_Debug, "H2 Optimistic Upgrade"); |
361 |
280 |
req->err_code = H2_OU_MARKER; |
362 |
280 |
SES_SetTransport(wrk, sp, req, &HTTP2_transport); |
363 |
280 |
} |
364 |
|
|
365 |
|
static void v_matchproto_(task_func_t) |
366 |
5680 |
h2_new_session(struct worker *wrk, void *arg) |
367 |
|
{ |
368 |
|
struct req *req; |
369 |
|
struct sess *sp; |
370 |
|
struct h2_sess h2s; |
371 |
|
struct h2_sess *h2; |
372 |
|
struct h2_req *r2, *r22; |
373 |
|
int again; |
374 |
|
uint8_t settings[48]; |
375 |
|
struct h2h_decode decode; |
376 |
|
size_t l; |
377 |
|
|
378 |
5680 |
CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); |
379 |
5680 |
CAST_OBJ_NOTNULL(req, arg, REQ_MAGIC); |
380 |
5680 |
sp = req->sp; |
381 |
5680 |
CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); |
382 |
|
|
383 |
5680 |
if (wrk->wpriv->vcl) |
384 |
735 |
VCL_Rel(&wrk->wpriv->vcl); |
385 |
|
|
386 |
5680 |
assert(req->transport == &HTTP2_transport); |
387 |
|
|
388 |
5680 |
assert (req->err_code == H2_PU_MARKER || req->err_code == H2_OU_MARKER); |
389 |
|
|
390 |
11360 |
h2 = h2_init_sess(sp, &h2s, |
391 |
5680 |
req->err_code == H2_PU_MARKER ? req : NULL, &decode); |
392 |
5680 |
h2->req0 = h2_new_req(h2, 0, NULL); |
393 |
5680 |
AZ(h2->htc->priv); |
394 |
5680 |
h2->htc->priv = h2; |
395 |
|
|
396 |
5680 |
AZ(wrk->vsl); |
397 |
5680 |
wrk->vsl = h2->vsl; |
398 |
|
|
399 |
5680 |
if (req->err_code == H2_OU_MARKER && !h2_ou_session(wrk, h2, req)) { |
400 |
160 |
assert(h2->refcnt == 1); |
401 |
160 |
h2_del_req(wrk, h2->req0); |
402 |
160 |
h2_del_sess(wrk, h2, SC_RX_JUNK); |
403 |
160 |
wrk->vsl = NULL; |
404 |
160 |
return; |
405 |
|
} |
406 |
5520 |
assert(HTC_S_COMPLETE == H2_prism_complete(h2->htc)); |
407 |
5520 |
HTC_RxPipeline(h2->htc, h2->htc->rxbuf_b + sizeof(H2_prism)); |
408 |
5520 |
HTC_RxInit(h2->htc, h2->ws); |
409 |
5520 |
AN(WS_Reservation(h2->ws)); |
410 |
5520 |
VSLb(h2->vsl, SLT_Debug, "H2: Got pu PRISM"); |
411 |
|
|
412 |
5520 |
THR_SetRequest(h2->srq); |
413 |
5520 |
AN(WS_Reservation(h2->ws)); |
414 |
|
|
415 |
5520 |
l = h2_enc_settings(&h2->local_settings, settings, sizeof (settings)); |
416 |
5520 |
AN(WS_Reservation(h2->ws)); |
417 |
5520 |
H2_Send_Get(wrk, h2, h2->req0); |
418 |
5520 |
AN(WS_Reservation(h2->ws)); |
419 |
11040 |
H2_Send_Frame(wrk, h2, |
420 |
5520 |
H2_F_SETTINGS, H2FF_NONE, l, 0, settings); |
421 |
5520 |
AN(WS_Reservation(h2->ws)); |
422 |
5520 |
H2_Send_Rel(h2, h2->req0); |
423 |
5520 |
AN(WS_Reservation(h2->ws)); |
424 |
|
|
425 |
|
/* and off we go... */ |
426 |
5520 |
h2->cond = &wrk->cond; |
427 |
|
|
428 |
41220 |
while (h2_rxframe(wrk, h2)) { |
429 |
35700 |
HTC_RxInit(h2->htc, h2->ws); |
430 |
35700 |
if (WS_Overflowed(h2->ws)) { |
431 |
0 |
H2S_Lock_VSLb(h2, SLT_SessError, "H2: Empty Rx Workspace"); |
432 |
0 |
h2->error = H2CE_INTERNAL_ERROR; |
433 |
0 |
break; |
434 |
|
} |
435 |
35700 |
AN(WS_Reservation(h2->ws)); |
436 |
|
} |
437 |
|
|
438 |
5520 |
AN(h2->error); |
439 |
|
|
440 |
|
/* Delete all idle streams */ |
441 |
5520 |
Lck_Lock(&h2->sess->mtx); |
442 |
5520 |
VSLb(h2->vsl, SLT_Debug, "H2 CLEANUP %s", h2->error->name); |
443 |
14500 |
VTAILQ_FOREACH(r2, &h2->streams, list) { |
444 |
8980 |
if (r2->error == 0) |
445 |
8358 |
r2->error = h2->error; |
446 |
8980 |
if (r2->cond != NULL) |
447 |
164 |
PTOK(pthread_cond_signal(r2->cond)); |
448 |
8980 |
} |
449 |
5520 |
PTOK(pthread_cond_broadcast(h2->winupd_cond)); |
450 |
5520 |
Lck_Unlock(&h2->sess->mtx); |
451 |
9201 |
while (1) { |
452 |
9201 |
again = 0; |
453 |
23313 |
VTAILQ_FOREACH_SAFE(r2, &h2->streams, list, r22) { |
454 |
14112 |
if (r2 != h2->req0) { |
455 |
5195 |
h2_kill_req(wrk, h2, r2, h2->error); |
456 |
5195 |
again++; |
457 |
5195 |
} |
458 |
14112 |
} |
459 |
9201 |
if (!again) |
460 |
5520 |
break; |
461 |
3681 |
Lck_Lock(&h2->sess->mtx); |
462 |
9057 |
VTAILQ_FOREACH(r2, &h2->streams, list) |
463 |
10752 |
VSLb(h2->vsl, SLT_Debug, "ST %u %d", |
464 |
5376 |
r2->stream, r2->state); |
465 |
3681 |
(void)Lck_CondWaitTimeout(h2->cond, &h2->sess->mtx, .1); |
466 |
3681 |
Lck_Unlock(&h2->sess->mtx); |
467 |
|
} |
468 |
5520 |
h2->cond = NULL; |
469 |
5520 |
assert(h2->refcnt == 1); |
470 |
5520 |
h2_del_req(wrk, h2->req0); |
471 |
5520 |
h2_del_sess(wrk, h2, h2->error->reason); |
472 |
5520 |
wrk->vsl = NULL; |
473 |
5680 |
} |
474 |
|
|
475 |
|
static int v_matchproto_(vtr_poll_f) |
476 |
15201 |
h2_poll(struct req *req) |
477 |
|
{ |
478 |
|
struct h2_req *r2; |
479 |
|
|
480 |
15201 |
CHECK_OBJ_NOTNULL(req, REQ_MAGIC); |
481 |
15201 |
CAST_OBJ_NOTNULL(r2, req->transport_priv, H2_REQ_MAGIC); |
482 |
15201 |
return (r2->error ? -1 : 1); |
483 |
|
} |
484 |
|
|
485 |
|
struct transport HTTP2_transport = { |
486 |
|
.name = "HTTP/2", |
487 |
|
.magic = TRANSPORT_MAGIC, |
488 |
|
.deliver = h2_deliver, |
489 |
|
.minimal_response = h2_minimal_response, |
490 |
|
.new_session = h2_new_session, |
491 |
|
.req_body = h2_req_body, |
492 |
|
.req_fail = h2_req_fail, |
493 |
|
.sess_panic = h2_sess_panic, |
494 |
|
.poll = h2_poll, |
495 |
|
}; |