Coverage Report

Created: 2025-07-11 06:26

/src/h2o/fuzz/driver_common.cc
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2021 Fastly, Inc.
3
 *
4
 * Permission is hereby granted, free of charge, to any person obtaining a copy
5
 * of this software and associated documentation files (the "Software"), to
6
 * deal in the Software without restriction, including without limitation the
7
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8
 * sell copies of the Software, and to permit persons to whom the Software is
9
 * furnished to do so, subject to the following conditions:
10
 *
11
 * The above copyright notice and this permission notice shall be included in
12
 * all copies or substantial portions of the Software.
13
 *
14
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20
 * IN THE SOFTWARE.
21
 */
22
23
#define H2O_USE_EPOLL 1
24
#include "driver_common.h"
25
26
#include <unistd.h>
27
#include <fcntl.h>
28
#include <stdio.h>
29
30
/*
31
 * Registers a request handler with h2o
32
 */
33
h2o_pathconf_t *register_handler(h2o_hostconf_t *hostconf, const char *path, int (*on_req)(h2o_handler_t *, h2o_req_t *))
34
1
{
35
1
    h2o_pathconf_t *pathconf = h2o_config_register_path(hostconf, path, 0);
36
1
    h2o_handler_t *handler = h2o_create_handler(pathconf, sizeof(*handler));
37
1
    handler->on_req = on_req;
38
1
    return pathconf;
39
1
}
40
41
/*
42
 * Writes the writer_thread_args at buf to fd
43
 */
44
void write_fully(int fd, char *buf, size_t len, int abort_on_err)
45
13.2k
{
46
13.2k
    int done = 0;
47
26.4k
    while (len) {
48
13.2k
        int ret;
49
13.2k
        while ((ret = write(fd, buf + done, len)) == -1 && errno == EINTR)
50
0
            ;
51
13.2k
        if (ret <= 0) {
52
64
            if (abort_on_err)
53
0
                abort();
54
64
            else
55
64
                return;
56
64
        }
57
13.1k
        done += ret;
58
13.1k
        len -= ret;
59
13.1k
    }
60
13.2k
}
61
62
#define OK_RESP                                                                                                                    \
63
4.85k
    "HTTP/1.0 200 OK\r\n"                                                                                                          \
64
4.85k
    "Connection: Close\r\n\r\nOk"
65
2.42k
#define OK_RESP_LEN (sizeof(OK_RESP) - 1)
66
67
h2o_barrier_t init_barrier;
68
void *upstream_thread(void *arg)
69
1
{
70
1
    char *dirname = (char *)arg;
71
1
    char path[PATH_MAX];
72
1
    char rbuf[1 * 1024 * 1024];
73
1
    snprintf(path, sizeof(path), "/%s/_.sock", dirname);
74
1
    int sd = socket(AF_UNIX, SOCK_STREAM, 0);
75
1
    if (sd < 0) {
76
0
        abort();
77
0
    }
78
1
    struct sockaddr_un addr;
79
1
    memset(&addr, 0, sizeof(addr));
80
1
    addr.sun_family = AF_UNIX;
81
1
    strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
82
1
    if (bind(sd, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
83
0
        abort();
84
0
    }
85
1
    if (listen(sd, 100) != 0) {
86
0
        abort();
87
0
    }
88
89
1
    h2o_barrier_wait(&init_barrier);
90
2.42k
    while (1) {
91
2.42k
        struct sockaddr_un caddr;
92
2.42k
        socklen_t slen = 0;
93
2.42k
        int cfs = accept(sd, (struct sockaddr *)&caddr, &slen);
94
2.42k
        if (cfs < 0) {
95
0
            continue;
96
0
        }
97
2.42k
        read(cfs, rbuf, sizeof(rbuf));
98
2.42k
        write_fully(cfs, (char *)OK_RESP, OK_RESP_LEN, 0);
99
2.42k
        close(cfs);
100
2.42k
    }
101
1
}
102
103
void register_proxy(h2o_hostconf_t *hostconf, const char *unix_path, h2o_access_log_filehandle_t *logfh)
104
1
{
105
1
    h2o_url_t upstream;
106
1
    h2o_proxy_config_vars_t proxy_config = {};
107
1
    h2o_pathconf_t *pathconf;
108
1
    h2o_mem_pool_t pool;
109
110
1
    h2o_mem_init_pool(&pool);
111
112
    /* Assuming the origin is in the same node and is not super busy, we expect 100ms should be enough for proxy timeout.
113
     * Having a large value would explode the total runtime of the fuzzer. */
114
1
    proxy_config.io_timeout = 100;
115
1
    proxy_config.connect_timeout = proxy_config.io_timeout;
116
1
    proxy_config.first_byte_timeout = proxy_config.io_timeout;
117
1
    proxy_config.max_buffer_size = 1024 * 1024;
118
1
    h2o_url_parse(&pool, unix_path, strlen(unix_path), &upstream);
119
1
    h2o_socketpool_t *sockpool = new h2o_socketpool_t();
120
1
    h2o_socketpool_target_t *target = h2o_socketpool_create_target(&upstream, NULL);
121
1
    h2o_socketpool_init_specific(sockpool, SIZE_MAX /* FIXME */, &target, 1, NULL);
122
1
    h2o_socketpool_set_timeout(sockpool, 2000);
123
1
    h2o_socketpool_set_ssl_ctx(sockpool, NULL);
124
1
    pathconf = h2o_config_register_path(hostconf, "/reproxy-test", 0);
125
1
    h2o_proxy_register_reverse_proxy(pathconf, &proxy_config, sockpool);
126
1
    if (logfh != NULL)
127
0
        h2o_access_log_register(pathconf, logfh);
128
129
1
    h2o_mem_clear_pool(&pool);
130
1
}