This commit is contained in:
yhirose 2022-11-15 11:53:06 -05:00
parent 87994811a1
commit 07c6e58951
2 changed files with 133 additions and 89 deletions

View File

@ -902,6 +902,7 @@ public:
Result Head(const std::string &path, const Headers &headers); Result Head(const std::string &path, const Headers &headers);
Result Post(const std::string &path); Result Post(const std::string &path);
Result Post(const std::string &path, const Headers &headers);
Result Post(const std::string &path, const char *body, size_t content_length, Result Post(const std::string &path, const char *body, size_t content_length,
const std::string &content_type); const std::string &content_type);
Result Post(const std::string &path, const Headers &headers, const char *body, Result Post(const std::string &path, const Headers &headers, const char *body,
@ -1263,6 +1264,7 @@ public:
Result Head(const std::string &path, const Headers &headers); Result Head(const std::string &path, const Headers &headers);
Result Post(const std::string &path); Result Post(const std::string &path);
Result Post(const std::string &path, const Headers &headers);
Result Post(const std::string &path, const char *body, size_t content_length, Result Post(const std::string &path, const char *body, size_t content_length,
const std::string &content_type); const std::string &content_type);
Result Post(const std::string &path, const Headers &headers, const char *body, Result Post(const std::string &path, const Headers &headers, const char *body,
@ -6752,6 +6754,11 @@ inline Result ClientImpl::Post(const std::string &path) {
return Post(path, std::string(), std::string()); return Post(path, std::string(), std::string());
} }
inline Result ClientImpl::Post(const std::string &path,
const Headers &headers) {
return Post(path, headers, nullptr, 0, std::string());
}
inline Result ClientImpl::Post(const std::string &path, const char *body, inline Result ClientImpl::Post(const std::string &path, const char *body,
size_t content_length, size_t content_length,
const std::string &content_type) { const std::string &content_type) {
@ -8075,6 +8082,9 @@ inline Result Client::Head(const std::string &path, const Headers &headers) {
} }
inline Result Client::Post(const std::string &path) { return cli_->Post(path); } inline Result Client::Post(const std::string &path) { return cli_->Post(path); }
inline Result Client::Post(const std::string &path, const Headers &headers) {
return cli_->Post(path, headers);
}
inline Result Client::Post(const std::string &path, const char *body, inline Result Client::Post(const std::string &path, const char *body,
size_t content_length, size_t content_length,
const std::string &content_type) { const std::string &content_type) {

View File

@ -1715,6 +1715,22 @@ protected:
EXPECT_EQ("0", req.get_header_value("Content-Length")); EXPECT_EQ("0", req.get_header_value("Content-Length"));
res.set_content("empty-no-content-type", "text/plain"); res.set_content("empty-no-content-type", "text/plain");
}) })
.Post("/path-only",
[&](const Request &req, Response &res) {
EXPECT_EQ(req.body, "");
EXPECT_EQ("", req.get_header_value("Content-Type"));
EXPECT_EQ("0", req.get_header_value("Content-Length"));
res.set_content("path-only", "text/plain");
})
.Post("/path-headers-only",
[&](const Request &req, Response &res) {
EXPECT_EQ(req.body, "");
EXPECT_EQ("", req.get_header_value("Content-Type"));
EXPECT_EQ("0", req.get_header_value("Content-Length"));
EXPECT_EQ("world", req.get_header_value("hello"));
EXPECT_EQ("world2", req.get_header_value("hello2"));
res.set_content("path-headers-only", "text/plain");
})
.Post("/post-large", .Post("/post-large",
[&](const Request &req, Response &res) { [&](const Request &req, Response &res) {
EXPECT_EQ(req.body, LARGE_DATA); EXPECT_EQ(req.body, LARGE_DATA);
@ -2125,6 +2141,21 @@ TEST_F(ServerTest, PostEmptyContentWithNoContentType) {
ASSERT_EQ("empty-no-content-type", res->body); ASSERT_EQ("empty-no-content-type", res->body);
} }
TEST_F(ServerTest, PostPathOnly) {
auto res = cli_.Post("/path-only");
ASSERT_TRUE(res);
ASSERT_EQ(200, res->status);
ASSERT_EQ("path-only", res->body);
}
TEST_F(ServerTest, PostPathAndHeadersOnly) {
auto res = cli_.Post("/path-headers-only",
Headers({{"hello", "world"}, {"hello2", "world2"}}));
ASSERT_TRUE(res);
ASSERT_EQ(200, res->status);
ASSERT_EQ("path-headers-only", res->body);
}
TEST_F(ServerTest, PostLarge) { TEST_F(ServerTest, PostLarge) {
auto res = cli_.Post("/post-large", LARGE_DATA, "text/plain"); auto res = cli_.Post("/post-large", LARGE_DATA, "text/plain");
ASSERT_TRUE(res); ASSERT_TRUE(res);
@ -4181,7 +4212,8 @@ protected:
res.set_content("Hello World!", "text/plain"); res.set_content("Hello World!", "text/plain");
}); });
t_ = thread([&]() { ASSERT_TRUE(svr_.listen(std::string(), PORT, AI_PASSIVE)); }); t_ = thread(
[&]() { ASSERT_TRUE(svr_.listen(std::string(), PORT, AI_PASSIVE)); });
while (!svr_.is_running()) { while (!svr_.is_running()) {
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1));
@ -5142,11 +5174,11 @@ TEST(MultipartFormDataTest, PostInvalidBoundaryChars) {
}; };
for (const char &c : " \t\r\n") { for (const char &c : " \t\r\n") {
auto res = cli.Post("/invalid_boundary", {}, items, string("abc123").append(1, c)); auto res =
cli.Post("/invalid_boundary", {}, items, string("abc123").append(1, c));
ASSERT_EQ(Error::UnsupportedMultipartBoundaryChars, res.error()); ASSERT_EQ(Error::UnsupportedMultipartBoundaryChars, res.error());
ASSERT_FALSE(res); ASSERT_FALSE(res);
} }
} }
TEST(MultipartFormDataTest, PutFormData) { TEST(MultipartFormDataTest, PutFormData) {
@ -5215,7 +5247,8 @@ TEST(MultipartFormDataTest, PutFormData) {
TEST(MultipartFormDataTest, PutFormDataCustomBoundary) { TEST(MultipartFormDataTest, PutFormDataCustomBoundary) {
SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE); SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE);
svr.Put("/put_customboundary", [&](const Request &req, const Response & /*res*/, svr.Put("/put_customboundary",
[&](const Request &req, const Response & /*res*/,
const ContentReader &content_reader) { const ContentReader &content_reader) {
if (req.is_multipart_form_data()) { if (req.is_multipart_form_data()) {
MultipartFormDataItems files; MultipartFormDataItems files;
@ -5303,9 +5336,7 @@ TEST(MultipartFormDataTest, PutInvalidBoundaryChars) {
#ifndef _WIN32 #ifndef _WIN32
class UnixSocketTest : public ::testing::Test { class UnixSocketTest : public ::testing::Test {
protected: protected:
void TearDown() override { void TearDown() override { std::remove(pathname_.c_str()); }
std::remove(pathname_.c_str());
}
void client_GET(const std::string &addr) { void client_GET(const std::string &addr) {
httplib::Client cli{addr}; httplib::Client cli{addr};
@ -5332,7 +5363,8 @@ TEST_F(UnixSocketTest, pathname) {
}); });
std::thread t{[&] { std::thread t{[&] {
ASSERT_TRUE(svr.set_address_family(AF_UNIX).listen(pathname_, 80)); }}; ASSERT_TRUE(svr.set_address_family(AF_UNIX).listen(pathname_, 80));
}};
while (!svr.is_running()) { while (!svr.is_running()) {
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1));
} }
@ -5344,8 +5376,8 @@ TEST_F(UnixSocketTest, pathname) {
t.join(); t.join();
} }
#if defined(__linux__) \ #if defined(__linux__) || \
|| /* __APPLE__ */ (defined(SOL_LOCAL) && defined(SO_PEERPID)) /* __APPLE__ */ (defined(SOL_LOCAL) && defined(SO_PEERPID))
TEST_F(UnixSocketTest, PeerPid) { TEST_F(UnixSocketTest, PeerPid) {
httplib::Server svr; httplib::Server svr;
std::string remote_port_val; std::string remote_port_val;
@ -5355,7 +5387,8 @@ TEST_F(UnixSocketTest, PeerPid) {
}); });
std::thread t{[&] { std::thread t{[&] {
ASSERT_TRUE(svr.set_address_family(AF_UNIX).listen(pathname_, 80)); }}; ASSERT_TRUE(svr.set_address_family(AF_UNIX).listen(pathname_, 80));
}};
while (!svr.is_running()) { while (!svr.is_running()) {
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1));
} }
@ -5380,7 +5413,8 @@ TEST_F(UnixSocketTest, abstract) {
}); });
std::thread t{[&] { std::thread t{[&] {
ASSERT_TRUE(svr.set_address_family(AF_UNIX).listen(abstract_addr, 80)); }}; ASSERT_TRUE(svr.set_address_family(AF_UNIX).listen(abstract_addr, 80));
}};
while (!svr.is_running()) { while (!svr.is_running()) {
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1));
} }
@ -5394,23 +5428,23 @@ TEST_F(UnixSocketTest, abstract) {
#endif #endif
TEST(SocketStream, is_writable_UNIX) { TEST(SocketStream, is_writable_UNIX) {
int fd[2]; int fds[2];
ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, fd)); ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, fds));
const auto asSocketStream = const auto asSocketStream = [&](socket_t fd,
[&] (socket_t fd, std::function<bool(Stream &)> func) { std::function<bool(Stream &)> func) {
return detail::process_client_socket(fd, 0, 0, 0, 0, func); return detail::process_client_socket(fd, 0, 0, 0, 0, func);
}; };
asSocketStream(fd[0], [&] (Stream &s0) { asSocketStream(fds[0], [&](Stream &s0) {
EXPECT_EQ(s0.socket(), fd[0]); EXPECT_EQ(s0.socket(), fds[0]);
EXPECT_TRUE(s0.is_writable()); EXPECT_TRUE(s0.is_writable());
EXPECT_EQ(0, close(fd[1])); EXPECT_EQ(0, close(fds[1]));
EXPECT_FALSE(s0.is_writable()); EXPECT_FALSE(s0.is_writable());
return true; return true;
}); });
EXPECT_EQ(0, close(fd[0])); EXPECT_EQ(0, close(fds[0]));
} }
TEST(SocketStream, is_writable_INET) { TEST(SocketStream, is_writable_INET) {
@ -5441,8 +5475,8 @@ TEST(SocketStream, is_writable_INET) {
svr.join(); svr.join();
ASSERT_NE(disconnected_svr_sock, -1); ASSERT_NE(disconnected_svr_sock, -1);
const auto asSocketStream = const auto asSocketStream = [&](socket_t fd,
[&] (socket_t fd, std::function<bool(Stream &)> func) { std::function<bool(Stream &)> func) {
return detail::process_client_socket(fd, 0, 0, 0, 0, func); return detail::process_client_socket(fd, 0, 0, 0, 0, func);
}; };
asSocketStream(disconnected_svr_sock, [&](Stream &ss) { asSocketStream(disconnected_svr_sock, [&](Stream &ss) {