1 // 2 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot 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/boostorg/beast 8 // 9 10 #ifndef BOOST_BEAST_HTTP_STRING_BODY_HPP 11 #define BOOST_BEAST_HTTP_STRING_BODY_HPP 12 13 #include <boost/beast/core/detail/config.hpp> 14 #include <boost/beast/core/buffer_traits.hpp> 15 #include <boost/beast/http/error.hpp> 16 #include <boost/beast/http/message.hpp> 17 #include <boost/beast/core/buffers_range.hpp> 18 #include <boost/beast/core/detail/clamp.hpp> 19 #include <boost/asio/buffer.hpp> 20 #include <boost/optional.hpp> 21 #include <cstdint> 22 #include <limits> 23 #include <memory> 24 #include <stdexcept> 25 #include <string> 26 #include <utility> 27 28 namespace boost { 29 namespace beast { 30 namespace http { 31 32 /** A <em>Body</em> using `std::basic_string` 33 34 This body uses `std::basic_string` as a memory-based container 35 for holding message payloads. Messages using this body type 36 may be serialized and parsed. 37 */ 38 template< 39 class CharT, 40 class Traits = std::char_traits<CharT>, 41 class Allocator = std::allocator<CharT>> 42 struct basic_string_body 43 { 44 private: 45 static_assert( 46 std::is_integral<CharT>::value && 47 sizeof(CharT) == 1, 48 "CharT requirements not met"); 49 50 public: 51 /** The type of container used for the body 52 53 This determines the type of @ref message::body 54 when this body type is used with a message container. 55 */ 56 using value_type = 57 std::basic_string<CharT, Traits, Allocator>; 58 59 /** Returns the payload size of the body 60 61 When this body is used with @ref message::prepare_payload, 62 the Content-Length will be set to the payload size, and 63 any chunked Transfer-Encoding will be removed. 64 */ 65 static 66 std::uint64_t sizeboost::beast::http::basic_string_body67 size(value_type const& body) 68 { 69 return body.size(); 70 } 71 72 /** The algorithm for parsing the body 73 74 Meets the requirements of <em>BodyReader</em>. 75 */ 76 #if BOOST_BEAST_DOXYGEN 77 using reader = __implementation_defined__; 78 #else 79 class reader 80 { 81 value_type& body_; 82 83 public: 84 template<bool isRequest, class Fields> 85 explicit reader(header<isRequest,Fields> &,value_type & b)86 reader(header<isRequest, Fields>&, value_type& b) 87 : body_(b) 88 { 89 } 90 91 void init(boost::optional<std::uint64_t> const & length,error_code & ec)92 init(boost::optional< 93 std::uint64_t> const& length, error_code& ec) 94 { 95 if(length) 96 { 97 if(*length > body_.max_size()) 98 { 99 ec = error::buffer_overflow; 100 return; 101 } 102 body_.reserve(beast::detail::clamp(*length)); 103 } 104 ec = {}; 105 } 106 107 template<class ConstBufferSequence> 108 std::size_t put(ConstBufferSequence const & buffers,error_code & ec)109 put(ConstBufferSequence const& buffers, 110 error_code& ec) 111 { 112 auto const extra = buffer_bytes(buffers); 113 auto const size = body_.size(); 114 if (extra > body_.max_size() - size) 115 { 116 ec = error::buffer_overflow; 117 return 0; 118 } 119 120 body_.resize(size + extra); 121 ec = {}; 122 CharT* dest = &body_[size]; 123 for(auto b : beast::buffers_range_ref(buffers)) 124 { 125 Traits::copy(dest, static_cast< 126 CharT const*>(b.data()), b.size()); 127 dest += b.size(); 128 } 129 return extra; 130 } 131 132 void finish(error_code & ec)133 finish(error_code& ec) 134 { 135 ec = {}; 136 } 137 }; 138 #endif 139 140 /** The algorithm for serializing the body 141 142 Meets the requirements of <em>BodyWriter</em>. 143 */ 144 #if BOOST_BEAST_DOXYGEN 145 using writer = __implementation_defined__; 146 #else 147 class writer 148 { 149 value_type const& body_; 150 151 public: 152 using const_buffers_type = 153 net::const_buffer; 154 155 template<bool isRequest, class Fields> 156 explicit writer(header<isRequest,Fields> const &,value_type const & b)157 writer(header<isRequest, Fields> const&, value_type const& b) 158 : body_(b) 159 { 160 } 161 162 void init(error_code & ec)163 init(error_code& ec) 164 { 165 ec = {}; 166 } 167 168 boost::optional<std::pair<const_buffers_type, bool>> get(error_code & ec)169 get(error_code& ec) 170 { 171 ec = {}; 172 return {{const_buffers_type{ 173 body_.data(), body_.size()}, false}}; 174 } 175 }; 176 #endif 177 }; 178 179 /// A <em>Body</em> using `std::string` 180 using string_body = basic_string_body<char>; 181 182 } // http 183 } // beast 184 } // boost 185 186 #endif 187