LCOV - code coverage report
Current view: top level - http/common - http_response.cpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 93.8 % 178 167
Test Date: 2026-02-20 15:38:22 Functions: 95.5 % 22 21

            Line data    Source code
       1              : #include "http_response.hpp"
       2              : #include "../server/mime_types.hpp"
       3              : #include "../data/out_string.hpp"
       4              : 
       5              : #include <memory>
       6              : #include "../../util/logger.hpp"
       7              : 
       8              : namespace thinger::http{
       9              : 
      10              :     namespace status_strings{
      11              : 
      12              :         const std::string ok =
      13              :                 "HTTP/1.1 200 OK";
      14              :         const std::string created =
      15              :                 "HTTP/1.1 201 Created";
      16              :         const std::string accepted =
      17              :                 "HTTP/1.1 202 Accepted";
      18              :         const std::string no_content =
      19              :                 "HTTP/1.1 204 No Content";
      20              :         const std::string multiple_choices =
      21              :                 "HTTP/1.1 300 Multiple Choices";
      22              :         const std::string moved_permanently =
      23              :                 "HTTP/1.1 301 Moved Permanently";
      24              :         const std::string moved_temporarily =
      25              :                 "HTTP/1.1 302 Moved Temporarily";
      26              :         const std::string not_modified =
      27              :                 "HTTP/1.1 304 Not Modified";
      28              :         const std::string bad_request =
      29              :                 "HTTP/1.1 400 Bad Request";
      30              :         const std::string unauthorized =
      31              :                 "HTTP/1.1 401 Unauthorized";
      32              :         const std::string forbidden =
      33              :                 "HTTP/1.1 403 Forbidden";
      34              :         const std::string not_found =
      35              :                 "HTTP/1.1 404 Not Found";
      36              :         const std::string not_allowed =
      37              :                 "HTTP/1.1 405 Method Not Allowed";
      38              :         const std::string timed_out =
      39              :                 "HTTP/1.1 408 Request Timeout";
      40              :         const std::string internal_server_error =
      41              :                 "HTTP/1.1 500 Internal Server Error";
      42              :         const std::string not_implemented =
      43              :                 "HTTP/1.1 501 Not Implemented";
      44              :         const std::string bad_gateway =
      45              :                 "HTTP/1.1 502 Bad Gateway";
      46              :         const std::string service_unavailable =
      47              :                 "HTTP/1.1 503 Service Unavailable";
      48              :         const std::string switching_protocols =
      49              :                 "HTTP/1.1 101 Switching Protocols";
      50              :         const std::string too_many_requests =
      51              :                 "HTTP/1.1 429 Too Many Requests";
      52              :         const std::string temporary_redirect =
      53              :                 "HTTP/1.1 307 Temporary Redirect";
      54              :         const std::string permanent_redirect =
      55              :                 "HTTP/1.1 308 Permanent Redirect";
      56              :         const std::string upgrade_required =
      57              :                 "HTTP/1.1 426 Upgrade Required";
      58              :         const std::string conflict =
      59              :                 "HTTP/1.1 409 Conflict";
      60              :         const std::string payload_too_large =
      61              :                 "HTTP/1.1 413 Payload Too Large";
      62              :         const std::string unknown =
      63              :                 "HTTP/1.1 000 Unknown Status";
      64              : 
      65         2648 :         const std::string& get_status_string(http_response::status status){
      66         2648 :             switch(status){
      67         2056 :                 case http_response::status::ok:
      68         2056 :                     return ok;
      69           24 :                 case http_response::status::created:
      70           24 :                     return created;
      71            3 :                 case http_response::status::accepted:
      72            3 :                     return accepted;
      73            6 :                 case http_response::status::no_content:
      74            6 :                     return no_content;
      75            3 :                 case http_response::status::multiple_choices:
      76            3 :                     return multiple_choices;
      77            9 :                 case http_response::status::moved_permanently:
      78            9 :                     return moved_permanently;
      79          198 :                 case http_response::status::moved_temporarily:
      80          198 :                     return moved_temporarily;
      81            3 :                 case http_response::status::temporary_redirect:
      82            3 :                     return temporary_redirect;
      83            3 :                 case http_response::status::permanent_redirect:
      84            3 :                     return permanent_redirect;
      85            3 :                 case http_response::status::not_modified:
      86            3 :                     return not_modified;
      87           18 :                 case http_response::status::bad_request:
      88           18 :                     return bad_request;
      89           15 :                 case http_response::status::unauthorized:
      90           15 :                     return unauthorized;
      91            9 :                 case http_response::status::forbidden:
      92            9 :                     return forbidden;
      93           81 :                 case http_response::status::not_found:
      94           81 :                     return not_found;
      95           27 :                 case http_response::status::not_allowed:
      96           27 :                     return not_allowed;
      97            3 :                 case http_response::status::timed_out:
      98            3 :                     return timed_out;
      99           24 :                 case http_response::status::internal_server_error:
     100           24 :                     return internal_server_error;
     101            3 :                 case http_response::status::not_implemented:
     102            3 :                     return not_implemented;
     103            3 :                 case http_response::status::bad_gateway:
     104            3 :                     return bad_gateway;
     105           12 :                 case http_response::status::service_unavailable:
     106           12 :                     return service_unavailable;
     107          117 :                 case http_response::status::switching_protocols:
     108          117 :                     return switching_protocols;
     109            3 :                 case http_response::status::too_many_requests:
     110            3 :                     return too_many_requests;
     111            3 :                 case http_response::status::upgrade_required:
     112            3 :                     return upgrade_required;
     113            3 :                 case http_response::status::conflict:
     114            3 :                     return conflict;
     115           16 :                 case http_response::status::payload_too_large:
     116           16 :                     return payload_too_large;
     117            3 :                 default:
     118            3 :                     return unknown;
     119              :             }
     120              :         }
     121              :     }
     122              : 
     123          949 :     void http_response::to_buffer(std::vector<boost::asio::const_buffer>& buffer) const{
     124          949 :         buffer.emplace_back(boost::asio::buffer(status_strings::get_status_string(status_)));
     125          949 :         buffer.emplace_back(boost::asio::buffer(misc_strings::crlf));
     126         3623 :         for(const auto& t: headers_){
     127         2674 :             buffer.emplace_back(boost::asio::buffer(t.first));
     128         2674 :             buffer.emplace_back(boost::asio::buffer(misc_strings::name_value_separator));
     129         2674 :             buffer.emplace_back(boost::asio::buffer(t.second));
     130         2674 :             buffer.emplace_back(boost::asio::buffer(misc_strings::crlf));
     131              :         }
     132          949 :         buffer.emplace_back(boost::asio::buffer(misc_strings::crlf));
     133          949 :         if(!content_.empty()){
     134          733 :             buffer.emplace_back(boost::asio::buffer(content_));
     135              :         }
     136          949 :     }
     137              : 
     138              : 
     139         1699 :     void http_response::log(const char* scope, int level) const{
     140              :         // Log the response with context
     141         1699 :         LOG_INFO("[{}] {}", scope, status_strings::get_status_string(status_));
     142              :         
     143              :         // Log headers at debug level
     144         1699 :         LOG_DEBUG("Headers:");
     145         6888 :         for(const auto& t: headers_){
     146         5189 :             LOG_DEBUG("  {}: {}", t.first, t.second);
     147              :         }
     148         1702 :         for(const auto& t: proxy_headers_){
     149            3 :             LOG_DEBUG("  (PROXY) {}: {}", t.first, t.second);
     150              :         }
     151              :         
     152              :         // Log body if present (at trace level)
     153         1699 :         if(!content_.empty()){
     154         1415 :             LOG_TRACE("Body: {} bytes", content_.size());
     155              :             // Limit body output to avoid flooding logs
     156         1415 :             if(content_.size() <= 500) {
     157         1394 :                 LOG_TRACE("  {}", content_);
     158              :             } else {
     159           21 :                 LOG_TRACE("  {} (truncated)", content_.substr(0, 500));
     160              :             }
     161              :         }
     162         1699 :     }
     163              : 
     164              :     namespace stock_replies{
     165              : 
     166              :         static const std::string ok;
     167              : 
     168              :         static const std::string created(
     169              :                 "<html>"
     170              :                 "<head><title>Created</title></head>"
     171              :                 "<body><h1>201 Created</h1></body>"
     172              :                 "</html>");
     173              : 
     174              :         static const std::string accepted(
     175              :                 "<html>"
     176              :                 "<head><title>Accepted</title></head>"
     177              :                 "<body><h1>202 Accepted</h1></body>"
     178              :                 "</html>");
     179              : 
     180              :         static const std::string no_content(
     181              :                 "<html>"
     182              :                 "<head><title>No Content</title></head>"
     183              :                 "<body><h1>204 Content</h1></body>"
     184              :                 "</html>");
     185              : 
     186              :         static const std::string multiple_choices(
     187              :                 "<html>"
     188              :                 "<head><title>Multiple Choices</title></head>"
     189              :                 "<body><h1>300 Multiple Choices</h1></body>"
     190              :                 "</html>");
     191              : 
     192              :         static const std::string moved_permanently(
     193              :                 "<html>"
     194              :                 "<head><title>Moved Permanently</title></head>"
     195              :                 "<body><h1>301 Moved Permanently</h1></body>"
     196              :                 "</html>");
     197              : 
     198              :         static const std::string moved_temporarily(
     199              :                 "<html>"
     200              :                 "<head><title>Moved Temporarily</title></head>"
     201              :                 "<body><h1>302 Moved Temporarily</h1></body>"
     202              :                 "</html>");
     203              : 
     204              :         static const std::string temporary_redirect(
     205              :                 "<html>"
     206              :                 "<head><title>Temporary Redirect</title></head>"
     207              :                 "<body><h1>307 Temporary Redirect</h1></body>"
     208              :                 "</html>");
     209              : 
     210              :         static const std::string permanent_redirect(
     211              :                 "<html>"
     212              :                 "<head><title>Permanet Redirect</title></head>"
     213              :                 "<body><h1>308 Permanent Redirect</h1></body>"
     214              :                 "</html>");
     215              : 
     216              :         static const std::string not_modified(
     217              :                 "<html>"
     218              :                 "<head><title>Not Modified</title></head>"
     219              :                 "<body><h1>304 Not Modified</h1></body>"
     220              :                 "</html>");
     221              : 
     222              :         static const std::string bad_request(
     223              :                 "<html>"
     224              :                 "<head><title>Bad Request</title></head>"
     225              :                 "<body><h1>400 Bad Request</h1></body>"
     226              :                 "</html>");
     227              : 
     228              :         static const std::string unauthorized(
     229              :                 "<html>"
     230              :                 "<head><title>Unauthorized</title></head>"
     231              :                 "<body><h1>401 Unauthorized</h1></body>"
     232              :                 "</html>");
     233              : 
     234              :         static const std::string forbidden(
     235              :                 "<html>"
     236              :                 "<head><title>Forbidden</title></head>"
     237              :                 "<body><h1>403 Forbidden</h1></body>"
     238              :                 "</html>");
     239              : 
     240              :         static const std::string not_found(
     241              :                 "<html>"
     242              :                 "<head><title>Not Found</title></head>"
     243              :                 "<body><h1>404 Not Found</h1></body>"
     244              :                 "</html>");
     245              : 
     246              :         static const std::string internal_server_error(
     247              :                 "<html>"
     248              :                 "<head><title>Internal Server Error</title></head>"
     249              :                 "<body><h1>500 Internal Server Error</h1></body>"
     250              :                 "</html>");
     251              : 
     252              :         static const std::string not_implemented(
     253              :                 "<html>"
     254              :                 "<head><title>Not Implemented</title></head>"
     255              :                 "<body><h1>501 Not Implemented</h1></body>"
     256              :                 "</html>");
     257              : 
     258              :         static const std::string bad_gateway(
     259              :                 "<html>"
     260              :                 "<head><title>Bad Gateway</title></head>"
     261              :                 "<body><h1>502 Bad Gateway</h1></body>"
     262              :                 "</html>");
     263              : 
     264              :         static const std::string service_unavailable(
     265              :                 "<html>"
     266              :                 "<head><title>Service Unavailable</title></head>"
     267              :                 "<body><h1>503 Service Unavailable</h1></body>"
     268              :                 "</html>");
     269              : 
     270              :         static const std::string too_many_requests(
     271              :                 "<html>"
     272              :                 "<head><title>Too Many Requests</title></head>"
     273              :                 "<body><h1>429 Too Many Requests</h1></body>"
     274              :                 "</html>");
     275              : 
     276              :         static const std::string timed_out(
     277              :                 "<html>"
     278              :                 "<head><title>Request Timeout</title></head>"
     279              :                 "<body><h1>408 Request Timeout</h1></body>"
     280              :                 "</html>");
     281              : 
     282              :         static const std::string payload_too_large(
     283              :                 "<html>"
     284              :                 "<head><title>Payload Too Large</title></head>"
     285              :                 "<body><h1>413 Payload Too Large</h1></body>"
     286              :                 "</html>");
     287              : 
     288           54 :         const std::string& to_string(http_response::status status){
     289           54 :             switch(status){
     290            3 :                 case http_response::status::ok:
     291            3 :                     return ok;
     292            3 :                 case http_response::status::created:
     293            3 :                     return created;
     294            3 :                 case http_response::status::accepted:
     295            3 :                     return accepted;
     296            3 :                 case http_response::status::no_content:
     297            3 :                     return no_content;
     298            0 :                 case http_response::status::multiple_choices:
     299            0 :                     return multiple_choices;
     300            3 :                 case http_response::status::moved_permanently:
     301            3 :                     return moved_permanently;
     302            3 :                 case http_response::status::moved_temporarily:
     303            3 :                     return moved_temporarily;
     304            3 :                 case http_response::status::temporary_redirect:
     305            3 :                     return temporary_redirect;
     306            3 :                 case http_response::status::permanent_redirect:
     307            3 :                     return permanent_redirect;
     308            3 :                 case http_response::status::not_modified:
     309            3 :                     return not_modified;
     310            3 :                 case http_response::status::bad_request:
     311            3 :                     return bad_request;
     312            3 :                 case http_response::status::unauthorized:
     313            3 :                     return unauthorized;
     314            3 :                 case http_response::status::forbidden:
     315            3 :                     return forbidden;
     316            3 :                 case http_response::status::not_found:
     317            3 :                     return not_found;
     318            3 :                 case http_response::status::timed_out:
     319            3 :                     return timed_out;
     320            3 :                 case http_response::status::internal_server_error:
     321            3 :                     return internal_server_error;
     322            0 :                 case http_response::status::not_implemented:
     323            0 :                     return not_implemented;
     324            0 :                 case http_response::status::bad_gateway:
     325            0 :                     return bad_gateway;
     326            3 :                 case http_response::status::service_unavailable:
     327            3 :                     return service_unavailable;
     328            3 :                 case http_response::status::too_many_requests:
     329            3 :                     return too_many_requests;
     330            3 :                 case http_response::status::payload_too_large:
     331            3 :                     return payload_too_large;
     332            0 :                 default:
     333            0 :                     return internal_server_error;
     334              :             }
     335              :         }
     336              : 
     337              :     } // namespace stock_replies
     338              : 
     339           54 :     std::shared_ptr<http_response> http_response::stock_http_reply(http_response::status status){
     340           54 :         auto response = std::make_shared<http_response>();
     341           54 :         response->set_status(status);
     342           54 :         response->set_content(stock_replies::to_string(status), http::mime_types::text_html);
     343           54 :         return response;
     344            0 :     }
     345              : 
     346         1891 :     http_response::http_response()= default;
     347              : 
     348          806 :     bool http_response::is_redirect_response() const{
     349         1609 :         return status_ == status::temporary_redirect ||
     350          803 :                status_ == status::moved_temporarily ||
     351         2336 :                status_ == status::permanent_redirect ||
     352         1533 :                status_ == status::moved_permanently;
     353              :     }
     354              : 
     355          825 :     void http_response::set_status(uint16_t status_code){
     356          825 :         status_ = (status) status_code;
     357          825 :     }
     358              : 
     359         1043 :     void http_response::set_status(http_response::status status_code){
     360         1043 :         status_ = status_code;
     361         1043 :     }
     362              : 
     363              : 
     364         1587 :     http_response::status http_response::get_status() const{
     365         1587 :         return status_;
     366              :     }
     367              : 
     368           97 :     int http_response::get_status_code() const{
     369           97 :         return static_cast<int>(status_);
     370              :     }
     371              : 
     372           12 :     bool http_response::is_ok() const{
     373           12 :         return status_>=status::ok && status_<status::multiple_choices;
     374              :     }
     375              : 
     376            6 :     size_t http_response::get_size(){
     377              :         // Return the size of the content/payload
     378            6 :         return content_.size();
     379              :     }
     380              : 
     381            0 :     const std::string& http_response::get_content() const{
     382            0 :         return content_;
     383              :     }
     384              : 
     385        45698 :     std::string& http_response::get_content(){
     386        45698 :         return content_;
     387              :     }
     388              : 
     389           12 :     size_t http_response::get_content_size() const{
     390           12 :         return content_.size();
     391              :     }
     392              : 
     393          933 :     void http_response::set_content(std::string content){
     394          933 :         content_ = std::move(content);
     395          933 :         set_content_length(content_.size());
     396          933 :     }
     397              : 
     398          828 :     void http_response::set_content(std::string content, std::string content_type){
     399          828 :         set_content(std::move(content));
     400          828 :         set_content_type(std::move(content_type));
     401          828 :     }
     402              : 
     403          936 :     void http_response::set_content_length(size_t content_length){
     404          936 :         content_length_ = content_length;
     405          936 :         set_header(http::header::content_length, boost::lexical_cast<std::string>(content_length));
     406          936 :     }
     407              : 
     408          831 :     void http_response::set_content_type(std::string&& content_type){
     409          831 :         set_header(http::header::content_type, std::move(content_type));
     410          831 :     }
     411              : 
     412           11 :     void http_response::set_content_type(const std::string& content_type) {
     413           11 :         set_header(http::header::content_type, content_type);
     414           11 :     }
     415              : 
     416          822 :     void http_response::set_reason_phrase(const std::string& reason) {
     417          822 :         reason_phrase_ = reason;
     418          822 :     }
     419              : 
     420              : }
        

Generated by: LCOV version 2.0-1