LCOV - code coverage report
Current view: top level - http/server - response_sink.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 68.4 % 19 13
Test Date: 2026-11-10 10:38:07 Functions: 69.2 % 13 9

            Line data    Source code
       1              : #ifndef THINGER_HTTP_SERVER_RESPONSE_SINK_HPP
       2              : #define THINGER_HTTP_SERVER_RESPONSE_SINK_HPP
       3              : 
       4              : #include "../common/http_response.hpp"
       5              : #include "../../util/types.hpp"
       6              : #include "server_connection.hpp"
       7              : #include "http_stream.hpp"
       8              : #include "response_observer.hpp"
       9              : #include <memory>
      10              : #include <string>
      11              : 
      12              : namespace thinger::http {
      13              : 
      14              : class request;
      15              : 
      16              : // How the body of a streamed response is delimited (see response::start_stream)
      17              : enum class body_framing {
      18              :     none,       // no body (a response to HEAD, 1xx, 204, 304): the head alone
      19              :     length,     // Content-Length, already set in the head
      20              :     chunked,    // chunked transfer coding
      21              :     close       // closing the connection at its end (HTTP/1.0 clients)
      22              : };
      23              : 
      24              : // Where a response is written: a connection, or memory for requests dispatched in memory.
      25              : // Shared by every copy of a response, which writes it once: whole (send), in chunks
      26              : // (begin, append..., finish), streamed with flow control (begin_stream, write_stream...,
      27              : // end_stream or abort_stream), or followed by a connection takeover (take_over).
      28              : class response_sink {
      29              : public:
      30        28535 :     virtual ~response_sink() = default;
      31              : 
      32              :     // Whole response
      33              :     virtual void send(std::shared_ptr<http_response> response) = 0;
      34              : 
      35              :     // Chunked response: the headers, then the data, then the end. They return false if
      36              :     // the response can no longer be written (e.g. the connection is gone)
      37              :     virtual bool begin(std::shared_ptr<http_response> headers) = 0;
      38              :     virtual bool append(const std::string& data) = 0;
      39              :     virtual bool finish() = 0;
      40              : 
      41              :     // Streamed response: the head (its framing headers are set by the sink), then the
      42              :     // body, each write completing once its data is written (false if it could not be),
      43              :     // then the end; or an abort, ending the response so the client sees it incomplete.
      44              :     // By default they are the chunked response above, collected at once.
      45            6 :     virtual bool begin_stream(std::shared_ptr<http_response> head, body_framing /*framing*/) {
      46            6 :         return begin(std::move(head));
      47              :     }
      48            6 :     virtual awaitable<bool> write_stream(std::string data) {
      49              :         co_return append(data);
      50           12 :     }
      51            3 :     virtual awaitable<bool> end_stream() {
      52              :         co_return finish();
      53            6 :     }
      54            0 :     virtual void abort_stream() {
      55            0 :         finish();
      56            0 :     }
      57              : 
      58              :     // Whether the connection can be taken over (WebSocket, SSE, response::take_over)
      59           12 :     virtual bool can_take_over() const { return false; }
      60              : 
      61              :     // Send the response, then hand the connection to `handler` (see response::take_over).
      62              :     // `framing` is close when what the handler writes is the body of the response, ending
      63              :     // when the connection closes: the response says so
      64            0 :     virtual void take_over(std::shared_ptr<http_response> /*response*/, takeover_handler /*handler*/,
      65            0 :                            body_framing /*framing*/) {}
      66              : 
      67              :     // Connection the response is written to, null if none
      68            3 :     virtual std::shared_ptr<server_connection> connection() const { return nullptr; }
      69              : 
      70              :     // Tell `observer` about the response written (its head, the bytes written and its end),
      71              :     // for the response hook (see http_application::on_response). Called before the response
      72              :     // is answered. A sink ignoring it, as by default, has its responses reported as aborted
      73            0 :     virtual void observe(std::shared_ptr<response_observer> /*observer*/) {}
      74              : };
      75              : 
      76              : // Response written to a stream of a server connection
      77              : class connection_sink : public response_sink {
      78              : public:
      79           24 :     connection_sink(const std::shared_ptr<server_connection>& connection, const std::shared_ptr<http_stream>& stream)
      80           24 :         : connection_(connection), stream_(stream) {}
      81              : 
      82              :     // For a request read from a connection: the connection and stream it came from (copied as
      83              :     // the request holds them, without locking them)
      84              :     explicit connection_sink(const request& req);
      85              : 
      86              :     void send(std::shared_ptr<http_response> response) override;
      87              :     bool begin(std::shared_ptr<http_response> headers) override;
      88              :     bool append(const std::string& data) override;
      89              :     bool finish() override;
      90              :     bool begin_stream(std::shared_ptr<http_response> head, body_framing framing) override;
      91              :     awaitable<bool> write_stream(std::string data) override;
      92              :     awaitable<bool> end_stream() override;
      93              :     void abort_stream() override;
      94         4497 :     bool can_take_over() const override { return true; }
      95              :     void take_over(std::shared_ptr<http_response> response, takeover_handler handler,
      96              :                    body_framing framing) override;
      97          279 :     std::shared_ptr<server_connection> connection() const override { return connection_.lock(); }
      98              :     void observe(std::shared_ptr<response_observer> observer) override;
      99              : 
     100              : private:
     101              :     // Queue a frame on the stream; false if the connection is gone
     102              :     bool write(std::shared_ptr<http_frame> frame);
     103              : 
     104              :     // Queue a frame and wait until it is written; false if it could not be
     105              :     awaitable<bool> write_and_wait(std::shared_ptr<http_frame> frame);
     106              : 
     107              :     // Close the connection once this response is written, for `reason` (see
     108              :     // http_stream::must_close()); before any frame written after this call
     109              :     void must_close(detail::close_reason reason);
     110              : 
     111              :     std::weak_ptr<server_connection> connection_;
     112              :     std::weak_ptr<http_stream> stream_;
     113              : 
     114              :     // Framing of a streamed response
     115              :     body_framing framing_ = body_framing::none;
     116              : };
     117              : 
     118              : } // namespace thinger::http
     119              : 
     120              : #endif // THINGER_HTTP_SERVER_RESPONSE_SINK_HPP
        

Generated by: LCOV version 2.0-1