From 66b6be499da228be4ee29fc8afa6a7f63356ba38 Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 10 Jul 2019 15:08:06 +0200 Subject: [PATCH] Client now supports event streams with \r\n line endings in addition to regular \n --- client_http.hpp | 6 ++--- tests/io_test.cpp | 57 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/client_http.hpp b/client_http.hpp index dc8aca5..f3006d9 100644 --- a/client_http.hpp +++ b/client_http.hpp @@ -719,7 +719,7 @@ namespace SimpleWeb { void read_server_sent_event(const std::shared_ptr &session, const std::shared_ptr &events_streambuf) { session->connection->set_timeout(); - asio::async_read_until(*session->connection->socket, *events_streambuf, "\n\n", [this, session, events_streambuf](const error_code &ec, std::size_t /*bytes_transferred*/) { + asio::async_read_until(*session->connection->socket, *events_streambuf, HeaderEndMatch(), [this, session, events_streambuf](const error_code &ec, std::size_t /*bytes_transferred*/) { session->connection->cancel_timeout(); auto lock = session->connection->handler_runner->continue_lock(); if(!lock) @@ -733,8 +733,8 @@ namespace SimpleWeb { std::istream istream(events_streambuf.get()); std::ostream ostream(&session->response->streambuf); std::string line; - while(std::getline(istream, line) && !line.empty()) { - ostream.write(line.data(), static_cast(line.size())); + while(std::getline(istream, line) && !line.empty() && !(line.back() == '\r' && line.size() == 1)) { + ostream.write(line.data(), static_cast(line.size() - (line.back() == '\r' ? 1 : 0))); ostream.put('\n'); } diff --git a/tests/io_test.cpp b/tests/io_test.cpp index e29c30a..8a139b7 100644 --- a/tests/io_test.cpp +++ b/tests/io_test.cpp @@ -142,7 +142,7 @@ int main() { response->write("6\r\nSimple\r\n3\r\nWeb\r\nE\r\n in\r\n\r\nchunks.\r\n0\r\n\r\n", {{"Transfer-Encoding", "chunked"}}); }; - server.resource["^/event-stream$"]["GET"] = [](shared_ptr response, shared_ptr /*request*/) { + server.resource["^/event-stream1$"]["GET"] = [](shared_ptr response, shared_ptr /*request*/) { thread work_thread([response] { response->close_connection_after_response = true; // Unspecified content length @@ -167,6 +167,31 @@ int main() { work_thread.detach(); }; + server.resource["^/event-stream2$"]["GET"] = [](shared_ptr response, shared_ptr /*request*/) { + thread work_thread([response] { + response->close_connection_after_response = true; // Unspecified content length + + // Send header + promise header_error; + response->write({{"Content-Type", "text/event-stream"}}); + response->send([&header_error](const SimpleWeb::error_code &ec) { + header_error.set_value(static_cast(ec)); + }); + ASSERT(!header_error.get_future().get()); + + *response << "data: 1\r\n\r\n"; + promise error; + response->send([&error](const SimpleWeb::error_code &ec) { + error.set_value(static_cast(ec)); + }); + ASSERT(!error.get_future().get()); + + // Write result + *response << "data: 2\r\n\r\n"; + }); + work_thread.detach(); + }; + server.resource["^/session-close$"]["GET"] = [](shared_ptr response, shared_ptr /*request*/) { response->close_connection_after_response = true; // Unspecified content length response->write("test", {{"Session", "close"}}); @@ -371,7 +396,35 @@ int main() { { vector calls(4, 0); std::size_t call_num = 0; - client.request("GET", "/event-stream", [&calls, &call_num](shared_ptr response, const SimpleWeb::error_code &ec) { + client.request("GET", "/event-stream1", [&calls, &call_num](shared_ptr response, const SimpleWeb::error_code &ec) { + calls.at(call_num) = 1; + if(call_num == 0) { + ASSERT(response->content.string().empty()); + ASSERT(!ec); + } + else if(call_num == 1) { + ASSERT(response->content.string() == "data: 1\n"); + ASSERT(!ec); + } + else if(call_num == 2) { + ASSERT(response->content.string() == "data: 2\n"); + ASSERT(!ec); + } + else if(call_num == 3) { + ASSERT(response->content.string().empty()); + ASSERT(ec == SimpleWeb::error::eof); + } + ++call_num; + }); + SimpleWeb::restart(*client.io_service); + client.io_service->run(); + for(auto call : calls) + ASSERT(call); + } + { + vector calls(4, 0); + std::size_t call_num = 0; + client.request("GET", "/event-stream2", [&calls, &call_num](shared_ptr response, const SimpleWeb::error_code &ec) { calls.at(call_num) = 1; if(call_num == 0) { ASSERT(response->content.string().empty());