mirror of
https://github.com/yhirose/cpp-httplib
synced 2026-06-08 18:30:49 +00:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 30b7732565 | |||
| 6650632e7f | |||
| afe627e7af | |||
| 67f6ff7fa9 | |||
| c7ed1796a7 | |||
| 44c62d838e | |||
| 6bb580cda8 | |||
| 00a8cb8e5d | |||
| 2e34a39673 | |||
| 01b90829bc |
@@ -8,7 +8,7 @@
|
||||
#ifndef CPPHTTPLIB_HTTPLIB_H
|
||||
#define CPPHTTPLIB_HTTPLIB_H
|
||||
|
||||
#define CPPHTTPLIB_VERSION "0.13.2"
|
||||
#define CPPHTTPLIB_VERSION "0.14.0"
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
@@ -193,6 +193,7 @@ using socket_t = SOCKET;
|
||||
#endif
|
||||
#include <csignal>
|
||||
#include <pthread.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
@@ -486,8 +487,7 @@ struct Request {
|
||||
|
||||
bool has_header(const std::string &key) const;
|
||||
std::string get_header_value(const std::string &key, size_t id = 0) const;
|
||||
template <typename T>
|
||||
T get_header_value(const std::string &key, size_t id = 0) const;
|
||||
uint64_t get_header_value_u64(const std::string &key, size_t id = 0) const;
|
||||
size_t get_header_value_count(const std::string &key) const;
|
||||
void set_header(const std::string &key, const std::string &val);
|
||||
|
||||
@@ -519,8 +519,7 @@ struct Response {
|
||||
|
||||
bool has_header(const std::string &key) const;
|
||||
std::string get_header_value(const std::string &key, size_t id = 0) const;
|
||||
template <typename T>
|
||||
T get_header_value(const std::string &key, size_t id = 0) const;
|
||||
uint64_t get_header_value_u64(const std::string &key, size_t id = 0) const;
|
||||
size_t get_header_value_count(const std::string &key) const;
|
||||
void set_header(const std::string &key, const std::string &val);
|
||||
|
||||
@@ -784,6 +783,7 @@ public:
|
||||
bool remove_mount_point(const std::string &mount_point);
|
||||
Server &set_file_extension_and_mimetype_mapping(const std::string &ext,
|
||||
const std::string &mime);
|
||||
Server &set_default_file_mimetype(const std::string &mime);
|
||||
Server &set_file_request_handler(Handler handler);
|
||||
|
||||
Server &set_error_handler(HandlerWithResponse handler);
|
||||
@@ -907,6 +907,7 @@ private:
|
||||
};
|
||||
std::vector<MountPointEntry> base_dirs_;
|
||||
std::map<std::string, std::string> file_extension_and_mimetype_map_;
|
||||
std::string default_file_mimetype_ = "application/octet-stream";
|
||||
Handler file_request_handler_;
|
||||
|
||||
Handlers get_handlers_;
|
||||
@@ -985,8 +986,8 @@ public:
|
||||
bool has_request_header(const std::string &key) const;
|
||||
std::string get_request_header_value(const std::string &key,
|
||||
size_t id = 0) const;
|
||||
template <typename T>
|
||||
T get_request_header_value(const std::string &key, size_t id = 0) const;
|
||||
uint64_t get_request_header_value_u64(const std::string &key,
|
||||
size_t id = 0) const;
|
||||
size_t get_request_header_value_count(const std::string &key) const;
|
||||
|
||||
private:
|
||||
@@ -1707,15 +1708,9 @@ inline void duration_to_sec_and_usec(const T &duration, U callback) {
|
||||
callback(static_cast<time_t>(sec), static_cast<time_t>(usec));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T get_header_value(const Headers & /*headers*/,
|
||||
const std::string & /*key*/, size_t /*id*/ = 0,
|
||||
uint64_t /*def*/ = 0) {}
|
||||
|
||||
template <>
|
||||
inline uint64_t get_header_value<uint64_t>(const Headers &headers,
|
||||
const std::string &key, size_t id,
|
||||
uint64_t def) {
|
||||
inline uint64_t get_header_value_u64(const Headers &headers,
|
||||
const std::string &key, size_t id,
|
||||
uint64_t def) {
|
||||
auto rng = headers.equal_range(key);
|
||||
auto it = rng.first;
|
||||
std::advance(it, static_cast<ssize_t>(id));
|
||||
@@ -1727,14 +1722,14 @@ inline uint64_t get_header_value<uint64_t>(const Headers &headers,
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename T>
|
||||
inline T Request::get_header_value(const std::string &key, size_t id) const {
|
||||
return detail::get_header_value<T>(headers, key, id, 0);
|
||||
inline uint64_t Request::get_header_value_u64(const std::string &key,
|
||||
size_t id) const {
|
||||
return detail::get_header_value_u64(headers, key, id, 0);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T Response::get_header_value(const std::string &key, size_t id) const {
|
||||
return detail::get_header_value<T>(headers, key, id, 0);
|
||||
inline uint64_t Response::get_header_value_u64(const std::string &key,
|
||||
size_t id) const {
|
||||
return detail::get_header_value_u64(headers, key, id, 0);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
@@ -1903,10 +1898,9 @@ inline std::ostream &operator<<(std::ostream &os, const Error &obj) {
|
||||
return os;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T Result::get_request_header_value(const std::string &key,
|
||||
size_t id) const {
|
||||
return detail::get_header_value<T>(request_headers_, key, id, 0);
|
||||
inline uint64_t Result::get_request_header_value_u64(const std::string &key,
|
||||
size_t id) const {
|
||||
return detail::get_header_value_u64(request_headers_, key, id, 0);
|
||||
}
|
||||
|
||||
template <class Rep, class Period>
|
||||
@@ -2142,6 +2136,29 @@ private:
|
||||
std::string glowable_buffer_;
|
||||
};
|
||||
|
||||
class mmap {
|
||||
public:
|
||||
mmap(const char *path);
|
||||
~mmap();
|
||||
|
||||
bool open(const char *path);
|
||||
void close();
|
||||
|
||||
bool is_open() const;
|
||||
size_t size() const;
|
||||
const char *data() const;
|
||||
|
||||
private:
|
||||
#if defined(_WIN32)
|
||||
HANDLE hFile_;
|
||||
HANDLE hMapping_;
|
||||
#else
|
||||
int fd_;
|
||||
#endif
|
||||
size_t size_;
|
||||
void *addr_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -2522,6 +2539,95 @@ inline void stream_line_reader::append(char c) {
|
||||
}
|
||||
}
|
||||
|
||||
inline mmap::mmap(const char *path)
|
||||
#if defined(_WIN32)
|
||||
: hFile_(NULL), hMapping_(NULL)
|
||||
#else
|
||||
: fd_(-1)
|
||||
#endif
|
||||
,
|
||||
size_(0), addr_(nullptr) {
|
||||
if (!open(path)) { std::runtime_error(""); }
|
||||
}
|
||||
|
||||
inline mmap::~mmap() { close(); }
|
||||
|
||||
inline bool mmap::open(const char *path) {
|
||||
close();
|
||||
|
||||
#if defined(_WIN32)
|
||||
hFile_ = ::CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
if (hFile_ == INVALID_HANDLE_VALUE) { return false; }
|
||||
|
||||
size_ = ::GetFileSize(hFile_, NULL);
|
||||
|
||||
hMapping_ = ::CreateFileMapping(hFile_, NULL, PAGE_READONLY, 0, 0, NULL);
|
||||
|
||||
if (hMapping_ == NULL) {
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
addr_ = ::MapViewOfFile(hMapping_, FILE_MAP_READ, 0, 0, 0);
|
||||
#else
|
||||
fd_ = ::open(path, O_RDONLY);
|
||||
if (fd_ == -1) { return false; }
|
||||
|
||||
struct stat sb;
|
||||
if (fstat(fd_, &sb) == -1) {
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
size_ = static_cast<size_t>(sb.st_size);
|
||||
|
||||
addr_ = ::mmap(NULL, size_, PROT_READ, MAP_PRIVATE, fd_, 0);
|
||||
#endif
|
||||
|
||||
if (addr_ == nullptr) {
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool mmap::is_open() const { return addr_ != nullptr; }
|
||||
|
||||
inline size_t mmap::size() const { return size_; }
|
||||
|
||||
inline const char *mmap::data() const { return (const char *)addr_; }
|
||||
|
||||
inline void mmap::close() {
|
||||
#if defined(_WIN32)
|
||||
if (addr_) {
|
||||
::UnmapViewOfFile(addr_);
|
||||
addr_ = nullptr;
|
||||
}
|
||||
|
||||
if (hMapping_) {
|
||||
::CloseHandle(hMapping_);
|
||||
hMapping_ = NULL;
|
||||
}
|
||||
|
||||
if (hFile_ != INVALID_HANDLE_VALUE) {
|
||||
::CloseHandle(hFile_);
|
||||
hFile_ = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
#else
|
||||
if (addr_ != nullptr) {
|
||||
munmap(addr_, size_);
|
||||
addr_ = nullptr;
|
||||
}
|
||||
|
||||
if (fd_ != -1) {
|
||||
::close(fd_);
|
||||
fd_ = -1;
|
||||
}
|
||||
#endif
|
||||
size_ = 0;
|
||||
}
|
||||
inline int close_socket(socket_t sock) {
|
||||
#ifdef _WIN32
|
||||
return closesocket(sock);
|
||||
@@ -3197,9 +3303,10 @@ inline constexpr unsigned int operator"" _t(const char *s, size_t l) {
|
||||
|
||||
} // namespace udl
|
||||
|
||||
inline const char *
|
||||
inline std::string
|
||||
find_content_type(const std::string &path,
|
||||
const std::map<std::string, std::string> &user_data) {
|
||||
const std::map<std::string, std::string> &user_data,
|
||||
const std::string &default_content_type) {
|
||||
auto ext = file_extension(path);
|
||||
|
||||
auto it = user_data.find(ext);
|
||||
@@ -3208,7 +3315,8 @@ find_content_type(const std::string &path,
|
||||
using udl::operator""_t;
|
||||
|
||||
switch (str2tag(ext)) {
|
||||
default: return nullptr;
|
||||
default: return default_content_type;
|
||||
|
||||
case "css"_t: return "text/css";
|
||||
case "csv"_t: return "text/csv";
|
||||
case "htm"_t:
|
||||
@@ -3777,7 +3885,7 @@ bool read_content(Stream &strm, T &x, size_t payload_max_length, int &status,
|
||||
} else if (!has_header(x.headers, "Content-Length")) {
|
||||
ret = read_content_without_length(strm, out);
|
||||
} else {
|
||||
auto len = get_header_value<uint64_t>(x.headers, "Content-Length");
|
||||
auto len = get_header_value_u64(x.headers, "Content-Length", 0, 0);
|
||||
if (len > payload_max_length) {
|
||||
exceed_payload_max_length = true;
|
||||
skip_content_with_length(strm, len);
|
||||
@@ -4111,7 +4219,7 @@ inline bool parse_range_header(const std::string &s, Ranges &ranges) try {
|
||||
if (std::regex_match(s, m, re_first_range)) {
|
||||
auto pos = static_cast<size_t>(m.position(1));
|
||||
auto len = static_cast<size_t>(m.length(1));
|
||||
bool all_valid_ranges = true;
|
||||
auto 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*))");
|
||||
@@ -4489,12 +4597,13 @@ get_range_offset_and_length(const Request &req, size_t content_length,
|
||||
return std::make_pair(r.first, static_cast<size_t>(r.second - r.first) + 1);
|
||||
}
|
||||
|
||||
inline std::string make_content_range_header_field(size_t offset, size_t length,
|
||||
size_t content_length) {
|
||||
inline std::string
|
||||
make_content_range_header_field(const std::pair<ssize_t, ssize_t> &range,
|
||||
size_t content_length) {
|
||||
std::string field = "bytes ";
|
||||
field += std::to_string(offset);
|
||||
if (range.first != -1) { field += std::to_string(range.first); }
|
||||
field += "-";
|
||||
field += std::to_string(offset + length - 1);
|
||||
if (range.second != -1) { field += std::to_string(range.second); }
|
||||
field += "/";
|
||||
field += std::to_string(content_length);
|
||||
return field;
|
||||
@@ -4516,21 +4625,22 @@ bool process_multipart_ranges_data(const Request &req, Response &res,
|
||||
ctoken("\r\n");
|
||||
}
|
||||
|
||||
auto offsets = get_range_offset_and_length(req, res.body.size(), i);
|
||||
ctoken("Content-Range: ");
|
||||
const auto &range = req.ranges[i];
|
||||
stoken(make_content_range_header_field(range, res.content_length_));
|
||||
ctoken("\r\n");
|
||||
ctoken("\r\n");
|
||||
|
||||
auto offsets = get_range_offset_and_length(req, res.content_length_, i);
|
||||
auto offset = offsets.first;
|
||||
auto length = offsets.second;
|
||||
|
||||
ctoken("Content-Range: ");
|
||||
stoken(make_content_range_header_field(offset, length, res.body.size()));
|
||||
ctoken("\r\n");
|
||||
ctoken("\r\n");
|
||||
if (!content(offset, length)) { return false; }
|
||||
ctoken("\r\n");
|
||||
}
|
||||
|
||||
ctoken("--");
|
||||
stoken(boundary);
|
||||
ctoken("--\r\n");
|
||||
ctoken("--");
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -4867,7 +4977,7 @@ inline bool parse_www_authenticate(const Response &res,
|
||||
s = s.substr(pos + 1);
|
||||
auto beg = std::sregex_iterator(s.begin(), s.end(), re);
|
||||
for (auto i = beg; i != std::sregex_iterator(); ++i) {
|
||||
auto m = *i;
|
||||
const auto &m = *i;
|
||||
auto key = s.substr(static_cast<size_t>(m.position(1)),
|
||||
static_cast<size_t>(m.length(1)));
|
||||
auto val = m.length(2) > 0
|
||||
@@ -5493,6 +5603,11 @@ Server::set_file_extension_and_mimetype_mapping(const std::string &ext,
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Server &Server::set_default_file_mimetype(const std::string &mime) {
|
||||
default_file_mimetype_ = mime;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Server &Server::set_file_request_handler(Handler handler) {
|
||||
file_request_handler_ = std::move(handler);
|
||||
return *this;
|
||||
@@ -5944,17 +6059,26 @@ inline bool Server::handle_file_request(const Request &req, Response &res,
|
||||
if (path.back() == '/') { path += "index.html"; }
|
||||
|
||||
if (detail::is_file(path)) {
|
||||
detail::read_file(path, res.body);
|
||||
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) {
|
||||
res.set_header(kv.first.c_str(), kv.second);
|
||||
}
|
||||
res.status = req.has_header("Range") ? 206 : 200;
|
||||
|
||||
auto mm = std::make_shared<detail::mmap>(path.c_str());
|
||||
if (!mm->is_open()) { return false; }
|
||||
|
||||
res.set_content_provider(
|
||||
mm->size(),
|
||||
detail::find_content_type(path, file_extension_and_mimetype_map_,
|
||||
default_file_mimetype_),
|
||||
[mm](size_t offset, size_t length, DataSink &sink) -> bool {
|
||||
sink.write(mm->data() + offset, length);
|
||||
return true;
|
||||
});
|
||||
|
||||
if (!head && file_request_handler_) {
|
||||
file_request_handler_(req, res);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -6202,10 +6326,10 @@ inline void Server::apply_ranges(const Request &req, Response &res,
|
||||
} else if (req.ranges.size() == 1) {
|
||||
auto offsets =
|
||||
detail::get_range_offset_and_length(req, res.content_length_, 0);
|
||||
auto offset = offsets.first;
|
||||
length = offsets.second;
|
||||
|
||||
auto content_range = detail::make_content_range_header_field(
|
||||
offset, length, res.content_length_);
|
||||
req.ranges[0], res.content_length_);
|
||||
res.set_header("Content-Range", content_range);
|
||||
} else {
|
||||
length = detail::get_multipart_ranges_data_length(req, res, boundary,
|
||||
@@ -6228,13 +6352,15 @@ inline void Server::apply_ranges(const Request &req, Response &res,
|
||||
if (req.ranges.empty()) {
|
||||
;
|
||||
} else if (req.ranges.size() == 1) {
|
||||
auto content_range = detail::make_content_range_header_field(
|
||||
req.ranges[0], res.body.size());
|
||||
res.set_header("Content-Range", content_range);
|
||||
|
||||
auto offsets =
|
||||
detail::get_range_offset_and_length(req, res.body.size(), 0);
|
||||
auto offset = offsets.first;
|
||||
auto length = offsets.second;
|
||||
auto content_range = detail::make_content_range_header_field(
|
||||
offset, length, res.body.size());
|
||||
res.set_header("Content-Range", content_range);
|
||||
|
||||
if (offset < res.body.size()) {
|
||||
res.body = res.body.substr(offset, length);
|
||||
} else {
|
||||
@@ -6390,7 +6516,7 @@ Server::process_request(Stream &strm, bool close_connection,
|
||||
}
|
||||
|
||||
// Rounting
|
||||
bool routed = false;
|
||||
auto routed = false;
|
||||
#ifdef CPPHTTPLIB_NO_EXCEPTIONS
|
||||
routed = routing(req, res, strm);
|
||||
#else
|
||||
@@ -6588,9 +6714,9 @@ inline bool ClientImpl::read_response_line(Stream &strm, const Request &req,
|
||||
if (!line_reader.getline()) { return false; }
|
||||
|
||||
#ifdef CPPHTTPLIB_ALLOW_LF_AS_LINE_TERMINATOR
|
||||
const static std::regex re("(HTTP/1\\.[01]) (\\d{3})(?: (.*?))?\r\n");
|
||||
#else
|
||||
const static std::regex re("(HTTP/1\\.[01]) (\\d{3})(?: (.*?))?\r?\n");
|
||||
#else
|
||||
const static std::regex re("(HTTP/1\\.[01]) (\\d{3})(?: (.*?))?\r\n");
|
||||
#endif
|
||||
|
||||
std::cmatch m;
|
||||
@@ -7206,7 +7332,7 @@ inline ContentProviderWithoutLength ClientImpl::get_multipart_content_provider(
|
||||
}
|
||||
|
||||
DataSink cur_sink;
|
||||
bool has_data = true;
|
||||
auto has_data = true;
|
||||
cur_sink.write = sink.write;
|
||||
cur_sink.done = [&]() { has_data = false; };
|
||||
|
||||
@@ -8335,10 +8461,9 @@ inline bool SSLClient::connect_with_proxy(Socket &socket, Response &res,
|
||||
}
|
||||
|
||||
// If status code is not 200, proxy request is failed.
|
||||
// Set error to ProxyConnection and return proxy response
|
||||
// Set error to ProxyConnection and return proxy response
|
||||
// as the response of the request
|
||||
if (proxy_res.status != 200)
|
||||
{
|
||||
if (proxy_res.status != 200) {
|
||||
error = Error::ProxyConnection;
|
||||
res = std::move(proxy_res);
|
||||
// Thread-safe to close everything because we are assuming there are
|
||||
@@ -8353,7 +8478,7 @@ inline bool SSLClient::connect_with_proxy(Socket &socket, Response &res,
|
||||
}
|
||||
|
||||
inline bool SSLClient::load_certs() {
|
||||
bool ret = true;
|
||||
auto ret = true;
|
||||
|
||||
std::call_once(initialize_cert_, [&]() {
|
||||
std::lock_guard<std::mutex> guard(ctx_mutex_);
|
||||
|
||||
+57
-10
@@ -211,8 +211,7 @@ TEST(GetHeaderValueTest, DefaultValue) {
|
||||
|
||||
TEST(GetHeaderValueTest, DefaultValueInt) {
|
||||
Headers headers = {{"Dummy", "Dummy"}};
|
||||
auto val =
|
||||
detail::get_header_value<uint64_t>(headers, "Content-Length", 0, 100);
|
||||
auto val = detail::get_header_value_u64(headers, "Content-Length", 0, 100);
|
||||
EXPECT_EQ(100ull, val);
|
||||
}
|
||||
|
||||
@@ -241,8 +240,7 @@ TEST(GetHeaderValueTest, SetContent) {
|
||||
|
||||
TEST(GetHeaderValueTest, RegularValueInt) {
|
||||
Headers headers = {{"Content-Length", "100"}, {"Dummy", "Dummy"}};
|
||||
auto val =
|
||||
detail::get_header_value<uint64_t>(headers, "Content-Length", 0, 0);
|
||||
auto val = detail::get_header_value_u64(headers, "Content-Length", 0, 0);
|
||||
EXPECT_EQ(100ull, val);
|
||||
}
|
||||
|
||||
@@ -1016,7 +1014,7 @@ TEST(UrlWithSpace, Redirect_Online) {
|
||||
auto res = cli.Get("/files/2595/310/Neat 1.4-17.jar");
|
||||
ASSERT_TRUE(res);
|
||||
EXPECT_EQ(200, res->status);
|
||||
EXPECT_EQ(18527U, res->get_header_value<uint64_t>("Content-Length"));
|
||||
EXPECT_EQ(18527U, res->get_header_value_u64("Content-Length"));
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -2501,6 +2499,55 @@ TEST_F(ServerTest, StaticFileRange) {
|
||||
EXPECT_EQ(std::string("cd"), res->body);
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, StaticFileRanges) {
|
||||
auto res =
|
||||
cli_.Get("/dir/test.abcde", {{make_range_header({{1, 2}, {4, -1}})}});
|
||||
ASSERT_TRUE(res);
|
||||
EXPECT_EQ(206, res->status);
|
||||
EXPECT_TRUE(
|
||||
res->get_header_value("Content-Type")
|
||||
.find(
|
||||
"multipart/byteranges; boundary=--cpp-httplib-multipart-data-") ==
|
||||
0);
|
||||
EXPECT_EQ("265", res->get_header_value("Content-Length"));
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, StaticFileRangeHead) {
|
||||
auto res = cli_.Head("/dir/test.abcde", {{make_range_header({{2, 3}})}});
|
||||
ASSERT_TRUE(res);
|
||||
EXPECT_EQ(206, res->status);
|
||||
EXPECT_EQ("text/abcde", res->get_header_value("Content-Type"));
|
||||
EXPECT_EQ("2", res->get_header_value("Content-Length"));
|
||||
EXPECT_EQ(true, res->has_header("Content-Range"));
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, StaticFileRangeBigFile) {
|
||||
auto res = cli_.Get("/dir/1MB.txt", {{make_range_header({{-1, 5}})}});
|
||||
ASSERT_TRUE(res);
|
||||
EXPECT_EQ(206, res->status);
|
||||
EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
|
||||
EXPECT_EQ("5", res->get_header_value("Content-Length"));
|
||||
EXPECT_EQ(true, res->has_header("Content-Range"));
|
||||
EXPECT_EQ("LAST\n", res->body);
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, StaticFileRangeBigFile2) {
|
||||
auto res = cli_.Get("/dir/1MB.txt", {{make_range_header({{1, 4097}})}});
|
||||
ASSERT_TRUE(res);
|
||||
EXPECT_EQ(206, res->status);
|
||||
EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
|
||||
EXPECT_EQ("4097", res->get_header_value("Content-Length"));
|
||||
EXPECT_EQ(true, res->has_header("Content-Range"));
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, StaticFileBigFile) {
|
||||
auto res = cli_.Get("/dir/1MB.txt");
|
||||
ASSERT_TRUE(res);
|
||||
EXPECT_EQ(200, res->status);
|
||||
EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
|
||||
EXPECT_EQ("1048576", res->get_header_value("Content-Length"));
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, InvalidBaseDirMount) {
|
||||
EXPECT_EQ(false, svr_.set_mount_point("invalid_mount_point", "./www3"));
|
||||
}
|
||||
@@ -2886,9 +2933,9 @@ TEST_F(ServerTest, GetStreamedWithRangeMultipart) {
|
||||
cli_.Get("/streamed-with-range", {{make_range_header({{1, 2}, {4, 5}})}});
|
||||
ASSERT_TRUE(res);
|
||||
EXPECT_EQ(206, res->status);
|
||||
EXPECT_EQ("269", res->get_header_value("Content-Length"));
|
||||
EXPECT_EQ("267", res->get_header_value("Content-Length"));
|
||||
EXPECT_EQ(false, res->has_header("Content-Range"));
|
||||
EXPECT_EQ(269U, res->body.size());
|
||||
EXPECT_EQ(267U, res->body.size());
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, GetStreamedEndless) {
|
||||
@@ -2978,9 +3025,9 @@ TEST_F(ServerTest, GetWithRangeMultipart) {
|
||||
auto res = cli_.Get("/with-range", {{make_range_header({{1, 2}, {4, 5}})}});
|
||||
ASSERT_TRUE(res);
|
||||
EXPECT_EQ(206, res->status);
|
||||
EXPECT_EQ("269", res->get_header_value("Content-Length"));
|
||||
EXPECT_EQ("267", res->get_header_value("Content-Length"));
|
||||
EXPECT_EQ(false, res->has_header("Content-Range"));
|
||||
EXPECT_EQ(269U, res->body.size());
|
||||
EXPECT_EQ(267U, res->body.size());
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, GetWithRangeMultipartOffsetGreaterThanContent) {
|
||||
@@ -3247,7 +3294,7 @@ TEST_F(ServerTest, PutLargeFileWithGzip2) {
|
||||
ASSERT_TRUE(res);
|
||||
EXPECT_EQ(200, res->status);
|
||||
EXPECT_EQ(LARGE_DATA, res->body);
|
||||
EXPECT_EQ(101942u, res.get_request_header_value<uint64_t>("Content-Length"));
|
||||
EXPECT_EQ(101942u, res.get_request_header_value_u64("Content-Length"));
|
||||
EXPECT_EQ("gzip", res.get_request_header_value("Content-Encoding"));
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user