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