mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-10-12 10:22:39 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
25d72bf881 | ||
|
|
9d5b5297cc | ||
|
|
462884bebb | ||
|
|
b1cc24b795 | ||
|
|
f0eb55b327 | ||
|
|
6dc285b5ca | ||
|
|
07e614eef7 | ||
|
|
916b2a8fd3 | ||
|
|
869f5bb279 | ||
|
|
3e21338f82 | ||
|
|
37bb3c6a77 | ||
|
|
d4ab2fa0e6 | ||
|
|
72d3f4896a | ||
|
|
5e6f973b99 | ||
|
|
7ed77b02ad | ||
|
|
127a64d5a0 | ||
|
|
caa31aafda | ||
|
|
dae318495f | ||
|
|
305a7abcb9 |
@@ -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
|
||||||
-----------------
|
-----------------
|
||||||
|
|||||||
+58
-7
@@ -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 *compressed_data_chunk, size_t compressed_data_size) {
|
/*last=*/true,
|
||||||
compressed_data.insert(compressed_data.size(), compressed_data_chunk, compressed_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 *decompressed_data_chunk, size_t decompressed_data_chunk_size) {
|
[&](const char *decompressed_data_chunk,
|
||||||
decompressed_data.insert(decompressed_data.size(), decompressed_data_chunk, decompressed_data_chunk_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));
|
||||||
@@ -4974,5 +4982,48 @@ 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
|
||||||
|
|
||||||
|
|||||||
+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