I'm using nghttp2 to implement a REST server which should use HTTP/2 and server-sent events (to be consumed by an EventSource in the browser). However, based on the examples it is unclear to me how to implement SSE. Using res.push() as in asio-sv.cc doesn't seem to be the right approach.
What would be the right way to do it? I'd prefer to use nghttp2's C++ API, but the C API would do as well.
Yup, I did something like that back in 2018. The documentation was rather sparse :).
First of all, ignore
response::pushbecause that's the HTTP2 push -- something for proactively sending unsolicited objects to the client before it requests them. I know it sounds like what you need, but it is not -- the typical use case would be proactively sending a CSS file and some images along with the originally requested HTML page.The key thing is that your
end()callback must eventually returnNGHTTP2_ERR_DEFERREDwhenever you run out of data to send. When your application somehow obtains more data to be sent, callhttp::response::resume().Here's a simple code. Build it as
g++ -std=c++17 -Wall -O3 -ggdb clock.cpp -lssl -lcrypto -pthread -lnghttp2_asio -lspdlog -lfmt. Be careful, modern browsers don't do HTTP/2 over a plaintext socket, so you'll need to reverse-proxy it via something likenghttpx -f '*,8080;no-tls' -b '::1,10080;;proto=h2'.I have a feeling that my queue handling is probably too complex. When testing via
curl, I never seem to run out of buffer space. In other words, even if the client is not reading any data from the socket, the library keep invokingsend_chunk, asking for up to 16kB of data at a time for me. Strange. I have no idea how it works when pushing more data more heavily.My "real code" used to have a third state,
Closed, but I think that blocking events viaon_closeis enough here. However, I think you never want to entersend_chunkif the client has already disconnected, but before the destructor gets called.