LCOV - code coverage report
Current view: top level - src/net - http_parser.cpp (source / functions) Coverage Total Hit
Test: HPActor Coverage Lines: 98.2 % 113 111
Test Date: 2026-05-20 02:24:49 Functions: 100.0 % 14 14
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : // Copyright 2026 HPActor Contributors
       2                 :             : //
       3                 :             : // Licensed under the Apache License, Version 2.0 (the "License");
       4                 :             : // you may not use this file except in compliance with the License.
       5                 :             : // You may obtain a copy of the License at
       6                 :             : //
       7                 :             : //     http://www.apache.org/licenses/LICENSE-2.0
       8                 :             : //
       9                 :             : // Unless required by applicable law or agreed to in writing, software
      10                 :             : // distributed under the License is distributed on an "AS IS" BASIS,
      11                 :             : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12                 :             : // See the License for the specific language governing permissions and
      13                 :             : // limitations under the License.
      14                 :             : 
      15                 :             : #include <hpactor/net/http_parser.hpp>
      16                 :             : #include <hpactor/net/http_types.hpp>
      17                 :             : #include <hpactor/types/types.hpp>
      18                 :             : 
      19                 :             : #include <cstring>
      20                 :             : #include <string>
      21                 :             : #include <vector>
      22                 :             : 
      23                 :             : namespace hpactor {
      24                 :             : namespace net {
      25                 :             : 
      26                 :             : // =============================================================================
      27                 :             : // HttpParser Implementation
      28                 :             : // =============================================================================
      29                 :             : 
      30                 :          14 : HttpParser::HttpParser(HttpParserMode mode) : mode_(mode) {
      31                 :          14 :     llhttp_settings_init(&settings_);
      32                 :             : 
      33                 :          14 :     settings_.on_message_begin = on_message_begin_cb;
      34                 :          14 :     settings_.on_url = on_url_cb;
      35                 :          14 :     settings_.on_method = on_method_cb;
      36                 :          14 :     settings_.on_header_field = on_header_field_cb;
      37                 :          14 :     settings_.on_header_value = on_header_value_cb;
      38                 :          14 :     settings_.on_headers_complete = on_headers_complete_cb;
      39                 :          14 :     settings_.on_body = on_body_cb;
      40                 :          14 :     settings_.on_message_complete = on_message_complete_cb;
      41                 :             : 
      42                 :          14 :     auto llhttp_type = (mode == HttpParserMode::Request) ? HTTP_REQUEST
      43                 :             :                                                           : HTTP_RESPONSE;
      44                 :          14 :     llhttp_init(&parser_, llhttp_type, &settings_);
      45                 :          14 :     parser_.data = this;
      46                 :          14 : }
      47                 :             : 
      48                 :          14 : HttpParser::~HttpParser() = default;
      49                 :             : 
      50                 :           1 : void HttpParser::reset() {
      51                 :           1 :     auto llhttp_type = (mode_ == HttpParserMode::Request) ? HTTP_REQUEST
      52                 :             :                                                             : HTTP_RESPONSE;
      53                 :           1 :     llhttp_init(&parser_, llhttp_type, &settings_);
      54                 :           1 :     parser_.data = this;
      55                 :             : 
      56                 :           1 :     url_buf_.clear();
      57                 :           1 :     header_name_buf_.clear();
      58                 :           1 :     header_value_buf_.clear();
      59                 :           1 :     headers_.clear();
      60                 :           1 :     body_buf_.clear();
      61                 :           1 :     method_ = HttpMethod::GET;
      62                 :           1 :     http_major_ = 1;
      63                 :           1 :     http_minor_ = 1;
      64                 :           1 :     upgrade_ = false;
      65                 :           1 :     state_ = HttpParseState::Idle;
      66                 :           1 : }
      67                 :             : 
      68                 :          25 : size_t HttpParser::execute(const StreamBuffer& data) {
      69                 :          25 :     if (state_ == HttpParseState::Error) return 0;
      70                 :             : 
      71                 :          25 :     if (state_ == HttpParseState::ParsingBody) {
      72                 :           0 :         llhttp_resume(&parser_);
      73                 :             :     }
      74                 :             : 
      75                 :          25 :     const char* data_start = reinterpret_cast<const char*>(data.data());
      76                 :          25 :     size_t data_len = data.size();
      77                 :             : 
      78                 :          25 :     auto result = llhttp_execute(&parser_, data_start, data_len);
      79                 :             : 
      80                 :          25 :     if (result == HPE_PAUSED || result == HPE_PAUSED_UPGRADE) {
      81                 :           1 :         state_ = HttpParseState::ParsingBody;
      82                 :           1 :         const char* error_pos = llhttp_get_error_pos(&parser_);
      83                 :           1 :         if (error_pos && error_pos > data_start) {
      84                 :           1 :             size_t consumed = static_cast<size_t>(error_pos - data_start);
      85                 :           1 :             return (consumed <= data_len) ? consumed : data_len;
      86                 :             :         }
      87                 :           0 :         return 0;
      88                 :          24 :     } else if (result != HPE_OK) {
      89                 :           1 :         state_ = HttpParseState::Error;
      90                 :           1 :         if (on_error_) {
      91                 :           1 :             on_error_(result, llhttp_errno_name(result));
      92                 :             :         }
      93                 :           1 :         return 0;
      94                 :             :     }
      95                 :             : 
      96                 :          23 :     return data_len;
      97                 :             : }
      98                 :             : 
      99                 :           5 : bool HttpParser::should_keep_alive() const {
     100                 :           5 :     return llhttp_should_keep_alive(&parser_);
     101                 :             : }
     102                 :             : 
     103                 :          16 : void HttpParser::finish_header() {
     104                 :          16 :     headers_.push_back({std::move(header_name_buf_), std::move(header_value_buf_)});
     105                 :          16 :     header_name_buf_.clear();
     106                 :          16 :     header_value_buf_.clear();
     107                 :          16 : }
     108                 :             : 
     109                 :             : // =============================================================================
     110                 :             : // llhttp Callback Trampolines
     111                 :             : // =============================================================================
     112                 :             : 
     113                 :          15 : int HttpParser::on_message_begin_cb(llhttp_t* parser) {
     114                 :          15 :     auto* self = static_cast<HttpParser*>(parser->data);
     115                 :          15 :     self->state_ = HttpParseState::ParsingHeaders;
     116                 :          15 :     self->url_buf_.clear();
     117                 :          15 :     self->headers_.clear();
     118                 :          15 :     self->body_buf_.clear();
     119                 :          15 :     return 0;
     120                 :             : }
     121                 :             : 
     122                 :          13 : int HttpParser::on_url_cb(llhttp_t* parser, const char* data, size_t len) {
     123                 :          13 :     auto* self = static_cast<HttpParser*>(parser->data);
     124                 :          13 :     self->url_buf_.append(data, len);
     125                 :          13 :     return 0;
     126                 :             : }
     127                 :             : 
     128                 :          12 : int HttpParser::on_method_cb(llhttp_t* parser, const char* data, size_t len) {
     129                 :          12 :     auto* self = static_cast<HttpParser*>(parser->data);
     130                 :          12 :     self->method_ = method_from_string(data, len);
     131                 :          12 :     return 0;
     132                 :             : }
     133                 :             : 
     134                 :          17 : int HttpParser::on_header_field_cb(llhttp_t* parser, const char* data, size_t len) {
     135                 :          17 :     auto* self = static_cast<HttpParser*>(parser->data);
     136                 :          17 :     if (!self->header_value_buf_.empty()) {
     137                 :           4 :         self->finish_header();
     138                 :             :     }
     139                 :          17 :     self->header_name_buf_.append(data, len);
     140                 :          17 :     return 0;
     141                 :             : }
     142                 :             : 
     143                 :          19 : int HttpParser::on_header_value_cb(llhttp_t* parser, const char* data, size_t len) {
     144                 :          19 :     auto* self = static_cast<HttpParser*>(parser->data);
     145                 :          19 :     self->header_value_buf_.append(data, len);
     146                 :          19 :     return 0;
     147                 :             : }
     148                 :             : 
     149                 :          14 : int HttpParser::on_headers_complete_cb(llhttp_t* parser) {
     150                 :          14 :     auto* self = static_cast<HttpParser*>(parser->data);
     151                 :          14 :     if (!self->header_name_buf_.empty()) {
     152                 :          12 :         self->finish_header();
     153                 :             :     }
     154                 :          14 :     self->http_major_ = parser->http_major;
     155                 :          14 :     self->http_minor_ = parser->http_minor;
     156                 :          14 :     self->upgrade_ = parser->upgrade;
     157                 :          14 :     return 0;
     158                 :             : }
     159                 :             : 
     160                 :           6 : int HttpParser::on_body_cb(llhttp_t* parser, const char* data, size_t len) {
     161                 :           6 :     auto* self = static_cast<HttpParser*>(parser->data);
     162                 :           6 :     self->body_buf_.append(reinterpret_cast<const uint8_t*>(data), len);
     163                 :           6 :     return 0;
     164                 :             : }
     165                 :             : 
     166                 :          14 : int HttpParser::on_message_complete_cb(llhttp_t* parser) {
     167                 :          14 :     auto* self = static_cast<HttpParser*>(parser->data);
     168                 :          14 :     self->state_ = HttpParseState::Complete;
     169                 :             : 
     170                 :          14 :     if (self->mode_ == HttpParserMode::Response) {
     171                 :           2 :         if (self->on_response_) {
     172                 :           2 :             int status = llhttp_get_status_code(parser);
     173                 :           2 :             self->on_response_(status, std::move(self->headers_),
     174                 :           2 :                                 std::move(self->body_buf_));
     175                 :             :         }
     176                 :             :     } else {
     177                 :          12 :         if (self->on_message_) {
     178                 :           9 :             HttpRequest req;
     179                 :           9 :             req.method = self->method_;
     180                 :           9 :             req.path = std::move(self->url_buf_);
     181                 :           9 :             req.headers = std::move(self->headers_);
     182                 :           9 :             req.http_major = self->http_major_;
     183                 :           9 :             req.http_minor = self->http_minor_;
     184                 :           9 :             req.body = std::move(self->body_buf_);
     185                 :           9 :             self->on_message_(std::move(req));
     186                 :           9 :         }
     187                 :             :     }
     188                 :             : 
     189                 :          14 :     return 0;
     190                 :             : }
     191                 :             : 
     192                 :             : } // namespace net
     193                 :             : } // namespace hpactor
        

Generated by: LCOV version 2.0-1