LCOV - code coverage report
Current view: top level - http/common - headers.cpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 92.3 % 130 120
Test Date: 2026-04-21 17:49:55 Functions: 93.3 % 30 28

            Line data    Source code
       1              : #include "headers.hpp"
       2              : #include <charconv>
       3              : #include <regex>
       4              : #include "../../util/logger.hpp"
       5              : 
       6              : namespace thinger::http{
       7              : 
       8         5342 :     void headers::process_header(std::string key, std::string value){
       9         5342 :         if(boost::indeterminate(keep_alive_) && is_header(key, header::connection)){
      10              :             /*
      11              :              * Firefox send both keep-alive and upgrade values in Connection header, i.e., when opening a WebSocket,
      12              :              * so it is necessary to test values separately.
      13              :              */
      14         1041 :             std::vector<std::string> strs;
      15         1041 :             boost::split(strs, value, boost::is_any_of(","));
      16         2085 :             for(auto& str:strs){
      17         1044 :                 boost::algorithm::trim(str);
      18         1044 :                 if(is_header(str, connection::keep_alive)){
      19          961 :                     keep_alive_ = true;
      20              :                 }
      21           83 :                 else if (is_header(str, connection::close)){
      22           39 :                     keep_alive_ = false;
      23              :                 }
      24           44 :                 else if(is_header(str, connection::upgrade)){
      25           44 :                     upgrade_ = true;
      26              :                 }
      27              :             }
      28         1041 :         }
      29              : 
      30         5342 :         if(is_header(key, header::accept)){
      31           27 :             stream_ = boost::iequals(value, accept::event_stream);
      32         5315 :         }else if(is_header(key, header::content_length)){
      33         1010 :             auto [ptr, ec] = std::from_chars(value.data(), value.data() + value.size(), content_length_);
      34         1010 :             if (ec != std::errc{}) {
      35            3 :                 content_length_ = 0;
      36              :             }
      37              :         }
      38              : 
      39         5342 :         headers_.emplace_back(std::move(key), std::move(value));
      40         5342 :     }
      41              : 
      42         8150 :     void headers::add_header(std::string key, std::string value){
      43         8150 :         if(key.empty()) return;
      44         8150 :         headers_.emplace_back(std::move(key), std::move(value));
      45              :     }
      46              : 
      47           21 :     void headers::add_proxy(std::string key, std::string value){
      48           21 :         if(key.empty()) return;
      49           18 :         proxy_headers_.emplace_back(std::move(key), std::move(value));
      50              :     }
      51              : 
      52         7056 :     void headers::set_header(std::string key, std::string value){
      53        11510 :         for(auto & header : headers_)
      54              :         {
      55         5851 :             if(is_header(header.first, key)){
      56         1397 :                 header.second = std::move(value);
      57         1397 :                 return;
      58              :             }
      59              :         }
      60         5659 :         add_header(std::move(key), std::move(value));
      61              :     }
      62              : 
      63            6 :     void headers::set_proxy(std::string key, std::string value){
      64            6 :         for(auto & header : proxy_headers_)
      65              :         {
      66            3 :             if(is_header(header.first, key)){
      67            3 :                 header.second = std::move(value);
      68            3 :                 return;
      69              :             }
      70              :         }
      71            3 :         add_proxy(std::move(key), std::move(value));
      72              :     }
      73              : 
      74           12 :     bool headers::upgrade() const{
      75           12 :         return upgrade_;
      76              :     }
      77              : 
      78            9 :     bool headers::stream() const{
      79            9 :         return stream_;
      80              :     }
      81              : 
      82         3484 :     bool headers::has_header(std::string_view key) const{
      83        11139 :         for(const auto & header : headers_)
      84              :         {
      85         7946 :             if(is_header(header.first, key)){
      86          291 :                 return true;
      87              :             }
      88              :         }
      89         3193 :         return false;
      90              :     }
      91              : 
      92          637 :     const std::string& headers::get_header(std::string_view key) const
      93              :     {
      94         2039 :         for(const auto & header : headers_)
      95              :         {
      96         1972 :             if(is_header(header.first, key)){
      97          570 :                 return header.second;
      98              :             }
      99              :         }
     100           67 :         static std::string emtpy;
     101           67 :         return emtpy;
     102              :     }
     103              : 
     104           52 :     std::vector<std::string> headers::get_headers_with_key(std::string_view key) const{
     105           52 :         std::vector<std::string> headers;
     106          156 :         for(const auto & header : headers_)
     107              :         {
     108          104 :             if(is_header(header.first, key)){
     109           12 :                 headers.push_back(header.second);
     110              :             }
     111              :         }
     112           52 :         return headers;
     113            0 :     }
     114              : 
     115            0 :     const std::vector<headers::http_header>& headers::get_headers() const{
     116            0 :         return headers_;
     117              :     }
     118              : 
     119           80 :     std::vector<headers::http_header>& headers::get_headers(){
     120           80 :         return headers_;
     121              :     }
     122              : 
     123           57 :     bool headers::remove_header(std::string_view key)
     124              :     {
     125          192 :         for(auto it=headers_.begin(); it!=headers_.end(); ++it){
     126          189 :             if(is_header(it->first, key)){
     127           54 :                 headers_.erase(it);
     128           54 :                 return true;
     129              :             }
     130              :         }
     131            3 :         return false;
     132              :     }
     133              : 
     134            6 :     const std::string& headers::get_authorization() const
     135              :     {
     136            6 :         return get_header(header::authorization);
     137              :     }
     138              : 
     139            6 :     const std::string& headers::get_cookie() const
     140              :     {
     141            6 :         return get_header(header::cookie);
     142              :     }
     143              : 
     144            6 :     const std::string& headers::get_user_agent() const{
     145            6 :         return get_header(header::user_agent);
     146              :     }
     147              : 
     148           73 :     const std::string& headers::get_content_type() const
     149              :     {
     150           73 :         return get_header(header::content_type);
     151              :     }
     152              : 
     153            9 :     bool headers::is_content_type(const std::string& value) const
     154              :     {
     155            9 :         return boost::istarts_with(get_header(header::content_type), value);
     156              :     }
     157              : 
     158         6378 :     bool headers::empty_headers() const{
     159         6378 :         return headers_.empty();
     160              :     }
     161              : 
     162            3 :     void headers::debug_headers(std::ostream& os) const{
     163            9 :         for(const std::pair<std::string, std::string>& t: headers_){
     164            6 :             os << "\t> " << t.first << ": " << t.second << std::endl;
     165              :         }
     166            3 :     }
     167              : 
     168            0 :     void headers::log(const char* scope, int level) const{
     169            0 :         LOG_DEBUG("[{}] Headers:", scope);
     170            0 :         for(const auto& t: headers_){
     171            0 :             LOG_DEBUG("  {}: {}", t.first, t.second);
     172              :         }
     173            0 :         for(const auto& t: proxy_headers_){
     174            0 :             LOG_DEBUG("  (PROXY REPLACE) {}: {}", t.first, t.second);
     175              :         }
     176            0 :     }
     177              : 
     178         4123 :     size_t headers::get_content_length() const{
     179         4123 :         return content_length_;
     180              :     }
     181              : 
     182         3021 :     bool headers::keep_alive() const
     183              :     {
     184         3021 :         if(boost::indeterminate(keep_alive_)){
     185         1950 :             return http_version_major_>=1 && http_version_minor_>=1;
     186              :         }else{
     187         1071 :             return (bool) keep_alive_;
     188              :         }
     189              :     }
     190              : 
     191         1026 :     void headers::set_keep_alive(bool keep_alive){
     192         1026 :             keep_alive_ = keep_alive;
     193         1026 :             set_header(http::header::connection, (keep_alive ? "Keep-Alive" : "Close"));
     194         1026 :     }
     195              : 
     196         1992 :     void headers::set_http_version_major(uint8_t http_version_major) {
     197         1992 :         http_version_major_ = http_version_major;
     198         1992 :     }
     199              : 
     200         1992 :     void headers::set_http_version_minor(uint8_t http_version_minor) {
     201         1992 :         http_version_minor_ = http_version_minor;
     202         1992 :     }
     203              : 
     204            6 :     int headers::get_http_version_major() const {
     205            6 :         return http_version_major_;
     206              :     }
     207              : 
     208            6 :     int headers::get_http_version_minor() const {
     209            6 :         return http_version_minor_;
     210              :     }
     211              : 
     212           24 :     std::string headers::get_parameter(const std::string& header_value, std::string_view name) {
     213              : 
     214           24 :         auto start = header_value.begin();
     215           24 :                 auto end   = header_value.end();
     216              : 
     217           30 :                 if(start==end) return "";
     218              : 
     219           21 :                 static std::regex cookie_regex("([^;^\\s]+)=\"?([^;^\"]*)\"?");
     220           21 :                 std::smatch what;
     221              : 
     222           36 :                 while (std::regex_search(start, end, what, cookie_regex))
     223              :                 {
     224           66 :                         std::string key(what[1].first, what[1].second);
     225           33 :                         std::string value(what[2].first, what[2].second);
     226              : 
     227           33 :                         if(key==name) return value;
     228              : 
     229           15 :                         start = what[0].second;
     230           51 :                 }
     231              : 
     232            6 :                 return "";
     233           21 :         }
     234              : 
     235        31317 :     bool inline headers::is_header(std::string_view key, std::string_view header) const{
     236        31317 :         return boost::iequals(key, header);
     237              :     }
     238              : }
        

Generated by: LCOV version 2.0-1