mirror of
https://github.com/yhirose/cpp-httplib
synced 2026-06-08 18:30:49 +00:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d3076f5a70 | |||
| ed129f057f | |||
| eab5ea01d7 | |||
| 3e287b3a26 | |||
| 4f33637b43 | |||
| 698a1e51ec | |||
| 27c0e1186c | |||
| c54c71a3e5 | |||
| 3409c00e6f | |||
| f8ef5fab64 | |||
| 5b397d455d |
+27
-17
@@ -9,6 +9,7 @@
|
||||
* HTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN (default on)
|
||||
* HTTPLIB_REQUIRE_BROTLI (default off)
|
||||
* HTTPLIB_COMPILE (default off)
|
||||
* HTTPLIB_INSTALL (default on)
|
||||
* HTTPLIB_TEST (default off)
|
||||
* BROTLI_USE_STATIC_LIBS - tells Cmake to use the static Brotli libs (only works if you have them installed).
|
||||
* OPENSSL_USE_STATIC_LIBS - tells Cmake to use the static OpenSSL libs (only works if you have them installed).
|
||||
@@ -74,6 +75,10 @@ string(REGEX MATCH "([0-9]+\\.?)+" _httplib_version "${_raw_version_string}")
|
||||
|
||||
project(httplib VERSION ${_httplib_version} LANGUAGES CXX)
|
||||
|
||||
# Lets you disable C++ exception during CMake configure time.
|
||||
# The value is used in the install CMake config file.
|
||||
option(HTTPLIB_NO_EXCEPTIONS "Disable the use of C++ exceptions" OFF)
|
||||
|
||||
# Change as needed to set an OpenSSL minimum version.
|
||||
# This is used in the installed Cmake config file.
|
||||
set(_HTTPLIB_OPENSSL_MIN_VER "1.1.1")
|
||||
@@ -87,6 +92,8 @@ option(HTTPLIB_USE_OPENSSL_IF_AVAILABLE "Uses OpenSSL (if available) to enable H
|
||||
option(HTTPLIB_USE_ZLIB_IF_AVAILABLE "Uses ZLIB (if available) to enable Zlib compression support." ON)
|
||||
# Lets you compile the program as a regular library instead of header-only
|
||||
option(HTTPLIB_COMPILE "If ON, uses a Python script to split the header into a compilable header & source file (requires Python v3)." OFF)
|
||||
# Lets you disable the installation (useful when fetched from another CMake project)
|
||||
option(HTTPLIB_INSTALL "Enables the installation target" ON)
|
||||
# Just setting this variable here for people building in-tree
|
||||
if(HTTPLIB_COMPILE)
|
||||
set(HTTPLIB_IS_COMPILED TRUE)
|
||||
@@ -226,6 +233,7 @@ target_link_libraries(${PROJECT_NAME} ${_INTERFACE_OR_PUBLIC}
|
||||
|
||||
# Set the definitions to enable optional features
|
||||
target_compile_definitions(${PROJECT_NAME} ${_INTERFACE_OR_PUBLIC}
|
||||
$<$<BOOL:${HTTPLIB_NO_EXCEPTIONS}>:CPPHTTPLIB_NO_EXCEPTIONS>
|
||||
$<$<BOOL:${HTTPLIB_IS_USING_BROTLI}>:CPPHTTPLIB_BROTLI_SUPPORT>
|
||||
$<$<BOOL:${HTTPLIB_IS_USING_ZLIB}>:CPPHTTPLIB_ZLIB_SUPPORT>
|
||||
$<$<BOOL:${HTTPLIB_IS_USING_OPENSSL}>:CPPHTTPLIB_OPENSSL_SUPPORT>
|
||||
@@ -262,31 +270,33 @@ else()
|
||||
)
|
||||
endif()
|
||||
|
||||
# Creates the export httplibTargets.cmake
|
||||
# This is strictly what holds compilation requirements
|
||||
# and linkage information (doesn't find deps though).
|
||||
install(TARGETS ${PROJECT_NAME}
|
||||
EXPORT httplibTargets
|
||||
)
|
||||
if(HTTPLIB_INSTALL)
|
||||
# Creates the export httplibTargets.cmake
|
||||
# This is strictly what holds compilation requirements
|
||||
# and linkage information (doesn't find deps though).
|
||||
install(TARGETS ${PROJECT_NAME}
|
||||
EXPORT httplibTargets
|
||||
)
|
||||
|
||||
install(FILES "${_httplib_build_includedir}/httplib.h" TYPE INCLUDE)
|
||||
install(FILES "${_httplib_build_includedir}/httplib.h" TYPE INCLUDE)
|
||||
|
||||
install(FILES
|
||||
install(FILES
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
|
||||
# Install it so it can be used later by the httplibConfig.cmake file.
|
||||
# Put it in the same dir as our config file instead of a global path so we don't potentially stomp on other packages.
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/FindBrotli.cmake"
|
||||
DESTINATION ${_TARGET_INSTALL_CMAKEDIR}
|
||||
)
|
||||
DESTINATION ${_TARGET_INSTALL_CMAKEDIR}
|
||||
)
|
||||
|
||||
# NOTE: This path changes depending on if it's on Windows or Linux
|
||||
install(EXPORT httplibTargets
|
||||
# Puts the targets into the httplib namespace
|
||||
# So this makes httplib::httplib linkable after doing find_package(httplib)
|
||||
NAMESPACE ${PROJECT_NAME}::
|
||||
DESTINATION ${_TARGET_INSTALL_CMAKEDIR}
|
||||
)
|
||||
# NOTE: This path changes depending on if it's on Windows or Linux
|
||||
install(EXPORT httplibTargets
|
||||
# Puts the targets into the httplib namespace
|
||||
# So this makes httplib::httplib linkable after doing find_package(httplib)
|
||||
NAMESPACE ${PROJECT_NAME}::
|
||||
DESTINATION ${_TARGET_INSTALL_CMAKEDIR}
|
||||
)
|
||||
endif()
|
||||
|
||||
if(HTTPLIB_TEST)
|
||||
include(CTest)
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#ifndef CPPHTTPLIB_HTTPLIB_H
|
||||
#define CPPHTTPLIB_HTTPLIB_H
|
||||
|
||||
#define CPPHTTPLIB_VERSION "0.12.3"
|
||||
#define CPPHTTPLIB_VERSION "0.12.6"
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
@@ -172,9 +172,15 @@ using socket_t = SOCKET;
|
||||
#else // not _WIN32
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#ifndef _AIX
|
||||
#if !defined(_AIX) && !defined(__MVS__)
|
||||
#include <ifaddrs.h>
|
||||
#endif
|
||||
#ifdef __MVS__
|
||||
#include <strings.h>
|
||||
#ifndef NI_MAXHOST
|
||||
#define NI_MAXHOST 1025
|
||||
#endif
|
||||
#endif
|
||||
#include <net/if.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
@@ -223,6 +229,7 @@ using socket_t = int;
|
||||
#include <string>
|
||||
#include <sys/stat.h>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
#ifdef _WIN32
|
||||
@@ -1117,6 +1124,7 @@ public:
|
||||
void set_ca_cert_path(const std::string &ca_cert_file_path,
|
||||
const std::string &ca_cert_dir_path = std::string());
|
||||
void set_ca_cert_store(X509_STORE *ca_cert_store);
|
||||
X509_STORE *create_ca_cert_store(const char *ca_cert, std::size_t size);
|
||||
#endif
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
@@ -1497,6 +1505,7 @@ public:
|
||||
const std::string &ca_cert_dir_path = std::string());
|
||||
|
||||
void set_ca_cert_store(X509_STORE *ca_cert_store);
|
||||
void load_ca_cert_store(const char *ca_cert, std::size_t size);
|
||||
|
||||
long get_openssl_verify_result() const;
|
||||
|
||||
@@ -1556,6 +1565,7 @@ public:
|
||||
bool is_valid() const override;
|
||||
|
||||
void set_ca_cert_store(X509_STORE *ca_cert_store);
|
||||
void load_ca_cert_store(const char *ca_cert, std::size_t size);
|
||||
|
||||
long get_openssl_verify_result() const;
|
||||
|
||||
@@ -2804,7 +2814,7 @@ inline bool bind_ip_address(socket_t sock, const std::string &host) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if !defined _WIN32 && !defined ANDROID && !defined _AIX
|
||||
#if !defined _WIN32 && !defined ANDROID && !defined _AIX && !defined __MVS__
|
||||
#define USE_IF2IP
|
||||
#endif
|
||||
|
||||
@@ -5272,7 +5282,6 @@ inline Server &Server::set_logger(Logger logger) {
|
||||
inline Server &
|
||||
Server::set_expect_100_continue_handler(Expect100ContinueHandler handler) {
|
||||
expect_100_continue_handler_ = std::move(handler);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -5925,8 +5934,8 @@ inline void Server::apply_ranges(const Request &req, Response &res,
|
||||
res.headers.erase(it);
|
||||
}
|
||||
|
||||
res.headers.emplace("Content-Type",
|
||||
"multipart/byteranges; boundary=" + boundary);
|
||||
res.set_header("Content-Type",
|
||||
"multipart/byteranges; boundary=" + boundary);
|
||||
}
|
||||
|
||||
auto type = detail::encoding_type(req, res);
|
||||
@@ -6616,32 +6625,32 @@ inline bool ClientImpl::write_request(Stream &strm, Request &req,
|
||||
// Prepare additional headers
|
||||
if (close_connection) {
|
||||
if (!req.has_header("Connection")) {
|
||||
req.headers.emplace("Connection", "close");
|
||||
req.set_header("Connection", "close");
|
||||
}
|
||||
}
|
||||
|
||||
if (!req.has_header("Host")) {
|
||||
if (is_ssl()) {
|
||||
if (port_ == 443) {
|
||||
req.headers.emplace("Host", host_);
|
||||
req.set_header("Host", host_);
|
||||
} else {
|
||||
req.headers.emplace("Host", host_and_port_);
|
||||
req.set_header("Host", host_and_port_);
|
||||
}
|
||||
} else {
|
||||
if (port_ == 80) {
|
||||
req.headers.emplace("Host", host_);
|
||||
req.set_header("Host", host_);
|
||||
} else {
|
||||
req.headers.emplace("Host", host_and_port_);
|
||||
req.set_header("Host", host_and_port_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!req.has_header("Accept")) { req.headers.emplace("Accept", "*/*"); }
|
||||
if (!req.has_header("Accept")) { req.set_header("Accept", "*/*"); }
|
||||
|
||||
#ifndef CPPHTTPLIB_NO_DEFAULT_USER_AGENT
|
||||
if (!req.has_header("User-Agent")) {
|
||||
auto agent = std::string("cpp-httplib/") + CPPHTTPLIB_VERSION;
|
||||
req.headers.emplace("User-Agent", agent);
|
||||
req.set_header("User-Agent", agent);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -6650,23 +6659,23 @@ inline bool ClientImpl::write_request(Stream &strm, Request &req,
|
||||
if (!req.is_chunked_content_provider_) {
|
||||
if (!req.has_header("Content-Length")) {
|
||||
auto length = std::to_string(req.content_length_);
|
||||
req.headers.emplace("Content-Length", length);
|
||||
req.set_header("Content-Length", length);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (req.method == "POST" || req.method == "PUT" ||
|
||||
req.method == "PATCH") {
|
||||
req.headers.emplace("Content-Length", "0");
|
||||
req.set_header("Content-Length", "0");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!req.has_header("Content-Type")) {
|
||||
req.headers.emplace("Content-Type", "text/plain");
|
||||
req.set_header("Content-Type", "text/plain");
|
||||
}
|
||||
|
||||
if (!req.has_header("Content-Length")) {
|
||||
auto length = std::to_string(req.body.size());
|
||||
req.headers.emplace("Content-Length", length);
|
||||
req.set_header("Content-Length", length);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6734,12 +6743,10 @@ inline std::unique_ptr<Response> ClientImpl::send_with_content_provider(
|
||||
ContentProvider content_provider,
|
||||
ContentProviderWithoutLength content_provider_without_length,
|
||||
const std::string &content_type, Error &error) {
|
||||
if (!content_type.empty()) {
|
||||
req.headers.emplace("Content-Type", content_type);
|
||||
}
|
||||
if (!content_type.empty()) { req.set_header("Content-Type", content_type); }
|
||||
|
||||
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
|
||||
if (compress_) { req.headers.emplace("Content-Encoding", "gzip"); }
|
||||
if (compress_) { req.set_header("Content-Encoding", "gzip"); }
|
||||
#endif
|
||||
|
||||
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
|
||||
@@ -6800,10 +6807,9 @@ inline std::unique_ptr<Response> ClientImpl::send_with_content_provider(
|
||||
req.content_provider_ = detail::ContentProviderAdapter(
|
||||
std::move(content_provider_without_length));
|
||||
req.is_chunked_content_provider_ = true;
|
||||
req.headers.emplace("Transfer-Encoding", "chunked");
|
||||
req.set_header("Transfer-Encoding", "chunked");
|
||||
} else {
|
||||
req.body.assign(body, content_length);
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7423,9 +7429,7 @@ inline Result ClientImpl::Delete(const std::string &path,
|
||||
req.headers = headers;
|
||||
req.path = path;
|
||||
|
||||
if (!content_type.empty()) {
|
||||
req.headers.emplace("Content-Type", content_type);
|
||||
}
|
||||
if (!content_type.empty()) { req.set_header("Content-Type", content_type); }
|
||||
req.body.assign(body, content_length);
|
||||
|
||||
return send_(std::move(req));
|
||||
@@ -7575,9 +7579,7 @@ inline void ClientImpl::set_proxy_digest_auth(const std::string &username,
|
||||
proxy_digest_auth_username_ = username;
|
||||
proxy_digest_auth_password_ = password;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
inline void ClientImpl::set_ca_cert_path(const std::string &ca_cert_file_path,
|
||||
const std::string &ca_cert_dir_path) {
|
||||
ca_cert_file_path_ = ca_cert_file_path;
|
||||
@@ -7589,9 +7591,34 @@ inline void ClientImpl::set_ca_cert_store(X509_STORE *ca_cert_store) {
|
||||
ca_cert_store_ = ca_cert_store;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
inline X509_STORE *ClientImpl::create_ca_cert_store(const char *ca_cert,
|
||||
std::size_t size) {
|
||||
auto mem = BIO_new_mem_buf(ca_cert, static_cast<int>(size));
|
||||
if (!mem) return nullptr;
|
||||
|
||||
auto inf = PEM_X509_INFO_read_bio(mem, nullptr, nullptr, nullptr);
|
||||
if (!inf) {
|
||||
BIO_free_all(mem);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto cts = X509_STORE_new();
|
||||
if (cts) {
|
||||
for (auto first = 0, last = sk_X509_INFO_num(inf); first < last; ++first) {
|
||||
auto itmp = sk_X509_INFO_value(inf, first);
|
||||
if (!itmp) { continue; }
|
||||
|
||||
if (itmp->x509) { X509_STORE_add_cert(cts, itmp->x509); }
|
||||
if (itmp->crl) { X509_STORE_add_crl(cts, itmp->crl); }
|
||||
}
|
||||
}
|
||||
|
||||
sk_X509_INFO_pop_free(inf, X509_INFO_free);
|
||||
BIO_free_all(mem);
|
||||
return cts;
|
||||
}
|
||||
|
||||
inline void ClientImpl::enable_server_certificate_verification(bool enabled) {
|
||||
server_certificate_verification_ = enabled;
|
||||
}
|
||||
@@ -7989,6 +8016,11 @@ inline void SSLClient::set_ca_cert_store(X509_STORE *ca_cert_store) {
|
||||
}
|
||||
}
|
||||
|
||||
inline void SSLClient::load_ca_cert_store(const char *ca_cert,
|
||||
std::size_t size) {
|
||||
set_ca_cert_store(ClientImpl::create_ca_cert_store(ca_cert, size));
|
||||
}
|
||||
|
||||
inline long SSLClient::get_openssl_verify_result() const {
|
||||
return verify_result_;
|
||||
}
|
||||
@@ -8754,7 +8786,9 @@ inline void Client::enable_server_certificate_verification(bool enabled) {
|
||||
}
|
||||
#endif
|
||||
|
||||
inline void Client::set_logger(Logger logger) { cli_->set_logger(logger); }
|
||||
inline void Client::set_logger(Logger logger) {
|
||||
cli_->set_logger(std::move(logger));
|
||||
}
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
inline void Client::set_ca_cert_path(const std::string &ca_cert_file_path,
|
||||
@@ -8770,6 +8804,10 @@ inline void Client::set_ca_cert_store(X509_STORE *ca_cert_store) {
|
||||
}
|
||||
}
|
||||
|
||||
inline void Client::load_ca_cert_store(const char *ca_cert, std::size_t size) {
|
||||
set_ca_cert_store(cli_->create_ca_cert_store(ca_cert, size));
|
||||
}
|
||||
|
||||
inline long Client::get_openssl_verify_result() const {
|
||||
if (is_ssl_) {
|
||||
return static_cast<SSLClient &>(*cli_).get_openssl_verify_result();
|
||||
|
||||
+96
-6
@@ -1843,21 +1843,21 @@ protected:
|
||||
|
||||
{
|
||||
const auto &text_value = req.get_file_values("text");
|
||||
EXPECT_EQ(text_value.size(), 1);
|
||||
EXPECT_EQ(1u, text_value.size());
|
||||
auto &text = text_value[0];
|
||||
EXPECT_TRUE(text.filename.empty());
|
||||
EXPECT_EQ("default text", text.content);
|
||||
}
|
||||
{
|
||||
const auto &text1_values = req.get_file_values("multi_text1");
|
||||
EXPECT_EQ(text1_values.size(), 2);
|
||||
EXPECT_EQ(2u, text1_values.size());
|
||||
EXPECT_EQ("aaaaa", text1_values[0].content);
|
||||
EXPECT_EQ("bbbbb", text1_values[1].content);
|
||||
}
|
||||
|
||||
{
|
||||
const auto &file1_values = req.get_file_values("multi_file1");
|
||||
EXPECT_EQ(file1_values.size(), 2);
|
||||
EXPECT_EQ(2u, file1_values.size());
|
||||
auto file1 = file1_values[0];
|
||||
EXPECT_EQ(file1.filename, "hello.txt");
|
||||
EXPECT_EQ(file1.content_type, "text/plain");
|
||||
@@ -3921,9 +3921,10 @@ TEST(ServerStopTest, StopServerWithChunkedTransmission) {
|
||||
res.set_header("Cache-Control", "no-cache");
|
||||
res.set_chunked_content_provider("text/event-stream", [](size_t offset,
|
||||
DataSink &sink) {
|
||||
char buffer[27];
|
||||
auto size = static_cast<size_t>(sprintf(buffer, "data:%zd\n\n", offset));
|
||||
auto ret = sink.write(buffer, size);
|
||||
std::string s = "data:";
|
||||
s += std::to_string(offset);
|
||||
s += "\n\n";
|
||||
auto ret = sink.write(s.data(), s.size());
|
||||
EXPECT_TRUE(ret);
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
return true;
|
||||
@@ -4709,6 +4710,49 @@ TEST(SSLClientTest, ServerCertificateVerification4) {
|
||||
ASSERT_EQ(200, res->status);
|
||||
}
|
||||
|
||||
TEST(SSLClientTest, ServerCertificateVerification5_Online) {
|
||||
std::string cert;
|
||||
detail::read_file(CA_CERT_FILE, cert);
|
||||
|
||||
SSLClient cli("google.com");
|
||||
cli.load_ca_cert_store(cert.data(), cert.size());
|
||||
const auto res = cli.Get("/");
|
||||
ASSERT_TRUE(res);
|
||||
ASSERT_EQ(301, res->status);
|
||||
}
|
||||
|
||||
TEST(SSLClientTest, ServerCertificateVerification6_Online) {
|
||||
// clang-format off
|
||||
static constexpr char cert[] =
|
||||
"GlobalSign Root CA\n"
|
||||
"==================\n"
|
||||
"-----BEGIN CERTIFICATE-----\n"
|
||||
"MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx\n"
|
||||
"GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds\n"
|
||||
"b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV\n"
|
||||
"BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD\n"
|
||||
"VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa\n"
|
||||
"DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc\n"
|
||||
"THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb\n"
|
||||
"Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP\n"
|
||||
"c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX\n"
|
||||
"gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV\n"
|
||||
"HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF\n"
|
||||
"AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj\n"
|
||||
"Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG\n"
|
||||
"j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH\n"
|
||||
"hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC\n"
|
||||
"X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==\n"
|
||||
"-----END CERTIFICATE-----\n";
|
||||
// clang-format on
|
||||
|
||||
SSLClient cli("google.com");
|
||||
cli.load_ca_cert_store(cert, sizeof(cert));
|
||||
const auto res = cli.Get("/");
|
||||
ASSERT_TRUE(res);
|
||||
ASSERT_EQ(301, res->status);
|
||||
}
|
||||
|
||||
TEST(SSLClientTest, WildcardHostNameMatch_Online) {
|
||||
SSLClient cli("www.youtube.com");
|
||||
|
||||
@@ -6116,3 +6160,49 @@ TEST(RedirectTest, RedirectToUrlWithQueryParameters) {
|
||||
EXPECT_EQ("val&key2=val2", res->body);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(VulnerabilityTest, CRLFInjection) {
|
||||
Server svr;
|
||||
|
||||
svr.Post("/test1", [](const Request &/*req*/, Response &res) {
|
||||
res.set_content("Hello 1", "text/plain");
|
||||
});
|
||||
|
||||
svr.Delete("/test2", [](const Request &/*req*/, Response &res) {
|
||||
res.set_content("Hello 2", "text/plain");
|
||||
});
|
||||
|
||||
svr.Put("/test3", [](const Request &/*req*/, Response &res) {
|
||||
res.set_content("Hello 3", "text/plain");
|
||||
});
|
||||
|
||||
svr.Patch("/test4", [](const Request &/*req*/, Response &res) {
|
||||
res.set_content("Hello 4", "text/plain");
|
||||
});
|
||||
|
||||
svr.set_logger([](const Request &req, const Response & /*res*/) {
|
||||
for (const auto &x : req.headers) {
|
||||
auto key = x.first;
|
||||
EXPECT_STRNE("evil", key.c_str());
|
||||
}
|
||||
});
|
||||
|
||||
auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
|
||||
auto se = detail::scope_exit([&] {
|
||||
svr.stop();
|
||||
thread.join();
|
||||
ASSERT_FALSE(svr.is_running());
|
||||
});
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
|
||||
{
|
||||
Client cli(HOST, PORT);
|
||||
|
||||
cli.Post("/test1", "A=B",
|
||||
"application/x-www-form-urlencoded\r\nevil: hello1");
|
||||
cli.Delete("/test2", "A=B", "text/plain\r\nevil: hello2");
|
||||
cli.Put("/test3", "text", "text/plain\r\nevil: hello3");
|
||||
cli.Patch("/test4", "content", "text/plain\r\nevil: hello4");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user