GCC Code Coverage Report


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