mirror of
https://github.com/yhirose/cpp-httplib
synced 2026-06-08 18:30:49 +00:00
Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6ad25b6cf0 | |||
| 3dff60eb16 | |||
| 5038314b21 | |||
| 6e1297cab0 | |||
| 7de743c962 | |||
| 964fb5e5ca | |||
| c4f3f9529b | |||
| 887def9490 | |||
| bad6b2d22f | |||
| 3d47a51430 | |||
| 0a2cb20223 | |||
| ce502a73e1 | |||
| 010e4479f4 | |||
| 70e193374a | |||
| 6b22409217 | |||
| 969cccd52a | |||
| 4a9c048bbc | |||
| bfabbec8c7 | |||
| 3e9c06cf79 | |||
| 29677540ae | |||
| 71fcfeb912 | |||
| c7d22e451f | |||
| 42f9f9107f | |||
| 7cd25fbd63 |
+2
-1
@@ -50,8 +50,9 @@
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
FindPython3 requires Cmake v3.12
|
||||
ARCH_INDEPENDENT option of write_basic_package_version_file() requires Cmake v3.14
|
||||
]]
|
||||
cmake_minimum_required(VERSION 3.12.0 FATAL_ERROR)
|
||||
cmake_minimum_required(VERSION 3.14.0 FATAL_ERROR)
|
||||
|
||||
# Gets the latest tag as a string like "v0.6.6"
|
||||
# Can silently fail if git isn't on the system
|
||||
|
||||
@@ -287,7 +287,7 @@ Client Example
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// IMPORTANT: 1st parameter must be a hostname or an IP adress string.
|
||||
// IMPORTANT: 1st parameter must be a hostname or an IP address string.
|
||||
httplib::Client cli("localhost", 1234);
|
||||
|
||||
auto res = cli.Get("/hi");
|
||||
@@ -482,29 +482,15 @@ httplib::make_range_header({{0, 0}, {-1, 1}}) // 'Range: bytes=0-0, -1'
|
||||
### Keep-Alive connection
|
||||
|
||||
```cpp
|
||||
cli.set_keep_alive_max_count(2); // Default is 5
|
||||
httplib::Client cli("localhost", 1234);
|
||||
|
||||
std::vector<Request> requests;
|
||||
Get(requests, "/get-request1");
|
||||
Get(requests, "/get-request2");
|
||||
Post(requests, "/post-request1", "text", "text/plain");
|
||||
Post(requests, "/post-request2", "text", "text/plain");
|
||||
cli.Get("/hello"); // with "Connection: close"
|
||||
|
||||
const size_t DATA_CHUNK_SIZE = 4;
|
||||
std::string data("abcdefg");
|
||||
Post(requests, "/post-request-with-content-provider",
|
||||
data.size(),
|
||||
[&](size_t offset, size_t length, DataSink &sink){
|
||||
sink.write(&data[offset], std::min(length, DATA_CHUNK_SIZE));
|
||||
},
|
||||
"text/plain");
|
||||
cli.set_keep_alive(true);
|
||||
cli.Get("/world");
|
||||
|
||||
std::vector<Response> responses;
|
||||
if (cli.send(requests, responses)) {
|
||||
for (const auto& res: responses) {
|
||||
...
|
||||
}
|
||||
}
|
||||
cli.set_keep_alive(false);
|
||||
cli.Get("/last-request"); // with "Connection: close"
|
||||
```
|
||||
|
||||
### Redirect
|
||||
|
||||
+78
-44
@@ -578,6 +578,7 @@ TEST(DigestAuthTest, FromHTTPWatch) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
TEST(AbsoluteRedirectTest, Redirect) {
|
||||
auto host = "httpbin.org";
|
||||
|
||||
@@ -636,6 +637,7 @@ TEST(TooManyRedirectTest, Redirect) {
|
||||
auto res = cli.Get("/redirect/21");
|
||||
ASSERT_TRUE(res == nullptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
TEST(YahooRedirectTest, Redirect) {
|
||||
@@ -651,6 +653,7 @@ TEST(YahooRedirectTest, Redirect) {
|
||||
EXPECT_EQ(200, res->status);
|
||||
}
|
||||
|
||||
#if 0
|
||||
TEST(HttpsToHttpRedirectTest, Redirect) {
|
||||
httplib::SSLClient cli("httpbin.org");
|
||||
cli.set_follow_location(true);
|
||||
@@ -659,6 +662,7 @@ TEST(HttpsToHttpRedirectTest, Redirect) {
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(200, res->status);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(RedirectToDifferentPort, Redirect) {
|
||||
Server svr8080;
|
||||
@@ -761,6 +765,9 @@ protected:
|
||||
svr_(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE)
|
||||
#endif
|
||||
{
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
cli_.enable_server_certificate_verification(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual void SetUp() {
|
||||
@@ -1136,6 +1143,10 @@ protected:
|
||||
EXPECT_EQ(req.get_param_value("key"), "value");
|
||||
EXPECT_EQ(req.body, "content");
|
||||
})
|
||||
.Get("/last-request",
|
||||
[&](const Request & req, Response &/*res*/) {
|
||||
EXPECT_EQ("close", req.get_header_value("Connection"));
|
||||
})
|
||||
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
|
||||
.Get("/gzip",
|
||||
[&](const Request & /*req*/, Response &res) {
|
||||
@@ -2127,42 +2138,48 @@ TEST_F(ServerTest, HTTP2Magic) {
|
||||
}
|
||||
|
||||
TEST_F(ServerTest, KeepAlive) {
|
||||
cli_.set_keep_alive_max_count(4);
|
||||
auto res = cli_.Get("/hi");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(200, res->status);
|
||||
EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
|
||||
EXPECT_EQ("Hello World!", res->body);
|
||||
|
||||
std::vector<Request> requests;
|
||||
Get(requests, "/hi");
|
||||
Get(requests, "/hi");
|
||||
Get(requests, "/hi");
|
||||
Get(requests, "/not-exist");
|
||||
Post(requests, "/empty", "", "text/plain");
|
||||
Post(
|
||||
requests, "/empty", 0,
|
||||
[&](size_t, size_t, httplib::DataSink &) { return true; }, "text/plain");
|
||||
res = cli_.Get("/hi");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(200, res->status);
|
||||
EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
|
||||
EXPECT_EQ("Hello World!", res->body);
|
||||
|
||||
std::vector<Response> responses;
|
||||
auto ret = cli_.send(requests, responses);
|
||||
res = cli_.Get("/hi");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(200, res->status);
|
||||
EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
|
||||
EXPECT_EQ("Hello World!", res->body);
|
||||
|
||||
ASSERT_TRUE(ret == true);
|
||||
ASSERT_TRUE(requests.size() == responses.size());
|
||||
res = cli_.Get("/not-exist");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(404, res->status);
|
||||
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
auto &res = responses[i];
|
||||
EXPECT_EQ(200, res.status);
|
||||
EXPECT_EQ("text/plain", res.get_header_value("Content-Type"));
|
||||
EXPECT_EQ("Hello World!", res.body);
|
||||
}
|
||||
res = cli_.Post("/empty", "", "text/plain");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(200, res->status);
|
||||
EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
|
||||
EXPECT_EQ("empty", res->body);
|
||||
EXPECT_EQ("close", res->get_header_value("Connection"));
|
||||
|
||||
{
|
||||
auto &res = responses[3];
|
||||
EXPECT_EQ(404, res.status);
|
||||
}
|
||||
res = cli_.Post(
|
||||
"/empty", 0, [&](size_t, size_t, httplib::DataSink &) { return true; },
|
||||
"text/plain");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(200, res->status);
|
||||
EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
|
||||
EXPECT_EQ("empty", res->body);
|
||||
|
||||
for (size_t i = 4; i < 6; i++) {
|
||||
auto &res = responses[i];
|
||||
EXPECT_EQ(200, res.status);
|
||||
EXPECT_EQ("text/plain", res.get_header_value("Content-Type"));
|
||||
EXPECT_EQ("empty", res.body);
|
||||
}
|
||||
cli_.set_keep_alive(false);
|
||||
res = cli_.Get("/last-request");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
EXPECT_EQ(200, res->status);
|
||||
EXPECT_EQ("close", res->get_header_value("Connection"));
|
||||
}
|
||||
|
||||
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
|
||||
@@ -2305,15 +2322,13 @@ TEST_F(ServerTest, MultipartFormDataGzip) {
|
||||
static bool send_request(time_t read_timeout_sec, const std::string &req,
|
||||
std::string *resp = nullptr) {
|
||||
auto client_sock =
|
||||
detail::create_client_socket(HOST, PORT, nullptr,
|
||||
detail::create_client_socket(HOST, PORT, false, nullptr,
|
||||
/*timeout_sec=*/5, 0, std::string());
|
||||
|
||||
if (client_sock == INVALID_SOCKET) { return false; }
|
||||
|
||||
auto ret = detail::process_socket(
|
||||
true, client_sock, 1, read_timeout_sec, 0, 0, 0,
|
||||
[&](Stream &strm, bool /*last_connection*/, bool &
|
||||
/*connection_close*/) -> bool {
|
||||
auto ret = detail::process_client_socket(
|
||||
client_sock, read_timeout_sec, 0, 0, 0, [&](Stream &strm) {
|
||||
if (req.size() !=
|
||||
static_cast<size_t>(strm.write(req.data(), req.size()))) {
|
||||
return false;
|
||||
@@ -2515,8 +2530,7 @@ TEST(ServerStopTest, StopServerWithChunkedTransmission) {
|
||||
}
|
||||
|
||||
Client client(HOST, PORT);
|
||||
const Headers headers = {{"Accept", "text/event-stream"},
|
||||
{"Connection", "Keep-Alive"}};
|
||||
const Headers headers = {{"Accept", "text/event-stream"}};
|
||||
|
||||
auto get_thread = std::thread([&client, &headers]() {
|
||||
std::shared_ptr<Response> res = client.Get(
|
||||
@@ -2616,6 +2630,9 @@ protected:
|
||||
svr_(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE)
|
||||
#endif
|
||||
{
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
cli_.enable_server_certificate_verification(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual void SetUp() {
|
||||
@@ -2693,6 +2710,9 @@ protected:
|
||||
svr_(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE)
|
||||
#endif
|
||||
{
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
cli_.enable_server_certificate_verification(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual void SetUp() {
|
||||
@@ -2742,19 +2762,25 @@ TEST(SSLClientTest, ServerNameIndication) {
|
||||
ASSERT_EQ(200, res->status);
|
||||
}
|
||||
|
||||
TEST(SSLClientTest, ServerCertificateVerification) {
|
||||
TEST(SSLClientTest, ServerCertificateVerification1) {
|
||||
SSLClient cli("google.com");
|
||||
|
||||
auto res = cli.Get("/");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
ASSERT_EQ(301, res->status);
|
||||
}
|
||||
|
||||
TEST(SSLClientTest, ServerCertificateVerification2) {
|
||||
SSLClient cli("google.com");
|
||||
cli.enable_server_certificate_verification(true);
|
||||
res = cli.Get("/");
|
||||
cli.set_ca_cert_path("hello");
|
||||
auto res = cli.Get("/");
|
||||
ASSERT_TRUE(res == nullptr);
|
||||
}
|
||||
|
||||
TEST(SSLClientTest, ServerCertificateVerification3) {
|
||||
SSLClient cli("google.com");
|
||||
cli.set_ca_cert_path(CA_CERT_FILE);
|
||||
res = cli.Get("/");
|
||||
auto res = cli.Get("/");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
ASSERT_EQ(301, res->status);
|
||||
}
|
||||
@@ -2803,8 +2829,10 @@ TEST(SSLClientServerTest, ClientCertPresent) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
|
||||
httplib::SSLClient cli(HOST, PORT, CLIENT_CERT_FILE, CLIENT_PRIVATE_KEY_FILE);
|
||||
auto res = cli.Get("/test");
|
||||
cli.enable_server_certificate_verification(false);
|
||||
cli.set_connection_timeout(30);
|
||||
|
||||
auto res = cli.Get("/test");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
ASSERT_EQ(200, res->status);
|
||||
|
||||
@@ -2872,8 +2900,10 @@ TEST(SSLClientServerTest, MemoryClientCertPresent) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
|
||||
httplib::SSLClient cli(HOST, PORT, client_cert, client_private_key);
|
||||
auto res = cli.Get("/test");
|
||||
cli.enable_server_certificate_verification(false);
|
||||
cli.set_connection_timeout(30);
|
||||
|
||||
auto res = cli.Get("/test");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
ASSERT_EQ(200, res->status);
|
||||
|
||||
@@ -2918,8 +2948,10 @@ TEST(SSLClientServerTest, TrustDirOptional) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
|
||||
httplib::SSLClient cli(HOST, PORT, CLIENT_CERT_FILE, CLIENT_PRIVATE_KEY_FILE);
|
||||
auto res = cli.Get("/test");
|
||||
cli.enable_server_certificate_verification(false);
|
||||
cli.set_connection_timeout(30);
|
||||
|
||||
auto res = cli.Get("/test");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
ASSERT_EQ(200, res->status);
|
||||
|
||||
@@ -2971,6 +3003,7 @@ TEST(YahooRedirectTest3, SimpleInterface) {
|
||||
EXPECT_EQ(200, res->status);
|
||||
}
|
||||
|
||||
#if 0
|
||||
TEST(HttpsToHttpRedirectTest2, SimpleInterface) {
|
||||
auto res =
|
||||
httplib::Client2("https://httpbin.org")
|
||||
@@ -2981,3 +3014,4 @@ TEST(HttpsToHttpRedirectTest2, SimpleInterface) {
|
||||
EXPECT_EQ(200, res->status);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
+29
-47
@@ -52,6 +52,7 @@ void RedirectProxyText(Client& cli, const char *path, bool basic) {
|
||||
EXPECT_EQ(200, res->status);
|
||||
}
|
||||
|
||||
#if 0
|
||||
TEST(RedirectTest, HTTPBinNoSSLBasic) {
|
||||
Client cli("httpbin.org");
|
||||
RedirectProxyText(cli, "/redirect/2", true);
|
||||
@@ -73,6 +74,7 @@ TEST(RedirectTest, HTTPBinSSLDigest) {
|
||||
RedirectProxyText(cli, "/redirect/2", false);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
TEST(RedirectTest, YouTubeNoSSLBasic) {
|
||||
@@ -222,66 +224,46 @@ void KeepAliveTest(Client& cli, bool basic) {
|
||||
#endif
|
||||
}
|
||||
|
||||
cli.set_keep_alive_max_count(4);
|
||||
cli.set_follow_location(true);
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
cli.set_digest_auth("hello", "world");
|
||||
#endif
|
||||
|
||||
std::vector<Request> requests;
|
||||
{
|
||||
auto res = cli.Get("/get");
|
||||
EXPECT_EQ(200, res->status);
|
||||
}
|
||||
{
|
||||
auto res = cli.Get("/redirect/2");
|
||||
EXPECT_EQ(200, res->status);
|
||||
}
|
||||
|
||||
Get(requests, "/get");
|
||||
Get(requests, "/redirect/2");
|
||||
{
|
||||
std::vector<std::string> paths = {
|
||||
"/digest-auth/auth/hello/world/MD5",
|
||||
"/digest-auth/auth/hello/world/SHA-256",
|
||||
"/digest-auth/auth/hello/world/SHA-512",
|
||||
"/digest-auth/auth-int/hello/world/MD5",
|
||||
};
|
||||
|
||||
std::vector<std::string> paths = {
|
||||
"/digest-auth/auth/hello/world/MD5",
|
||||
"/digest-auth/auth/hello/world/SHA-256",
|
||||
"/digest-auth/auth/hello/world/SHA-512",
|
||||
"/digest-auth/auth-int/hello/world/MD5",
|
||||
};
|
||||
|
||||
for (auto path : paths) {
|
||||
Get(requests, path.c_str());
|
||||
for (auto path: paths) {
|
||||
auto res = cli.Get(path.c_str());
|
||||
EXPECT_EQ("{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n", res->body);
|
||||
EXPECT_EQ(200, res->status);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
int count = 100;
|
||||
while (count--) {
|
||||
Get(requests, "/get");
|
||||
auto res = cli.Get("/get");
|
||||
EXPECT_EQ(200, res->status);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Response> responses;
|
||||
auto ret = cli.send(requests, responses);
|
||||
ASSERT_TRUE(ret == true);
|
||||
ASSERT_TRUE(requests.size() == responses.size());
|
||||
|
||||
size_t i = 0;
|
||||
|
||||
{
|
||||
auto &res = responses[i++];
|
||||
EXPECT_EQ(200, res.status);
|
||||
}
|
||||
|
||||
{
|
||||
auto &res = responses[i++];
|
||||
EXPECT_EQ(200, res.status);
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
int count = static_cast<int>(paths.size());
|
||||
while (count--) {
|
||||
auto &res = responses[i++];
|
||||
EXPECT_EQ("{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n", res.body);
|
||||
EXPECT_EQ(200, res.status);
|
||||
}
|
||||
}
|
||||
|
||||
for (; i < responses.size(); i++) {
|
||||
auto &res = responses[i];
|
||||
EXPECT_EQ(200, res.status);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
TEST(KeepAliveTest, NoSSLWithBasic) {
|
||||
Client cli("httpbin.org");
|
||||
KeepAliveTest(cli, true);
|
||||
@@ -292,7 +274,6 @@ TEST(KeepAliveTest, SSLWithBasic) {
|
||||
KeepAliveTest(cli, true);
|
||||
}
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
TEST(KeepAliveTest, NoSSLWithDigest) {
|
||||
Client cli("httpbin.org");
|
||||
KeepAliveTest(cli, false);
|
||||
@@ -303,3 +284,4 @@ TEST(KeepAliveTest, SSLWithDigest) {
|
||||
KeepAliveTest(cli, false);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user