oss-fuzz/projects/uriparser/uri_parse_fuzzer.cc

121 lines
3.4 KiB
C++

// 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 <cstddef>
#include <cstring>
#include <string>
#include <vector>
#include <fuzzer/FuzzedDataProvider.h>
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<UriUriA *>(&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<char> buf1(uri.size() * 6 + 1);
std::vector<char> 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<char> 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;
}