GCC Code Coverage Report


Directory: libs/http_proto/include/boost/http_proto/
File: boost/http_proto/parser.hpp
Date: 2023-03-02 17:13:10
Exec Total Coverage
Lines: 8 9 88.9%
Functions: 3 4 75.0%
Branches: 6 6 100.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/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.
142 */
143 BOOST_HTTP_PROTO_DECL
144 parser(parser&&) noexcept;
145
146 //--------------------------------------------
147 //
148 // Observers
149 //
150 //--------------------------------------------
151
152 #if 0
153 /** Return true if any input was committed.
154 */
155 bool
156 got_some() const noexcept
157 {
158 return st_ != state::need_start;
159 }
160 #endif
161
162 /** Return true if the complete header was parsed.
163 */
164 bool
165 57707 got_header() const noexcept
166 {
167 57707 return st_ > state::header;
168 }
169
170 /** Returns `true` if a complete message has been parsed.
171
172 Calling @ref reset prepares the parser
173 to process the next message in the stream.
174
175 */
176 bool
177 48814 is_complete() const noexcept
178 {
179 48814 return st_ == state::complete;
180 }
181
182 /** Returns `true` if the end of the stream was reached.
183
184 The end of the stream is encountered
185 when one of the following conditions
186 occurs:
187
188 @li @ref commit_eof was called and there
189 is no more data left to parse, or
190
191 @li An unrecoverable error occurred
192 during parsing.
193
194 When the end of stream is reached, the
195 function @ref reset must be called
196 to start parsing a new stream.
197 */
198 bool
199 13550 is_end_of_stream() const noexcept
200 {
201 return
202
2/2
✓ Branch 0 taken 12690 times.
✓ Branch 1 taken 860 times.
26240 st_ == state::reset ||
203
2/2
✓ Branch 0 taken 12684 times.
✓ Branch 1 taken 6 times.
12690 ( st_ == state::complete &&
204
2/2
✓ Branch 0 taken 3759 times.
✓ Branch 1 taken 8925 times.
26234 got_eof_);
205 }
206
207 //--------------------------------------------
208 //
209 // Modifiers
210 //
211 //--------------------------------------------
212
213 /** Prepare for a new stream.
214 */
215 BOOST_HTTP_PROTO_DECL
216 void
217 reset() noexcept;
218
219 private:
220 // New message on the current stream
221 BOOST_HTTP_PROTO_DECL void
222 start_impl(bool head_response);
223 public:
224
225 /** Return the input buffer
226 */
227 BOOST_HTTP_PROTO_DECL
228 mutable_buffers_type
229 prepare();
230
231 /** Commit bytes to the input buffer
232 */
233 BOOST_HTTP_PROTO_DECL
234 void
235 commit(
236 std::size_t n);
237
238 /** Indicate there will be no more input
239 */
240 BOOST_HTTP_PROTO_DECL
241 void
242 commit_eof();
243
244 /** Parse pending input data
245 */
246 BOOST_HTTP_PROTO_DECL
247 void
248 parse(
249 system::error_code& ec);
250
251 /** Attach a body
252 */
253 // VFALCO Should this function have
254 // error_code& ec and call parse?
255 #ifndef BOOST_HTTP_PROTO_DOCS
256 template<
257 class DynamicBuffer
258 , class = typename std::enable_if<
259 buffers::is_dynamic_buffer<
260 DynamicBuffer>::value
261 >::type
262 >
263 #else
264 template<class DynamicBuffer>
265 #endif
266 typename std::decay<
267 DynamicBuffer>::type&
268 set_body(DynamicBuffer&& b);
269
270 /** Attach a body
271 */
272 template<class Sink>
273 #ifndef BOOST_HTTP_PROTO_DOCS
274 typename std::enable_if<
275 is_sink<Sink>::value,
276 typename std::decay<Sink>::type
277 >::type
278 #else
279 typename std::decay<Sink>::type
280 #endif
281 set_body(Sink&& sink);
282
283 /** Return the available body data and consume it.
284
285 The buffer referenced by the string view
286 will be invalidated if any member function
287 of the parser is called.
288 */
289 BOOST_HTTP_PROTO_DECL
290 const_buffers_type
291 pull_some();
292
293 /** Return the complete body as a contiguous character buffer.
294 */
295 BOOST_HTTP_PROTO_DECL
296 core::string_view
297 body() const noexcept;
298
299 //--------------------------------------------
300
301 /** Return any leftover data
302
303 This is used to forward unconsumed data
304 that could lie past the last message.
305 For example on a CONNECT request there
306 could be additional protocol-dependent
307 data that we want to retrieve.
308 */
309 BOOST_HTTP_PROTO_DECL
310 core::string_view
311 release_buffered_data() noexcept;
312
313 private:
314 friend class request_parser;
315 friend class response_parser;
316
317 detail::header const*
318 safe_get_header() const;
319 bool is_plain() const noexcept;
320 void on_headers(system::error_code&);
321
322 BOOST_HTTP_PROTO_DECL void on_set_body();
323
324 static constexpr unsigned buffers_N = 8;
325
326 enum class state
327 {
328 // order matters
329 reset,
330 start,
331 header,
332 body,
333 body_set,
334 complete,
335 };
336
337 enum class how
338 {
339 in_place,
340 dynamic,
341 sink,
342 pull
343 };
344
345 context& ctx_;
346 parser_service& svc_;
347 detail::workspace ws_;
348 detail::header h_;
349 std::uint64_t body_avail_; // in body_buf_
350 std::uint64_t body_total_; // total output
351 std::uint64_t payload_remain_; // if known
352
353 buffers::flat_buffer fb_;
354 buffers::circular_buffer cb0_;
355 buffers::circular_buffer cb1_;
356 buffers::circular_buffer* body_buf_;
357 buffers::mutable_buffer_pair mbp_;
358 buffers::any_dynamic_buffer* dyn_;
359 filter* filt_;
360 sink* sink_;
361
362 state st_;
363 how how_;
364 bool got_eof_;
365 bool head_response_;
366 };
367
368 //------------------------------------------------
369
370 /** Install the parser service.
371 */
372 BOOST_HTTP_PROTO_DECL
373 void
374 install_parser_service(
375 context& ctx,
376 parser::config_base const& cfg);
377
378 } // http_proto
379 } // boost
380
381 #include <boost/http_proto/impl/parser.hpp>
382
383 #endif
384