varnish-cache/bin/varnishtest/vtc_http.c
1
/*-
2
 * Copyright (c) 2008-2015 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
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/socket.h>
32
33
#include <errno.h>
34
#include <math.h>
35
#include <poll.h>
36
#include <stdio.h>
37
#include <stdlib.h>
38
#include <unistd.h>
39
#include <string.h>
40
41
#include "vtc.h"
42
#include "vtc_http.h"
43
44
#include "vct.h"
45
#include "vfil.h"
46
#include "vgz.h"
47
#include "vnum.h"
48
#include "vrnd.h"
49
#include "vtcp.h"
50
#include "hpack.h"
51
52
extern const struct cmds http_cmds[];
53
54
/* SECTION: client-server client/server
55
 *
56
 * Client and server threads are fake HTTP entities used to test your Varnish
57
 * and VCL. They take any number of arguments, and the one that are not
58
 * recognized, assuming they don't start with '-', are treated as
59
 * specifications, laying out the actions to undertake::
60
 *
61
 *         client cNAME [...]
62
 *         server sNAME [...]
63
 *
64
 * Clients and server are identified by a string that's the first argument,
65
 * clients' names start with 'c' and servers' names start with 's'.
66
 *
67
 * As the client and server commands share a good deal of arguments and
68
 * specification actions, they are grouped in this single section, specific
69
 * items will be explicitly marked as such.
70
 *
71
 * SECTION: client-server.macros Macros and automatic behaviour
72
 *
73
 * To make things easier in the general case, clients will connect by default
74
 * to the first Varnish server declared and the -vcl+backend switch of the
75
 * ``varnish`` command will add all the declared servers as backends.
76
 *
77
 * Be careful though, servers will by default listen to the 127.0.0.1 IP and
78
 * will pick a random port, and publish 3 macros: sNAME_addr, sNAME_port and
79
 * sNAME_sock, but only once they are started.
80
 * For 'varnish -vcl+backend' to create the vcl with the correct values, the
81
 * server must be started first.
82
 *
83
 * SECTION: client-server.args Arguments
84
 *
85
 * \-start
86
 *        Start the thread in background, processing the last given
87
 *        specification.
88
 *
89
 * \-wait
90
 *        Block until the thread finishes.
91
 *
92
 * \-run (client only)
93
 *        Equivalent to "-start -wait".
94
 *
95
 * \-repeat NUMBER
96
 *        Instead of processing the specification only once, do it NUMBER times.
97
 *
98
 * \-keepalive
99
 *        For repeat, do not open new connections but rather run all
100
 *        iterations in the same connection
101
 *
102
 * \-break (server only)
103
 *        Stop the server.
104
 *
105
 * \-listen STRING (server only)
106
 *        Dictate the listening socket for the server. STRING is of the form
107
 *        "IP PORT", or "/PATH/TO/SOCKET" for a Unix domain socket. In the
108
 *        latter case, the path must begin with '/', and the server must be
109
 *        able to create it.
110
 *
111
 * \-connect STRING (client only)
112
 *        Indicate the server to connect to. STRING is also of the form
113
 *        "IP PORT", or "/PATH/TO/SOCKET". As with "server -listen", a
114
 *        Unix domain socket is recognized when STRING begins with a '/'.
115
 *
116
 * \-dispatch (server only, s0 only)
117
 *        Normally, to keep things simple, server threads only handle one
118
 *        connection at a time, but the -dispatch switch allows to accept
119
 *        any number of connection and handle them following the given spec.
120
 *
121
 *        However, -dispatch is only allowed for the server name "s0".
122
 *
123
 * \-proxy1 STRING (client only)
124
 *        Use the PROXY protocol version 1 for this connection. STRING
125
 *        is of the form "CLIENTIP:PORT SERVERIP:PORT".
126
 *
127
 * \-proxy2 STRING (client only)
128
 *        Use the PROXY protocol version 2 for this connection. STRING
129
 *        is of the form "CLIENTIP:PORT SERVERIP:PORT".
130
 *
131
 * SECTION: client-server.spec Specification
132
 *
133
 * It's a string, either double-quoted "like this", but most of the time
134
 * enclosed in curly brackets, allowing multilining. Write a command per line in
135
 * it, empty line are ignored, and long line can be wrapped by using a
136
 * backslash. For example::
137
 *
138
 *     client c1 {
139
 *         txreq -url /foo \
140
 *               -hdr "bar: baz"
141
 *
142
 *         rxresp
143
 *     } -run
144
 */
145
146
#define ONLY_CLIENT(hp, av)                                             \
147
        do {                                                            \
148
                if (hp->h2)                                             \
149
                        vtc_fatal(hp->vl,                               \
150
                            "\"%s\" only possible before H/2 upgrade",  \
151
                                        av[0]);                         \
152
                if (hp->sfd != NULL)                                    \
153
                        vtc_fatal(hp->vl,                               \
154
                            "\"%s\" only possible in client", av[0]);   \
155
        } while (0)
156
157
#define ONLY_SERVER(hp, av)                                             \
158
        do {                                                            \
159
                if (hp->h2)                                             \
160
                        vtc_fatal(hp->vl,                               \
161
                            "\"%s\" only possible before H/2 upgrade",  \
162
                                        av[0]);                         \
163
                if (hp->sfd == NULL)                                    \
164
                        vtc_fatal(hp->vl,                               \
165
                            "\"%s\" only possible in server", av[0]);   \
166
        } while (0)
167
168
169
/* XXX: we may want to vary this */
170
static const char * const nl = "\r\n";
171
172
/**********************************************************************
173
 * Generate a synthetic body
174
 */
175
176
char *
177 376
synth_body(const char *len, int rnd)
178
{
179
        int i, j, k, l;
180
        char *b;
181
182
183 376
        AN(len);
184 376
        i = strtoul(len, NULL, 0);
185 376
        assert(i > 0);
186 376
        b = malloc(i + 1L);
187 376
        AN(b);
188 376
        l = k = '!';
189 38553176
        for (j = 0; j < i; j++) {
190 38552800
                if ((j % 64) == 63) {
191 602296
                        b[j] = '\n';
192 602296
                        k++;
193 602296
                        if (k == '~')
194 6440
                                k = '!';
195 602296
                        l = k;
196 37950504
                } else if (rnd) {
197 8236
                        b[j] = (VRND_RandomTestable() % 95) + ' ';
198
                } else {
199 37942268
                        b[j] = (char)l;
200 37942268
                        if (++l == '~')
201 407172
                                l = '!';
202
                }
203
        }
204 376
        b[i - 1] = '\n';
205 376
        b[i] = '\0';
206 376
        return (b);
207
}
208
209
/**********************************************************************
210
 * Finish and write the vsb to the fd
211
 */
212
213
static void
214 7925
http_write(const struct http *hp, int lvl, const char *pfx)
215
{
216
        ssize_t l;
217
218 7925
        AZ(VSB_finish(hp->vsb));
219 7934
        vtc_dump(hp->vl, lvl, pfx, VSB_data(hp->vsb), VSB_len(hp->vsb));
220 7934
        l = write(hp->fd, VSB_data(hp->vsb), VSB_len(hp->vsb));
221 7934
        if (l != VSB_len(hp->vsb))
222 16
                vtc_log(hp->vl, hp->fatal, "Write failed: (%zd vs %zd) %s",
223 16
                    l, VSB_len(hp->vsb), strerror(errno));
224 7934
}
225
226
/**********************************************************************
227
 * find header
228
 */
229
230
static char *
231 20704
http_find_header(char * const *hh, const char *hdr)
232
{
233
        int n, l;
234
        char *r;
235
236 20704
        l = strlen(hdr);
237
238 253742
        for (n = 3; hh[n] != NULL; n++) {
239 115247
                if (strncasecmp(hdr, hh[n], l) || hh[n][l] != ':')
240 106167
                        continue;
241 18184
                for (r = hh[n] + l + 1; vct_issp(*r); r++)
242 9104
                        continue;
243 9079
                return (r);
244
        }
245 11624
        return (NULL);
246
}
247
248
/**********************************************************************
249
 * count header
250
 */
251
252
static int
253 8052
http_count_header(char * const *hh, const char *hdr)
254
{
255 8052
        int n, l, r = 0;
256
257 8052
        l = strlen(hdr);
258
259 56238
        for (n = 3; hh[n] != NULL; n++) {
260 48186
                if (strncasecmp(hdr, hh[n], l) || hh[n][l] != ':')
261 44288
                        continue;
262 3898
                r++;
263
        }
264 8052
        return (r);
265
}
266
267
/* SECTION: client-server.spec.expect
268
 *
269
 * expect STRING1 OP STRING2
270
 *         Test if "STRING1 OP STRING2" is true, and if not, fails the test.
271
 *         OP can be ==, <, <=, >, >= when STRING1 and STRING2 represent numbers
272
 *         in which case it's an order operator. If STRING1 and STRING2 are
273
 *         meant as strings OP is a matching operator, either == (exact match)
274
 *         or ~ (regex match).
275
 *
276
 *         varnishtet will first try to resolve STRING1 and STRING2 by looking
277
 *         if they have special meanings, in which case, the resolved value is
278
 *         use for the test. Note that this value can be a string representing a
279
 *         number, allowing for tests such as::
280
 *
281
 *                 expect req.http.x-num > 2
282
 *
283
 *         Here's the list of recognized strings, most should be obvious as they
284
 *         either match VCL logic, or the txreq/txresp options:
285
 *
286
 *         - remote.ip
287
 *         - remote.port
288
 *         - remote.path
289
 *         - req.method
290
 *         - req.url
291
 *         - req.proto
292
 *         - resp.proto
293
 *         - resp.status
294
 *         - resp.reason
295
 *         - resp.chunklen
296
 *         - req.bodylen
297
 *         - req.body
298
 *         - resp.bodylen
299
 *         - resp.body
300
 *         - req.http.NAME
301
 *         - resp.http.NAME
302
 */
