LCOV - code coverage report
Current view: top level - http/common - headers.cpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 92.4 % 131 121
Test Date: 2026-02-20 15:38:22 Functions: 93.3 % 30 28

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

Generated by: LCOV version 2.0-1