Toolbox snapshot
The Reactive C++ Toolbox
Loading...
Searching...
No Matches
Parser.hpp
Go to the documentation of this file.
1// The Reactive C++ Toolbox.
2// Copyright (C) 2013-2019 Swirly Cloud Limited
3// Copyright (C) 2022 Reactive Markets Limited
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17#ifndef TOOLBOX_HTTP_PARSER_HPP
18#define TOOLBOX_HTTP_PARSER_HPP
19
21#include <toolbox/io/Buffer.hpp>
22#include <toolbox/sys/Time.hpp>
23
24namespace toolbox {
25inline namespace http {
26
27template <typename DerivedT>
29 public:
30 explicit BasicParser(Type type) noexcept // NOLINT(hicpp-member-init)
31 : type_{type}
32 {
33 // The http_parser_init() function preserves "data".
34 // Important: cast is required for CRTP to work correctly with multiple inheritance.
35 parser_.data = static_cast<DerivedT*>(this);
36 http_parser_init(&parser_, static_cast<http_parser_type>(type));
37 last_header_elem_ = None;
38 }
39
40 // Copy.
41 BasicParser(const BasicParser&) noexcept = default;
42 BasicParser& operator=(const BasicParser&) noexcept = default;
43
44 // Move.
47
48 int http_major() const noexcept { return parser_.http_major; }
49 int http_minor() const noexcept { return parser_.http_minor; }
50 int status_code() const noexcept { return parser_.status_code; }
51 Method method() const noexcept { return static_cast<Method>(parser_.method); }
52 bool should_keep_alive() const noexcept { return http_should_keep_alive(&parser_) != 0; }
53 bool body_is_final() const noexcept { return http_body_is_final(&parser_) != 0; }
54
55 void pause() noexcept { http_parser_pause(&parser_, 1); }
56
57 protected:
58 ~BasicParser() = default;
59
61 {
62 // The http_parser_init() function preserves "data".
63 http_parser_init(&parser_, static_cast<http_parser_type>(type_));
64 last_header_elem_ = None;
65 }
66 std::size_t parse(CyclTime /*now*/, ConstBuffer buf)
67 {
68 static http_parser_settings settings{make_settings()};
70 buffer_size(buf));
71 const auto err = static_cast<http_errno>(parser_.http_errno);
72 if (err != HPE_OK) {
73 if (err == HPE_PAUSED) {
74 // Clear pause state.
75 http_parser_pause(&parser_, 0);
76 } else {
78 err_msg()
80 }
81 }
82 return rc;
83 }
84
85 private:
86 static http_parser_settings make_settings() noexcept
87 {
88 // Important: callbacks must return 0 on success. Returning a non-zero value indicates error
89 // to the parser, making it exit immediately.
91 settings.on_message_begin = on_message_begin;
92 settings.on_url = on_url;
93 settings.on_status = on_status;
94 settings.on_header_field = on_header_field;
95 settings.on_header_value = on_header_value;
96 settings.on_headers_complete = on_headers_end;
97 settings.on_body = on_body;
98 settings.on_message_complete = on_message_end;
99 settings.on_chunk_header = on_chunk_header;
100 settings.on_chunk_complete = on_chunk_end;
101 return settings;
102 }
103 static int on_message_begin(http_parser* parser) noexcept
104 {
105 return static_cast<DerivedT*>(parser->data)->on_http_message_begin(CyclTime::current())
106 ? 0
107 : -1;
108 }
109 static int on_url(http_parser* parser, const char* at, std::size_t length) noexcept
110 {
111 return static_cast<DerivedT*>(parser->data)->on_http_url(CyclTime::current(), {at, length})
112 ? 0
113 : -1;
114 }
115 static int on_status(http_parser* parser, const char* at, std::size_t length) noexcept
116 {
117 return static_cast<DerivedT*>(parser->data)
118 ->on_http_status(CyclTime::current(), {at, length})
119 ? 0
120 : -1;
121 }
122 static int on_header_field(http_parser* parser, const char* at, std::size_t length) noexcept
123 {
124 auto* const obj = static_cast<DerivedT*>(parser->data);
125 First first;
126 if (obj->last_header_elem_ != Field) {
127 obj->last_header_elem_ = Field;
128 first = First::Yes;
129 } else {
130 first = First::No;
131 }
132 return obj->on_http_header_field(CyclTime::current(), {at, length}, first) ? 0 : -1;
133 }
134 static int on_header_value(http_parser* parser, const char* at, std::size_t length) noexcept
135 {
136 auto* const obj = static_cast<DerivedT*>(parser->data);
137 First first;
138 if (obj->last_header_elem_ != Value) {
139 obj->last_header_elem_ = Value;
140 first = First::Yes;
141 } else {
142 first = First::No;
143 }
144 return obj->on_http_header_value(CyclTime::current(), {at, length}, first) ? 0 : -1;
145 }
146 static int on_headers_end(http_parser* parser) noexcept
147 {
148 return static_cast<DerivedT*>(parser->data)->on_http_headers_end(CyclTime::current()) ? 0
149 : -1;
150 }
151 static int on_body(http_parser* parser, const char* at, std::size_t length) noexcept
152 {
153 return static_cast<DerivedT*>(parser->data)->on_http_body(CyclTime::current(), {at, length})
154 ? 0
155 : -1;
156 }
157 static int on_message_end(http_parser* parser) noexcept
158 {
159 return static_cast<DerivedT*>(parser->data)->on_http_message_end(CyclTime::current()) ? 0
160 : -1;
161 }
162 static int on_chunk_header(http_parser* parser) noexcept
163 {
164 // When on_chunk_header is called, the current chunk length is stored in parser->content_length.
165 return static_cast<DerivedT*>(parser->data)
166 ->on_http_chunk_header(CyclTime::current(), parser->content_length)
167 ? 0
168 : -1;
169 }
170 static int on_chunk_end(http_parser* parser) noexcept
171 {
172 return static_cast<DerivedT*>(parser->data)->on_http_chunk_end(CyclTime::current()) ? 0
173 : -1;
174 }
175 Type type_;
176 http_parser parser_;
177 enum { None = 0, Field, Value } last_header_elem_;
178};
179
180} // namespace http
181} // namespace toolbox
182
183#endif // TOOLBOX_HTTP_PARSER_HPP
bool body_is_final() const noexcept
Definition Parser.hpp:53
int http_minor() const noexcept
Definition Parser.hpp:49
BasicParser(Type type) noexcept
Definition Parser.hpp:30
BasicParser(const BasicParser &) noexcept=default
std::size_t parse(CyclTime, ConstBuffer buf)
Definition Parser.hpp:66
void pause() noexcept
Definition Parser.hpp:55
void reset() noexcept
Definition Parser.hpp:60
BasicParser & operator=(const BasicParser &) noexcept=default
BasicParser(BasicParser &&) noexcept=default
bool should_keep_alive() const noexcept
Definition Parser.hpp:52
Method method() const noexcept
Definition Parser.hpp:51
int http_major() const noexcept
Definition Parser.hpp:48
int status_code() const noexcept
Definition Parser.hpp:50
boost::asio::const_buffer ConstBuffer
Definition Buffer.hpp:28
ErrMsg & err_msg() noexcept
Definition Exception.cpp:57
constexpr auto bind() noexcept
Definition Slot.hpp:92