303
304
static const char *
305 20552
cmd_var_resolve(struct http *hp, char *spec)
306
{
307
        char **hh, *hdr;
308 20552
        if (!strcmp(spec, "remote.ip"))
309 8
                return(hp->rem_ip);
310 20544
        if (!strcmp(spec, "remote.port"))
311 8
                return(hp->rem_port);
312 20536
        if (!strcmp(spec, "remote.path"))
313 8
                return(hp->rem_path);
314 20528
        if (!strcmp(spec, "req.method"))
315 78
                return(hp->req[0]);
316 20450
        if (!strcmp(spec, "req.url"))
317 1066
                return(hp->req[1]);
318 19384
        if (!strcmp(spec, "req.proto"))
319 84
                return(hp->req[2]);
320 19300
        if (!strcmp(spec, "resp.proto"))
321 68
                return(hp->resp[0]);
322 19232
        if (!strcmp(spec, "resp.status"))
323 2356
                return(hp->resp[1]);
324 16876
        if (!strcmp(spec, "resp.reason"))
325 268
                return(hp->resp[2]);
326 16608
        if (!strcmp(spec, "resp.chunklen"))
327 0
                return(hp->chunklen);
328 16608
        if (!strcmp(spec, "req.bodylen"))
329 30
                return(hp->bodylen);
330 16578
        if (!strcmp(spec, "req.body"))
331 4
                return(hp->body != NULL ? hp->body : spec);
332 16574
        if (!strcmp(spec, "resp.bodylen"))
333 1158
                return(hp->bodylen);
334 15416
        if (!strcmp(spec, "resp.body"))
335 286
                return(hp->body != NULL ? hp->body : spec);
336 15130
        if (!strncmp(spec, "req.http.", 9)) {
337 460
                hh = hp->req;
338 460
                hdr = spec + 9;
339 14670
        } else if (!strncmp(spec, "resp.http.", 10)) {
340 4662
                hh = hp->resp;
341 4662
                hdr = spec + 10;
342 10008
        } else if (!strcmp(spec, "h2.state")) {
343 14
                if (hp->h2)
344 6
                        return ("true");
345
                else
346 8
                        return ("false");
347
        } else
348 9994
                return (spec);
349 5122
        hdr = http_find_header(hh, hdr);
350 5122
        return (hdr);
351
}
352
353
static void
354 10276
cmd_http_expect(CMD_ARGS)
355
{
356
        struct http *hp;
357
        const char *lhs;
358
        char *cmp;
359
        const char *rhs;
360
361
        (void)cmd;
362
        (void)vl;
363 10276
        CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC);
364 10276
        AZ(strcmp(av[0], "expect"));
365 10276
        av++;
366
367 10276
        AN(av[0]);
368 10276
        AN(av[1]);
369 10276
        AN(av[2]);
370 10276
        AZ(av[3]);
371 10276
        lhs = cmd_var_resolve(hp, av[0]);
372 10276
        cmp = av[1];
373 10276
        rhs = cmd_var_resolve(hp, av[2]);
374
375 10276
        vtc_expect(vl, av[0], lhs, cmp, av[2], rhs);
376 10276
}
377
378
static void
379 2
cmd_http_expect_pattern(CMD_ARGS)
380
{
381
        char *p;
382
        struct http *hp;
383 2
        char t = '0';
384
385
        (void)cmd;
386
        (void)vl;
387 2
        CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC);
388 2
        AZ(strcmp(av[0], "expect_pattern"));
389 2
        av++;
390 2
        AZ(av[0]);
391 131074
        for (p = hp->body; *p != '\0'; p++) {
392 131072
                if (*p != t)
393 0
                        vtc_fatal(hp->vl,
394
                            "EXPECT PATTERN FAIL @%zd should 0x%02x is 0x%02x",
395 0
                            p - hp->body, t, *p);
396 131072
                t += 1;
397 131072
                t &= ~0x08;
398
        }
399 2
        vtc_log(hp->vl, 4, "EXPECT PATTERN SUCCESS");
400 2
}
401
402
/**********************************************************************
403
 * Split a HTTP protocol header
404
 */
405
406
static void
407 8052
http_splitheader(struct http *hp, int req)
408
{
409
        char *p, *q, **hh;
410
        int n;
411
        char buf[20];
412
413 8052
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
414 8052
        if (req) {
415 3644
                memset(hp->req, 0, sizeof hp->req);
416 3644
                hh = hp->req;
417
        } else {
418 4408
                memset(hp->resp, 0, sizeof hp->resp);
419 4408
                hh = hp->resp;
420
        }
421
422 8052
        n = 0;
423 8052
        p = hp->rxbuf;
424
425
        /* REQ/PROTO */
426 16104
        while (vct_islws(*p))
427 0
                p++;
428 8052
        hh[n++] = p;
429 62394
        while (!vct_islws(*p))
430 46290
                p++;
431 8052
        AZ(vct_iscrlf(p));
432 8052
        *p++ = '\0';
433
434
        /* URL/STATUS */
435 16104
        while (vct_issp(*p))            /* XXX: H space only */
436 0
                p++;
437 8052
        AZ(vct_iscrlf(p));
438 8052
        hh[n++] = p;
439 50902
        while (!vct_islws(*p))
440 34798
                p++;
441 8053
        if (vct_iscrlf(p)) {
442 3
                hh[n++] = NULL;
443 3
                q = p;
444 3
                p += vct_skipcrlf(p);
445 3
                *q = '\0';
446
        } else {
447 8050
                *p++ = '\0';
448
                /* PROTO/MSG */
449 16100
                while (vct_issp(*p))            /* XXX: H space only */
450 0
                        p++;
451 8050
                hh[n++] = p;
452 65266
                while (!vct_iscrlf(p))
453 49166
                        p++;
454 8050
                q = p;
455 8050
                p += vct_skipcrlf(p);
456 8050
                *q = '\0';
457
        }
458 8053
        assert(n == 3);
459
460 64285
        while (*p != '\0') {
461 56232
                assert(n < MAX_HDR);
462 56231
                if (vct_iscrlf(p))
463
                        break;
464 48179
                hh[n++] = p++;
465 1161471
                while (*p != '\0' && !vct_iscrlf(p))
466 1065113
                        p++;
467 48179
                q = p;
468 48179
                p += vct_skipcrlf(p);
469 48179
                *q = '\0';
470
        }
471 8052
        p += vct_skipcrlf(p);
472 8052
        assert(*p == '\0');
473
474 80394
        for (n = 0; n < 3 || hh[n] != NULL; n++) {
475 72342
                bprintf(buf, "http[%2d] ", n);
476 72340
                vtc_dump(hp->vl, 4, buf, hh[n], -1);
477
        }
478 8052
}
479
480
481
/**********************************************************************
482
 * Receive another character
483
 */
484
485
static int
486 1665164
http_rxchar(struct http *hp, int n, int eof)
487
{
488
        int i;
489
        struct pollfd pfd[1];
490
491 4995236
        while (n > 0) {
492 1664380
                pfd[0].fd = hp->fd;
493 1664380
                pfd[0].events = POLLIN;
494 1664380
                pfd[0].revents = 0;
495 1664380
                i = poll(pfd, 1, hp->timeout);
496 1665258
                if (i < 0 && errno == EINTR)
497 0
                        continue;
498 1665258
                if (i == 0) {
499 0
                        vtc_log(hp->vl, hp->fatal,
500
                            "HTTP rx timeout (fd:%d %u ms)",
501
                            hp->fd, hp->timeout);
502 0
                        continue;
503
                }
504 1665258
                if (i < 0) {
505 0
                        vtc_log(hp->vl, hp->fatal,
506
                            "HTTP rx failed (fd:%d poll: %s)",
507 0
                            hp->fd, strerror(errno));
508 0
                        continue;
509
                }
510 1665258
                assert(i > 0);
511 1665258
                assert(hp->prxbuf + n < hp->nrxbuf);
512 1665258
                i = read(hp->fd, hp->rxbuf + hp->prxbuf, n);
513 1664829
                if (!(pfd[0].revents & POLLIN))
514 0
                        vtc_log(hp->vl, 4,
515
                            "HTTP rx poll (fd:%d revents: %x n=%d, i=%d)",
516 0
                            hp->fd, pfd[0].revents, n, i);
517 1664928
                if (i == 0 && eof)
518 14
                        return (i);
519 1664914
                if (i == 0) {
520 6
                        vtc_log(hp->vl, hp->fatal,
521
                            "HTTP rx EOF (fd:%d read: %s) %d",
522 6
                            hp->fd, strerror(errno), n);
523 6
                        return (-1);
524
                }
525 1664908
                if (i < 0) {
526 0
                        vtc_log(hp->vl, hp->fatal,
527
                            "HTTP rx failed (fd:%d read: %s)",
528 0
                            hp->fd, strerror(errno));
529 0
                        return (-1);
530
                }
531 1664908
                hp->prxbuf += i;
532 1664908
                hp->rxbuf[hp->prxbuf] = '\0';
533 1664908
                n -= i;
534
        }
535 1665692
        return (1);
536
}
537
538
static int
539 1763
http_rxchunk(struct http *hp)
540
{
541
        char *q;
542
        int l, i;
543
544 1763
        l = hp->prxbuf;
545
        do {
546 8702
                if (http_rxchar(hp, 1, 0) < 0)
547 2
                        return (-1);
548 8700
        } while (hp->rxbuf[hp->prxbuf - 1] != '\n');
549 1761
        vtc_dump(hp->vl, 4, "len", hp->rxbuf + l, -1);
550 1761
        i = strtoul(hp->rxbuf + l, &q, 16);
551 1761
        bprintf(hp->chunklen, "%d", i);
552 3522
        if ((q == hp->rxbuf + l) ||
553 3522
                (*q != '\0' && !vct_islws(*q))) {
554 0
                vtc_log(hp->vl, hp->fatal, "chunked fail %02x @ %td",
555 0
                    *q, q - (hp->rxbuf + l));
556 0
                return (-1);
557
        }
558 1761
        assert(q != hp->rxbuf + l);
559 1761
        assert(*q == '\0' || vct_islws(*q));
560 1761
        hp->prxbuf = l;
561 1761
        if (i > 0) {
562 1387
                if (http_rxchar(hp, i, 0) < 0)
563 0
                        return (-1);
564 1387
                vtc_dump(hp->vl, 4, "chunk", hp->rxbuf + l, i);
565
        }
566 1761
        l = hp->prxbuf;
567 1761
        if (http_rxchar(hp, 2, 0) < 0)
568 0
                return (-1);
569 1761
        if (!vct_iscrlf(hp->rxbuf + l)) {
570 0
                vtc_log(hp->vl, hp->fatal,
571
                    "Wrong chunk tail[0] = %02x",
572 0
                    hp->rxbuf[l] & 0xff);
573 0
                return (-1);
574
        }
575 1761
        if (!vct_iscrlf(hp->rxbuf + l + 1)) {
576 0
                vtc_log(hp->vl, hp->fatal,
577
                    "Wrong chunk tail[1] = %02x",
578 0
                    hp->rxbuf[l + 1] & 0xff);
579 0
                return (-1);
580
        }
581 1761
        hp->prxbuf = l;
582 1761
        hp->rxbuf[l] = '\0';
583 1761
        return (i);
584
}
585
586
/**********************************************************************
587
 * Swallow a HTTP message body
588
 */
