mirror of
https://github.com/yhirose/cpp-httplib
synced 2026-06-08 18:30:49 +00:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d2c7b447d5 | |||
| 72b20c08da | |||
| afd6d5f9dc | |||
| e5827ad16f | |||
| 5324b3d661 | |||
| 151ccba57e | |||
| 69a28d50f6 |
@@ -119,15 +119,14 @@ svr.Get("/stream", [&](const Request &req, Response &res) {
|
||||
svr.Post("/content_receiver",
|
||||
[&](const Request &req, Response &res, const ContentReader &content_reader) {
|
||||
if (req.is_multipart_form_data()) {
|
||||
MultipartFiles files;
|
||||
MultipartFormDataItems files;
|
||||
content_reader(
|
||||
[&](const std::string &name, const MultipartFile &file) {
|
||||
files.emplace(name, file);
|
||||
[&](const MultipartFormData &file) {
|
||||
files.push_back(file);
|
||||
return true;
|
||||
},
|
||||
[&](const std::string &name, const char *data, size_t data_length) {
|
||||
auto &file = files.find(name)->second;
|
||||
file.content.append(data, data_length);
|
||||
[&](const char *data, size_t data_length) {
|
||||
files.back().content.append(data, data_length);
|
||||
return true;
|
||||
});
|
||||
} else {
|
||||
@@ -388,7 +387,7 @@ httplib::Client cli("yahoo.com");
|
||||
auto res = cli.Get("/");
|
||||
res->status; // 301
|
||||
|
||||
cli.follow_location(true);
|
||||
cli.set_follow_location(true);
|
||||
res = cli.Get("/");
|
||||
res->status; // 200
|
||||
```
|
||||
@@ -424,6 +423,13 @@ The server applies gzip compression to the following MIME type contents:
|
||||
* application/xml
|
||||
* application/xhtml+xml
|
||||
|
||||
### Compress content on client
|
||||
|
||||
```c++
|
||||
cli.set_compress(true);
|
||||
res = cli.Post("/resource/foo", "...", "text/plain");
|
||||
```
|
||||
|
||||
NOTE
|
||||
----
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ string dump_headers(const Headers &headers) {
|
||||
return s;
|
||||
}
|
||||
|
||||
string dump_multipart_files(const MultipartFiles &files) {
|
||||
string dump_multipart_files(const MultipartFormDataMap &files) {
|
||||
string s;
|
||||
char buf[BUFSIZ];
|
||||
|
||||
|
||||
@@ -211,13 +211,6 @@ using Progress = std::function<bool(uint64_t current, uint64_t total)>;
|
||||
struct Response;
|
||||
using ResponseHandler = std::function<bool(const Response &response)>;
|
||||
|
||||
struct MultipartFile {
|
||||
std::string filename;
|
||||
std::string content_type;
|
||||
std::string content;
|
||||
};
|
||||
using MultipartFiles = std::multimap<std::string, MultipartFile>;
|
||||
|
||||
struct MultipartFormData {
|
||||
std::string name;
|
||||
std::string content;
|
||||
@@ -225,25 +218,23 @@ struct MultipartFormData {
|
||||
std::string content_type;
|
||||
};
|
||||
using MultipartFormDataItems = std::vector<MultipartFormData>;
|
||||
using MultipartFormDataMap = std::multimap<std::string, MultipartFormData>;
|
||||
|
||||
using ContentReceiver =
|
||||
std::function<bool(const char *data, size_t data_length)>;
|
||||
|
||||
using MultipartContentHeader =
|
||||
std::function<bool(const std::string &name, const MultipartFile &file)>;
|
||||
|
||||
using MultipartContentReceiver =
|
||||
std::function<bool(const std::string& name, const char *data, size_t data_length)>;
|
||||
std::function<bool(const MultipartFormData &file)>;
|
||||
|
||||
class ContentReader {
|
||||
public:
|
||||
using Reader = std::function<bool(ContentReceiver receiver)>;
|
||||
using MultipartReader = std::function<bool(MultipartContentHeader header, MultipartContentReceiver receiver)>;
|
||||
using MultipartReader = std::function<bool(MultipartContentHeader header, ContentReceiver receiver)>;
|
||||
|
||||
ContentReader(Reader reader, MultipartReader muitlpart_reader)
|
||||
: reader_(reader), muitlpart_reader_(muitlpart_reader) {}
|
||||
|
||||
bool operator()(MultipartContentHeader header, MultipartContentReceiver receiver) const {
|
||||
bool operator()(MultipartContentHeader header, ContentReceiver receiver) const {
|
||||
return muitlpart_reader_(header, receiver);
|
||||
}
|
||||
|
||||
@@ -268,7 +259,7 @@ struct Request {
|
||||
std::string version;
|
||||
std::string target;
|
||||
Params params;
|
||||
MultipartFiles files;
|
||||
MultipartFormDataMap files;
|
||||
Ranges ranges;
|
||||
Match matches;
|
||||
|
||||
@@ -295,7 +286,7 @@ struct Request {
|
||||
bool is_multipart_form_data() const;
|
||||
|
||||
bool has_file(const char *key) const;
|
||||
MultipartFile get_file_value(const char *key) const;
|
||||
MultipartFormData get_file_value(const char *key) const;
|
||||
|
||||
// private members...
|
||||
size_t content_length;
|
||||
@@ -596,12 +587,12 @@ private:
|
||||
Request &req, Response &res,
|
||||
ContentReceiver receiver,
|
||||
MultipartContentHeader multipart_header,
|
||||
MultipartContentReceiver multipart_receiver);
|
||||
ContentReceiver multipart_receiver);
|
||||
bool read_content_core(Stream &strm, bool last_connection,
|
||||
Request &req, Response &res,
|
||||
ContentReceiver receiver,
|
||||
MultipartContentHeader mulitpart_header,
|
||||
MultipartContentReceiver multipart_receiver);
|
||||
ContentReceiver multipart_receiver);
|
||||
|
||||
virtual bool process_and_close_socket(socket_t sock);
|
||||
|
||||
@@ -666,78 +657,63 @@ public:
|
||||
std::shared_ptr<Response> Head(const char *path, const Headers &headers);
|
||||
|
||||
std::shared_ptr<Response> Post(const char *path, const std::string &body,
|
||||
const char *content_type,
|
||||
bool compress = false);
|
||||
const char *content_type);
|
||||
|
||||
std::shared_ptr<Response> Post(const char *path, const Headers &headers,
|
||||
const std::string &body,
|
||||
const char *content_type,
|
||||
bool compress = false);
|
||||
const char *content_type);
|
||||
|
||||
std::shared_ptr<Response> Post(const char *path, size_t content_length,
|
||||
ContentProvider content_provider,
|
||||
const char *content_type,
|
||||
bool compress = false);
|
||||
const char *content_type);
|
||||
|
||||
std::shared_ptr<Response> Post(const char *path, const Headers &headers,
|
||||
size_t content_length,
|
||||
ContentProvider content_provider,
|
||||
const char *content_type,
|
||||
bool compress = false);
|
||||
const char *content_type);
|
||||
|
||||
std::shared_ptr<Response> Post(const char *path, const Params ¶ms,
|
||||
bool compress = false);
|
||||
std::shared_ptr<Response> Post(const char *path, const Params ¶ms);
|
||||
|
||||
std::shared_ptr<Response> Post(const char *path, const Headers &headers,
|
||||
const Params ¶ms, bool compress = false);
|
||||
const Params ¶ms);
|
||||
|
||||
std::shared_ptr<Response> Post(const char *path,
|
||||
const MultipartFormDataItems &items,
|
||||
bool compress = false);
|
||||
const MultipartFormDataItems &items);
|
||||
|
||||
std::shared_ptr<Response> Post(const char *path, const Headers &headers,
|
||||
const MultipartFormDataItems &items,
|
||||
bool compress = false);
|
||||
const MultipartFormDataItems &items);
|
||||
|
||||
std::shared_ptr<Response> Put(const char *path, const std::string &body,
|
||||
const char *content_type,
|
||||
bool compress = false);
|
||||
const char *content_type);
|
||||
|
||||
std::shared_ptr<Response> Put(const char *path, const Headers &headers,
|
||||
const std::string &body,
|
||||
const char *content_type,
|
||||
bool compress = false);
|
||||
const char *content_type);
|
||||
|
||||
std::shared_ptr<Response> Put(const char *path, size_t content_length,
|
||||
ContentProvider content_provider,
|
||||
const char *content_type,
|
||||
bool compress = false);
|
||||
const char *content_type);
|
||||
|
||||
std::shared_ptr<Response> Put(const char *path, const Headers &headers,
|
||||
size_t content_length,
|
||||
ContentProvider content_provider,
|
||||
const char *content_type,
|
||||
bool compress = false);
|
||||
const char *content_type);
|
||||
|
||||
std::shared_ptr<Response> Patch(const char *path, const std::string &body,
|
||||
const char *content_type,
|
||||
bool compress = false);
|
||||
const char *content_type);
|
||||
|
||||
std::shared_ptr<Response> Patch(const char *path, const Headers &headers,
|
||||
const std::string &body,
|
||||
const char *content_type,
|
||||
bool compress = false);
|
||||
const char *content_type);
|
||||
|
||||
std::shared_ptr<Response> Patch(const char *path, size_t content_length,
|
||||
ContentProvider content_provider,
|
||||
const char *content_type,
|
||||
bool compress = false);
|
||||
const char *content_type);
|
||||
|
||||
std::shared_ptr<Response> Patch(const char *path, const Headers &headers,
|
||||
size_t content_length,
|
||||
ContentProvider content_provider,
|
||||
const char *content_type,
|
||||
bool compress = false);
|
||||
const char *content_type);
|
||||
|
||||
std::shared_ptr<Response> Delete(const char *path);
|
||||
|
||||
@@ -763,10 +739,12 @@ public:
|
||||
|
||||
void set_read_timeout(time_t sec, time_t usec);
|
||||
|
||||
void follow_location(bool on);
|
||||
|
||||
void set_auth(const char *username, const char *password);
|
||||
|
||||
void set_follow_location(bool on);
|
||||
|
||||
void set_compress(bool on);
|
||||
|
||||
protected:
|
||||
bool process_request(Stream &strm, const Request &req, Response &res,
|
||||
bool last_connection, bool &connection_close);
|
||||
@@ -778,9 +756,10 @@ protected:
|
||||
size_t keep_alive_max_count_;
|
||||
time_t read_timeout_sec_;
|
||||
time_t read_timeout_usec_;
|
||||
size_t follow_location_;
|
||||
bool follow_location_;
|
||||
std::string username_;
|
||||
std::string password_;
|
||||
bool compress_;
|
||||
|
||||
private:
|
||||
socket_t create_client_socket() const;
|
||||
@@ -793,7 +772,7 @@ private:
|
||||
const Headers &headers, const std::string &body,
|
||||
size_t content_length,
|
||||
ContentProvider content_provider,
|
||||
const char *content_type, bool compress);
|
||||
const char *content_type);
|
||||
|
||||
virtual bool process_and_close_socket(
|
||||
socket_t sock, size_t request_count,
|
||||
@@ -912,6 +891,8 @@ private:
|
||||
};
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* Implementation
|
||||
*/
|
||||
@@ -2013,8 +1994,9 @@ public:
|
||||
case 2: { // Headers
|
||||
auto pos = buf_.find(crlf_);
|
||||
while (pos != std::string::npos) {
|
||||
// Empty line
|
||||
if (pos == 0) {
|
||||
if (!header_callback(name_, file_)) {
|
||||
if (!header_callback(file_)) {
|
||||
is_valid_ = false;
|
||||
is_done_ = false;
|
||||
return false;
|
||||
@@ -2031,7 +2013,7 @@ public:
|
||||
if (std::regex_match(header, m, re_content_type)) {
|
||||
file_.content_type = m[1];
|
||||
} else if (std::regex_match(header, m, re_content_disposition)) {
|
||||
name_ = m[1];
|
||||
file_.name = m[1];
|
||||
file_.filename = m[2];
|
||||
}
|
||||
}
|
||||
@@ -2049,7 +2031,7 @@ public:
|
||||
if (pos == std::string::npos) {
|
||||
pos = buf_.size();
|
||||
}
|
||||
if (!content_callback(name_, buf_.data(), pos)) {
|
||||
if (!content_callback(buf_.data(), pos)) {
|
||||
is_valid_ = false;
|
||||
is_done_ = false;
|
||||
return false;
|
||||
@@ -2065,7 +2047,7 @@ public:
|
||||
|
||||
auto pos = buf_.find(pattern);
|
||||
if (pos != std::string::npos) {
|
||||
if (!content_callback(name_, buf_.data(), pos)) {
|
||||
if (!content_callback(buf_.data(), pos)) {
|
||||
is_valid_ = false;
|
||||
is_done_ = false;
|
||||
return false;
|
||||
@@ -2075,7 +2057,7 @@ public:
|
||||
buf_.erase(0, pos + pattern.size());
|
||||
state_ = 4;
|
||||
} else {
|
||||
if (!content_callback(name_, buf_.data(), pattern.size())) {
|
||||
if (!content_callback(buf_.data(), pattern.size())) {
|
||||
is_valid_ = false;
|
||||
is_done_ = false;
|
||||
return false;
|
||||
@@ -2120,7 +2102,7 @@ public:
|
||||
|
||||
private:
|
||||
void clear_file_info() {
|
||||
name_.clear();
|
||||
file_.name.clear();
|
||||
file_.filename.clear();
|
||||
file_.content_type.clear();
|
||||
}
|
||||
@@ -2134,8 +2116,7 @@ private:
|
||||
size_t is_valid_ = false;
|
||||
size_t is_done_ = false;
|
||||
size_t off_ = 0;
|
||||
std::string name_;
|
||||
MultipartFile file_;
|
||||
MultipartFormData file_;
|
||||
};
|
||||
|
||||
inline std::string to_lower(const char *beg, const char *end) {
|
||||
@@ -2304,11 +2285,11 @@ inline std::string message_digest(const std::string &s, Init init,
|
||||
size_t digest_length) {
|
||||
using namespace std;
|
||||
|
||||
unsigned char md[digest_length];
|
||||
std::vector<unsigned char> md(digest_length, 0);
|
||||
CTX ctx;
|
||||
init(&ctx);
|
||||
update(&ctx, s.data(), s.size());
|
||||
final(md, &ctx);
|
||||
final(md.data(), &ctx);
|
||||
|
||||
stringstream ss;
|
||||
for (auto c : md) {
|
||||
@@ -2510,10 +2491,10 @@ inline bool Request::has_file(const char *key) const {
|
||||
return files.find(key) != files.end();
|
||||
}
|
||||
|
||||
inline MultipartFile Request::get_file_value(const char *key) const {
|
||||
inline MultipartFormData Request::get_file_value(const char *key) const {
|
||||
auto it = files.find(key);
|
||||
if (it != files.end()) { return it->second; }
|
||||
return MultipartFile();
|
||||
return MultipartFormData();
|
||||
}
|
||||
|
||||
// Response implementation
|
||||
@@ -2975,6 +2956,7 @@ Server::write_content_with_provider(Stream &strm, const Request &req,
|
||||
|
||||
inline bool Server::read_content(Stream &strm, bool last_connection,
|
||||
Request &req, Response &res) {
|
||||
MultipartFormDataMap::iterator cur;
|
||||
auto ret = read_content_core(strm, last_connection, req, res,
|
||||
// Regular
|
||||
[&](const char *buf, size_t n) {
|
||||
@@ -2983,14 +2965,12 @@ inline bool Server::read_content(Stream &strm, bool last_connection,
|
||||
return true;
|
||||
},
|
||||
// Multipart
|
||||
[&](const std::string &name, const MultipartFile &file) {
|
||||
req.files.emplace(name, file);
|
||||
[&](const MultipartFormData &file) {
|
||||
cur = req.files.emplace(file.name, file);
|
||||
return true;
|
||||
},
|
||||
[&](const std::string &name, const char *buf, size_t n) {
|
||||
// TODO: handle elements with a same key
|
||||
auto it = req.files.find(name);
|
||||
auto &content = it->second.content;
|
||||
[&](const char *buf, size_t n) {
|
||||
auto &content = cur->second.content;
|
||||
if (content.size() + n > content.max_size()) { return false; }
|
||||
content.append(buf, n);
|
||||
return true;
|
||||
@@ -3010,7 +2990,7 @@ Server::read_content_with_content_receiver(Stream &strm, bool last_connection,
|
||||
Request &req, Response &res,
|
||||
ContentReceiver receiver,
|
||||
MultipartContentHeader multipart_header,
|
||||
MultipartContentReceiver multipart_receiver) {
|
||||
ContentReceiver multipart_receiver) {
|
||||
return read_content_core(strm, last_connection, req, res,
|
||||
receiver, multipart_header, multipart_receiver);
|
||||
}
|
||||
@@ -3020,7 +3000,7 @@ Server::read_content_core(Stream &strm, bool last_connection,
|
||||
Request &req, Response &res,
|
||||
ContentReceiver receiver,
|
||||
MultipartContentHeader mulitpart_header,
|
||||
MultipartContentReceiver multipart_receiver) {
|
||||
ContentReceiver multipart_receiver) {
|
||||
detail::MultipartFormDataParser multipart_form_data_parser;
|
||||
ContentReceiver out;
|
||||
|
||||
@@ -3183,7 +3163,7 @@ inline bool Server::routing(Request &req, Response &res, Stream &strm,
|
||||
return read_content_with_content_receiver(strm, last_connection, req, res,
|
||||
receiver, nullptr, nullptr);
|
||||
},
|
||||
[&](MultipartContentHeader header, MultipartContentReceiver receiver) {
|
||||
[&](MultipartContentHeader header, ContentReceiver receiver) {
|
||||
return read_content_with_content_receiver(strm, last_connection, req, res,
|
||||
nullptr, header, receiver);
|
||||
}
|
||||
@@ -3339,7 +3319,8 @@ inline Client::Client(const char *host, int port, time_t timeout_sec)
|
||||
keep_alive_max_count_(CPPHTTPLIB_KEEPALIVE_MAX_COUNT),
|
||||
read_timeout_sec_(CPPHTTPLIB_READ_TIMEOUT_SECOND),
|
||||
read_timeout_usec_(CPPHTTPLIB_READ_TIMEOUT_USECOND),
|
||||
follow_location_(false) {}
|
||||
follow_location_(false),
|
||||
compress_(false) {}
|
||||
|
||||
inline Client::~Client() {}
|
||||
|
||||
@@ -3483,14 +3464,14 @@ inline bool Client::redirect(const Request &req, Response &res) {
|
||||
if (next_scheme == "https") {
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
SSLClient cli(next_host.c_str());
|
||||
cli.follow_location(true);
|
||||
cli.set_follow_location(true);
|
||||
return detail::redirect(cli, req, res, next_path);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
} else {
|
||||
Client cli(next_host.c_str());
|
||||
cli.follow_location(true);
|
||||
cli.set_follow_location(true);
|
||||
return detail::redirect(cli, req, res, next_path);
|
||||
}
|
||||
}
|
||||
@@ -3578,11 +3559,7 @@ inline void Client::write_request(Stream &strm, const Request &req,
|
||||
inline std::shared_ptr<Response> Client::send_with_content_provider(
|
||||
const char *method, const char *path, const Headers &headers,
|
||||
const std::string &body, size_t content_length,
|
||||
ContentProvider content_provider, const char *content_type, bool compress) {
|
||||
#ifndef CPPHTTPLIB_ZLIB_SUPPORT
|
||||
(void)compress;
|
||||
#endif
|
||||
|
||||
ContentProvider content_provider, const char *content_type) {
|
||||
Request req;
|
||||
req.method = method;
|
||||
req.headers = headers;
|
||||
@@ -3591,7 +3568,7 @@ inline std::shared_ptr<Response> Client::send_with_content_provider(
|
||||
req.headers.emplace("Content-Type", content_type);
|
||||
|
||||
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
|
||||
if (compress) {
|
||||
if (compress_) {
|
||||
if (content_provider) {
|
||||
size_t offset = 0;
|
||||
while (offset < content_length) {
|
||||
@@ -3779,45 +3756,40 @@ inline std::shared_ptr<Response> Client::Head(const char *path,
|
||||
|
||||
inline std::shared_ptr<Response> Client::Post(const char *path,
|
||||
const std::string &body,
|
||||
const char *content_type,
|
||||
bool compress) {
|
||||
return Post(path, Headers(), body, content_type, compress);
|
||||
const char *content_type) {
|
||||
return Post(path, Headers(), body, content_type);
|
||||
}
|
||||
|
||||
inline std::shared_ptr<Response>
|
||||
Client::Post(const char *path, const Headers &headers, const std::string &body,
|
||||
const char *content_type, bool compress) {
|
||||
const char *content_type) {
|
||||
return send_with_content_provider("POST", path, headers, body, 0, nullptr,
|
||||
content_type, compress);
|
||||
content_type);
|
||||
}
|
||||
|
||||
inline std::shared_ptr<Response>
|
||||
Client::Post(const char *path, const Params ¶ms, bool compress) {
|
||||
return Post(path, Headers(), params, compress);
|
||||
Client::Post(const char *path, const Params ¶ms) {
|
||||
return Post(path, Headers(), params);
|
||||
}
|
||||
|
||||
inline std::shared_ptr<Response> Client::Post(const char *path,
|
||||
size_t content_length,
|
||||
ContentProvider content_provider,
|
||||
const char *content_type,
|
||||
bool compress) {
|
||||
return Post(path, Headers(), content_length, content_provider, content_type,
|
||||
compress);
|
||||
const char *content_type) {
|
||||
return Post(path, Headers(), content_length, content_provider, content_type);
|
||||
}
|
||||
|
||||
inline std::shared_ptr<Response>
|
||||
Client::Post(const char *path, const Headers &headers, size_t content_length,
|
||||
ContentProvider content_provider, const char *content_type,
|
||||
bool compress) {
|
||||
ContentProvider content_provider, const char *content_type) {
|
||||
return send_with_content_provider("POST", path, headers, std::string(),
|
||||
content_length, content_provider,
|
||||
content_type, compress);
|
||||
content_type);
|
||||
}
|
||||
|
||||
inline std::shared_ptr<Response> Client::Post(const char *path,
|
||||
const Headers &headers,
|
||||
const Params ¶ms,
|
||||
bool compress) {
|
||||
const Params ¶ms) {
|
||||
std::string query;
|
||||
for (auto it = params.begin(); it != params.end(); ++it) {
|
||||
if (it != params.begin()) { query += "&"; }
|
||||
@@ -3826,19 +3798,17 @@ inline std::shared_ptr<Response> Client::Post(const char *path,
|
||||
query += detail::encode_url(it->second);
|
||||
}
|
||||
|
||||
return Post(path, headers, query, "application/x-www-form-urlencoded",
|
||||
compress);
|
||||
return Post(path, headers, query, "application/x-www-form-urlencoded");
|
||||
}
|
||||
|
||||
inline std::shared_ptr<Response>
|
||||
Client::Post(const char *path, const MultipartFormDataItems &items,
|
||||
bool compress) {
|
||||
return Post(path, Headers(), items, compress);
|
||||
Client::Post(const char *path, const MultipartFormDataItems &items) {
|
||||
return Post(path, Headers(), items);
|
||||
}
|
||||
|
||||
inline std::shared_ptr<Response>
|
||||
Client::Post(const char *path, const Headers &headers,
|
||||
const MultipartFormDataItems &items, bool compress) {
|
||||
const MultipartFormDataItems &items) {
|
||||
auto boundary = detail::make_multipart_data_boundary();
|
||||
|
||||
std::string body;
|
||||
@@ -3860,71 +3830,63 @@ Client::Post(const char *path, const Headers &headers,
|
||||
body += "--" + boundary + "--\r\n";
|
||||
|
||||
std::string content_type = "multipart/form-data; boundary=" + boundary;
|
||||
return Post(path, headers, body, content_type.c_str(), compress);
|
||||
return Post(path, headers, body, content_type.c_str());
|
||||
}
|
||||
|
||||
inline std::shared_ptr<Response> Client::Put(const char *path,
|
||||
const std::string &body,
|
||||
const char *content_type,
|
||||
bool compress) {
|
||||
return Put(path, Headers(), body, content_type, compress);
|
||||
const char *content_type) {
|
||||
return Put(path, Headers(), body, content_type);
|
||||
}
|
||||
|
||||
inline std::shared_ptr<Response>
|
||||
Client::Put(const char *path, const Headers &headers, const std::string &body,
|
||||
const char *content_type, bool compress) {
|
||||
const char *content_type) {
|
||||
return send_with_content_provider("PUT", path, headers, body, 0, nullptr,
|
||||
content_type, compress);
|
||||
content_type);
|
||||
}
|
||||
|
||||
inline std::shared_ptr<Response> Client::Put(const char *path,
|
||||
size_t content_length,
|
||||
ContentProvider content_provider,
|
||||
const char *content_type,
|
||||
bool compress) {
|
||||
return Put(path, Headers(), content_length, content_provider, content_type,
|
||||
compress);
|
||||
const char *content_type) {
|
||||
return Put(path, Headers(), content_length, content_provider, content_type);
|
||||
}
|
||||
|
||||
inline std::shared_ptr<Response>
|
||||
Client::Put(const char *path, const Headers &headers, size_t content_length,
|
||||
ContentProvider content_provider, const char *content_type,
|
||||
bool compress) {
|
||||
ContentProvider content_provider, const char *content_type) {
|
||||
return send_with_content_provider("PUT", path, headers, std::string(),
|
||||
content_length, content_provider,
|
||||
content_type, compress);
|
||||
content_type);
|
||||
}
|
||||
|
||||
inline std::shared_ptr<Response> Client::Patch(const char *path,
|
||||
const std::string &body,
|
||||
const char *content_type,
|
||||
bool compress) {
|
||||
return Patch(path, Headers(), body, content_type, compress);
|
||||
const char *content_type) {
|
||||
return Patch(path, Headers(), body, content_type);
|
||||
}
|
||||
|
||||
inline std::shared_ptr<Response>
|
||||
Client::Patch(const char *path, const Headers &headers, const std::string &body,
|
||||
const char *content_type, bool compress) {
|
||||
const char *content_type) {
|
||||
return send_with_content_provider("PATCH", path, headers, body, 0, nullptr,
|
||||
content_type, compress);
|
||||
content_type);
|
||||
}
|
||||
|
||||
inline std::shared_ptr<Response> Client::Patch(const char *path,
|
||||
size_t content_length,
|
||||
ContentProvider content_provider,
|
||||
const char *content_type,
|
||||
bool compress) {
|
||||
return Patch(path, Headers(), content_length, content_provider, content_type,
|
||||
compress);
|
||||
const char *content_type) {
|
||||
return Patch(path, Headers(), content_length, content_provider, content_type);
|
||||
}
|
||||
|
||||
inline std::shared_ptr<Response>
|
||||
Client::Patch(const char *path, const Headers &headers, size_t content_length,
|
||||
ContentProvider content_provider, const char *content_type,
|
||||
bool compress) {
|
||||
ContentProvider content_provider, const char *content_type) {
|
||||
return send_with_content_provider("PATCH", path, headers, std::string(),
|
||||
content_length, content_provider,
|
||||
content_type, compress);
|
||||
content_type);
|
||||
}
|
||||
|
||||
inline std::shared_ptr<Response> Client::Delete(const char *path) {
|
||||
@@ -3984,13 +3946,15 @@ inline void Client::set_read_timeout(time_t sec, time_t usec) {
|
||||
read_timeout_usec_ = usec;
|
||||
}
|
||||
|
||||
inline void Client::follow_location(bool on) { follow_location_ = on; }
|
||||
|
||||
inline void Client::set_auth(const char *username, const char *password) {
|
||||
username_ = username;
|
||||
password_ = password;
|
||||
}
|
||||
|
||||
inline void Client::set_follow_location(bool on) { follow_location_ = on; }
|
||||
|
||||
inline void Client::set_compress(bool on) { compress_ = on; }
|
||||
|
||||
/*
|
||||
* SSL Implementation
|
||||
*/
|
||||
@@ -4435,6 +4399,8 @@ inline bool SSLClient::check_host_name(const char *pattern,
|
||||
}
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
} // namespace httplib
|
||||
|
||||
#endif // CPPHTTPLIB_HTTPLIB_H
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import os
|
||||
|
||||
border = '// ----------------------------------------------------------------------------'
|
||||
|
||||
with open('httplib.h') as f:
|
||||
lines = f.readlines()
|
||||
inImplementation = False
|
||||
os.makedirs('out', exist_ok=True)
|
||||
with open('out/httplib.h', 'w') as fh:
|
||||
with open('out/httplib.cc', 'w') as fc:
|
||||
fc.write('#include "httplib.h"\n')
|
||||
fc.write('namespace httplib {\n')
|
||||
for line in lines:
|
||||
isBorderLine = border in line
|
||||
if isBorderLine:
|
||||
inImplementation = not inImplementation
|
||||
else:
|
||||
if inImplementation:
|
||||
fc.write(line.replace('inline ', ''))
|
||||
pass
|
||||
else:
|
||||
fh.write(line)
|
||||
pass
|
||||
fc.write('} // namespace httplib\n')
|
||||
+24
-19
@@ -30,9 +30,11 @@ const std::string JSON_DATA = "{\"hello\":\"world\"}";
|
||||
|
||||
const string LARGE_DATA = string(1024 * 1024 * 100, '@'); // 100MB
|
||||
|
||||
MultipartFile& get_file_value(MultipartFiles &files, const char *key) {
|
||||
auto it = files.find(key);
|
||||
if (it != files.end()) { return it->second; }
|
||||
MultipartFormData& get_file_value(MultipartFormDataItems &files, const char *key) {
|
||||
auto it = std::find_if(files.begin(), files.end(), [&](const MultipartFormData &file) {
|
||||
return file.name == key;
|
||||
});
|
||||
if (it != files.end()) { return *it; }
|
||||
throw std::runtime_error("invalid mulitpart form data name error");
|
||||
}
|
||||
|
||||
@@ -522,7 +524,7 @@ TEST(AbsoluteRedirectTest, Redirect) {
|
||||
httplib::Client cli(host);
|
||||
#endif
|
||||
|
||||
cli.follow_location(true);
|
||||
cli.set_follow_location(true);
|
||||
auto res = cli.Get("/absolute-redirect/3");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(200, res->status);
|
||||
@@ -537,7 +539,7 @@ TEST(RedirectTest, Redirect) {
|
||||
httplib::Client cli(host);
|
||||
#endif
|
||||
|
||||
cli.follow_location(true);
|
||||
cli.set_follow_location(true);
|
||||
auto res = cli.Get("/redirect/3");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(200, res->status);
|
||||
@@ -552,7 +554,7 @@ TEST(RelativeRedirectTest, Redirect) {
|
||||
httplib::Client cli(host);
|
||||
#endif
|
||||
|
||||
cli.follow_location(true);
|
||||
cli.set_follow_location(true);
|
||||
auto res = cli.Get("/relative-redirect/3");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(200, res->status);
|
||||
@@ -567,7 +569,7 @@ TEST(TooManyRedirectTest, Redirect) {
|
||||
httplib::Client cli(host);
|
||||
#endif
|
||||
|
||||
cli.follow_location(true);
|
||||
cli.set_follow_location(true);
|
||||
auto res = cli.Get("/redirect/21");
|
||||
ASSERT_TRUE(res == nullptr);
|
||||
}
|
||||
@@ -580,7 +582,7 @@ TEST(YahooRedirectTest, Redirect) {
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(301, res->status);
|
||||
|
||||
cli.follow_location(true);
|
||||
cli.set_follow_location(true);
|
||||
res = cli.Get("/");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(200, res->status);
|
||||
@@ -588,7 +590,7 @@ TEST(YahooRedirectTest, Redirect) {
|
||||
|
||||
TEST(HttpsToHttpRedirectTest, Redirect) {
|
||||
httplib::SSLClient cli("httpbin.org");
|
||||
cli.follow_location(true);
|
||||
cli.set_follow_location(true);
|
||||
auto res =
|
||||
cli.Get("/redirect-to?url=http%3A%2F%2Fwww.google.com&status_code=302");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
@@ -801,15 +803,14 @@ protected:
|
||||
.Post("/content_receiver",
|
||||
[&](const Request & req, Response &res, const ContentReader &content_reader) {
|
||||
if (req.is_multipart_form_data()) {
|
||||
MultipartFiles files;
|
||||
MultipartFormDataItems files;
|
||||
content_reader(
|
||||
[&](const std::string &name, const MultipartFile &file) {
|
||||
files.emplace(name, file);
|
||||
[&](const MultipartFormData &file) {
|
||||
files.push_back(file);
|
||||
return true;
|
||||
},
|
||||
[&](const std::string &name, const char *data, size_t data_length) {
|
||||
auto &file = files.find(name)->second;
|
||||
file.content.append(data, data_length);
|
||||
[&](const char *data, size_t data_length) {
|
||||
files.back().content.append(data, data_length);
|
||||
return true;
|
||||
});
|
||||
|
||||
@@ -1534,12 +1535,13 @@ TEST_F(ServerTest, PutWithContentProvider) {
|
||||
|
||||
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
|
||||
TEST_F(ServerTest, PutWithContentProviderWithGzip) {
|
||||
cli_.set_compress(true);
|
||||
auto res = cli_.Put(
|
||||
"/put", 3,
|
||||
[](size_t /*offset*/, size_t /*length*/, DataSink sink) {
|
||||
sink("PUT", 3);
|
||||
},
|
||||
"text/plain", true);
|
||||
"text/plain");
|
||||
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(200, res->status);
|
||||
@@ -1547,7 +1549,8 @@ TEST_F(ServerTest, PutWithContentProviderWithGzip) {
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, PutLargeFileWithGzip) {
|
||||
auto res = cli_.Put("/put-large", LARGE_DATA, "text/plain", true);
|
||||
cli_.set_compress(true);
|
||||
auto res = cli_.Put("/put-large", LARGE_DATA, "text/plain");
|
||||
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(200, res->status);
|
||||
@@ -1620,7 +1623,8 @@ TEST_F(ServerTest, PostMulitpartFilsContentReceiver) {
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, PostContentReceiverGzip) {
|
||||
auto res = cli_.Post("/content_receiver", "content", "text/plain", true);
|
||||
cli_.set_compress(true);
|
||||
auto res = cli_.Post("/content_receiver", "content", "text/plain");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
ASSERT_EQ(200, res->status);
|
||||
ASSERT_EQ("content", res->body);
|
||||
@@ -1801,7 +1805,8 @@ TEST_F(ServerTest, MultipartFormDataGzip) {
|
||||
{"key2", "--abcdefg123", "", ""},
|
||||
};
|
||||
|
||||
auto res = cli_.Post("/gzipmultipart", items, true);
|
||||
cli_.set_compress(true);
|
||||
auto res = cli_.Post("/gzipmultipart", items);
|
||||
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(200, res->status);
|
||||
|
||||
Reference in New Issue
Block a user