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