Skip to content

Commit f07bffe

Browse files
committed
Add HTTP client implementation with logging for chat API
- Implemented a new HTTP client in send_with_httplib.cpp using the httplib library. - Added a logger function to log request and response details, including headers. - Created a main function to send a POST request to the chat API with a sample message. - Included error handling for the HTTP response.
1 parent 5472e95 commit f07bffe

File tree

2 files changed

+78
-4
lines changed

2 files changed

+78
-4
lines changed

httplib.h

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7246,9 +7246,54 @@ inline ssize_t detail::BodyReader::read(char *buf, size_t len) {
72467246
return n;
72477247
}
72487248

7249-
// TODO: Chunked transfer encoding (Phase 2.3 extension)
7250-
// For now, return error for chunked
7251-
return -1;
7249+
// Chunked transfer encoding
7250+
// If no data remaining in current chunk, read next chunk header
7251+
while (current_chunk_remaining == 0) {
7252+
// Read chunk size line
7253+
const size_t line_buf_size = 32;
7254+
char line_buf[line_buf_size];
7255+
stream_line_reader line_reader(*stream, line_buf, line_buf_size);
7256+
7257+
if (!line_reader.getline()) {
7258+
eof = true;
7259+
return 0;
7260+
}
7261+
7262+
// Skip empty lines (CRLF between chunks)
7263+
if (line_reader.size() <= 2 && (strcmp(line_reader.ptr(), "\r\n") == 0 ||
7264+
strcmp(line_reader.ptr(), "\n") == 0)) {
7265+
continue;
7266+
}
7267+
7268+
// Parse chunk size (hex)
7269+
char *end_ptr;
7270+
auto chunk_size = std::strtoul(line_reader.ptr(), &end_ptr, 16);
7271+
if (end_ptr == line_reader.ptr() || chunk_size == ULONG_MAX) {
7272+
return -1; // Parse error
7273+
}
7274+
7275+
if (chunk_size == 0) {
7276+
// Final chunk
7277+
eof = true;
7278+
return 0;
7279+
}
7280+
7281+
current_chunk_remaining = chunk_size;
7282+
}
7283+
7284+
// Read from current chunk
7285+
auto to_read = (std::min)(len, current_chunk_remaining);
7286+
auto n = stream->read(buf, to_read);
7287+
7288+
if (n <= 0) {
7289+
eof = true;
7290+
return n;
7291+
}
7292+
7293+
current_chunk_remaining -= static_cast<size_t>(n);
7294+
bytes_read += static_cast<size_t>(n);
7295+
7296+
return n;
72527297
}
72537298

72547299
namespace detail {

test/test20.cc

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -812,7 +812,8 @@ class OpenStreamDirectTest : public ::testing::Test {
812812
svr_.Get("/chunked", [](const httplib::Request &, httplib::Response &res) {
813813
res.set_chunked_content_provider(
814814
"text/plain", [](size_t offset, httplib::DataSink &sink) {
815-
if (offset < 3) {
815+
// Send "chunk" 3 times (offset 0, 5, 10)
816+
if (offset < 15) {
816817
sink.write("chunk", 5);
817818
return true;
818819
}
@@ -897,3 +898,31 @@ TEST_F(OpenStreamDirectTest, ConnectionError) {
897898
EXPECT_FALSE(handle.is_valid());
898899
EXPECT_NE(httplib::Error::Success, handle.error);
899900
}
901+
902+
TEST_F(OpenStreamDirectTest, ChunkedResponse) {
903+
httplib::Client cli("127.0.0.1", 8787);
904+
905+
auto handle = cli.open_stream_direct("/chunked");
906+
ASSERT_TRUE(handle.is_valid());
907+
EXPECT_TRUE(handle.body_reader_.chunked);
908+
909+
auto body = handle.read_all();
910+
// Server sends "chunk" 3 times
911+
EXPECT_EQ("chunkchunkchunk", body);
912+
}
913+
914+
TEST_F(OpenStreamDirectTest, ChunkedResponseInPieces) {
915+
httplib::Client cli("127.0.0.1", 8787);
916+
917+
auto handle = cli.open_stream_direct("/chunked");
918+
ASSERT_TRUE(handle.is_valid());
919+
920+
std::string result;
921+
char buf[3]; // Small buffer to force multiple reads
922+
ssize_t n;
923+
while ((n = handle.read(buf, sizeof(buf))) > 0) {
924+
result.append(buf, static_cast<size_t>(n));
925+
}
926+
927+
EXPECT_EQ("chunkchunkchunk", result);
928+
}

0 commit comments

Comments
 (0)