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/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 0 : 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 4 : apply_params(P0&& p0, Pn&&... pn) 262 : { 263 : // If you get an error here it means 264 : // you passed an unknown parameter type. 265 4 : apply_param(std::forward<P0>(p0)); 266 : 267 4 : apply_params(std::forward<Pn>(pn)...); 268 4 : } 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