589
590
static void
591 7976
http_swallow_body(struct http *hp, char * const *hh, int body)
592
{
593
        char *p;
594
        int i, l, ll;
595
596 7976
        ll = 0;
597 7976
        p = http_find_header(hh, "transfer-encoding");
598 7976
        if (p != NULL && !strcasecmp(p, "chunked")) {
599 2125
                while (http_rxchunk(hp) > 0)
600 1373
                        continue;
601 376
                vtc_dump(hp->vl, 4, "body", hp->body, ll);
602 376
                ll = hp->rxbuf + hp->prxbuf - hp->body;
603 376
                hp->bodyl = ll;
604 376
                bprintf(hp->bodylen, "%d", ll);
605 376
                return;
606
        }
607 7600
        p = http_find_header(hh, "content-length");
608 7600
        if (p != NULL) {
609 3878
                l = strtoul(p, NULL, 10);
610 3878
                if (http_rxchar(hp, l, 0) < 0)
611 4
                        return;
612 3874
                vtc_dump(hp->vl, 4, "body", hp->body, l);
613 3874
                hp->bodyl = l;
614 3874
                bprintf(hp->bodylen, "%d", l);
615 3874
                return;
616
        }
617 3722
        if (body) {
618
                do  {
619 262376
                        i = http_rxchar(hp, 1, 1);
620 262376
                        if (i < 0)
621 0
                                return;
622 262376
                        ll += i;
623 262376
                } while (i > 0);
624 8
                vtc_dump(hp->vl, 4, "rxeof", hp->body, ll);
625
        }
626 3722
        hp->bodyl = ll;
627 3722
        bprintf(hp->bodylen, "%d", ll);
628
}
629
630
/**********************************************************************
631
 * Receive a HTTP protocol header
632
 */
633
634
static void
635 8085
http_rxhdr(struct http *hp)
636
{
637
        int i;
638
        char *p;
639
640 8085
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
641 8085
        hp->prxbuf = 0;
642 8085
        hp->body = NULL;
643 8085
        bprintf(hp->bodylen, "%s", "<undef>");
644
        while (1) {
645 2766921
                (void)http_rxchar(hp, 1, 0);
646 1387469
                p = hp->rxbuf + hp->prxbuf - 1;
647 1451753
                for (i = 0; p > hp->rxbuf; p--) {
648 1443619
                        if (*p != '\n')
649 1371284
                                break;
650 72335
                        if (p - 1 > hp->rxbuf && p[-1] == '\r')
651 72338
                                p--;
652 72335
                        if (++i == 2)
653 8051
                                break;
654
                }
655 1387469
                if (i == 2)
656 8051
                        break;
657
        }
658 8051
        vtc_dump(hp->vl, 4, "rxhdr", hp->rxbuf, -1);
659 8052
        vtc_log(hp->vl, 4, "rxhdrlen = %zd", strlen(hp->rxbuf));
660 8052
        hp->body = hp->rxbuf + hp->prxbuf;
661 8052
}
662
663
/* SECTION: client-server.spec.rxresp
664
 *
665
 * rxresp [-no_obj] (client only)
666
 *         Receive and parse a response's headers and body. If -no_obj is present, only get
667
 *         the headers.
668
 */
669
static void
670 4382
cmd_http_rxresp(CMD_ARGS)
671
{
672
        struct http *hp;
673 4382
        int has_obj = 1;
674
675
        (void)cmd;
676
        (void)vl;
677 4382
        CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC);
678 4382
        ONLY_CLIENT(hp, av);
679 4382
        AZ(strcmp(av[0], "rxresp"));
680 4382
        av++;
681
682 4436
        for (; *av != NULL; av++)
683 54
                if (!strcmp(*av, "-no_obj"))
684 54
                        has_obj = 0;
685
                else
686 0
                        vtc_fatal(hp->vl,
687
                            "Unknown http rxresp spec: %s\n", *av);
688 4382
        http_rxhdr(hp);
689 4382
        http_splitheader(hp, 0);
690 4382
        if (http_count_header(hp->resp, "Content-Length") > 1)
691 0
                vtc_fatal(hp->vl,
692
                    "Multiple Content-Length headers.\n");
693 4382
        if (!has_obj)
694 54
                return;
695 4328
        else if (!strcmp(hp->resp[1], "200"))
696 3422
                http_swallow_body(hp, hp->resp, 1);
697
        else
698 906
                http_swallow_body(hp, hp->resp, 0);
699 4328
        vtc_log(hp->vl, 4, "bodylen = %s", hp->bodylen);
700
}
701
702
/* SECTION: client-server.spec.rxresphdrs
703
 *
704
 * rxresphdrs (client only)
705
 *         Receive and parse a response's headers.
706
 */
707
static void
708 26
cmd_http_rxresphdrs(CMD_ARGS)
709
{
710
        struct http *hp;
711
712
        (void)cmd;
713
        (void)vl;
714 26
        CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC);
715 26
        ONLY_CLIENT(hp, av);
716 26
        AZ(strcmp(av[0], "rxresphdrs"));
717 26
        av++;
718
719 52
        for (; *av != NULL; av++)
720 0
                vtc_fatal(hp->vl, "Unknown http rxresp spec: %s\n", *av);
721 26
        http_rxhdr(hp);
722 26
        http_splitheader(hp, 0);
723 26
        if (http_count_header(hp->resp, "Content-Length") > 1)
724 0
                vtc_fatal(hp->vl,
725
                    "Multiple Content-Length headers.\n");
726 26
}
727
728
729
/**********************************************************************
730
 * Ungzip rx'ed body
731
 */
732
733
#define OVERHEAD 64L
734
735
static void
736 72
cmd_http_gunzip(CMD_ARGS)
737
{
738
        int i;
739
        z_stream vz;
740
        struct http *hp;
741
        char *p;
742
        unsigned l;
743
744
        (void)av;
745
        (void)cmd;
746
        (void)vl;
747 72
        CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC);
748
749 72
        memset(&vz, 0, sizeof vz);
750
751 72
        AN(hp->body);
752 72
        if (hp->body[0] != (char)0x1f || hp->body[1] != (char)0x8b)
753 0
                vtc_log(hp->vl, hp->fatal,
754
                    "Gunzip error: Body lacks gzip magics");
755 72
        vz.next_in = TRUST_ME(hp->body);
756 72
        vz.avail_in = hp->bodyl;
757
758 72
        l = hp->bodyl * 10;
759 72
        p = calloc(1, l);
760 72
        AN(p);
761
762 72
        vz.next_out = TRUST_ME(p);
763 72
        vz.avail_out = l;
764
765 72
        assert(Z_OK == inflateInit2(&vz, 31));
766 72
        i = inflate(&vz, Z_FINISH);
767 72
        assert(vz.total_out < l);
768 72
        hp->bodyl = vz.total_out;
769 72
        memcpy(hp->body, p, hp->bodyl);
770 72
        free(p);
771 72
        vtc_log(hp->vl, 3, "new bodylen %u", hp->bodyl);
772 72
        vtc_dump(hp->vl, 4, "body", hp->body, hp->bodyl);
773 72
        bprintf(hp->bodylen, "%u", hp->bodyl);
774
#ifdef VGZ_EXTENSIONS
775 216
        vtc_log(hp->vl, 4, "startbit = %ju %ju/%ju",
776 72
            (uintmax_t)vz.start_bit,
777 144
            (uintmax_t)vz.start_bit >> 3, (uintmax_t)vz.start_bit & 7);
