Coverage Report

Created: 2025-06-13 06:09

/src/uWebSockets/fuzzing/Http.cpp
Line
Count
Source (jump to first uncovered line)
1
/* This is a fuzz test of the http parser */
2
3
#define WIN32_EXPORT
4
5
#include "helpers.h"
6
7
/* We test the websocket parser */
8
#include "../src/HttpParser.h"
9
10
/* And the router */
11
#include "../src/HttpRouter.h"
12
13
/* Also ProxyParser */
14
#include "../src/ProxyParser.h"
15
16
struct StaticData {
17
18
    struct RouterData {
19
20
    };
21
22
    uWS::HttpRouter<RouterData> router;
23
24
2
    StaticData() {
25
26
2.87k
        router.add({"get"}, "/:hello/:hi", [](auto *h) mutable {
27
2.87k
            auto [paramsTop, params] = h->getParameters();
28
29
            /* Something is horribly wrong */
30
2.87k
            if (paramsTop != 1 || !params[0].length() || !params[1].length()) {
31
0
                exit(-1);
32
0
            }
33
34
            /* This route did handle it */
35
2.87k
            return true;
36
2.87k
        });
37
38
1.23k
        router.add({"post"}, "/:hello/:hi/*", [](auto *h) mutable {
39
1.23k
            auto [paramsTop, params] = h->getParameters();
40
41
            /* Something is horribly wrong */
42
1.23k
            if (paramsTop != 1 || !params[0].length() || !params[1].length()) {
43
0
                exit(-1);
44
0
            }
45
46
            /* This route did handle it */
47
1.23k
            return true;
48
1.23k
        });
49
50
122
        router.add({"get"}, "/*", [](auto *h) mutable {
51
122
            auto [paramsTop, params] = h->getParameters();
52
53
            /* Something is horribly wrong */
54
122
            if (paramsTop != -1) {
55
0
                exit(-1);
56
0
            }
57
58
            /* This route did not handle it */
59
122
            return false;
60
122
        });
61
62
6.97k
        router.add({"get"}, "/hi", [](auto *h) mutable {
63
6.97k
            auto [paramsTop, params] = h->getParameters();
64
65
            /* Something is horribly wrong */
66
6.97k
            if (paramsTop != -1) {
67
0
                exit(-1);
68
0
            }
69
70
            /* This route did handle it */
71
6.97k
            return true;
72
6.97k
        });
73
2
    }
74
} staticData;
75
76
3.13k
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
77
    /* Create parser */
78
3.13k
    uWS::HttpParser httpParser;
79
    /* User data */
80
3.13k
    void *user = (void *) 13;
81
82
    /* If we are built with WITH_PROXY, pass a ProxyParser as reserved */
83
3.13k
    void *reserved = nullptr;
84
#ifdef UWS_WITH_PROXY
85
    uWS::ProxyParser pp;
86
    reserved = (void *) &pp;
87
#endif
88
89
    /* Iterate the padded fuzz as chunks */
90
90.1k
    makeChunked(makePadded(data, size), size, [&httpParser, &user, reserved](const uint8_t *data, size_t size) {
91
        /* We need at least 1 byte post padding */
92
90.1k
        if (size) {
93
90.0k
            size--;
94
90.0k
        } else {
95
            /* We might be given zero length chunks */
96
22
            return;
97
22
        }
98
99
        /* If user is null then ignore this chunk */
100
90.0k
        if (!user) {
101
349
            return;
102
349
        }
103
104
        /* Parse it */
105
89.7k
        auto [err, returnedUser] = httpParser.consumePostPadded((char *) data, size, user, reserved, [reserved](void *s, uWS::HttpRequest *httpRequest) -> void * {
106
107
11.8k
            readBytes(httpRequest->getHeader(httpRequest->getUrl()));
108
11.8k
            readBytes(httpRequest->getMethod());
109
11.8k
            readBytes(httpRequest->getQuery());
110
11.8k
            readBytes(httpRequest->getQuery("hello"));
111
11.8k
            readBytes(httpRequest->getQuery(""));
112
            //readBytes(httpRequest->getParameter(0));
113
114
#ifdef UWS_WITH_PROXY
115
            auto *pp = (uWS::ProxyParser *) reserved;
116
            readBytes(pp->getSourceAddress());
117
#endif
118
119
            /* Route the method and URL in two passes */
120
11.8k
            staticData.router.getUserData() = {};
121
11.8k
            if (!staticData.router.route(httpRequest->getMethod(), httpRequest->getUrl())) {
122
                /* It was not handled */
123
764
                return nullptr;
124
764
            }
125
126
23.6k
            for (auto p : *httpRequest) {
127
128
23.6k
            }
129
130
            /* Return ok */
131
11.0k
            return s;
132
133
36.9k
        }, [](void *user, std::string_view data, bool fin) -> void * {
134
135
            /* Return ok */
136
36.9k
            return user;
137
138
36.9k
        });
139
140
89.7k
        if (!returnedUser) {
141
            /* It is of uttermost importance that if and when we return nullptr from the httpParser we must not
142
             * ever use the httpParser ever again. It is in a broken state as returning nullptr is only used
143
             * for signalling early closure. You must absolutely must throw it away. Here we just mark user as
144
             * null so that we can ignore further chunks of data */
145
764
            user = nullptr;
146
764
        }
147
89.7k
    });
148
149
3.13k
    return 0;
150
3.13k
}
151