GCC Code Coverage Report


Directory: libs/http_proto/include/boost/http_proto/
File: boost/http_proto/parser.hpp
Date: 2023-02-11 03:18:39
Exec Total Coverage
Lines: 8 9 88.9%
Functions: 5 6 83.3%
Branches: 0 2 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/string_view.hpp>
16 #include <boost/http_proto/detail/header.hpp>
17 #include <boost/http_proto/detail/workspace.hpp>
18 #include <boost/buffers/circular_buffer.hpp>
19 #include <boost/buffers/flat_buffer.hpp>
20 #include <boost/buffers/mutable_buffer_pair.hpp>
21 #include <boost/buffers/sink.hpp>
22 #include <boost/url/grammar/error.hpp>
23 #include <cstddef>
24 #include <cstdint>
25 #include <memory>
26 #include <utility>
27
28 namespace boost {
29 namespace http_proto {
30
31 #ifndef BOOST_HTTP_PROTO_DOCS
32 enum class version : char;
33 class request_parser;
34 class response_parser;
35 struct brotli_decoder_t;
36 struct brotli_encoder_t;
37 struct deflate_decoder_t;
38 struct deflate_encoder_t;
39 struct gzip_decoder_t;
40 struct gzip_encoder_t;
41 namespace detail {
42 struct codec;
43 }
44 #endif
45
46 /** A parser for HTTP/1 messages.
47
48 The parser is strict. Any malformed
49 inputs according to the documented
50 HTTP ABNFs is treated as an
51 unrecoverable error.
52 */
53 class BOOST_SYMBOL_VISIBLE
54 parser
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 /** Largest allowed size for the headers.
66
67 This determines an upper bound on the
68 allowed size of the start-line plus
69 all of the individual fields in the
70 headers. This counts all delimiters
71 including trailing CRLFs.
72 */
73 std::size_t headers_limit = 16 * 1024;
74
75 /** Largest allowed size for the start-line.
76
77 This determines an upper bound on the
78 allowed size for the request-line of
79 an HTTP request or the status-line of
80 an HTTP response.
81 */
82 std::size_t start_line_limit = 4096;
83
84 /** Largest size for one field.
85
86 This determines an upper bound on the
87 allowed size for any single header
88 in an HTTP message. This counts
89 the field name, field value, and
90 delimiters including a trailing CRLF.
91 */
92 std::size_t field_size_limit = 4096;
93
94 /** Largest allowed number of fields.
95
96 This determines an upper bound on the
97 largest number of individual header
98 fields that may appear in an HTTP
99 message.
100 */
101 std::size_t fields_limit = 100;
102
103 /** Largest allowed size for a content body.
104
105 The size of the body is measured
106 after removing any transfer encodings,
107 including a chunked encoding.
108 */
109 std::uint64_t body_limit = 64 * 1024;
110 };
111
112 using mutable_buffers_type =
113 buffers::mutable_buffer_pair;
114
115 private:
116 BOOST_HTTP_PROTO_DECL parser(
117 detail::kind, config_base const&);
118 BOOST_HTTP_PROTO_DECL void construct(
119 std::size_t extra_buffer_size);
120 public:
121
122 //--------------------------------------------
123 //
124 // Special Members
125 //
126 //--------------------------------------------
127
128 /** Destructor
129 */
130 BOOST_HTTP_PROTO_DECL
131 ~parser();
132
133 /** Constructor
134 */
135 BOOST_HTTP_PROTO_DECL
136 parser(parser&&) noexcept;
137
138 //--------------------------------------------
139 //
140 // Observers
141 //
142 //--------------------------------------------
143
144 #if 0
145 /** Return true if any input was committed.
146 */
147 bool
148 got_some() const noexcept
149 {
150 return st_ != state::need_start;
151 }
152 #endif
153
154 /** Return true if the complete header was parsed.
155 */
156 bool
157 34 got_header() const noexcept
158 {
159 34 return st_ > state::headers;
160 }
161
162 /** Returns `true` if a complete message has been parsed.
163
164 Calling @ref reset prepares the parser
165 to process the next message in the stream.
166
167 */
168 bool
169 is_complete() const noexcept
170 {
171 return st_ == state::complete;
172 }
173
174 BOOST_HTTP_PROTO_DECL
175 string_view
176 body() const noexcept;
177
178 //--------------------------------------------
179 //
180 // Modifiers
181 //
182 //--------------------------------------------
183
184 /** Prepare for a new stream.
185 */
186 BOOST_HTTP_PROTO_DECL
187 void
188 reset() noexcept;
189
190 private:
191 // New message on the current stream
192 BOOST_HTTP_PROTO_DECL void
193 start_impl(bool head_response);
194 public:
195
196 /** Return the input buffer
197 */
198 BOOST_HTTP_PROTO_DECL
199 mutable_buffers_type
200 prepare();
201
202 /** Commit bytes to the input buffer
203 */
204 BOOST_HTTP_PROTO_DECL
205 void
206 commit(
207 std::size_t n);
208
209 /** Indicate there will be no more input
210 */
211 BOOST_HTTP_PROTO_DECL
212 void
213 commit_eof();
214
215 /** Parse pending input data
216 */
217 BOOST_HTTP_PROTO_DECL
218 void
219 parse(
220 error_code& ec);
221
222 /** Attach a body
223 */
224 template<
225 class Sink
226 #ifndef BOOST_HTTP_PROTO_DOCS
227 ,class = typename
228 std::enable_if<
229 buffers::is_sink<Sink
230 >::value>::type
231 #endif
232 >
233 auto
234 set_body(Sink&& sink) ->
235 typename std::decay<
236 Sink>::type;
237
238 //--------------------------------------------
239
240 /** Return any leftover data
241
242 This is used to forward unconsumed data
243 that could lie past the last message.
244 For example on a CONNECT request there
245 could be additional protocol-dependent
246 data that we want to retrieve.
247 */
248 BOOST_HTTP_PROTO_DECL
249 string_view
250 release_buffered_data() noexcept;
251
252 private:
253 745 void apply_params() noexcept
254 {
255 745 }
256
257 void apply_param(...) = delete;
258
259 template<class P0, class... Pn>
260 void
261 8 apply_params(P0&& p0, Pn&&... pn)
262 {
263 // If you get an error here it means
264 // you passed an unknown parameter type.
265 8 apply_param(std::forward<P0>(p0));
266
267 8 apply_params(std::forward<Pn>(pn)...);
268 8 }
269
270 BOOST_HTTP_PROTO_DECL void apply_param(config_base const&) noexcept;
271
272 // in detail/impl/brotli_codec.ipp
273 BOOST_HTTP_PROTO_EXT_DECL void apply_param(brotli_decoder_t const&);
274
275 // in detail/impl/zlib_codec.ipp
276 BOOST_HTTP_PROTO_ZLIB_DECL void apply_param(deflate_decoder_t const&);
277 BOOST_HTTP_PROTO_ZLIB_DECL void apply_param(gzip_decoder_t const&);
278
279 detail::header const* safe_get_header() const;
280 void parse_body(error_code&);
281 void parse_chunk(error_code&);
282
283 friend class request_parser;
284 friend class response_parser;
285
286 enum
287 {
288 br_codec = 0,
289 deflate_codec = 1,
290 gzip_codec = 2
291 };
292
293 enum class state
294 {
295 // order matters
296 need_start,
297 headers, // header fields
298 headers_done, // delivered headers
299 body, // reading payload
300 complete, // done
301 };
302
303 config_base cfg_;
304 detail::header h_;
305 detail::workspace ws_;
306 detail::header::config cfg_impl_;
307
308 std::unique_ptr<
309 detail::codec> dec_[3];
310 buffers::flat_buffer h_buf_;
311 buffers::circular_buffer b_buf_;
312 buffers::circular_buffer c_buf_;
313 detail::codec* cod_;
314
315 state st_;
316 bool got_eof_;
317 bool head_response_;
318 };
319
320 } // http_proto
321 } // boost
322
323 #include <boost/http_proto/impl/parser.hpp>
324
325 #endif
326