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
|