/src/uriparser/fuzz/ParseFuzzer.cpp
Line | Count | Source |
1 | | // Copyright 2020 Google LLC |
2 | | // Copyright 2025 Mikhail Khachaiants <mkhachaiants@gmail.com> |
3 | | // |
4 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
5 | | // you may not use this file except in compliance with the License. |
6 | | // You may obtain a copy of the License at |
7 | | // |
8 | | // http://www.apache.org/licenses/LICENSE-2.0 |
9 | | // |
10 | | // Unless required by applicable law or agreed to in writing, software |
11 | | // distributed under the License is distributed on an "AS IS" BASIS, |
12 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | | // See the License for the specific language governing permissions and |
14 | | // limitations under the License. |
15 | | |
16 | | #include "uriparser/Uri.h" |
17 | | #include "uriparser/UriIp4.h" |
18 | | #include "FuzzingUtils.h" |
19 | | #include <cstddef> |
20 | | #include <cstring> |
21 | | #include <vector> |
22 | | |
23 | | |
24 | | |
25 | | class UriHolder { |
26 | | public: |
27 | 19.4k | UriHolder() { |
28 | 19.4k | memset((void *)&uri_, 0, sizeof(uri_)); |
29 | 19.4k | } |
30 | | |
31 | 19.4k | ~UriHolder() { |
32 | 19.4k | URI_FUNC(FreeUriMembers)(&uri_); |
33 | 19.4k | } |
34 | | |
35 | 40.3k | URI_TYPE(Uri) * get() { |
36 | 40.3k | return &uri_; |
37 | 40.3k | } |
38 | | |
39 | | private: |
40 | | URI_TYPE(Uri) uri_; |
41 | | }; |
42 | | |
43 | | |
44 | | |
45 | 20.3k | void Escapes(const UriString & uri) { |
46 | 20.3k | const URI_CHAR * first = uri.c_str(); |
47 | | // Up to 6 bytes per character with normalizeBreaks enabled (\n -> %0D%0A) |
48 | 20.3k | std::vector<URI_CHAR> buf1(uri.size() * 6 + 1); |
49 | | // and up to 3 bytes per character otherwise |
50 | 20.3k | std::vector<URI_CHAR> buf2(uri.size() * 3 + 1); |
51 | | |
52 | 20.3k | URI_FUNC(Escape)(first, &buf1[0], URI_TRUE, URI_TRUE); |
53 | 20.3k | URI_FUNC(Escape)(first, &buf1[0], URI_FALSE, URI_TRUE); |
54 | 20.3k | if (buf1.data()) { |
55 | 20.3k | URI_FUNC(UnescapeInPlace)(&buf1[0]); |
56 | 20.3k | } |
57 | | |
58 | 20.3k | URI_FUNC(Escape)(first, &buf2[0], URI_TRUE, URI_FALSE); |
59 | 20.3k | URI_FUNC(Escape)(first, &buf2[0], URI_FALSE, URI_FALSE); |
60 | 20.3k | if (buf2.data()) { |
61 | 20.3k | URI_FUNC(UnescapeInPlace)(&buf2[0]); |
62 | 20.3k | } |
63 | 20.3k | } |
64 | | |
65 | | |
66 | | |
67 | 20.3k | void FileNames(const UriString & uri) { |
68 | 20.3k | const size_t size = 8 + 3 * uri.size() + 1; |
69 | 20.3k | std::vector<URI_CHAR> buf(size); |
70 | | |
71 | 20.3k | URI_FUNC(UnixFilenameToUriString)(uri.c_str(), &buf[0]); |
72 | 20.3k | URI_FUNC(WindowsFilenameToUriString)(uri.c_str(), &buf[0]); |
73 | 20.3k | URI_FUNC(UriStringToUnixFilename)(uri.c_str(), &buf[0]); |
74 | 20.3k | URI_FUNC(UriStringToWindowsFilename)(uri.c_str(), &buf[0]); |
75 | 20.3k | } |
76 | | |
77 | | |
78 | | |
79 | 20.3k | void Ipv4(const UriString & s) { |
80 | 20.3k | const URI_CHAR * cstr = s.c_str(); |
81 | 20.3k | unsigned char result[4] = {}; |
82 | 20.3k | URI_FUNC(ParseIpFourAddress)(result, cstr, &cstr[s.size()]); |
83 | 20.3k | } |
84 | | |
85 | | |
86 | | |
87 | 10.1k | extern "C" int LLVMFuzzerTestOneInput(const uint8_t * data, size_t size) { |
88 | 10.1k | FuzzedDataProvider stream(data, size); |
89 | 10.1k | bool domainRelative = stream.ConsumeBool(); |
90 | | |
91 | 10.1k | const UriString uri1 = consumeRandomLengthString(stream); |
92 | 10.1k | const UriString uri2 = consumeRemainingBytesAsString(stream); |
93 | | |
94 | 10.1k | Escapes(uri1); |
95 | 10.1k | Escapes(uri2); |
96 | | |
97 | 10.1k | FileNames(uri1); |
98 | 10.1k | FileNames(uri2); |
99 | | |
100 | 10.1k | Ipv4(uri1); |
101 | 10.1k | Ipv4(uri2); |
102 | | |
103 | 10.1k | UriHolder uriHolder1; |
104 | 10.1k | URI_TYPE(ParserState) state1; |
105 | 10.1k | state1.uri = uriHolder1.get(); |
106 | 10.1k | if (URI_FUNC(ParseUri)(&state1, uri1.c_str()) != URI_SUCCESS) { |
107 | 974 | return 0; |
108 | 974 | } |
109 | | |
110 | 9.22k | URI_CHAR buf[1024 * 8] = {0}; |
111 | 9.22k | int written = 0; |
112 | 9.22k | URI_FUNC(ToString)(buf, state1.uri, sizeof(buf) / sizeof(buf[0]), &written); |
113 | | |
114 | 9.22k | UriHolder uriHolder2; |
115 | 9.22k | if (URI_FUNC(ParseSingleUri)(uriHolder2.get(), uri2.c_str(), nullptr) != URI_SUCCESS) { |
116 | 2.23k | return 0; |
117 | 2.23k | } |
118 | | |
119 | 6.98k | URI_FUNC(EqualsUri)(state1.uri, uriHolder2.get()); |
120 | | |
121 | 6.98k | unsigned int mask = 0; |
122 | 6.98k | URI_FUNC(NormalizeSyntaxMaskRequiredEx)(state1.uri, &mask); |
123 | 6.98k | URI_FUNC(NormalizeSyntax)(state1.uri); |
124 | | |
125 | 6.98k | URI_TYPE(Uri) absUri; |
126 | 6.98k | URI_FUNC(AddBaseUri)(&absUri, state1.uri, uriHolder2.get()); |
127 | 6.98k | URI_FUNC(FreeUriMembers)(&absUri); |
128 | | |
129 | 6.98k | URI_TYPE(Uri) relUri; |
130 | 6.98k | URI_FUNC(RemoveBaseUri)(&relUri, state1.uri, uriHolder2.get(), domainRelative); |
131 | 6.98k | URI_FUNC(FreeUriMembers)(&relUri); |
132 | | |
133 | 6.98k | return 0; |
134 | 9.22k | } |