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