mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-10-12 10:22:39 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d92c314466 | ||
|
|
b747fb111d | ||
|
|
7e0a0b2d0c | ||
|
|
362d064afa | ||
|
|
1bd88de2e5 | ||
|
|
0b541ffebc | ||
|
|
106be19c3e | ||
|
|
25d72bf881 | ||
|
|
9d5b5297cc | ||
|
|
462884bebb | ||
|
|
b1cc24b795 | ||
|
|
f0eb55b327 | ||
|
|
6dc285b5ca | ||
|
|
07e614eef7 | ||
|
|
916b2a8fd3 | ||
|
|
869f5bb279 | ||
|
|
3e21338f82 | ||
|
|
37bb3c6a77 | ||
|
|
d4ab2fa0e6 | ||
|
|
72d3f4896a | ||
|
|
5e6f973b99 | ||
|
|
7ed77b02ad | ||
|
|
127a64d5a0 | ||
|
|
caa31aafda | ||
|
|
dae318495f | ||
|
|
305a7abcb9 | ||
|
|
219d13b718 | ||
|
|
df20c27696 | ||
|
|
a5a62768c0 | ||
|
|
4001637beb | ||
|
|
47044c05a8 | ||
|
|
a449d82723 | ||
|
|
fee8e97b4e | ||
|
|
72d9ed4056 | ||
|
|
1be1b3a86d |
+4
-15
@@ -100,6 +100,7 @@ if (BUILD_SHARED_LIBS AND WIN32 AND HTTPLIB_COMPILE)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Threads needed for <thread> on some systems, and for <pthread.h> on Linux
|
# Threads needed for <thread> on some systems, and for <pthread.h> on Linux
|
||||||
|
set(THREADS_PREFER_PTHREAD_FLAG true)
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
# Since Cmake v3.11, Crypto & SSL became optional when not specified as COMPONENTS.
|
# Since Cmake v3.11, Crypto & SSL became optional when not specified as COMPONENTS.
|
||||||
if(HTTPLIB_REQUIRE_OPENSSL)
|
if(HTTPLIB_REQUIRE_OPENSSL)
|
||||||
@@ -160,7 +161,7 @@ if(HTTPLIB_COMPILE)
|
|||||||
ERROR_VARIABLE _httplib_split_error
|
ERROR_VARIABLE _httplib_split_error
|
||||||
)
|
)
|
||||||
if(_httplib_split_error)
|
if(_httplib_split_error)
|
||||||
message(FATAL_ERROR "Failed when trying to split Cpp-httplib with the Python script.\n${_httplib_split_error}")
|
message(FATAL_ERROR "Failed when trying to split cpp-httplib with the Python script.\n${_httplib_split_error}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# split.py puts output in "out"
|
# split.py puts output in "out"
|
||||||
@@ -187,19 +188,9 @@ endif()
|
|||||||
# Only useful if building in-tree, versus using it from an installation.
|
# Only useful if building in-tree, versus using it from an installation.
|
||||||
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
|
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
|
||||||
|
|
||||||
# Might be missing some, but this list is somewhat comprehensive
|
# Require C++11
|
||||||
target_compile_features(${PROJECT_NAME} ${_INTERFACE_OR_PUBLIC}
|
target_compile_features(${PROJECT_NAME} ${_INTERFACE_OR_PUBLIC}
|
||||||
cxx_std_11
|
cxx_std_11
|
||||||
cxx_nullptr
|
|
||||||
cxx_lambdas
|
|
||||||
cxx_override
|
|
||||||
cxx_defaulted_functions
|
|
||||||
cxx_attribute_deprecated
|
|
||||||
cxx_auto_type
|
|
||||||
cxx_decltype
|
|
||||||
cxx_deleted_functions
|
|
||||||
cxx_range_for
|
|
||||||
cxx_sizeof_member
|
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(${PROJECT_NAME} ${_INTERFACE_OR_PUBLIC}
|
target_include_directories(${PROJECT_NAME} ${_INTERFACE_OR_PUBLIC}
|
||||||
@@ -274,11 +265,9 @@ endif()
|
|||||||
# and linkage information (doesn't find deps though).
|
# and linkage information (doesn't find deps though).
|
||||||
install(TARGETS ${PROJECT_NAME}
|
install(TARGETS ${PROJECT_NAME}
|
||||||
EXPORT httplibTargets
|
EXPORT httplibTargets
|
||||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|
||||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
install(FILES "${_httplib_build_includedir}/httplib.h" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
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}Config.cmake"
|
||||||
|
|||||||
@@ -7,12 +7,12 @@ A C++11 single-file header-only cross platform HTTP/HTTPS library.
|
|||||||
|
|
||||||
It's extremely easy to setup. Just include the **httplib.h** file in your code!
|
It's extremely easy to setup. Just include the **httplib.h** file in your code!
|
||||||
|
|
||||||
NOTE: This is a multi-threaded 'blocking' HTTP library. If you are looking for a 'non-blocking' library, this is not the one that you want.
|
NOTE: This library uses 'blocking' socket I/O. If you are looking for a library with 'non-blocking' socket I/O, this is not the one that you want.
|
||||||
|
|
||||||
Simple examples
|
Simple examples
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
#### Server
|
#### Server (Multi-threaded)
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
#define CPPHTTPLIB_OPENSSL_SUPPORT
|
#define CPPHTTPLIB_OPENSSL_SUPPORT
|
||||||
@@ -212,15 +212,23 @@ svr.set_error_handler([](const auto& req, auto& res) {
|
|||||||
The exception handler gets called if a user routing handler throws an error.
|
The exception handler gets called if a user routing handler throws an error.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
svr.set_exception_handler([](const auto& req, auto& res, std::exception &e) {
|
svr.set_exception_handler([](const auto& req, auto& res, std::exception_ptr ep) {
|
||||||
res.status = 500;
|
|
||||||
auto fmt = "<h1>Error 500</h1><p>%s</p>";
|
auto fmt = "<h1>Error 500</h1><p>%s</p>";
|
||||||
char buf[BUFSIZ];
|
char buf[BUFSIZ];
|
||||||
snprintf(buf, sizeof(buf), fmt, e.what());
|
try {
|
||||||
|
std::rethrow_exception(ep);
|
||||||
|
} catch (std::exception &e) {
|
||||||
|
snprintf(buf, sizeof(buf), fmt, e.what());
|
||||||
|
} catch (...) { // See the following NOTE
|
||||||
|
snprintf(buf, sizeof(buf), fmt, "Unknown Exception");
|
||||||
|
}
|
||||||
res.set_content(buf, "text/html");
|
res.set_content(buf, "text/html");
|
||||||
|
res.status = 500;
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
NOTE: if you don't provide the `catch (...)` block for a rethrown exception pointer, an uncaught exception will end up causing the server crash. Be careful!
|
||||||
|
|
||||||
### Pre routing handler
|
### Pre routing handler
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
@@ -435,7 +443,7 @@ int main(void)
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
auto err = res.error();
|
auto err = res.error();
|
||||||
...
|
std::cout << "HTTP error: " << httplib::to_string(err) << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -468,7 +476,9 @@ enum Error {
|
|||||||
SSLConnection,
|
SSLConnection,
|
||||||
SSLLoadingCerts,
|
SSLLoadingCerts,
|
||||||
SSLServerVerification,
|
SSLServerVerification,
|
||||||
UnsupportedMultipartBoundaryChars
|
UnsupportedMultipartBoundaryChars,
|
||||||
|
Compression,
|
||||||
|
ConnectionTimeout,
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -799,12 +809,12 @@ Include `httplib.h` before `Windows.h` or include `Windows.h` by defining `WIN32
|
|||||||
|
|
||||||
Note: cpp-httplib officially supports only the latest Visual Studio. It might work with former versions of Visual Studio, but I can no longer verify it. Pull requests are always welcome for the older versions of Visual Studio unless they break the C++11 conformance.
|
Note: cpp-httplib officially supports only the latest Visual Studio. It might work with former versions of Visual Studio, but I can no longer verify it. Pull requests are always welcome for the older versions of Visual Studio unless they break the C++11 conformance.
|
||||||
|
|
||||||
Note: Windows 8 or lower and Cygwin on Windows are not supported.
|
Note: Windows 8 or lower, Visual Studio 2013 or lower, and Cygwin on Windows are not supported.
|
||||||
|
|
||||||
License
|
License
|
||||||
-------
|
-------
|
||||||
|
|
||||||
MIT license (© 2021 Yuji Hirose)
|
MIT license (© 2022 Yuji Hirose)
|
||||||
|
|
||||||
Special Thanks To
|
Special Thanks To
|
||||||
-----------------
|
-----------------
|
||||||
|
|||||||
+2
-3
@@ -19,7 +19,6 @@ project(
|
|||||||
# Check just in case downstream decides to edit the source
|
# Check just in case downstream decides to edit the source
|
||||||
# and add a project version
|
# and add a project version
|
||||||
version = meson.project_version()
|
version = meson.project_version()
|
||||||
python3 = find_program('python3')
|
|
||||||
if version == 'undefined'
|
if version == 'undefined'
|
||||||
cxx = meson.get_compiler('cpp')
|
cxx = meson.get_compiler('cpp')
|
||||||
version = cxx.get_define('CPPHTTPLIB_VERSION',
|
version = cxx.get_define('CPPHTTPLIB_VERSION',
|
||||||
@@ -28,8 +27,6 @@ if version == 'undefined'
|
|||||||
assert(version != '', 'failed to get version from httplib.h')
|
assert(version != '', 'failed to get version from httplib.h')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
message('cpp-httplib version ' + version)
|
|
||||||
|
|
||||||
deps = [dependency('threads')]
|
deps = [dependency('threads')]
|
||||||
args = []
|
args = []
|
||||||
|
|
||||||
@@ -64,6 +61,8 @@ endif
|
|||||||
cpp_httplib_dep = dependency('', required: false)
|
cpp_httplib_dep = dependency('', required: false)
|
||||||
|
|
||||||
if get_option('cpp-httplib_compile')
|
if get_option('cpp-httplib_compile')
|
||||||
|
python3 = find_program('python3')
|
||||||
|
|
||||||
httplib_ch = custom_target(
|
httplib_ch = custom_target(
|
||||||
'split',
|
'split',
|
||||||
input: 'httplib.h',
|
input: 'httplib.h',
|
||||||
|
|||||||
+1
-1
@@ -5,5 +5,5 @@
|
|||||||
option('cpp-httplib_openssl', type: 'feature', value: 'auto', description: 'Enable OpenSSL support')
|
option('cpp-httplib_openssl', type: 'feature', value: 'auto', description: 'Enable OpenSSL support')
|
||||||
option('cpp-httplib_zlib', type: 'feature', value: 'auto', description: 'Enable zlib support')
|
option('cpp-httplib_zlib', type: 'feature', value: 'auto', description: 'Enable zlib support')
|
||||||
option('cpp-httplib_brotli', type: 'feature', value: 'auto', description: 'Enable Brotli support')
|
option('cpp-httplib_brotli', type: 'feature', value: 'auto', description: 'Enable Brotli support')
|
||||||
option('cpp-httplib_compile', type: 'boolean', value: false, description: 'Split the header into a compilable header & source file')
|
option('cpp-httplib_compile', type: 'boolean', value: false, description: 'Split the header into a compilable header & source file (requires python3)')
|
||||||
option('cpp-httplib_test', type: 'boolean', value: false, description: 'Build tests')
|
option('cpp-httplib_test', type: 'boolean', value: false, description: 'Build tests')
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
CXX = clang++
|
CXX = clang++
|
||||||
CXXFLAGS = -g -std=c++11 -I. -Wall -Wextra -Wtype-limits -Wconversion # -fno-exceptions -DCPPHTTPLIB_NO_EXCEPTIONS -fsanitize=address
|
CXXFLAGS = -g -std=c++11 -I. -Wall -Wextra -Wtype-limits -Wconversion -Wshadow # -fno-exceptions -DCPPHTTPLIB_NO_EXCEPTIONS -fsanitize=address
|
||||||
|
|
||||||
PREFIX = /usr/local
|
PREFIX = /usr/local
|
||||||
#PREFIX = $(shell brew --prefix)
|
#PREFIX = $(shell brew --prefix)
|
||||||
|
|||||||
Binary file not shown.
File diff suppressed because one or more lines are too long
+200
-10
@@ -109,11 +109,11 @@ TEST(SplitTest, ParseQueryString) {
|
|||||||
detail::split(s.c_str(), s.c_str() + s.size(), '&',
|
detail::split(s.c_str(), s.c_str() + s.size(), '&',
|
||||||
[&](const char *b, const char *e) {
|
[&](const char *b, const char *e) {
|
||||||
string key, val;
|
string key, val;
|
||||||
detail::split(b, e, '=', [&](const char *b, const char *e) {
|
detail::split(b, e, '=', [&](const char *b2, const char *e2) {
|
||||||
if (key.empty()) {
|
if (key.empty()) {
|
||||||
key.assign(b, e);
|
key.assign(b2, e2);
|
||||||
} else {
|
} else {
|
||||||
val.assign(b, e);
|
val.assign(b2, e2);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
dic.emplace(key, val);
|
dic.emplace(key, val);
|
||||||
@@ -1249,8 +1249,11 @@ TEST(ExceptionHandlerTest, ContentLength) {
|
|||||||
Server svr;
|
Server svr;
|
||||||
|
|
||||||
svr.set_exception_handler([](const Request & /*req*/, Response &res,
|
svr.set_exception_handler([](const Request & /*req*/, Response &res,
|
||||||
std::exception &e) {
|
std::exception_ptr ep) {
|
||||||
EXPECT_EQ("abc", std::string(e.what()));
|
EXPECT_FALSE(ep == nullptr);
|
||||||
|
try {
|
||||||
|
std::rethrow_exception(ep);
|
||||||
|
} catch (std::exception &e) { EXPECT_EQ("abc", std::string(e.what())); }
|
||||||
res.status = 500;
|
res.status = 500;
|
||||||
res.set_content("abcdefghijklmnopqrstuvwxyz",
|
res.set_content("abcdefghijklmnopqrstuvwxyz",
|
||||||
"text/html"); // <= Content-Length still 13 at this point
|
"text/html"); // <= Content-Length still 13 at this point
|
||||||
@@ -3015,8 +3018,10 @@ TEST(GzipDecompressor, ChunkedDecompression) {
|
|||||||
httplib::detail::gzip_compressor compressor;
|
httplib::detail::gzip_compressor compressor;
|
||||||
bool result = compressor.compress(
|
bool result = compressor.compress(
|
||||||
data.data(), data.size(),
|
data.data(), data.size(),
|
||||||
/*last=*/true, [&](const char *data, size_t size) {
|
/*last=*/true,
|
||||||
compressed_data.insert(compressed_data.size(), data, size);
|
[&](const char *compressed_data_chunk, size_t compressed_data_size) {
|
||||||
|
compressed_data.insert(compressed_data.size(), compressed_data_chunk,
|
||||||
|
compressed_data_size);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
ASSERT_TRUE(result);
|
ASSERT_TRUE(result);
|
||||||
@@ -3035,8 +3040,11 @@ TEST(GzipDecompressor, ChunkedDecompression) {
|
|||||||
std::min(compressed_data.size() - chunk_begin, chunk_size);
|
std::min(compressed_data.size() - chunk_begin, chunk_size);
|
||||||
bool result = decompressor.decompress(
|
bool result = decompressor.decompress(
|
||||||
compressed_data.data() + chunk_begin, current_chunk_size,
|
compressed_data.data() + chunk_begin, current_chunk_size,
|
||||||
[&](const char *data, size_t size) {
|
[&](const char *decompressed_data_chunk,
|
||||||
decompressed_data.insert(decompressed_data.size(), data, size);
|
size_t decompressed_data_chunk_size) {
|
||||||
|
decompressed_data.insert(decompressed_data.size(),
|
||||||
|
decompressed_data_chunk,
|
||||||
|
decompressed_data_chunk_size);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
ASSERT_TRUE(result);
|
ASSERT_TRUE(result);
|
||||||
@@ -4172,7 +4180,7 @@ protected:
|
|||||||
res.set_content("Hello World!", "text/plain");
|
res.set_content("Hello World!", "text/plain");
|
||||||
});
|
});
|
||||||
|
|
||||||
t_ = thread([&]() { ASSERT_TRUE(svr_.listen(nullptr, 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));
|
||||||
@@ -4742,6 +4750,77 @@ TEST(SendAPI, SimpleInterface_Online) {
|
|||||||
EXPECT_EQ(301, res->status);
|
EXPECT_EQ(301, res->status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(ClientImplMethods, GetSocketTest) {
|
||||||
|
httplib::Server svr;
|
||||||
|
svr.Get( "/", [&](const httplib::Request& /*req*/, httplib::Response& res) {
|
||||||
|
res.status = 200;
|
||||||
|
});
|
||||||
|
|
||||||
|
auto thread = std::thread([&]() { svr.listen("127.0.0.1", 3333); });
|
||||||
|
|
||||||
|
while (!svr.is_running()) {
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
httplib::Client cli("http://127.0.0.1:3333");
|
||||||
|
cli.set_keep_alive(true);
|
||||||
|
|
||||||
|
// Use the behavior of cpp-httplib of opening the connection
|
||||||
|
// only when the first request happens. If that changes,
|
||||||
|
// this test would be obsolete.
|
||||||
|
|
||||||
|
EXPECT_EQ(cli.socket(), INVALID_SOCKET);
|
||||||
|
|
||||||
|
// This also implicitly tests the server. But other tests would fail much
|
||||||
|
// earlier than this one to be considered.
|
||||||
|
|
||||||
|
auto res = cli.Get("/");
|
||||||
|
ASSERT_TRUE(res);
|
||||||
|
|
||||||
|
EXPECT_EQ(200, res->status);
|
||||||
|
ASSERT_TRUE(cli.socket() != INVALID_SOCKET);
|
||||||
|
}
|
||||||
|
|
||||||
|
svr.stop();
|
||||||
|
thread.join();
|
||||||
|
ASSERT_FALSE(svr.is_running());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disabled due to out-of-memory problem on GitHub Actions
|
||||||
|
#ifdef _WIN64
|
||||||
|
TEST(ServerLargeContentTest, DISABLED_SendLargeContent) {
|
||||||
|
// allocate content size larger than 2GB in memory
|
||||||
|
const size_t content_size = 2LL * 1024LL * 1024LL * 1024LL + 1LL;
|
||||||
|
char *content = (char *)malloc(content_size);
|
||||||
|
ASSERT_TRUE(content);
|
||||||
|
|
||||||
|
Server svr;
|
||||||
|
svr.Get("/foo", [=](const httplib::Request &req, httplib::Response &resp) {
|
||||||
|
resp.set_content(content, content_size, "application/octet-stream");
|
||||||
|
});
|
||||||
|
|
||||||
|
auto listen_thread = std::thread([&svr]() { svr.listen(HOST, 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(HOST, PORT);
|
||||||
|
auto res = cli.Get("/foo");
|
||||||
|
ASSERT_TRUE(res);
|
||||||
|
EXPECT_EQ(200, res->status);
|
||||||
|
EXPECT_EQ(content_size, res->body.length());
|
||||||
|
|
||||||
|
free(content);
|
||||||
|
svr.stop();
|
||||||
|
listen_thread.join();
|
||||||
|
ASSERT_FALSE(svr.is_running());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||||
TEST(YahooRedirectTest2, SimpleInterface_Online) {
|
TEST(YahooRedirectTest2, SimpleInterface_Online) {
|
||||||
Client cli("http://yahoo.com");
|
Client cli("http://yahoo.com");
|
||||||
@@ -4940,5 +5019,116 @@ TEST(MultipartFormDataTest, LargeData) {
|
|||||||
svr.stop();
|
svr.stop();
|
||||||
t.join();
|
t.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(MultipartFormDataTest, WithPreamble) {
|
||||||
|
Server svr;
|
||||||
|
svr.Post("/post", [&](const Request & /*req*/, Response &res) {
|
||||||
|
res.set_content("ok", "text/plain");
|
||||||
|
});
|
||||||
|
|
||||||
|
thread t = thread([&] { svr.listen(HOST, PORT); });
|
||||||
|
while (!svr.is_running()) {
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string body =
|
||||||
|
"This is the preamble. It is to be ignored, though it\r\n"
|
||||||
|
"is a handy place for composition agents to include an\r\n"
|
||||||
|
"explanatory note to non-MIME conformant readers.\r\n"
|
||||||
|
"\r\n"
|
||||||
|
"\r\n"
|
||||||
|
"--simple boundary\r\n"
|
||||||
|
"Content-Disposition: form-data; name=\"field1\"\r\n"
|
||||||
|
"\r\n"
|
||||||
|
"value1\r\n"
|
||||||
|
"--simple boundary\r\n"
|
||||||
|
"Content-Disposition: form-data; name=\"field2\"; "
|
||||||
|
"filename=\"example.txt\"\r\n"
|
||||||
|
"\r\n"
|
||||||
|
"value2\r\n"
|
||||||
|
"--simple boundary--\r\n"
|
||||||
|
"This is the epilogue. It is also to be ignored.\r\n";
|
||||||
|
|
||||||
|
std::string content_type =
|
||||||
|
R"(multipart/form-data; boundary="simple boundary")";
|
||||||
|
|
||||||
|
Client cli(HOST, PORT);
|
||||||
|
auto res = cli.Post("/post", body, content_type.c_str());
|
||||||
|
|
||||||
|
ASSERT_TRUE(res);
|
||||||
|
EXPECT_EQ(200, res->status);
|
||||||
|
|
||||||
|
svr.stop();
|
||||||
|
t.join();
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
class UnixSocketTest : public ::testing::Test {
|
||||||
|
protected:
|
||||||
|
void TearDown() override {
|
||||||
|
std::remove(pathname_.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void client_GET(const std::string &addr) {
|
||||||
|
httplib::Client cli{addr};
|
||||||
|
cli.set_address_family(AF_UNIX);
|
||||||
|
ASSERT_TRUE(cli.is_valid());
|
||||||
|
|
||||||
|
const auto &result = cli.Get(pattern_);
|
||||||
|
ASSERT_TRUE(result) << "error: " << result.error();
|
||||||
|
|
||||||
|
const auto &resp = result.value();
|
||||||
|
EXPECT_EQ(resp.status, 200);
|
||||||
|
EXPECT_EQ(resp.body, content_);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string pathname_ {"./httplib-server.sock"};
|
||||||
|
const std::string pattern_ {"/hi"};
|
||||||
|
const std::string content_ {"Hello World!"};
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(UnixSocketTest, pathname) {
|
||||||
|
httplib::Server svr;
|
||||||
|
svr.Get(pattern_, [&](const httplib::Request &, httplib::Response &res) {
|
||||||
|
res.set_content(content_, "text/plain");
|
||||||
|
});
|
||||||
|
|
||||||
|
std::thread t {[&] {
|
||||||
|
ASSERT_TRUE(svr.set_address_family(AF_UNIX).listen(pathname_, 80)); }};
|
||||||
|
while (!svr.is_running()) {
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||||
|
}
|
||||||
|
ASSERT_TRUE(svr.is_running());
|
||||||
|
|
||||||
|
client_GET(pathname_);
|
||||||
|
|
||||||
|
svr.stop();
|
||||||
|
t.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
TEST_F(UnixSocketTest, abstract) {
|
||||||
|
constexpr char svr_path[] {"\x00httplib-server.sock"};
|
||||||
|
const std::string abstract_addr {svr_path, sizeof(svr_path) - 1};
|
||||||
|
|
||||||
|
httplib::Server svr;
|
||||||
|
svr.Get(pattern_, [&](const httplib::Request &, httplib::Response &res) {
|
||||||
|
res.set_content(content_, "text/plain");
|
||||||
|
});
|
||||||
|
|
||||||
|
std::thread t {[&] {
|
||||||
|
ASSERT_TRUE(svr.set_address_family(AF_UNIX).listen(abstract_addr, 80)); }};
|
||||||
|
while (!svr.is_running()) {
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||||
|
}
|
||||||
|
ASSERT_TRUE(svr.is_running());
|
||||||
|
|
||||||
|
client_GET(abstract_addr);
|
||||||
|
|
||||||
|
svr.stop();
|
||||||
|
t.join();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif // #ifndef _WIN32
|
||||||
|
|||||||
@@ -116,6 +116,7 @@
|
|||||||
<AdditionalUsingDirectories>
|
<AdditionalUsingDirectories>
|
||||||
</AdditionalUsingDirectories>
|
</AdditionalUsingDirectories>
|
||||||
<SDLCheck>true</SDLCheck>
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Console</SubSystem>
|
<SubSystem>Console</SubSystem>
|
||||||
@@ -158,6 +159,7 @@
|
|||||||
<AdditionalUsingDirectories>
|
<AdditionalUsingDirectories>
|
||||||
</AdditionalUsingDirectories>
|
</AdditionalUsingDirectories>
|
||||||
<SDLCheck>true</SDLCheck>
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Console</SubSystem>
|
<SubSystem>Console</SubSystem>
|
||||||
|
|||||||
+1
-1
@@ -82,7 +82,7 @@ TEST(RedirectTest, YouTubeNoSSLBasic) {
|
|||||||
RedirectProxyText(cli, "/", true);
|
RedirectProxyText(cli, "/", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(RedirectTest, YouTubeNoSSLDigest) {
|
TEST(RedirectTest, DISABLED_YouTubeNoSSLDigest) {
|
||||||
Client cli("youtube.com");
|
Client cli("youtube.com");
|
||||||
RedirectProxyText(cli, "/", false);
|
RedirectProxyText(cli, "/", false);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user