Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
yhirose committed Dec 1, 2020
1 parent 9c0c98b commit 5dd605d
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 56 deletions.
58 changes: 39 additions & 19 deletions httplib.h
Original file line number Diff line number Diff line change
Expand Up @@ -1340,14 +1340,6 @@ inline std::string from_i_to_hex(size_t n) {
return ret;
}

inline bool start_with(const std::string &a, const std::string &b) {
if (a.size() < b.size()) { return false; }
for (size_t i = 0; i < b.size(); i++) {
if (::tolower(a[i]) != ::tolower(b[i])) { return false; }
}
return true;
}

inline size_t to_utf8(int code, char *buff) {
if (code < 0x0080) {
buff[0] = (code & 0x7F);
Expand Down Expand Up @@ -3126,7 +3118,7 @@ class MultipartFormDataParser {

static const std::string header_name = "content-type:";
const auto header = buf_.substr(0, pos);
if (start_with(header, header_name)) {
if (start_with_case_ignore(header, header_name)) {
file_.content_type = trim_copy(header.substr(header_name.size()));
} else {
std::smatch m;
Expand All @@ -3148,15 +3140,7 @@ class MultipartFormDataParser {
auto pattern = crlf_ + dash_;
if (pattern.size() > buf_.size()) { return true; }

auto pos = buf_.find(pattern);
if (pos == std::string::npos) {
pos = buf_.size();
while (pos > 0) {
auto c = buf_[pos - 1];
if (c != '\r' && c != '\n' && c != '-') { break; }
pos--;
}
}
auto pos = find_string(buf_, pattern);

if (!content_callback(buf_.data(), pos)) {
is_valid_ = false;
Expand All @@ -3166,7 +3150,6 @@ class MultipartFormDataParser {
off_ += pos;
buf_.erase(0, pos);
}

{
auto pattern = crlf_ + dash_ + boundary_;
if (pattern.size() > buf_.size()) { return true; }
Expand Down Expand Up @@ -3230,6 +3213,43 @@ class MultipartFormDataParser {
file_.content_type.clear();
}

bool start_with_case_ignore(const std::string &a,
const std::string &b) const {
if (a.size() < b.size()) { return false; }
for (size_t i = 0; i < b.size(); i++) {
if (::tolower(a[i]) != ::tolower(b[i])) { return false; }
}
return true;
}

bool start_with(const std::string &a, size_t off,
const std::string &b) const {
if (a.size() - off < b.size()) { return false; }
for (size_t i = 0; i < b.size(); i++) {
if (a[i + off] != b[i]) { return false; }
}
return true;
}

size_t find_string(const std::string &s, const std::string &pattern) const {
auto c = pattern.front();

size_t off = 0;
while (off < s.size()) {
auto pos = s.find(c, off);
if (pos == std::string::npos) { return s.size(); }

auto rem = s.size() - pos;
if (pattern.size() > rem) { return pos; }

if (start_with(s, pos, pattern)) { return pos; }

off = pos + 1;
}

return s.size();
}

std::string boundary_;

std::string buf_;
Expand Down
72 changes: 35 additions & 37 deletions test/fuzzing/server_fuzzer.cc
Original file line number Diff line number Diff line change
@@ -1,28 +1,26 @@
#include <memory>
#include <httplib.h>
#include <memory>

class FuzzedStream : public httplib::Stream {
public:
FuzzedStream(const uint8_t* data, size_t size)
public:
FuzzedStream(const uint8_t *data, size_t size)
: data_(data), size_(size), read_pos_(0) {}

ssize_t read(char* ptr, size_t size) override {
if (size + read_pos_ > size_) {
size = size_ - read_pos_;
}
ssize_t read(char *ptr, size_t size) override {
if (size + read_pos_ > size_) { size = size_ - read_pos_; }
memcpy(ptr, data_ + read_pos_, size);
read_pos_ += size;
return size;
return static_cast<ssize_t>(size);
}

ssize_t write(const char* ptr, size_t size) override {
ssize_t write(const char *ptr, size_t size) override {
response_.append(ptr, size);
return static_cast<int>(size);
}

int write(const char* ptr) { return write(ptr, strlen(ptr)); }
ssize_t write(const char *ptr) { return write(ptr, strlen(ptr)); }

int write(const std::string& s) { return write(s.data(), s.size()); }
ssize_t write(const std::string &s) { return write(s.data(), s.size()); }

std::string get_remote_addr() const { return ""; }

Expand All @@ -37,16 +35,16 @@ class FuzzedStream : public httplib::Stream {

socket_t socket() const override { return 0; }

private:
const uint8_t* data_;
private:
const uint8_t *data_;
size_t size_;
size_t read_pos_;
std::string response_;
};

class FuzzableServer : public httplib::Server {
public:
void ProcessFuzzedRequest(FuzzedStream& stream) {
public:
void ProcessFuzzedRequest(FuzzedStream &stream) {
bool connection_close = false;
process_request(stream, /*last_connection=*/false, connection_close,
nullptr);
Expand All @@ -55,36 +53,36 @@ class FuzzableServer : public httplib::Server {

static FuzzableServer g_server;

extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
extern "C" int LLVMFuzzerInitialize(int * /*argc*/, char *** /*argv*/) {
g_server.Get(R"(.*)",
[&](const httplib::Request& req, httplib::Response& res) {
res.set_content("response content", "text/plain");
});
[&](const httplib::Request & /*req*/, httplib::Response &res) {
res.set_content("response content", "text/plain");
});
g_server.Post(R"(.*)",
[&](const httplib::Request& req, httplib::Response& res) {
res.set_content("response content", "text/plain");
});
g_server.Put(R"(.*)",
[&](const httplib::Request& req, httplib::Response& res) {
[&](const httplib::Request & /*req*/, httplib::Response &res) {
res.set_content("response content", "text/plain");
});
g_server.Put(R"(.*)",
[&](const httplib::Request & /*req*/, httplib::Response &res) {
res.set_content("response content", "text/plain");
});
g_server.Patch(R"(.*)",
[&](const httplib::Request& req, httplib::Response& res) {
res.set_content("response content", "text/plain");
});
g_server.Delete(R"(.*)",
[&](const httplib::Request& req, httplib::Response& res) {
res.set_content("response content", "text/plain");
});
g_server.Options(R"(.*)",
[&](const httplib::Request& req, httplib::Response& res) {
res.set_content("response content", "text/plain");
});
[&](const httplib::Request & /*req*/, httplib::Response &res) {
res.set_content("response content", "text/plain");
});
g_server.Delete(
R"(.*)", [&](const httplib::Request & /*req*/, httplib::Response &res) {
res.set_content("response content", "text/plain");
});
g_server.Options(
R"(.*)", [&](const httplib::Request & /*req*/, httplib::Response &res) {
res.set_content("response content", "text/plain");
});
return 0;
}

extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
FuzzedStream stream{data, size};
g_server.ProcessFuzzedRequest(stream);
return 0;
}
}

0 comments on commit 5dd605d

Please sign in to comment.