LCOV - code coverage report
Current view: top level - http/server - request_factory.cpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 72.5 % 211 153
Test Date: 2026-02-20 15:38:22 Functions: 82.4 % 17 14

            Line data    Source code
       1              : #include <sstream>
       2              : #include "request_factory.hpp"
       3              : #include "../common/http_request.hpp"
       4              : #include "../util/url.hpp"
       5              : #include "../../util/logger.hpp"
       6              : 
       7              : namespace thinger::http {
       8              : 
       9          858 :     request_factory::request_factory() : state_(method_start) {
      10          858 :     }
      11              : 
      12       103750 :     boost::tribool request_factory::consume(char input) {
      13       103750 :         switch (state_) {
      14          918 :             case method_start:
      15          918 :                 if (!is_char(input) || is_ctl(input) || is_tspecial(input)) {
      16            0 :                     return false;
      17              :                 }
      18              :                 else {
      19          918 :                     state_ = method;
      20          918 :                     tempString1_.push_back(input);
      21          918 :                     return boost::indeterminate;
      22              :                 }
      23         3444 :             case method:
      24         3444 :                 if (input == ' ') {
      25              :                     // initialize a new http request if necessary
      26          914 :                     if(!req) req = std::make_shared<http_request>();
      27              :                     // store read method
      28          914 :                     on_http_method(tempString1_);
      29          914 :                     tempString1_.clear();
      30          914 :                     state_ = uri;
      31          914 :                     return boost::indeterminate;
      32              :                 }
      33         2530 :                 else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) {
      34            0 :                     return false;
      35              :                 }
      36              :                 else {
      37         2530 :                     tempString1_.push_back(input);
      38         2530 :                     return boost::indeterminate;
      39              :                 }
      40         8501 :             case uri:
      41         8501 :                 if (input == ' ') {
      42              :                     // decode get uri
      43          914 :                     std::string parsed_uri;
      44          914 :                     bool parsed_ok = util::url::url_decode(tempString1_, parsed_uri);
      45          914 :                     if (parsed_ok) {
      46              :                         // http_request path must be absolute and not contain "..".
      47          914 :                         if (parsed_uri.empty() || parsed_uri[0] != '/' || parsed_uri.find("..") != std::string::npos) {
      48            0 :                             return false;
      49              :                         }
      50          914 :                         on_http_uri(tempString1_);
      51          914 :                         tempString1_.clear();
      52              :                         // next step reading http version
      53          914 :                         state_ = http_version_h;
      54          914 :                         return boost::indeterminate;
      55              :                     } else {
      56            0 :                         tempString1_.clear();
      57            0 :                         return false;
      58              :                     }
      59          914 :                 }
      60         7587 :                 else if (is_ctl(input)) {
      61            0 :                     return false;
      62              :                 }
      63              :                 else {
      64         7587 :                     tempString1_.push_back(input);
      65         7587 :                     return boost::indeterminate;
      66              :                 }
      67          914 :             case http_version_h:
      68          914 :                 if (input == 'H') {
      69          914 :                     state_ = http_version_t_1;
      70          914 :                     return boost::indeterminate;
      71              :                 }
      72            0 :                 return false;
      73          914 :             case http_version_t_1:
      74          914 :                 if (input == 'T') {
      75          914 :                     state_ = http_version_t_2;
      76          914 :                     return boost::indeterminate;
      77              :                 }
      78            0 :                 return false;
      79          914 :             case http_version_t_2:
      80          914 :                 if (input == 'T') {
      81          914 :                     state_ = http_version_p;
      82          914 :                     return boost::indeterminate;
      83              :                 }
      84            0 :                 return false;
      85          914 :             case http_version_p:
      86          914 :                 if (input == 'P') {
      87          914 :                     state_ = http_version_slash;
      88          914 :                     return boost::indeterminate;
      89              :                 }
      90            0 :                 return false;
      91          914 :             case http_version_slash:
      92          914 :                 if (input == '/') {
      93          914 :                     state_ = http_version_major_start;
      94          914 :                     return boost::indeterminate;
      95              :                 }
      96            0 :                 return false;
      97          914 :             case http_version_major_start:
      98          914 :                 if (is_digit(input)) {
      99          914 :                     tempInt_ = input - '0';
     100          914 :                     state_ = http_version_major;
     101          914 :                     return boost::indeterminate;
     102              :                 }
     103            0 :                 return false;
     104          914 :             case http_version_major:
     105          914 :                 if (input == '.') {
     106          914 :                     on_http_major_version(tempInt_);
     107          914 :                     state_ = http_version_minor_start;
     108          914 :                     return boost::indeterminate;
     109              :                 }
     110            0 :                 else if (is_digit(input)) {
     111            0 :                     tempInt_ = tempInt_ * 10 + input - '0';
     112            0 :                     return boost::indeterminate;
     113              :                 }
     114            0 :                 return false;
     115          914 :             case http_version_minor_start:
     116          914 :                 if (is_digit(input)) {
     117          914 :                     tempInt_ = input - '0';
     118          914 :                     state_ = http_version_minor;
     119          914 :                     return boost::indeterminate;
     120              :                 }
     121            0 :                 return false;
     122          914 :             case http_version_minor:
     123          914 :                 if (is_digit(input)) {
     124            0 :                     tempInt_ = tempInt_ * 10 + input - '0';
     125            0 :                     return boost::indeterminate;
     126              :                 }
     127          914 :                 else if (input == '\r') {
     128          914 :                     on_http_minor_version(tempInt_);
     129          914 :                     tempInt_ = -1; // reserve temp int for storing content-lenght value
     130          914 :                     state_ = expecting_newline_1;
     131          914 :                     return boost::indeterminate;
     132              :                 }
     133            0 :                 return false;
     134          914 :             case expecting_newline_1:
     135          914 :                 if (input == '\n') {
     136          914 :                     state_ = header_line_start;
     137          914 :                     return boost::indeterminate;
     138              :                 }
     139            0 :                 return false;
     140         3863 :             case header_line_start:
     141         3863 :                 if (input == '\r') {
     142          914 :                     state_ = expecting_newline_3;
     143          914 :                     return boost::indeterminate;
     144              :                 }
     145         2949 :                 else if (!empty_headers() && (input == ' ' || input == '\t')) {
     146            0 :                     state_ = header_lws;
     147            0 :                     return boost::indeterminate;
     148              :                 }
     149         2949 :                 else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) {
     150            0 :                     return false;
     151              :                 }
     152              :                 else {
     153         2949 :                     tempString1_.clear();
     154         2949 :                     tempString1_.push_back(input);
     155         2949 :                     state_ = header_name;
     156         2949 :                     return boost::indeterminate;
     157              :                 }
     158            0 :             case header_lws:
     159            0 :                 if (input == '\r') {
     160            0 :                     state_ = expecting_newline_2;
     161            0 :                     return boost::indeterminate;
     162              :                 }
     163            0 :                 else if (input == ' ' || input == '\t') {
     164            0 :                     return boost::indeterminate;
     165              :                 }
     166            0 :                 else if (is_ctl(input)) {
     167            0 :                     return false;
     168              :                 }
     169              :                 else {
     170            0 :                     state_ = header_value;
     171            0 :                     tempString1_.push_back(input);
     172            0 :                     return boost::indeterminate;
     173              :                 }
     174        29591 :             case header_name:
     175        29591 :                 if (input == ':') {
     176         2949 :                     state_ = space_before_header_value;
     177         2949 :                     return boost::indeterminate;
     178              :                 }
     179        26642 :                 else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) {
     180            0 :                     return false;
     181              :                 }
     182              :                 else {
     183        26642 :                     tempString1_.push_back(input);
     184        26642 :                     return boost::indeterminate;
     185              :                 }
     186         2949 :             case space_before_header_value:
     187         2949 :                 if (input == ' ') {
     188         2949 :                     tempString2_.clear();
     189         2949 :                     state_ = header_value;
     190         2949 :                     return boost::indeterminate;
     191              :                 }
     192            0 :                 return false;
     193        41481 :             case header_value:
     194        41481 :                 if (input == '\r') {
     195         2949 :                     on_http_header(tempString1_, tempString2_);
     196         2949 :                     state_ = expecting_newline_2;
     197         2949 :                     return boost::indeterminate;
     198              :                 }
     199        38532 :                 else if (is_ctl(input)) {
     200            0 :                     return false;
     201              :                 }
     202              :                 else {
     203        38532 :                     tempString2_.push_back(input);
     204        38532 :                     return boost::indeterminate;
     205              :                 }
     206         2949 :             case expecting_newline_2:
     207         2949 :                 if (input == '\n') {
     208         2949 :                     state_ = header_line_start;
     209         2949 :                     return boost::indeterminate;
     210              :                 }
     211            0 :                 return false;
     212          914 :             case expecting_newline_3:
     213          914 :                 if (input == '\n'){
     214          914 :                     if(headers_only_ || get_content_length() == 0){
     215          914 :                         return true;
     216              :                     }
     217            0 :                     state_ = content;
     218            0 :                     return boost::indeterminate;
     219              :                 }
     220            0 :                 return false;
     221            0 :             case content:
     222            0 :                 on_content(input);
     223            0 :                 if(get_content_read()<get_content_length()){
     224            0 :                     return boost::indeterminate;
     225              :                 }
     226            0 :                 return true;
     227            0 :             default:
     228            0 :                 return false;
     229              :         }
     230              :     }
     231              : 
     232        33039 :     bool request_factory::is_char(int c) {
     233        33039 :         return c >= 0 && c <= 127;
     234              :     }
     235              : 
     236        79158 :     bool request_factory::is_ctl(int c) {
     237        79158 :         return (c >= 0 && c <= 31) || (c == 127);
     238              :     }
     239              : 
     240        33039 :     bool request_factory::is_tspecial(int c) {
     241        33039 :         switch (c) {
     242            0 :             case '(':
     243              :             case ')':
     244              :             case '<':
     245              :             case '>':
     246              :             case '@':
     247              :             case ',':
     248              :             case ';':
     249              :             case ':':
     250              :             case '\\':
     251              :             case '"':
     252              :             case '/':
     253              :             case '[':
     254              :             case ']':
     255              :             case '?':
     256              :             case '=':
     257              :             case '{':
     258              :             case '}':
     259              :             case ' ':
     260              :             case '\t':
     261            0 :                 return true;
     262        33039 :             default:
     263        33039 :                 return false;
     264              :         }
     265              :     }
     266              : 
     267         2742 :     bool request_factory::is_digit(int c) {
     268         2742 :         return c >= '0' && c <= '9';
     269              :     }
     270              : 
     271          912 :     std::shared_ptr<http_request> request_factory::consume_request() {
     272          912 :         std::shared_ptr<http_request> request(req);
     273          912 :         req.reset();
     274          912 :         state_ =  method_start;
     275          912 :         tempString1_.clear();
     276          912 :         tempString2_.clear();
     277          912 :         return request;
     278              :     }
     279              : 
     280          914 :     void request_factory::on_http_method(const std::string& method){
     281          914 :         req->set_method(method);
     282          914 :     }
     283              : 
     284            0 :     void request_factory::on_http_status_code(unsigned short status_code){
     285              : 
     286            0 :     }
     287              : 
     288          914 :     void request_factory::on_http_uri(const std::string& uri){
     289          914 :         req->set_uri(uri);
     290          914 :     }
     291              : 
     292          914 :     void request_factory::on_http_major_version(uint8_t major)
     293              :     {
     294          914 :         req->set_http_version_major(major);
     295          914 :     }
     296              : 
     297          914 :     void request_factory::on_http_minor_version(uint16_t minor){
     298          914 :         req->set_http_version_minor(minor);
     299          914 :     }
     300              : 
     301         2949 :     void request_factory::on_http_header(const std::string& name, const std::string& value){
     302         2949 :         req->process_header(name, value);
     303         2949 :     }
     304              : 
     305            0 :     void request_factory::on_content(char content){
     306            0 :         req->get_body().push_back(content);
     307            0 :     }
     308              : 
     309            4 :     size_t request_factory::get_content_length(){
     310            4 :         return req->get_content_length();
     311              :     }
     312              : 
     313            0 :     size_t request_factory::get_content_read(){
     314            0 :         return req->get_body().size();
     315              :     }
     316              : 
     317         2949 :     bool request_factory::empty_headers(){
     318         2949 :         return req->empty_headers();
     319              :     }
     320              : }
        

Generated by: LCOV version 2.0-1