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
StaticDataStaticData24 StaticData() {
25
26 router.add({"get"}, "/:hello/:hi", [](auto *h) mutable {
27 auto [paramsTop, params] = h->getParameters();
28
29 /* Something is horribly wrong */
30 if (paramsTop != 1 || !params[0].length() || !params[1].length()) {
31 exit(-1);
32 }
33
34 /* This route did handle it */
35 return true;
36 });
37
38 router.add({"post"}, "/:hello/:hi/*", [](auto *h) mutable {
39 auto [paramsTop, params] = h->getParameters();
40
41 /* Something is horribly wrong */
42 if (paramsTop != 1 || !params[0].length() || !params[1].length()) {
43 exit(-1);
44 }
45
46 /* This route did handle it */
47 return true;
48 });
49
50 router.add({"get"}, "/*", [](auto *h) mutable {
51 auto [paramsTop, params] = h->getParameters();
52
53 /* Something is horribly wrong */
54 if (paramsTop != -1) {
55 exit(-1);
56 }
57
58 /* This route did not handle it */
59 return false;
60 });
61
62 router.add({"get"}, "/hi", [](auto *h) mutable {
63 auto [paramsTop, params] = h->getParameters();
64
65 /* Something is horribly wrong */
66 if (paramsTop != -1) {
67 exit(-1);
68 }
69
70 /* This route did handle it */
71 return true;
72 });
73 }
74 } staticData;
75
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)76 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
77 /* Create parser */
78 uWS::HttpParser httpParser;
79 /* User data */
80 void *user = (void *) 13;
81
82 /* If we are built with WITH_PROXY, pass a ProxyParser as reserved */
83 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 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 if (size) {
93 size--;
94 } else {
95 /* We might be given zero length chunks */
96 return;
97 }
98
99 /* If user is null then ignore this chunk */
100 if (!user) {
101 return;
102 }
103
104 /* Parse it */
105 void *returnedUser = httpParser.consumePostPadded((char *) data, size, user, reserved, [reserved](void *s, uWS::HttpRequest *httpRequest) -> void * {
106
107 readBytes(httpRequest->getHeader(httpRequest->getUrl()));
108 readBytes(httpRequest->getMethod());
109 readBytes(httpRequest->getQuery());
110 readBytes(httpRequest->getQuery("hello"));
111 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 staticData.router.getUserData() = {};
121 if (!staticData.router.route(httpRequest->getMethod(), httpRequest->getUrl())) {
122 /* It was not handled */
123 return nullptr;
124 }
125
126 for (auto p : *httpRequest) {
127
128 }
129
130 /* Return ok */
131 return s;
132
133 }, [](void *user, std::string_view data, bool fin) -> void * {
134
135 /* Return ok */
136 return user;
137
138 }, [](void *user) -> void * {
139
140 /* Return break */
141 return nullptr;
142 });
143
144 if (!returnedUser) {
145 /* It is of uttermost importance that if and when we return nullptr from the httpParser we must not
146 * ever use the httpParser ever again. It is in a broken state as returning nullptr is only used
147 * for signalling early closure. You must absolutely must throw it away. Here we just mark user as
148 * null so that we can ignore further chunks of data */
149 user = nullptr;
150 }
151 });
152
153 return 0;
154 }
155
156