Skip to content

Commit ee4eb8d

Browse files
committed
Merge branch 'fix-100-continue' of github.com:solarispika/cpp-httplib into solarispika-fix-100-continue
2 parents c88b09b + 7196ac8 commit ee4eb8d

File tree

3 files changed

+106
-2
lines changed

3 files changed

+106
-2
lines changed

httplib.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6975,7 +6975,9 @@ Server::process_request(Stream &strm, bool close_connection,
69756975
strm.write_format("HTTP/1.1 %d %s\r\n\r\n", status,
69766976
status_message(status));
69776977
break;
6978-
default: return write_response(strm, close_connection, req, res);
6978+
default:
6979+
connection_closed = true;
6980+
return write_response(strm, true, req, res);
69796981
}
69806982
}
69816983

test/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@ else()
2424
FetchContent_MakeAvailable(gtest)
2525
endif()
2626

27+
find_package(curl REQUIRED)
28+
2729
add_executable(httplib-test test.cc)
2830
target_compile_options(httplib-test PRIVATE "$<$<CXX_COMPILER_ID:MSVC>:/utf-8;/bigobj>")
29-
target_link_libraries(httplib-test PRIVATE httplib GTest::gtest_main)
31+
target_link_libraries(httplib-test PRIVATE httplib GTest::gtest_main CURL::libcurl)
3032
gtest_discover_tests(httplib-test)
3133

3234
file(

test/test.cc

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include <httplib.h>
22
#include <signal.h>
33

4+
#include <curl/curl.h>
45
#include <gtest/gtest.h>
56

67
#include <atomic>
@@ -12,6 +13,7 @@
1213
#include <stdexcept>
1314
#include <thread>
1415
#include <type_traits>
16+
#include <vector>
1517

1618
#define SERVER_CERT_FILE "./cert.pem"
1719
#define SERVER_CERT2_FILE "./cert2.pem"
@@ -7604,3 +7606,101 @@ TEST(DirtyDataRequestTest, HeadFieldValueContains_CR_LF_NUL) {
76047606
Client cli(HOST, PORT);
76057607
cli.Get("/test", {{"Test", "_\n\r_\n\r_"}});
76067608
}
7609+
7610+
TEST(Expect100ContinueTest, ServerClosesConnection) {
7611+
static constexpr char reject[] = "Unauthorized";
7612+
static constexpr char accept[] = "Upload accepted";
7613+
constexpr size_t total_size = 10 * 1024 * 1024 * 1024ULL;
7614+
7615+
Server svr;
7616+
7617+
svr.set_expect_100_continue_handler([](const Request &req, Response &res) {
7618+
res.status = StatusCode::Unauthorized_401;
7619+
res.set_content(reject, "text/plain");
7620+
return res.status;
7621+
});
7622+
svr.Post("/", [&](const Request & /*req*/, Response &res) {
7623+
res.set_content(accept, "text/plain");
7624+
});
7625+
7626+
auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
7627+
auto se = detail::scope_exit([&] {
7628+
svr.stop();
7629+
thread.join();
7630+
ASSERT_FALSE(svr.is_running());
7631+
});
7632+
7633+
svr.wait_until_ready();
7634+
7635+
{
7636+
const auto curl = std::unique_ptr<CURL, decltype(&curl_easy_cleanup)>{
7637+
curl_easy_init(), &curl_easy_cleanup};
7638+
ASSERT_NE(curl, nullptr);
7639+
7640+
curl_easy_setopt(curl.get(), CURLOPT_URL, HOST);
7641+
curl_easy_setopt(curl.get(), CURLOPT_PORT, PORT);
7642+
curl_easy_setopt(curl.get(), CURLOPT_POST, 1L);
7643+
auto list = std::unique_ptr<curl_slist, decltype(&curl_slist_free_all)>{
7644+
curl_slist_append(nullptr, "Content-Type: application/octet-stream"),
7645+
&curl_slist_free_all};
7646+
ASSERT_NE(list, nullptr);
7647+
curl_easy_setopt(curl.get(), CURLOPT_HTTPHEADER, list.get());
7648+
7649+
struct read_data {
7650+
size_t read_size;
7651+
size_t total_size;
7652+
} data = {0, total_size};
7653+
using read_callback_t =
7654+
size_t (*)(char *ptr, size_t size, size_t nmemb, void *userdata);
7655+
read_callback_t read_callback = [](char *ptr, size_t size, size_t nmemb,
7656+
void *userdata) -> size_t {
7657+
read_data *data = (read_data *)userdata;
7658+
7659+
if (!userdata || data->read_size >= data->total_size) { return 0; }
7660+
7661+
std::fill_n(ptr, size * nmemb, 'A');
7662+
data->read_size += size * nmemb;
7663+
return size * nmemb;
7664+
};
7665+
curl_easy_setopt(curl.get(), CURLOPT_READDATA, data);
7666+
curl_easy_setopt(curl.get(), CURLOPT_READFUNCTION, read_callback);
7667+
7668+
std::vector<char> buffer;
7669+
curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, &buffer);
7670+
using write_callback_t =
7671+
size_t (*)(char *ptr, size_t size, size_t nmemb, void *userdata);
7672+
write_callback_t write_callback = [](char *ptr, size_t size, size_t nmemb,
7673+
void *userdata) -> size_t {
7674+
std::vector<char> *buffer = (std::vector<char> *)userdata;
7675+
buffer->reserve(buffer->size() + size * nmemb + 1);
7676+
buffer->insert(buffer->end(), (char *)ptr, (char *)ptr + size * nmemb);
7677+
return size * nmemb;
7678+
};
7679+
curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION, write_callback);
7680+
7681+
{
7682+
const auto res = curl_easy_perform(curl.get());
7683+
ASSERT_EQ(res, CURLE_OK);
7684+
}
7685+
7686+
{
7687+
auto response_code = long{};
7688+
const auto res =
7689+
curl_easy_getinfo(curl.get(), CURLINFO_RESPONSE_CODE, &response_code);
7690+
ASSERT_EQ(res, CURLE_OK);
7691+
ASSERT_EQ(response_code, StatusCode::Unauthorized_401);
7692+
}
7693+
7694+
{
7695+
auto dl = curl_off_t{};
7696+
const auto res = curl_easy_getinfo(curl.get(), CURLINFO_SIZE_DOWNLOAD_T, &dl);
7697+
ASSERT_EQ(res, CURLE_OK);
7698+
ASSERT_EQ(dl, sizeof reject - 1);
7699+
}
7700+
7701+
{
7702+
buffer.push_back('\0');
7703+
ASSERT_STRCASEEQ(buffer.data(), reject);
7704+
}
7705+
}
7706+
}

0 commit comments

Comments
 (0)