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