778 216
        vtc_log(hp->vl, 4, "lastbit = %ju %ju/%ju",
779 72
            (uintmax_t)vz.last_bit,
780 144
            (uintmax_t)vz.last_bit >> 3, (uintmax_t)vz.last_bit & 7);
781 216
        vtc_log(hp->vl, 4, "stopbit = %ju %ju/%ju",
782 72
            (uintmax_t)vz.stop_bit,
783 144
            (uintmax_t)vz.stop_bit >> 3, (uintmax_t)vz.stop_bit & 7);
784
#endif
785 72
        if (i != Z_STREAM_END)
786 0
                vtc_log(hp->vl, hp->fatal,
787
                    "Gunzip error = %d (%s) in:%jd out:%jd",
788 0
                    i, vz.msg, (intmax_t)vz.total_in, (intmax_t)vz.total_out);
789 72
        assert(Z_OK == inflateEnd(&vz));
790 72
        hp->body[hp->bodyl] = '\0';
791 72
}
792
793
/**********************************************************************
794
 * Create a gzip'ed body
795
 */
796
797
static void
798 104
gzip_body(const struct http *hp, const char *txt, char **body, int *bodylen)
799
{
800
        int l, i;
801
        z_stream vz;
802
803 104
        memset(&vz, 0, sizeof vz);
804
805 104
        l = strlen(txt);
806 104
        *body = calloc(1, l + OVERHEAD);
807 104
        AN(*body);
808
809 104
        vz.next_in = TRUST_ME(txt);
810 104
        vz.avail_in = l;
811
812 104
        vz.next_out = TRUST_ME(*body);
813 104
        vz.avail_out = l + OVERHEAD;
814
815 104
        assert(Z_OK == deflateInit2(&vz,
816
            hp->gziplevel, Z_DEFLATED, 31, 9, Z_DEFAULT_STRATEGY));
817 104
        assert(Z_STREAM_END == deflate(&vz, Z_FINISH));
818 104
        *bodylen = vz.total_out;
819
#ifdef VGZ_EXTENSIONS
820 104
        i = vz.stop_bit & 7;
821 104
        if (hp->gzipresidual >= 0 && hp->gzipresidual != i)
822 0
                vtc_log(hp->vl, hp->fatal,
823
                    "Wrong gzip residual got %d wanted %d",
824
                    i, hp->gzipresidual);
825 312
        vtc_log(hp->vl, 4, "startbit = %ju %ju/%ju",
826 104
            (uintmax_t)vz.start_bit,
827 208
            (uintmax_t)vz.start_bit >> 3, (uintmax_t)vz.start_bit & 7);
828 312
        vtc_log(hp->vl, 4, "lastbit = %ju %ju/%ju",
829 104
            (uintmax_t)vz.last_bit,
830 208
            (uintmax_t)vz.last_bit >> 3, (uintmax_t)vz.last_bit & 7);
831 312
        vtc_log(hp->vl, 4, "stopbit = %ju %ju/%ju",
832 104
            (uintmax_t)vz.stop_bit,
833 208
            (uintmax_t)vz.stop_bit >> 3, (uintmax_t)vz.stop_bit & 7);
834 104
        assert(Z_OK == deflateEnd(&vz));
835
#endif
836 104
}
837
838
/**********************************************************************
839
 * Handle common arguments of a transmited request or response
840
 */
841
842
static char* const *
843 7693
http_tx_parse_args(char * const *av, struct vtclog *vl, struct http *hp,
844
    char *body, unsigned nohost)
845
{
846 7693
        int bodylen = 0;
847
        char *b, *c;
848
        char *nullbody;
849
        char *m;
850 7693
        int nolen = 0;
851
        int l;
852
853
        (void)vl;
854 7693
        nullbody = body;
855
856 10665
        for (; *av != NULL; av++) {
857 4768
                if (!strcmp(*av, "-nolen")) {
858 166
                        nolen = 1;
859 4602
                } else if (!strcmp(*av, "-nohost")) {
860 4
                        nohost = 1;
861 4598
                } else if (!strcmp(*av, "-hdr")) {
862 2796
                        if (!strncasecmp(av[1], "Host:", 5))
863 24
                                nohost = 1;
864 2796
                        VSB_printf(hp->vsb, "%s%s", av[1], nl);
865 2796
                        av++;
866 1802
                } else if (!strcmp(*av, "-hdrlen")) {
867 6
                        VSB_printf(hp->vsb, "%s: ", av[1]);
868 6
                        l = atoi(av[2]);
869 1312
                        while (l-- > 0)
870 1300
                                VSB_putc(hp->vsb, '0' + (l % 10));
871 6
                        VSB_printf(hp->vsb, "%s", nl);
872 6
                        av+=2;
873
                } else
874 1796
                        break;
875
        }
876 9521
        for (; *av != NULL; av++) {
877 1828
                if (!strcmp(*av, "-body")) {
878 1342
                        assert(body == nullbody);
879 1342
                        REPLACE(body, av[1]);
880
881 1342
                        AN(body);
882 1342
                        av++;
883 1342
                        bodylen = strlen(body);
884 42486
                        for (b = body; *b != '\0'; b++) {
885 41144
                                if (*b == '\\' && b[1] == '0') {
886 8
                                        *b = '\0';
887 82
                                        for (c = b+1; *c != '\0'; c++) {
888 74
                                                *c = c[1];
889
                                        }
890 8
                                        b++;
891 8
                                        bodylen--;
892
                                }
893
                        }
894 486
                } else if (!strcmp(*av, "-bodylen")) {
895 350
                        assert(body == nullbody);
896 350
                        free(body);
897 350
                        body = synth_body(av[1], 0);
898 350
                        bodylen = strlen(body);
899 350
                        av++;
900 136
                } else if (!strcmp(*av, "-gzipresidual")) {
901 16
                        hp->gzipresidual = strtoul(av[1], NULL, 0);
902 16
                        av++;
903 120
                } else if (!strcmp(*av, "-gziplevel")) {
904 16
                        hp->gziplevel = strtoul(av[1], NULL, 0);
905 16
                        av++;
906 104
                } else if (!strcmp(*av, "-gziplen")) {
907 6
                        assert(body == nullbody);
908 6
                        free(body);
909 6
                        b = synth_body(av[1], 1);
910 6
                        gzip_body(hp, b, &body, &bodylen);
911 6
                        free(b);
912 6
                        VSB_printf(hp->vsb, "Content-Encoding: gzip%s", nl);
913
                        // vtc_hexdump(hp->vl, 4, "gzip", (void*)body, bodylen);
914 6
                        av++;
915 98
                } else if (!strcmp(*av, "-gzipbody")) {
916 98
                        assert(body == nullbody);
917 98
                        free(body);
918 98
                        gzip_body(hp, av[1], &body, &bodylen);
919 98
                        VSB_printf(hp->vsb, "Content-Encoding: gzip%s", nl);
920
                        // vtc_hexdump(hp->vl, 4, "gzip", (void*)body, bodylen);
921 98
                        av++;
922
                } else
923 0
                        break;
924
        }
925 7693
        if (!nohost) {
926 4229
                m = macro_get("localhost", NULL);
927 4230
                AN(m);
928 4230
                VSB_printf(hp->vsb, "Host: %s%s", m, nl);
929 4230
                free(m);
930
        }
931 7694
        if (body != NULL && !nolen)
932 3282
                VSB_printf(hp->vsb, "Content-Length: %d%s", bodylen, nl);
933 7694
        VSB_cat(hp->vsb, nl);
934 7694
        if (body != NULL) {
935 3424
                VSB_bcat(hp->vsb, body, bodylen);
936 3424
                free(body);
937
        }
938 7694
        return (av);
939
}
940
941
/* SECTION: client-server.spec.txreq
942
 *
943
 * txreq|txresp [...]
944
 *         Send a minimal request or response, but overload it if necessary.
945
 *
946
 *         txreq is client-specific and txresp is server-specific.
947
 *
948
 *         The only thing different between a request and a response, apart
949
 *         from who can send them is that the first line (request line vs
950
 *         status line), so all the options are prety much the same.
951
 *
952
 *         \-req STRING (txreq only)
953
 *                 What method to use (default: "GET").
954
 *
955
 *         \-url STRING (txreq only)
956
 *                 What location to use (default "/").
957
 *
958
 *         \-proto STRING
959
 *                 What protocol use in the status line.
960
 *                 (default: "HTTP/1.1").
961
 *
962
 *         \-status NUMBER (txresp only)
963
 *                 What status code to return (default 200).
964
 *
965
 *         \-reason STRING (txresp only)
966
 *                 What message to put in the status line (default: "OK").
967
 *
968
 *         These three switches can appear in any order but must come before the
969
 *         following ones.
970
 *
971
 *         \-nohost
972
 *                 Don't include a Host header in the request.
973
 *
974
 *         \-nolen
975
 *                 Don't include a Content-Length header.
976
 *
977
 *         \-hdr STRING
978
 *                 Add STRING as a header, it must follow this format:
979
 *                 "name: value". It can be called multiple times.
980
 *
981
 *         \-hdrlen STRING NUMBER
982
 *                 Add STRING as a header with NUMBER bytes of content.
983
 *
984
 *         You can then use the arguments related to the body:
985
 *
986
 *         \-body STRING
987
 *                 Input STRING as body.
988
 *
989
 *         \-bodylen NUMBER
990
 *                 Generate and input a body that is NUMBER bytes-long.
991
 *
992
 *         \-gziplevel NUMBER
993
 *                 Set the gzip level (call it before any of the other gzip
994
 *                 switches).
995
 *
996
 *         \-gzipresidual NUMBER
997
 *                 Add extra gzip bits. You should never need it.
998
 *
999
 *         \-gzipbody STRING
1000
 *                 Zip STRING and send it as body.
1001
 *
1002
 *         \-gziplen NUMBER
1003
 *                 Combine -body and -gzipbody: create a body of length NUMBER,
1004
 *                 zip it and send as body.
1005
 */
