GCC Code Coverage Report


Directory: libs/http_proto/
File: boost/http_proto/parser.hpp
Date: 2024-02-09 15:32:02
Exec Total Coverage
Lines: 11 11 100.0%
Functions: 4 4 100.0%
Branches: 5 6 83.3%

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/sink.hpp>
17 #include <boost/http_proto/detail/header.hpp>
18 #include <boost/http_proto/detail/type_traits.hpp>
19 #include <boost/http_proto/detail/workspace.hpp>
20 #include <boost/buffers/circular_buffer.hpp>
21 #include <boost/buffers/flat_buffer.hpp>
22 #include <boost/buffers/mutable_buffer_pair.hpp>
23 #include <boost/buffers/mutable_buffer_span.hpp>
24 #include <boost/buffers/type_traits.hpp>
25 #include <boost/buffers/any_dynamic_buffer.hpp>
26 #include <boost/url/grammar/error.hpp>
27 #include <cstddef>
28 #include <cstdint>
29 #include <functional>
30 #include <memory>
31 #include <utility>
32
33 namespace boost {
34 namespace http_proto {
35
36 #ifndef BOOST_HTTP_PROTO_DOCS
37 class parser_service;
38 class filter;
39 class request_parser;
40 class response_parser;
41 class context;
42
43 #endif
44
45 /** A parser for HTTP/1 messages.
46
47 The parser is strict. Any malformed
48 inputs according to the documented
49 HTTP ABNFs is treated as an
50 unrecoverable error.
51 */
52 class BOOST_SYMBOL_VISIBLE
53 parser
54 {
55 BOOST_HTTP_PROTO_DECL
56 parser(context& ctx, detail::kind);
57
58 public:
59 /** Parser configuration settings
60
61 @see
62 @li <a href="https://stackoverflow.com/questions/686217/maximum-on-http-header-values"
63 >Maximum on HTTP header values (Stackoverflow)</a>
64 */
65 struct config_base
66 {
67 header_limits headers;
68
69 /** Largest allowed size for a content body.
70
71 The size of the body is measured
72 after removing any transfer encodings,
73 including a chunked encoding.
74 */
75 std::uint64_t body_limit = 64 * 1024;
76
77 /** True if parser can decode deflate transfer and content encodings.
78
79 The deflate decoder must already be
80 installed thusly, or else an exception
81 is thrown.
82
83 @par Install Deflate Decoder
84 @code
85 deflate_decoder_service::config cfg;
86 cfg.install( ctx );
87 @endcode
88 */
89 bool apply_deflate_decoder = false;
90
91 /** Minimum space for payload buffering.
92
93 This value controls the following
94 settings:
95
96 @li The smallest allocated size of
97 the buffers used for reading
98 and decoding the payload.
99
100 @li The lowest guaranteed size of
101 an in-place body.
102
103 @li The largest size used to reserve
104 space in dynamic buffer bodies
105 when the payload size is not
106 known ahead of time.
107
108 This cannot be zero, and this cannot
109 be greater than @ref body_limit.
110 */
111 std::size_t min_buffer = 4096;
112
113 /** Largest permissible output size in prepare.
114
115 This cannot be zero.
116 */
117 std::size_t max_prepare = std::size_t(-1);
118
119 /** Space to reserve for type-erasure.
120 */
121 std::size_t max_type_erase = 1024;
122 };
123
124 using mutable_buffers_type =
125 buffers::mutable_buffer_span;
126
127 using const_buffers_type =
128 buffers::const_buffer_span;
129
130 struct stream;
131
132 //--------------------------------------------
133 //
134 // Special Members
135 //
136 //--------------------------------------------
137
138 /** Destructor.
139 */
140 BOOST_HTTP_PROTO_DECL
141 ~parser();
142
143 /** Constructor (deleted)
144 */
145 parser(parser&&) = delete;
146
147 /** Assignment (deleted)
148 */
149 parser& operator=(parser&&) = delete;
150
151 //--------------------------------------------
152 //
153 // Observers
154 //
155 //--------------------------------------------
156
157 #if 0
158 /** Return true if any input was committed.
159 */
160 bool
161 got_some() const noexcept
162 {
163 return st_ != state::need_start;
164 }
165 #endif
166
167 /** Return true if the complete header was parsed.
168 */
169 bool
170 3622 got_header() const noexcept
171 {
172 3622 return st_ > state::header;
173 }
174
175 /** Returns `true` if a complete message has been parsed.
176
177 Calling @ref reset prepares the parser
178 to process the next message in the stream.
179
180 */
181 bool
182 2249 is_complete() const noexcept
183 {
184 2249 return st_ == state::complete;
185 }
186
187 /** Returns `true` if the end of the stream was reached.
188
189 The end of the stream is encountered
190 when one of the following conditions
191 occurs:
192
193 @li @ref commit_eof was called and there
194 is no more data left to parse, or
195
196 @li An unrecoverable error occurred
197 during parsing.
198
199 When the end of stream is reached, the
200 function @ref reset must be called
201 to start parsing a new stream.
202 */
203 bool
204 714 is_end_of_stream() const noexcept
205 {
206 return
207
2/2
✓ Branch 0 taken 582 times.
✓ Branch 1 taken 132 times.
1296 st_ == state::reset ||
208
1/2
✓ Branch 0 taken 582 times.
✗ Branch 1 not taken.
582 ( st_ == state::complete &&
209
2/2
✓ Branch 0 taken 342 times.
✓ Branch 1 taken 240 times.
1296 got_eof_);
210 }
211
212 //--------------------------------------------
213 //
214 // Modifiers
215 //
216 //--------------------------------------------
217
218 /** Prepare for a new stream.
219 */
220 BOOST_HTTP_PROTO_DECL
221 void
222 reset() noexcept;
223
224 /** Prepare for the next message on the stream.
225 */
226 void
227 1741 start()
228 {
229 1741 start_impl(false);
230 1736 }
231
232 private:
233 // New message on the current stream
234 BOOST_HTTP_PROTO_DECL void
235 start_impl(bool head_response);
236 public:
237
238 /** Return the input buffer
239 */
240 BOOST_HTTP_PROTO_DECL
241 mutable_buffers_type
242 prepare();
243
244 /** Commit bytes to the input buffer
245 */
246 BOOST_HTTP_PROTO_DECL
247 void
248 commit(
249 std::size_t n);
250
251 /** Indicate there will be no more input
252
253 @par Postconditions
254 All buffer sequences previously obtained
255 by calling @ref prepare are invalidated.
256 */
257 BOOST_HTTP_PROTO_DECL
258 void
259 commit_eof();
260
261 /** Parse pending input data
262 */
263 // VFALCO return result<void>?
264 BOOST_HTTP_PROTO_DECL
265 void
266 parse(
267 system::error_code& ec);
268
269 /** Attach a body.
270
271 This function attaches the specified elastic
272 buffer as the storage for the message body.
273 The parser acquires ownership of the object
274 `eb` and destroys it when:
275
276 @li @ref is_complete returns `true`, or
277 @li @ref reset is called, or
278 @li an unrecoverable parsing error occurs, or
279 @li the parser is destroyed.
280 */
281 // VFALCO Should this function have
282 // error_code& ec and call parse?
283 template<class ElasticBuffer>
284 #ifndef BOOST_HTTP_PROTO_DOCS
285 typename std::enable_if<
286 ! detail::is_reference_wrapper<
287 ElasticBuffer>::value &&
288 ! is_sink<ElasticBuffer>::value>::type
289 #else
290 void
291 #endif
292 set_body(ElasticBuffer&& eb);
293
294 /** Attach a body.
295
296 This function attaches the specified elastic
297 buffer reference as the storage for the message body.
298 Ownership is not transferred; the caller must
299 ensure that the lifetime of the object
300 reference by `eb` extends until:
301
302 @li @ref is_complete returns `true`, or
303 @li @ref reset is called, or
304 @li an unrecoverable parsing error occurs, or
305 @li the parser is destroyed.
306 */
307 template<class ElasticBuffer>
308 void set_body(
309 std::reference_wrapper<ElasticBuffer> eb);
310
311 /** Attach a body
312 */
313 template<class Sink>
314 #ifndef BOOST_HTTP_PROTO_DOCS
315 typename std::enable_if<
316 is_sink<Sink>::value,
317 typename std::decay<Sink>::type
318 >::type&
319 #else
320 typename std::decay<Sink>::type&
321 #endif
322 set_body(Sink&& sink);
323
324 /** Return the available body data and consume it.
325
326 The buffer referenced by the string view
327 will be invalidated if any member function
328 of the parser is called.
329 */
330 BOOST_HTTP_PROTO_DECL
331 const_buffers_type
332 pull_some();
333
334 /** Return the complete body as a contiguous character buffer.
335 */
336 BOOST_HTTP_PROTO_DECL
337 core::string_view
338 body() const noexcept;
339
340 //--------------------------------------------
341
342 /** Return any leftover data
343
344 This is used to forward unconsumed data
345 that could lie past the last message.
346 For example on a CONNECT request there
347 could be additional protocol-dependent
348 data that we want to retrieve.
349 */
350 // VFALCO rename to get_leftovers()?
351 BOOST_HTTP_PROTO_DECL
352 core::string_view
353 release_buffered_data() noexcept;
354
355 private:
356 friend class request_parser;
357 friend class response_parser;
358
359 detail::header const*
360 safe_get_header() const;
361 bool is_plain() const noexcept;
362 void on_headers(system::error_code&);
363 BOOST_HTTP_PROTO_DECL void on_set_body();
364 void init_dynamic(system::error_code&);
365
366 static constexpr unsigned buffers_N = 8;
367
368 enum class state
369 {
370 // order matters
371 reset,
372 start,
373 header,
374 body,
375 set_body,
376 complete
377 };
378
379 enum class how
380 {
381 in_place,
382 elastic,
383 sink,
384 pull
385 };
386
387 context& ctx_;
388 parser_service& svc_;
389 detail::workspace ws_;
390 detail::header h_;
391 std::uint64_t body_avail_;
392 std::uint64_t body_total_;
393 std::uint64_t payload_remain_;
394 std::size_t nprepare_;
395
396 buffers::flat_buffer fb_;
397 buffers::circular_buffer cb0_;
398 buffers::circular_buffer cb1_;
399 buffers::circular_buffer* body_buf_;
400 buffers::mutable_buffer_pair mbp_;
401 buffers::any_dynamic_buffer* eb_;
402 filter* filt_;
403 sink* sink_;
404
405 state st_;
406 how how_;
407 bool got_eof_;
408 // bool need_more_;
409 bool head_response_;
410 };
411
412 //------------------------------------------------
413
414 /** Install the parser service.
415 */
416 BOOST_HTTP_PROTO_DECL
417 void
418 install_parser_service(
419 context& ctx,
420 parser::config_base const& cfg);
421
422 } // http_proto
423 } // boost
424
425 #include <boost/http_proto/impl/parser.hpp>
426
427 #endif
428