diff --git a/httplib.h b/httplib.h index bef0ceb..5b39ff1 100644 --- a/httplib.h +++ b/httplib.h @@ -688,8 +688,8 @@ private: ContentReceiver multipart_receiver); virtual bool process_and_close_socket(socket_t sock); - - struct MountPointEntry { + + struct MountPointEntry { std::string mount_point; std::string base_dir; Headers headers; @@ -803,8 +803,7 @@ public: Result Post(const char *path, const Headers &headers, const MultipartFormDataItems &items); Result Post(const char *path, const Headers &headers, - const MultipartFormDataItems &items, - const std::string& boundary); + const MultipartFormDataItems &items, const std::string &boundary); Result Put(const char *path); Result Put(const char *path, const std::string &body, @@ -1041,8 +1040,7 @@ public: Result Post(const char *path, const Headers &headers, const MultipartFormDataItems &items); Result Post(const char *path, const Headers &headers, - const MultipartFormDataItems &items, - const std::string& boundary); + const MultipartFormDataItems &items, const std::string &boundary); Result Put(const char *path); Result Put(const char *path, const std::string &body, const char *content_type); @@ -2650,7 +2648,8 @@ bool read_content(Stream &strm, T &x, size_t payload_max_length, int &status, Progress progress, ContentReceiver receiver, bool decompress) { return prepare_content_receiver( - x, status, std::move(receiver), decompress, [&](const ContentReceiver &out) { + x, status, std::move(receiver), decompress, + [&](const ContentReceiver &out) { auto ret = true; auto exceed_payload_max_length = false; @@ -2907,37 +2906,40 @@ inline bool parse_multipart_boundary(const std::string &content_type, } inline bool parse_range_header(const std::string &s, Ranges &ranges) { - static auto re_first_range = std::regex(R"(bytes=(\d*-\d*(?:,\s*\d*-\d*)*))"); - std::smatch m; - if (std::regex_match(s, m, re_first_range)) { - auto pos = static_cast(m.position(1)); - auto len = static_cast(m.length(1)); - bool all_valid_ranges = true; - split(&s[pos], &s[pos + len], ',', [&](const char *b, const char *e) { - if (!all_valid_ranges) return; - static auto re_another_range = std::regex(R"(\s*(\d*)-(\d*))"); - std::cmatch cm; - if (std::regex_match(b, e, cm, re_another_range)) { - ssize_t first = -1; - if (!cm.str(1).empty()) { - first = static_cast(std::stoll(cm.str(1))); - } + try { + static auto re_first_range = + std::regex(R"(bytes=(\d*-\d*(?:,\s*\d*-\d*)*))"); + std::smatch m; + if (std::regex_match(s, m, re_first_range)) { + auto pos = static_cast(m.position(1)); + auto len = static_cast(m.length(1)); + bool all_valid_ranges = true; + split(&s[pos], &s[pos + len], ',', [&](const char *b, const char *e) { + if (!all_valid_ranges) return; + static auto re_another_range = std::regex(R"(\s*(\d*)-(\d*))"); + std::cmatch cm; + if (std::regex_match(b, e, cm, re_another_range)) { + ssize_t first = -1; + if (!cm.str(1).empty()) { + first = static_cast(std::stoll(cm.str(1))); + } - ssize_t last = -1; - if (!cm.str(2).empty()) { - last = static_cast(std::stoll(cm.str(2))); - } + ssize_t last = -1; + if (!cm.str(2).empty()) { + last = static_cast(std::stoll(cm.str(2))); + } - if (first != -1 && last != -1 && first > last) { - all_valid_ranges = false; - return; + if (first != -1 && last != -1 && first > last) { + all_valid_ranges = false; + return; + } + ranges.emplace_back(std::make_pair(first, last)); } - ranges.emplace_back(std::make_pair(first, last)); - } - }); - return all_valid_ranges; - } - return false; + }); + return all_valid_ranges; + } + return false; + } catch (...) { return false; } } class MultipartFormDataParser { @@ -2949,7 +2951,8 @@ public: bool is_valid() const { return is_valid_; } template - bool parse(const char *buf, size_t n, const T &content_callback, const U &header_callback) { + bool parse(const char *buf, size_t n, const T &content_callback, + const U &header_callback) { static const std::regex re_content_disposition( "^Content-Disposition:\\s*form-data;\\s*name=\"(.*?)\"(?:;\\s*filename=" @@ -3797,14 +3800,14 @@ inline Server::Server() inline Server::~Server() {} inline Server &Server::Get(const char *pattern, Handler handler) { - get_handlers_.push_back(std::make_pair(std::regex(pattern), - std::move(handler))); + get_handlers_.push_back( + std::make_pair(std::regex(pattern), std::move(handler))); return *this; } inline Server &Server::Post(const char *pattern, Handler handler) { - post_handlers_.push_back(std::make_pair(std::regex(pattern), - std::move(handler))); + post_handlers_.push_back( + std::make_pair(std::regex(pattern), std::move(handler))); return *this; } @@ -3816,8 +3819,8 @@ inline Server &Server::Post(const char *pattern, } inline Server &Server::Put(const char *pattern, Handler handler) { - put_handlers_.push_back(std::make_pair(std::regex(pattern), - std::move(handler))); + put_handlers_.push_back( + std::make_pair(std::regex(pattern), std::move(handler))); return *this; } @@ -3829,8 +3832,8 @@ inline Server &Server::Put(const char *pattern, } inline Server &Server::Patch(const char *pattern, Handler handler) { - patch_handlers_.push_back(std::make_pair(std::regex(pattern), - std::move(handler))); + patch_handlers_.push_back( + std::make_pair(std::regex(pattern), std::move(handler))); return *this; } @@ -3842,8 +3845,8 @@ inline Server &Server::Patch(const char *pattern, } inline Server &Server::Delete(const char *pattern, Handler handler) { - delete_handlers_.push_back(std::make_pair(std::regex(pattern), - std::move(handler))); + delete_handlers_.push_back( + std::make_pair(std::regex(pattern), std::move(handler))); return *this; } @@ -3855,8 +3858,8 @@ inline Server &Server::Delete(const char *pattern, } inline Server &Server::Options(const char *pattern, Handler handler) { - options_handlers_.push_back(std::make_pair(std::regex(pattern), - std::move(handler))); + options_handlers_.push_back( + std::make_pair(std::regex(pattern), std::move(handler))); return *this; } @@ -4240,7 +4243,7 @@ inline bool Server::read_content_with_content_receiver( Stream &strm, Request &req, Response &res, ContentReceiver receiver, MultipartContentHeader multipart_header, ContentReceiver multipart_receiver) { - return read_content_core(strm, req, res, std::move(receiver), + return read_content_core(strm, req, res, std::move(receiver), std::move(multipart_header), std::move(multipart_receiver)); } @@ -4314,7 +4317,7 @@ inline bool Server::handle_file_request(Request &req, Response &res, auto type = detail::find_content_type(path, file_extension_and_mimetype_map_); if (type) { res.set_header("Content-Type", type); } - for (const auto& kv : entry.headers) { + for (const auto &kv : entry.headers) { res.set_header(kv.first.c_str(), kv.second); } res.status = 200; @@ -4435,9 +4438,8 @@ inline bool Server::routing(Request &req, Response &res, Stream &strm) { { ContentReader reader( [&](ContentReceiver receiver) { - return read_content_with_content_receiver(strm, req, res, - std::move(receiver), - nullptr, nullptr); + return read_content_with_content_receiver( + strm, req, res, std::move(receiver), nullptr, nullptr); }, [&](MultipartContentHeader header, ContentReceiver receiver) { return read_content_with_content_receiver(strm, req, res, nullptr, @@ -4580,7 +4582,8 @@ Server::process_request(Stream &strm, bool close_connection, if (req.has_header("Range")) { const auto &range_header_value = req.get_header_value("Range"); if (!detail::parse_range_header(range_header_value, req.ranges)) { - // TODO: error + res.status = 416; + return write_response(strm, close_connection, req, res); } } @@ -5160,10 +5163,9 @@ inline bool ClientImpl::process_request(Stream &strm, const Request &req, inline bool ClientImpl::process_socket(Socket &socket, std::function callback) { - return detail::process_client_socket(socket.sock, read_timeout_sec_, - read_timeout_usec_, write_timeout_sec_, - write_timeout_usec_, - std::move(callback)); + return detail::process_client_socket( + socket.sock, read_timeout_sec_, read_timeout_usec_, write_timeout_sec_, + write_timeout_usec_, std::move(callback)); } inline bool ClientImpl::is_ssl() const { return false; } @@ -5306,10 +5308,9 @@ inline Result ClientImpl::Post(const char *path, const Headers &headers, size_t content_length, ContentProvider content_provider, const char *content_type) { - auto ret = send_with_content_provider("POST", path, headers, std::string(), - content_length, - std::move(content_provider), - content_type); + auto ret = send_with_content_provider( + "POST", path, headers, std::string(), content_length, + std::move(content_provider), content_type); return Result{std::move(ret), get_last_error()}; } @@ -5330,7 +5331,7 @@ inline Result ClientImpl::Post(const char *path, const Headers &headers, } inline Result ClientImpl::Post(const char *path, const Headers &headers, const MultipartFormDataItems &items, - const std::string& boundary) { + const std::string &boundary) { for (size_t i = 0; i < boundary.size(); i++) { char c = boundary[i]; if (!std::isalnum(c) && c != '-' && c != '_') { @@ -5389,10 +5390,9 @@ inline Result ClientImpl::Put(const char *path, const Headers &headers, size_t content_length, ContentProvider content_provider, const char *content_type) { - auto ret = send_with_content_provider("PUT", path, headers, std::string(), - content_length, - std::move(content_provider), - content_type); + auto ret = send_with_content_provider( + "PUT", path, headers, std::string(), content_length, + std::move(content_provider), content_type); return Result{std::move(ret), get_last_error()}; } @@ -5430,10 +5430,9 @@ inline Result ClientImpl::Patch(const char *path, const Headers &headers, size_t content_length, ContentProvider content_provider, const char *content_type) { - auto ret = send_with_content_provider("PATCH", path, headers, std::string(), - content_length, - std::move(content_provider), - content_type); + auto ret = send_with_content_provider( + "PATCH", path, headers, std::string(), content_length, + std::move(content_provider), content_type); return Result{std::move(ret), get_last_error()}; } @@ -6381,7 +6380,7 @@ inline Result Client::Post(const char *path, const Headers &headers, } inline Result Client::Post(const char *path, const Headers &headers, const MultipartFormDataItems &items, - const std::string& boundary) { + const std::string &boundary) { return cli_->Post(path, headers, items, boundary); } inline Result Client::Put(const char *path) { return cli_->Put(path); } diff --git a/test/test.cc b/test/test.cc index f6c4c97..fdec7a9 100644 --- a/test/test.cc +++ b/test/test.cc @@ -1897,6 +1897,14 @@ TEST_F(ServerTest, GetStreamedWithRange2) { EXPECT_EQ(std::string("bcdefg"), res->body); } +TEST_F(ServerTest, GetStreamedWithRangeError) { + auto res = cli_.Get("/streamed-with-range", { + {"Range", "bytes=92233720368547758079223372036854775806-92233720368547758079223372036854775807"} + }); + ASSERT_TRUE(res); + EXPECT_EQ(416, res->status); +} + TEST_F(ServerTest, GetStreamedWithRangeMultipart) { auto res = cli_.Get("/streamed-with-range", {{make_range_header({{1, 2}, {4, 5}})}});