Skip to content

Commit b176669

Browse files
etrclaude
andcommitted
websocket_handler: dedupe send_ping / send_pong scaffolding
Both functions had byte-identical bodies aside from the MHD encode function called (MHD_websocket_encode_ping vs _pong, identical signatures). Extract a shared `send_control_frame` static helper parameterised on the encoder via decltype so the function-pointer type matches MHD's `enum MHD_WEBSOCKET_STATUS` return without restating it; a static_assert pins the ping/pong signature invariant in case MHD ever diverges them. Caught by `make lint-duplication` at CPD_MIN_TOKENS=50 (7 lines / 59 tokens). Below the day-1 gate at 100 tokens, but worth fixing since the dedup is trivial and the original was a verbatim copy. Build is unchanged on platforms without HAVE_WEBSOCKET (whole block is still under the existing #ifdef). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 9527b98 commit b176669

1 file changed

Lines changed: 26 additions & 10 deletions

File tree

src/websocket_handler.cpp

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <cstdint>
3434
#include <cstring>
3535
#include <string>
36+
#include <type_traits>
3637

3738
namespace httpserver {
3839

@@ -92,24 +93,39 @@ void websocket_session::send_binary(const void* data, size_t len) {
9293
}
9394
}
9495

95-
void websocket_session::send_ping(const std::string& payload) {
96-
if (!valid) return;
96+
// Shared scaffolding for the ping/pong control frames: both MHD encode
97+
// functions share an identical signature and the surrounding
98+
// encode -> send_all -> free dance is byte-identical between them.
99+
// Type the encoder via decltype so we pick up MHD's exact return type
100+
// (`enum MHD_WEBSOCKET_STATUS`, not `int`) without restating it.
101+
using control_frame_encoder = decltype(&MHD_websocket_encode_ping);
102+
static_assert(std::is_same_v<control_frame_encoder, decltype(&MHD_websocket_encode_pong)>,
103+
"MHD_websocket_encode_ping and _pong must share a signature "
104+
"for send_control_frame's function-pointer parameter to be valid.");
105+
106+
static void send_control_frame(control_frame_encoder encode,
107+
struct MHD_WebSocketStream* ws_stream,
108+
MHD_socket sock,
109+
const std::string& payload,
110+
bool& valid) {
97111
char* frame = nullptr;
98112
size_t frame_len = 0;
99-
if (MHD_websocket_encode_ping(ws_stream, payload.c_str(), payload.size(), &frame, &frame_len) == MHD_WEBSOCKET_STATUS_OK) {
100-
if (!send_all(static_cast<MHD_socket>(sock), frame, frame_len)) valid = false;
113+
if (encode(ws_stream, payload.c_str(), payload.size(), &frame, &frame_len) == MHD_WEBSOCKET_STATUS_OK) {
114+
if (!send_all(sock, frame, frame_len)) valid = false;
101115
MHD_websocket_free(ws_stream, frame);
102116
}
103117
}
104118

119+
void websocket_session::send_ping(const std::string& payload) {
120+
if (!valid) return;
121+
send_control_frame(&MHD_websocket_encode_ping, ws_stream,
122+
static_cast<MHD_socket>(sock), payload, valid);
123+
}
124+
105125
void websocket_session::send_pong(const std::string& payload) {
106126
if (!valid) return;
107-
char* frame = nullptr;
108-
size_t frame_len = 0;
109-
if (MHD_websocket_encode_pong(ws_stream, payload.c_str(), payload.size(), &frame, &frame_len) == MHD_WEBSOCKET_STATUS_OK) {
110-
if (!send_all(static_cast<MHD_socket>(sock), frame, frame_len)) valid = false;
111-
MHD_websocket_free(ws_stream, frame);
112-
}
127+
send_control_frame(&MHD_websocket_encode_pong, ws_stream,
128+
static_cast<MHD_socket>(sock), payload, valid);
113129
}
114130

115131
void websocket_session::close(uint16_t code, const std::string& reason) {

0 commit comments

Comments
 (0)