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-04-21 17:49:55 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         1004 :     request_factory::request_factory() : state_(method_start) {
      10         1004 :     }
      11              : 
      12       123052 :     boost::tribool request_factory::consume(char input) {
      13       123052 :         switch (state_) {
      14         1064 :             case method_start:
      15         1064 :                 if (!is_char(input) || is_ctl(input) || is_tspecial(input)) {
      16            0 :                     return false;
      17              :                 }
      18              :                 else {
      19         1064 :                     state_ = method;
      20         1064 :                     tempString1_.push_back(input);
      21         1064 :                     return boost::indeterminate;
      22              :                 }
      23         3965 :             case method:
      24         3965 :                 if (input == ' ') {
      25              :                     // initialize a new http request if necessary
      26         1060 :                     if(!req) req = std::make_shared<http_request>();
      27              :                     // store read method
      28         1060 :                     on_http_method(tempString1_);
      29         1060 :                     tempString1_.clear();
      30         1060 :                     state_ = uri;
      31         1060 :                     return boost::indeterminate;
      32              :                 }
      33         2905 :                 else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) {
      34            0 :                     return false;
      35              :                 }
      36              :                 else {
      37         2905 :                     tempString1_.push_back(input);
      38         2905 :                     return boost::indeterminate;
      39              :                 }
      40        10249 :             case uri:
      41        10249 :                 if (input == ' ') {
      42              :                     // decode get uri
      43         1060 :                     std::string parsed_uri;
      44         1060 :                     bool parsed_ok = util::url::url_decode(tempString1_, parsed_uri);
      45         1060 :                     if (parsed_ok) {
      46              :                         // http_request path must be absolute and not contain "..".
      47         1060 :                         if (parsed_uri.empty() || parsed_uri[0] != '/' || parsed_uri.find("..") != std::string::npos) {
      48            0 :                             return false;
      49              :                         }
      50         1060 :                         on_http_uri(tempString1_);
      51         1060 :                         tempString1_.clear();
      52              :                         // next step reading http version
      53         1060 :                         state_ = http_version_h;
      54         1060 :                         return boost::indeterminate;
      55              :                     } else {
      56            0 :                         tempString1_.clear();
      57            0 :                         return false;
      58              :                     }
      59         1060 :                 }
      60         9189 :                 else if (is_ctl(input)) {
      61            0 :                     return false;
      62              :                 }
      63              :                 else {
      64         9189 :                     tempString1_.push_back(input);
      65         9189 :                     return boost::indeterminate;
      66              :                 }
      67         1060 :             case http_version_h:
      68         1060 :                 if (input == 'H') {
      69         1060 :                     state_ = http_version_t_1;
      70         1060 :                     return boost::indeterminate;
      71              :                 }
      72            0 :                 return false;
      73         1060 :             case http_version_t_1:
      74         1060 :                 if (input == 'T') {
      75         1060 :                     state_ = http_version_t_2;
      76         1060 :                     return boost::indeterminate;
      77              :                 }
      78            0 :                 return false;
      79         1060 :             case http_version_t_2:
      80         1060 :                 if (input == 'T') {
      81         1060 :                     state_ = http_version_p;
      82         1060 :                     return boost::indeterminate;
      83              :                 }
      84            0 :                 return false;
      85         1060 :             case http_version_p:
      86         1060 :                 if (input == 'P') {
      87         1060 :                     state_ = http_version_slash;
      88         1060 :                     return boost::indeterminate;
      89              :                 }
      90            0 :                 return false;
      91         1060 :             case http_version_slash:
      92         1060 :                 if (input == '/') {
      93         1060 :                     state_ = http_version_major_start;
      94         1060 :                     return boost::indeterminate;
      95              :                 }
      96            0 :                 return false;
      97         1060 :             case http_version_major_start:
      98         1060 :                 if (is_digit(input)) {
      99         1060 :                     tempInt_ = input - '0';
     100         1060 :                     state_ = http_version_major;
     101         1060 :                     return boost::indeterminate;
     102              :                 }
     103            0 :                 return false;
     104         1060 :             case http_version_major:
     105         1060 :                 if (input == '.') {
     106         1060 :                     on_http_major_version(tempInt_);
     107         1060 :                     state_ = http_version_minor_start;
     108         1060 :                     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         1060 :             case http_version_minor_start:
     116         1060 :                 if (is_digit(input)) {
     117         1060 :                     tempInt_ = input - '0';
     118         1060 :                     state_ = http_version_minor;
     119         1060 :                     return boost::indeterminate;
     120              :                 }
     121            0 :                 return false;
     122         1060 :             case http_version_minor:
     123         1060 :                 if (is_digit(input)) {
     124            0 :                     tempInt_ = tempInt_ * 10 + input - '0';
     125            0 :                     return boost::indeterminate;
     126              :                 }
     127         1060 :                 else if (input == '\r') {
     128         1060 :                     on_http_minor_version(tempInt_);
     129         1060 :                     tempInt_ = -1; // reserve temp int for storing content-lenght value
     130         1060 :                     state_ = expecting_newline_1;
     131         1060 :                     return boost::indeterminate;
     132              :                 }
     133            0 :                 return false;
     134         1060 :             case expecting_newline_1:
     135         1060 :                 if (input == '\n') {
     136         1060 :                     state_ = header_line_start;
     137         1060 :                     return boost::indeterminate;
     138              :                 }
     139            0 :                 return false;
     140         4582 :             case header_line_start:
     141         4582 :                 if (input == '\r') {
     142         1060 :                     state_ = expecting_newline_3;
     143         1060 :                     return boost::indeterminate;
     144              :                 }
     145         3522 :                 else if (!empty_headers() && (input == ' ' || input == '\t')) {
     146            0 :                     state_ = header_lws;
     147            0 :                     return boost::indeterminate;
     148              :                 }
     149         3522 :                 else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) {
     150            0 :                     return false;
     151              :                 }
     152              :                 else {
     153         3522 :                     tempString1_.clear();
     154         3522 :                     tempString1_.push_back(input);
     155         3522 :                     state_ = header_name;
     156         3522 :                     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        35376 :             case header_name:
     175        35376 :                 if (input == ':') {
     176         3522 :                     state_ = space_before_header_value;
     177         3522 :                     return boost::indeterminate;
     178              :                 }
     179        31854 :                 else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) {
     180            0 :                     return false;
     181              :                 }
     182              :                 else {
     183        31854 :                     tempString1_.push_back(input);
     184        31854 :                     return boost::indeterminate;
     185              :                 }
     186         3522 :             case space_before_header_value:
     187         3522 :                 if (input == ' ') {
     188         3522 :                     tempString2_.clear();
     189         3522 :                     state_ = header_value;
     190         3522 :                     return boost::indeterminate;
     191              :                 }
     192            0 :                 return false;
     193        49112 :             case header_value:
     194        49112 :                 if (input == '\r') {
     195         3522 :                     on_http_header(tempString1_, tempString2_);
     196         3522 :                     state_ = expecting_newline_2;
     197         3522 :                     return boost::indeterminate;
     198              :                 }
     199        45590 :                 else if (is_ctl(input)) {
     200            0 :                     return false;
     201              :                 }
     202              :                 else {
     203        45590 :                     tempString2_.push_back(input);
     204        45590 :                     return boost::indeterminate;
     205              :                 }
     206         3522 :             case expecting_newline_2:
     207         3522 :                 if (input == '\n') {
     208         3522 :                     state_ = header_line_start;
     209         3522 :                     return boost::indeterminate;
     210              :                 }
     211            0 :                 return false;
     212         1060 :             case expecting_newline_3:
     213         1060 :                 if (input == '\n'){
     214         1060 :                     if(headers_only_ || get_content_length() == 0){
     215         1060 :                         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        39345 :     bool request_factory::is_char(int c) {
     233        39345 :         return c >= 0 && c <= 127;
     234              :     }
     235              : 
     236        94124 :     bool request_factory::is_ctl(int c) {
     237        94124 :         return (c >= 0 && c <= 31) || (c == 127);
     238              :     }
     239              : 
     240        39345 :     bool request_factory::is_tspecial(int c) {
     241        39345 :         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        39345 :             default:
     263        39345 :                 return false;
     264              :         }
     265              :     }
     266              : 
     267         3180 :     bool request_factory::is_digit(int c) {
     268         3180 :         return c >= '0' && c <= '9';
     269              :     }
     270              : 
     271         1058 :     std::shared_ptr<http_request> request_factory::consume_request() {
     272         1058 :         std::shared_ptr<http_request> request(req);
     273         1058 :         req.reset();
     274         1058 :         state_ =  method_start;
     275         1058 :         tempString1_.clear();
     276         1058 :         tempString2_.clear();
     277         1058 :         return request;
     278              :     }
     279              : 
     280         1060 :     void request_factory::on_http_method(const std::string& method){
     281         1060 :         req->set_method(method);
     282         1060 :     }
     283              : 
     284            0 :     void request_factory::on_http_status_code(unsigned short status_code){
     285              : 
     286            0 :     }
     287              : 
     288         1060 :     void request_factory::on_http_uri(const std::string& uri){
     289         1060 :         req->set_uri(uri);
     290         1060 :     }
     291              : 
     292         1060 :     void request_factory::on_http_major_version(uint8_t major)
     293              :     {
     294         1060 :         req->set_http_version_major(major);
     295         1060 :     }
     296              : 
     297         1060 :     void request_factory::on_http_minor_version(uint16_t minor){
     298         1060 :         req->set_http_version_minor(minor);
     299         1060 :     }
     300              : 
     301         3522 :     void request_factory::on_http_header(const std::string& name, const std::string& value){
     302         3522 :         req->process_header(name, value);
     303         3522 :     }
     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         3522 :     bool request_factory::empty_headers(){
     318         3522 :         return req->empty_headers();
     319              :     }
     320              : }
        

Generated by: LCOV version 2.0-1