Fix SSE firing order
When sending last-event-id, the previous events were being received
before the the header was completed. This is because the open handler is
being called before the connect call was in place, so you get:
Connection starts
open handler called
sendEvent() called from open handler
sendSSEHeader() called.
This results in a spec violation.
Tested:
curl --user root:0penBmc -vvv -s --no-buffer -k -N -H 'Accept:
text/event-stream' -H 'Last-Event-Id: 4' -X GET
https://localhost:8000/redfish/v1/EventService/SSE
Now succeeds, and wireshark dumps show the header is being sent
correctly. Note that previously this command would fail unless http0.9
header was set.
Unit test coverage for this path without last-event-id passes.
Change-Id: I44bb6eedbcbdc727b257646ec55e808157231f75
Signed-off-by: Ed Tanous <etanous@nvidia.com>
diff --git a/http/server_sent_event.hpp b/http/server_sent_event.hpp
index 906c326..72d0684 100644
--- a/http/server_sent_event.hpp
+++ b/http/server_sent_event.hpp
@@ -71,13 +71,16 @@
void start(const Request& req)
{
- if (!openHandler)
- {
- BMCWEB_LOG_CRITICAL("No open handler???");
- return;
- }
- openHandler(*this, req);
- sendSSEHeader();
+ BMCWEB_LOG_DEBUG("Starting SSE connection");
+
+ res.set(boost::beast::http::field::content_type, "text/event-stream");
+ boost::beast::http::response_serializer<BodyType>& serial =
+ serializer.emplace(res);
+
+ boost::beast::http::async_write_header(
+ adaptor, serial,
+ std::bind_front(&ConnectionImpl::sendSSEHeaderCallback, this,
+ shared_from_this(), req));
}
void close(const std::string_view msg) override
@@ -92,21 +95,8 @@
boost::beast::get_lowest_layer(adaptor).close();
}
- void sendSSEHeader()
- {
- BMCWEB_LOG_DEBUG("Starting SSE connection");
-
- res.set(boost::beast::http::field::content_type, "text/event-stream");
- boost::beast::http::response_serializer<BodyType>& serial =
- serializer.emplace(res);
-
- boost::beast::http::async_write_header(
- adaptor, serial,
- std::bind_front(&ConnectionImpl::sendSSEHeaderCallback, this,
- shared_from_this()));
- }
-
void sendSSEHeaderCallback(const std::shared_ptr<Connection>& /*self*/,
+ const Request& req,
const boost::system::error_code& ec,
size_t /*bytesSent*/)
{
@@ -118,6 +108,12 @@
return;
}
BMCWEB_LOG_DEBUG("SSE header sent - Connection established");
+ if (!openHandler)
+ {
+ BMCWEB_LOG_CRITICAL("No open handler???");
+ return;
+ }
+ openHandler(*this, req);
// SSE stream header sent, So let us setup monitor.
// Any read data on this stream will be error in case of SSE.
diff --git a/test/http/server_sent_event_test.cpp b/test/http/server_sent_event_test.cpp
index bf5cee3..24d61ee 100644
--- a/test/http/server_sent_event_test.cpp
+++ b/test/http/server_sent_event_test.cpp
@@ -49,7 +49,7 @@
"Content-Type: text/event-stream\r\n"
"\r\n";
- while (out.str().size() != expected.size())
+ while (out.str().size() != expected.size() || !openCalled)
{
io.run_for(std::chrono::milliseconds(1));
}