1006
1007
/**********************************************************************
1008
 * Transmit a response
1009
 */
1010
1011
static void
1012 3352
cmd_http_txresp(CMD_ARGS)
1013
{
1014
        struct http *hp;
1015 3352
        const char *proto = "HTTP/1.1";
1016 3352
        const char *status = "200";
1017 3352
        const char *reason = "OK";
1018 3352
        char* body = NULL;
1019
1020
        (void)cmd;
1021
        (void)vl;
1022 3352
        CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC);
1023 3352
        ONLY_SERVER(hp, av);
1024 3352
        AZ(strcmp(av[0], "txresp"));
1025 3352
        av++;
1026
1027 3352
        VSB_clear(hp->vsb);
1028
1029 3748
        for (; *av != NULL; av++) {
1030 2586
                if (!strcmp(*av, "-proto")) {
1031 82
                        proto = av[1];
1032 82
                        av++;
1033 2504
                } else if (!strcmp(*av, "-status")) {
1034 262
                        status = av[1];
1035 262
                        av++;
1036 2242
                } else if (!strcmp(*av, "-reason")) {
1037 52
                        reason = av[1];
1038 52
                        av++;
1039 52
                        continue;
1040
                } else
1041 2190
                        break;
1042
        }
1043
1044 3352
        VSB_printf(hp->vsb, "%s %s %s%s", proto, status, reason, nl);
1045
1046
        /* send a "Content-Length: 0" header unless something else happens */
1047 3352
        REPLACE(body, "");
1048
1049 3352
        av = http_tx_parse_args(av, vl, hp, body, 1);
1050 3352
        if (*av != NULL)
1051 0
                vtc_fatal(hp->vl, "Unknown http txresp spec: %s\n", *av);
1052
1053 3352
        http_write(hp, 4, "txresp");
1054 3352
}
1055
1056
static void
1057 2
cmd_http_upgrade(CMD_ARGS)
1058
{
1059
        char *h;
1060
        struct http *hp;
1061
1062 2
        CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC);
1063 2
        ONLY_SERVER(hp, av);
1064 2
        AN(hp->sfd);
1065
1066 2
        h = http_find_header(hp->req, "Upgrade");
1067 2
        if (!h || strcmp(h, "h2c"))
1068 0
                vtc_fatal(vl, "Req misses \"Upgrade: h2c\" header");
1069
1070 2
        h = http_find_header(hp->req, "Connection");
1071 2
        if (!h || strcmp(h, "Upgrade, HTTP2-Settings"))
1072 0
                vtc_fatal(vl, "Req misses \"Connection: "
1073
                        "Upgrade, HTTP2-Settings\" header");
1074
1075 2
        h = http_find_header(hp->req, "HTTP2-Settings");
1076 2
        if (!h)
1077 0
                vtc_fatal(vl, "Req misses \"HTTP2-Settings\" header");
1078
1079
1080 2
        parse_string("txresp -status 101 "
1081
                                "-hdr \"Connection: Upgrade\" "
1082
                                "-hdr \"Upgrade: h2c\"\n", cmd, hp, vl);
1083
1084 2
        b64_settings(hp, h);
1085
1086 2
        parse_string("rxpri\n"
1087
                        "stream 0 {\n"
1088
                        "txsettings\n"
1089
                        "rxsettings\n"
1090
                        "txsettings -ack\n"
1091
                        "rxsettings\n"
1092
                        "expect settings.ack == true\n"
1093
                        "} -start\n", cmd, hp, vl);
1094 2
}
1095
1096
/**********************************************************************
1097
 * Receive a request
1098
 */
1099
1100
/* SECTION: client-server.spec.rxreq
1101
 *
1102
 * rxreq (server only)
1103
 *         Receive and parse a request's headers and body.
1104
 */
1105
static void
1106 3672
cmd_http_rxreq(CMD_ARGS)
1107
{
1108
        struct http *hp;
1109
1110
        (void)cmd;
1111 3672
        CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC);
1112 3672
        ONLY_SERVER(hp, av);
1113 3672
        AZ(strcmp(av[0], "rxreq"));
1114 3672
        av++;
1115
1116 7344
        for (; *av != NULL; av++)
1117 0
                vtc_fatal(vl, "Unknown http rxreq spec: %s\n", *av);
1118 3672
        http_rxhdr(hp);
1119 3642
        http_splitheader(hp, 1);
1120 3642
        if (http_count_header(hp->req, "Content-Length") > 1)
1121 0
                vtc_fatal(vl, "Multiple Content-Length headers.\n");
1122 3642
        http_swallow_body(hp, hp->req, 0);
1123 3642
        vtc_log(vl, 4, "bodylen = %s", hp->bodylen);
1124 3642
}
1125
1126
/* SECTION: client-server.spec.rxreqhdrs
1127
 *
1128
 * rxreqhdrs
1129
 *         Receive and parse a request's headers (but not the body).
1130
 */
1131
1132
static void
1133 2
cmd_http_rxreqhdrs(CMD_ARGS)
1134
{
1135
        struct http *hp;
1136
1137
        (void)cmd;
1138
        (void)vl;
1139 2
        CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC);
1140 2
        AZ(strcmp(av[0], "rxreqhdrs"));
1141 2
        av++;
1142
1143 4
        for (; *av != NULL; av++)
1144 0
                vtc_fatal(hp->vl, "Unknown http rxreq spec: %s\n", *av);
1145 2
        http_rxhdr(hp);
1146 2
        http_splitheader(hp, 1);
1147 2
        if (http_count_header(hp->req, "Content-Length") > 1)
1148 0
                vtc_fatal(hp->vl, "Multiple Content-Length headers.\n");
1149 2
}
1150
1151
/* SECTION: client-server.spec.rxreqbody
1152
 *
1153
 * rxreqbody (server only)
1154
 *         Receive a request's body.
1155
 */
1156
1157
static void
1158 0
cmd_http_rxreqbody(CMD_ARGS)
1159
{
1160
        struct http *hp;
1161
1162
        (void)cmd;
1163
        (void)vl;
1164 0
        CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC);
1165 0
        ONLY_SERVER(hp, av);
1166 0
        AZ(strcmp(av[0], "rxreqbody"));
1167 0
        av++;
1168
1169 0
        for (; *av != NULL; av++)
1170 0
                vtc_fatal(hp->vl, "Unknown http rxreq spec: %s\n", *av);
1171 0
        http_swallow_body(hp, hp->req, 0);
1172 0
        vtc_log(hp->vl, 4, "bodylen = %s", hp->bodylen);
1173 0
}
1174
1175
/* SECTION: client-server.spec.rxrespbody
1176
 *
1177
 * rxrespbody (client only)
1178
 *         Receive a response's body.
1179
 */
1180
1181
static void
1182 6
cmd_http_rxrespbody(CMD_ARGS)
1183
{
1184
        struct http *hp;
1185
1186
        (void)cmd;
1187
        (void)vl;
1188 6
        CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC);
1189 6
        ONLY_CLIENT(hp, av);
1190 6
        AZ(strcmp(av[0], "rxrespbody"));
1191 6
        av++;
1192
1193 12
        for (; *av != NULL; av++)
1194 0
                vtc_fatal(hp->vl, "Unknown http rxrespbody spec: %s\n", *av);
1195 6
        http_swallow_body(hp, hp->resp, 0);
1196 6
        vtc_log(hp->vl, 4, "bodylen = %s", hp->bodylen);
1197 6
}
1198
1199
/* SECTION: client-server.spec.rxchunk
1200
 *
1201
 * rxchunk
1202
 *         Receive an HTTP chunk.
1203
 */
1204
1205
static void
1206 14
cmd_http_rxchunk(CMD_ARGS)
1207
{
1208
        struct http *hp;
1209
        int ll, i;
1210
1211
        (void)cmd;
1212
        (void)vl;
1213 14
        CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC);
1214 14
        ONLY_CLIENT(hp, av);
1215
1216 14
        i = http_rxchunk(hp);
1217 14
        if (i == 0) {
1218 0
                ll = hp->rxbuf + hp->prxbuf - hp->body;
1219 0
                hp->bodyl = ll;
1220 0
                bprintf(hp->bodylen, "%d", ll);
1221 0
                vtc_log(hp->vl, 4, "bodylen = %s", hp->bodylen);
1222
        }
1223 14
}
1224
1225
/**********************************************************************
1226
 * Transmit a request
1227
 */
1228
1229
static void
1230 4335
cmd_http_txreq(CMD_ARGS)
1231
{
1232
        struct http *hp;
1233 4335
        const char *req = "GET";
1234 4335
        const char *url = "/";
1235 4335
        const char *proto = "HTTP/1.1";
1236 4335
        const char *up = NULL;
1237
        unsigned nohost;
1238
1239
        (void)cmd;
1240
        (void)vl;
1241 4335
        CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC);
1242 4335
        ONLY_CLIENT(hp, av);
1243 4335
        AZ(strcmp(av[0], "txreq"));
1244 4335
        av++;
1245
1246 4335
        VSB_clear(hp->vsb);
