Skip to content

Commit 12a7783

Browse files
committed
Additional code cleanup.
1 parent 3782ee9 commit 12a7783

5 files changed

Lines changed: 36 additions & 106 deletions

File tree

libs/internal/tests/curl_requester_test.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ TEST_F(CurlRequesterTest, HandlesCustomHeaders) {
220220
server_->SetHandler(
221221
[](http::request<http::string_body> const& req)
222222
-> http::response<http::string_body> {
223-
auto header_it = req.find("X-Custom-Header");
223+
const auto header_it = req.find("X-Custom-Header");
224224
EXPECT_NE(req.end(), header_it);
225225
if (header_it != req.end()) {
226226
EXPECT_EQ("custom-value", header_it->value());
@@ -275,7 +275,7 @@ TEST_F(CurlRequesterTest, Handles404Status) {
275275
});
276276

277277
net::io_context client_ioc;
278-
CurlRequester requester(
278+
const CurlRequester requester(
279279
client_ioc.get_executor(),
280280
launchdarkly::config::shared::built::TlsOptions());
281281

@@ -304,8 +304,8 @@ TEST_F(CurlRequesterTest, Handles404Status) {
304304

305305
TEST_F(CurlRequesterTest, HandlesInvalidUrl) {
306306
net::io_context client_ioc;
307-
CurlRequester requester(
308-
client_ioc.get_executor(),
307+
const CurlRequester requester(
308+
client_ioc.get_executor(),
309309
launchdarkly::config::shared::built::TlsOptions());
310310

311311
HttpRequest request("not a valid url", HttpMethod::kGet,

libs/networking/include/launchdarkly/network/curl_multi_manager.hpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,6 @@ using SocketHandle = boost::asio::ip::tcp::socket;
2525
* multi interface with Boost.ASIO. Instead of blocking threads, CURL notifies
2626
* us via callbacks when sockets need attention, and we use ASIO to monitor
2727
* those sockets asynchronously.
28-
*
29-
* Key features:
30-
* - Non-blocking I/O using curl_multi_socket_action
31-
* - Cross-platform socket monitoring via ASIO tcp::socket
32-
* - Timer integration with ASIO steady_timer
33-
* - Thread-safe operation on ASIO executor
3428
*/
3529
class CurlMultiManager : public std::enable_shared_from_this<CurlMultiManager> {
3630
public:
@@ -135,7 +129,6 @@ class CurlMultiManager : public std::enable_shared_from_this<CurlMultiManager> {
135129
};
136130

137131
boost::asio::any_io_executor executor_;
138-
// CURLM* multi_handle_;
139132
std::unique_ptr<CURLM, decltype(&curl_multi_cleanup)> multi_handle_;
140133
boost::asio::steady_timer timer_;
141134

libs/server-sent-events/src/curl_client.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -346,11 +346,6 @@ curl_socket_t CurlClient::OpenSocketCallback(void* clientp,
346346
curl_socket_t sockfd = socket(address->family, address->socktype,
347347
address->protocol);
348348

349-
// Store it so we can close it during shutdown
350-
if (sockfd != CURL_SOCKET_BAD) {
351-
context->set_curl_socket(sockfd);
352-
}
353-
354349
return sockfd;
355350
}
356351

libs/server-sent-events/src/curl_client.hpp

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -68,27 +68,26 @@ class CurlClient final : public Client,
6868
/**
6969
* The request context represents the state required by the executing CURL
7070
* request. Not directly including the shared data in the CurlClient allows
71-
* for easy seperation of its lifetime from that of the CURL client. This
71+
* for easy separation of its lifetime from that of the CURL client. This
7272
* facilitates destruction of the CurlClient being used to stop in-progress
7373
* requests.
7474
*
75-
* Also the CURL client can be destructed and pending tasks will still
75+
* The CURL client can be destructed and pending tasks will still
7676
* have a valid RequestContext and will detect the shutdown.
7777
*/
7878
class RequestContext {
7979
// Only items used by both the curl thread and the executor/main
8080
// thread need to be mutex protected.
8181
std::mutex mutex_;
8282
std::atomic<bool> shutting_down_;
83-
std::atomic<curl_socket_t> curl_socket_;
8483
// End mutex protected items.
8584
std::optional<Callbacks> callbacks_;
8685

8786
public:
8887
// SSE parser using common parser from parser.hpp
8988
using ParserBody = detail::EventBody<std::function<void(Event)>>;
90-
std::unique_ptr<typename ParserBody::value_type> parser_body;
91-
std::unique_ptr<typename ParserBody::reader> parser_reader;
89+
std::unique_ptr<ParserBody::value_type> parser_body;
90+
std::unique_ptr<ParserBody::reader> parser_reader;
9291

9392
// Track last event ID for reconnection (separate from parser state)
9493
std::optional<std::string> last_event_id;
@@ -165,34 +164,20 @@ class CurlClient final : public Client,
165164
return shutting_down_;
166165
}
167166

168-
void set_curl_socket(curl_socket_t curl_socket) {
169-
std::lock_guard lock(mutex_);
170-
curl_socket_ = curl_socket;
171-
}
172-
173167
void shutdown() {
174168
std::lock_guard lock(mutex_);
175169
shutting_down_ = true;
176-
if (curl_socket_ != CURL_SOCKET_BAD) {
177-
#ifdef _WIN32
178-
closesocket(curl_socket_);
179-
#else
180-
close(curl_socket_);
181-
#endif
182-
}
183170
}
184171

185-
186172
RequestContext(std::string url,
187173
http::request<http::string_body> req,
188174
std::optional<std::chrono::milliseconds> connect_timeout,
189175
std::optional<std::chrono::milliseconds> read_timeout,
190176
std::optional<std::chrono::milliseconds> write_timeout,
191177
std::optional<std::string> custom_ca_file,
192178
std::optional<std::string> proxy_url,
193-
bool skip_verify_peer
179+
const bool skip_verify_peer
194180
) : shutting_down_(false),
195-
curl_socket_(CURL_SOCKET_BAD),
196181
last_download_amount(0),
197182
req(std::move(req)),
198183
url(std::move(url)),

libs/server-sent-events/tests/curl_client_test.cpp

Lines changed: 27 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
#include "mock_sse_server.hpp"
99

1010
#include <boost/asio/io_context.hpp>
11-
#include <boost/asio/steady_timer.hpp>
1211

1312
#include <atomic>
1413
#include <chrono>
@@ -23,12 +22,13 @@ using namespace std::chrono_literals;
2322
namespace {
2423

2524
// C++17-compatible latch replacement
25+
// https://en.cppreference.com/w/cpp/thread/latch.html
2626
class SimpleLatch {
2727
public:
28-
explicit SimpleLatch(std::size_t count) : count_(count) {}
28+
explicit SimpleLatch(const std::size_t count) : count_(count) {}
2929

3030
void count_down() {
31-
std::lock_guard<std::mutex> lock(mutex_);
31+
std::lock_guard lock(mutex_);
3232
if (count_ > 0) {
3333
--count_;
3434
}
@@ -37,7 +37,7 @@ class SimpleLatch {
3737

3838
template<typename Rep, typename Period>
3939
bool wait_for(std::chrono::duration<Rep, Period> timeout) {
40-
std::unique_lock<std::mutex> lock(mutex_);
40+
std::unique_lock lock(mutex_);
4141
return cv_.wait_for(lock, timeout, [this] { return count_ == 0; });
4242
}
4343

@@ -82,12 +82,6 @@ class EventCollector {
8282
return errors_;
8383
}
8484

85-
void clear() {
86-
std::lock_guard<std::mutex> lock(mutex_);
87-
events_.clear();
88-
errors_.clear();
89-
}
90-
9185
private:
9286
mutable std::mutex mutex_;
9387
std::condition_variable cv_;
@@ -456,7 +450,7 @@ TEST(CurlClientTest, Handles500Error) {
456450
std::atomic<int> connection_attempts{0};
457451

458452
auto handler = [&](auto const&, auto send_response, auto, auto) {
459-
connection_attempts++;
453+
++connection_attempts;
460454
http::response<http::string_body> res{http::status::internal_server_error, 11};
461455
res.body() = "Error";
462456
res.prepare_payload();
@@ -585,7 +579,7 @@ TEST(CurlClientTest, HandlesImmediateClose) {
585579
std::atomic<int> connection_attempts{0};
586580

587581
auto handler = [&](auto const&, auto, auto, auto close) {
588-
connection_attempts++;
582+
++connection_attempts;
589583
close(); // Immediately close without sending headers
590584
};
591585

@@ -664,59 +658,26 @@ TEST(CurlClientTest, RespectsReadTimeout) {
664658
EXPECT_TRUE(shutdown_latch.wait_for(100ms));
665659
}
666660

667-
// Resource management tests
668-
669-
TEST(CurlClientTest, NoThreadLeaksAfterMultipleConnections) {
670-
// This test verifies that threads are properly joined and not leaked
671-
MockSSEServer server;
672-
auto port = server.start(TestHandlers::simple_event("test"));
673-
674-
IoContextRunner runner;
675-
676-
// Create and destroy multiple clients
677-
for (int i = 0; i < 5; i++) {
678-
EventCollector collector;
679-
680-
auto client = Builder(runner.context().get_executor(), "http://localhost:" + std::to_string(port))
681-
.receiver([&](Event e) { collector.add_event(std::move(e)); })
682-
.build();
683-
684-
client->async_connect();
685-
ASSERT_TRUE(collector.wait_for_events(1));
686-
687-
SimpleLatch shutdown_latch(1);
688-
client->async_shutdown([&] { shutdown_latch.count_down(); });
689-
EXPECT_TRUE(shutdown_latch.wait_for(5000ms));
690-
691-
// Client should be cleanly destroyed here
692-
}
693-
694-
// If threads weren't properly joined, we'd likely see issues here
695-
// The test passing indicates proper resource cleanup
696-
}
697-
698661
TEST(CurlClientTest, DestructorCleansUpProperly) {
699-
MockSSEServer server;
700-
auto port = server.start([](auto const&, auto send_response, auto send_sse_event, auto) {
701-
http::response<http::string_body> res{http::status::ok, 11};
702-
res.set(http::field::content_type, "text/event-stream");
703-
res.chunked(true);
704-
send_response(res);
705-
706-
// Keep sending events
707-
for (int i = 0; i < 100; i++) {
708-
send_sse_event(SSEFormatter::event("event " + std::to_string(i)));
709-
std::this_thread::sleep_for(10ms);
710-
}
711-
});
712-
713-
IoContextRunner runner;
714-
EventCollector collector;
715-
716662
{
663+
MockSSEServer server;
664+
auto port = server.start([](auto const&, auto send_response, auto send_sse_event, auto) {
665+
http::response<http::string_body> res{http::status::ok, 11};
666+
res.set(http::field::content_type, "text/event-stream");
667+
res.chunked(true);
668+
send_response(res);
669+
670+
// Keep sending events
671+
for (int i = 0; i < 100; i++) {
672+
send_sse_event(SSEFormatter::event("event " + std::to_string(i)));
673+
std::this_thread::sleep_for(10ms);
674+
}
675+
});
676+
EventCollector collector;
677+
IoContextRunner runner;
717678
auto client = Builder(runner.context().get_executor(), "http://localhost:" + std::to_string(port))
718-
.receiver([&](Event e) { collector.add_event(std::move(e)); })
719-
.build();
679+
.receiver([&](Event e) { collector.add_event(std::move(e)); })
680+
.build();
720681

721682
client->async_connect();
722683
ASSERT_TRUE(collector.wait_for_events(1));
@@ -728,8 +689,6 @@ TEST(CurlClientTest, DestructorCleansUpProperly) {
728689
// Test passing indicates proper cleanup in destructor
729690
}
730691

731-
// Edge case tests
732-
733692
TEST(CurlClientTest, HandlesEmptyEventData) {
734693
MockSSEServer server;
735694
auto port = server.start([](auto const&, auto send_response, auto send_sse_event, auto close) {
@@ -798,9 +757,9 @@ TEST(CurlClientTest, HandlesEventWithOnlyType) {
798757

799758
TEST(CurlClientTest, HandlesRapidEvents) {
800759
MockSSEServer server;
801-
const int num_events = 100;
760+
constexpr int num_events = 100;
802761

803-
auto port = server.start([num_events](auto const&, auto send_response, auto send_sse_event, auto close) {
762+
auto port = server.start([](auto const&, auto send_response, auto send_sse_event, auto close) {
804763
http::response<http::string_body> res{http::status::ok, 11};
805764
res.set(http::field::content_type, "text/event-stream");
806765
res.chunked(true);
@@ -832,14 +791,12 @@ TEST(CurlClientTest, HandlesRapidEvents) {
832791
EXPECT_TRUE(shutdown_latch.wait_for(5000ms));
833792
}
834793

835-
// Shutdown-specific tests - critical for preventing crashes/hangs in user applications
836-
837794
TEST(CurlClientTest, ShutdownDuringBackoffDelay) {
838795
// This ensures clean shutdown during backoff/retry wait period
839796
std::atomic<int> connection_attempts{0};
840797

841798
auto handler = [&](auto const&, auto send_response, auto, auto) {
842-
connection_attempts++;
799+
++connection_attempts;
843800
// Return 500 to trigger backoff
844801
http::response<http::string_body> res{http::status::internal_server_error, 11};
845802
res.body() = "Error";
@@ -906,7 +863,7 @@ TEST(CurlClientTest, ShutdownDuringDataReception) {
906863

907864
IoContextRunner runner;
908865
// Shared ptr to prevent handling events during destruction.
909-
std::shared_ptr<EventCollector> collector = std::make_shared<EventCollector>();
866+
auto collector = std::make_shared<EventCollector>();
910867

911868
auto client = Builder(runner.context().get_executor(), "http://localhost:" + std::to_string(port))
912869
.receiver([collector, &client_received_some](Event e) {

0 commit comments

Comments
 (0)