mirror of
https://github.com/yhirose/cpp-httplib
synced 2024-11-21 14:29:10 -07:00
Added chunked content provider support on client
This commit is contained in:
parent
cee062d4c9
commit
c2afc5ca44
2 changed files with 318 additions and 129 deletions
391
httplib.h
391
httplib.h
|
@ -269,9 +269,11 @@ make_unique(std::size_t n) {
|
||||||
|
|
||||||
struct ci {
|
struct ci {
|
||||||
bool operator()(const std::string &s1, const std::string &s2) const {
|
bool operator()(const std::string &s1, const std::string &s2) const {
|
||||||
return std::lexicographical_compare(
|
return std::lexicographical_compare(s1.begin(), s1.end(), s2.begin(),
|
||||||
s1.begin(), s1.end(), s2.begin(), s2.end(),
|
s2.end(),
|
||||||
[](unsigned char c1, unsigned char c2) { return ::tolower(c1) < ::tolower(c2); });
|
[](unsigned char c1, unsigned char c2) {
|
||||||
|
return ::tolower(c1) < ::tolower(c2);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -388,13 +390,6 @@ struct Request {
|
||||||
Match matches;
|
Match matches;
|
||||||
|
|
||||||
// for client
|
// for client
|
||||||
size_t redirect_count = CPPHTTPLIB_REDIRECT_MAX_COUNT;
|
|
||||||
ResponseHandler response_handler;
|
|
||||||
ContentReceiverWithProgress content_receiver;
|
|
||||||
size_t content_length = 0;
|
|
||||||
ContentProvider content_provider;
|
|
||||||
Progress progress;
|
|
||||||
|
|
||||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||||
const SSL *ssl;
|
const SSL *ssl;
|
||||||
#endif
|
#endif
|
||||||
|
@ -417,6 +412,13 @@ struct Request {
|
||||||
MultipartFormData get_file_value(const char *key) const;
|
MultipartFormData get_file_value(const char *key) const;
|
||||||
|
|
||||||
// private members...
|
// private members...
|
||||||
|
size_t redirect_count_ = CPPHTTPLIB_REDIRECT_MAX_COUNT;
|
||||||
|
ResponseHandler response_handler_;
|
||||||
|
ContentReceiverWithProgress content_receiver_;
|
||||||
|
size_t content_length_ = 0;
|
||||||
|
ContentProvider content_provider_;
|
||||||
|
bool is_chunked_content_provider_ = false;
|
||||||
|
Progress progress_;
|
||||||
size_t authorization_count_ = 0;
|
size_t authorization_count_ = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -467,7 +469,7 @@ struct Response {
|
||||||
size_t content_length_ = 0;
|
size_t content_length_ = 0;
|
||||||
ContentProvider content_provider_;
|
ContentProvider content_provider_;
|
||||||
std::function<void()> content_provider_resource_releaser_;
|
std::function<void()> content_provider_resource_releaser_;
|
||||||
bool is_chunked_content_provider = false;
|
bool is_chunked_content_provider_ = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Stream {
|
class Stream {
|
||||||
|
@ -819,8 +821,13 @@ public:
|
||||||
const char *content_type);
|
const char *content_type);
|
||||||
Result Post(const char *path, size_t content_length,
|
Result Post(const char *path, size_t content_length,
|
||||||
ContentProvider content_provider, const char *content_type);
|
ContentProvider content_provider, const char *content_type);
|
||||||
|
Result Post(const char *path, ContentProviderWithoutLength content_provider,
|
||||||
|
const char *content_type);
|
||||||
Result Post(const char *path, const Headers &headers, size_t content_length,
|
Result Post(const char *path, const Headers &headers, size_t content_length,
|
||||||
ContentProvider content_provider, const char *content_type);
|
ContentProvider content_provider, const char *content_type);
|
||||||
|
Result Post(const char *path, const Headers &headers,
|
||||||
|
ContentProviderWithoutLength content_provider,
|
||||||
|
const char *content_type);
|
||||||
Result Post(const char *path, const Params ¶ms);
|
Result Post(const char *path, const Params ¶ms);
|
||||||
Result Post(const char *path, const Headers &headers, const Params ¶ms);
|
Result Post(const char *path, const Headers &headers, const Params ¶ms);
|
||||||
Result Post(const char *path, const MultipartFormDataItems &items);
|
Result Post(const char *path, const MultipartFormDataItems &items);
|
||||||
|
@ -836,8 +843,13 @@ public:
|
||||||
const char *content_type);
|
const char *content_type);
|
||||||
Result Put(const char *path, size_t content_length,
|
Result Put(const char *path, size_t content_length,
|
||||||
ContentProvider content_provider, const char *content_type);
|
ContentProvider content_provider, const char *content_type);
|
||||||
|
Result Put(const char *path, ContentProviderWithoutLength content_provider,
|
||||||
|
const char *content_type);
|
||||||
Result Put(const char *path, const Headers &headers, size_t content_length,
|
Result Put(const char *path, const Headers &headers, size_t content_length,
|
||||||
ContentProvider content_provider, const char *content_type);
|
ContentProvider content_provider, const char *content_type);
|
||||||
|
Result Put(const char *path, const Headers &headers,
|
||||||
|
ContentProviderWithoutLength content_provider,
|
||||||
|
const char *content_type);
|
||||||
Result Put(const char *path, const Params ¶ms);
|
Result Put(const char *path, const Params ¶ms);
|
||||||
Result Put(const char *path, const Headers &headers, const Params ¶ms);
|
Result Put(const char *path, const Headers &headers, const Params ¶ms);
|
||||||
|
|
||||||
|
@ -847,8 +859,13 @@ public:
|
||||||
const std::string &body, const char *content_type);
|
const std::string &body, const char *content_type);
|
||||||
Result Patch(const char *path, size_t content_length,
|
Result Patch(const char *path, size_t content_length,
|
||||||
ContentProvider content_provider, const char *content_type);
|
ContentProvider content_provider, const char *content_type);
|
||||||
|
Result Patch(const char *path, ContentProviderWithoutLength content_provider,
|
||||||
|
const char *content_type);
|
||||||
Result Patch(const char *path, const Headers &headers, size_t content_length,
|
Result Patch(const char *path, const Headers &headers, size_t content_length,
|
||||||
ContentProvider content_provider, const char *content_type);
|
ContentProvider content_provider, const char *content_type);
|
||||||
|
Result Patch(const char *path, const Headers &headers,
|
||||||
|
ContentProviderWithoutLength content_provider,
|
||||||
|
const char *content_type);
|
||||||
|
|
||||||
Result Delete(const char *path);
|
Result Delete(const char *path);
|
||||||
Result Delete(const char *path, const std::string &body,
|
Result Delete(const char *path, const std::string &body,
|
||||||
|
@ -919,6 +936,7 @@ protected:
|
||||||
bool process_request(Stream &strm, const Request &req, Response &res,
|
bool process_request(Stream &strm, const Request &req, Response &res,
|
||||||
bool close_connection);
|
bool close_connection);
|
||||||
|
|
||||||
|
bool write_content_with_provider(Stream &strm, const Request &req);
|
||||||
Error get_last_error() const;
|
Error get_last_error() const;
|
||||||
|
|
||||||
void copy_settings(const ClientImpl &rhs);
|
void copy_settings(const ClientImpl &rhs);
|
||||||
|
@ -997,7 +1015,9 @@ private:
|
||||||
std::unique_ptr<Response> send_with_content_provider(
|
std::unique_ptr<Response> send_with_content_provider(
|
||||||
const char *method, const char *path, const Headers &headers,
|
const char *method, const char *path, const Headers &headers,
|
||||||
const std::string &body, size_t content_length,
|
const std::string &body, size_t content_length,
|
||||||
ContentProvider content_provider, const char *content_type);
|
ContentProvider content_provider,
|
||||||
|
ContentProviderWithoutLength content_provider_without_length,
|
||||||
|
const char *content_type);
|
||||||
|
|
||||||
virtual bool process_socket(Socket &socket,
|
virtual bool process_socket(Socket &socket,
|
||||||
std::function<bool(Stream &strm)> callback);
|
std::function<bool(Stream &strm)> callback);
|
||||||
|
@ -1056,8 +1076,13 @@ public:
|
||||||
const char *content_type);
|
const char *content_type);
|
||||||
Result Post(const char *path, size_t content_length,
|
Result Post(const char *path, size_t content_length,
|
||||||
ContentProvider content_provider, const char *content_type);
|
ContentProvider content_provider, const char *content_type);
|
||||||
|
Result Post(const char *path, ContentProviderWithoutLength content_provider,
|
||||||
|
const char *content_type);
|
||||||
Result Post(const char *path, const Headers &headers, size_t content_length,
|
Result Post(const char *path, const Headers &headers, size_t content_length,
|
||||||
ContentProvider content_provider, const char *content_type);
|
ContentProvider content_provider, const char *content_type);
|
||||||
|
Result Post(const char *path, const Headers &headers,
|
||||||
|
ContentProviderWithoutLength content_provider,
|
||||||
|
const char *content_type);
|
||||||
Result Post(const char *path, const Params ¶ms);
|
Result Post(const char *path, const Params ¶ms);
|
||||||
Result Post(const char *path, const Headers &headers, const Params ¶ms);
|
Result Post(const char *path, const Headers &headers, const Params ¶ms);
|
||||||
Result Post(const char *path, const MultipartFormDataItems &items);
|
Result Post(const char *path, const MultipartFormDataItems &items);
|
||||||
|
@ -1072,8 +1097,13 @@ public:
|
||||||
const char *content_type);
|
const char *content_type);
|
||||||
Result Put(const char *path, size_t content_length,
|
Result Put(const char *path, size_t content_length,
|
||||||
ContentProvider content_provider, const char *content_type);
|
ContentProvider content_provider, const char *content_type);
|
||||||
|
Result Put(const char *path, ContentProviderWithoutLength content_provider,
|
||||||
|
const char *content_type);
|
||||||
Result Put(const char *path, const Headers &headers, size_t content_length,
|
Result Put(const char *path, const Headers &headers, size_t content_length,
|
||||||
ContentProvider content_provider, const char *content_type);
|
ContentProvider content_provider, const char *content_type);
|
||||||
|
Result Put(const char *path, const Headers &headers,
|
||||||
|
ContentProviderWithoutLength content_provider,
|
||||||
|
const char *content_type);
|
||||||
Result Put(const char *path, const Params ¶ms);
|
Result Put(const char *path, const Params ¶ms);
|
||||||
Result Put(const char *path, const Headers &headers, const Params ¶ms);
|
Result Put(const char *path, const Headers &headers, const Params ¶ms);
|
||||||
Result Patch(const char *path, const std::string &body,
|
Result Patch(const char *path, const std::string &body,
|
||||||
|
@ -1082,8 +1112,13 @@ public:
|
||||||
const std::string &body, const char *content_type);
|
const std::string &body, const char *content_type);
|
||||||
Result Patch(const char *path, size_t content_length,
|
Result Patch(const char *path, size_t content_length,
|
||||||
ContentProvider content_provider, const char *content_type);
|
ContentProvider content_provider, const char *content_type);
|
||||||
|
Result Patch(const char *path, ContentProviderWithoutLength content_provider,
|
||||||
|
const char *content_type);
|
||||||
Result Patch(const char *path, const Headers &headers, size_t content_length,
|
Result Patch(const char *path, const Headers &headers, size_t content_length,
|
||||||
ContentProvider content_provider, const char *content_type);
|
ContentProvider content_provider, const char *content_type);
|
||||||
|
Result Patch(const char *path, const Headers &headers,
|
||||||
|
ContentProviderWithoutLength content_provider,
|
||||||
|
const char *content_type);
|
||||||
|
|
||||||
Result Delete(const char *path);
|
Result Delete(const char *path);
|
||||||
Result Delete(const char *path, const std::string &body,
|
Result Delete(const char *path, const std::string &body,
|
||||||
|
@ -2755,17 +2790,20 @@ inline bool write_data(Stream &strm, const char *d, size_t l) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline ssize_t write_content(Stream &strm, ContentProvider content_provider,
|
inline bool write_content(Stream &strm, const ContentProvider &content_provider,
|
||||||
size_t offset, size_t length, T is_shutting_down) {
|
size_t offset, size_t length, T is_shutting_down,
|
||||||
size_t begin_offset = offset;
|
Error &error) {
|
||||||
size_t end_offset = offset + length;
|
size_t end_offset = offset + length;
|
||||||
auto ok = true;
|
auto ok = true;
|
||||||
DataSink data_sink;
|
DataSink data_sink;
|
||||||
|
|
||||||
data_sink.write = [&](const char *d, size_t l) {
|
data_sink.write = [&](const char *d, size_t l) {
|
||||||
if (ok) {
|
if (ok) {
|
||||||
offset += l;
|
if (write_data(strm, d, l)) {
|
||||||
if (!write_data(strm, d, l)) { ok = false; }
|
offset += l;
|
||||||
|
} else {
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2773,18 +2811,33 @@ inline ssize_t write_content(Stream &strm, ContentProvider content_provider,
|
||||||
|
|
||||||
while (offset < end_offset && !is_shutting_down()) {
|
while (offset < end_offset && !is_shutting_down()) {
|
||||||
if (!content_provider(offset, end_offset - offset, data_sink)) {
|
if (!content_provider(offset, end_offset - offset, data_sink)) {
|
||||||
return -1;
|
error = Error::Canceled;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!ok) {
|
||||||
|
error = Error::Write;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
if (!ok) { return -1; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return static_cast<ssize_t>(offset - begin_offset);
|
error = Error::Success;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline ssize_t write_content_without_length(Stream &strm,
|
inline bool write_content(Stream &strm, const ContentProvider &content_provider,
|
||||||
ContentProvider content_provider,
|
size_t offset, size_t length,
|
||||||
T is_shutting_down) {
|
const T &is_shutting_down) {
|
||||||
|
Error error;
|
||||||
|
return write_content(strm, content_provider, offset, length, is_shutting_down,
|
||||||
|
error);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline bool
|
||||||
|
write_content_without_length(Stream &strm,
|
||||||
|
const ContentProvider &content_provider,
|
||||||
|
const T &is_shutting_down) {
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
auto data_available = true;
|
auto data_available = true;
|
||||||
auto ok = true;
|
auto ok = true;
|
||||||
|
@ -2802,20 +2855,18 @@ inline ssize_t write_content_without_length(Stream &strm,
|
||||||
data_sink.is_writable = [&](void) { return ok && strm.is_writable(); };
|
data_sink.is_writable = [&](void) { return ok && strm.is_writable(); };
|
||||||
|
|
||||||
while (data_available && !is_shutting_down()) {
|
while (data_available && !is_shutting_down()) {
|
||||||
if (!content_provider(offset, 0, data_sink)) { return -1; }
|
if (!content_provider(offset, 0, data_sink)) { return false; }
|
||||||
if (!ok) { return -1; }
|
if (!ok) { return false; }
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
return static_cast<ssize_t>(offset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
inline ssize_t write_content_chunked(Stream &strm,
|
inline bool
|
||||||
ContentProvider content_provider,
|
write_content_chunked(Stream &strm, const ContentProvider &content_provider,
|
||||||
T is_shutting_down, U &compressor) {
|
const T &is_shutting_down, U &compressor, Error &error) {
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
auto data_available = true;
|
auto data_available = true;
|
||||||
ssize_t total_written_length = 0;
|
|
||||||
auto ok = true;
|
auto ok = true;
|
||||||
DataSink data_sink;
|
DataSink data_sink;
|
||||||
|
|
||||||
|
@ -2838,9 +2889,7 @@ inline ssize_t write_content_chunked(Stream &strm,
|
||||||
if (!payload.empty()) {
|
if (!payload.empty()) {
|
||||||
// Emit chunked response header and footer for each chunk
|
// Emit chunked response header and footer for each chunk
|
||||||
auto chunk = from_i_to_hex(payload.size()) + "\r\n" + payload + "\r\n";
|
auto chunk = from_i_to_hex(payload.size()) + "\r\n" + payload + "\r\n";
|
||||||
if (write_data(strm, chunk.data(), chunk.size())) {
|
if (!write_data(strm, chunk.data(), chunk.size())) {
|
||||||
total_written_length += chunk.size();
|
|
||||||
} else {
|
|
||||||
ok = false;
|
ok = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2865,18 +2914,14 @@ inline ssize_t write_content_chunked(Stream &strm,
|
||||||
if (!payload.empty()) {
|
if (!payload.empty()) {
|
||||||
// Emit chunked response header and footer for each chunk
|
// Emit chunked response header and footer for each chunk
|
||||||
auto chunk = from_i_to_hex(payload.size()) + "\r\n" + payload + "\r\n";
|
auto chunk = from_i_to_hex(payload.size()) + "\r\n" + payload + "\r\n";
|
||||||
if (write_data(strm, chunk.data(), chunk.size())) {
|
if (!write_data(strm, chunk.data(), chunk.size())) {
|
||||||
total_written_length += chunk.size();
|
|
||||||
} else {
|
|
||||||
ok = false;
|
ok = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const std::string done_marker("0\r\n\r\n");
|
static const std::string done_marker("0\r\n\r\n");
|
||||||
if (write_data(strm, done_marker.data(), done_marker.size())) {
|
if (!write_data(strm, done_marker.data(), done_marker.size())) {
|
||||||
total_written_length += done_marker.size();
|
|
||||||
} else {
|
|
||||||
ok = false;
|
ok = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -2884,11 +2929,27 @@ inline ssize_t write_content_chunked(Stream &strm,
|
||||||
data_sink.is_writable = [&](void) { return ok && strm.is_writable(); };
|
data_sink.is_writable = [&](void) { return ok && strm.is_writable(); };
|
||||||
|
|
||||||
while (data_available && !is_shutting_down()) {
|
while (data_available && !is_shutting_down()) {
|
||||||
if (!content_provider(offset, 0, data_sink)) { return -1; }
|
if (!content_provider(offset, 0, data_sink)) {
|
||||||
if (!ok) { return -1; }
|
error = Error::Canceled;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!ok) {
|
||||||
|
error = Error::Write;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return total_written_length;
|
error = Error::Success;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename U>
|
||||||
|
inline bool write_content_chunked(Stream &strm,
|
||||||
|
const ContentProvider &content_provider,
|
||||||
|
const T &is_shutting_down, U &compressor) {
|
||||||
|
Error error;
|
||||||
|
return write_content_chunked(strm, content_provider, is_shutting_down,
|
||||||
|
compressor, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -2896,7 +2957,7 @@ inline bool redirect(T &cli, const Request &req, Response &res,
|
||||||
const std::string &path) {
|
const std::string &path) {
|
||||||
Request new_req = req;
|
Request new_req = req;
|
||||||
new_req.path = path;
|
new_req.path = path;
|
||||||
new_req.redirect_count -= 1;
|
new_req.redirect_count_ -= 1;
|
||||||
|
|
||||||
if (res.status == 303 && (req.method != "GET" && req.method != "HEAD")) {
|
if (res.status == 303 && (req.method != "GET" && req.method != "HEAD")) {
|
||||||
new_req.method = "GET";
|
new_req.method = "GET";
|
||||||
|
@ -3291,14 +3352,14 @@ inline bool write_multipart_ranges_data(Stream &strm, const Request &req,
|
||||||
Response &res,
|
Response &res,
|
||||||
const std::string &boundary,
|
const std::string &boundary,
|
||||||
const std::string &content_type,
|
const std::string &content_type,
|
||||||
T is_shutting_down) {
|
const T &is_shutting_down) {
|
||||||
return process_multipart_ranges_data(
|
return process_multipart_ranges_data(
|
||||||
req, res, boundary, content_type,
|
req, res, boundary, content_type,
|
||||||
[&](const std::string &token) { strm.write(token); },
|
[&](const std::string &token) { strm.write(token); },
|
||||||
[&](const char *token) { strm.write(token); },
|
[&](const char *token) { strm.write(token); },
|
||||||
[&](size_t offset, size_t length) {
|
[&](size_t offset, size_t length) {
|
||||||
return write_content(strm, res.content_provider_, offset, length,
|
return write_content(strm, res.content_provider_, offset, length,
|
||||||
is_shutting_down) >= 0;
|
is_shutting_down);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3686,7 +3747,7 @@ Response::set_content_provider(size_t in_length, const char *content_type,
|
||||||
content_length_ = in_length;
|
content_length_ = in_length;
|
||||||
content_provider_ = std::move(provider);
|
content_provider_ = std::move(provider);
|
||||||
content_provider_resource_releaser_ = resource_releaser;
|
content_provider_resource_releaser_ = resource_releaser;
|
||||||
is_chunked_content_provider = false;
|
is_chunked_content_provider_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
|
@ -3697,7 +3758,7 @@ Response::set_content_provider(const char *content_type,
|
||||||
content_length_ = 0;
|
content_length_ = 0;
|
||||||
content_provider_ = detail::ContentProviderAdapter(std::move(provider));
|
content_provider_ = detail::ContentProviderAdapter(std::move(provider));
|
||||||
content_provider_resource_releaser_ = resource_releaser;
|
content_provider_resource_releaser_ = resource_releaser;
|
||||||
is_chunked_content_provider = false;
|
is_chunked_content_provider_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Response::set_chunked_content_provider(
|
inline void Response::set_chunked_content_provider(
|
||||||
|
@ -3707,7 +3768,7 @@ inline void Response::set_chunked_content_provider(
|
||||||
content_length_ = 0;
|
content_length_ = 0;
|
||||||
content_provider_ = detail::ContentProviderAdapter(std::move(provider));
|
content_provider_ = detail::ContentProviderAdapter(std::move(provider));
|
||||||
content_provider_resource_releaser_ = resource_releaser;
|
content_provider_resource_releaser_ = resource_releaser;
|
||||||
is_chunked_content_provider = true;
|
is_chunked_content_provider_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rstream implementation
|
// Rstream implementation
|
||||||
|
@ -4131,27 +4192,21 @@ Server::write_content_with_provider(Stream &strm, const Request &req,
|
||||||
|
|
||||||
if (res.content_length_ > 0) {
|
if (res.content_length_ > 0) {
|
||||||
if (req.ranges.empty()) {
|
if (req.ranges.empty()) {
|
||||||
if (detail::write_content(strm, res.content_provider_, 0,
|
return detail::write_content(strm, res.content_provider_, 0,
|
||||||
res.content_length_, is_shutting_down) < 0) {
|
res.content_length_, is_shutting_down);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (req.ranges.size() == 1) {
|
} else if (req.ranges.size() == 1) {
|
||||||
auto offsets =
|
auto offsets =
|
||||||
detail::get_range_offset_and_length(req, res.content_length_, 0);
|
detail::get_range_offset_and_length(req, res.content_length_, 0);
|
||||||
auto offset = offsets.first;
|
auto offset = offsets.first;
|
||||||
auto length = offsets.second;
|
auto length = offsets.second;
|
||||||
if (detail::write_content(strm, res.content_provider_, offset, length,
|
return detail::write_content(strm, res.content_provider_, offset, length,
|
||||||
is_shutting_down) < 0) {
|
is_shutting_down);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (!detail::write_multipart_ranges_data(
|
return detail::write_multipart_ranges_data(
|
||||||
strm, req, res, boundary, content_type, is_shutting_down)) {
|
strm, req, res, boundary, content_type, is_shutting_down);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (res.is_chunked_content_provider) {
|
if (res.is_chunked_content_provider_) {
|
||||||
auto type = detail::encoding_type(req, res);
|
auto type = detail::encoding_type(req, res);
|
||||||
|
|
||||||
std::unique_ptr<detail::compressor> compressor;
|
std::unique_ptr<detail::compressor> compressor;
|
||||||
|
@ -4168,15 +4223,11 @@ Server::write_content_with_provider(Stream &strm, const Request &req,
|
||||||
}
|
}
|
||||||
assert(compressor != nullptr);
|
assert(compressor != nullptr);
|
||||||
|
|
||||||
if (detail::write_content_chunked(strm, res.content_provider_,
|
return detail::write_content_chunked(strm, res.content_provider_,
|
||||||
is_shutting_down, *compressor) < 0) {
|
is_shutting_down, *compressor);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (detail::write_content_without_length(strm, res.content_provider_,
|
return detail::write_content_without_length(strm, res.content_provider_,
|
||||||
is_shutting_down) < 0) {
|
is_shutting_down);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -4531,7 +4582,7 @@ inline void Server::apply_ranges(const Request &req, Response &res,
|
||||||
res.set_header("Content-Length", std::to_string(length));
|
res.set_header("Content-Length", std::to_string(length));
|
||||||
} else {
|
} else {
|
||||||
if (res.content_provider_) {
|
if (res.content_provider_) {
|
||||||
if (res.is_chunked_content_provider) {
|
if (res.is_chunked_content_provider_) {
|
||||||
res.set_header("Transfer-Encoding", "chunked");
|
res.set_header("Transfer-Encoding", "chunked");
|
||||||
if (type == detail::EncodingType::Gzip) {
|
if (type == detail::EncodingType::Gzip) {
|
||||||
res.set_header("Content-Encoding", "gzip");
|
res.set_header("Content-Encoding", "gzip");
|
||||||
|
@ -4943,7 +4994,7 @@ inline bool ClientImpl::handle_request(Stream &strm, const Request &req,
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool ClientImpl::redirect(const Request &req, Response &res) {
|
inline bool ClientImpl::redirect(const Request &req, Response &res) {
|
||||||
if (req.redirect_count == 0) {
|
if (req.redirect_count_ == 0) {
|
||||||
error_ = Error::ExceedRedirectCount;
|
error_ = Error::ExceedRedirectCount;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -4998,6 +5049,30 @@ inline bool ClientImpl::redirect(const Request &req, Response &res) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool ClientImpl::write_content_with_provider(Stream &strm,
|
||||||
|
const Request &req) {
|
||||||
|
auto is_shutting_down = []() { return false; };
|
||||||
|
|
||||||
|
if (req.is_chunked_content_provider_) {
|
||||||
|
// TODO: Brotli suport
|
||||||
|
std::unique_ptr<detail::compressor> compressor;
|
||||||
|
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
|
||||||
|
if (compress_) {
|
||||||
|
compressor = detail::make_unique<detail::gzip_compressor>();
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
compressor = detail::make_unique<detail::nocompressor>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return detail::write_content_chunked(strm, req.content_provider_,
|
||||||
|
is_shutting_down, *compressor, error_);
|
||||||
|
} else {
|
||||||
|
return detail::write_content(strm, req.content_provider_, 0,
|
||||||
|
req.content_length_, is_shutting_down, error_);
|
||||||
|
}
|
||||||
|
} // namespace httplib
|
||||||
|
|
||||||
inline bool ClientImpl::write_request(Stream &strm, const Request &req,
|
inline bool ClientImpl::write_request(Stream &strm, const Request &req,
|
||||||
bool close_connection) {
|
bool close_connection) {
|
||||||
detail::BufferStream bstrm;
|
detail::BufferStream bstrm;
|
||||||
|
@ -5034,9 +5109,11 @@ inline bool ClientImpl::write_request(Stream &strm, const Request &req,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.body.empty()) {
|
if (req.body.empty()) {
|
||||||
if (req.content_provider) {
|
if (req.content_provider_) {
|
||||||
auto length = std::to_string(req.content_length);
|
if (!req.is_chunked_content_provider_) {
|
||||||
headers.emplace("Content-Length", length);
|
auto length = std::to_string(req.content_length_);
|
||||||
|
headers.emplace("Content-Length", length);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (req.method == "POST" || req.method == "PUT" ||
|
if (req.method == "POST" || req.method == "PUT" ||
|
||||||
req.method == "PATCH") {
|
req.method == "PATCH") {
|
||||||
|
@ -5086,35 +5163,7 @@ inline bool ClientImpl::write_request(Stream &strm, const Request &req,
|
||||||
|
|
||||||
// Body
|
// Body
|
||||||
if (req.body.empty()) {
|
if (req.body.empty()) {
|
||||||
if (req.content_provider) {
|
return write_content_with_provider(strm, req);
|
||||||
size_t offset = 0;
|
|
||||||
size_t end_offset = req.content_length;
|
|
||||||
|
|
||||||
bool ok = true;
|
|
||||||
|
|
||||||
DataSink data_sink;
|
|
||||||
data_sink.write = [&](const char *d, size_t l) {
|
|
||||||
if (ok) {
|
|
||||||
if (detail::write_data(strm, d, l)) {
|
|
||||||
offset += l;
|
|
||||||
} else {
|
|
||||||
ok = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
data_sink.is_writable = [&](void) { return ok && strm.is_writable(); };
|
|
||||||
|
|
||||||
while (offset < end_offset) {
|
|
||||||
if (!req.content_provider(offset, end_offset - offset, data_sink)) {
|
|
||||||
error_ = Error::Canceled;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!ok) {
|
|
||||||
error_ = Error::Write;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return detail::write_data(strm, req.body.data(), req.body.size());
|
return detail::write_data(strm, req.body.data(), req.body.size());
|
||||||
}
|
}
|
||||||
|
@ -5125,7 +5174,9 @@ inline bool ClientImpl::write_request(Stream &strm, const Request &req,
|
||||||
inline std::unique_ptr<Response> ClientImpl::send_with_content_provider(
|
inline std::unique_ptr<Response> ClientImpl::send_with_content_provider(
|
||||||
const char *method, const char *path, const Headers &headers,
|
const char *method, const char *path, const Headers &headers,
|
||||||
const std::string &body, size_t content_length,
|
const std::string &body, size_t content_length,
|
||||||
ContentProvider content_provider, const char *content_type) {
|
ContentProvider content_provider,
|
||||||
|
ContentProviderWithoutLength content_provider_without_length,
|
||||||
|
const char *content_type) {
|
||||||
|
|
||||||
Request req;
|
Request req;
|
||||||
req.method = method;
|
req.method = method;
|
||||||
|
@ -5136,14 +5187,19 @@ inline std::unique_ptr<Response> ClientImpl::send_with_content_provider(
|
||||||
if (content_type) { req.headers.emplace("Content-Type", content_type); }
|
if (content_type) { req.headers.emplace("Content-Type", content_type); }
|
||||||
|
|
||||||
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
|
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
|
||||||
if (compress_) {
|
if (compress_) { req.headers.emplace("Content-Encoding", "gzip"); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
|
||||||
|
if (compress_ && !content_provider_without_length) {
|
||||||
|
// TODO: Brotli support
|
||||||
detail::gzip_compressor compressor;
|
detail::gzip_compressor compressor;
|
||||||
|
|
||||||
if (content_provider) {
|
if (content_provider) {
|
||||||
auto ok = true;
|
auto ok = true;
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
|
|
||||||
DataSink data_sink;
|
DataSink data_sink;
|
||||||
|
|
||||||
data_sink.write = [&](const char *data, size_t data_len) {
|
data_sink.write = [&](const char *data, size_t data_len) {
|
||||||
if (ok) {
|
if (ok) {
|
||||||
auto last = offset + data_len == content_length;
|
auto last = offset + data_len == content_length;
|
||||||
|
@ -5161,6 +5217,7 @@ inline std::unique_ptr<Response> ClientImpl::send_with_content_provider(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
data_sink.is_writable = [&](void) { return ok && true; };
|
data_sink.is_writable = [&](void) { return ok && true; };
|
||||||
|
|
||||||
while (ok && offset < content_length) {
|
while (ok && offset < content_length) {
|
||||||
|
@ -5178,14 +5235,19 @@ inline std::unique_ptr<Response> ClientImpl::send_with_content_provider(
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
req.headers.emplace("Content-Encoding", "gzip");
|
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
if (content_provider) {
|
if (content_provider) {
|
||||||
req.content_length = content_length;
|
req.content_length_ = content_length;
|
||||||
req.content_provider = std::move(content_provider);
|
req.content_provider_ = std::move(content_provider);
|
||||||
|
req.is_chunked_content_provider_ = false;
|
||||||
|
} else if (content_provider_without_length) {
|
||||||
|
req.content_length_ = 0;
|
||||||
|
req.content_provider_ = detail::ContentProviderAdapter(
|
||||||
|
std::move(content_provider_without_length));
|
||||||
|
req.is_chunked_content_provider_ = true;
|
||||||
|
req.headers.emplace("Transfer-Encoding", "chunked");
|
||||||
} else {
|
} else {
|
||||||
req.body = body;
|
req.body = body;
|
||||||
}
|
}
|
||||||
|
@ -5208,8 +5270,8 @@ inline bool ClientImpl::process_request(Stream &strm, const Request &req,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.response_handler) {
|
if (req.response_handler_) {
|
||||||
if (!req.response_handler(res)) {
|
if (!req.response_handler_(res)) {
|
||||||
error_ = Error::Canceled;
|
error_ = Error::Canceled;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -5218,10 +5280,10 @@ inline bool ClientImpl::process_request(Stream &strm, const Request &req,
|
||||||
// Body
|
// Body
|
||||||
if (req.method != "HEAD" && req.method != "CONNECT") {
|
if (req.method != "HEAD" && req.method != "CONNECT") {
|
||||||
auto out =
|
auto out =
|
||||||
req.content_receiver
|
req.content_receiver_
|
||||||
? static_cast<ContentReceiverWithProgress>(
|
? static_cast<ContentReceiverWithProgress>(
|
||||||
[&](const char *buf, size_t n, uint64_t off, uint64_t len) {
|
[&](const char *buf, size_t n, uint64_t off, uint64_t len) {
|
||||||
auto ret = req.content_receiver(buf, n, off, len);
|
auto ret = req.content_receiver_(buf, n, off, len);
|
||||||
if (!ret) { error_ = Error::Canceled; }
|
if (!ret) { error_ = Error::Canceled; }
|
||||||
return ret;
|
return ret;
|
||||||
})
|
})
|
||||||
|
@ -5236,8 +5298,8 @@ inline bool ClientImpl::process_request(Stream &strm, const Request &req,
|
||||||
});
|
});
|
||||||
|
|
||||||
auto progress = [&](uint64_t current, uint64_t total) {
|
auto progress = [&](uint64_t current, uint64_t total) {
|
||||||
if (!req.progress) { return true; }
|
if (!req.progress_) { return true; }
|
||||||
auto ret = req.progress(current, total);
|
auto ret = req.progress_(current, total);
|
||||||
if (!ret) { error_ = Error::Canceled; }
|
if (!ret) { error_ = Error::Canceled; }
|
||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
|
@ -5291,7 +5353,7 @@ inline Result ClientImpl::Get(const char *path, const Headers &headers,
|
||||||
req.path = path;
|
req.path = path;
|
||||||
req.headers = default_headers_;
|
req.headers = default_headers_;
|
||||||
req.headers.insert(headers.begin(), headers.end());
|
req.headers.insert(headers.begin(), headers.end());
|
||||||
req.progress = std::move(progress);
|
req.progress_ = std::move(progress);
|
||||||
|
|
||||||
auto res = detail::make_unique<Response>();
|
auto res = detail::make_unique<Response>();
|
||||||
auto ret = send(req, *res);
|
auto ret = send(req, *res);
|
||||||
|
@ -5353,13 +5415,13 @@ inline Result ClientImpl::Get(const char *path, const Headers &headers,
|
||||||
req.path = path;
|
req.path = path;
|
||||||
req.headers = default_headers_;
|
req.headers = default_headers_;
|
||||||
req.headers.insert(headers.begin(), headers.end());
|
req.headers.insert(headers.begin(), headers.end());
|
||||||
req.response_handler = std::move(response_handler);
|
req.response_handler_ = std::move(response_handler);
|
||||||
req.content_receiver =
|
req.content_receiver_ =
|
||||||
[content_receiver](const char *data, size_t data_length,
|
[content_receiver](const char *data, size_t data_length,
|
||||||
uint64_t /*offset*/, uint64_t /*total_length*/) {
|
uint64_t /*offset*/, uint64_t /*total_length*/) {
|
||||||
return content_receiver(data, data_length);
|
return content_receiver(data, data_length);
|
||||||
};
|
};
|
||||||
req.progress = std::move(progress);
|
req.progress_ = std::move(progress);
|
||||||
|
|
||||||
auto res = detail::make_unique<Response>();
|
auto res = detail::make_unique<Response>();
|
||||||
auto ret = send(req, *res);
|
auto ret = send(req, *res);
|
||||||
|
@ -5395,7 +5457,7 @@ inline Result ClientImpl::Post(const char *path, const Headers &headers,
|
||||||
const std::string &body,
|
const std::string &body,
|
||||||
const char *content_type) {
|
const char *content_type) {
|
||||||
auto ret = send_with_content_provider("POST", path, headers, body, 0, nullptr,
|
auto ret = send_with_content_provider("POST", path, headers, body, 0, nullptr,
|
||||||
content_type);
|
nullptr, content_type);
|
||||||
return Result{std::move(ret), get_last_error()};
|
return Result{std::move(ret), get_last_error()};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5410,13 +5472,28 @@ inline Result ClientImpl::Post(const char *path, size_t content_length,
|
||||||
content_type);
|
content_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline Result ClientImpl::Post(const char *path,
|
||||||
|
ContentProviderWithoutLength content_provider,
|
||||||
|
const char *content_type) {
|
||||||
|
return Post(path, Headers(), std::move(content_provider), content_type);
|
||||||
|
}
|
||||||
|
|
||||||
inline Result ClientImpl::Post(const char *path, const Headers &headers,
|
inline Result ClientImpl::Post(const char *path, const Headers &headers,
|
||||||
size_t content_length,
|
size_t content_length,
|
||||||
ContentProvider content_provider,
|
ContentProvider content_provider,
|
||||||
const char *content_type) {
|
const char *content_type) {
|
||||||
auto ret = send_with_content_provider(
|
auto ret = send_with_content_provider(
|
||||||
"POST", path, headers, std::string(), content_length,
|
"POST", path, headers, std::string(), content_length,
|
||||||
std::move(content_provider), content_type);
|
std::move(content_provider), nullptr, content_type);
|
||||||
|
return Result{std::move(ret), get_last_error()};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Result ClientImpl::Post(const char *path, const Headers &headers,
|
||||||
|
ContentProviderWithoutLength content_provider,
|
||||||
|
const char *content_type) {
|
||||||
|
auto ret = send_with_content_provider("POST", path, headers, std::string(), 0,
|
||||||
|
nullptr, std::move(content_provider),
|
||||||
|
content_type);
|
||||||
return Result{std::move(ret), get_last_error()};
|
return Result{std::move(ret), get_last_error()};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5481,7 +5558,7 @@ inline Result ClientImpl::Put(const char *path, const Headers &headers,
|
||||||
const std::string &body,
|
const std::string &body,
|
||||||
const char *content_type) {
|
const char *content_type) {
|
||||||
auto ret = send_with_content_provider("PUT", path, headers, body, 0, nullptr,
|
auto ret = send_with_content_provider("PUT", path, headers, body, 0, nullptr,
|
||||||
content_type);
|
nullptr, content_type);
|
||||||
return Result{std::move(ret), get_last_error()};
|
return Result{std::move(ret), get_last_error()};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5492,13 +5569,28 @@ inline Result ClientImpl::Put(const char *path, size_t content_length,
|
||||||
content_type);
|
content_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline Result ClientImpl::Put(const char *path,
|
||||||
|
ContentProviderWithoutLength content_provider,
|
||||||
|
const char *content_type) {
|
||||||
|
return Put(path, Headers(), std::move(content_provider), content_type);
|
||||||
|
}
|
||||||
|
|
||||||
inline Result ClientImpl::Put(const char *path, const Headers &headers,
|
inline Result ClientImpl::Put(const char *path, const Headers &headers,
|
||||||
size_t content_length,
|
size_t content_length,
|
||||||
ContentProvider content_provider,
|
ContentProvider content_provider,
|
||||||
const char *content_type) {
|
const char *content_type) {
|
||||||
auto ret = send_with_content_provider(
|
auto ret = send_with_content_provider(
|
||||||
"PUT", path, headers, std::string(), content_length,
|
"PUT", path, headers, std::string(), content_length,
|
||||||
std::move(content_provider), content_type);
|
std::move(content_provider), nullptr, content_type);
|
||||||
|
return Result{std::move(ret), get_last_error()};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Result ClientImpl::Put(const char *path, const Headers &headers,
|
||||||
|
ContentProviderWithoutLength content_provider,
|
||||||
|
const char *content_type) {
|
||||||
|
auto ret = send_with_content_provider("PUT", path, headers, std::string(), 0,
|
||||||
|
nullptr, std::move(content_provider),
|
||||||
|
content_type);
|
||||||
return Result{std::move(ret), get_last_error()};
|
return Result{std::move(ret), get_last_error()};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5521,7 +5613,7 @@ inline Result ClientImpl::Patch(const char *path, const Headers &headers,
|
||||||
const std::string &body,
|
const std::string &body,
|
||||||
const char *content_type) {
|
const char *content_type) {
|
||||||
auto ret = send_with_content_provider("PATCH", path, headers, body, 0,
|
auto ret = send_with_content_provider("PATCH", path, headers, body, 0,
|
||||||
nullptr, content_type);
|
nullptr, nullptr, content_type);
|
||||||
return Result{std::move(ret), get_last_error()};
|
return Result{std::move(ret), get_last_error()};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5532,13 +5624,28 @@ inline Result ClientImpl::Patch(const char *path, size_t content_length,
|
||||||
content_type);
|
content_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline Result ClientImpl::Patch(const char *path,
|
||||||
|
ContentProviderWithoutLength content_provider,
|
||||||
|
const char *content_type) {
|
||||||
|
return Patch(path, Headers(), std::move(content_provider), content_type);
|
||||||
|
}
|
||||||
|
|
||||||
inline Result ClientImpl::Patch(const char *path, const Headers &headers,
|
inline Result ClientImpl::Patch(const char *path, const Headers &headers,
|
||||||
size_t content_length,
|
size_t content_length,
|
||||||
ContentProvider content_provider,
|
ContentProvider content_provider,
|
||||||
const char *content_type) {
|
const char *content_type) {
|
||||||
auto ret = send_with_content_provider(
|
auto ret = send_with_content_provider(
|
||||||
"PATCH", path, headers, std::string(), content_length,
|
"PATCH", path, headers, std::string(), content_length,
|
||||||
std::move(content_provider), content_type);
|
std::move(content_provider), nullptr, content_type);
|
||||||
|
return Result{std::move(ret), get_last_error()};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Result ClientImpl::Patch(const char *path, const Headers &headers,
|
||||||
|
ContentProviderWithoutLength content_provider,
|
||||||
|
const char *content_type) {
|
||||||
|
auto ret = send_with_content_provider("PATCH", path, headers, std::string(),
|
||||||
|
0, nullptr, std::move(content_provider),
|
||||||
|
content_type);
|
||||||
return Result{std::move(ret), get_last_error()};
|
return Result{std::move(ret), get_last_error()};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6500,6 +6607,11 @@ inline Result Client::Post(const char *path, size_t content_length,
|
||||||
return cli_->Post(path, content_length, std::move(content_provider),
|
return cli_->Post(path, content_length, std::move(content_provider),
|
||||||
content_type);
|
content_type);
|
||||||
}
|
}
|
||||||
|
inline Result Client::Post(const char *path,
|
||||||
|
ContentProviderWithoutLength content_provider,
|
||||||
|
const char *content_type) {
|
||||||
|
return cli_->Post(path, std::move(content_provider), content_type);
|
||||||
|
}
|
||||||
inline Result Client::Post(const char *path, const Headers &headers,
|
inline Result Client::Post(const char *path, const Headers &headers,
|
||||||
size_t content_length,
|
size_t content_length,
|
||||||
ContentProvider content_provider,
|
ContentProvider content_provider,
|
||||||
|
@ -6507,6 +6619,11 @@ inline Result Client::Post(const char *path, const Headers &headers,
|
||||||
return cli_->Post(path, headers, content_length, std::move(content_provider),
|
return cli_->Post(path, headers, content_length, std::move(content_provider),
|
||||||
content_type);
|
content_type);
|
||||||
}
|
}
|
||||||
|
inline Result Client::Post(const char *path, const Headers &headers,
|
||||||
|
ContentProviderWithoutLength content_provider,
|
||||||
|
const char *content_type) {
|
||||||
|
return cli_->Post(path, headers, std::move(content_provider), content_type);
|
||||||
|
}
|
||||||
inline Result Client::Post(const char *path, const Params ¶ms) {
|
inline Result Client::Post(const char *path, const Params ¶ms) {
|
||||||
return cli_->Post(path, params);
|
return cli_->Post(path, params);
|
||||||
}
|
}
|
||||||
|
@ -6542,6 +6659,11 @@ inline Result Client::Put(const char *path, size_t content_length,
|
||||||
return cli_->Put(path, content_length, std::move(content_provider),
|
return cli_->Put(path, content_length, std::move(content_provider),
|
||||||
content_type);
|
content_type);
|
||||||
}
|
}
|
||||||
|
inline Result Client::Put(const char *path,
|
||||||
|
ContentProviderWithoutLength content_provider,
|
||||||
|
const char *content_type) {
|
||||||
|
return cli_->Put(path, std::move(content_provider), content_type);
|
||||||
|
}
|
||||||
inline Result Client::Put(const char *path, const Headers &headers,
|
inline Result Client::Put(const char *path, const Headers &headers,
|
||||||
size_t content_length,
|
size_t content_length,
|
||||||
ContentProvider content_provider,
|
ContentProvider content_provider,
|
||||||
|
@ -6549,6 +6671,11 @@ inline Result Client::Put(const char *path, const Headers &headers,
|
||||||
return cli_->Put(path, headers, content_length, std::move(content_provider),
|
return cli_->Put(path, headers, content_length, std::move(content_provider),
|
||||||
content_type);
|
content_type);
|
||||||
}
|
}
|
||||||
|
inline Result Client::Put(const char *path, const Headers &headers,
|
||||||
|
ContentProviderWithoutLength content_provider,
|
||||||
|
const char *content_type) {
|
||||||
|
return cli_->Put(path, headers, std::move(content_provider), content_type);
|
||||||
|
}
|
||||||
inline Result Client::Put(const char *path, const Params ¶ms) {
|
inline Result Client::Put(const char *path, const Params ¶ms) {
|
||||||
return cli_->Put(path, params);
|
return cli_->Put(path, params);
|
||||||
}
|
}
|
||||||
|
@ -6570,6 +6697,11 @@ inline Result Client::Patch(const char *path, size_t content_length,
|
||||||
return cli_->Patch(path, content_length, std::move(content_provider),
|
return cli_->Patch(path, content_length, std::move(content_provider),
|
||||||
content_type);
|
content_type);
|
||||||
}
|
}
|
||||||
|
inline Result Client::Patch(const char *path,
|
||||||
|
ContentProviderWithoutLength content_provider,
|
||||||
|
const char *content_type) {
|
||||||
|
return cli_->Patch(path, std::move(content_provider), content_type);
|
||||||
|
}
|
||||||
inline Result Client::Patch(const char *path, const Headers &headers,
|
inline Result Client::Patch(const char *path, const Headers &headers,
|
||||||
size_t content_length,
|
size_t content_length,
|
||||||
ContentProvider content_provider,
|
ContentProvider content_provider,
|
||||||
|
@ -6577,6 +6709,11 @@ inline Result Client::Patch(const char *path, const Headers &headers,
|
||||||
return cli_->Patch(path, headers, content_length, std::move(content_provider),
|
return cli_->Patch(path, headers, content_length, std::move(content_provider),
|
||||||
content_type);
|
content_type);
|
||||||
}
|
}
|
||||||
|
inline Result Client::Patch(const char *path, const Headers &headers,
|
||||||
|
ContentProviderWithoutLength content_provider,
|
||||||
|
const char *content_type) {
|
||||||
|
return cli_->Patch(path, headers, std::move(content_provider), content_type);
|
||||||
|
}
|
||||||
inline Result Client::Delete(const char *path) { return cli_->Delete(path); }
|
inline Result Client::Delete(const char *path) { return cli_->Delete(path); }
|
||||||
inline Result Client::Delete(const char *path, const std::string &body,
|
inline Result Client::Delete(const char *path, const std::string &body,
|
||||||
const char *content_type) {
|
const char *content_type) {
|
||||||
|
|
56
test/test.cc
56
test/test.cc
|
@ -2217,6 +2217,31 @@ TEST_F(ServerTest, PostWithContentProviderAbort) {
|
||||||
EXPECT_EQ(Error::Canceled, res.error());
|
EXPECT_EQ(Error::Canceled, res.error());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ServerTest, PutWithContentProviderWithoutLength) {
|
||||||
|
auto res = cli_.Put(
|
||||||
|
"/put",
|
||||||
|
[](size_t /*offset*/, DataSink &sink) {
|
||||||
|
EXPECT_TRUE(sink.is_writable());
|
||||||
|
sink.os << "PUT";
|
||||||
|
sink.done();
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
"text/plain");
|
||||||
|
|
||||||
|
ASSERT_TRUE(res);
|
||||||
|
EXPECT_EQ(200, res->status);
|
||||||
|
EXPECT_EQ("PUT", res->body);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ServerTest, PostWithContentProviderWithoutLengthAbort) {
|
||||||
|
auto res = cli_.Post(
|
||||||
|
"/post", [](size_t /*offset*/, DataSink & /*sink*/) { return false; },
|
||||||
|
"text/plain");
|
||||||
|
|
||||||
|
ASSERT_TRUE(!res);
|
||||||
|
EXPECT_EQ(Error::Canceled, res.error());
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
|
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
|
||||||
TEST_F(ServerTest, PutWithContentProviderWithGzip) {
|
TEST_F(ServerTest, PutWithContentProviderWithGzip) {
|
||||||
cli_.set_compress(true);
|
cli_.set_compress(true);
|
||||||
|
@ -2247,6 +2272,33 @@ TEST_F(ServerTest, PostWithContentProviderWithGzipAbort) {
|
||||||
EXPECT_EQ(Error::Canceled, res.error());
|
EXPECT_EQ(Error::Canceled, res.error());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ServerTest, PutWithContentProviderWithoutLengthWithGzip) {
|
||||||
|
cli_.set_compress(true);
|
||||||
|
auto res = cli_.Put(
|
||||||
|
"/put",
|
||||||
|
[](size_t /*offset*/, DataSink &sink) {
|
||||||
|
EXPECT_TRUE(sink.is_writable());
|
||||||
|
sink.os << "PUT";
|
||||||
|
sink.done();
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
"text/plain");
|
||||||
|
|
||||||
|
ASSERT_TRUE(res);
|
||||||
|
EXPECT_EQ(200, res->status);
|
||||||
|
EXPECT_EQ("PUT", res->body);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ServerTest, PostWithContentProviderWithoutLengthWithGzipAbort) {
|
||||||
|
cli_.set_compress(true);
|
||||||
|
auto res = cli_.Post(
|
||||||
|
"/post", [](size_t /*offset*/, DataSink & /*sink*/) { return false; },
|
||||||
|
"text/plain");
|
||||||
|
|
||||||
|
ASSERT_TRUE(!res);
|
||||||
|
EXPECT_EQ(Error::Canceled, res.error());
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(ServerTest, PutLargeFileWithGzip) {
|
TEST_F(ServerTest, PutLargeFileWithGzip) {
|
||||||
cli_.set_compress(true);
|
cli_.set_compress(true);
|
||||||
auto res = cli_.Put("/put-large", LARGE_DATA, "text/plain");
|
auto res = cli_.Put("/put-large", LARGE_DATA, "text/plain");
|
||||||
|
@ -3627,8 +3679,8 @@ TEST(YahooRedirectTest3, NewResultInterface) {
|
||||||
#ifdef CPPHTTPLIB_BROTLI_SUPPORT
|
#ifdef CPPHTTPLIB_BROTLI_SUPPORT
|
||||||
TEST(DecodeWithChunkedEncoding, BrotliEncoding) {
|
TEST(DecodeWithChunkedEncoding, BrotliEncoding) {
|
||||||
Client cli("https://cdnjs.cloudflare.com");
|
Client cli("https://cdnjs.cloudflare.com");
|
||||||
auto res = cli.Get("/ajax/libs/jquery/3.5.1/jquery.js",
|
auto res =
|
||||||
{{"Accept-Encoding", "br"}});
|
cli.Get("/ajax/libs/jquery/3.5.1/jquery.js", {{"Accept-Encoding", "br"}});
|
||||||
|
|
||||||
ASSERT_TRUE(res);
|
ASSERT_TRUE(res);
|
||||||
EXPECT_EQ(200, res->status);
|
EXPECT_EQ(200, res->status);
|
||||||
|
|
Loading…
Reference in a new issue