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