mirror of
https://github.com/yhirose/cpp-httplib
synced 2026-06-08 18:30:49 +00:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 953600c177 | |||
| 536e7eb7f2 | |||
| 6d66721ba1 | |||
| 3b29cd0bdc | |||
| 109b624dfe | |||
| 0ed70c4d9f | |||
| a50b7591ca | |||
| bf8fc11b53 | |||
| bc4a613b6d | |||
| 4bb001351c |
@@ -173,6 +173,7 @@ using socket_t = int;
|
||||
#define INVALID_SOCKET (-1)
|
||||
#endif //_WIN32
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
@@ -325,6 +326,10 @@ using ContentProvider =
|
||||
using ContentProviderWithoutLength =
|
||||
std::function<bool(size_t offset, DataSink &sink)>;
|
||||
|
||||
using ContentReceiverWithProgress =
|
||||
std::function<bool(const char *data, size_t data_length, uint64_t offset,
|
||||
uint64_t total_length)>;
|
||||
|
||||
using ContentReceiver =
|
||||
std::function<bool(const char *data, size_t data_length)>;
|
||||
|
||||
@@ -377,7 +382,7 @@ struct Request {
|
||||
// for client
|
||||
size_t redirect_count = CPPHTTPLIB_REDIRECT_MAX_COUNT;
|
||||
ResponseHandler response_handler;
|
||||
ContentReceiver content_receiver;
|
||||
ContentReceiverWithProgress content_receiver;
|
||||
size_t content_length = 0;
|
||||
ContentProvider content_provider;
|
||||
Progress progress;
|
||||
@@ -688,8 +693,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 +808,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 +1045,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);
|
||||
@@ -2509,7 +2512,8 @@ inline bool read_headers(Stream &strm, Headers &headers) {
|
||||
}
|
||||
|
||||
inline bool read_content_with_length(Stream &strm, uint64_t len,
|
||||
Progress progress, ContentReceiver out) {
|
||||
Progress progress,
|
||||
ContentReceiverWithProgress out) {
|
||||
char buf[CPPHTTPLIB_RECV_BUFSIZ];
|
||||
|
||||
uint64_t r = 0;
|
||||
@@ -2518,8 +2522,7 @@ inline bool read_content_with_length(Stream &strm, uint64_t len,
|
||||
auto n = strm.read(buf, (std::min)(read_len, CPPHTTPLIB_RECV_BUFSIZ));
|
||||
if (n <= 0) { return false; }
|
||||
|
||||
if (!out(buf, static_cast<size_t>(n))) { return false; }
|
||||
|
||||
if (!out(buf, static_cast<size_t>(n), r, len)) { return false; }
|
||||
r += static_cast<uint64_t>(n);
|
||||
|
||||
if (progress) {
|
||||
@@ -2541,8 +2544,10 @@ inline void skip_content_with_length(Stream &strm, uint64_t len) {
|
||||
}
|
||||
}
|
||||
|
||||
inline bool read_content_without_length(Stream &strm, ContentReceiver out) {
|
||||
inline bool read_content_without_length(Stream &strm,
|
||||
ContentReceiverWithProgress out) {
|
||||
char buf[CPPHTTPLIB_RECV_BUFSIZ];
|
||||
uint64_t r = 0;
|
||||
for (;;) {
|
||||
auto n = strm.read(buf, CPPHTTPLIB_RECV_BUFSIZ);
|
||||
if (n < 0) {
|
||||
@@ -2550,13 +2555,16 @@ inline bool read_content_without_length(Stream &strm, ContentReceiver out) {
|
||||
} else if (n == 0) {
|
||||
return true;
|
||||
}
|
||||
if (!out(buf, static_cast<size_t>(n))) { return false; }
|
||||
|
||||
if (!out(buf, static_cast<size_t>(n), r, 0)) { return false; }
|
||||
r += static_cast<uint64_t>(n);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool read_content_chunked(Stream &strm, ContentReceiver out) {
|
||||
inline bool read_content_chunked(Stream &strm,
|
||||
ContentReceiverWithProgress out) {
|
||||
const auto bufsiz = 16;
|
||||
char buf[bufsiz];
|
||||
|
||||
@@ -2601,7 +2609,8 @@ inline bool is_chunked_transfer_encoding(const Headers &headers) {
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
bool prepare_content_receiver(T &x, int &status, ContentReceiver receiver,
|
||||
bool prepare_content_receiver(T &x, int &status,
|
||||
ContentReceiverWithProgress receiver,
|
||||
bool decompress, U callback) {
|
||||
if (decompress) {
|
||||
std::string encoding = x.get_header_value("Content-Encoding");
|
||||
@@ -2626,10 +2635,12 @@ bool prepare_content_receiver(T &x, int &status, ContentReceiver receiver,
|
||||
|
||||
if (decompressor) {
|
||||
if (decompressor->is_valid()) {
|
||||
ContentReceiver out = [&](const char *buf, size_t n) {
|
||||
return decompressor->decompress(
|
||||
buf, n,
|
||||
[&](const char *buf, size_t n) { return receiver(buf, n); });
|
||||
ContentReceiverWithProgress out = [&](const char *buf, size_t n,
|
||||
uint64_t off, uint64_t len) {
|
||||
return decompressor->decompress(buf, n,
|
||||
[&](const char *buf, size_t n) {
|
||||
return receiver(buf, n, off, len);
|
||||
});
|
||||
};
|
||||
return callback(std::move(out));
|
||||
} else {
|
||||
@@ -2639,18 +2650,20 @@ bool prepare_content_receiver(T &x, int &status, ContentReceiver receiver,
|
||||
}
|
||||
}
|
||||
|
||||
ContentReceiver out = [&](const char *buf, size_t n) {
|
||||
return receiver(buf, n);
|
||||
ContentReceiverWithProgress out = [&](const char *buf, size_t n, uint64_t off,
|
||||
uint64_t len) {
|
||||
return receiver(buf, n, off, len);
|
||||
};
|
||||
return callback(std::move(out));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool read_content(Stream &strm, T &x, size_t payload_max_length, int &status,
|
||||
Progress progress, ContentReceiver receiver,
|
||||
Progress progress, ContentReceiverWithProgress receiver,
|
||||
bool decompress) {
|
||||
return prepare_content_receiver(
|
||||
x, status, std::move(receiver), decompress, [&](const ContentReceiver &out) {
|
||||
x, status, std::move(receiver), decompress,
|
||||
[&](const ContentReceiverWithProgress &out) {
|
||||
auto ret = true;
|
||||
auto exceed_payload_max_length = false;
|
||||
|
||||
@@ -2906,7 +2919,7 @@ inline bool parse_multipart_boundary(const std::string &content_type,
|
||||
return !boundary.empty();
|
||||
}
|
||||
|
||||
inline bool parse_range_header(const std::string &s, Ranges &ranges) {
|
||||
inline bool parse_range_header(const std::string &s, Ranges &ranges) 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)) {
|
||||
@@ -2938,7 +2951,7 @@ inline bool parse_range_header(const std::string &s, Ranges &ranges) {
|
||||
return all_valid_ranges;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} catch (...) { return false; }
|
||||
|
||||
class MultipartFormDataParser {
|
||||
public:
|
||||
@@ -2949,7 +2962,8 @@ public:
|
||||
bool is_valid() const { return is_valid_; }
|
||||
|
||||
template <typename T, typename U>
|
||||
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="
|
||||
@@ -3150,7 +3164,7 @@ get_range_offset_and_length(const Request &req, size_t content_length,
|
||||
auto slen = static_cast<ssize_t>(content_length);
|
||||
|
||||
if (r.first == -1) {
|
||||
r.first = slen - r.second;
|
||||
r.first = (std::max)(static_cast<ssize_t>(0), slen - r.second);
|
||||
r.second = slen - 1;
|
||||
}
|
||||
|
||||
@@ -3797,14 +3811,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 +3830,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 +3843,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 +3856,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 +3869,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 +4254,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));
|
||||
}
|
||||
@@ -4250,7 +4264,7 @@ inline bool Server::read_content_core(Stream &strm, Request &req, Response &res,
|
||||
MultipartContentHeader mulitpart_header,
|
||||
ContentReceiver multipart_receiver) {
|
||||
detail::MultipartFormDataParser multipart_form_data_parser;
|
||||
ContentReceiver out;
|
||||
ContentReceiverWithProgress out;
|
||||
|
||||
if (req.is_multipart_form_data()) {
|
||||
const auto &content_type = req.get_header_value("Content-Type");
|
||||
@@ -4261,7 +4275,7 @@ inline bool Server::read_content_core(Stream &strm, Request &req, Response &res,
|
||||
}
|
||||
|
||||
multipart_form_data_parser.set_boundary(std::move(boundary));
|
||||
out = [&](const char *buf, size_t n) {
|
||||
out = [&](const char *buf, size_t n, uint64_t /*off*/, uint64_t /*len*/) {
|
||||
/* For debug
|
||||
size_t pos = 0;
|
||||
while (pos < n) {
|
||||
@@ -4277,7 +4291,8 @@ inline bool Server::read_content_core(Stream &strm, Request &req, Response &res,
|
||||
mulitpart_header);
|
||||
};
|
||||
} else {
|
||||
out = std::move(receiver);
|
||||
out = [receiver](const char *buf, size_t n, uint64_t /*off*/,
|
||||
uint64_t /*len*/) { return receiver(buf, n); };
|
||||
}
|
||||
|
||||
if (req.method == "DELETE" && !req.has_header("Content-Length")) {
|
||||
@@ -4314,7 +4329,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 +4450,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,
|
||||
@@ -4497,7 +4511,6 @@ inline bool Server::routing(Request &req, Response &res, Stream &strm) {
|
||||
|
||||
inline bool Server::dispatch_request(Request &req, Response &res,
|
||||
const Handlers &handlers) {
|
||||
|
||||
try {
|
||||
for (const auto &x : handlers) {
|
||||
const auto &pattern = x.first;
|
||||
@@ -4580,7 +4593,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5119,16 +5133,21 @@ inline bool ClientImpl::process_request(Stream &strm, const Request &req,
|
||||
if (req.method != "HEAD" && req.method != "CONNECT") {
|
||||
auto out =
|
||||
req.content_receiver
|
||||
? static_cast<ContentReceiver>([&](const char *buf, size_t n) {
|
||||
auto ret = req.content_receiver(buf, n);
|
||||
if (!ret) { error_ = Error::Canceled; }
|
||||
return ret;
|
||||
})
|
||||
: static_cast<ContentReceiver>([&](const char *buf, size_t n) {
|
||||
if (res.body.size() + n > res.body.max_size()) { return false; }
|
||||
res.body.append(buf, n);
|
||||
return true;
|
||||
});
|
||||
? static_cast<ContentReceiverWithProgress>(
|
||||
[&](const char *buf, size_t n, uint64_t off, uint64_t len) {
|
||||
auto ret = req.content_receiver(buf, n, off, len);
|
||||
if (!ret) { error_ = Error::Canceled; }
|
||||
return ret;
|
||||
})
|
||||
: static_cast<ContentReceiverWithProgress>(
|
||||
[&](const char *buf, size_t n, uint64_t /*off*/,
|
||||
uint64_t /*len*/) {
|
||||
if (res.body.size() + n > res.body.max_size()) {
|
||||
return false;
|
||||
}
|
||||
res.body.append(buf, n);
|
||||
return true;
|
||||
});
|
||||
|
||||
auto progress = [&](uint64_t current, uint64_t total) {
|
||||
if (!req.progress) { return true; }
|
||||
@@ -5160,10 +5179,9 @@ inline bool ClientImpl::process_request(Stream &strm, const Request &req,
|
||||
inline bool
|
||||
ClientImpl::process_socket(Socket &socket,
|
||||
std::function<bool(Stream &strm)> 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; }
|
||||
@@ -5250,7 +5268,11 @@ inline Result ClientImpl::Get(const char *path, const Headers &headers,
|
||||
req.headers = default_headers_;
|
||||
req.headers.insert(headers.begin(), headers.end());
|
||||
req.response_handler = std::move(response_handler);
|
||||
req.content_receiver = std::move(content_receiver);
|
||||
req.content_receiver =
|
||||
[content_receiver](const char *data, size_t data_length,
|
||||
uint64_t /*offset*/, uint64_t /*total_length*/) {
|
||||
return content_receiver(data, data_length);
|
||||
};
|
||||
req.progress = std::move(progress);
|
||||
|
||||
auto res = detail::make_unique<Response>();
|
||||
@@ -5306,10 +5328,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 +5351,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 +5410,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 +5450,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()};
|
||||
}
|
||||
|
||||
@@ -5718,22 +5737,7 @@ inline SSLSocketStream::SSLSocketStream(socket_t sock, SSL *ssl,
|
||||
read_timeout_usec_(read_timeout_usec),
|
||||
write_timeout_sec_(write_timeout_sec),
|
||||
write_timeout_usec_(write_timeout_usec) {
|
||||
{
|
||||
timeval tv;
|
||||
tv.tv_sec = static_cast<long>(read_timeout_sec);
|
||||
tv.tv_usec = static_cast<decltype(tv.tv_usec)>(read_timeout_usec);
|
||||
|
||||
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<char *>(&tv),
|
||||
sizeof(tv));
|
||||
}
|
||||
{
|
||||
timeval tv;
|
||||
tv.tv_sec = static_cast<long>(write_timeout_sec);
|
||||
tv.tv_usec = static_cast<decltype(tv.tv_usec)>(write_timeout_usec);
|
||||
|
||||
setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, reinterpret_cast<char *>(&tv),
|
||||
sizeof(tv));
|
||||
}
|
||||
SSL_clear_mode(ssl, SSL_MODE_AUTO_RETRY);
|
||||
}
|
||||
|
||||
inline SSLSocketStream::~SSLSocketStream() {}
|
||||
@@ -5748,8 +5752,27 @@ inline bool SSLSocketStream::is_writable() const {
|
||||
}
|
||||
|
||||
inline ssize_t SSLSocketStream::read(char *ptr, size_t size) {
|
||||
if (SSL_pending(ssl_) > 0 || is_readable()) {
|
||||
if (SSL_pending(ssl_) > 0) {
|
||||
return SSL_read(ssl_, ptr, static_cast<int>(size));
|
||||
} else if (is_readable()) {
|
||||
auto ret = SSL_read(ssl_, ptr, static_cast<int>(size));
|
||||
if (ret < 0) {
|
||||
auto err = SSL_get_error(ssl_, ret);
|
||||
while (err == SSL_ERROR_WANT_READ) {
|
||||
if (SSL_pending(ssl_) > 0) {
|
||||
return SSL_read(ssl_, ptr, static_cast<int>(size));
|
||||
} else if (is_readable()) {
|
||||
ret = SSL_read(ssl_, ptr, static_cast<int>(size));
|
||||
if (ret >= 0) {
|
||||
return ret;
|
||||
}
|
||||
err = SSL_get_error(ssl_, ret);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -6246,6 +6269,8 @@ inline Client::Client(const char *scheme_host_port,
|
||||
#else
|
||||
if (!scheme.empty() && scheme != "http") {
|
||||
#endif
|
||||
std::string msg = "'" + scheme + "' scheme is not supported.";
|
||||
throw std::invalid_argument(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -6381,7 +6406,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); }
|
||||
|
||||
+40
-8
@@ -1897,6 +1897,38 @@ TEST_F(ServerTest, GetStreamedWithRange2) {
|
||||
EXPECT_EQ(std::string("bcdefg"), res->body);
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, GetStreamedWithRangeSuffix1) {
|
||||
auto res = cli_.Get("/streamed-with-range", {
|
||||
{"Range", "bytes=-3"}
|
||||
});
|
||||
ASSERT_TRUE(res);
|
||||
EXPECT_EQ(206, res->status);
|
||||
EXPECT_EQ("3", res->get_header_value("Content-Length"));
|
||||
EXPECT_EQ(true, res->has_header("Content-Range"));
|
||||
EXPECT_EQ(std::string("efg"), res->body);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(ServerTest, GetStreamedWithRangeSuffix2) {
|
||||
auto res = cli_.Get("/streamed-with-range", {
|
||||
{"Range", "bytes=-9999"}
|
||||
});
|
||||
ASSERT_TRUE(res);
|
||||
EXPECT_EQ(206, res->status);
|
||||
EXPECT_EQ("7", res->get_header_value("Content-Length"));
|
||||
EXPECT_EQ(true, res->has_header("Content-Range"));
|
||||
EXPECT_EQ(std::string("abcdefg"), 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}})}});
|
||||
@@ -3267,6 +3299,7 @@ TEST(SSLClientServerTest, ClientCertPresent) {
|
||||
t.join();
|
||||
}
|
||||
|
||||
#if !defined(_WIN32) || defined(OPENSSL_USE_APPLINK)
|
||||
TEST(SSLClientServerTest, MemoryClientCertPresent) {
|
||||
X509 *server_cert;
|
||||
EVP_PKEY *server_private_key;
|
||||
@@ -3342,6 +3375,7 @@ TEST(SSLClientServerTest, MemoryClientCertPresent) {
|
||||
|
||||
t.join();
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(SSLClientServerTest, ClientCertMissing) {
|
||||
SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE, CLIENT_CA_CERT_FILE,
|
||||
@@ -3395,17 +3429,15 @@ TEST(CleanupTest, WSACleanup) {
|
||||
}
|
||||
#endif
|
||||
|
||||
// #ifndef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
// TEST(NoSSLSupport, SimpleInterface) {
|
||||
// Client cli("https://yahoo.com");
|
||||
// ASSERT_FALSE(cli.is_valid());
|
||||
// }
|
||||
// #endif
|
||||
#ifndef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
TEST(NoSSLSupport, SimpleInterface) {
|
||||
ASSERT_ANY_THROW(Client cli("https://yahoo.com"));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
TEST(InvalidScheme, SimpleInterface) {
|
||||
Client cli("scheme://yahoo.com");
|
||||
ASSERT_FALSE(cli.is_valid());
|
||||
ASSERT_ANY_THROW(Client cli("scheme://yahoo.com"));
|
||||
}
|
||||
|
||||
TEST(NoScheme, SimpleInterface) {
|
||||
|
||||
Reference in New Issue
Block a user