Skip to content

Commit 21e3815

Browse files
committed
Backported test server updates from 1.10.x
1 parent 743ca57 commit 21e3815

13 files changed

+536
-479
lines changed

CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -301,8 +301,8 @@ if(CPR_BUILD_TESTS)
301301
clear_variable(DESTINATION CMAKE_CXX_CLANG_TIDY BACKUP CMAKE_CXX_CLANG_TIDY_BKP)
302302

303303
FetchContent_Declare(mongoose
304-
URL https://github.com/cesanta/mongoose/archive/6.18.tar.gz
305-
URL_HASH SHA256=f5c10346abc9c72f7cac7885d853ca064fb09aad57580433941a8fd7a3543769 # the hash for 6.18.tar.gz
304+
URL https://github.com/cesanta/mongoose/archive/7.7.tar.gz
305+
URL_HASH SHA256=4e5733dae31c3a81156af63ca9aa3a6b9b736547f21f23c3ab2f8e3f1ecc16c0 # the hash for 7.7.tar.gz
306306
USES_TERMINAL_DOWNLOAD TRUE) # <---- This is needed only for Ninja to show download progress
307307
# We can not use FetchContent_MakeAvailable, since we need to patch mongoose to use CMake
308308
if (NOT mongoose_POPULATED)

cmake/mongoose.CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@ target_include_directories(mongoose PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
77

88
if(ENABLE_SSL_TESTS)
99
# Enable mongoose SSL
10-
target_compile_definitions(mongoose PUBLIC MG_ENABLE_SSL)
10+
target_compile_definitions(mongoose PUBLIC MG_ENABLE_OPENSSL)
1111
target_link_libraries(mongoose PRIVATE OpenSSL::SSL)
1212
endif()

test/abstractServer.cpp

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@ void AbstractServer::Stop() {
2323
server_stop_cv.wait(server_lock);
2424
}
2525

26-
static void EventHandler(mg_connection* conn, int event, void* event_data) {
26+
static void EventHandler(mg_connection* conn, int event, void* event_data, void* context) {
2727
switch (event) {
28-
case MG_EV_RECV:
29-
case MG_EV_SEND:
28+
case MG_EV_READ:
29+
case MG_EV_WRITE:
3030
/** Do nothing. Just for housekeeping. **/
3131
break;
3232
case MG_EV_POLL:
@@ -36,22 +36,20 @@ static void EventHandler(mg_connection* conn, int event, void* event_data) {
3636
/** Do nothing. Just for housekeeping. **/
3737
break;
3838
case MG_EV_ACCEPT:
39-
/** Do nothing. Just for housekeeping. **/
39+
/* Initialize HTTPS connection if Server is an HTTPS Server */
40+
static_cast<AbstractServer*>(context)->acceptConnection(conn);
4041
break;
4142
case MG_EV_CONNECT:
4243
/** Do nothing. Just for housekeeping. **/
4344
break;
44-
case MG_EV_TIMER:
45-
/** Do nothing. Just for housekeeping. **/
46-
break;
4745

4846
case MG_EV_HTTP_CHUNK: {
4947
/** Do nothing. Just for housekeeping. **/
5048
} break;
5149

52-
case MG_EV_HTTP_REQUEST: {
53-
AbstractServer* server = static_cast<AbstractServer*>(conn->mgr->user_data);
54-
server->OnRequest(conn, static_cast<http_message*>(event_data));
50+
case MG_EV_HTTP_MSG: {
51+
AbstractServer* server = static_cast<AbstractServer*>(context);
52+
server->OnRequest(conn, static_cast<mg_http_message*>(event_data));
5553
} break;
5654

5755
default:
@@ -69,10 +67,12 @@ void AbstractServer::Run() {
6967

7068
// Main server loop:
7169
while (should_run) {
72-
mg_mgr_poll(&mgr, 1000);
70+
// NOLINTNEXTLINE (cppcoreguidelines-avoid-magic-numbers)
71+
mg_mgr_poll(&mgr, 100);
7372
}
7473

7574
// Shutdown and cleanup:
75+
timer_args.clear();
7676
mg_mgr_free(&mgr);
7777

7878
// Notify the main thread that we have shut down everything:
@@ -110,4 +110,34 @@ std::string AbstractServer::Base64Decode(const std::string& in) {
110110
return out;
111111
}
112112

113+
// Sends error similar like in mongoose 6 method mg_http_send_error
114+
// https://github.com/cesanta/mongoose/blob/6.18/mongoose.c#L7081-L7089
115+
void AbstractServer::SendError(mg_connection* conn, int code, std::string& reason) {
116+
std::string headers{"Content-Type: text/plain\r\nConnection: close\r\n"};
117+
mg_http_reply(conn, code, headers.c_str(), reason.c_str());
118+
}
119+
120+
// Checks whether a pointer to a connection is still managed by a mg_mgr.
121+
// This check tells whether it is still possible to send a message via the given connection
122+
// Note that it is still possible that the pointer of an old connection object may be reused by mongoose.
123+
// In this case, the active connection might refer to a different connection than the one the caller refers to
124+
bool AbstractServer::IsConnectionActive(mg_mgr* mgr, mg_connection* conn) {
125+
mg_connection* c{mgr->conns};
126+
while (c) {
127+
if (c == conn) {
128+
return true;
129+
}
130+
c = c->next;
131+
}
132+
return false;
133+
}
134+
135+
uint16_t AbstractServer::GetRemotePort(const mg_connection* conn) {
136+
return (conn->rem.port >> 8) | (conn->rem.port << 8);
137+
}
138+
139+
uint16_t AbstractServer::GetLocalPort(const mg_connection* conn) {
140+
return (conn->loc.port >> 8) | (conn->loc.port << 8);
141+
}
142+
113143
} // namespace cpr

test/abstractServer.hpp

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,22 @@
1212
#include "mongoose.h"
1313

1414
namespace cpr {
15+
16+
// Helper struct for functions using timers to simulate slow connections
17+
struct TimerArg {
18+
mg_mgr* mgr;
19+
mg_connection* connection;
20+
unsigned long connection_id;
21+
mg_timer timer;
22+
unsigned counter;
23+
24+
explicit TimerArg(mg_mgr* m, mg_connection* c, mg_timer&& t) : mgr{m}, connection{c}, connection_id{0}, timer{t}, counter{0} {}
25+
26+
~TimerArg() {
27+
mg_timer_free(&mgr->timers, &timer);
28+
}
29+
};
30+
1531
class AbstractServer : public testing::Environment {
1632
public:
1733
~AbstractServer() override = default;
@@ -25,22 +41,29 @@ class AbstractServer : public testing::Environment {
2541
virtual std::string GetBaseUrl() = 0;
2642
virtual uint16_t GetPort() = 0;
2743

28-
virtual void OnRequest(mg_connection* conn, http_message* msg) = 0;
44+
virtual void acceptConnection(mg_connection* conn) = 0;
45+
virtual void OnRequest(mg_connection* conn, mg_http_message* msg) = 0;
2946

3047
private:
3148
std::shared_ptr<std::thread> serverThread{nullptr};
3249
std::mutex server_mutex;
3350
std::condition_variable server_start_cv;
3451
std::condition_variable server_stop_cv;
3552
std::atomic<bool> should_run{false};
36-
mg_mgr mgr{};
3753

3854
void Run();
3955

4056
protected:
41-
virtual mg_connection* initServer(mg_mgr* mgr, MG_CB(mg_event_handler_t event_handler, void* user_data)) = 0;
57+
mg_mgr mgr{};
58+
std::vector<std::unique_ptr<TimerArg>> timer_args{};
59+
virtual mg_connection* initServer(mg_mgr* mgr, mg_event_handler_t event_handler) = 0;
4260

4361
static std::string Base64Decode(const std::string& in);
62+
static void SendError(mg_connection* conn, int code, std::string& reason);
63+
static bool IsConnectionActive(mg_mgr* mgr, mg_connection* conn);
64+
65+
static uint16_t GetRemotePort(const mg_connection* conn);
66+
static uint16_t GetLocalPort(const mg_connection* conn);
4467
};
4568
} // namespace cpr
4669

test/callback_tests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -863,7 +863,7 @@ TEST(CallbackDataTests, CallbackHeaderFunctionCancelTest) {
863863

864864
TEST(CallbackDataTests, CallbackHeaderFunctionTextTest) {
865865
Url url{server->GetBaseUrl() + "/url_post.html"};
866-
std::vector<std::string> expected_headers{"HTTP/1.1 201 OK\r\n", "Content-Type: application/json\r\n", "\r\n"};
866+
std::vector<std::string> expected_headers{"HTTP/1.1 201 Created\r\n", "Content-Type: application/json\r\n", "\r\n"};
867867
std::set<std::string> response_headers;
868868
Post(url, HeaderCallback{[&response_headers](const std::string& header, intptr_t /*userdata*/) -> bool {
869869
response_headers.insert(header);

test/error_tests.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,14 +60,14 @@ TEST(ErrorTests, ChronoConnectTimeoutFailure) {
6060
TEST(ErrorTests, LowSpeedTimeFailure) {
6161
Url url{server->GetBaseUrl() + "/low_speed.html"};
6262
Response response = cpr::Get(url, cpr::LowSpeed{1000, 1});
63-
EXPECT_EQ(0, response.status_code);
63+
// Do not check for the HTTP status code, since libcurl always provides the status code of the header if it was received
6464
EXPECT_EQ(ErrorCode::OPERATION_TIMEDOUT, response.error.code);
6565
}
6666

6767
TEST(ErrorTests, LowSpeedBytesFailure) {
6868
Url url{server->GetBaseUrl() + "/low_speed_bytes.html"};
6969
Response response = cpr::Get(url, cpr::LowSpeed{1000, 1});
70-
EXPECT_EQ(0, response.status_code);
70+
// Do not check for the HTTP status code, since libcurl always provides the status code of the header if it was received
7171
EXPECT_EQ(ErrorCode::OPERATION_TIMEDOUT, response.error.code);
7272
}
7373

0 commit comments

Comments
 (0)