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_ICY_STREAM_HPP 11 #define BOOST_BEAST_HTTP_ICY_STREAM_HPP 12 13 #include <boost/beast/core/detail/config.hpp> 14 #include <boost/beast/core/error.hpp> 15 #include <boost/asio/async_result.hpp> 16 #include <boost/asio/buffer.hpp> 17 #include <boost/logic/tribool.hpp> 18 #include <type_traits> 19 20 namespace boost { 21 namespace beast { 22 namespace http { 23 24 /** Stream wrapper to process Shoutcast HTTP responses 25 26 This wrapper replaces the word "ICY" in the first 27 HTTP response received on the connection, with "HTTP/1.1". 28 This allows the Beast parser to be used with Shoutcast 29 servers, which send a non-standard HTTP message as the 30 response. 31 32 For asynchronous operations, the application must ensure 33 that they are are all performed within the same implicit 34 or explicit strand. 35 36 @par Thread Safety 37 @e Distinct @e objects: Safe.@n 38 @e Shared @e objects: Unsafe. 39 The application must also ensure that all asynchronous 40 operations are performed within the same implicit or explicit strand. 41 42 @par Example 43 To use the @ref icy_stream template with an @ref tcp_stream 44 you would write: 45 @code 46 http::icy_stream<tcp_stream> is(ioc); 47 @endcode 48 49 @tparam NextLayer The type representing the next layer, to which 50 data will be read and written during operations. For synchronous 51 operations, the type must support the <em>SyncStream</em> concept. 52 For asynchronous operations, the type must support the 53 <em>AsyncStream</em> concept. 54 55 @note A stream object must not be moved or destroyed while there 56 are pending asynchronous operations associated with it. 57 58 @par Concepts 59 <em>AsyncStream</em>, <em>SyncStream</em> 60 */ 61 template<class NextLayer> 62 class icy_stream 63 { 64 NextLayer stream_; 65 char buf_[8]; 66 unsigned char n_ = 0; 67 bool detect_ = true; 68 69 struct ops; 70 71 static 72 net::const_buffer version()73 version() 74 { 75 return {"HTTP/1.1", 8}; 76 } 77 78 public: 79 /// The type of the next layer. 80 using next_layer_type = 81 typename std::remove_reference<NextLayer>::type; 82 83 /// The type of the executor associated with the object. 84 using executor_type = typename next_layer_type::executor_type; 85 86 icy_stream(icy_stream&&) = default; 87 icy_stream(icy_stream const&) = default; 88 icy_stream& operator=(icy_stream&&) = default; 89 icy_stream& operator=(icy_stream const&) = default; 90 91 /** Destructor 92 93 The treatment of pending operations will be the same as that 94 of the next layer. 95 */ 96 ~icy_stream() = default; 97 98 /** Constructor 99 100 Arguments, if any, are forwarded to the next layer's constructor. 101 */ 102 template<class... Args> 103 explicit 104 icy_stream(Args&&... args); 105 106 //-------------------------------------------------------------------------- 107 108 /** Get the executor associated with the object. 109 110 This function may be used to obtain the executor object that the 111 stream uses to dispatch handlers for asynchronous operations. 112 113 @return A copy of the executor that stream will use to dispatch handlers. 114 */ 115 executor_type get_executor()116 get_executor() noexcept 117 { 118 return stream_.get_executor(); 119 } 120 121 /** Get a reference to the next layer 122 123 This function returns a reference to the next layer 124 in a stack of stream layers. 125 126 @return A reference to the next layer in the stack of 127 stream layers. 128 */ 129 next_layer_type& next_layer()130 next_layer() 131 { 132 return stream_; 133 } 134 135 /** Get a reference to the next layer 136 137 This function returns a reference to the next layer in a 138 stack of stream layers. 139 140 @return A reference to the next layer in the stack of 141 stream layers. 142 */ 143 next_layer_type const& next_layer() const144 next_layer() const 145 { 146 return stream_; 147 } 148 149 //-------------------------------------------------------------------------- 150 151 /** Read some data from the stream. 152 153 This function is used to read data from the stream. The function call will 154 block until one or more bytes of data has been read successfully, or until 155 an error occurs. 156 157 @param buffers The buffers into which the data will be read. 158 159 @returns The number of bytes read. 160 161 @throws system_error Thrown on failure. 162 163 @note The `read_some` operation may not read all of the requested number of 164 bytes. Consider using the function `net::read` if you need to ensure 165 that the requested amount of data is read before the blocking operation 166 completes. 167 */ 168 template<class MutableBufferSequence> 169 std::size_t 170 read_some(MutableBufferSequence const& buffers); 171 172 /** Read some data from the stream. 173 174 This function is used to read data from the stream. The function call will 175 block until one or more bytes of data has been read successfully, or until 176 an error occurs. 177 178 @param buffers The buffers into which the data will be read. 179 180 @param ec Set to indicate what error occurred, if any. 181 182 @returns The number of bytes read. 183 184 @note The `read_some` operation may not read all of the requested number of 185 bytes. Consider using the function `net::read` if you need to ensure 186 that the requested amount of data is read before the blocking operation 187 completes. 188 */ 189 template<class MutableBufferSequence> 190 std::size_t 191 read_some( 192 MutableBufferSequence const& buffers, 193 error_code& ec); 194 195 /** Start an asynchronous read. 196 197 This function is used to asynchronously read one or more bytes of data from 198 the stream. The function call always returns immediately. 199 200 @param buffers The buffers into which the data will be read. Although the 201 buffers object may be copied as necessary, ownership of the underlying 202 buffers is retained by the caller, which must guarantee that they remain 203 valid until the handler is called. 204 205 @param handler The completion handler to invoke when the operation 206 completes. The implementation takes ownership of the handler by 207 performing a decay-copy. The equivalent function signature of 208 the handler must be: 209 @code 210 void handler( 211 const boost::system::error_code& error, // Result of operation. 212 std::size_t bytes_transferred // Number of bytes read. 213 ); 214 @endcode 215 Regardless of whether the asynchronous operation completes 216 immediately or not, the handler will not be invoked from within 217 this function. Invocation of the handler will be performed in a 218 manner equivalent to using `net::post`. 219 220 @note The `async_read_some` operation may not read all of the requested number of 221 bytes. Consider using the function `net::async_read` if you need 222 to ensure that the requested amount of data is read before the asynchronous 223 operation completes. 224 */ 225 template< 226 class MutableBufferSequence, 227 BOOST_BEAST_ASYNC_TPARAM2 ReadHandler = 228 net::default_completion_token_t<executor_type> 229 > 230 BOOST_BEAST_ASYNC_RESULT2(ReadHandler) 231 async_read_some( 232 MutableBufferSequence const& buffers, 233 ReadHandler&& handler = 234 net::default_completion_token_t<executor_type>{}); 235 236 /** Write some data to the stream. 237 238 This function is used to write data on the stream. The function call will 239 block until one or more bytes of data has been written successfully, or 240 until an error occurs. 241 242 @param buffers The data to be written. 243 244 @returns The number of bytes written. 245 246 @throws system_error Thrown on failure. 247 248 @note The `write_some` operation may not transmit all of the data to the 249 peer. Consider using the function `net::write` if you need to 250 ensure that all data is written before the blocking operation completes. 251 */ 252 template<class ConstBufferSequence> 253 std::size_t 254 write_some(ConstBufferSequence const& buffers); 255 256 /** Write some data to the stream. 257 258 This function is used to write data on the stream. The function call will 259 block until one or more bytes of data has been written successfully, or 260 until an error occurs. 261 262 @param buffers The data to be written. 263 264 @param ec Set to indicate what error occurred, if any. 265 266 @returns The number of bytes written. 267 268 @note The `write_some` operation may not transmit all of the data to the 269 peer. Consider using the function `net::write` if you need to 270 ensure that all data is written before the blocking operation completes. 271 */ 272 template<class ConstBufferSequence> 273 std::size_t 274 write_some( 275 ConstBufferSequence const& buffers, 276 error_code& ec); 277 278 /** Start an asynchronous write. 279 280 This function is used to asynchronously write one or more bytes of data to 281 the stream. The function call always returns immediately. 282 283 @param buffers The data to be written to the stream. Although the buffers 284 object may be copied as necessary, ownership of the underlying buffers is 285 retained by the caller, which must guarantee that they remain valid until 286 the handler is called. 287 288 @param handler The completion handler to invoke when the operation 289 completes. The implementation takes ownership of the handler by 290 performing a decay-copy. The equivalent function signature of 291 the handler must be: 292 @code 293 void handler( 294 error_code const& error, // Result of operation. 295 std::size_t bytes_transferred // Number of bytes written. 296 ); 297 @endcode 298 Regardless of whether the asynchronous operation completes 299 immediately or not, the handler will not be invoked from within 300 this function. Invocation of the handler will be performed in a 301 manner equivalent to using `net::post`. 302 303 @note The `async_write_some` operation may not transmit all of the data to 304 the peer. Consider using the function `net::async_write` if you need 305 to ensure that all data is written before the asynchronous operation completes. 306 */ 307 template< 308 class ConstBufferSequence, 309 BOOST_BEAST_ASYNC_TPARAM2 WriteHandler = 310 net::default_completion_token_t<executor_type> 311 > 312 BOOST_BEAST_ASYNC_RESULT2(WriteHandler) 313 async_write_some( 314 ConstBufferSequence const& buffers, 315 WriteHandler&& handler = 316 net::default_completion_token_t<executor_type>{}); 317 }; 318 319 } // http 320 } // beast 321 } // boost 322 323 #include <boost/beast/_experimental/http/impl/icy_stream.hpp> 324 325 #endif 326