// Copyright 2020 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include #include #include #include #include using std::string; #include "uriparser/include/uriparser/Uri.h" #include "uriparser/include/uriparser/UriIp4.h" class UriParserA { public: UriParserA() { memset((void *)&uri_, 0, sizeof(uri_)); } ~UriParserA() { uriFreeUriMembersA(&uri_); } UriUriA *get_mutable_uri() { return &uri_; } UriUriA *get_uri() const { return const_cast(&uri_); } private: UriUriA uri_; }; void Escapes(const string &uri) { const char *first = uri.c_str(); // A new line char takes 6 char to encode. // Use a vector to make a C string. std::vector buf1(uri.size() * 6 + 1); std::vector buf2(uri.size() * 3 + 1); char *result; result = uriEscapeA(first, &buf1[0], URI_TRUE, URI_TRUE); result = uriEscapeA(first, &buf1[0], URI_FALSE, URI_TRUE); if (buf1.data()) uriUnescapeInPlaceA(&buf1[0]); result = uriEscapeA(first, &buf2[0], URI_TRUE, URI_FALSE); result = uriEscapeA(first, &buf2[0], URI_FALSE, URI_FALSE); if (buf2.data()) uriUnescapeInPlaceA(&buf2[0]); } void FileNames(const string &uri) { const size_t size = 8 + 3 * uri.size() + 1; std::vector buf(size); uriUnixFilenameToUriStringA(uri.c_str(), &buf[0]); uriWindowsFilenameToUriStringA(uri.c_str(), &buf[0]); uriUriStringToUnixFilenameA(uri.c_str(), &buf[0]); uriUriStringToWindowsFilenameA(uri.c_str(), &buf[0]); } int uriParseIpFourAddressA(unsigned char *octetOutput, const char *first, const char *afterLast); void Ipv4(const string &s) { const char *cstr = s.c_str(); unsigned char result[4] = {}; uriParseIpFourAddressA(result, cstr, &cstr[s.size()]); } extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { FuzzedDataProvider stream(data, size); bool domainRelative = stream.ConsumeBool(); size_t uriSize = stream.remaining_bytes() / 2; const string uri1 = stream.ConsumeBytesAsString(uriSize); const string uri2 = stream.ConsumeRemainingBytesAsString(); Escapes(uri1); Escapes(uri2); FileNames(uri1); FileNames(uri2); Ipv4(uri1); Ipv4(uri2); UriParserA parser1; UriParserStateA state1; state1.uri = parser1.get_mutable_uri(); if (uriParseUriA(&state1, uri1.c_str()) != URI_SUCCESS) return 0; char buf[1024 * 8] = {0}; int written = 0; uriToStringA(buf, state1.uri, sizeof(buf), &written); UriParserA parser2; UriParserStateA state2; state2.uri = parser2.get_mutable_uri(); if (uriParseUriA(&state2, uri2.c_str()) != URI_SUCCESS) return 0; uriEqualsUriA(state1.uri, state2.uri); uriNormalizeSyntaxA(state1.uri); UriUriA absUri; uriAddBaseUriA(&absUri, state1.uri, state2.uri); uriFreeUriMembersA(&absUri); UriUriA relUri; uriRemoveBaseUriA(&relUri, state1.uri, state2.uri, domainRelative); uriFreeUriMembersA(&relUri); return 0; }