| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  | // | 
					
						
							|  |  |  | // Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // Distributed under the Boost Software License, Version 1.0. (See accompanying | 
					
						
							|  |  |  | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifndef BEAST_HTTP_IMPL_BASIC_PARSER_IPP | 
					
						
							|  |  |  | #define BEAST_HTTP_IMPL_BASIC_PARSER_IPP | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-10 12:03:00 -07:00
										 |  |  | #include <beast/core/type_traits.hpp> | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  | #include <beast/core/detail/ci_char_traits.hpp> | 
					
						
							|  |  |  | #include <beast/core/detail/clamp.hpp> | 
					
						
							|  |  |  | #include <beast/http/error.hpp> | 
					
						
							|  |  |  | #include <beast/http/rfc7230.hpp> | 
					
						
							|  |  |  | #include <boost/asio/buffer.hpp> | 
					
						
							| 
									
										
										
										
											2017-06-08 05:54:47 -07:00
										 |  |  | #include <boost/config.hpp> | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  | #include <algorithm> | 
					
						
							|  |  |  | #include <utility> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace beast { | 
					
						
							|  |  |  | namespace http { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  | template<bool isRequest, class Derived> | 
					
						
							|  |  |  | template<class OtherDerived> | 
					
						
							|  |  |  | basic_parser<isRequest, Derived>:: | 
					
						
							|  |  |  | basic_parser(basic_parser< | 
					
						
							|  |  |  |         isRequest, OtherDerived>&& other) | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |     : len_(other.len_) | 
					
						
							|  |  |  |     , buf_(std::move(other.buf_)) | 
					
						
							|  |  |  |     , buf_len_(other.buf_len_) | 
					
						
							|  |  |  |     , skip_(other.skip_) | 
					
						
							|  |  |  |     , state_(other.state_) | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     , f_(other.f_) | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  | template<bool isRequest, class Derived> | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  | bool | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  | basic_parser<isRequest, Derived>:: | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  | is_keep_alive() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     BOOST_ASSERT(is_header_done()); | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |     if(f_ & flagHTTP11) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if(f_ & flagConnectionClose) | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if(! (f_ & flagConnectionKeepAlive)) | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return (f_ & flagNeedEOF) == 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  | template<bool isRequest, class Derived> | 
					
						
							|  |  |  | boost::optional<std::uint64_t> | 
					
						
							|  |  |  | basic_parser<isRequest, Derived>:: | 
					
						
							|  |  |  | content_length() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     BOOST_ASSERT(is_header_done()); | 
					
						
							|  |  |  |     if(! (f_ & flagContentLength)) | 
					
						
							|  |  |  |         return boost::none; | 
					
						
							|  |  |  |     return len_; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template<bool isRequest, class Derived> | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | basic_parser<isRequest, Derived>:: | 
					
						
							|  |  |  | skip(bool v) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     BOOST_ASSERT(! got_some()); | 
					
						
							|  |  |  |     if(v) | 
					
						
							|  |  |  |         f_ |= flagSkipBody; | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         f_ &= ~flagSkipBody; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template<bool isRequest, class Derived> | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  | template<class ConstBufferSequence> | 
					
						
							|  |  |  | std::size_t | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  | basic_parser<isRequest, Derived>:: | 
					
						
							|  |  |  | put(ConstBufferSequence const& buffers, | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |     error_code& ec) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2017-05-06 12:36:40 -07:00
										 |  |  |     static_assert(is_const_buffer_sequence< | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |         ConstBufferSequence>::value, | 
					
						
							|  |  |  |             "ConstBufferSequence requirements not met"); | 
					
						
							|  |  |  |     auto const buffer = maybe_flatten(buffers); | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     return put(boost::asio::const_buffers_1{ | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |         buffer.data(), buffer.size()}, ec); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  | template<bool isRequest, class Derived> | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  | std::size_t | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  | basic_parser<isRequest, Derived>:: | 
					
						
							|  |  |  | put(boost::asio::const_buffers_1 const& buffer, | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |     error_code& ec) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     BOOST_ASSERT(state_ != state::complete); | 
					
						
							|  |  |  |     using boost::asio::buffer_size; | 
					
						
							|  |  |  |     auto p = boost::asio::buffer_cast< | 
					
						
							|  |  |  |         char const*>(*buffer.begin()); | 
					
						
							|  |  |  |     auto n = buffer_size(*buffer.begin()); | 
					
						
							|  |  |  |     auto const p0 = p; | 
					
						
							|  |  |  |     auto const p1 = p0 + n; | 
					
						
							|  |  |  | loop: | 
					
						
							|  |  |  |     switch(state_) | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     case state::nothing_yet: | 
					
						
							|  |  |  |         if(n == 0) | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |             ec = error::need_more; | 
					
						
							|  |  |  |             return 0; | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |         state_ = state::header; | 
					
						
							| 
									
										
										
										
											2017-06-08 05:54:47 -07:00
										 |  |  |         BOOST_FALLTHROUGH; | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     case state::header: | 
					
						
							|  |  |  |         parse_header(p, n, ec); | 
					
						
							|  |  |  |         if(ec) | 
					
						
							|  |  |  |             goto done; | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     case state::body0: | 
					
						
							|  |  |  |         impl().on_body(content_length(), ec); | 
					
						
							|  |  |  |         if(ec) | 
					
						
							|  |  |  |             goto done; | 
					
						
							|  |  |  |         state_ = state::body; | 
					
						
							| 
									
										
										
										
											2017-06-08 05:54:47 -07:00
										 |  |  |         BOOST_FALLTHROUGH; | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     case state::body: | 
					
						
							|  |  |  |         parse_body(p, n, ec); | 
					
						
							|  |  |  |         if(ec) | 
					
						
							|  |  |  |             goto done; | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     case state::body_to_eof0: | 
					
						
							|  |  |  |         impl().on_body(content_length(), ec); | 
					
						
							|  |  |  |         if(ec) | 
					
						
							|  |  |  |             goto done; | 
					
						
							|  |  |  |         state_ = state::body_to_eof; | 
					
						
							| 
									
										
										
										
											2017-06-08 05:54:47 -07:00
										 |  |  |         BOOST_FALLTHROUGH; | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     case state::body_to_eof: | 
					
						
							|  |  |  |         parse_body_to_eof(p, n, ec); | 
					
						
							|  |  |  |         if(ec) | 
					
						
							|  |  |  |             goto done; | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     case state::chunk_header0: | 
					
						
							|  |  |  |         impl().on_body(content_length(), ec); | 
					
						
							|  |  |  |         if(ec) | 
					
						
							| 
									
										
										
										
											2017-06-07 10:48:35 -07:00
										 |  |  |             goto done; | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |         state_ = state::chunk_header; | 
					
						
							| 
									
										
										
										
											2017-06-08 05:54:47 -07:00
										 |  |  |         BOOST_FALLTHROUGH; | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     case state::chunk_header: | 
					
						
							|  |  |  |         parse_chunk_header(p, n, ec); | 
					
						
							|  |  |  |         if(ec) | 
					
						
							|  |  |  |             goto done; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case state::chunk_body: | 
					
						
							|  |  |  |         parse_chunk_body(p, n, ec); | 
					
						
							|  |  |  |         if(ec) | 
					
						
							|  |  |  |             goto done; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case state::complete: | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-06-09 13:27:38 -07:00
										 |  |  |     if(p < p1 && ! is_done() && eager()) | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     { | 
					
						
							|  |  |  |         n = static_cast<std::size_t>(p1 - p); | 
					
						
							|  |  |  |         goto loop; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | done: | 
					
						
							|  |  |  |     return static_cast<std::size_t>(p - p0); | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  | template<bool isRequest, class Derived> | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  | void | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  | basic_parser<isRequest, Derived>:: | 
					
						
							|  |  |  | put_eof(error_code& ec) | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     BOOST_ASSERT(got_some()); | 
					
						
							|  |  |  |     if(state_ == state::header) | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |         ec = error::partial_message; | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if(f_ & (flagContentLength | flagChunked)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if(state_ != state::complete) | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |             ec = error::partial_message; | 
					
						
							|  |  |  |             return; | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |         return; | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     impl().on_complete(ec); | 
					
						
							|  |  |  |     if(ec) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     state_ = state::complete; | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  | template<bool isRequest, class Derived> | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  | template<class ConstBufferSequence> | 
					
						
							|  |  |  | inline | 
					
						
							| 
									
										
										
										
											2017-05-05 14:45:15 -07:00
										 |  |  | string_view | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  | basic_parser<isRequest, Derived>:: | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  | maybe_flatten( | 
					
						
							|  |  |  |     ConstBufferSequence const& buffers) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     using boost::asio::buffer_cast; | 
					
						
							|  |  |  |     using boost::asio::buffer_copy; | 
					
						
							|  |  |  |     using boost::asio::buffer_size; | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     auto const p = buffers.begin(); | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |     auto const last = buffers.end(); | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     if(p == last) | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |         return {nullptr, 0}; | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     if(std::next(p) == last) | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |     { | 
					
						
							|  |  |  |         // single buffer | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |         auto const b = *p; | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |         return {buffer_cast<char const*>(b), | 
					
						
							|  |  |  |             buffer_size(b)}; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     auto const len = buffer_size(buffers); | 
					
						
							|  |  |  |     if(len > buf_len_) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // reallocate | 
					
						
							|  |  |  |         buf_.reset(new char[len]); | 
					
						
							|  |  |  |         buf_len_ = len; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // flatten | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     buffer_copy(boost::asio::buffer( | 
					
						
							|  |  |  |         buf_.get(), buf_len_), buffers); | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |     return {buf_.get(), buf_len_}; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  | template<bool isRequest, class Derived> | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  | inline | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  | void | 
					
						
							|  |  |  | basic_parser<isRequest, Derived>:: | 
					
						
							|  |  |  | parse_header(char const*& p, | 
					
						
							|  |  |  |     std::size_t n, error_code& ec) | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     if(n < skip_ + 4) | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |         ec = http::error::need_more; | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     auto const term = find_eom( | 
					
						
							|  |  |  |         p + skip_, p + n, ec); | 
					
						
							|  |  |  |     if(ec) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     if(! term) | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |         skip_ = n - 3; | 
					
						
							|  |  |  |         ec = http::error::need_more; | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     skip_ = 0; | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     parse_header(p, term, ec, | 
					
						
							|  |  |  |         std::integral_constant<bool, isRequest>{}); | 
					
						
							|  |  |  |     if(ec) | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     impl().on_header(ec); | 
					
						
							|  |  |  |     if(ec) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     if(state_ == state::complete) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         impl().on_complete(ec); | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |         if(ec) | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |             return; | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  | template<bool isRequest, class Derived> | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  | void | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  | basic_parser<isRequest, Derived>:: | 
					
						
							|  |  |  | parse_header(char const*& p, char const* term, | 
					
						
							|  |  |  |     error_code& ec, std::true_type) | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  | { | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  |     request-line   = method SP request-target SP HTTP-version CRLF | 
					
						
							|  |  |  |     method         = token | 
					
						
							|  |  |  | */ | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     auto const method = parse_method(p); | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |     if(method.empty()) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         ec = error::bad_method; | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     if(*p++ != ' ') | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |     { | 
					
						
							|  |  |  |         ec = error::bad_method; | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     auto const target = parse_target(p); | 
					
						
							| 
									
										
										
										
											2017-05-02 15:49:22 -07:00
										 |  |  |     if(target.empty()) | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |     { | 
					
						
							|  |  |  |         ec = error::bad_path; | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     if(*p++ != ' ') | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |     { | 
					
						
							|  |  |  |         ec = error::bad_path; | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     auto const version = parse_version(p); | 
					
						
							|  |  |  |     if(version < 0 || ! parse_crlf(p)) | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |     { | 
					
						
							|  |  |  |         ec = error::bad_version; | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     if(version >= 11) | 
					
						
							|  |  |  |         f_ |= flagHTTP11; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-05 15:44:47 -07:00
										 |  |  |     impl().on_request(string_to_verb(method), | 
					
						
							| 
									
										
										
										
											2017-05-02 15:49:22 -07:00
										 |  |  |         method, target, version, ec); | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |     if(ec) | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     parse_fields(p, term, ec); | 
					
						
							|  |  |  |     if(ec) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     BOOST_ASSERT(p == term); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // RFC 7230 section 3.3 | 
					
						
							|  |  |  |     // https://tools.ietf.org/html/rfc7230#section-3.3 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if(f_ & flagSkipBody) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         state_ = state::complete; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if(f_ & flagContentLength) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if(len_ > 0) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             f_ |= flagHasBody; | 
					
						
							|  |  |  |             state_ = state::body0; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             state_ = state::complete; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if(f_ & flagChunked) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         f_ |= flagHasBody; | 
					
						
							|  |  |  |         state_ = state::chunk_header0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         len_ = 0; | 
					
						
							|  |  |  |         state_ = state::complete; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  | template<bool isRequest, class Derived> | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  | void | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  | basic_parser<isRequest, Derived>:: | 
					
						
							|  |  |  | parse_header(char const*& p, char const* term, | 
					
						
							|  |  |  |     error_code& ec, std::false_type) | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  | { | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  |      status-line    = HTTP-version SP status-code SP reason-phrase CRLF | 
					
						
							|  |  |  |      status-code    = 3*DIGIT | 
					
						
							|  |  |  |      reason-phrase  = *( HTAB / SP / VCHAR / obs-text ) | 
					
						
							|  |  |  | */ | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     auto const version = parse_version(p); | 
					
						
							|  |  |  |     if(version < 0 || *p != ' ') | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |     { | 
					
						
							|  |  |  |         ec = error::bad_version; | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     ++p; | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     auto const status = parse_status(p); | 
					
						
							|  |  |  |     if(status < 0 || *p != ' ') | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |     { | 
					
						
							|  |  |  |         ec = error::bad_status; | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     ++p; | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     auto const reason = parse_reason(p); | 
					
						
							|  |  |  |     if(! parse_crlf(p)) | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |     { | 
					
						
							|  |  |  |         ec = error::bad_reason; | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     if(version >= 11) | 
					
						
							|  |  |  |         f_ |= flagHTTP11; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |     impl().on_response( | 
					
						
							|  |  |  |         status, reason, version, ec); | 
					
						
							|  |  |  |     if(ec) | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     parse_fields(p, term, ec); | 
					
						
							|  |  |  |     if(ec) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     BOOST_ASSERT(p == term); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // RFC 7230 section 3.3 | 
					
						
							|  |  |  |     // https://tools.ietf.org/html/rfc7230#section-3.3 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if( (f_ & flagSkipBody) ||  // e.g. response to a HEAD request | 
					
						
							|  |  |  |         status  / 100 == 1 ||   // 1xx e.g. Continue | 
					
						
							|  |  |  |         status == 204 ||        // No Content | 
					
						
							|  |  |  |         status == 304)          // Not Modified | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         state_ = state::complete; | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if(f_ & flagContentLength) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if(len_ > 0) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             f_ |= flagHasBody; | 
					
						
							|  |  |  |             state_ = state::body0; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             state_ = state::complete; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if(f_ & flagChunked) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         f_ |= flagHasBody; | 
					
						
							|  |  |  |         state_ = state::chunk_header0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         f_ |= flagHasBody; | 
					
						
							|  |  |  |         f_ |= flagNeedEOF; | 
					
						
							|  |  |  |         state_ = state::body_to_eof0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template<bool isRequest, class Derived> | 
					
						
							|  |  |  | inline | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | basic_parser<isRequest, Derived>:: | 
					
						
							|  |  |  | parse_body(char const*& p, | 
					
						
							|  |  |  |     std::size_t n, error_code& ec) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     n = beast::detail::clamp(len_, n); | 
					
						
							|  |  |  |     impl().on_data(string_view{p, n}, ec); | 
					
						
							|  |  |  |     if(ec) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     p += n; | 
					
						
							|  |  |  |     len_ -= n; | 
					
						
							|  |  |  |     if(len_ > 0) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     impl().on_complete(ec); | 
					
						
							|  |  |  |     if(ec) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     state_ = state::complete; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template<bool isRequest, class Derived> | 
					
						
							|  |  |  | inline | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | basic_parser<isRequest, Derived>:: | 
					
						
							|  |  |  | parse_body_to_eof(char const*& p, | 
					
						
							|  |  |  |     std::size_t n, error_code& ec) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     impl().on_data(string_view{p, n}, ec); | 
					
						
							|  |  |  |     if(ec) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     p += n; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template<bool isRequest, class Derived> | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | basic_parser<isRequest, Derived>:: | 
					
						
							| 
									
										
										
										
											2017-06-07 10:48:35 -07:00
										 |  |  | parse_chunk_header(char const*& p0, | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     std::size_t n, error_code& ec) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  |     chunked-body   = *chunk last-chunk trailer-part CRLF | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     chunk          = chunk-size [ chunk-ext ] CRLF chunk-data CRLF | 
					
						
							|  |  |  |     last-chunk     = 1*("0") [ chunk-ext ] CRLF | 
					
						
							|  |  |  |     trailer-part   = *( header-field CRLF ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     chunk-size     = 1*HEXDIG | 
					
						
							|  |  |  |     chunk-data     = 1*OCTET ; a sequence of chunk-size octets | 
					
						
							|  |  |  |     chunk-ext      = *( ";" chunk-ext-name [ "=" chunk-ext-val ] ) | 
					
						
							|  |  |  |     chunk-ext-name = token | 
					
						
							|  |  |  |     chunk-ext-val  = token / quoted-string | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-07 10:48:35 -07:00
										 |  |  |     auto p = p0; | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     auto const pend = p + n; | 
					
						
							| 
									
										
										
										
											2017-06-07 10:48:35 -07:00
										 |  |  |     char const* eol; | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if(! (f_ & flagFinalChunk)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if(n < skip_ + 2) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             ec = error::need_more; | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-06-07 10:48:35 -07:00
										 |  |  |         if(f_ & flagExpectCRLF) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             // Treat the last CRLF in a chunk as | 
					
						
							|  |  |  |             // part of the next chunk, so p can | 
					
						
							|  |  |  |             // be parsed in one call instead of two. | 
					
						
							|  |  |  |             if(! parse_crlf(p)) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 ec = error::bad_chunk; | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         eol = find_eol(p0 + skip_, pend, ec); | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |         if(ec) | 
					
						
							|  |  |  |             return; | 
					
						
							| 
									
										
										
										
											2017-06-07 10:48:35 -07:00
										 |  |  |         if(! eol) | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |         { | 
					
						
							|  |  |  |             ec = error::need_more; | 
					
						
							|  |  |  |             skip_ = n - 1; | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-06-07 10:48:35 -07:00
										 |  |  |         skip_ = static_cast< | 
					
						
							|  |  |  |             std::size_t>(eol - 2 - p0); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |         std::uint64_t v; | 
					
						
							|  |  |  |         if(! parse_hex(p, v)) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             ec = error::bad_chunk; | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if(v != 0) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if(*p == ';') | 
					
						
							|  |  |  |             { | 
					
						
							| 
									
										
										
										
											2017-06-07 10:48:35 -07:00
										 |  |  |                 // VFALCO TODO Validate extension | 
					
						
							|  |  |  |                 impl().on_chunk(v, make_string( | 
					
						
							|  |  |  |                     p, eol - 2), ec); | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |                 if(ec) | 
					
						
							|  |  |  |                     return; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2017-06-07 10:48:35 -07:00
										 |  |  |             else if(p != eol - 2) | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |             { | 
					
						
							|  |  |  |                 ec = error::bad_chunk; | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             len_ = v; | 
					
						
							| 
									
										
										
										
											2017-06-07 10:48:35 -07:00
										 |  |  |             skip_ = 2; | 
					
						
							|  |  |  |             p0 = eol; | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |             f_ |= flagExpectCRLF; | 
					
						
							|  |  |  |             state_ = state::chunk_body; | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         f_ |= flagFinalChunk; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-06-07 10:48:35 -07:00
										 |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         BOOST_ASSERT(n >= 5); | 
					
						
							|  |  |  |         if(f_ & flagExpectCRLF) | 
					
						
							|  |  |  |             BOOST_VERIFY(parse_crlf(p)); | 
					
						
							|  |  |  |         std::uint64_t v; | 
					
						
							|  |  |  |         BOOST_VERIFY(parse_hex(p, v)); | 
					
						
							|  |  |  |         eol = find_eol(p, pend, ec); | 
					
						
							|  |  |  |         BOOST_ASSERT(! ec); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-07 10:48:35 -07:00
										 |  |  |     auto eom = find_eom(p0 + skip_, pend, ec); | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     if(ec) | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2017-06-07 10:48:35 -07:00
										 |  |  |     if(! eom) | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2017-06-07 10:48:35 -07:00
										 |  |  |         BOOST_ASSERT(n >= 3); | 
					
						
							|  |  |  |         skip_ = n - 3; | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |         ec = error::need_more; | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if(*p == ';') | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2017-06-07 10:48:35 -07:00
										 |  |  |         // VFALCO TODO Validate extension | 
					
						
							|  |  |  |         impl().on_chunk(0, make_string( | 
					
						
							|  |  |  |             p, eol - 2), ec); | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |         if(ec) | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-06-07 10:48:35 -07:00
										 |  |  |     p = eol; | 
					
						
							|  |  |  |     parse_fields(p, eom, ec); | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     if(ec) | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2017-06-07 10:48:35 -07:00
										 |  |  |     BOOST_ASSERT(p == eom); | 
					
						
							|  |  |  |     p0 = eom; | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     impl().on_complete(ec); | 
					
						
							|  |  |  |     if(ec) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     state_ = state::complete; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template<bool isRequest, class Derived> | 
					
						
							|  |  |  | inline | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | basic_parser<isRequest, Derived>:: | 
					
						
							|  |  |  | parse_chunk_body(char const*& p, | 
					
						
							|  |  |  |     std::size_t n, error_code& ec) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     n = beast::detail::clamp(len_, n); | 
					
						
							|  |  |  |     impl().on_data(string_view{p, n}, ec); | 
					
						
							|  |  |  |     if(ec) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     p += n; | 
					
						
							|  |  |  |     len_ -= n; | 
					
						
							|  |  |  |     if(len_ > 0) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     state_ = state::chunk_header; | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  | template<bool isRequest, class Derived> | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  | void | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  | basic_parser<isRequest, Derived>:: | 
					
						
							|  |  |  | parse_fields(char const*& p, | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |     char const* last, error_code& ec) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | /*  header-field   = field-name ":" OWS field-value OWS | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     field-name     = token | 
					
						
							|  |  |  |     field-value    = *( field-content / obs-fold ) | 
					
						
							|  |  |  |     field-content  = field-vchar [ 1*( SP / HTAB ) field-vchar ] | 
					
						
							|  |  |  |     field-vchar    = VCHAR / obs-text | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     obs-fold       = CRLF 1*( SP / HTAB ) | 
					
						
							|  |  |  |                    ; obsolete line folding | 
					
						
							|  |  |  |                    ; see Section 3.2.4 | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  |     for(;;) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |         auto term = find_eol(p, last, ec); | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |         if(ec) | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         BOOST_ASSERT(term); | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |         if(p == term - 2) | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |             p = term; | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |         auto const name = parse_name(p); | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |         if(name.empty()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             ec = error::bad_field; | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |         if(*p++ != ':') | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |         { | 
					
						
							|  |  |  |             ec = error::bad_field; | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if(*term != ' ' && | 
					
						
							|  |  |  |            *term != '\t') | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             auto it2 = term - 2; | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |             detail::skip_ows(p, it2); | 
					
						
							|  |  |  |             detail::skip_ows_rev(it2, p); | 
					
						
							| 
									
										
										
										
											2017-06-06 14:04:17 -07:00
										 |  |  |             auto const f = string_to_field(name); | 
					
						
							|  |  |  |             auto const value = make_string(p, it2); | 
					
						
							|  |  |  |             do_field(f, value, ec); | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |             if(ec) | 
					
						
							|  |  |  |                 return; | 
					
						
							| 
									
										
										
										
											2017-06-06 14:04:17 -07:00
										 |  |  |             impl().on_field(f, name, value, ec); | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |             if(ec) | 
					
						
							|  |  |  |                 return; | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |             p = term; | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             // obs-fold | 
					
						
							|  |  |  |             for(;;) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 auto const it2 = term - 2; | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |                 detail::skip_ows(p, it2); | 
					
						
							|  |  |  |                 if(p != it2) | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |                     break; | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |                 p = term; | 
					
						
							|  |  |  |                 if(*p != ' ' && *p != '\t') | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |                     break; | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |                 term = find_eol(p, last, ec); | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |                 if(ec) | 
					
						
							|  |  |  |                     return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             std::string s; | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |             if(p != term) | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |             { | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |                 s.append(p, term - 2); | 
					
						
							|  |  |  |                 p = term; | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |                 for(;;) | 
					
						
							|  |  |  |                 { | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |                     if(*p != ' ' && *p != '\t') | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |                         break; | 
					
						
							|  |  |  |                     s.push_back(' '); | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |                     detail::skip_ows(p, term - 2); | 
					
						
							|  |  |  |                     term = find_eol(p, last, ec); | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |                     if(ec) | 
					
						
							|  |  |  |                         return; | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |                     if(p != term - 2) | 
					
						
							|  |  |  |                         s.append(p, term - 2); | 
					
						
							|  |  |  |                     p = term; | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2017-06-06 14:04:17 -07:00
										 |  |  |             auto const f = string_to_field(name); | 
					
						
							|  |  |  |             string_view const value{s.data(), s.size()}; | 
					
						
							|  |  |  |             do_field(f, value, ec); | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |             if(ec) | 
					
						
							|  |  |  |                 return; | 
					
						
							| 
									
										
										
										
											2017-06-06 14:04:17 -07:00
										 |  |  |             impl().on_field(f, name, value, ec); | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |             if(ec) | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  | template<bool isRequest, class Derived> | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  | void | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  | basic_parser<isRequest, Derived>:: | 
					
						
							| 
									
										
										
										
											2017-06-06 14:04:17 -07:00
										 |  |  | do_field(field f, | 
					
						
							|  |  |  |     string_view value, error_code& ec) | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  | { | 
					
						
							|  |  |  |     // Connection | 
					
						
							| 
									
										
										
										
											2017-06-06 14:04:17 -07:00
										 |  |  |     if(f == field::connection || | 
					
						
							|  |  |  |         f == field::proxy_connection) | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |     { | 
					
						
							|  |  |  |         auto const list = opt_token_list{value}; | 
					
						
							|  |  |  |         if(! validate_list(list)) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             // VFALCO Should this be a field specific error? | 
					
						
							|  |  |  |             ec = error::bad_value; | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         for(auto const& s : list) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if(strieq("close", s)) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 f_ |= flagConnectionClose; | 
					
						
							|  |  |  |                 continue; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if(strieq("keep-alive", s)) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 f_ |= flagConnectionKeepAlive; | 
					
						
							|  |  |  |                 continue; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if(strieq("upgrade", s)) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 f_ |= flagConnectionUpgrade; | 
					
						
							|  |  |  |                 continue; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |     for(auto p = value.begin(); | 
					
						
							|  |  |  |         p != value.end(); ++p) | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |         if(! is_text(*p)) | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |         { | 
					
						
							|  |  |  |             ec = error::bad_value; | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Content-Length | 
					
						
							| 
									
										
										
										
											2017-06-06 14:04:17 -07:00
										 |  |  |     if(f == field::content_length) | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |     { | 
					
						
							|  |  |  |         if(f_ & flagContentLength) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             // duplicate | 
					
						
							|  |  |  |             ec = error::bad_content_length; | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if(f_ & flagChunked) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             // conflicting field | 
					
						
							|  |  |  |             ec = error::bad_content_length; | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         std::uint64_t v; | 
					
						
							|  |  |  |         if(! parse_dec( | 
					
						
							|  |  |  |             value.begin(), value.end(), v)) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             ec = error::bad_content_length; | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         len_ = v; | 
					
						
							|  |  |  |         f_ |= flagContentLength; | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Transfer-Encoding | 
					
						
							| 
									
										
										
										
											2017-06-06 14:04:17 -07:00
										 |  |  |     if(f == field::transfer_encoding) | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |     { | 
					
						
							|  |  |  |         if(f_ & flagChunked) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             // duplicate | 
					
						
							|  |  |  |             ec = error::bad_transfer_encoding; | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if(f_ & flagContentLength) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             // conflicting field | 
					
						
							|  |  |  |             ec = error::bad_transfer_encoding; | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         auto const v = token_list{value}; | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |         auto const p = std::find_if(v.begin(), v.end(), | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |             [&](typename token_list::value_type const& s) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 return strieq("chunked", s); | 
					
						
							|  |  |  |             }); | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |         if(p == v.end()) | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |             return; | 
					
						
							| 
									
										
										
										
											2017-05-31 08:01:55 -07:00
										 |  |  |         if(std::next(p) != v.end()) | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |             return; | 
					
						
							|  |  |  |         len_ = 0; | 
					
						
							|  |  |  |         f_ |= flagChunked; | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Upgrade | 
					
						
							| 
									
										
										
										
											2017-06-06 14:04:17 -07:00
										 |  |  |     if(f == field::upgrade) | 
					
						
							| 
									
										
										
										
											2016-11-20 07:32:41 -05:00
										 |  |  |     { | 
					
						
							|  |  |  |         f_ |= flagUpgrade; | 
					
						
							|  |  |  |         ec = {}; | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } // http | 
					
						
							|  |  |  | } // beast | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif |