LCOV - code coverage report
Current view: top level - http/common - chunked_decoder.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 100.0 % 3 3
Test Date: 2026-11-10 10:38:07 Functions: 100.0 % 3 3

            Line data    Source code
       1              : #ifndef THINGER_HTTP_COMMON_CHUNKED_DECODER_HPP
       2              : #define THINGER_HTTP_COMMON_CHUNKED_DECODER_HPP
       3              : 
       4              : #include <cstddef>
       5              : #include <cstdint>
       6              : 
       7              : namespace thinger::http {
       8              : 
       9              :     /**
      10              :      * Strict decoder of the chunked transfer coding (RFC 9112, section 7.1), of request and
      11              :      * response bodies. It is fed with the raw bytes following the header section and stops
      12              :      * right after the end of the body (last chunk and trailer section), so whatever follows
      13              :      * is left for the next message.
      14              :      * Anything that does not follow the grammar fails the decoding: there is no recovery,
      15              :      * as a lenient parser would frame the body differently than a proxy in front of it.
      16              :      */
      17              :     class chunked_decoder {
      18              :     public:
      19              :         // Longest chunk size line (size and extensions) and trailer section accepted
      20              :         static constexpr size_t max_line_size = 4096;
      21              :         static constexpr size_t max_trailer_size = 8192;
      22              : 
      23              :         /// Decode up to `size` input bytes, writing up to `out_size` body bytes to `out`
      24              :         /// (their number is stored in `produced`). Returns the input bytes consumed: it stops
      25              :         /// at the end of the body, on error, or when `out` is full.
      26              :         size_t decode(const uint8_t* in, size_t size, uint8_t* out, size_t out_size, size_t& produced);
      27              : 
      28              :         /// Bytes of the current chunk that can be read straight from the input (0 if the
      29              :         /// decoder is not within chunk data), and notify that `size` of them were read so
      30              :         size_t data_pending() const;
      31              :         void data_consumed(size_t size);
      32              : 
      33       141682 :         bool done() const { return state_ == state::done; }
      34       115430 :         bool failed() const { return state_ == state::error; }
      35              : 
      36              :     private:
      37              :         // The states of the chunk size line (size and extensions) come first, up to ext_bws
      38              :         enum class state {
      39              :             size_start,         // first hex digit of the chunk size
      40              :             size,               // more hex digits, ';' or CR
      41              :             ext_name_start,     // after ';': whitespace or the first character of a name
      42              :             ext_name,           // within an extension name
      43              :             ext_after_name,     // whitespace after an extension name, then '=' or ';'
      44              :             ext_value_start,    // after '=': whitespace, then a token or a quoted string
      45              :             ext_value,          // within a token value
      46              :             ext_quoted,         // within a quoted string value
      47              :             ext_quoted_pair,    // after a backslash in a quoted string
      48              :             ext_after_quoted,   // after a quoted string: whitespace, ';' or CR
      49              :             ext_bws,            // whitespace after a value, before the next ';'
      50              :             size_lf,
      51              :             data,
      52              :             data_cr,
      53              :             data_lf,
      54              :             trailer_start,      // start of a trailer field line, or CR of the final CRLF
      55              :             trailer_name,       // within a trailer field name, up to ':'
      56              :             trailer,            // within a trailer field value
      57              :             trailer_lf,
      58              :             end_lf,             // LF of the final CRLF
      59              :             done,
      60              :             error
      61              :         };
      62              : 
      63              :         state state_ = state::size_start;
      64              :         size_t chunk_size_ = 0;     // size being parsed, then data left in the chunk
      65              :         size_t line_size_ = 0;      // bytes of the current size line
      66              :         size_t trailer_size_ = 0;   // bytes of the trailer section
      67              : 
      68        13830 :         bool fail() { state_ = state::error; return false; }
      69              :         bool consume(uint8_t byte);
      70              :     };
      71              : 
      72              : }
      73              : 
      74              : #endif
        

Generated by: LCOV version 2.0-1