1247
1248 7137
        for (; *av != NULL; av++) {
1249 3851
                if (!strcmp(*av, "-url")) {
1250 2480
                        url = av[1];
1251 2480
                        av++;
1252 1371
                } else if (!strcmp(*av, "-proto")) {
1253 96
                        proto = av[1];
1254 96
                        av++;
1255 1275
                } else if (!strcmp(*av, "-req")) {
1256 220
                        req = av[1];
1257 220
                        av++;
1258 1055
                } else if (!hp->sfd && !strcmp(*av, "-up")) {
1259 0
                        up = av[1];
1260 0
                        av++;
1261
                } else
1262
                        break;
1263
        }
1264 4341
        VSB_printf(hp->vsb, "%s %s %s%s", req, url, proto, nl);
1265
1266 4342
        if (up)
1267 0
                VSB_printf(hp->vsb, "Connection: Upgrade, HTTP2-Settings%s"
1268
                                "Upgrade: h2c%s"
1269
                                "HTTP2-Settings: %s%s", nl, nl, up, nl);
1270
1271 4342
        nohost = strcasecmp(proto, "HTTP/1.1") != 0;
1272 4342
        av = http_tx_parse_args(av, vl, hp, NULL, nohost);
1273 4342
        if (*av != NULL)
1274 0
                vtc_fatal(hp->vl, "Unknown http txreq spec: %s\n", *av);
1275 4342
        http_write(hp, 4, "txreq");
1276
1277 4342
        if (up) {
1278 0
                parse_string("rxresp\n"
1279
                                "expect resp.status == 101\n"
1280
                                "expect resp.http.connection == Upgrade\n"
1281
                                "expect resp.http.upgrade == h2c\n"
1282
                                "txpri\n", http_cmds, hp, vl);
1283 0
                b64_settings(hp, up);
1284 0
                parse_string("stream 0 {\n"
1285
                                "txsettings\n"
1286
                                "rxsettings\n"
1287
                                "txsettings -ack\n"
1288
                                "rxsettings\n"
1289
                                "expect settings.ack == true"
1290
                             "} -start\n", http_cmds, hp, vl);
1291
        }
1292 4342
}
1293
1294
/* SECTION: client-server.spec.recv
1295
 *
1296
 * recv NUMBER
1297
 *         Read NUMBER bytes from the connection.
1298
 */
1299
1300
static void
1301 16
cmd_http_recv(CMD_ARGS)
1302
{
1303
        struct http *hp;
1304
        int i, n;
1305
        char u[32];
1306
1307
        (void)cmd;
1308
        (void)vl;
1309 16
        CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC);
1310 16
        AN(av[1]);
1311 16
        AZ(av[2]);
1312 16
        n = strtoul(av[1], NULL, 0);
1313 70
        while (n > 0) {
1314 38
                i = read(hp->fd, u, n > 32 ? 32 : n);
1315 38
                if (i > 0)
1316 38
                        vtc_dump(hp->vl, 4, "recv", u, i);
1317
                else
1318 0
                        vtc_log(hp->vl, hp->fatal, "recv() got %d (%s)", i,
1319 0
                            strerror(errno));
1320 38
                n -= i;
1321
        }
1322 16
}
1323
1324
/* SECTION: client-server.spec.send
1325
 *
1326
 * send STRING
1327
 *         Push STRING on the connection.
1328
 */
1329
1330
static void
1331 1520
cmd_http_send(CMD_ARGS)
1332
{
1333
        struct http *hp;
1334
        int i;
1335
1336
        (void)cmd;
1337
        (void)vl;
1338 1520
        CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC);
1339 1520
        AN(av[1]);
1340 1520
        AZ(av[2]);
1341 1520
        vtc_dump(hp->vl, 4, "send", av[1], -1);
1342 1520
        i = write(hp->fd, av[1], strlen(av[1]));
1343 1520
        if (i != strlen(av[1]))
1344 0
                vtc_log(hp->vl, hp->fatal, "Write error in http_send(): %s",
1345 0
                    strerror(errno));
1346 1520
}
1347
1348
/* SECTION: client-server.spec.send_n
1349
 *
1350
 * send_n NUMBER STRING
1351
 *         Write STRING on the socket NUMBER times.
1352
 */
1353
1354
static void
1355 4
cmd_http_send_n(CMD_ARGS)
1356
{
1357
        struct http *hp;
1358
        int i, n, l;
1359
1360
        (void)cmd;
1361
        (void)vl;
1362 4
        CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC);
1363 4
        AN(av[1]);
1364 4
        AN(av[2]);
1365 4
        AZ(av[3]);
1366 4
        n = strtoul(av[1], NULL, 0);
1367 4
                vtc_dump(hp->vl, 4, "send_n", av[2], -1);
1368 4
        l = strlen(av[2]);
1369 4124
        while (n--) {
1370 4116
                i = write(hp->fd, av[2], l);
1371 4116
                if (i != l)
1372 0
                        vtc_log(hp->vl, hp->fatal,
1373
                            "Write error in http_send(): %s",
1374 0
                            strerror(errno));
1375
        }
1376 4
}
1377
1378
/* SECTION: client-server.spec.send_urgent
1379
 *
1380
 * send_urgent STRING
1381
 *         Send string as TCP OOB urgent data. You will never need this.
1382
 */
1383
1384
static void
1385 20
cmd_http_send_urgent(CMD_ARGS)
1386
{
1387
        struct http *hp;
1388
        int i;
1389
1390
        (void)cmd;
1391
        (void)vl;
1392 20
        CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC);
1393 20
        AN(av[1]);
1394 20
        AZ(av[2]);
1395 20
        vtc_dump(hp->vl, 4, "send_urgent", av[1], -1);
1396 20
        i = send(hp->fd, av[1], strlen(av[1]), MSG_OOB);
1397 20
        if (i != strlen(av[1]))
1398 0
                vtc_log(hp->vl, hp->fatal,
1399 0
                    "Write error in http_send_urgent(): %s", strerror(errno));
1400 20
}
1401
1402
/* SECTION: client-server.spec.sendhex
1403
 *
1404
 * sendhex STRING
1405
 *         Send bytes as described by STRING. STRING should consist of hex pairs
1406
 *         possibly separated by whitespace or newlines. For example:
1407
 *         "0F EE a5    3df2".
1408
 */
1409
1410
static void
1411 242
cmd_http_sendhex(CMD_ARGS)
1412
{
1413
        struct vsb *vsb;
1414
        struct http *hp;
1415
        int j;
1416
1417
        (void)cmd;
1418
        (void)vl;
1419 242
        CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC);
1420 242
        AN(av[1]);
1421 242
        AZ(av[2]);
1422 242
        vsb = vtc_hex_to_bin(hp->vl, av[1]);
1423 242
        assert(VSB_len(vsb) >= 0);
1424 242
        vtc_hexdump(hp->vl, 4, "sendhex", VSB_data(vsb), VSB_len(vsb));
1425 242
        j = write(hp->fd, VSB_data(vsb), VSB_len(vsb));
1426 242
        assert(j == VSB_len(vsb));
1427 242
        VSB_destroy(&vsb);
1428 242
}
1429
1430
/* SECTION: client-server.spec.chunked
1431
 *
1432
 * chunked STRING
1433
 *         Send STRING as chunked encoding.
1434
 */
1435
1436
static void
1437 100
cmd_http_chunked(CMD_ARGS)
1438
{
1439
        struct http *hp;
1440
1441
        (void)cmd;
1442
        (void)vl;
1443 100
        CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC);
1444 100
        AN(av[1]);
1445 100
        AZ(av[2]);
1446 100
        VSB_clear(hp->vsb);
1447 300
        VSB_printf(hp->vsb, "%jx%s%s%s",
1448 200
            (uintmax_t)strlen(av[1]), nl, av[1], nl);
1449 100
        http_write(hp, 4, "chunked");
1450 100
}
1451
1452
/* SECTION: client-server.spec.chunkedlen
1453
 *
1454
 * chunkedlen NUMBER
1455
 *         Do as ``chunked`` except that the string will be generated
1456
 *         for you, with a length of NUMBER characters.
1457
 */
1458
1459
static void
1460 140
cmd_http_chunkedlen(CMD_ARGS)
1461
{
1462
        unsigned len;
1463
        unsigned u, v;
1464
        char buf[16384];
1465
        struct http *hp;
1466
1467
        (void)cmd;
1468
        (void)vl;
1469 140
        CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC);
1470 140
        AN(av[1]);
1471 140
        AZ(av[2]);
1472 140
        VSB_clear(hp->vsb);
1473
1474 140
        len = atoi(av[1]);
1475
1476 140
        if (len == 0) {
1477 62
                VSB_printf(hp->vsb, "0%s%s", nl, nl);
1478
        } else {
1479 1278030
                for (u = 0; u < sizeof buf; u++)
1480 1277952
                        buf[u] = (u & 7) + '0';
1481
1482 78
                VSB_printf(hp->vsb, "%x%s", len, nl);
1483 422
                for (u = 0; u < len; u += v) {
1484 344
                        v = len - u;
1485 344
                        if (v > sizeof buf)
1486 266
                                v = sizeof buf;
1487 344
                        VSB_bcat(hp->vsb, buf, v);
1488
                }
1489 78
                VSB_printf(hp->vsb, "%s", nl);
1490
        }
1491 140
        http_write(hp, 4, "chunked");
1492 140
}
1493
1494
1495
/* SECTION: client-server.spec.timeout
1496
 *
1497
 * timeout NUMBER
1498
 *         Set the TCP timeout for this entity.
1499
 */
1500
1501
static void
1502 56
cmd_http_timeout(CMD_ARGS)
1503
{
1504
        struct http *hp;
1505
        double d;
1506
1507
        (void)cmd;
1508
        (void)vl;
1509 56
        CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC);
