This commit is contained in:
yhirose 2020-11-30 21:46:36 -05:00
parent 9c0c98b1ed
commit 5dd605d3a2
2 changed files with 74 additions and 56 deletions

View file

@ -1340,14 +1340,6 @@ inline std::string from_i_to_hex(size_t n) {
return ret; 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) { inline size_t to_utf8(int code, char *buff) {
if (code < 0x0080) { if (code < 0x0080) {
buff[0] = (code & 0x7F); buff[0] = (code & 0x7F);
@ -3126,7 +3118,7 @@ public:
static const std::string header_name = "content-type:"; static const std::string header_name = "content-type:";
const auto header = buf_.substr(0, pos); 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())); file_.content_type = trim_copy(header.substr(header_name.size()));
} else { } else {
std::smatch m; std::smatch m;
@ -3148,15 +3140,7 @@ public:
auto pattern = crlf_ + dash_; auto pattern = crlf_ + dash_;
if (pattern.size() > buf_.size()) { return true; } if (pattern.size() > buf_.size()) { return true; }
auto pos = buf_.find(pattern); auto pos = find_string(buf_, 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--;
}
}
if (!content_callback(buf_.data(), pos)) { if (!content_callback(buf_.data(), pos)) {
is_valid_ = false; is_valid_ = false;
@ -3166,7 +3150,6 @@ public:
off_ += pos; off_ += pos;
buf_.erase(0, pos); buf_.erase(0, pos);
} }
{ {
auto pattern = crlf_ + dash_ + boundary_; auto pattern = crlf_ + dash_ + boundary_;
if (pattern.size() > buf_.size()) { return true; } if (pattern.size() > buf_.size()) { return true; }
@ -3230,6 +3213,43 @@ private:
file_.content_type.clear(); 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 boundary_;
std::string buf_; std::string buf_;

View file

@ -1,28 +1,26 @@
#include <memory>
#include <httplib.h> #include <httplib.h>
#include <memory>
class FuzzedStream : public httplib::Stream { class FuzzedStream : public httplib::Stream {
public: public:
FuzzedStream(const uint8_t* data, size_t size) FuzzedStream(const uint8_t *data, size_t size)
: data_(data), size_(size), read_pos_(0) {} : data_(data), size_(size), read_pos_(0) {}
ssize_t read(char* ptr, size_t size) override { ssize_t read(char *ptr, size_t size) override {
if (size + read_pos_ > size_) { if (size + read_pos_ > size_) { size = size_ - read_pos_; }
size = size_ - read_pos_;
}
memcpy(ptr, data_ + read_pos_, size); memcpy(ptr, data_ + read_pos_, size);
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); response_.append(ptr, size);
return static_cast<int>(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 ""; } std::string get_remote_addr() const { return ""; }
@ -37,16 +35,16 @@ class FuzzedStream : public httplib::Stream {
socket_t socket() const override { return 0; } socket_t socket() const override { return 0; }
private: private:
const uint8_t* data_; const uint8_t *data_;
size_t size_; size_t size_;
size_t read_pos_; size_t read_pos_;
std::string response_; std::string response_;
}; };
class FuzzableServer : public httplib::Server { class FuzzableServer : public httplib::Server {
public: public:
void ProcessFuzzedRequest(FuzzedStream& stream) { void ProcessFuzzedRequest(FuzzedStream &stream) {
bool connection_close = false; bool connection_close = false;
process_request(stream, /*last_connection=*/false, connection_close, process_request(stream, /*last_connection=*/false, connection_close,
nullptr); nullptr);
@ -55,36 +53,36 @@ class FuzzableServer : public httplib::Server {
static FuzzableServer g_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"(.*)", g_server.Get(R"(.*)",
[&](const httplib::Request& req, httplib::Response& res) { [&](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"); res.set_content("response content", "text/plain");
}); });
g_server.Post(R"(.*)", 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.Patch(R"(.*)",
[&](const httplib::Request & /*req*/, httplib::Response &res) {
res.set_content("response content", "text/plain"); res.set_content("response content", "text/plain");
}); });
g_server.Put(R"(.*)", g_server.Delete(
[&](const httplib::Request& req, httplib::Response& res) { R"(.*)", [&](const httplib::Request & /*req*/, httplib::Response &res) {
res.set_content("response content", "text/plain"); res.set_content("response content", "text/plain");
}); });
g_server.Patch(R"(.*)", g_server.Options(
[&](const httplib::Request& req, httplib::Response& res) { R"(.*)", [&](const httplib::Request & /*req*/, httplib::Response &res) {
res.set_content("response content", "text/plain"); 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; 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}; FuzzedStream stream{data, size};
g_server.ProcessFuzzedRequest(stream); g_server.ProcessFuzzedRequest(stream);
return 0; return 0;
} }