1 // Copyright 2020 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <cstddef>
16 #include <cstring>
17 #include <string>
18 #include <vector>
19 #include <fuzzer/FuzzedDataProvider.h>
20
21 using std::string;
22 #include "uriparser/include/uriparser/Uri.h"
23 #include "uriparser/include/uriparser/UriIp4.h"
24
25 class UriParserA {
26 public:
UriParserA()27 UriParserA() { memset((void *)&uri_, 0, sizeof(uri_)); }
~UriParserA()28 ~UriParserA() { uriFreeUriMembersA(&uri_); }
29
get_mutable_uri()30 UriUriA *get_mutable_uri() { return &uri_; }
get_uri() const31 UriUriA *get_uri() const { return const_cast<UriUriA *>(&uri_); }
32
33 private:
34 UriUriA uri_;
35 };
36
Escapes(const string & uri)37 void Escapes(const string &uri) {
38 const char *first = uri.c_str();
39 // A new line char takes 6 char to encode.
40 // Use a vector to make a C string.
41 std::vector<char> buf1(uri.size() * 6 + 1);
42 std::vector<char> buf2(uri.size() * 3 + 1);
43
44 char *result;
45 result = uriEscapeA(first, &buf1[0], URI_TRUE, URI_TRUE);
46 result = uriEscapeA(first, &buf1[0], URI_FALSE, URI_TRUE);
47 if (buf1.data()) uriUnescapeInPlaceA(&buf1[0]);
48
49 result = uriEscapeA(first, &buf2[0], URI_TRUE, URI_FALSE);
50 result = uriEscapeA(first, &buf2[0], URI_FALSE, URI_FALSE);
51 if (buf2.data()) uriUnescapeInPlaceA(&buf2[0]);
52 }
53
FileNames(const string & uri)54 void FileNames(const string &uri) {
55 const size_t size = 8 + 3 * uri.size() + 1;
56 std::vector<char> buf(size);
57
58 uriUnixFilenameToUriStringA(uri.c_str(), &buf[0]);
59 uriWindowsFilenameToUriStringA(uri.c_str(), &buf[0]);
60 uriUriStringToUnixFilenameA(uri.c_str(), &buf[0]);
61 uriUriStringToWindowsFilenameA(uri.c_str(), &buf[0]);
62 }
63
64 int uriParseIpFourAddressA(unsigned char *octetOutput, const char *first,
65 const char *afterLast);
66
Ipv4(const string & s)67 void Ipv4(const string &s) {
68 const char *cstr = s.c_str();
69 unsigned char result[4] = {};
70 uriParseIpFourAddressA(result, cstr, &cstr[s.size()]);
71 }
72
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)73 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
74
75 FuzzedDataProvider stream(data, size);
76 bool domainRelative = stream.ConsumeBool();
77 size_t uriSize = stream.remaining_bytes() / 2;
78
79 const string uri1 = stream.ConsumeBytesAsString(uriSize);
80 const string uri2 = stream.ConsumeRemainingBytesAsString();
81
82 Escapes(uri1);
83 Escapes(uri2);
84
85 FileNames(uri1);
86 FileNames(uri2);
87
88 Ipv4(uri1);
89 Ipv4(uri2);
90
91 UriParserA parser1;
92 UriParserStateA state1;
93 state1.uri = parser1.get_mutable_uri();
94 if (uriParseUriA(&state1, uri1.c_str()) != URI_SUCCESS)
95 return 0;
96
97 char buf[1024 * 8] = {0};
98 int written = 0;
99 uriToStringA(buf, state1.uri, sizeof(buf), &written);
100
101 UriParserA parser2;
102 UriParserStateA state2;
103 state2.uri = parser2.get_mutable_uri();
104 if (uriParseUriA(&state2, uri2.c_str()) != URI_SUCCESS)
105 return 0;
106
107 uriEqualsUriA(state1.uri, state2.uri);
108
109 uriNormalizeSyntaxA(state1.uri);
110
111 UriUriA absUri;
112 uriAddBaseUriA(&absUri, state1.uri, state2.uri);
113 uriFreeUriMembersA(&absUri);
114
115 UriUriA relUri;
116 uriRemoveBaseUriA(&relUri, state1.uri, state2.uri, domainRelative);
117 uriFreeUriMembersA(&relUri);
118
119 return 0;
120 }
121