diff --git a/httplib.h b/httplib.h index e904901..120edc7 100644 --- a/httplib.h +++ b/httplib.h @@ -589,36 +589,37 @@ public: std::shared_ptr Head(const char *path, const Headers &headers); std::shared_ptr Post(const char *path, const std::string &body, - const char *content_type); + const char *content_type, bool compress = false); std::shared_ptr Post(const char *path, const Headers &headers, const std::string &body, - const char *content_type); + const char *content_type, + bool compress = false); - std::shared_ptr Post(const char *path, const Params ¶ms); + std::shared_ptr Post(const char *path, const Params ¶ms, bool compress = false); std::shared_ptr Post(const char *path, const Headers &headers, - const Params ¶ms); + const Params ¶ms, bool compress = false); std::shared_ptr Post(const char *path, - const MultipartFormDataItems &items); + const MultipartFormDataItems &items, bool compress = false); std::shared_ptr Post(const char *path, const Headers &headers, - const MultipartFormDataItems &items); + const MultipartFormDataItems &items, bool compress = false); std::shared_ptr Put(const char *path, const std::string &body, - const char *content_type); + const char *content_type, bool compress = false); std::shared_ptr Put(const char *path, const Headers &headers, const std::string &body, - const char *content_type); + const char *content_type, bool compress = false); std::shared_ptr Patch(const char *path, const std::string &body, - const char *content_type); + const char *content_type, bool compress = false); std::shared_ptr Patch(const char *path, const Headers &headers, const std::string &body, - const char *content_type); + const char *content_type, bool compress = false); std::shared_ptr Delete(const char *path); @@ -3119,14 +3120,14 @@ inline std::shared_ptr Client::Head(const char *path, inline std::shared_ptr Client::Post(const char *path, const std::string &body, - const char *content_type) { - return Post(path, Headers(), body, content_type); + const char *content_type, bool compress) { + return Post(path, Headers(), body, content_type, compress); } inline std::shared_ptr Client::Post(const char *path, const Headers &headers, const std::string &body, - const char *content_type) { + const char *content_type, bool compress) { Request req; req.method = "POST"; req.headers = headers; @@ -3135,18 +3136,25 @@ inline std::shared_ptr Client::Post(const char *path, req.headers.emplace("Content-Type", content_type); req.body = body; + if (compress) { + if (!detail::compress(req.body)) { + return nullptr; + } + req.headers.emplace("Content-Encoding", "gzip"); + } + auto res = std::make_shared(); return send(req, *res) ? res : nullptr; } inline std::shared_ptr Client::Post(const char *path, - const Params ¶ms) { - return Post(path, Headers(), params); + const Params ¶ms, bool compress) { + return Post(path, Headers(), params, compress); } inline std::shared_ptr -Client::Post(const char *path, const Headers &headers, const Params ¶ms) { +Client::Post(const char *path, const Headers &headers, const Params ¶ms, bool compress) { std::string query; for (auto it = params.begin(); it != params.end(); ++it) { if (it != params.begin()) { query += "&"; } @@ -3155,58 +3163,53 @@ Client::Post(const char *path, const Headers &headers, const Params ¶ms) { query += detail::encode_url(it->second); } - return Post(path, headers, query, "application/x-www-form-urlencoded"); + return Post(path, headers, query, "application/x-www-form-urlencoded", compress); } inline std::shared_ptr -Client::Post(const char *path, const MultipartFormDataItems &items) { - return Post(path, Headers(), items); +Client::Post(const char *path, const MultipartFormDataItems &items, bool compress) { + return Post(path, Headers(), items, compress); } inline std::shared_ptr Client::Post(const char *path, const Headers &headers, - const MultipartFormDataItems &items) { - Request req; - req.method = "POST"; - req.headers = headers; - req.path = path; - + const MultipartFormDataItems &items, bool compress) { auto boundary = detail::make_multipart_data_boundary(); - req.headers.emplace("Content-Type", - "multipart/form-data; boundary=" + boundary); + std::string body; for (const auto &item : items) { - req.body += "--" + boundary + "\r\n"; - req.body += "Content-Disposition: form-data; name=\"" + item.name + "\""; + body += "--" + boundary + "\r\n"; + body += "Content-Disposition: form-data; name=\"" + item.name + "\""; if (!item.filename.empty()) { - req.body += "; filename=\"" + item.filename + "\""; + body += "; filename=\"" + item.filename + "\""; } - req.body += "\r\n"; + body += "\r\n"; if (!item.content_type.empty()) { - req.body += "Content-Type: " + item.content_type + "\r\n"; + body += "Content-Type: " + item.content_type + "\r\n"; } - req.body += "\r\n"; - req.body += item.content + "\r\n"; + body += "\r\n"; + body += item.content + "\r\n"; } - req.body += "--" + boundary + "--\r\n"; + body += "--" + boundary + "--\r\n"; - auto res = std::make_shared(); - - return send(req, *res) ? res : nullptr; + std::string content_type = "multipart/form-data; boundary=" + boundary; + return Post(path, headers, body, content_type.c_str(), compress); } inline std::shared_ptr Client::Put(const char *path, const std::string &body, - const char *content_type) { - return Put(path, Headers(), body, content_type); + const char *content_type, + bool compress) { + return Put(path, Headers(), body, content_type, compress); } inline std::shared_ptr Client::Put(const char *path, const Headers &headers, const std::string &body, - const char *content_type) { + const char *content_type, + bool compress) { Request req; req.method = "PUT"; req.headers = headers; @@ -3215,6 +3218,13 @@ inline std::shared_ptr Client::Put(const char *path, req.headers.emplace("Content-Type", content_type); req.body = body; + if (compress) { + if (!detail::compress(req.body)) { + return nullptr; + } + req.headers.emplace("Content-Encoding", "gzip"); + } + auto res = std::make_shared(); return send(req, *res) ? res : nullptr; @@ -3222,14 +3232,16 @@ inline std::shared_ptr Client::Put(const char *path, inline std::shared_ptr Client::Patch(const char *path, const std::string &body, - const char *content_type) { - return Patch(path, Headers(), body, content_type); + const char *content_type, + bool compress) { + return Patch(path, Headers(), body, content_type, compress); } inline std::shared_ptr Client::Patch(const char *path, const Headers &headers, const std::string &body, - const char *content_type) { + const char *content_type, + bool compress) { Request req; req.method = "PATCH"; req.headers = headers; @@ -3238,6 +3250,13 @@ inline std::shared_ptr Client::Patch(const char *path, req.headers.emplace("Content-Type", content_type); req.body = body; + if (compress) { + if (!detail::compress(req.body)) { + return nullptr; + } + req.headers.emplace("Content-Encoding", "gzip"); + } + auto res = std::make_shared(); return send(req, *res) ? res : nullptr; diff --git a/test/test.cc b/test/test.cc index 9ecfb6b..d34bc89 100644 --- a/test/test.cc +++ b/test/test.cc @@ -1549,56 +1549,14 @@ TEST_F(ServerTest, NoGzipWithContentReceiver) { } TEST_F(ServerTest, MultipartFormDataGzip) { - Request req; - req.method = "POST"; - req.path = "/gzipmultipart"; + MultipartFormDataItems items = { + {"key1", "test", "", ""}, + {"key2", "--abcdefg123", "", ""}, + }; - std::string host_and_port; - host_and_port += HOST; - host_and_port += ":"; - host_and_port += std::to_string(PORT); + auto res = cli_.Post("/gzipmultipart", items, true); - req.headers.emplace("Host", host_and_port.c_str()); - req.headers.emplace("Accept", "*/*"); - req.headers.emplace("User-Agent", "cpp-httplib/0.1"); - req.headers.emplace( - "Content-Type", - "multipart/form-data; boundary=------------------------fcba8368a9f48c0f"); - req.headers.emplace("Content-Encoding", "gzip"); - - // compressed_body generated by creating input.txt to this file: - /* - --------------------------fcba8368a9f48c0f - Content-Disposition: form-data; name="key1" - - test - --------------------------fcba8368a9f48c0f - Content-Disposition: form-data; name="key2" - - --abcdefg123 - --------------------------fcba8368a9f48c0f-- - */ - // then running unix2dos input.txt; gzip -9 -c input.txt | xxd -i. - uint8_t compressed_body[] = { - 0x1f, 0x8b, 0x08, 0x08, 0x48, 0xf1, 0xd4, 0x5a, 0x02, 0x03, 0x69, 0x6e, - 0x70, 0x75, 0x74, 0x2e, 0x74, 0x78, 0x74, 0x00, 0xd3, 0xd5, 0xc5, 0x05, - 0xd2, 0x92, 0x93, 0x12, 0x2d, 0x8c, 0xcd, 0x2c, 0x12, 0x2d, 0xd3, 0x4c, - 0x2c, 0x92, 0x0d, 0xd2, 0x78, 0xb9, 0x9c, 0xf3, 0xf3, 0x4a, 0x52, 0xf3, - 0x4a, 0x74, 0x5d, 0x32, 0x8b, 0x0b, 0xf2, 0x8b, 0x33, 0x4b, 0x32, 0xf3, - 0xf3, 0xac, 0x14, 0xd2, 0xf2, 0x8b, 0x72, 0x75, 0x53, 0x12, 0x4b, 0x12, - 0xad, 0x15, 0xf2, 0x12, 0x73, 0x53, 0x6d, 0x95, 0xb2, 0x53, 0x2b, 0x0d, - 0x95, 0x78, 0xb9, 0x78, 0xb9, 0x4a, 0x52, 0x8b, 0x4b, 0x78, 0xb9, 0x74, - 0x69, 0x61, 0x81, 0x11, 0xd8, 0x02, 0x5d, 0xdd, 0xc4, 0xa4, 0xe4, 0x94, - 0xd4, 0xb4, 0x74, 0x43, 0x23, 0x63, 0x52, 0x2c, 0xd2, 0xd5, 0xe5, 0xe5, - 0x02, 0x00, 0xff, 0x0e, 0x72, 0xdf, 0xf8, 0x00, 0x00, 0x00}; - - req.body = std::string((char *)compressed_body, - sizeof(compressed_body) / sizeof(compressed_body[0])); - - auto res = std::make_shared(); - auto ret = cli_.send(req, *res); - - ASSERT_TRUE(ret); + ASSERT_TRUE(res != nullptr); EXPECT_EQ(200, res->status); } #endif