1510 56
        AN(av[1]);
1511 56
        AZ(av[2]);
1512 56
        d = VNUM(av[1]);
1513 56
        if (isnan(d))
1514 0
                vtc_fatal(vl, "timeout is not a number (%s)", av[1]);
1515 56
        hp->timeout = (int)(d * 1000.0);
1516 56
}
1517
1518
/* SECTION: client-server.spec.expect_close
1519
 *
1520
 * expect_close
1521
 *      Reads from the connection, expecting nothing to read but an EOF.
1522
 */
1523
static void
1524 192
cmd_http_expect_close(CMD_ARGS)
1525
{
1526
        struct http *hp;
1527
        struct pollfd fds[1];
1528
        char c;
1529
        int i;
1530
1531
        (void)cmd;
1532
        (void)vl;
1533 192
        CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC);
1534 192
        AZ(av[1]);
1535
1536 192
        vtc_log(vl, 4, "Expecting close (fd = %d)", hp->fd);
1537 192
        if (hp->h2)
1538 26
                stop_h2(hp);
1539
        while (1) {
1540 192
                fds[0].fd = hp->fd;
1541 192
                fds[0].events = POLLIN;
1542 192
                fds[0].revents = 0;
1543 192
                i = poll(fds, 1, hp->timeout);
1544 190
                if (i < 0 && errno == EINTR)
1545 0
                        continue;
1546 190
                if (i == 0)
1547 0
                        vtc_log(vl, hp->fatal, "Expected close: timeout");
1548 190
                if (i != 1 || !(fds[0].revents & (POLLIN|POLLERR|POLLHUP)))
1549 0
                        vtc_log(vl, hp->fatal,
1550
                            "Expected close: poll = %d, revents = 0x%x",
1551 0
                            i, fds[0].revents);
1552 190
                i = read(hp->fd, &c, 1);
1553 190
                if (VTCP_Check(i))
1554 190
                        break;
1555 0
                if (i == 1 && vct_islws(c))
1556 0
                        continue;
1557 0
                vtc_log(vl, hp->fatal,
1558
                    "Expecting close: read = %d, c = 0x%02x", i, c);
1559
        }
1560 190
        vtc_log(vl, 4, "fd=%d EOF, as expected", hp->fd);
1561 190
}
1562
1563
/* SECTION: client-server.spec.close
1564
 *
1565
 * close (server only)
1566
 *      Close the connection. Note that if operating in HTTP/2 mode no
1567
 *      extra (GOAWAY) frame is sent, it's simply a TCP close.
1568
 */
1569
static void
1570 32
cmd_http_close(CMD_ARGS)
1571
{
1572
        struct http *hp;
1573
1574
        (void)cmd;
1575
        (void)vl;
1576 32
        CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC);
1577 32
        ONLY_SERVER(hp, av);
1578 32
        AZ(av[1]);
1579 32
        assert(hp->sfd != NULL);
1580 32
        assert(*hp->sfd >= 0);
1581 32
        if (hp->h2)
1582 0
                stop_h2(hp);
1583 32
        VTCP_close(&hp->fd);
1584 32
        vtc_log(vl, 4, "Closed");
1585 32
}
1586
1587
/* SECTION: client-server.spec.accept
1588
 *
1589
 * accept (server only)
1590
 *      Close the current connection, if any, and accept a new one. Note
1591
 *      that this new connection is HTTP/1.x.
1592
 */
1593
static void
1594 214
cmd_http_accept(CMD_ARGS)
1595
{
1596
        struct http *hp;
1597
1598
        (void)cmd;
1599
        (void)vl;
1600 214
        CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC);
1601 214
        ONLY_SERVER(hp, av);
1602 214
        AZ(av[1]);
1603 214
        assert(hp->sfd != NULL);
1604 214
        assert(*hp->sfd >= 0);
1605 214
        if (hp->h2)
1606 0
                stop_h2(hp);
1607 214
        if (hp->fd >= 0)
1608 184
                VTCP_close(&hp->fd);
1609 214
        vtc_log(vl, 4, "Accepting");
1610 214
        hp->fd = accept(*hp->sfd, NULL, NULL);
1611 202
        if (hp->fd < 0)
1612 0
                vtc_log(vl, hp->fatal, "Accepted failed: %s", strerror(errno));
1613 202
        vtc_log(vl, 3, "Accepted socket fd is %d", hp->fd);
1614 202
}
1615
1616
/* SECTION: client-server.spec.loop
1617
 *
1618
 * loop NUMBER STRING
1619
 *         Process STRING as a specification, NUMBER times.
1620
 */
1621
1622
static void
1623 63
cmd_http_loop(CMD_ARGS)
1624
{
1625
        struct http *hp;
1626
        unsigned n, m;
1627
1628 63
        CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC);
1629 63
        AN(av[1]);
1630 63
        AN(av[2]);
1631 63
        AZ(av[3]);
1632 63
        n = strtoul(av[1], NULL, 0);
1633 867
        for (m = 1 ; m <= n; m++) {
1634 814
                vtc_log(vl, 4, "Loop #%u", m);
1635 814
                parse_string(av[2], cmd, hp, vl);
1636
        }
1637 53
}
1638
1639
/* SECTION: client-server.spec.fatal
1640
 *
1641
 * fatal|non_fatal
1642
 *         Control whether a failure of this entity should stop the test.
1643
 */
1644
1645
static void
1646 56
cmd_http_fatal(CMD_ARGS)
1647
{
1648
        struct http *hp;
1649 56
        CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC);
1650
1651 56
        AZ(av[1]);
1652 56
        if (!strcmp(av[0], "fatal"))
1653 12
                hp->fatal = 0;
1654 44
        else if (!strcmp(av[0], "non_fatal"))
1655 44
                hp->fatal = -1;
1656
        else
1657 0
                vtc_fatal(vl, "XXX: fatal %s", cmd->name);
1658 56
}
1659
1660
#define cmd_http_non_fatal cmd_http_fatal
1661
1662
static const char PREFACE[24] = {
1663
        0x50, 0x52, 0x49, 0x20, 0x2a, 0x20, 0x48, 0x54,
1664
        0x54, 0x50, 0x2f, 0x32, 0x2e, 0x30, 0x0d, 0x0a,
1665
        0x0d, 0x0a, 0x53, 0x4d, 0x0d, 0x0a, 0x0d, 0x0a
1666
};
1667
1668
/* SECTION: client-server.spec.txpri
1669
 *
1670
 * txpri (client only)
1671
 *      Send an HTTP/2 preface ("PRI * HTTP/2.0\\r\\n\\r\\nSM\\r\\n\\r\\n")
1672
 *      and set client to HTTP/2.
1673
 */
1674
static void
1675 195
cmd_http_txpri(CMD_ARGS)
1676
{
1677
        size_t l;
1678
        struct http *hp;
1679
        (void)cmd;
1680 195
        CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC);
1681 195
        ONLY_CLIENT(hp, av);
1682
1683 195
        vtc_dump(hp->vl, 4, "txpri", PREFACE, sizeof(PREFACE));
1684
        /* Dribble out the preface */
1685 196
        l = write(hp->fd, PREFACE, 18);
1686 196
        if (l != 18)
1687 0
                vtc_log(vl, hp->fatal, "Write failed: (%zd vs %zd) %s",
1688 0
                    l, sizeof(PREFACE), strerror(errno));
1689 196
        usleep(10000);
1690 196
        l = write(hp->fd, PREFACE + 18, sizeof(PREFACE) - 18);
1691 196
        if (l != sizeof(PREFACE) - 18)
1692 0
                vtc_log(vl, hp->fatal, "Write failed: (%zd vs %zd) %s",
1693 0
                    l, sizeof(PREFACE), strerror(errno));
1694
1695 196
        start_h2(hp);
1696 196
        AN(hp->h2);
1697 196
}
1698
1699
/* SECTION: client-server.spec.rxpri
1700
 *
1701
 * rxpri (server only)
1702
 *      Receive a preface. If valid set the server to HTTP/2, abort
1703
 *      otherwise.
1704
 */
1705
static void
1706 52
cmd_http_rxpri(CMD_ARGS)
1707
{
1708
        struct http *hp;
1709
        (void)cmd;
1710 52
        CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC);
1711 52
        ONLY_SERVER(hp, av);
1712
1713 52
        hp->prxbuf = 0;
1714 52
        if (!http_rxchar(hp, sizeof(PREFACE), 0))
1715 0
                vtc_fatal(vl, "Couldn't retrieve connection preface");
1716 52
        if (memcmp(hp->rxbuf, PREFACE, sizeof(PREFACE)))
1717 0
                vtc_fatal(vl, "Received invalid preface\n");
1718 52
        start_h2(hp);
1719 52
        AN(hp->h2);
1720 52
}
1721
1722
/* SECTION: client-server.spec.settings
1723
 *
1724
 * settings -dectbl INT
1725
 *      Force internal HTTP/2 settings to certain values. Currently only
1726
 *      support setting the decoding table size.
1727
 */
1728
static void
1729 0
cmd_http_settings(CMD_ARGS)
1730
{
1731
        uint32_t n;
1732
        char *p;
1733
        struct http *hp;
1734 0
        CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC);
1735
        (void)cmd;
1736
1737 0
        if (!hp->h2)
1738 0
                vtc_fatal(hp->vl, "Only possible in H/2 mode");
1739
1740 0
        CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC);
