LCOV - code coverage report
Current view: top level - http/server - request.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 100.0 % 1 1
Test Date: 2026-02-20 15:38:22 Functions: 100.0 % 1 1

            Line data    Source code
       1              : #ifndef API_REQUEST_HPP
       2              : #define API_REQUEST_HPP
       3              : 
       4              : #include <string>
       5              : #include <memory>
       6              : #include <set>
       7              : #include <vector>
       8              : #include <nlohmann/json.hpp>
       9              : #include <boost/algorithm/string.hpp>
      10              : 
      11              : #include "http_stream.hpp"
      12              : #include "server_connection.hpp"
      13              : #include "../common/http_response.hpp"
      14              : #include "../../util/types.hpp"
      15              : 
      16              : namespace thinger::http{
      17              : 
      18              :     // Forward declarations
      19              :     class route;
      20              :     enum class auth_level;
      21              : 
      22              :     /**
      23              :      * Class that represents a single HTTP request over the API. It means, that the HTTP request
      24              :      * was matched to some of the registered endpoints in the API. It holds the original HTTP
      25              :      * connection, the stream associated to the HTTP request, and the HTTP request itself.
      26              :      */
      27              :     class request{
      28              :     public:
      29              :         request(const std::shared_ptr<server_connection>& http_connection,
      30              :                     const std::shared_ptr<http_stream>& http_stream,
      31              :                     std::shared_ptr<http_request> http_request);
      32              : 
      33              :         virtual ~request();
      34              : 
      35              :     public:
      36              :         /// get parameter
      37              :         const std::string& operator[](const std::string& param) const;
      38              : 
      39              :         /// has parameter
      40              :         bool has(const std::string& param) const;
      41              : 
      42              :         /// erase parameter
      43              :         bool erase(const std::string& param);
      44              : 
      45              :         std::string debug_parameters() const;
      46              : 
      47              :         std::shared_ptr<http_request> get_http_request();
      48              : 
      49              :         std::string get_request_ip() const;
      50              : 
      51              :         // Convenience methods for accessing request data
      52              : 
      53              :         /// Get query parameter by key
      54              :         std::string query(const std::string& key) const;
      55              : 
      56              :         /// Get query parameter by key with default value
      57              :         std::string query(const std::string& key, const std::string& default_value) const;
      58              : 
      59              :         /// Get request body as string
      60              :         std::string body() const;
      61              : 
      62              :         /// Get request body parsed as JSON
      63              :         nlohmann::json json() const;
      64              : 
      65              :         /// Get request header by key
      66              :         std::string header(const std::string& key) const;
      67              : 
      68              :         std::shared_ptr<server_connection> get_http_connection() const;
      69              :         
      70              :         std::shared_ptr<http_stream> get_http_stream() const;
      71              : 
      72              :         //void add_matched_param(const std::string& param);
      73              : 
      74              :         void set_uri_parameter(const std::string& param, const std::string& value);
      75              : 
      76              :         void add_uri_parameter(const std::string& param, const std::string& value);
      77              : 
      78              :         const std::string& get_uri_parameter(const std::string& param) const;
      79              : 
      80              :         const std::multimap<std::string, std::string>& get_uri_parameters() const;
      81              : 
      82              :         void set_auth_groups(const std::set<std::string>& groups);
      83              : 
      84              :         const std::set<std::string>& get_auth_groups() const;
      85              : 
      86              :         void set_auth_user(const std::string& auth_user);
      87              : 
      88              :         const std::string& get_auth_user() const;
      89              :         
      90              :         void set_matched_route(const route* route);
      91              :         
      92              :         const route* get_matched_route() const;
      93              :         
      94              :         auth_level get_required_auth_level() const;
      95              : 
      96              : 
      97              :         bool keep_alive() const;
      98              : 
      99              :         // --- Deferred body reading support ---
     100              : 
     101              :         /// Store read-ahead data (called by server_connection before dispatch)
     102              :         void set_read_ahead(const uint8_t* data, size_t size);
     103              : 
     104              :         /// Read exactly `size` bytes (read-ahead first, then socket). TCP backpressure.
     105              :         thinger::awaitable<size_t> read(uint8_t* buffer, size_t size);
     106              : 
     107              :         /// Read up to `max_size` bytes (read-ahead first, then socket).
     108              :         thinger::awaitable<size_t> read_some(uint8_t* buffer, size_t max_size);
     109              : 
     110              :         /// Read full body into http_request content (for non-deferred dispatch).
     111              :         thinger::awaitable<bool> read_body();
     112              : 
     113              :         /// Content-Length convenience (0 for chunked requests)
     114              :         size_t content_length() const;
     115              : 
     116              :         /// Whether the request uses chunked transfer encoding
     117              :         bool is_chunked() const;
     118              : 
     119              :         /// Bytes remaining in read-ahead buffer
     120              :         size_t read_ahead_available() const;
     121              : 
     122              :         /// Direct socket access (for pipe-style forwarding)
     123              :         std::shared_ptr<asio::socket> get_socket() const;
     124              : 
     125              :         //exec_result get_request_data() const;
     126              : 
     127              :     private:
     128              : 
     129              :         /**
     130              :          * HTTP connection is the wrapper for a raw socket, being able to parse request and to
     131              :          * pipeline HTTP responses
     132              :          */
     133              :         std::weak_ptr<server_connection> http_connection_;
     134              : 
     135              :         /**
     136              :          * A stream is a channel inside the HTTP connection. i.e, while receiving multiple requests
     137              :          * and responses are generated asynchronously, it is required to know which response
     138              :          * belong to a given query, and provide an ordered response (to support HTTP pipelining).
     139              :          * With HTTP2.0 it is possible to provide responses without pipelining.
     140              :          */
     141              :         std::weak_ptr<http_stream> http_stream_;
     142              : 
     143              :         /**
     144              :          * This is the request that originated the API Request, and required to know the body, the
     145              :          * content type, etc.
     146              :          */
     147              :         std::shared_ptr<http_request> http_request_;
     148              : 
     149              :         /**
     150              :          * Vector for storing the matched parameters found in the URL, like username, device, etc.
     151              :          */
     152              :         std::multimap<std::string, std::string> params_;
     153              : 
     154              :         std::string auth_user_;
     155              : 
     156              :         std::set<std::string> groups_;
     157              :         
     158              :         const route* matched_route_ = nullptr;
     159              : 
     160              :         /// Leftover data from header parsing buffer (for deferred body reading)
     161              :         std::vector<uint8_t> read_ahead_;
     162              :         size_t read_ahead_offset_ = 0;
     163              : 
     164              :         /// Raw read (bypasses chunked decoding) — reads from read-ahead, then socket
     165              :         thinger::awaitable<size_t> raw_read_some(uint8_t* buffer, size_t max_size);
     166              : 
     167              :         /// Chunked transfer encoding decoder state
     168              :         enum class chunk_state { size, size_lf, data, data_cr, data_lf, trailer_lf, done };
     169              :         chunk_state chunk_state_ = chunk_state::size;
     170              :         size_t chunk_remaining_ = 0;
     171              :         size_t chunk_size_accum_ = 0;
     172              : 
     173              :         /// Read with chunked decoding (transparent to caller)
     174              :         thinger::awaitable<size_t> read_some_chunked(uint8_t* buffer, size_t max_size);
     175              : 
     176              :         /// Max body size for non-deferred chunked read_body()
     177              :         size_t max_body_size_ = 8 * 1024 * 1024;
     178              : 
     179              :     public:
     180          104 :         void set_max_body_size(size_t size) { max_body_size_ = size; }
     181              :     };
     182              : 
     183              : }
     184              : 
     185              : 
     186              : #endif
        

Generated by: LCOV version 2.0-1