Line data Source code
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 0 : 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 0 : stream( 338 : parser& pr) noexcept 339 0 : : pr_(&pr) 340 : { 341 0 : } 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