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