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