| 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 |
| 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 |
| 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& |
| 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& |
| 144 | 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 | If the handler has an associated immediate executor, |
| 216 | an immediate completion will be dispatched to it. |
| 217 | Otherwise, the handler will not be invoked from within |
| 218 | this function. Invocation of the handler will be performed |
| 219 | by dispatching to the immediate executor. If no |
| 220 | immediate executor is specified, this is equivalent |
| 221 | to using `net::post`. |
| 222 | @note The `async_read_some` operation may not read all of the requested number of |
| 223 | bytes. Consider using the function `net::async_read` if you need |
| 224 | to ensure that the requested amount of data is read before the asynchronous |
| 225 | operation completes. |
| 226 | */ |
| 227 | template< |
| 228 | class MutableBufferSequence, |
| 229 | BOOST_BEAST_ASYNC_TPARAM2 ReadHandler = |
| 230 | net::default_completion_token_t<executor_type> |
| 231 | > |
| 232 | BOOST_BEAST_ASYNC_RESULT2(ReadHandler) |
| 233 | async_read_some( |
| 234 | MutableBufferSequence const& buffers, |
| 235 | ReadHandler&& handler = |
| 236 | net::default_completion_token_t<executor_type>{}); |
| 237 | |
| 238 | /** Write some data to the stream. |
| 239 | |
| 240 | This function is used to write data on the stream. The function call will |
| 241 | block until one or more bytes of data has been written successfully, or |
| 242 | until an error occurs. |
| 243 | |
| 244 | @param buffers The data to be written. |
| 245 | |
| 246 | @returns The number of bytes written. |
| 247 | |
| 248 | @throws system_error Thrown on failure. |
| 249 | |
| 250 | @note The `write_some` operation may not transmit all of the data to the |
| 251 | peer. Consider using the function `net::write` if you need to |
| 252 | ensure that all data is written before the blocking operation completes. |
| 253 | */ |
| 254 | template<class ConstBufferSequence> |
| 255 | std::size_t |
| 256 | write_some(ConstBufferSequence const& buffers); |
| 257 | |
| 258 | /** Write some data to the stream. |
| 259 | |
| 260 | This function is used to write data on the stream. The function call will |
| 261 | block until one or more bytes of data has been written successfully, or |
| 262 | until an error occurs. |
| 263 | |
| 264 | @param buffers The data to be written. |
| 265 | |
| 266 | @param ec Set to indicate what error occurred, if any. |
| 267 | |
| 268 | @returns The number of bytes written. |
| 269 | |
| 270 | @note The `write_some` operation may not transmit all of the data to the |
| 271 | peer. Consider using the function `net::write` if you need to |
| 272 | ensure that all data is written before the blocking operation completes. |
| 273 | */ |
| 274 | template<class ConstBufferSequence> |
| 275 | std::size_t |
| 276 | write_some( |
| 277 | ConstBufferSequence const& buffers, |
| 278 | error_code& ec); |
| 279 | |
| 280 | /** Start an asynchronous write. |
| 281 | |
| 282 | This function is used to asynchronously write one or more bytes of data to |
| 283 | the stream. The function call always returns immediately. |
| 284 | |
| 285 | @param buffers The data to be written to the stream. Although the buffers |
| 286 | object may be copied as necessary, ownership of the underlying buffers is |
| 287 | retained by the caller, which must guarantee that they remain valid until |
| 288 | the handler is called. |
| 289 | |
| 290 | @param handler The completion handler to invoke when the operation |
| 291 | completes. The implementation takes ownership of the handler by |
| 292 | performing a decay-copy. The equivalent function signature of |
| 293 | the handler must be: |
| 294 | @code |
| 295 | void handler( |
| 296 | error_code const& error, // Result of operation. |
| 297 | std::size_t bytes_transferred // Number of bytes written. |
| 298 | ); |
| 299 | @endcode |
| 300 | If the handler has an associated immediate executor, |
| 301 | an immediate completion will be dispatched to it. |
| 302 | Otherwise, the handler will not be invoked from within |
| 303 | this function. Invocation of the handler will be performed |
| 304 | by dispatching to the immediate executor. If no |
| 305 | immediate executor is specified, this is equivalent |
| 306 | to using `net::post`. |
| 307 | @note The `async_write_some` operation may not transmit all of the data to |
| 308 | the peer. Consider using the function `net::async_write` if you need |
| 309 | to ensure that all data is written before the asynchronous operation completes. |
| 310 | */ |
| 311 | template< |
| 312 | class ConstBufferSequence, |
| 313 | BOOST_BEAST_ASYNC_TPARAM2 WriteHandler = |
| 314 | net::default_completion_token_t<executor_type> |
| 315 | > |
| 316 | BOOST_BEAST_ASYNC_RESULT2(WriteHandler) |
| 317 | async_write_some( |
| 318 | ConstBufferSequence const& buffers, |
| 319 | WriteHandler&& handler = |
| 320 | net::default_completion_token_t<executor_type>{}); |
| 321 | }; |
| 322 | |
| 323 | } // http |
| 324 | } // beast |
| 325 | } // boost |
| 326 | |
| 327 | #include <boost/beast/_experimental/http/impl/icy_stream.hpp> |
| 328 | |
| 329 | #endif |
| 330 | |