1741
1742 0
        for (; *av != NULL; av++) {
1743 0
                if (!strcmp(*av, "-dectbl")) {
1744 0
                        n = strtoul(av[1], &p, 0);
1745 0
                        if (*p != '\0')
1746 0
                                vtc_fatal(hp->vl, "-dectbl takes an integer as "
1747 0
                                    "argument (found %s)", av[1]);
1748 0
                        assert(HPK_ResizeTbl(hp->decctx, n) != hpk_err);
1749 0
                        av++;
1750
                } else
1751 0
                        vtc_fatal(vl, "Unknown settings spec: %s\n", *av);
1752
        }
1753 0
}
1754
1755
static void
1756 744
cmd_http_stream(CMD_ARGS)
1757
{
1758 744
        struct http *hp = (struct http *)priv;
1759 744
        CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC);
1760 744
        if (!hp->h2) {
1761 224
                vtc_log(hp->vl, 4, "Not in H/2 mode, do what's needed");
1762 224
                if (hp->sfd)
1763 46
                        parse_string("rxpri", http_cmds, hp, vl);
1764
                else
1765 178
                        parse_string("txpri", http_cmds, hp, vl);
1766 224
                parse_string("stream 0 {\n"
1767
                                "txsettings\n"
1768
                                "rxsettings\n"
1769
                                "txsettings -ack\n"
1770
                                "rxsettings\n"
1771
                                "expect settings.ack == true"
1772
                             "} -run\n", http_cmds, hp, vl);
1773
        }
1774 744
        cmd_stream(av, hp, cmd, vl);
1775 746
}
1776
1777
/* SECTION: client-server.spec.write_body
1778
 *
1779
 * write_body STRING
1780
 *      Write the body of a request or a response to a file. By using the
1781
 *      shell command, higher-level checks on the body can be performed
1782
 *      (eg. XML, JSON, ...) provided that such checks can be delegated
1783
 *      to an external program.
1784
 */
1785
static void
1786 4
cmd_http_write_body(CMD_ARGS)
1787
{
1788
        struct http *hp;
1789
1790
        (void)cmd;
1791
        (void)vl;
1792 4
        CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC);
1793 4
        AN(av[0]);
1794 4
        AN(av[1]);
1795 4
        AZ(av[2]);
1796 4
        AZ(strcmp(av[0], "write_body"));
1797 4
        if (VFIL_writefile(NULL, av[1], hp->body, hp->bodyl) != 0)
1798 0
                vtc_fatal(hp->vl, "failed to write body: %s (%d)",
1799 0
                    strerror(errno), errno);
1800 4
}
1801
1802
/**********************************************************************
1803
 * Execute HTTP specifications
1804
 */
1805
1806
const struct cmds http_cmds[] = {
1807
#define CMD_HTTP(n) { #n, cmd_http_##n },
1808
        /* session */
1809
        CMD_HTTP(accept)
1810
        CMD_HTTP(close)
1811
        CMD_HTTP(recv)
1812
        CMD_HTTP(send)
1813
        CMD_HTTP(send_n)
1814
        CMD_HTTP(send_urgent)
1815
        CMD_HTTP(sendhex)
1816
        CMD_HTTP(timeout)
1817
1818
        /* spec */
1819
        CMD_HTTP(fatal)
1820
        CMD_HTTP(loop)
1821
        CMD_HTTP(non_fatal)
1822
1823
        /* body */
1824
        CMD_HTTP(gunzip)
1825
        CMD_HTTP(write_body)
1826
1827
        /* HTTP/1.x */
1828
        CMD_HTTP(chunked)
1829
        CMD_HTTP(chunkedlen)
1830
        CMD_HTTP(rxchunk)
1831
1832
        /* HTTP/2 */
1833
        CMD_HTTP(stream)
1834
        CMD_HTTP(settings)
1835
1836
        /* client */
1837
        CMD_HTTP(rxresp)
1838
        CMD_HTTP(rxrespbody)
1839
        CMD_HTTP(rxresphdrs)
1840
        CMD_HTTP(txpri)
1841
        CMD_HTTP(txreq)
1842
1843
        /* server */
1844
        CMD_HTTP(rxpri)
1845
        CMD_HTTP(rxreq)
1846
        CMD_HTTP(rxreqbody)
1847
        CMD_HTTP(rxreqhdrs)
1848
        CMD_HTTP(txresp)
1849
        CMD_HTTP(upgrade)
1850
1851
        /* expect */
1852
        CMD_HTTP(expect)
1853
        CMD_HTTP(expect_close)
1854
        CMD_HTTP(expect_pattern)
1855
#undef CMD_HTTP
1856
        { NULL, NULL }
1857
};
1858
1859
static void
1860 5491
http_process_cleanup(void *arg)
1861
{
1862 5491
        struct http *hp = arg;
1863
1864 5491
        if (hp->h2)
1865 222
                stop_h2(hp);
1866 5491
        VSB_destroy(&hp->vsb);
1867 5490
        free(hp->rxbuf);
1868 5490
        free(hp->rem_ip);
1869 5490
        free(hp->rem_port);
1870 5490
        free(hp->rem_path);
1871 5490
        FREE_OBJ(hp);
1872 5491
}
1873
1874
int
1875 5491
http_process(struct vtclog *vl, const char *spec, int sock, int *sfd,
1876
             const char *addr)
1877
{
1878
        struct http *hp;
1879
        int retval;
1880
1881
        (void)sfd;
1882 5491
        ALLOC_OBJ(hp, HTTP_MAGIC);
1883 5491
        AN(hp);
1884 5491
        hp->fd = sock;
1885 5491
        hp->timeout = vtc_maxdur * 1000 / 2;
1886
1887 5491
        hp->nrxbuf = 2048*1024;
1888 5491
        hp->rxbuf = malloc(hp->nrxbuf);         /* XXX */
1889 5491
        AN(hp->rxbuf);
1890
1891 5491
        hp->vsb = VSB_new_auto();
1892 5491
        AN(hp->vsb);
1893
1894 5491
        hp->sfd = sfd;
1895
1896 5491
        hp->rem_ip = malloc(VTCP_ADDRBUFSIZE);
1897 5491
        AN(hp->rem_ip);
1898
1899 5491
        hp->rem_port = malloc(VTCP_PORTBUFSIZE);
1900 5491
        AN(hp->rem_port);
1901
1902 5491
        hp->vl = vl;
1903 5491
        hp->gziplevel = 0;
1904 5491
        hp->gzipresidual = -1;
1905
1906 5491
        if (*addr != '/') {
1907 5204
                VTCP_hisname(sock, hp->rem_ip, VTCP_ADDRBUFSIZE, hp->rem_port,
1908
                             VTCP_PORTBUFSIZE);
1909 5203
                hp->rem_path = NULL;
1910
        } else {
1911 287
                strcpy(hp->rem_ip, "0.0.0.0");
1912 287
                strcpy(hp->rem_port, "0");
1913 287
                hp->rem_path = strdup(addr);
1914
        }
1915 5490
        pthread_cleanup_push(http_process_cleanup, hp);
1916 5490
        parse_string(spec, http_cmds, hp, vl);
1917 5440
        retval = hp->fd;
1918 5440
        pthread_cleanup_pop(0);
1919 5440
        http_process_cleanup(hp);
1920 5440
        return (retval);
1921
}
1922
1923
/**********************************************************************
1924
 * Magic test routine
1925
 *
1926
 * This function brute-forces some short strings through gzip(9) to
1927
 * find candidates for all possible 8 bit positions of the stopbit.
1928
 *
1929
 * Here is some good short output strings:
1930
 *
1931
 *      0 184 <e04c8d0fd604c>
1932
 *      1 257 <1ea86e6cf31bf4ec3d7a86>
1933
 *      2 106 <10>
1934
 *      3 163 <a5e2e2e1c2e2>
1935
 *      4 180 <71c5d18ec5d5d1>
1936
 *      5 189 <39886d28a6d2988>
1937
 *      6 118 <80000>
1938
 *      7 151 <386811868>
1939
 *
1940
 */
1941
1942
#if 0
1943
void xxx(void);
1944
1945
void
1946
xxx(void)
1947
{
1948
        z_stream vz;
1949
        int n;
1950
        char ibuf[200];
1951
        char obuf[200];
1952
        int fl[8];
1953
        int i, j;
1954
1955
        for (n = 0; n < 8; n++)
1956
                fl[n] = 9999;
1957
1958
        memset(&vz, 0, sizeof vz);
1959
1960
        for (n = 0;  n < 999999999; n++) {
1961
                *ibuf = 0;
1962
                for (j = 0; j < 7; j++) {
1963
                        snprintf(strchr(ibuf, 0), 5, "%x",
1964
                            (unsigned)VRND_RandomTestable() & 0xffff);
1965
                        vz.next_in = TRUST_ME(ibuf);
1966
                        vz.avail_in = strlen(ibuf);
1967
                        vz.next_out = TRUST_ME(obuf);
1968
                        vz.avail_out = sizeof obuf;
1969
                        assert(Z_OK == deflateInit2(&vz,
1970
                            9, Z_DEFLATED, 31, 9, Z_DEFAULT_STRATEGY));
1971
                        assert(Z_STREAM_END == deflate(&vz, Z_FINISH));
1972
                        i = vz.stop_bit & 7;
1973
                        if (fl[i] > strlen(ibuf)) {
1974
                                printf("%d %jd <%s>\n", i, vz.stop_bit, ibuf);
1975
                                fl[i] = strlen(ibuf);
1976
                        }
1977
                        assert(Z_OK == deflateEnd(&vz));
1978
                }
1979
        }
1980
1981
        printf("FOO\n");
1982
}
1983
#endif