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