GCC Code Coverage Report


Directory: libs/http_proto/include/boost/http_proto/
File: boost/http_proto/parser.hpp
Date: 2023-02-25 19:48:06
Exec Total Coverage
Lines: 2 5 40.0%
Functions: 1 3 33.3%
Branches: 0 0 -%

Line Branch Exec Source
1 //
2 // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // Official repository: https://github.com/CPPAlliance/http_proto
8 //
9
10 #ifndef BOOST_HTTP_PROTO_PARSER_HPP
11 #define BOOST_HTTP_PROTO_PARSER_HPP
12
13 #include <boost/http_proto/detail/config.hpp>
14 #include <boost/http_proto/error.hpp>
15 #include <boost/http_proto/header_limits.hpp>
16 #include <boost/http_proto/string_view.hpp>
17 #include <boost/http_proto/detail/header.hpp>
18 #include <boost/http_proto/detail/workspace.hpp>
19 #include <boost/buffers/circular_buffer.hpp>
20 #include <boost/buffers/flat_buffer.hpp>
21 #include <boost/buffers/mutable_buffer_pair.hpp>
22 #include <boost/buffers/sink.hpp>
23 #include <boost/buffers/type_traits.hpp>
24 #include <boost/url/grammar/error.hpp>
25 #include <cstddef>
26 #include <cstdint>
27 #include <memory>
28 #include <utility>
29
30 namespace boost {
31 namespace http_proto {
32
33 #ifndef BOOST_HTTP_PROTO_DOCS
34 struct parser_service;
35 class request_parser;
36 class response_parser;
37 class context;
38
39 #endif
40
41 /** A parser for HTTP/1 messages.
42
43 The parser is strict. Any malformed
44 inputs according to the documented
45 HTTP ABNFs is treated as an
46 unrecoverable error.
47 */
48 class BOOST_SYMBOL_VISIBLE
49 parser
50 {
51 BOOST_HTTP_PROTO_DECL
52 parser(context& ctx, detail::kind);
53
54 public:
55 /** Parser configuration settings
56
57 @see
58 @li <a href="https://stackoverflow.com/questions/686217/maximum-on-http-header-values"
59 >Maximum on HTTP header values (Stackoverflow)</a>
60 */
61 struct config_base
62 {
63 header_limits headers;
64
65 /** Largest allowed size for a content body.
66
67 The size of the body is measured
68 after removing any transfer encodings,
69 including a chunked encoding.
70 */
71 std::uint64_t body_limit = 64 * 1024;
72
73 /** True if parser can decode deflate transfer and content encodings.
74
75 The deflate decoder must already be
76 installed thusly, or else an exception
77 is thrown.
78
79 @par Install Deflate Decoder
80 @code
81 deflate_decoder_service::config cfg;
82 cfg.install( ctx );
83 @endcode
84 */
85 bool apply_deflate_decoder = false;
86
87 /** Minimum space for in-place bodies.
88 */
89 std::size_t min_in_place_body = 4096;
90
91 /** Largest permissible output size in prepare.
92 */
93 std::size_t max_prepare = std::size_t(-1);
94
95 /** Space to reserve for type-erasure.
96 */
97 std::size_t max_type_erase = 1024;
98 };
99
100 using mutable_buffers_type =
101 buffers::mutable_buffer_pair;
102
103 struct stream;
104
105 //--------------------------------------------
106 //
107 // Special Members
108 //
109 //--------------------------------------------
110
111 /** Destructor.
112 */
113 BOOST_HTTP_PROTO_DECL
114 ~parser();
115
116 /** Constructor.
117 */
118 BOOST_HTTP_PROTO_DECL
119 parser(parser&&) noexcept;
120
121 //--------------------------------------------
122 //
123 // Observers
124 //
125 //--------------------------------------------
126
127 #if 0
128 /** Return true if any input was committed.
129 */
130 bool
131 got_some() const noexcept
132 {
133 return st_ != state::need_start;
134 }
135 #endif
136
137 /** Return true if the complete header was parsed.
138 */
139 bool
140 34 got_header() const noexcept
141 {
142 34 return st_ > state::headers;
143 }
144
145 /** Returns `true` if a complete message has been parsed.
146
147 Calling @ref reset prepares the parser
148 to process the next message in the stream.
149
150 */
151 bool
152 is_complete() const noexcept
153 {
154 return st_ == state::complete;
155 }
156
157 //--------------------------------------------
158 //
159 // Modifiers
160 //
161 //--------------------------------------------
162
163 /** Prepare for a new stream.
164 */
165 BOOST_HTTP_PROTO_DECL
166 void
167 reset() noexcept;
168
169 private:
170 // New message on the current stream
171 BOOST_HTTP_PROTO_DECL void
172 start_impl(bool head_response);
173 public:
174
175 /** Return the input buffer
176 */
177 BOOST_HTTP_PROTO_DECL
178 mutable_buffers_type
179 prepare();
180
181 /** Commit bytes to the input buffer
182 */
183 BOOST_HTTP_PROTO_DECL
184 void
185 commit(
186 std::size_t n);
187
188 /** Indicate there will be no more input
189 */
190 BOOST_HTTP_PROTO_DECL
191 void
192 commit_eof();
193
194 /** Parse pending input data
195 */
196 BOOST_HTTP_PROTO_DECL
197 void
198 parse(
199 error_code& ec);
200
201 /** Attach a body
202 */
203 // VFALCO Should this function have
204 // error_code& ec and call parse?
205 template<class DynamicBuffer>
206 #ifndef BOOST_HTTP_PROTO_DOCS
207 typename std::enable_if<
208 buffers::is_dynamic_buffer<
209 DynamicBuffer>::value,
210 typename std::decay<
211 DynamicBuffer>::type
212 >::type
213 #else
214 typename std::decay<
215 DynamicBuffer>::type
216 #endif
217 set_body(DynamicBuffer&& b);
218
219 /** Attach a body
220 */
221 // VFALCO Should this function have
222 // error_code& ec and call parse?
223 template<class Sink>
224 #ifndef BOOST_HTTP_PROTO_DOCS
225 typename std::enable_if<
226 buffers::is_sink<Sink>::value,
227 typename std::decay<Sink>::type
228 >::type
229 #else
230 typename std::decay<Sink>::type
231 #endif
232 set_body(Sink&& sink);
233
234 /** Return a stream for receiving body data.
235 */
236 BOOST_HTTP_PROTO_DECL
237 stream
238 get_stream();
239
240 //--------------------------------------------
241
242 /** Return any leftover data
243
244 This is used to forward unconsumed data
245 that could lie past the last message.
246 For example on a CONNECT request there
247 could be additional protocol-dependent
248 data that we want to retrieve.
249 */
250 BOOST_HTTP_PROTO_DECL
251 string_view
252 release_buffered_data() noexcept;
253
254 private:
255 detail::header const* safe_get_header() const;
256 void on_set_body();
257 void parse_body(error_code&);
258 void parse_chunk(error_code&);
259
260 friend class request_parser;
261 friend class response_parser;
262
263 template<class T>
264 struct any_dynamic_impl;
265 struct any_dynamic;
266 static constexpr unsigned dynamic_N_ = 8;
267
268 enum class state
269 {
270 // order matters
271 need_start,
272 headers, // header fields
273 headers_done, // delivered headers
274 body, // reading payload
275 complete, // done
276 };
277
278 enum class body
279 {
280 in_place,
281 dynamic,
282 sink,
283 stream
284 };
285
286 context& ctx_;
287 parser_service& svc_;
288 detail::workspace ws_;
289 detail::header h_;
290
291 buffers::flat_buffer fb_;
292 buffers::circular_buffer cb0_;
293 buffers::circular_buffer cb1_;
294 buffers::circular_buffer* cb_;
295 buffers::sink* sink_;
296 any_dynamic* dynamic_;
297
298 state st_;
299 body body_;
300 bool got_eof_;
301 bool head_response_;
302 std::uint64_t remain_;
303 };
304
305 //------------------------------------------------
306
307 struct parser::stream
308 {
309 /** Constructor.
310 */
311 stream() = default;
312
313 /** Constructor.
314 */
315 stream(stream const&) = default;
316
317 /** Constructor.
318 */
319 stream& operator=
320 (stream const&) = default;
321
322 using buffers_type =
323 buffers::const_buffer_pair;
324
325 BOOST_HTTP_PROTO_DECL
326 buffers_type
327 data() const noexcept;
328
329 BOOST_HTTP_PROTO_DECL
330 void
331 consume(std::size_t n);
332
333 private:
334 friend class parser;
335
336 explicit
337 stream(
338 parser& pr) noexcept
339 : pr_(&pr)
340 {
341 }
342
343 parser* pr_ = nullptr;
344 };
345
346 //------------------------------------------------
347
348 /** Install the parser service.
349 */
350 BOOST_HTTP_PROTO_DECL
351 void
352 install_parser_service(
353 context& ctx,
354 parser::config_base const& cfg);
355
356 } // http_proto
357 } // boost
358
359 #include <boost/http_proto/impl/parser.hpp>
360
361 #endif
362