1 /*-
2  * Copyright (c) 2008-2016 Varnish Software AS
3  * All rights reserved.
4  *
5  * Author: Guillaume Quintard <guillaume.quintard@gmail.com>
6  *
7  * SPDX-License-Identifier: BSD-2-Clause
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 
31 #include "config.h"
32 
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 
36 #include <math.h>
37 #include <poll.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <unistd.h>
41 #include <string.h>
42 #include <netinet/in.h>
43 
44 #include "vtc.h"
45 #include "vtc_http.h"
46 
47 #include "vfil.h"
48 #include "hpack.h"
49 #include "vend.h"
50 
51 #define ERR_MAX		13
52 #define BUF_SIZE	(1024*2048)
53 
54 static const char *const h2_errs[] = {
55 #define H2_ERROR(n,v,sc,r,t) [v] = #n,
56 #include <tbl/h2_error.h>
57 	NULL
58 };
59 
60 static const char *const h2_types[] = {
61 #define H2_FRAME(l,u,t,f,...) [t] = #u,
62 #include <tbl/h2_frames.h>
63 	NULL
64 };
65 
66 static const char * const h2_settings[] = {
67 	[0] = "unknown",
68 #define H2_SETTING(U,l,v,...) [v] = #U,
69 #include <tbl/h2_settings.h>
70 	NULL
71 };
72 
73 #define SETTINGS_MAX (sizeof(h2_settings)/sizeof(h2_settings[0]) - 1U)
74 
75 
76 enum h2_type {
77 #define H2_FRAME(l,u,t,f,...) TYPE_##u = t,
78 #include <tbl/h2_frames.h>
79 	TYPE_MAX
80 };
81 
82 //lint -save -e849	Same enum value
83 enum {
84 	ACK = 0x1,
85 	END_STREAM = 0x1,
86 	PADDED = 0x8,
87 	END_HEADERS = 0x4,
88 	PRIORITY = 0x20,
89 };
90 //lint -restore
91 
92 struct stream {
93 	unsigned		magic;
94 #define STREAM_MAGIC		0x63f1fac2
95 	uint32_t		id;
96 	struct vtclog		*vl;
97 	char			*spec;
98 	char			*name;
99 	VTAILQ_ENTRY(stream)    list;
100 	unsigned		running;
101 	pthread_cond_t		cond;
102 	struct frame		*frame;
103 	pthread_t		tp;
104 	struct http		*hp;
105 	int64_t			ws;
106 	int			wf;
107 
108 	VTAILQ_HEAD(, frame)   fq;
109 
110 	char			*body;
111 	long			bodylen;
112 	struct hpk_hdr		req[MAX_HDR];
113 	struct hpk_hdr		resp[MAX_HDR];
114 
115 	int			dependency;
116 	int			weight;
117 };
118 
119 static void
clean_headers(struct hpk_hdr * h)120 clean_headers(struct hpk_hdr *h)
121 {
122 	unsigned n = MAX_HDR;
123 
124 	while (h->t && n > 0) {
125 		if (h->key.len)
126 			free(h->key.ptr);
127 		if (h->value.len)
128 			free(h->value.ptr);
129 		memset(h, 0, sizeof(*h));
130 		h++;
131 		n--;
132 	}
133 }
134 
135 #define ONLY_H2_CLIENT(hp, av)						\
136 	do {								\
137 		if (hp->sfd != NULL)					\
138 			vtc_fatal(s->vl,				\
139 			    "\"%s\" only possible in client", av[0]);	\
140 	} while (0)
141 
142 #define ONLY_H2_SERVER(hp, av)						\
143 	do {								\
144 		if (hp->sfd == NULL)					\
145 			vtc_fatal(s->vl,				\
146 			    "\"%s\" only possible in server", av[0]);	\
147 	} while (0)
148 
149 static void
http_write(const struct http * hp,int lvl,const char * buf,int s,const char * pfx)150 http_write(const struct http *hp, int lvl,
151     const char *buf, int s, const char *pfx)
152 {
153 	ssize_t l;
154 
155 	CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
156 	AN(buf);
157 	AN(pfx);
158 
159 	vtc_dump(hp->vl, lvl, pfx, buf, s);
160 	l = write(hp->sess->fd, buf, s);
161 	if (l != s)
162 		vtc_log(hp->vl, hp->fatal, "Write failed: (%zd vs %d) %s",
163 		    l, s, strerror(errno));
164 }
165 
166 static int
get_bytes(const struct http * hp,char * buf,int n)167 get_bytes(const struct http *hp, char *buf, int n)
168 {
169 	int i;
170 	struct pollfd pfd[1];
171 
172 	CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
173 	AN(buf);
174 
175 	while (n > 0) {
176 		pfd[0].fd = hp->sess->fd;
177 		pfd[0].events = POLLIN;
178 		pfd[0].revents = 0;
179 		i = poll(pfd, 1, hp->timeout);
180 		if (i < 0 && errno == EINTR)
181 			continue;
182 		if (i == 0)
183 			vtc_log(hp->vl, 3,
184 			    "HTTP2 rx timeout (fd:%d %u ms)",
185 			    hp->sess->fd, hp->timeout);
186 		if (i < 0)
187 			vtc_log(hp->vl, 3,
188 			    "HTTP2 rx failed (fd:%d poll: %s)",
189 			    hp->sess->fd, strerror(errno));
190 		if (i <= 0)
191 			return (i);
192 		i = read(hp->sess->fd, buf, n);
193 		if (!(pfd[0].revents & POLLIN))
194 			vtc_log(hp->vl, 4,
195 			    "HTTP2 rx poll (fd:%d revents: %x n=%d, i=%d)",
196 			    hp->sess->fd, pfd[0].revents, n, i);
197 		if (i == 0)
198 			vtc_log(hp->vl, 3,
199 			    "HTTP2 rx EOF (fd:%d read: %s)",
200 			    hp->sess->fd, strerror(errno));
201 		if (i < 0)
202 			vtc_log(hp->vl, 3,
203 			    "HTTP2 rx failed (fd:%d read: %s)",
204 			    hp->sess->fd, strerror(errno));
205 		if (i <= 0)
206 			return (i);
207 		n -= i;
208 	}
209 	return (1);
210 
211 }
212 
213 VTAILQ_HEAD(fq_head, frame);
214 
215 struct frame {
216 	unsigned	magic;
217 #define	FRAME_MAGIC	0x5dd3ec4
218 	uint32_t	size;
219 	uint32_t	stid;
220 	uint8_t		type;
221 	uint8_t		flags;
222 	char		*data;
223 
224 	VTAILQ_ENTRY(frame)    list;
225 
226 	union {
227 		struct {
228 			uint32_t stream;
229 			uint8_t  exclusive;
230 			uint8_t  weight;
231 		}		prio;
232 		uint32_t	rst_err;
233 		double settings[SETTINGS_MAX+1];
234 		struct {
235 			char data[9];
236 			int ack;
237 		}		ping;
238 		struct {
239 			uint32_t err;
240 			uint32_t stream;
241 			char	 *debug;
242 		}		goaway;
243 		uint32_t	winup_size;
244 		uint32_t	promised;
245 		uint8_t		padded;
246 	} md;
247 };
248 
249 static void
readFrameHeader(struct frame * f,const char * buf)250 readFrameHeader(struct frame *f, const char *buf)
251 {
252 	CHECK_OBJ_NOTNULL(f, FRAME_MAGIC);
253 	AN(buf);
254 
255 	f->size  = (unsigned char)buf[0] << 16;
256 	f->size += (unsigned char)buf[1] << 8;
257 	f->size += (unsigned char)buf[2];
258 
259 	f->type = (unsigned char)buf[3];
260 
261 	f->flags = (unsigned char)buf[4];
262 
263 	f->stid  = vbe32dec(buf+5);
264 }
265 
266 static void
writeFrameHeader(char * buf,const struct frame * f)267 writeFrameHeader(char *buf, const struct frame *f)
268 {
269 	CHECK_OBJ_NOTNULL(f, FRAME_MAGIC);
270 	AN(buf);
271 	buf[0] = (f->size >> 16) & 0xff;
272 	buf[1] = (f->size >>  8) & 0xff;
273 	buf[2] = (f->size      ) & 0xff;
274 
275 	buf[3] = f->type;
276 
277 	buf[4] = f->flags;
278 
279 	vbe32enc(buf + 5, f->stid);
280 }
281 
282 #define INIT_FRAME(f, ty, sz, id, fl) \
283 do { \
284 	f.magic = FRAME_MAGIC; \
285 	f.type = TYPE_ ## ty; \
286 	f.size = sz; \
287 	f.stid = id; \
288 	f.flags = fl; \
289 	f.data = NULL; \
290 } while(0)
291 
292 static void
replace_frame(struct frame ** fp,struct frame * new)293 replace_frame(struct frame **fp, struct frame *new)
294 {
295 	struct frame *old;
296 
297 	AN(fp);
298 	CHECK_OBJ_ORNULL(new, FRAME_MAGIC);
299 
300 	old = *fp;
301 	*fp = new;
302 	if (old == NULL)
303 		return;
304 
305 	CHECK_OBJ(old, FRAME_MAGIC);
306 	if (old->type == TYPE_GOAWAY)
307 		free(old->md.goaway.debug);
308 	free(old->data);
309 	FREE_OBJ(old);
310 }
311 
312 static void
clean_frame(struct frame ** fp)313 clean_frame(struct frame **fp)
314 {
315 
316 	replace_frame(fp, NULL);
317 }
318 
319 static void
write_frame(const struct stream * sp,const struct frame * f,const unsigned lock)320 write_frame(const struct stream *sp, const struct frame *f, const unsigned lock)
321 {
322 	struct http *hp;
323 	ssize_t l;
324 	char hdr[9];
325 
326 	CHECK_OBJ_NOTNULL(sp, STREAM_MAGIC);
327 	hp = sp->hp;
328 	CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
329 	CHECK_OBJ_NOTNULL(f, FRAME_MAGIC);
330 
331 	writeFrameHeader(hdr, f);
332 
333 	vtc_log(sp->vl, 3, "tx: stream: %d, type: %s (%d), "
334 			"flags: 0x%02x, size: %d",
335 			f->stid,
336 			f->type < TYPE_MAX ? h2_types[f->type] : "?",
337 			f->type, f->flags, f->size);
338 
339 	if (lock)
340 		AZ(pthread_mutex_lock(&hp->mtx));
341 	l = write(hp->sess->fd, hdr, sizeof(hdr));
342 	if (l != sizeof(hdr))
343 		vtc_log(sp->vl, hp->fatal, "Write failed: (%zd vs %zd) %s",
344 		    l, sizeof(hdr), strerror(errno));
345 
346 	if (f->size) {
347 		AN(f->data);
348 		l = write(hp->sess->fd, f->data, f->size);
349 		if (l != f->size)
350 			vtc_log(sp->vl, hp->fatal,
351 					"Write failed: (%zd vs %d) %s",
352 					l, f->size, strerror(errno));
353 	}
354 	if (lock)
355 		AZ(pthread_mutex_unlock(&hp->mtx));
356 }
357 
358 static void
exclusive_stream_dependency(const struct stream * s)359 exclusive_stream_dependency(const struct stream *s)
360 {
361 	struct stream *target;
362 	struct http *hp = s->hp;
363 
364 	if (s->id == 0)
365 		return;
366 
367 	VTAILQ_FOREACH(target, &hp->streams, list) {
368 		if (target->id != s->id && target->dependency == s->dependency)
369 			target->dependency = s->id;
370 	}
371 }
372 
373 static void
explain_flags(uint8_t flags,uint8_t type,struct vtclog * vl)374 explain_flags(uint8_t flags, uint8_t type, struct vtclog *vl)
375 {
376 	if (flags & ACK && (type == TYPE_PING || type == TYPE_SETTINGS)) {
377 		vtc_log(vl, 3, "flag: ACK");
378 	} else if (flags & END_STREAM && (type == TYPE_HEADERS ||
379 	    type == TYPE_PUSH_PROMISE || type == TYPE_DATA)) {
380 		vtc_log(vl, 3, "flag: END_STREAM");
381 	} else if (flags & END_HEADERS && (type == TYPE_HEADERS ||
382 	    type == TYPE_PUSH_PROMISE || type == TYPE_CONTINUATION)) {
383 		vtc_log(vl, 3, "flag: END_TYPE_HEADERS");
384 	} else if (flags & PRIORITY && (type == TYPE_HEADERS ||
385 	    type == TYPE_PUSH_PROMISE)) {
386 		vtc_log(vl, 3, "flag: END_PRIORITY");
387 	} else if (flags & PADDED && (type == TYPE_DATA || type ==
388 	    TYPE_HEADERS || type == TYPE_PUSH_PROMISE)) {
389 		vtc_log(vl, 3, "flag: PADDED");
390 	} else if (flags)
391 		vtc_log(vl, 3, "UNKNOWN FLAG(S): 0x%02x", flags);
392 }
393 
394 static void
parse_data(struct stream * s,struct frame * f)395 parse_data(struct stream *s, struct frame *f)
396 {
397 	struct http *hp;
398 	uint32_t size = f->size;
399 	char *data = f->data;
400 
401 	CHECK_OBJ_NOTNULL(f, FRAME_MAGIC);
402 	CHECK_OBJ_NOTNULL(s, STREAM_MAGIC);
403 	CAST_OBJ_NOTNULL(hp, s->hp, HTTP_MAGIC);;
404 
405 	if (f->flags & PADDED) {
406 		f->md.padded = *((uint8_t *)data);
407 		if (f->md.padded >= size) {
408 			vtc_log(s->vl, hp->fatal,
409 					"invalid padding: %d reported,"
410 					"but size is only %d",
411 					f->md.padded, size);
412 			size = 0;
413 			f->md.padded = 0;
414 		}
415 		data++;
416 		size -= f->md.padded + 1;
417 		vtc_log(s->vl, 4, "padding: %3d", f->md.padded);
418 	}
419 
420 	if (s->id)
421 		s->ws -= size;
422 
423 	s->hp->ws -= size;
424 
425 	if (!size) {
426 		AZ(data);
427 		vtc_log(s->vl, 4, "s%u - no data", s->id);
428 		return;
429 	}
430 
431 	s->body = realloc(s->body, s->bodylen + size + 1L);
432 	AN(s->body);
433 	memcpy(s->body + s->bodylen, data, size);
434 	s->bodylen += size;
435 	s->body[s->bodylen] = '\0';
436 }
437 
438 static void
decode_hdr(struct http * hp,struct hpk_hdr * h,const struct vsb * vsb)439 decode_hdr(struct http *hp, struct hpk_hdr *h, const struct vsb *vsb)
440 {
441 	struct hpk_iter *iter;
442 	enum hpk_result r = hpk_err;
443 	int n;
444 
445 	CHECK_OBJ_NOTNULL(vsb, VSB_MAGIC);
446 	CAST_OBJ_NOTNULL(hp, hp, HTTP_MAGIC);;
447 
448 	if (VSB_len(vsb) == 0)
449 		return;
450 
451 	iter = HPK_NewIter(hp->decctx, VSB_data(vsb), VSB_len(vsb));
452 
453 	n = 0;
454 	while (n < MAX_HDR && h[n].t)
455 		n++;
456 	while (n < MAX_HDR) {
457 		r = HPK_DecHdr(iter, h + n);
458 		if (r == hpk_err )
459 			break;
460 		vtc_log(hp->vl, 4,
461 				"header[%2d]: %s : %s",
462 				n,
463 				h[n].key.ptr,
464 				h[n].value.ptr);
465 		n++;
466 		if (r == hpk_done)
467 			break;
468 	}
469 
470 	if (r != hpk_done)
471 		vtc_log(hp->vl, hp->fatal ? 4 : 0,
472 				"Header decoding failed (%d) %d", r, hp->fatal);
473 	else if (n == MAX_HDR)
474 		vtc_log(hp->vl, hp->fatal,
475 				"Max number of headers reached (%d)", MAX_HDR);
476 
477 	HPK_FreeIter(iter);
478 }
479 
480 static void
parse_hdr(struct stream * s,struct frame * f,struct vsb * vsb)481 parse_hdr(struct stream *s, struct frame *f, struct vsb *vsb)
482 {
483 	int shift = 0;
484 	int exclusive = 0;
485 	uint32_t size = f->size;
486 	char *data = f->data;
487 	struct http *hp;
488 	uint32_t n;
489 
490 	CHECK_OBJ_NOTNULL(f, FRAME_MAGIC);
491 	CHECK_OBJ_NOTNULL(s, STREAM_MAGIC);
492 	CHECK_OBJ_NOTNULL(vsb, VSB_MAGIC);
493 	CAST_OBJ_NOTNULL(hp, s->hp, HTTP_MAGIC);;
494 
495 	if (f->flags & PADDED && f->type != TYPE_CONTINUATION) {
496 		f->md.padded = *((uint8_t *)data);
497 		if (f->md.padded >= size) {
498 			vtc_log(s->vl, hp->fatal,
499 					"invalid padding: %d reported,"
500 					"but size is only %d",
501 					f->md.padded, size);
502 			size = 0;
503 			f->md.padded = 0;
504 		}
505 		shift += 1;
506 		size -= f->md.padded;
507 		vtc_log(s->vl, 4, "padding: %3d", f->md.padded);
508 	}
509 
510 	if (f->type == TYPE_HEADERS && f->flags & PRIORITY){
511 		shift += 5;
512 		n = vbe32dec(f->data);
513 		s->dependency = n & ~(1U << 31);
514 		exclusive = n >> 31;
515 
516 		s->weight = f->data[4];
517 		if (exclusive)
518 			exclusive_stream_dependency(s);
519 
520 		vtc_log(s->vl, 4, "stream->dependency: %u", s->dependency);
521 		vtc_log(s->vl, 4, "stream->weight: %u", s->weight);
522 	} else if (f->type == TYPE_PUSH_PROMISE){
523 		shift += 4;
524 		n = vbe32dec(f->data);
525 		f->md.promised = n & ~(1U << 31);
526 	}
527 
528 	AZ(VSB_bcat(vsb, data + shift, size - shift));
529 }
530 
531 static void
parse_prio(struct stream * s,struct frame * f)532 parse_prio(struct stream *s, struct frame *f)
533 {
534 	struct http *hp;
535 	char *buf;
536 	uint32_t n;
537 
538 	CHECK_OBJ_NOTNULL(f, FRAME_MAGIC);
539 	CHECK_OBJ_NOTNULL(s, STREAM_MAGIC);
540 	CAST_OBJ_NOTNULL(hp, s->hp, HTTP_MAGIC);;
541 
542 	if (f->size != 5)
543 		vtc_fatal(s->vl, "Size should be 5, but isn't (%d)", f->size);
544 
545 	buf = f->data;
546 	AN(buf);
547 
548 	n = vbe32dec(f->data);
549 	f->md.prio.stream = n & ~(1U << 31);
550 
551 	s->dependency = f->md.prio.stream;
552 	if (n >> 31){
553 		f->md.prio.exclusive = 1;
554 		exclusive_stream_dependency(s);
555 	}
556 
557 	buf += 4;
558 	f->md.prio.weight = *buf;
559 	s->weight = f->md.prio.weight;
560 
561 	vtc_log(s->vl, 3, "prio->stream: %u", f->md.prio.stream);
562 	vtc_log(s->vl, 3, "prio->weight: %u", f->md.prio.weight);
563 }
564 
565 static void
parse_rst(const struct stream * s,struct frame * f)566 parse_rst(const struct stream *s, struct frame *f)
567 {
568 	struct http *hp;
569 	uint32_t err;
570 	const char *buf;
571 	CHECK_OBJ_NOTNULL(f, FRAME_MAGIC);
572 	CHECK_OBJ_NOTNULL(s, STREAM_MAGIC);
573 	CAST_OBJ_NOTNULL(hp, s->hp, HTTP_MAGIC);;
574 
575 	if (f->size != 4)
576 		vtc_fatal(s->vl, "Size should be 4, but isn't (%d)", f->size);
577 
578 	err = vbe32dec(f->data);
579 	f->md.rst_err = err;
580 
581 	vtc_log(s->vl, 2, "ouch");
582 	if (err <= ERR_MAX)
583 		buf = h2_errs[err];
584 	else
585 		buf = "unknown";
586 	vtc_log(s->vl, 4, "rst->err: %s (%d)", buf, err);
587 
588 }
589 
590 static void
parse_settings(const struct stream * s,struct frame * f)591 parse_settings(const struct stream *s, struct frame *f)
592 {
593 	struct http *hp;
594 	int v;
595 	unsigned u, t;
596 	const char *buf;
597 	enum hpk_result r;
598 	CHECK_OBJ_NOTNULL(f, FRAME_MAGIC);
599 	CHECK_OBJ_NOTNULL(s, STREAM_MAGIC);
600 	CAST_OBJ_NOTNULL(hp, s->hp, HTTP_MAGIC);;
601 
602 	if (f->size % 6)
603 		vtc_fatal(s->vl,
604 		    "Size should be a multiple of 6, but isn't (%d)", f->size);
605 
606 	for (u = 0; u <= SETTINGS_MAX; u++)
607 		f->md.settings[u] = NAN;
608 
609 	for (u = 0; u < f->size;) {
610 		t = vbe16dec(f->data + u);
611 		u += 2;
612 		v = vbe32dec(f->data + u);
613 		if (t <= SETTINGS_MAX) {
614 			buf = h2_settings[t];
615 			f->md.settings[t] = v;
616 		} else
617 			buf = "unknown";
618 		u += 4;
619 
620 		if (t == 1) {
621 			r = HPK_ResizeTbl(s->hp->encctx, v);
622 			assert(r == hpk_done);
623 		}
624 
625 		vtc_log(s->vl, 4, "settings->%s (%u): %d", buf, t, v);
626 	}
627 
628 }
629 
630 static void
parse_ping(const struct stream * s,struct frame * f)631 parse_ping(const struct stream *s, struct frame *f)
632 {
633 	struct http *hp;
634 	CHECK_OBJ_NOTNULL(f, FRAME_MAGIC);
635 	CHECK_OBJ_NOTNULL(s, STREAM_MAGIC);
636 	CAST_OBJ_NOTNULL(hp, s->hp, HTTP_MAGIC);;
637 	if (f->size != 8)
638 		vtc_fatal(s->vl, "Size should be 8, but isn't (%d)", f->size);
639 	f->md.ping.ack = f->flags & ACK;
640 	memcpy(f->md.ping.data, f->data, 8);
641 	f->md.ping.data[8] = '\0';
642 
643 	vtc_log(s->vl, 4, "ping->data: %s", f->md.ping.data);
644 
645 }
646 
647 static void
parse_goaway(const struct stream * s,struct frame * f)648 parse_goaway(const struct stream *s, struct frame *f)
649 {
650 	struct http *hp;
651 	const char *err_buf;
652 	uint32_t err, stid;
653 	CHECK_OBJ_NOTNULL(f, FRAME_MAGIC);
654 	CHECK_OBJ_NOTNULL(s, STREAM_MAGIC);
655 	CAST_OBJ_NOTNULL(hp, s->hp, HTTP_MAGIC);;
656 
657 	if (f->size < 8)
658 		vtc_fatal(s->vl,
659 		    "Size should be at least 8, but isn't (%d)", f->size);
660 	if (f->data[0] & (1<<7))
661 		vtc_fatal(s->vl,
662 		    "First bit of data is reserved and should be 0");
663 
664 	stid = vbe32dec(f->data);
665 	err = vbe32dec(f->data + 4);
666 	f->md.goaway.err = err;
667 	f->md.goaway.stream = stid;
668 
669 	if (err <= ERR_MAX)
670 		err_buf = h2_errs[err];
671 	else
672 		err_buf = "unknown";
673 
674 	if (f->size > 8) {
675 		f->md.goaway.debug = malloc((f->size - 8) + 1L);
676 		AN(f->md.goaway.debug);
677 		f->md.goaway.debug[f->size - 8] = '\0';
678 
679 		memcpy(f->md.goaway.debug, f->data + 8, f->size - 8);
680 	}
681 
682 	vtc_log(s->vl, 3, "goaway->laststream: %d", stid);
683 	vtc_log(s->vl, 3, "goaway->err: %s (%d)", err_buf, err);
684 	if (f->md.goaway.debug)
685 		vtc_log(s->vl, 3, "goaway->debug: %s", f->md.goaway.debug);
686 }
687 
688 static void
parse_winup(const struct stream * s,struct frame * f)689 parse_winup(const struct stream *s, struct frame *f)
690 {
691 	struct http *hp;
692 	uint32_t size;
693 	CHECK_OBJ_NOTNULL(f, FRAME_MAGIC);
694 	CHECK_OBJ_NOTNULL(s, STREAM_MAGIC);
695 	CAST_OBJ_NOTNULL(hp, s->hp, HTTP_MAGIC);;
696 
697 	if (f->size != 4)
698 		vtc_fatal(s->vl, "Size should be 4, but isn't (%d)", f->size);
699 	if (f->data[0] & (1<<7))
700 		vtc_log(s->vl, s->hp->fatal,
701 		    "First bit of data is reserved and should be 0");
702 
703 	size = vbe32dec(f->data);
704 	f->md.winup_size = size;
705 
706 	vtc_log(s->vl, 3, "winup->size: %d", size);
707 }
708 
709 /* read a frame and queue it in the relevant stream, wait if not present yet.
710  */
711 static void *
receive_frame(void * priv)712 receive_frame(void *priv)
713 {
714 	struct http *hp;
715 	char hdr[9];
716 	struct frame *f;
717 	struct stream *s;
718 	int expect_cont = 0;
719 	struct vsb *vsb = NULL;
720 	struct hpk_hdr *hdrs = NULL;
721 
722 	CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC);
723 
724 	AZ(pthread_mutex_lock(&hp->mtx));
725 	while (hp->h2) {
726 		/*no wanted frames? */
727 		assert(hp->wf >= 0);
728 		if (hp->wf == 0) {
729 			AZ(pthread_cond_wait(&hp->cond, &hp->mtx));
730 			continue;
731 		}
732 		AZ(pthread_mutex_unlock(&hp->mtx));
733 
734 		if (get_bytes(hp, hdr, sizeof hdr) <= 0) {
735 			AZ(pthread_mutex_lock(&hp->mtx));
736 			VTAILQ_FOREACH(s, &hp->streams, list)
737 				AZ(pthread_cond_signal(&s->cond));
738 			AZ(pthread_mutex_unlock(&hp->mtx));
739 			vtc_log(hp->vl, hp->fatal,
740 			    "could not get frame header");
741 			return (NULL);
742 		}
743 		ALLOC_OBJ(f, FRAME_MAGIC);
744 		AN(f);
745 		readFrameHeader(f, hdr);
746 
747 		vtc_log(hp->vl, 3, "rx: stream: %d, type: %s (%d), "
748 				"flags: 0x%02x, size: %d",
749 				f->stid,
750 				f->type < TYPE_MAX ? h2_types[f->type] : "?",
751 				f->type, f->flags, f->size);
752 		explain_flags(f->flags, f->type, hp->vl);
753 
754 		if (f->size) {
755 			f->data = malloc(f->size + 1L);
756 			AN(f->data);
757 			f->data[f->size] = '\0';
758 			if (get_bytes(hp, f->data, f->size) <= 0) {
759 				AZ(pthread_mutex_lock(&hp->mtx));
760 				VTAILQ_FOREACH(s, &hp->streams, list)
761 					AZ(pthread_cond_signal(&s->cond));
762 				clean_frame(&f);
763 				AZ(pthread_mutex_unlock(&hp->mtx));
764 				vtc_log(hp->vl, hp->fatal,
765 				    "could not get frame body");
766 				return (NULL);
767 			}
768 		}
769 
770 		/* is the corresponding stream waiting? */
771 		AZ(pthread_mutex_lock(&hp->mtx));
772 		s = NULL;
773 		while (!s) {
774 			VTAILQ_FOREACH(s, &hp->streams, list)
775 				if (s->id == f->stid)
776 					break;
777 			if (!s)
778 				AZ(pthread_cond_wait(&hp->cond, &hp->mtx));
779 			if (!hp->h2) {
780 				clean_frame(&f);
781 				AZ(pthread_mutex_unlock(&hp->mtx));
782 				return (NULL);
783 			}
784 		}
785 		AZ(pthread_mutex_unlock(&hp->mtx));
786 
787 		AN(s);
788 		if (expect_cont &&
789 		    (f->type != TYPE_CONTINUATION || expect_cont != s->id))
790 			vtc_fatal(s->vl, "Expected CONTINUATION frame for "
791 			    "stream %u", expect_cont);
792 
793 		/* parse the frame according to it type, and fill the metada */
794 		switch (f->type) {
795 			case TYPE_DATA:
796 				parse_data(s, f);
797 				break;
798 			case TYPE_PUSH_PROMISE:
799 				hdrs = s->req;
800 				/*FALLTHROUGH*/
801 			case TYPE_HEADERS:
802 				if (!hdrs) {
803 					if (hp->sfd)
804 						hdrs = s->req;
805 					else
806 						hdrs = s->resp;
807 				}
808 				clean_headers(hdrs);
809 				hdrs[0].t = hpk_unset;
810 				AZ(vsb);
811 				vsb = VSB_new_auto();
812 				/*FALLTHROUGH*/
813 			case TYPE_CONTINUATION:
814 				AN(hdrs);
815 				expect_cont = s->id;
816 				parse_hdr(s, f, vsb);
817 				if (f->flags & END_HEADERS) {
818 					expect_cont = 0;
819 					AZ(VSB_finish(vsb));
820 					decode_hdr(hp, hdrs, vsb);
821 					VSB_destroy(&vsb);
822 					hdrs = NULL;
823 				}
824 				break;
825 			case TYPE_PRIORITY:
826 				parse_prio(s, f);
827 				break;
828 			case TYPE_RST_STREAM:
829 				parse_rst(s, f);
830 				break;
831 			case TYPE_SETTINGS:
832 				parse_settings(s, f);
833 				break;
834 			case TYPE_PING:
835 				parse_ping(s, f);
836 				break;
837 			case TYPE_GOAWAY:
838 				parse_goaway(s, f);
839 				break;
840 			case TYPE_WINDOW_UPDATE:
841 				parse_winup(s, f);
842 				break;
843 			default:
844 				WRONG("wrong frame type");
845 		}
846 
847 		AZ(pthread_mutex_lock(&hp->mtx));
848 		VTAILQ_INSERT_HEAD(&s->fq, f, list);
849 		if (s->wf) {
850 			assert(hp->wf > 0);
851 			hp->wf--;
852 			s->wf = 0;
853 			AZ(pthread_cond_signal(&s->cond));
854 		}
855 		continue;
856 	}
857 	AZ(pthread_mutex_unlock(&hp->mtx));
858 	if (vsb != NULL)
859 		VSB_destroy(&vsb);
860 	return (NULL);
861 }
862 
863 #define STRTOU32(n, ss, p, v, c)					\
864 	do {								\
865 		n = strtoul(ss, &p, 0);					\
866 		if (*p != '\0')						\
867 			vtc_fatal(v, "%s takes an integer as argument "	\
868 				"(found %s)", c, ss);			\
869 	} while (0)
870 
871 #define STRTOU32_CHECK(n, sp, p, v, c, l)				\
872 do {									\
873 	sp++;								\
874 	AN(*sp);							\
875 	STRTOU32(n, *sp, p, v, c);					\
876 	if (l && n >= (1U << l))					\
877 		vtc_fatal(v,						\
878 		    c " must be a %d-bits integer (found %s)", l, *sp);	\
879 } while (0)
880 
881 #define CHECK_LAST_FRAME(TYPE) \
882 	if (!f || f->type != TYPE_ ## TYPE) {				   \
883 		vtc_fatal(s->vl, "Last frame was not of type " #TYPE); \
884 	}
885 
886 #define RETURN_SETTINGS(idx) \
887 do { \
888 	if (isnan(f->md.settings[idx])) { \
889 		return (NULL); \
890 	} \
891 	snprintf(buf, 20, "%.0f", f->md.settings[idx]); \
892 	return (buf); \
893 } while (0)
894 
895 #define RETURN_BUFFED(val) \
896 do { \
897 	snprintf(buf, 20, "%ld", (long)val); \
898 	return (buf); \
899 } while (0)
900 
901 static char *
find_header(const struct hpk_hdr * h,const char * k)902 find_header(const struct hpk_hdr *h, const char *k)
903 {
904 	AN(k);
905 
906 	int kl = strlen(k);
907 	while (h->t) {
908 		if (kl == h->key.len  && !strncasecmp(h->key.ptr, k, kl))
909 			return (h->value.ptr);
910 		h++;
911 	}
912 	return (NULL);
913 }
914 /* SECTION: stream.spec.zexpect expect
915  *
916  * expect in stream works as it does in client or server, except that the
917  * elements compared will be different.
918  *
919  * Most of these elements will be frame specific, meaning that the last frame
920  * received on that stream must of the correct type.
921  *
922  * Here the list of keywords you can look at.
923  */
924 static const char *
cmd_var_resolve(const struct stream * s,const char * spec,char * buf)925 cmd_var_resolve(const struct stream *s, const char *spec, char *buf)
926 {
927 	uint32_t idx;
928 	int n;
929 	const struct hpk_hdr *h;
930 	struct hpk_ctx *ctx;
931 	struct frame *f = s->frame;
932 
933 	CHECK_OBJ_NOTNULL(s, STREAM_MAGIC);
934 	CHECK_OBJ_NOTNULL(s->hp, HTTP_MAGIC);
935 	AN(spec);
936 	AN(buf);
937 
938 	n = 0;
939 	/* SECTION: stream.spec.zexpect.ping PING specific
940 	 * ping.data
941 	 *	The 8-bytes string of the PING frame payload.
942 	 * ping.ack (PING)
943 	 *	"true" if the ACK flag was set, "false" otherwise.
944 	 */
945 	if (!strcmp(spec, "ping.data")) {
946 		CHECK_LAST_FRAME(PING);
947 		return (f->md.ping.data);
948 	}
949 	if (!strcmp(spec, "ping.ack")) {
950 		CHECK_LAST_FRAME(PING);
951 		snprintf(buf, 20, (f->flags & ACK) ? "true" : "false");
952 		return (buf);
953 	}
954 	/* SECTION: stream.spec.zexpect.winup WINDOW_UPDATE specific
955 	 * winup.size
956 	 *	The size of the upgrade given by the WINDOW_UPDATE frame.
957 	 */
958 	if (!strcmp(spec, "winup.size")) {
959 		CHECK_LAST_FRAME(WINDOW_UPDATE);
960 		RETURN_BUFFED(f->md.winup_size);
961 	}
962 	/* SECTION: stream.spec.zexpect.prio PRIORITY specific
963 	 * prio.stream
964 	 *	The stream ID announced.
965 	 *
966 	 * prio.exclusive
967 	 *	"true" if the priority is exclusive, else "false".
968 	 *
969 	 * prio.weight
970 	 *	The dependency weight.
971 	 */
972 	if (!strcmp(spec, "prio.stream")) {
973 		CHECK_LAST_FRAME(PRIORITY);
974 		RETURN_BUFFED(f->md.prio.stream);
975 	}
976 	if (!strcmp(spec, "prio.exclusive")) {
977 		CHECK_LAST_FRAME(PRIORITY);
978 		snprintf(buf, 20, f->md.prio.exclusive ? "true" : "false");
979 		return (buf);
980 	}
981 	if (!strcmp(spec, "prio.weight")) {
982 		CHECK_LAST_FRAME(PRIORITY);
983 		RETURN_BUFFED(f->md.prio.weight);
984 	}
985 	/* SECTION: stream.spec.zexpect.rst RESET_STREAM specific
986 	 * rst.err
987 	 *	The error code (as integer) of the RESET_STREAM frame.
988 	 */
989 	if (!strcmp(spec, "rst.err")) {
990 		CHECK_LAST_FRAME(RST_STREAM);
991 		RETURN_BUFFED(f->md.rst_err);
992 	}
993 	/* SECTION: stream.spec.zexpect.settings SETTINGS specific
994 	 *
995 	 * settings.ack
996 	 *	"true" if the ACK flag was set, else ""false.
997 	 *
998 	 * settings.push
999 	 *	"true" if the push settings was set to yes, "false" if set to
1000 	 *	no, and <undef> if not present.
1001 	 *
1002 	 * settings.hdrtbl
1003 	 *	Value of HEADER_TABLE_SIZE if set, <undef> otherwise.
1004 	 *
1005 	 * settings.maxstreams
1006 	 *	Value of MAX_CONCURRENT_STREAMS if set, <undef> otherwise.
1007 	 *
1008 	 * settings.winsize
1009 	 *	Value of INITIAL_WINDOW_SIZE if set, <undef> otherwise.
1010 	 *
1011 	 * setting.framesize
1012 	 *	Value of MAX_FRAME_SIZE if set, <undef> otherwise.
1013 	 *
1014 	 * settings.hdrsize
1015 	 *	Value of MAX_HEADER_LIST_SIZE if set, <undef> otherwise.
1016 	 */
1017 	if (!strncmp(spec, "settings.", 9)) {
1018 		CHECK_LAST_FRAME(SETTINGS);
1019 		spec += 9;
1020 		if (!strcmp(spec, "ack")) {
1021 			snprintf(buf, 20, (f->flags & ACK) ? "true" : "false");
1022 			return (buf);
1023 		}
1024 		if (!strcmp(spec, "push")) {
1025 			if (isnan(f->md.settings[2]))
1026 				return (NULL);
1027 			else if (f->md.settings[2] == 1)
1028 				snprintf(buf, 20, "true");
1029 			else
1030 				snprintf(buf, 20, "false");
1031 			return (buf);
1032 		}
1033 		if (!strcmp(spec, "hdrtbl"))     { RETURN_SETTINGS(1); }
1034 		if (!strcmp(spec, "maxstreams")) { RETURN_SETTINGS(3); }
1035 		if (!strcmp(spec, "winsize"))    { RETURN_SETTINGS(4); }
1036 		if (!strcmp(spec, "framesize"))  { RETURN_SETTINGS(5); }
1037 		if (!strcmp(spec, "hdrsize"))    { RETURN_SETTINGS(6); }
1038 	}
1039 	/* SECTION: stream.spec.zexpect.push PUSH_PROMISE specific
1040 	 * push.id
1041 	 *	The id of the promised stream.
1042 	 */
1043 	if (!strcmp(spec, "push.id")) {
1044 		CHECK_LAST_FRAME(PUSH_PROMISE);
1045 		RETURN_BUFFED(f->md.promised);
1046 	}
1047 	/* SECTION: stream.spec.zexpect.goaway GOAWAY specific
1048 	 * goaway.err
1049 	 *	The error code (as integer) of the GOAWAY frame.
1050 	 *
1051 	 * goaway.laststream
1052 	 *	Last-Stream-ID
1053 	 *
1054 	 * goaway.debug
1055 	 *	Debug data, if any.
1056 	 */
1057 	if (!strncmp(spec, "goaway.", 7)) {
1058 		spec += 7;
1059 		CHECK_LAST_FRAME(GOAWAY);
1060 
1061 		if (!strcmp(spec, "err"))
1062 			RETURN_BUFFED(f->md.goaway.err);
1063 		else if (!strcmp(spec, "laststream"))
1064 			RETURN_BUFFED(f->md.goaway.stream);
1065 		else if (!strcmp(spec, "debug"))
1066 			return (f->md.goaway.debug);
1067 	}
1068 	/* SECTION: stream.spec.zexpect.zframe Generic frame
1069 	 * frame.data
1070 	 *	Payload of the last frame
1071 	 *
1072 	 * frame.type
1073 	 *	Type of the frame, as integer.
1074 	 *
1075 	 * frame.size
1076 	 *	Size of the frame.
1077 	 *
1078 	 * frame.stream
1079 	 *	Stream of the frame (correspond to the one you are executing
1080 	 *	this from, obviously).
1081 	 *
1082 	 * frame.padding (for DATA, HEADERS, PUSH_PROMISE frames)
1083 	 *	Number of padded bytes.
1084 	 */
1085 	if (!strncmp(spec, "frame.", 6)) {
1086 		spec += 6;
1087 		if (!f)
1088 			vtc_fatal(s->vl, "No frame received yet.");
1089 		if (!strcmp(spec, "data"))   { return (f->data); }
1090 		else if (!strcmp(spec, "type"))   { RETURN_BUFFED(f->type); }
1091 		else if (!strcmp(spec, "size"))	  { RETURN_BUFFED(f->size); }
1092 		else if (!strcmp(spec, "stream")) { RETURN_BUFFED(f->stid); }
1093 		else if (!strcmp(spec, "padding")) {
1094 			if (f->type != TYPE_DATA &&
1095 					f->type != TYPE_HEADERS &&
1096 					f->type != TYPE_PUSH_PROMISE)
1097 				vtc_fatal(s->vl,
1098 						"Last frame was not of type "
1099 						"DATA, HEADERS or PUSH");
1100 			RETURN_BUFFED(f->md.padded);
1101 		}
1102 	}
1103 	/* SECTION: stream.spec.zexpect.zstream Stream
1104 	 * stream.window
1105 	 *	The current window size of the stream, or, if on stream 0,
1106 	 *	of the connection.
1107 	 *
1108 	 * stream.weight
1109 	 *	Weight of the stream
1110 	 *
1111 	 * stream.dependency
1112 	 *	Id of the stream this one depends on.
1113 	 */
1114 	if (!strcmp(spec, "stream.window")) {
1115 		snprintf(buf, 20, "%jd",
1116 		    (intmax_t)(s->id ? s->ws : s->hp->ws));
1117 		return (buf);
1118 	}
1119 	if (!strcmp(spec, "stream.weight")) {
1120 		if (s->id) {
1121 			snprintf(buf, 20, "%d", s->weight);
1122 			return (buf);
1123 		} else
1124 			return (NULL);
1125 	}
1126 	if (!strcmp(spec, "stream.dependency")) {
1127 		if (s->id) {
1128 			snprintf(buf, 20, "%d", s->dependency);
1129 			return (buf);
1130 		} else
1131 			return (NULL);
1132 	}
1133 	/* SECTION: stream.spec.zexpect.ztable Index tables
1134 	 * tbl.dec.size / tbl.enc.size
1135 	 *	Size (bytes) of the decoding/encoding table.
1136 	 *
1137 	 * tbl.dec.size / tbl.enc.maxsize
1138 	 *	Maximum size (bytes) of the decoding/encoding table.
1139 	 *
1140 	 * tbl.dec.length / tbl.enc.length
1141 	 *	Number of headers in decoding/encoding table.
1142 	 *
1143 	 * tbl.dec[INT].key / tbl.enc[INT].key
1144 	 *	Name of the header at index INT of the decoding/encoding
1145 	 *	table.
1146 	 *
1147 	 * tbl.dec[INT].value / tbl.enc[INT].value
1148 	 *	Value of the header at index INT of the decoding/encoding
1149 	 *	table.
1150 	 */
1151 	if (!strncmp(spec, "tbl.dec", 7) || !strncmp(spec, "tbl.enc", 7)) {
1152 		if (spec[4] == 'd')
1153 			ctx = s->hp->decctx;
1154 		else
1155 			ctx = s->hp->encctx;
1156 		spec += 7;
1157 
1158 		if (1 == sscanf(spec, "[%u].key%n", &idx, &n) &&
1159 				spec[n] == '\0') {
1160 			h = HPK_GetHdr(ctx, idx + 61);
1161 			return (h ? h->key.ptr : NULL);
1162 		}
1163 		else if (1 == sscanf(spec, "[%u].value%n", &idx, &n) &&
1164 				spec[n] == '\0') {
1165 			h = HPK_GetHdr(ctx, idx + 61);
1166 			return (h ? h->value.ptr : NULL);
1167 		}
1168 		else if (!strcmp(spec, ".size"))
1169 			RETURN_BUFFED(HPK_GetTblSize(ctx));
1170 		else if (!strcmp(spec, ".maxsize"))
1171 			RETURN_BUFFED(HPK_GetTblMaxSize(ctx));
1172 		else if (!strcmp(spec, ".length"))
1173 			RETURN_BUFFED(HPK_GetTblLength(ctx));
1174 	}
1175 	/* SECTION: stream.spec.zexpect.zre Request and response
1176 	 *
1177 	 * Note: it's possible to inspect a request or response while it is
1178 	 * still being construct (in-between two frames for example).
1179 	 *
1180 	 * req.bodylen / resp.bodylen
1181 	 *	Length in bytes of the request/response so far.
1182 	 *
1183 	 * req.body / resp.body
1184 	 *	Body of the request/response so far.
1185 	 *
1186 	 * req.http.STRING / resp.http.STRING
1187 	 *	Value of the header STRING in the request/response.
1188 	 *
1189 	 * req.status / resp.status
1190 	 *	:status pseudo-header's value.
1191 	 *
1192 	 * req.url / resp.url
1193 	 *	:path pseudo-header's value.
1194 	 *
1195 	 * req.method / resp.method
1196 	 *	:method pseudo-header's value.
1197 	 *
1198 	 * req.authority / resp.authority
1199 	 *	:method pseudo-header's value.
1200 	 *
1201 	 * req.scheme / resp.scheme
1202 	 *	:method pseudo-header's value.
1203 	 */
1204 	if (!strncmp(spec, "req.", 4) || !strncmp(spec, "resp.", 5)) {
1205 		if (spec[2] == 'q') {
1206 			h = s->req;
1207 			spec += 4;
1208 		} else {
1209 			h = s->resp;
1210 			spec += 5;
1211 		}
1212 		if (!strcmp(spec, "body"))
1213 			return (s->body);
1214 		else if (!strcmp(spec, "bodylen"))
1215 			RETURN_BUFFED(s->bodylen);
1216 		else if (!strcmp(spec, "status"))
1217 			return (find_header(h, ":status"));
1218 		else if (!strcmp(spec, "url"))
1219 			return (find_header(h, ":path"));
1220 		else if (!strcmp(spec, "method"))
1221 			return (find_header(h, ":method"));
1222 		else if (!strcmp(spec, "authority"))
1223 			return (find_header(h, ":authority"));
1224 		else if (!strcmp(spec, "scheme"))
1225 			return (find_header(h, ":scheme"));
1226 		else if (!strncmp(spec, "http.", 5))
1227 			return (find_header(h, spec + 5));
1228 		else
1229 			return (NULL);
1230 	}
1231 #define H2_ERROR(U,v,sc,r,t) \
1232 	if (!strcmp(spec, #U)) { return (#v); }
1233 #include "tbl/h2_error.h"
1234 	return (spec);
1235 }
1236 
1237 /* SECTION: stream.spec.frame_sendhex sendhex
1238  *
1239  * Push bytes directly on the wire. sendhex takes exactly one argument: a string
1240  * describing the bytes, in hex notation, with possible whitespaces between
1241  * them. Here's an example::
1242  *
1243  *	sendhex "00 00 08 00 0900	8d"
1244  */
1245 static void
cmd_sendhex(CMD_ARGS)1246 cmd_sendhex(CMD_ARGS)
1247 {
1248 	struct http *hp;
1249 	struct stream *s;
1250 	struct vsb *vsb;
1251 
1252 	(void)vl;
1253 	CAST_OBJ_NOTNULL(s, priv, STREAM_MAGIC);
1254 	CAST_OBJ_NOTNULL(hp, s->hp, HTTP_MAGIC);
1255 	AN(av[1]);
1256 	AZ(av[2]);
1257 	vsb = vtc_hex_to_bin(hp->vl, av[1]);
1258 	assert(VSB_len(vsb) >= 0);
1259 	vtc_hexdump(hp->vl, 4, "sendhex", VSB_data(vsb), VSB_len(vsb));
1260 	AZ(pthread_mutex_lock(&hp->mtx));
1261 	http_write(hp, 4, VSB_data(vsb), VSB_len(vsb), "sendhex");
1262 	AZ(pthread_mutex_unlock(&hp->mtx));
1263 	VSB_destroy(&vsb);
1264 }
1265 
1266 #define ENC(hdr, k, v)					\
1267 {							\
1268 	AN(k);						\
1269 	hdr.key.ptr = strdup(k);			\
1270 	AN(hdr.key.ptr);				\
1271 	hdr.key.len = strlen(k);			\
1272 	AN(v);						\
1273 	hdr.value.ptr = strdup(v);			\
1274 	AN(hdr.value.ptr);				\
1275 	hdr.value.len = strlen(v);			\
1276 	assert(HPK_EncHdr(iter, &hdr) != hpk_err);	\
1277 	free(hdr.key.ptr);				\
1278 	free(hdr.value.ptr);				\
1279 }
1280 
1281 #define STR_ENC(av, field, str)						       \
1282 {									       \
1283 	av++;								       \
1284 	     if (AV_IS("plain")) { hdr.field.huff = 0; }		       \
1285 	else if (AV_IS("huf"))   { hdr.field.huff = 1; }		       \
1286 	else								       \
1287 		vtc_fatal(vl, str " arg can be huf or plain (got: %s)", *av); \
1288 	av++;								       \
1289 	AN(*av);							       \
1290 	hdr.field.ptr = *av;						       \
1291 	hdr.field.len = strlen(*av);					       \
1292 }
1293 
1294 
1295 /* SECTION: stream.spec.data_0 txreq, txresp, txcont, txpush
1296  *
1297  * These four commands are about sending headers. txreq and txresp
1298  * will send HEADER frames; txcont will send CONTINUATION frames; txpush
1299  * PUSH frames.
1300  * The only difference between txreq and txresp are the default headers
1301  * set by each of them.
1302  *
1303  * \-noadd
1304  *	Do not add default headers. Useful to avoid duplicates when sending
1305  *	default headers using ``-hdr``, ``-idxHdr`` and ``-litIdxHdr``.
1306  *
1307  * \-status INT (txresp)
1308  *	Set the :status pseudo-header.
1309  *
1310  * \-url STRING (txreq, txpush)
1311  *	Set the :path pseudo-header.
1312  *
1313  * \-method STRING (txreq, txpush)
1314  *	Set the :method pseudo-header.
1315  *
1316  * \-req STRING (txreq, txpush)
1317  *	Alias for -method.
1318  *
1319  * \-scheme STRING (txreq, txpush)
1320  *	Set the :scheme pseudo-header.
1321  *
1322  * \-hdr STRING1 STRING2
1323  *	Insert a header, STRING1 being the name, and STRING2 the value.
1324  *
1325  * \-idxHdr INT
1326  *	Insert an indexed header, using INT as index.
1327  *
1328  * \-litIdxHdr inc|not|never INT huf|plain STRING
1329  *	Insert an literal, indexed header. The first argument specify if the
1330  *	header should be added to the table, shouldn't, or mustn't be
1331  *	compressed if/when retransmitted.
1332  *
1333  *	INT is the idex of the header name to use.
1334  *
1335  *	The third argument informs about the Huffman encoding: yes (huf) or
1336  *	no (plain).
1337  *
1338  *	The last term is the literal value of the header.
1339  *
1340  * \-litHdr inc|not|never huf|plain STRING1 huf|plain STRING2
1341  *	Insert a literal header, with the same first argument as
1342  *	``-litIdxHdr``.
1343  *
1344  *	The second and third terms tell what the name of the header is and if
1345  *	it should be Huffman-encoded, while the last two do the same
1346  *	regarding the value.
1347  *
1348  * \-body STRING (txreq, txresp)
1349  *	Specify a body, effectively putting STRING into a DATA frame after
1350  *	the HEADER frame is sent.
1351  *
1352  * \-bodyfrom FILE (txreq, txresp)
1353  *	Same as ``-body`` but content is read from FILE.
1354  *
1355  * \-bodylen INT (txreq, txresp)
1356  *	Do the same thing as ``-body`` but generate a string of INT length
1357  *	for you.
1358  *
1359  * \-gzipbody STRING (txreq, txresp)
1360  *      Gzip STRING and send it as body.
1361  *
1362  * \-gziplen NUMBER (txreq, txresp)
1363  *      Combine -bodylen and -gzipbody: generate a string of length NUMBER,
1364  *      gzip it and send as body.
1365  *
1366  * \-nostrend (txreq, txresp)
1367  *	Don't set the END_STREAM flag automatically, making the peer expect
1368  *	a body after the headers.
1369  *
1370  * \-nohdrend
1371  *	Don't set the END_HEADERS flag automatically, making the peer expect
1372  *	more HEADER frames.
1373  *
1374  * \-dep INT (txreq, txresp)
1375  *	Tell the peer that this content depends on the stream with the INT
1376  *	id.
1377  *
1378  * \-ex (txreq, txresp)
1379  *	Make the dependency exclusive (``-dep`` is still needed).
1380  *
1381  * \-weight (txreq, txresp)
1382  *	Set the weight for the dependency.
1383  *
1384  * \-promised INT (txpush)
1385  *	The id of the promised stream.
1386  *
1387  * \-pad STRING / -padlen INT (txreq, txresp, txpush)
1388  *	Add string as padding to the frame, either the one you provided with
1389  *	\-pad, or one that is generated for you, of length INT is -padlen
1390  *	case.
1391  */
1392 
1393 #define cmd_txreq	cmd_tx11obj
1394 #define cmd_txresp	cmd_tx11obj
1395 #define cmd_txpush	cmd_tx11obj
1396 #define cmd_txcont	cmd_tx11obj
1397 
1398 static void
cmd_tx11obj(CMD_ARGS)1399 cmd_tx11obj(CMD_ARGS)
1400 {
1401 	struct stream *s;
1402 	int status_done = 1;
1403 	int method_done = 1;
1404 	int path_done = 1;
1405 	int scheme_done = 1;
1406 	long bodylen = 0;
1407 	ssize_t len;
1408 	uint32_t stid = 0, pstid;
1409 	uint32_t weight = 16;
1410 	uint32_t exclusive = 0;
1411 	char *buf;
1412 	struct hpk_iter *iter;
1413 	struct frame f;
1414 	char *body = NULL, *pad = NULL;
1415 	/*XXX: do we need a better api? yes we do */
1416 	struct hpk_hdr hdr;
1417 	char *cmd_str = *av;
1418 	char *b, *p;
1419 
1420 	CAST_OBJ_NOTNULL(s, priv, STREAM_MAGIC);
1421 	INIT_FRAME(f, CONTINUATION, 0, s->id, END_HEADERS);
1422 	buf = malloc(BUF_SIZE);
1423 	AN(buf);
1424 
1425 	if (!strcmp(cmd_str, "txreq")) {
1426 		ONLY_H2_CLIENT(s->hp, av);
1427 		f.type = TYPE_HEADERS;
1428 		f.flags |= END_STREAM;
1429 		method_done = 0;
1430 		path_done = 0;
1431 		scheme_done = 0;
1432 	} else if (!strcmp(cmd_str, "txresp")) {
1433 		ONLY_H2_SERVER(s->hp, av);
1434 		f.type = TYPE_HEADERS;
1435 		f.flags |= END_STREAM;
1436 		status_done = 0;
1437 	} else if (!strcmp(cmd_str, "txpush")) {
1438 		ONLY_H2_SERVER(s->hp, av);
1439 		f.type = TYPE_PUSH_PROMISE;
1440 		method_done = 0;
1441 		path_done = 0;
1442 		scheme_done = 0;
1443 	}
1444 
1445 	if (f.type == TYPE_PUSH_PROMISE) {
1446 		*buf = 0;
1447 		iter = HPK_NewIter(s->hp->encctx, buf + 4, BUF_SIZE - 4);
1448 	} else
1449 		iter = HPK_NewIter(s->hp->encctx, buf, BUF_SIZE);
1450 
1451 #define AV_IS(str) !strcmp(*av, str)
1452 #define CMD_IS(str) !strcmp(cmd_str, str)
1453 	while (*++av) {
1454 		memset(&hdr, 0, sizeof(hdr));
1455 		hdr.t = hpk_not;
1456 		if (AV_IS("-noadd")) {
1457 			path_done = 1;
1458 			status_done = 1;
1459 			method_done = 1;
1460 			scheme_done = 1;
1461 		}
1462 		else if (AV_IS("-status") && CMD_IS("txresp")) {
1463 			ENC(hdr, ":status", av[1]);
1464 			av++;
1465 			status_done = 1;
1466 		}
1467 		else if (AV_IS("-url") &&
1468 				(CMD_IS("txreq") || CMD_IS("txpush"))) {
1469 			ENC(hdr, ":path", av[1]);
1470 			av++;
1471 			path_done = 1;
1472 		}
1473 		else if ((AV_IS("-method") || AV_IS("-req")) &&
1474 				(CMD_IS("txreq") || CMD_IS("txpush"))) {
1475 			ENC(hdr, ":method", av[1]);
1476 			av++;
1477 			method_done = 1;
1478 		}
1479 		else if (AV_IS("-scheme") &&
1480 				(CMD_IS("txreq") || CMD_IS("txpush"))) {
1481 			ENC(hdr, ":scheme", av[1]);
1482 			av++;
1483 			scheme_done = 1;
1484 		}
1485 		else if (AV_IS("-hdr")) {
1486 			if (av[2] == NULL)
1487 				vtc_fatal(vl, "-hdr takes two arguments in http2");
1488 			ENC(hdr, av[1], av[2]);
1489 			av += 2;
1490 		}
1491 		else if (AV_IS("-idxHdr")) {
1492 			hdr.t = hpk_idx;
1493 			STRTOU32_CHECK(hdr.i, av, p, vl, "-idxHdr", 0);
1494 			assert(HPK_EncHdr(iter, &hdr) != hpk_err);
1495 		}
1496 		else if (AV_IS("-litIdxHdr")) {
1497 			av++;
1498 			if      (AV_IS("inc"))   { hdr.t = hpk_inc;   }
1499 			else if (AV_IS("not"))   { hdr.t = hpk_not;   }
1500 			else if (AV_IS("never")) { hdr.t = hpk_never; }
1501 			else
1502 				vtc_fatal(vl, "first -litidxHdr arg can be "
1503 				    "inc, not, never (got: %s)", *av);
1504 
1505 			STRTOU32_CHECK(hdr.i, av, p, vl,
1506 			    "second -litidxHdr arg", 0);
1507 
1508 			hdr.key.ptr = NULL;
1509 			hdr.key.len = 0;
1510 			STR_ENC(av, value,   "third -litHdr");
1511 			assert(HPK_EncHdr(iter, &hdr) != hpk_err);
1512 		}
1513 		else if (AV_IS("-litHdr")) {
1514 			av++;
1515 			if      (AV_IS("inc"))   { hdr.t = hpk_inc;   }
1516 			else if (AV_IS("not"))   { hdr.t = hpk_not;   }
1517 			else if (AV_IS("never")) { hdr.t = hpk_never; }
1518 			else
1519 				vtc_fatal(vl, "first -litHdr arg can be inc, "
1520 				    "not, never (got: %s)", *av);
1521 
1522 			STR_ENC(av, key,   "second -litHdr");
1523 			STR_ENC(av, value, "fourth -litHdr");
1524 			assert(HPK_EncHdr(iter, &hdr) != hpk_err);
1525 		}
1526 		else if (AV_IS("-nostrend")) {
1527 			f.flags &= ~END_STREAM;
1528 		}
1529 		else if (AV_IS("-nohdrend")) {
1530 			f.flags &= ~END_HEADERS;
1531 		}
1532 		else if (AV_IS("-promised") && CMD_IS("txpush")) {
1533 			STRTOU32_CHECK(pstid, av, p, vl, "-promised", 31);
1534 			vbe32enc(buf, pstid);
1535 		}
1536 		else if (AV_IS("-pad") && !CMD_IS("txcont")) {
1537 			AZ(pad);
1538 			av++;
1539 			AN(*av);
1540 			pad = strdup(*av);
1541 		}
1542 		else if (AV_IS("-padlen") && !CMD_IS("txcont")) {
1543 			AZ(pad);
1544 			av++;
1545 			pad = synth_body(*av, 0);
1546 		}
1547 		else if (CMD_IS("txreq") || CMD_IS("txresp")) {
1548 			if (AV_IS("-body")) {
1549 				AZ(body);
1550 				REPLACE(body, av[1]);
1551 				AN(body);
1552 				bodylen = strlen(body);
1553 				f.flags &= ~END_STREAM;
1554 				av++;
1555 			}
1556 			else if (AV_IS("-bodyfrom")) {
1557 				AZ(body);
1558 				body = VFIL_readfile(NULL, av[1], &len);
1559 				AN(body);
1560 				assert(len < INT_MAX);
1561 				bodylen = len;
1562 				f.flags &= ~END_STREAM;
1563 				av++;
1564 			}
1565 			else if (AV_IS("-bodylen")) {
1566 				AZ(body);
1567 				body = synth_body(av[1], 0);
1568 				bodylen = strlen(body);
1569 				f.flags &= ~END_STREAM;
1570 				av++;
1571 			}
1572 			else if (!strcmp(*av, "-gzipbody")) {
1573 				AZ(body);
1574 				vtc_gzip(s->hp, av[1], &body, &bodylen);
1575 				AN(body);
1576 				ENC(hdr, ":content-encoding", "gzip");
1577 				f.flags &= ~END_STREAM;
1578 				av++;
1579 			}
1580 			else if (!strcmp(*av, "-gziplen")) {
1581 				AZ(body);
1582 				b = synth_body(av[1], 1);
1583 				vtc_gzip(s->hp, b, &body, &bodylen);
1584 				AN(body);
1585 				free(b);
1586 				ENC(hdr, ":content-encoding", "gzip");
1587 				f.flags &= ~END_STREAM;
1588 				av++;
1589 			}
1590 			else if (AV_IS("-dep")) {
1591 				STRTOU32_CHECK(stid, av, p, vl, "-dep", 0);
1592 				f.flags |= PRIORITY;
1593 			}
1594 			else if (AV_IS("-ex")) {
1595 				exclusive = 1U << 31;
1596 				f.flags |= PRIORITY;
1597 			}
1598 			else if (AV_IS("-weight")) {
1599 				STRTOU32_CHECK(weight, av, p, vl, "-weight", 8);
1600 				f.flags |= PRIORITY;
1601 			} else
1602 				break;
1603 		} else
1604 			break;
1605 	}
1606 #undef CMD_IS
1607 #undef AV_IS
1608 	if (*av != NULL)
1609 		vtc_fatal(vl, "Unknown %s spec: %s\n", cmd_str, *av);
1610 
1611 	memset(&hdr, 0, sizeof(hdr));
1612 	hdr.t = hpk_not;
1613 
1614 	if (!status_done) { ENC(hdr, ":status", "200"); }
1615 	if (!path_done)   { ENC(hdr, ":path",	"/"); }
1616 	if (!method_done) { ENC(hdr, ":method", "GET"); }
1617 	if (!scheme_done) { ENC(hdr, ":scheme", "http"); }
1618 
1619 	f.size = gethpk_iterLen(iter);
1620 	if (f.flags & PRIORITY) {
1621 		s->weight = weight & 0xff;
1622 		s->dependency = stid;
1623 
1624 		assert(f.size + 5 < BUF_SIZE);
1625 		memmove(buf + 5, buf, f.size);
1626 		vbe32enc(buf, (stid | exclusive));
1627 		buf[4] = s->weight;
1628 		f.size += 5;
1629 
1630 		vtc_log(vl, 4, "stream->dependency: %u", s->dependency);
1631 		vtc_log(vl, 4, "stream->weight: %u", s->weight);
1632 		if (exclusive)
1633 			exclusive_stream_dependency(s);
1634 	}
1635 	if (pad) {
1636 		if (strlen(pad) >= 128)
1637 			vtc_fatal(vl, "Padding is limited to 128 bytes");
1638 		f.flags |= PADDED;
1639 		assert(f.size + strlen(pad) < BUF_SIZE);
1640 		memmove(buf + 1, buf, f.size);
1641 		buf[0] = strlen(pad);
1642 		f.size += 1;
1643 		memcpy(buf + f.size, pad, strlen(pad));
1644 		f.size += strlen(pad);
1645 		free(pad);
1646 	}
1647 	if (f.type == TYPE_PUSH_PROMISE)
1648 		f.size += 4;
1649 	f.data = buf;
1650 	HPK_FreeIter(iter);
1651 	write_frame(s, &f, 1);
1652 	free(buf);
1653 
1654 	if (!body)
1655 		return;
1656 
1657 	INIT_FRAME(f, DATA, bodylen, s->id, END_STREAM);
1658 	f.data = body;
1659 
1660 	write_frame(s, &f, 1);
1661 	free(body);
1662 }
1663 
1664 /* SECTION: stream.spec.data_1 txdata
1665  *
1666  * By default, data frames are empty. The receiving end will know the whole body
1667  * has been delivered thanks to the END_STREAM flag set in the last DATA frame,
1668  * and txdata automatically set it.
1669  *
1670  * \-data STRING
1671  *	Data to be embedded into the frame.
1672  *
1673  * \-datalen INT
1674  *	Generate and INT-bytes long string to be sent in the frame.
1675  *
1676  * \-pad STRING / -padlen INT
1677  *	Add string as padding to the frame, either the one you provided with
1678  *	\-pad, or one that is generated for you, of length INT is -padlen
1679  *	case.
1680  *
1681  * \-nostrend
1682  *	Don't set the END_STREAM flag, allowing to send more data on this
1683  *	stream.
1684  */
1685 static void
cmd_txdata(CMD_ARGS)1686 cmd_txdata(CMD_ARGS)
1687 {
1688 	struct stream *s;
1689 	char *pad = NULL;
1690 	struct frame f;
1691 	char *body = NULL;
1692 	char *data = NULL;
1693 
1694 	CAST_OBJ_NOTNULL(s, priv, STREAM_MAGIC);
1695 
1696 	INIT_FRAME(f, DATA, 0, s->id, END_STREAM);
1697 
1698 	while (*++av) {
1699 		if (!strcmp(*av, "-data")) {
1700 			AZ(body);
1701 			av++;
1702 			body = strdup(*av);
1703 		} else if (!strcmp(*av, "-datalen")) {
1704 			AZ(body);
1705 			av++;
1706 			body = synth_body(*av, 0);
1707 		} else if (!strcmp(*av, "-pad")) {
1708 			AZ(pad);
1709 			av++;
1710 			AN(*av);
1711 			pad = strdup(*av);
1712 		} else if (!strcmp(*av, "-padlen")) {
1713 			AZ(pad);
1714 			av++;
1715 			pad = synth_body(*av, 0);
1716 		} else if (!strcmp(*av, "-nostrend"))
1717 			f.flags &= ~END_STREAM;
1718 		else
1719 			break;
1720 	}
1721 	if (*av != NULL)
1722 		vtc_fatal(vl, "Unknown txdata spec: %s\n", *av);
1723 
1724 	if (!body)
1725 		body = strdup("");
1726 
1727 	if (pad) {
1728 		f.flags |= PADDED;
1729 		if (strlen(pad) >= 128)
1730 			vtc_fatal(vl, "Padding is limited to 128 bytes");
1731 		data = malloc( 1 + strlen(body) + strlen(pad));
1732 		AN(data);
1733 		*((uint8_t *)data) = strlen(pad);
1734 		f.size = 1;
1735 		memcpy(data + f.size, body, strlen(body));
1736 		f.size += strlen(body);
1737 		memcpy(data + f.size, pad, strlen(pad));
1738 		f.size += strlen(pad);
1739 		f.data = data;
1740 	} else {
1741 		f.size = strlen(body);
1742 		f.data = body;
1743 	}
1744 	write_frame(s, &f, 1);
1745 	free(body);
1746 	free(pad);
1747 	free(data);
1748 }
1749 
1750 /* SECTION: stream.spec.reset_txrst txrst
1751  *
1752  * Send a RST_STREAM frame. By default, txrst will send a 0 error code
1753  * (NO_ERROR).
1754  *
1755  * \-err STRING|INT
1756  *	Sets the error code to be sent. The argument can be an integer or a
1757  *	string describing the error, such as NO_ERROR, or CANCEL (see
1758  *	rfc7540#11.4 for more strings).
1759  */
1760 static void
cmd_txrst(CMD_ARGS)1761 cmd_txrst(CMD_ARGS)
1762 {
1763 	struct stream *s;
1764 	char *p;
1765 	uint32_t err = 0;
1766 	struct frame f;
1767 
1768 	CAST_OBJ_NOTNULL(s, priv, STREAM_MAGIC);
1769 
1770 	INIT_FRAME(f, RST_STREAM, 4, s->id, 0);
1771 
1772 	while (*++av) {
1773 		if (!strcmp(*av, "-err")) {
1774 			++av;
1775 			for (err = 0; h2_errs[err]; err++) {
1776 				if (!strcmp(h2_errs[err], *av))
1777 					break;
1778 			}
1779 
1780 			if (h2_errs[err])
1781 				continue;
1782 
1783 			STRTOU32(err, *av, p, vl, "-err");
1784 		} else
1785 			break;
1786 	}
1787 	if (*av != NULL)
1788 		vtc_fatal(vl, "Unknown txrst spec: %s\n", *av);
1789 
1790 	err = htonl(err);
1791 	f.data = (void *)&err;
1792 	write_frame(s, &f, 1);
1793 }
1794 
1795 /* SECTION: stream.spec.prio_txprio txprio
1796  *
1797  * Send a PRIORITY frame
1798  *
1799  * \-stream INT
1800  *	indicate the id of the stream the sender stream depends on.
1801  *
1802  * \-ex
1803  *	the dependency should be made exclusive (only this streams depends on
1804  *	the parent stream).
1805  *
1806  * \-weight INT
1807  *	an 8-bits integer is used to balance priority between streams
1808  *	depending on the same streams.
1809  */
1810 static void
cmd_txprio(CMD_ARGS)1811 cmd_txprio(CMD_ARGS)
1812 {
1813 	struct stream *s;
1814 	char *p;
1815 	uint32_t stid = 0;
1816 	struct frame f;
1817 	uint32_t weight = 0;
1818 	uint32_t exclusive = 0;
1819 	uint8_t buf[5];
1820 
1821 	CAST_OBJ_NOTNULL(s, priv, STREAM_MAGIC);
1822 
1823 	INIT_FRAME(f, PRIORITY, 5, s->id, 0);
1824 	f.data = (void *)buf;
1825 
1826 	while (*++av) {
1827 		if (!strcmp(*av, "-stream")) {
1828 			STRTOU32_CHECK(stid, av, p, vl, "-stream", 0);
1829 		} else if (!strcmp(*av, "-ex")) {
1830 			exclusive = 1U << 31;
1831 		} else if (!strcmp(*av, "-weight")) {
1832 			STRTOU32_CHECK(weight, av, p, vl, "-weight", 8);
1833 		} else
1834 			break;
1835 	}
1836 	if (*av != NULL)
1837 		vtc_fatal(vl, "Unknown txprio spec: %s\n", *av);
1838 	s->weight = weight & 0xff;
1839 	s->dependency = stid;
1840 
1841 	if (exclusive)
1842 		exclusive_stream_dependency(s);
1843 
1844 	vbe32enc(buf, (stid | exclusive));
1845 	buf[4] = s->weight;
1846 	write_frame(s, &f, 1);
1847 }
1848 
1849 #define PUT_KV(av, vl, name, val, code) \
1850 	do {\
1851 		STRTOU32_CHECK(val, av, p, vl, #name, 0);	\
1852 		vbe16enc(cursor, code);				\
1853 		cursor += sizeof(uint16_t);			\
1854 		vbe32enc(cursor, val);				\
1855 		cursor += sizeof(uint32_t);			\
1856 		f.size += 6;					\
1857 	} while(0)
1858 
1859 /* SECTION: stream.spec.settings_txsettings txsettings
1860  *
1861  * SETTINGS frames must be acknowledge, arguments are as follow (most of them
1862  * are from  rfc7540#6.5.2):
1863  *
1864  * \-hdrtbl INT
1865  *	headers table size
1866  *
1867  * \-push BOOL
1868  *	whether push frames are accepted or not
1869  *
1870  * \-maxstreams INT
1871  *	maximum concurrent streams allowed
1872  *
1873  * \-winsize INT
1874  *	sender's initial window size
1875  *
1876  * \-framesize INT
1877  *	largest frame size authorized
1878  *
1879  * \-hdrsize INT
1880  *	maximum size of the header list authorized
1881  *
1882  * \-ack
1883  *	set the ack bit
1884  */
1885 static void
cmd_txsettings(CMD_ARGS)1886 cmd_txsettings(CMD_ARGS)
1887 {
1888 	struct stream *s, *_s;
1889 	struct http *hp;
1890 	char *p;
1891 	uint32_t val = 0;
1892 	struct frame f;
1893 	//TODO dynamic alloc
1894 	char buf[512];
1895 	char *cursor = buf;
1896 
1897 	CAST_OBJ_NOTNULL(s, priv, STREAM_MAGIC);
1898 	CAST_OBJ_NOTNULL(hp, s->hp, HTTP_MAGIC);
1899 
1900 	memset(buf, 0, 512);
1901 	INIT_FRAME(f, SETTINGS, 0, s->id, 0);
1902 	f.data = buf;
1903 
1904 	AZ(pthread_mutex_lock(&hp->mtx));
1905 	while (*++av) {
1906 		if (!strcmp(*av, "-push")) {
1907 			++av;
1908 			vbe16enc(cursor, 0x2);
1909 			cursor += sizeof(uint16_t);
1910 			if (!strcmp(*av, "false"))
1911 				vbe32enc(cursor, 0);
1912 			else if (!strcmp(*av, "true"))
1913 				vbe32enc(cursor, 1);
1914 			else
1915 				vtc_fatal(vl, "Push parameter is either "
1916 				    "\"true\" or \"false\", not %s", *av);
1917 			cursor += sizeof(uint32_t);
1918 			f.size += 6;
1919 		}
1920 		else if (!strcmp(*av, "-hdrtbl")) {
1921 			PUT_KV(av, vl, hdrtbl, val, 0x1);
1922 			assert(HPK_ResizeTbl(s->hp->decctx, val) != hpk_err);
1923 		}
1924 		else if (!strcmp(*av, "-maxstreams"))
1925 			PUT_KV(av, vl, maxstreams, val, 0x3);
1926 		else if (!strcmp(*av, "-winsize"))	{
1927 			PUT_KV(av, vl, winsize, val, 0x4);
1928 			VTAILQ_FOREACH(_s, &hp->streams, list)
1929 				_s->ws += (val - hp->iws);
1930 			hp->iws = val;
1931 		}
1932 		else if (!strcmp(*av, "-framesize"))
1933 			PUT_KV(av, vl, framesize, val, 0x5);
1934 		else if (!strcmp(*av, "-hdrsize"))
1935 			PUT_KV(av, vl, hdrsize, val, 0x6);
1936 		else if (!strcmp(*av, "-ack"))
1937 			f.flags |= 1;
1938 		else
1939 			break;
1940 	}
1941 	if (*av != NULL)
1942 		vtc_fatal(vl, "Unknown txsettings spec: %s\n", *av);
1943 
1944 	AN(s->hp);
1945 	write_frame(s, &f, 0);
1946 	AZ(pthread_mutex_unlock(&hp->mtx));
1947 }
1948 
1949 /* SECTION: stream.spec.ping_txping txping
1950  *
1951  * Send PING frame.
1952  *
1953  * \-data STRING
1954  *	specify the payload of the frame, with STRING being an 8-char string.
1955  *
1956  * \-ack
1957  *	set the ACK flag.
1958  */
1959 static void
cmd_txping(CMD_ARGS)1960 cmd_txping(CMD_ARGS)
1961 {
1962 	struct stream *s;
1963 	struct frame f;
1964 	char buf[8];
1965 
1966 	memset(buf, 0, 8);
1967 	CAST_OBJ_NOTNULL(s, priv, STREAM_MAGIC);
1968 	INIT_FRAME(f, PING, 8, s->id, 0);
1969 
1970 	while (*++av) {
1971 		if (!strcmp(*av, "-data")) {
1972 			av++;
1973 			if (f.data)
1974 				vtc_fatal(vl, "this frame already has data");
1975 			if (strlen(*av) != 8)
1976 				vtc_fatal(vl, "data must be a 8-char string, found  (%s)", *av);
1977 			f.data = *av;
1978 		} else if (!strcmp(*av, "-ack"))
1979 			f.flags |= 1;
1980 		else
1981 			break;
1982 	}
1983 	if (*av != NULL)
1984 		vtc_fatal(vl, "Unknown txping spec: %s\n", *av);
1985 	if (!f.data)
1986 		f.data = buf;
1987 	write_frame(s, &f, 1);
1988 }
1989 
1990 /*
1991  * SECTION: stream.spec.goaway_txgoaway txgoaway
1992  *
1993  * Possible options include:
1994  *
1995  * \-err STRING|INT
1996  *	set the error code to explain the termination. The second argument
1997  *	can be a integer or the string version of the error code as found
1998  *	in rfc7540#7.
1999  *
2000  * \-laststream INT
2001  *	the id of the "highest-numbered stream identifier for which the
2002  *	sender of the GOAWAY frame might have taken some action on or might
2003  *	yet take action on".
2004  *
2005  * \-debug
2006  *	specify the debug data, if any to append to the frame.
2007  */
2008 static void
cmd_txgoaway(CMD_ARGS)2009 cmd_txgoaway(CMD_ARGS)
2010 {
2011 	struct stream *s;
2012 	char *p;
2013 	uint32_t err = 0;
2014 	uint32_t ls = 0;
2015 	struct frame f;
2016 
2017 	CAST_OBJ_NOTNULL(s, priv, STREAM_MAGIC);
2018 
2019 	INIT_FRAME(f, GOAWAY, 8, s->id, 0);
2020 
2021 	while (*++av) {
2022 		if (!strcmp(*av, "-err")) {
2023 			++av;
2024 			for (err = 0; h2_errs[err]; err++)
2025 				if (!strcmp(h2_errs[err], *av))
2026 					break;
2027 
2028 			if (h2_errs[err])
2029 				continue;
2030 
2031 			STRTOU32(err, *av, p, vl, "-err");
2032 		} else if (!strcmp(*av, "-laststream")) {
2033 			STRTOU32_CHECK(ls, av, p, vl, "-laststream", 31);
2034 		} else if (!strcmp(*av, "-debug")) {
2035 			++av;
2036 			if (f.data)
2037 				vtc_fatal(vl, "this frame already has debug data");
2038 			f.size = 8 + strlen(*av);
2039 			f.data = malloc(f.size);
2040 			AN(f.data);
2041 			memcpy(f.data + 8, *av, f.size - 8);
2042 		} else
2043 			break;
2044 	}
2045 	if (*av != NULL)
2046 		vtc_fatal(vl, "Unknown txgoaway spec: %s\n", *av);
2047 
2048 	if (!f.data) {
2049 		f.data = malloc(8);
2050 		AN(f.data);
2051 	}
2052 	vbe32enc(f.data, ls);
2053 	vbe32enc(f.data + 4, err);
2054 	write_frame(s, &f, 1);
2055 	free(f.data);
2056 }
2057 
2058 /* SECTION: stream.spec.winup_txwinup txwinup
2059  *
2060  * Transmit a WINDOW_UPDATE frame, increasing the amount of credit of the
2061  * connection (from stream 0) or of the stream (any other stream).
2062  *
2063  * \-size INT
2064  *	give INT credits to the peer.
2065  */
2066 static void
cmd_txwinup(CMD_ARGS)2067 cmd_txwinup(CMD_ARGS)
2068 {
2069 	struct http *hp;
2070 	struct stream *s;
2071 	char *p;
2072 	struct frame f;
2073 	char buf[8];
2074 	uint32_t size = 0;
2075 
2076 	CAST_OBJ_NOTNULL(s, priv, STREAM_MAGIC);
2077 	CAST_OBJ_NOTNULL(hp, s->hp, HTTP_MAGIC);
2078 	memset(buf, 0, 8);
2079 
2080 	AN(av[1]);
2081 	AN(av[2]);
2082 
2083 	INIT_FRAME(f, WINDOW_UPDATE, 4, s->id, 0);
2084 	f.data = buf;
2085 
2086 	while (*++av)
2087 		if (!strcmp(*av, "-size")) {
2088 			STRTOU32_CHECK(size, av, p, vl, "-size", 0);
2089 		} else
2090 			break;
2091 	if (*av != NULL)
2092 		vtc_fatal(vl, "Unknown txwinup spec: %s\n", *av);
2093 
2094 	AZ(pthread_mutex_lock(&hp->mtx));
2095 	if (s->id == 0)
2096 		hp->ws += size;
2097 	s->ws += size;
2098 	AZ(pthread_mutex_unlock(&hp->mtx));
2099 
2100 	size = htonl(size);
2101 	f.data = (void *)&size;
2102 	write_frame(s, &f, 1);
2103 }
2104 
2105 static struct frame *
rxstuff(struct stream * s)2106 rxstuff(struct stream *s)
2107 {
2108 	struct frame *f;
2109 
2110 	CHECK_OBJ_NOTNULL(s, STREAM_MAGIC);
2111 
2112 	AZ(pthread_mutex_lock(&s->hp->mtx));
2113 	if (VTAILQ_EMPTY(&s->fq)) {
2114 		assert(s->hp->wf >= 0);
2115 		s->hp->wf++;
2116 		s->wf = 1;
2117 		AZ(pthread_cond_signal(&s->hp->cond));
2118 		AZ(pthread_cond_wait(&s->cond, &s->hp->mtx));
2119 	}
2120 	if (VTAILQ_EMPTY(&s->fq)) {
2121 		AZ(pthread_mutex_unlock(&s->hp->mtx));
2122 		return (NULL);
2123 	}
2124 	clean_frame(&s->frame);
2125 	f = VTAILQ_LAST(&s->fq, fq_head);
2126 	CHECK_OBJ_NOTNULL(f, FRAME_MAGIC);
2127 	VTAILQ_REMOVE(&s->fq, f, list);
2128 	AZ(pthread_mutex_unlock(&s->hp->mtx));
2129 	return (f);
2130 }
2131 
2132 #define CHKFRAME(rt, wt, rcv, func) \
2133 	do { \
2134 	if (rt != wt) \
2135 		vtc_fatal(vl, "Frame #%d for %s was of type %s (%d) " \
2136 		    "instead of %s (%d)", \
2137 		    rcv, func, \
2138 		    rt < TYPE_MAX ? h2_types[rt] : "?", rt, \
2139 		    wt < TYPE_MAX ? h2_types[wt] : "?", wt); \
2140 	} while (0);
2141 
2142 /* SECTION: stream.spec.data_11 rxhdrs
2143  *
2144  * ``rxhdrs`` will expect one HEADER frame, then, depending on the arguments,
2145  * zero or more CONTINUATION frame.
2146  *
2147  * \-all
2148  *	Keep waiting for CONTINUATION frames until END_HEADERS flag is seen.
2149  *
2150  * \-some INT
2151  *	Retrieve INT - 1 CONTINUATION frames after the HEADER frame.
2152  *
2153  */
2154 static void
cmd_rxhdrs(CMD_ARGS)2155 cmd_rxhdrs(CMD_ARGS)
2156 {
2157 	struct stream *s;
2158 	struct frame *f = NULL;
2159 	char *p;
2160 	int loop = 0;
2161 	unsigned long int times = 1;
2162 	unsigned rcv = 0;
2163 	enum h2_type expect = TYPE_HEADERS;
2164 
2165 	CAST_OBJ_NOTNULL(s, priv, STREAM_MAGIC);
2166 
2167 	while (*++av) {
2168 		if (!strcmp(*av, "-some")) {
2169 			STRTOU32_CHECK(times, av, p, vl, "-some", 0);
2170 			if (!times)
2171 				vtc_fatal(vl, "-some argument must be more"
2172 					       "than 0 (found \"%s\")\n", *av);
2173 		} else if (!strcmp(*av, "-all"))
2174 			loop = 1;
2175 		else
2176 			break;
2177 	}
2178 	if (*av != NULL)
2179 		vtc_fatal(vl, "Unknown rxhdrs spec: %s\n", *av);
2180 
2181 	do {
2182 		replace_frame(&f, rxstuff(s));
2183 		if (f == NULL)
2184 			break;
2185 		rcv++;
2186 		CHKFRAME(f->type, expect, rcv, "rxhdrs");
2187 		expect = TYPE_CONTINUATION;
2188 	} while (rcv < times || (loop && !(f->flags & END_HEADERS)));
2189 	replace_frame(&s->frame, f);
2190 }
2191 
2192 static void
cmd_rxcont(CMD_ARGS)2193 cmd_rxcont(CMD_ARGS)
2194 {
2195 	struct stream *s;
2196 	struct frame *f = NULL;
2197 	char *p;
2198 	int loop = 0;
2199 	unsigned long int times = 1;
2200 	unsigned rcv = 0;
2201 
2202 	(void)av;
2203 	CAST_OBJ_NOTNULL(s, priv, STREAM_MAGIC);
2204 
2205 	while (*++av)
2206 		if (!strcmp(*av, "-some")) {
2207 			STRTOU32(times, *av, p, vl, "-some");
2208 			if (!times)
2209 				vtc_fatal(vl, "-some argument must be more"
2210 					       "than 0 (found \"%s\")\n", *av);
2211 		} else if (!strcmp(*av, "-all"))
2212 			loop = 1;
2213 		else
2214 			break;
2215 	if (*av != NULL)
2216 		vtc_fatal(vl, "Unknown rxcont spec: %s\n", *av);
2217 
2218 	do {
2219 		replace_frame(&f, rxstuff(s));
2220 		if (f == NULL)
2221 			break;
2222 		rcv++;
2223 		CHKFRAME(f->type, TYPE_CONTINUATION, rcv, "rxcont");
2224 	} while (rcv < times || (loop && !(f->flags & END_HEADERS)));
2225 	replace_frame(&s->frame, f);
2226 }
2227 
2228 
2229 /* SECTION: stream.spec.data_13 rxdata
2230  *
2231  * Receiving data is done using the ``rxdata`` keywords and will retrieve one
2232  * DATA frame, if you wish to receive more, you can use these two convenience
2233  * arguments:
2234  *
2235  * \-all
2236  *	keep waiting for DATA frame until one sets the END_STREAM flag
2237  *
2238  * \-some INT
2239  *	retrieve INT DATA frames.
2240  *
2241  */
2242 static void
cmd_rxdata(CMD_ARGS)2243 cmd_rxdata(CMD_ARGS)
2244 {
2245 	struct stream *s;
2246 	struct frame *f = NULL;
2247 	char *p;
2248 	int loop = 0;
2249 	unsigned long int times = 1;
2250 	unsigned rcv = 0;
2251 
2252 	(void)av;
2253 	CAST_OBJ_NOTNULL(s, priv, STREAM_MAGIC);
2254 
2255 	while (*++av)
2256 		if (!strcmp(*av, "-some")) {
2257 			av++;
2258 			STRTOU32(times, *av, p, vl, "-some");
2259 			if (!times)
2260 				vtc_fatal(vl, "-some argument must be more"
2261 					       "than 0 (found \"%s\")\n", *av);
2262 		} else if (!strcmp(*av, "-all"))
2263 			loop = 1;
2264 		else
2265 			break;
2266 	if (*av != NULL)
2267 		vtc_fatal(vl, "Unknown rxdata spec: %s\n", *av);
2268 
2269 	do {
2270 		replace_frame(&f, rxstuff(s));
2271 		if (f == NULL)
2272 			break;
2273 		rcv++;
2274 		CHKFRAME(f->type, TYPE_DATA, rcv, "rxhdata");
2275 	} while (rcv < times || (loop && !(f->flags & END_STREAM)));
2276 	replace_frame(&s->frame, f);
2277 }
2278 
2279 /* SECTION: stream.spec.data_10 rxreq, rxresp
2280  *
2281  * These are two convenience functions to receive headers and body of an
2282  * incoming request or response. The only difference is that rxreq can only be
2283  * by a server, and rxresp by a client.
2284  *
2285  */
2286 
2287 #define cmd_rxreq	cmd_rxmsg
2288 #define cmd_rxresp	cmd_rxmsg
2289 
2290 static void
cmd_rxmsg(CMD_ARGS)2291 cmd_rxmsg(CMD_ARGS)
2292 {
2293 	struct stream *s;
2294 	struct frame *f;
2295 	int end_stream;
2296 	int rcv = 0;
2297 
2298 	CAST_OBJ_NOTNULL(s, priv, STREAM_MAGIC);
2299 
2300 	if (!strcmp(av[0], "rxreq"))
2301 		ONLY_H2_SERVER(s->hp, av);
2302 	else
2303 		ONLY_H2_CLIENT(s->hp, av);
2304 
2305 	f = rxstuff(s);
2306 	if (!f)
2307 		return;
2308 
2309 	rcv++;
2310 	CHKFRAME(f->type, TYPE_HEADERS, rcv, *av);
2311 
2312 	end_stream = f->flags & END_STREAM;
2313 
2314 	while (!(f->flags & END_HEADERS)) {
2315 		replace_frame(&f, rxstuff(s));
2316 		if (f == NULL)
2317 			return;
2318 		rcv++;
2319 		CHKFRAME(f->type, TYPE_CONTINUATION, rcv, *av);
2320 	}
2321 
2322 	while (!end_stream) {
2323 		replace_frame(&f, rxstuff(s));
2324 		if (f == NULL)
2325 			break;
2326 		rcv++;
2327 		CHKFRAME(f->type, TYPE_DATA, rcv, *av);
2328 		end_stream = f->flags & END_STREAM;
2329 	}
2330 	replace_frame(&s->frame, f);
2331 }
2332 
2333 /* SECTION: stream.spec.data_12 rxpush
2334  *
2335  * This works like ``rxhdrs``, expecting a PUSH frame and then zero or more
2336  * CONTINUATION frames.
2337  *
2338  * \-all
2339  *	Keep waiting for CONTINUATION frames until END_HEADERS flag is seen.
2340  *
2341  * \-some INT
2342  *	Retrieve INT - 1 CONTINUATION frames after the PUSH frame.
2343  *
2344  */
2345 static void
cmd_rxpush(CMD_ARGS)2346 cmd_rxpush(CMD_ARGS)
2347 {
2348 	struct stream *s;
2349 	struct frame *f = NULL;
2350 	char *p;
2351 	int loop = 0;
2352 	unsigned long int times = 1;
2353 	unsigned rcv = 0;
2354 	enum h2_type expect = TYPE_PUSH_PROMISE;
2355 
2356 	CAST_OBJ_NOTNULL(s, priv, STREAM_MAGIC);
2357 
2358 	while (*++av) {
2359 		if (!strcmp(*av, "-some")) {
2360 			STRTOU32_CHECK(times, av, p, vl, "-some", 0);
2361 			if (!times)
2362 				vtc_fatal(vl, "-some argument must be more"
2363 					       "than 0 (found \"%s\")\n", *av);
2364 		} else if (!strcmp(*av, "-all")) {
2365 			loop = 1;
2366 		} else
2367 			break;
2368 	}
2369 	if (*av != NULL)
2370 		vtc_fatal(vl, "Unknown rxpush spec: %s\n", *av);
2371 
2372 	do {
2373 		f = rxstuff(s);
2374 		if (!f)
2375 			return;
2376 		rcv++;
2377 		CHKFRAME(f->type, expect, rcv, "rxpush");
2378 		expect = TYPE_CONTINUATION;
2379 	} while (rcv < times || (loop && !(f->flags & END_HEADERS)));
2380 	s->frame = f;
2381 }
2382 
2383 #define RXFUNC(lctype, upctype) \
2384 	static void \
2385 	cmd_rx ## lctype(CMD_ARGS) { \
2386 		struct stream *s; \
2387 		(void)av; \
2388 		CAST_OBJ_NOTNULL(s, priv, STREAM_MAGIC); \
2389 		s->frame = rxstuff(s); \
2390 		if (s->frame != NULL && s->frame->type != TYPE_ ## upctype) \
2391 			vtc_fatal(vl, \
2392 			    "Wrong frame type %s (%d) wanted %s", \
2393 			    s->frame->type < TYPE_MAX ? \
2394 			    h2_types[s->frame->type] : "?", \
2395 			    s->frame->type, #upctype); \
2396 	}
2397 
2398 /* SECTION: stream.spec.prio_rxprio rxprio
2399  *
2400  * Receive a PRIORITY frame.
2401  */
RXFUNC(prio,PRIORITY)2402 RXFUNC(prio,	PRIORITY)
2403 
2404 /* SECTION: stream.spec.reset_rxrst rxrst
2405  *
2406  * Receive a RST_STREAM frame.
2407  */
2408 RXFUNC(rst,	RST_STREAM)
2409 
2410 /* SECTION: stream.spec.settings_rxsettings rxsettings
2411  *
2412  * Receive a SETTINGS frame.
2413  */
2414 RXFUNC(settings,SETTINGS)
2415 
2416 /* SECTION: stream.spec.ping_rxping rxping
2417  *
2418  * Receive a PING frame.
2419  */
2420 RXFUNC(ping,	PING)
2421 
2422 /* SECTION: stream.spec.goaway_rxgoaway rxgoaway
2423  *
2424  * Receive a GOAWAY frame.
2425  */
2426 RXFUNC(goaway,	GOAWAY)
2427 
2428 /* SECTION: stream.spec.winup_rxwinup rxwinup
2429  *
2430  * Receive a WINDOW_UPDATE frame.
2431  */
2432 RXFUNC(winup,	WINDOW_UPDATE)
2433 
2434 /* SECTION: stream.spec.frame_rxframe
2435  *
2436  * Receive a frame, any frame.
2437  */
2438 static void
2439 cmd_rxframe(CMD_ARGS)
2440 {
2441 	struct stream *s;
2442 
2443 	(void)vl;
2444 	(void)av;
2445 	CAST_OBJ_NOTNULL(s, priv, STREAM_MAGIC);
2446 	if (rxstuff(s) == NULL)
2447 		vtc_fatal(s->vl, "No frame received");
2448 }
2449 
2450 static void
cmd_expect(CMD_ARGS)2451 cmd_expect(CMD_ARGS)
2452 {
2453 	struct http *hp;
2454 	struct stream *s;
2455 	const char *lhs;
2456 	char *cmp;
2457 	const char *rhs;
2458 	char buf[20];
2459 
2460 	CAST_OBJ_NOTNULL(s, priv, STREAM_MAGIC);
2461 	hp = s->hp;
2462 	CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
2463 
2464 	AZ(strcmp(av[0], "expect"));
2465 	av++;
2466 
2467 	AN(av[0]);
2468 	AN(av[1]);
2469 	AN(av[2]);
2470 	AZ(av[3]);
2471 	AZ(pthread_mutex_lock(&s->hp->mtx));
2472 	lhs = cmd_var_resolve(s, av[0], buf);
2473 	cmp = av[1];
2474 	rhs = cmd_var_resolve(s, av[2], buf);
2475 	vtc_expect(vl, av[0], lhs, cmp, av[2], rhs);
2476 	AZ(pthread_mutex_unlock(&s->hp->mtx));
2477 }
2478 
2479 /* SECTION: stream.spec.gunzip gunzip
2480  *
2481  * Same as the ``gunzip`` command for HTTP/1.
2482  */
2483 static void
cmd_gunzip(CMD_ARGS)2484 cmd_gunzip(CMD_ARGS)
2485 {
2486 	struct http *hp;
2487 	struct stream *s;
2488 
2489 	(void)av;
2490 	(void)vl;
2491 
2492 	CAST_OBJ_NOTNULL(s, priv, STREAM_MAGIC);
2493 	hp = s->hp;
2494 	CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
2495 
2496 	vtc_gunzip(s->hp, s->body, &s->bodylen);
2497 }
2498 
2499 /* SECTION: stream.spec.write_body
2500  *
2501  * write_body STRING
2502  *	Same as the ``write_body`` command for HTTP/1.
2503  */
2504 static void
cmd_write_body(CMD_ARGS)2505 cmd_write_body(CMD_ARGS)
2506 {
2507 	struct stream *s;
2508 
2509 	(void)vl;
2510 	CAST_OBJ_NOTNULL(s, priv, STREAM_MAGIC);
2511 	AN(av[0]);
2512 	AN(av[1]);
2513 	AZ(av[2]);
2514 	AZ(strcmp(av[0], "write_body"));
2515 	if (VFIL_writefile(NULL, av[1], s->body, s->bodylen) != 0)
2516 		vtc_fatal(s->vl, "failed to write body: %s (%d)",
2517 		    strerror(errno), errno);
2518 }
2519 
2520 /* SECTION: stream.spec Specification
2521  *
2522  * The specification of a stream follows the exact same rules as one for a
2523  * client or a server.
2524  */
2525 static const struct cmds stream_cmds[] = {
2526 #define CMD_STREAM(n) { #n, cmd_##n },
2527 	/* spec */
2528 	CMD_STREAM(expect)
2529 	CMD_STREAM(gunzip)
2530 	CMD_STREAM(rxcont)
2531 	CMD_STREAM(rxdata)
2532 	CMD_STREAM(rxframe)
2533 	CMD_STREAM(rxgoaway)
2534 	CMD_STREAM(rxhdrs)
2535 	CMD_STREAM(rxping)
2536 	CMD_STREAM(rxprio)
2537 	CMD_STREAM(rxpush)
2538 	CMD_STREAM(rxreq)
2539 	CMD_STREAM(rxresp)
2540 	CMD_STREAM(rxrst)
2541 	CMD_STREAM(rxsettings)
2542 	CMD_STREAM(rxwinup)
2543 	CMD_STREAM(sendhex)
2544 	CMD_STREAM(txcont)
2545 	CMD_STREAM(txdata)
2546 	CMD_STREAM(txgoaway)
2547 	CMD_STREAM(txping)
2548 	CMD_STREAM(txprio)
2549 	CMD_STREAM(txpush)
2550 	CMD_STREAM(txreq)
2551 	CMD_STREAM(txresp)
2552 	CMD_STREAM(txrst)
2553 	CMD_STREAM(txsettings)
2554 	CMD_STREAM(txwinup)
2555 	CMD_STREAM(write_body)
2556 	{ NULL, NULL }
2557 #undef CMD_STREAM
2558 };
2559 
2560 static void *
stream_thread(void * priv)2561 stream_thread(void *priv)
2562 {
2563 	struct stream *s;
2564 
2565 	CAST_OBJ_NOTNULL(s, priv, STREAM_MAGIC);
2566 	parse_string(s->vl, s, s->spec);
2567 	vtc_log(s->vl, 2, "Ending stream %u", s->id);
2568 	return (NULL);
2569 }
2570 /**********************************************************************
2571  * Allocate and initialize a stream
2572  */
2573 
2574 static struct stream *
stream_new(const char * name,struct http * h)2575 stream_new(const char *name, struct http *h)
2576 {
2577 	char *p;
2578 	struct stream *s;
2579 
2580 	ALLOC_OBJ(s, STREAM_MAGIC);
2581 	AN(s);
2582 	AZ(pthread_cond_init(&s->cond, NULL));
2583 	REPLACE(s->name, name);
2584 	AN(s->name);
2585 	VTAILQ_INIT(&s->fq);
2586 	s->ws = h->iws;
2587 	s->vl = vtc_logopen("%s.%s", h->sess->name, name);
2588 	vtc_log_set_cmd(s->vl, stream_cmds);
2589 
2590 	s->weight = 16;
2591 	s->dependency = 0;
2592 
2593 	STRTOU32(s->id, name, p, s->vl, "stream");
2594 	if (s->id & (1U << 31))
2595 		vtc_fatal(s->vl, "Stream id must be a 31-bits integer "
2596 		    "(found %s)", name);
2597 
2598 	CHECK_OBJ_NOTNULL(h, HTTP_MAGIC);
2599 	s->hp = h;
2600 
2601 	//bprintf(s->connect, "%s", "${v1_sock}");
2602 	AZ(pthread_mutex_lock(&h->mtx));
2603 	VTAILQ_INSERT_HEAD(&h->streams, s, list);
2604 	AZ(pthread_mutex_unlock(&h->mtx));
2605 	return (s);
2606 }
2607 
2608 /**********************************************************************
2609  * Clean up stream
2610  */
2611 
2612 static void
stream_delete(struct stream * s)2613 stream_delete(struct stream *s)
2614 {
2615 	struct frame *f, *f2;
2616 
2617 	CHECK_OBJ_NOTNULL(s, STREAM_MAGIC);
2618 
2619 	VTAILQ_FOREACH_SAFE(f, &s->fq, list, f2) {
2620 		VTAILQ_REMOVE(&s->fq, f, list);
2621 		clean_frame(&f);
2622 	}
2623 	vtc_logclose(s->vl);
2624 	clean_headers(s->req);
2625 	clean_headers(s->resp);
2626 	AZ(s->frame);
2627 	free(s->body);
2628 	free(s->spec);
2629 	free(s->name);
2630 	FREE_OBJ(s);
2631 }
2632 
2633 /**********************************************************************
2634  * Start the stream thread
2635  */
2636 
2637 static void
stream_start(struct stream * s)2638 stream_start(struct stream *s)
2639 {
2640 	CHECK_OBJ_NOTNULL(s, STREAM_MAGIC);
2641 	vtc_log(s->hp->vl, 2, "Starting stream %s (%p)", s->name, s);
2642 	AZ(pthread_create(&s->tp, NULL, stream_thread, s));
2643 	s->running = 1;
2644 }
2645 
2646 /**********************************************************************
2647  * Wait for stream thread to stop
2648  */
2649 static void
stream_wait(struct stream * s)2650 stream_wait(struct stream *s)
2651 {
2652 	void *res;
2653 	struct frame *f, *f2;
2654 
2655 	CHECK_OBJ_NOTNULL(s, STREAM_MAGIC);
2656 	vtc_log(s->hp->vl, 2, "Waiting for stream %u", s->id);
2657 	AZ(pthread_join(s->tp, &res));
2658 	if (res != NULL)
2659 		vtc_fatal(s->hp->vl, "Stream %u returned \"%s\"", s->id,
2660 		    (char *)res);
2661 
2662 	VTAILQ_FOREACH_SAFE(f, &s->fq, list, f2) {
2663 		VTAILQ_REMOVE(&s->fq, f, list);
2664 		clean_frame(&f);
2665 	}
2666 	clean_frame(&s->frame);
2667 	s->tp = 0;
2668 	s->running = 0;
2669 }
2670 
2671 /**********************************************************************
2672  * Run the stream thread
2673  */
2674 
2675 static void
stream_run(struct stream * s)2676 stream_run(struct stream *s)
2677 {
2678 	stream_start(s);
2679 	stream_wait(s);
2680 }
2681 
2682 
2683 
2684 /* SECTION: client-server.spec.stream
2685  *
2686  * stream
2687  *	HTTP/2 introduces the concept of streams, and these come with
2688  *	their own specification, and as it's quite big, have been moved
2689  *	to their own chapter.
2690  *
2691  * SECTION: stream stream
2692  *
2693  * (note: this section is at the top-level for easier navigation, but
2694  * it's part of the client/server specification)
2695  *
2696  * Streams map roughly to a request in HTTP/2, a request is sent on
2697  * stream N, the response too, then the stream is discarded. The main
2698  * exception is the first stream, 0, that serves as coordinator.
2699  *
2700  * Stream syntax follow the client/server one::
2701  *
2702  *	stream ID [SPEC] [ACTION]
2703  *
2704  * ID is the HTTP/2 stream number, while SPEC describes what will be
2705  * done in that stream.
2706  *
2707  * Note that, when parsing a stream action, if the entity isn't operating
2708  * in HTTP/2 mode, these spec is ran before::
2709  *
2710  *	txpri/rxpri # client/server
2711  *	stream 0 {
2712  *	    txsettings
2713  *	    rxsettings
2714  *	    txsettings -ack
2715  *	    rxsettings
2716  *	    expect settings.ack == true
2717  *	} -run
2718  *
2719  * And HTTP/2 mode is then activated before parsing the specification.
2720  *
2721  * SECTION: stream.actions Actions
2722  *
2723  * \-start
2724  *	Run the specification in a thread, giving back control immediately.
2725  *
2726  * \-wait
2727  *	Wait for the started thread to finish running the spec.
2728  *
2729  * \-run
2730  *	equivalent to calling ``-start`` then ``-wait``.
2731  */
2732 
2733 void
cmd_stream(CMD_ARGS)2734 cmd_stream(CMD_ARGS)
2735 {
2736 	struct stream *s;
2737 	struct http *h;
2738 
2739 	(void)vl;
2740 	CAST_OBJ_NOTNULL(h, priv, HTTP_MAGIC);
2741 
2742 	AZ(strcmp(av[0], "stream"));
2743 	av++;
2744 
2745 	VTAILQ_FOREACH(s, &h->streams, list)
2746 		if (!strcmp(s->name, av[0]))
2747 			break;
2748 	if (s == NULL)
2749 		s = stream_new(av[0], h);
2750 	av++;
2751 
2752 	for (; *av != NULL; av++) {
2753 		if (vtc_error)
2754 			break;
2755 
2756 		if (!strcmp(*av, "-wait")) {
2757 			stream_wait(s);
2758 			continue;
2759 		}
2760 
2761 		/* Don't muck about with a running client */
2762 		if (s->running)
2763 			stream_wait(s);
2764 
2765 		if (!strcmp(*av, "-start")) {
2766 			stream_start(s);
2767 			continue;
2768 		}
2769 		if (!strcmp(*av, "-run")) {
2770 			stream_run(s);
2771 			continue;
2772 		}
2773 		if (**av == '-')
2774 			vtc_fatal(vl, "Unknown client argument: %s", *av);
2775 		REPLACE(s->spec, *av);
2776 	}
2777 }
2778 
2779 void
b64_settings(const struct http * hp,const char * s)2780 b64_settings(const struct http *hp, const char *s)
2781 {
2782 	uint16_t i;
2783 	uint64_t v, vv;
2784 	const char *buf;
2785 	int shift;
2786 
2787 	while (*s) {
2788 		v = 0;
2789 		for (shift = 42; shift >= 0; shift -= 6) {
2790 			if (*s >= 'A' && *s <= 'Z')
2791 				vv = (*s - 'A');
2792 			else if (*s >= 'a' && *s <= 'z')
2793 				vv = (*s - 'a') + 26;
2794 			else if (*s >= '0' && *s <= '9')
2795 				vv = (*s - '0') + 52;
2796 			else if (*s == '-')
2797 				vv = 62;
2798 			else if (*s == '_')
2799 				vv = 63;
2800 			else
2801 				vtc_fatal(hp->vl,
2802 				    "Bad \"HTTP2-Settings\" header");
2803 			v |= vv << shift;
2804 			s++;
2805 		}
2806 		i = v >> 32;
2807 		v &= 0xffff;
2808 
2809 		if (i <= SETTINGS_MAX)
2810 			buf = h2_settings[i];
2811 		else
2812 			buf = "unknown";
2813 
2814 		if (v == 1) {
2815 			if (hp->sfd)
2816 				assert(HPK_ResizeTbl(hp->encctx, v) != hpk_err);
2817 			else
2818 				assert(HPK_ResizeTbl(hp->decctx, v) != hpk_err);
2819 		}
2820 
2821 		vtc_log(hp->vl, 4, "Upgrade: %s (%d): %ju",
2822 		    buf, i, (intmax_t)v);
2823 	}
2824 }
2825 
2826 void
start_h2(struct http * hp)2827 start_h2(struct http *hp)
2828 {
2829 	CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
2830 	AZ(pthread_mutex_init(&hp->mtx, NULL));
2831 	AZ(pthread_cond_init(&hp->cond, NULL));
2832 	VTAILQ_INIT(&hp->streams);
2833 	hp->iws = 0xffff;
2834 	hp->ws = 0xffff;
2835 
2836 	hp->h2 = 1;
2837 
2838 	hp->decctx = HPK_NewCtx(4096);
2839 	hp->encctx = HPK_NewCtx(4096);
2840 	AZ(pthread_create(&hp->tp, NULL, receive_frame, hp));
2841 }
2842 
2843 void
stop_h2(struct http * hp)2844 stop_h2(struct http *hp)
2845 {
2846 	struct stream *s, *s2;
2847 
2848 	CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
2849 	VTAILQ_FOREACH_SAFE(s, &hp->streams, list, s2) {
2850 		if (s->running)
2851 			stream_wait(s);
2852 		AZ(pthread_mutex_lock(&hp->mtx));
2853 		VTAILQ_REMOVE(&hp->streams, s, list);
2854 		AZ(pthread_mutex_unlock(&hp->mtx));
2855 		stream_delete(s);
2856 	}
2857 
2858 	AZ(pthread_mutex_lock(&hp->mtx));
2859 	hp->h2 = 0;
2860 	AZ(pthread_cond_signal(&hp->cond));
2861 	AZ(pthread_mutex_unlock(&hp->mtx));
2862 	AZ(pthread_join(hp->tp, NULL));
2863 
2864 	HPK_FreeCtx(hp->decctx);
2865 	HPK_FreeCtx(hp->encctx);
2866 
2867 	AZ(pthread_mutex_destroy(&hp->mtx));
2868 	AZ(pthread_cond_destroy(&hp->cond));
2869 }
2870