Compare commits

...

33 Commits

Author SHA1 Message Date
yhirose fc9b223acc Updated copyright year 2021-06-11 14:45:35 -04:00
CncGpp ba824089d7 Fix code err code 401 when the password is empty in base_auth. (#958) 2021-06-11 14:39:33 -04:00
Andrea Pappacoda 1a2faf09e0 Add header-only Meson support (#955)
* Add header-only Meson support
This allows users to call `dependency('httplib')` and have the include
directory automatically configured

* Rename `httplib` to `cpp-httplib`
2021-06-05 16:45:00 -04:00
yhirose 5a43bb8149 Implemented #946 in a different way 2021-06-02 13:45:47 -04:00
yhirose 0104614656 Code refactoring 2021-06-02 08:11:31 -04:00
yhirose 77a77f6d2d Added set_default_headers on Server 2021-05-23 19:06:28 -04:00
Mathias Laurin 089b9daa1c Fix virtual call in ClientImpl::~ClientImpl() (#942)
* Fix virtual call in ClientImpl::~ClientImpl()

This fixes a warning in clang tidy:

> Call to virtual method 'ClientImpl::shutdown_ssl' during
> destruction bypasses virtual dispatch

ClientImpl::~ClientImpl() calls lock_socket_and_shutdown_and_close()
that itself calls shutdown_ssl().  However, shutdown_ssl() is virtual
and C++ does not perform virtual dispatch in destructors, which results
in the wrong overload being called.

This change adds a non-virtual shutdown_ssl_impl() function that is
called from ~SSLClient().  We also inline sock_socket_and_shutdown_and_close()
and removes the virtual call in ~ClientImpl().

* Inline and remove lock_socket_and_shutdown_and_close()

The function only has one caller.
2021-05-22 20:15:20 -04:00
yhirose ba34ea4ee8 Fix #944 2021-05-22 19:24:50 -04:00
Baruch Nissenbaum 2917b8a005 Explicit cast from size_t to uInt (#941)
* Explicit cast from size_t to uInt

* static_cast<uInt> instead of C style cast
2021-05-19 18:03:59 -04:00
Joseph Huang dcf24d45a2 fix ssesvr use of deleted function (#938) 2021-05-18 23:19:15 -04:00
yhirose 75fdb06696 Added a missing member in copy_settings. 2021-05-15 09:14:44 -04:00
Alex Hornung e00ad37580 Add option to bypass URL encode of path (#934) 2021-05-15 08:48:25 -04:00
Vincent Stumpf 5cfb70c2b4 Fix some shadowed variable warnings (#935) 2021-05-15 08:46:16 -04:00
Alessio Pollero 2a70c45697 Fix client.cc code, since res.error() without operator overloading… (#921)
* Fix client.cc code, since res.error() without operator overloading causing error in Xcode

* Add unit test to check new error to string with operator overloading

* Add inline as requested in code review comment
2021-05-01 13:29:23 -04:00
Aswin Raj Kharel c58b00580e reserving before encoding (#912) 2021-04-24 16:19:14 -04:00
Ken Schalk 7c60e69c33 Remove redunant call to close_socket (#911) 2021-04-23 17:07:19 -04:00
yhirose 33e94891ee Updated test.cc 2021-04-22 08:04:46 -04:00
yhirose 73e0729f63 Change sink.write() to return boolean 2021-04-22 07:14:08 -04:00
yhirose 21c529229c Fixed timeout issues 2021-04-22 07:14:08 -04:00
yhirose 63643e6386 Code format 2021-04-13 20:52:49 -04:00
yhirose 6cc2edce99 Added set_address_family 2021-04-13 20:49:52 -04:00
yhirose d122ff3ca8 Code formatting 2021-04-13 12:38:45 -04:00
James Young 14c6d526b4 Use newer version-flexible TLS/SSL method (#904) 2021-04-13 09:11:38 -04:00
Philipp Hasper 28e07bca16 Fixed minor code smells (#901) 2021-04-09 14:55:21 -04:00
yhirose faa5f1d802 Additional changes for #889 2021-04-05 16:13:41 -04:00
yhirose 9d3365df54 Fix #889 2021-04-05 11:40:53 -04:00
yhirose 6ff84d34d1 Another simpler implementation of #890 (#891) 2021-04-02 18:25:04 -04:00
yhirose b845425cd0 Fix #878 2021-03-16 19:42:44 -04:00
yhirose 89519c88e2 Fix #874 2021-03-10 15:57:56 -05:00
yhirose ff813bf99d Fix #863 2021-02-17 15:36:56 -05:00
yhirose cf475bcb50 Fix #860 2021-02-12 12:21:43 -05:00
yhirose bc80d7c789 Fixed ClientStop test problem 2021-02-06 20:12:30 -05:00
yhirose b7566f6961 Resolve #852 2021-02-02 22:09:35 -05:00
5 changed files with 794 additions and 265 deletions
+2 -2
View File
@@ -266,7 +266,7 @@ svr.Get("/stream", [&](const Request &req, Response &res) {
sink.write(&d[offset], std::min(length, DATA_CHUNK_SIZE));
return true; // return 'false' if you want to cancel the process.
},
[data] { delete data; });
[data](bool success) { delete data; });
});
```
@@ -781,7 +781,7 @@ Note: Windows 8 or lower and Cygwin on Windows are not supported.
License
-------
MIT license (© 2020 Yuji Hirose)
MIT license (© 2021 Yuji Hirose)
Special Thanks To
-----------------
+2 -11
View File
@@ -1,10 +1,3 @@
//
// sse.cc
//
// Copyright (c) 2020 Yuji Hirose. All rights reserved.
// MIT License
//
#include <atomic>
#include <chrono>
#include <condition_variable>
@@ -20,8 +13,6 @@ using namespace std;
class EventDispatcher {
public:
EventDispatcher() {
id_ = 0;
cid_ = -1;
}
void wait_event(DataSink *sink) {
@@ -41,8 +32,8 @@ public:
private:
mutex m_;
condition_variable cv_;
atomic_int id_;
atomic_int cid_;
atomic_int id_{0};
atomic_int cid_{-1};
string message_;
};
+446 -201
View File
File diff suppressed because it is too large Load Diff
+7
View File
@@ -0,0 +1,7 @@
project('cpp-httplib', 'cpp', license: 'MIT')
cpp_httplib_dep = declare_dependency(include_directories: include_directories('.'))
if meson.version().version_compare('>=0.54.0')
meson.override_dependency('cpp-httplib', cpp_httplib_dep)
endif
+337 -51
View File
@@ -5,8 +5,9 @@
#include <atomic>
#include <chrono>
#include <future>
#include <thread>
#include <sstream>
#include <stdexcept>
#include <thread>
#define SERVER_CERT_FILE "./cert.pem"
#define SERVER_CERT2_FILE "./cert2.pem"
@@ -436,26 +437,6 @@ TEST(ChunkedEncodingTest, WithResponseHandlerAndContentReceiver) {
EXPECT_EQ(out, body);
}
TEST(DefaultHeadersTest, FromHTTPBin) {
Client cli("httpbin.org");
cli.set_default_headers({make_range_header({{1, 10}})});
cli.set_connection_timeout(5);
{
auto res = cli.Get("/range/32");
ASSERT_TRUE(res);
EXPECT_EQ("bcdefghijk", res->body);
EXPECT_EQ(206, res->status);
}
{
auto res = cli.Get("/range/32");
ASSERT_TRUE(res);
EXPECT_EQ("bcdefghijk", res->body);
EXPECT_EQ(206, res->status);
}
}
TEST(RangeTest, FromHTTPBin) {
auto host = "httpbin.org";
@@ -525,7 +506,7 @@ TEST(ConnectionErrorTest, InvalidHost) {
auto port = 80;
Client cli(host, port);
#endif
cli.set_connection_timeout(2);
cli.set_connection_timeout(std::chrono::seconds(2));
auto res = cli.Get("/");
ASSERT_TRUE(!res);
@@ -540,24 +521,40 @@ TEST(ConnectionErrorTest, InvalidHost2) {
#else
Client cli(host);
#endif
cli.set_connection_timeout(2);
cli.set_connection_timeout(std::chrono::seconds(2));
auto res = cli.Get("/");
ASSERT_TRUE(!res);
EXPECT_EQ(Error::Connection, res.error());
}
TEST(ConnectionErrorTest, InvalidPort) {
auto host = "localhost";
TEST(ConnectionErrorTest, InvalidHostCheckResultErrorToString) {
auto host = "httpbin.org/";
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
SSLClient cli(host);
#else
Client cli(host);
#endif
cli.set_connection_timeout(std::chrono::seconds(2));
auto res = cli.Get("/");
ASSERT_TRUE(!res);
stringstream s;
s << "error code: " << res.error();
EXPECT_EQ("error code: 2", s.str());
}
TEST(ConnectionErrorTest, InvalidPort) {
auto host = "localhost";
auto port = 44380;
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
SSLClient cli(host, port);
#else
auto port = 8080;
Client cli(host, port);
#endif
cli.set_connection_timeout(2);
cli.set_connection_timeout(std::chrono::seconds(2));
auto res = cli.Get("/");
ASSERT_TRUE(!res);
@@ -574,7 +571,7 @@ TEST(ConnectionErrorTest, Timeout) {
auto port = 8080;
Client cli(host, port);
#endif
cli.set_connection_timeout(2);
cli.set_connection_timeout(std::chrono::seconds(2));
auto res = cli.Get("/");
ASSERT_TRUE(!res);
@@ -591,7 +588,7 @@ TEST(CancelTest, NoCancel) {
auto port = 80;
Client cli(host, port);
#endif
cli.set_connection_timeout(5);
cli.set_connection_timeout(std::chrono::seconds(5));
auto res = cli.Get("/range/32", [](uint64_t, uint64_t) { return true; });
ASSERT_TRUE(res);
@@ -611,7 +608,7 @@ TEST(CancelTest, WithCancelSmallPayload) {
#endif
auto res = cli.Get("/range/32", [](uint64_t, uint64_t) { return false; });
cli.set_connection_timeout(5);
cli.set_connection_timeout(std::chrono::seconds(5));
ASSERT_TRUE(!res);
EXPECT_EQ(Error::Canceled, res.error());
}
@@ -626,7 +623,7 @@ TEST(CancelTest, WithCancelLargePayload) {
auto port = 80;
Client cli(host, port);
#endif
cli.set_connection_timeout(5);
cli.set_connection_timeout(std::chrono::seconds(5));
uint32_t count = 0;
auto res = cli.Get("/range/65536",
@@ -890,8 +887,100 @@ TEST(UrlWithSpace, Redirect) {
EXPECT_EQ(200, res->status);
EXPECT_EQ(18527, res->get_header_value<uint64_t>("Content-Length"));
}
TEST(RedirectFromPageWithContent, Redirect) {
Server svr;
svr.Get("/1", [&](const Request & /*req*/, Response &res) {
res.set_content("___", "text/plain");
res.set_redirect("/2");
});
svr.Get("/2", [&](const Request & /*req*/, Response &res) {
res.set_content("Hello World!", "text/plain");
});
auto th = std::thread([&]() { svr.listen("localhost", PORT); });
while (!svr.is_running()) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
// Give GET time to get a few messages.
std::this_thread::sleep_for(std::chrono::seconds(1));
{
Client cli("localhost", PORT);
cli.set_follow_location(true);
std::string body;
auto res = cli.Get("/1", [&](const char *data, size_t data_length) {
body.append(data, data_length);
return true;
});
ASSERT_TRUE(res);
EXPECT_EQ(200, res->status);
EXPECT_EQ("Hello World!", body);
}
{
Client cli("localhost", PORT);
std::string body;
auto res = cli.Get("/1", [&](const char *data, size_t data_length) {
body.append(data, data_length);
return true;
});
ASSERT_TRUE(res);
EXPECT_EQ(302, res->status);
EXPECT_EQ("___", body);
}
svr.stop();
th.join();
ASSERT_FALSE(svr.is_running());
}
#endif
TEST(PathUrlEncodeTest, PathUrlEncode) {
Server svr;
svr.Get("/foo", [](const Request &req, Response &res) {
auto a = req.params.find("a");
if (a != req.params.end()) {
res.set_content((*a).second, "text/plain");
res.status = 200;
} else {
res.status = 400;
}
});
auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
// Give GET time to get a few messages.
std::this_thread::sleep_for(std::chrono::seconds(1));
{
Client cli(HOST, PORT);
cli.set_url_encode(false);
auto res = cli.Get("/foo?a=explicitly+encoded");
ASSERT_TRUE(res);
EXPECT_EQ(200, res->status);
// This expects it back with a space, as the `+` won't have been
// url-encoded, and server-side the params get decoded turning `+`
// into spaces.
EXPECT_EQ("explicitly encoded", res->body);
}
svr.stop();
thread.join();
ASSERT_FALSE(svr.is_running());
}
TEST(BindServerTest, BindDualStack) {
Server svr;
@@ -982,11 +1071,12 @@ TEST(ErrorHandlerTest, ContentLength) {
TEST(ExceptionHandlerTest, ContentLength) {
Server svr;
svr.set_exception_handler([](const Request & /*req*/, Response &res, std::exception & /*e*/) {
res.status = 500;
res.set_content("abcdefghijklmnopqrstuvwxyz",
"text/html"); // <= Content-Length still 13
});
svr.set_exception_handler(
[](const Request & /*req*/, Response &res, std::exception & /*e*/) {
res.status = 500;
res.set_content("abcdefghijklmnopqrstuvwxyz",
"text/html"); // <= Content-Length still 13
});
svr.Get("/hi", [](const Request & /*req*/, Response &res) {
res.set_content("Hello World!\n", "text/plain");
@@ -1288,7 +1378,10 @@ protected:
(*i)++;
return true;
},
[i] { delete i; });
[i](bool success) {
EXPECT_TRUE(success);
delete i;
});
})
.Get("/streamed",
[&](const Request & /*req*/, Response &res) {
@@ -1310,10 +1403,15 @@ protected:
const auto &d = *data;
auto out_len =
std::min(static_cast<size_t>(length), DATA_CHUNK_SIZE);
sink.write(&d[static_cast<size_t>(offset)], out_len);
auto ret =
sink.write(&d[static_cast<size_t>(offset)], out_len);
EXPECT_TRUE(ret);
return true;
},
[data] { delete data; });
[data](bool success) {
EXPECT_TRUE(success);
delete data;
});
})
.Get("/streamed-cancel",
[&](const Request & /*req*/, Response &res) {
@@ -1644,6 +1742,7 @@ TEST_F(ServerTest, GetMethod200) {
ASSERT_TRUE(res);
EXPECT_EQ("HTTP/1.1", res->version);
EXPECT_EQ(200, res->status);
EXPECT_EQ("OK", res->reason);
EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
EXPECT_EQ(1, res->get_header_value_count("Content-Type"));
EXPECT_EQ("Hello World!", res->body);
@@ -2315,7 +2414,8 @@ TEST_F(ServerTest, ClientStop) {
auto res = cli_.Get("/streamed-cancel",
[&](const char *, uint64_t) { return true; });
ASSERT_TRUE(!res);
EXPECT_TRUE(res.error() == Error::Canceled || res.error() == Error::Read);
EXPECT_TRUE(res.error() == Error::Canceled ||
res.error() == Error::Read || res.error() == Error::Write);
}));
}
@@ -2463,7 +2563,8 @@ TEST_F(ServerTest, SlowPost) {
auto res = cli_.Post(
"/slowpost", 64 * 1024 * 1024,
[&](size_t /*offset*/, size_t /*length*/, DataSink &sink) {
sink.write(buffer, sizeof(buffer));
auto ret = sink.write(buffer, sizeof(buffer));
EXPECT_TRUE(ret);
return true;
},
"text/plain");
@@ -2476,7 +2577,7 @@ TEST_F(ServerTest, SlowPostFail) {
char buffer[64 * 1024];
memset(buffer, 0x42, sizeof(buffer));
cli_.set_write_timeout(0, 0);
cli_.set_write_timeout(std::chrono::seconds(0));
auto res = cli_.Post(
"/slowpost", 64 * 1024 * 1024,
[&](size_t /*offset*/, size_t /*length*/, DataSink &sink) {
@@ -2614,6 +2715,24 @@ TEST_F(ServerTest, PutLargeFileWithGzip) {
EXPECT_EQ(LARGE_DATA, res->body);
}
TEST_F(ServerTest, PutLargeFileWithGzip2) {
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
Client cli("https://localhost:1234");
cli.enable_server_certificate_verification(false);
#else
Client cli("http://localhost:1234");
#endif
cli.set_compress(true);
auto res = cli.Put("/put-large", LARGE_DATA, "text/plain");
ASSERT_TRUE(res);
EXPECT_EQ(200, res->status);
EXPECT_EQ(LARGE_DATA, res->body);
EXPECT_EQ(101942u, res.get_request_header_value<uint64_t>("Content-Length"));
EXPECT_EQ("gzip", res.get_request_header_value("Content-Encoding"));
}
TEST_F(ServerTest, PutContentWithDeflate) {
cli_.set_compress(false);
Headers headers;
@@ -3067,9 +3186,11 @@ static bool send_request(time_t read_timeout_sec, const std::string &req,
std::string *resp = nullptr) {
auto error = Error::Success;
auto client_sock =
detail::create_client_socket(HOST, PORT, false, nullptr,
/*timeout_sec=*/5, 0, std::string(), error);
auto client_sock = detail::create_client_socket(
HOST, PORT, AF_UNSPEC, false, nullptr,
/*connection_timeout_sec=*/5, 0,
/*read_timeout_sec=*/5, 0,
/*write_timeout_sec=*/5, 0, std::string(), error);
if (client_sock == INVALID_SOCKET) { return false; }
@@ -3135,7 +3256,7 @@ static void test_raw_request(const std::string &req,
// bug to reproduce, probably to force the server to process a request
// without a trailing blank line.
const time_t client_read_timeout_sec = 1;
svr.set_read_timeout(client_read_timeout_sec + 1, 0);
svr.set_read_timeout(std::chrono::seconds(client_read_timeout_sec + 1));
bool listen_thread_ok = false;
thread t = thread([&] { listen_thread_ok = svr.listen(HOST, PORT); });
while (!svr.is_running()) {
@@ -3270,7 +3391,8 @@ TEST(ServerStopTest, StopServerWithChunkedTransmission) {
DataSink &sink) {
char buffer[27];
auto size = static_cast<size_t>(sprintf(buffer, "data:%ld\n\n", offset));
sink.write(buffer, size);
auto ret = sink.write(buffer, size);
EXPECT_TRUE(ret);
std::this_thread::sleep_for(std::chrono::seconds(1));
return true;
});
@@ -3405,7 +3527,8 @@ TEST(ExceptionTest, ThrowExceptionInHandler) {
auto res = cli.Get("/hi");
ASSERT_TRUE(res);
EXPECT_EQ(500, res->status);
ASSERT_FALSE(res->has_header("EXCEPTION_WHAT"));
ASSERT_TRUE(res->has_header("EXCEPTION_WHAT"));
EXPECT_EQ("exception...", res->get_header_value("EXCEPTION_WHAT"));
svr.stop();
listen_thread.join();
@@ -3434,7 +3557,7 @@ TEST(KeepAliveTest, ReadTimeout) {
Client cli("localhost", PORT);
cli.set_keep_alive(true);
cli.set_read_timeout(1);
cli.set_read_timeout(std::chrono::seconds(1));
auto resa = cli.Get("/a");
ASSERT_TRUE(!resa);
@@ -3450,6 +3573,44 @@ TEST(KeepAliveTest, ReadTimeout) {
ASSERT_FALSE(svr.is_running());
}
TEST(ClientProblemDetectionTest, ContentProvider) {
Server svr;
size_t content_length = 1024 * 1024;
svr.Get("/hi", [&](const Request & /*req*/, Response &res) {
res.set_content_provider(
content_length, "text/plain",
[&](size_t offset, size_t length, DataSink &sink) {
auto out_len = std::min(length, static_cast<size_t>(1024));
std::string out(out_len, '@');
sink.write(out.data(), out_len);
return offset < 4096;
},
[](bool success) { ASSERT_FALSE(success); });
});
auto listen_thread = std::thread([&svr]() { svr.listen("localhost", PORT); });
while (!svr.is_running()) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
// Give GET time to get a few messages.
std::this_thread::sleep_for(std::chrono::seconds(1));
Client cli("localhost", PORT);
auto res = cli.Get("/hi", [&](const char * /*data*/, size_t /*data_length*/) {
return false;
});
ASSERT_FALSE(res);
svr.stop();
listen_thread.join();
ASSERT_FALSE(svr.is_running());
}
TEST(ErrorHandlerWithContentProviderTest, ErrorHandler) {
Server svr;
@@ -3483,6 +3644,118 @@ TEST(ErrorHandlerWithContentProviderTest, ErrorHandler) {
ASSERT_FALSE(svr.is_running());
}
TEST(GetWithParametersTest, GetWithParameters) {
Server svr;
svr.Get("/", [&](const Request &req, Response &res) {
auto text = req.get_param_value("hello");
res.set_content(text, "text/plain");
});
auto listen_thread = std::thread([&svr]() { svr.listen("localhost", PORT); });
while (!svr.is_running()) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
std::this_thread::sleep_for(std::chrono::seconds(1));
Client cli("localhost", PORT);
Params params;
params.emplace("hello", "world");
auto res = cli.Get("/", params, Headers{});
ASSERT_TRUE(res);
EXPECT_EQ(200, res->status);
EXPECT_EQ("world", res->body);
svr.stop();
listen_thread.join();
ASSERT_FALSE(svr.is_running());
}
TEST(GetWithParametersTest, GetWithParameters2) {
Server svr;
svr.Get("/", [&](const Request &req, Response &res) {
auto text = req.get_param_value("hello");
res.set_content(text, "text/plain");
});
auto listen_thread = std::thread([&svr]() { svr.listen("localhost", PORT); });
while (!svr.is_running()) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
std::this_thread::sleep_for(std::chrono::seconds(1));
Client cli("localhost", PORT);
Params params;
params.emplace("hello", "world");
std::string body;
auto res = cli.Get("/", params, Headers{},
[&](const char *data, size_t data_length) {
body.append(data, data_length);
return true;
});
ASSERT_TRUE(res);
EXPECT_EQ(200, res->status);
EXPECT_EQ("world", body);
svr.stop();
listen_thread.join();
ASSERT_FALSE(svr.is_running());
}
TEST(ClientDefaultHeadersTest, DefaultHeaders) {
Client cli("httpbin.org");
cli.set_default_headers({make_range_header({{1, 10}})});
cli.set_connection_timeout(5);
{
auto res = cli.Get("/range/32");
ASSERT_TRUE(res);
EXPECT_EQ("bcdefghijk", res->body);
EXPECT_EQ(206, res->status);
}
{
auto res = cli.Get("/range/32");
ASSERT_TRUE(res);
EXPECT_EQ("bcdefghijk", res->body);
EXPECT_EQ(206, res->status);
}
}
TEST(ServerDefaultHeadersTest, DefaultHeaders) {
Server svr;
svr.set_default_headers({{"Hello", "World"}});
svr.Get("/", [&](const Request & /*req*/, Response &res) {
res.set_content("ok", "text/plain");
});
auto listen_thread = std::thread([&svr]() { svr.listen("localhost", PORT); });
while (!svr.is_running()) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
std::this_thread::sleep_for(std::chrono::seconds(1));
Client cli("localhost", PORT);
auto res = cli.Get("/");
ASSERT_TRUE(res);
EXPECT_EQ(200, res->status);
EXPECT_EQ("ok", res->body);
EXPECT_EQ("World", res->get_header_value("Hello"));
svr.stop();
listen_thread.join();
ASSERT_FALSE(svr.is_running());
}
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
TEST(KeepAliveTest, ReadTimeoutSSL) {
SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE);
@@ -3508,7 +3781,7 @@ TEST(KeepAliveTest, ReadTimeoutSSL) {
SSLClient cli("localhost", PORT);
cli.enable_server_certificate_verification(false);
cli.set_keep_alive(true);
cli.set_read_timeout(1);
cli.set_read_timeout(std::chrono::seconds(1));
auto resa = cli.Get("/a");
ASSERT_TRUE(!resa);
@@ -3733,6 +4006,7 @@ TEST(SSLClientTest, WildcardHostNameMatch) {
cli.set_ca_cert_path(CA_CERT_FILE);
cli.enable_server_certificate_verification(true);
cli.set_follow_location(true);
auto res = cli.Get("/");
ASSERT_TRUE(res);
@@ -3963,7 +4237,6 @@ TEST(NoSSLSupport, SimpleInterface) {
}
#endif
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
TEST(InvalidScheme, SimpleInterface) {
ASSERT_ANY_THROW(Client cli("scheme://yahoo.com"));
}
@@ -3973,6 +4246,19 @@ TEST(NoScheme, SimpleInterface) {
ASSERT_TRUE(cli.is_valid());
}
TEST(SendAPI, SimpleInterface) {
Client cli("http://yahoo.com");
Request req;
req.method = "GET";
req.path = "/";
auto res = cli.send(req);
ASSERT_TRUE(res);
EXPECT_EQ(301, res->status);
}
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
TEST(YahooRedirectTest2, SimpleInterface) {
Client cli("http://yahoo.com");