File indexing completed on 2025-01-31 09:35:48
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #ifndef BOOST_BEAST_CORE_IMPL_ICY_STREAM_HPP
0011 #define BOOST_BEAST_CORE_IMPL_ICY_STREAM_HPP
0012
0013 #include <boost/beast/core/async_base.hpp>
0014 #include <boost/beast/core/buffer_traits.hpp>
0015 #include <boost/beast/core/error.hpp>
0016 #include <boost/beast/core/stream_traits.hpp>
0017 #include <boost/beast/core/detail/is_invocable.hpp>
0018 #include <boost/asio/coroutine.hpp>
0019 #include <boost/assert.hpp>
0020 #include <boost/throw_exception.hpp>
0021 #include <cstring>
0022 #include <memory>
0023 #include <utility>
0024
0025 namespace boost {
0026 namespace beast {
0027 namespace http {
0028
0029 namespace detail {
0030
0031 template<class ConstBufferSequence>
0032 boost::tribool
0033 is_icy(ConstBufferSequence const& buffers)
0034 {
0035 char buf[3];
0036 auto const n = net::buffer_copy(
0037 net::mutable_buffer(buf, 3),
0038 buffers);
0039 if(n >= 1 && buf[0] != 'I')
0040 return false;
0041 if(n >= 2 && buf[1] != 'C')
0042 return false;
0043 if(n >= 3 && buf[2] != 'Y')
0044 return false;
0045 if(n < 3)
0046 return boost::indeterminate;
0047 return true;
0048 }
0049
0050 }
0051
0052 template<class NextLayer>
0053 struct icy_stream<NextLayer>::ops
0054 {
0055
0056 template<class Buffers, class Handler>
0057 class read_op
0058 : public beast::async_base<Handler,
0059 beast::executor_type<icy_stream>>
0060 , public asio::coroutine
0061 {
0062 icy_stream& s_;
0063 Buffers b_;
0064 std::size_t n_ = 0;
0065 error_code ec_;
0066 bool match_ = false;
0067
0068 public:
0069 template<class Handler_>
0070 read_op(
0071 Handler_&& h,
0072 icy_stream& s,
0073 Buffers const& b)
0074 : async_base<Handler,
0075 beast::executor_type<icy_stream>>(
0076 std::forward<Handler_>(h), s.get_executor())
0077 , s_(s)
0078 , b_(b)
0079 {
0080 (*this)({}, 0, false);
0081 }
0082
0083 void
0084 operator()(
0085 error_code ec,
0086 std::size_t bytes_transferred,
0087 bool cont = true)
0088 {
0089 BOOST_ASIO_CORO_REENTER(*this)
0090 {
0091 if(s_.detect_)
0092 {
0093 BOOST_ASSERT(s_.n_ == 0);
0094 for(;;)
0095 {
0096
0097 BOOST_ASIO_CORO_YIELD
0098 {
0099 BOOST_ASIO_HANDLER_LOCATION((
0100 __FILE__, __LINE__,
0101 "http::icy_stream::async_read_some"));
0102
0103 s_.next_layer().async_read_some(
0104 net::mutable_buffer(
0105 s_.buf_ + s_.n_, 3 - s_.n_),
0106 std::move(*this));
0107 }
0108 s_.n_ += static_cast<char>(bytes_transferred);
0109 if(ec)
0110 goto upcall;
0111 auto result = detail::is_icy(
0112 net::const_buffer(s_.buf_, s_.n_));
0113 if(boost::indeterminate(result))
0114 continue;
0115 if(result)
0116 s_.n_ = static_cast<char>(net::buffer_copy(
0117 net::buffer(s_.buf_, sizeof(s_.buf_)),
0118 icy_stream::version()));
0119 break;
0120 }
0121 s_.detect_ = false;
0122 }
0123 if(s_.n_ > 0)
0124 {
0125 bytes_transferred = net::buffer_copy(
0126 b_, net::const_buffer(s_.buf_, s_.n_));
0127 s_.n_ -= static_cast<char>(bytes_transferred);
0128 std::memmove(
0129 s_.buf_,
0130 s_.buf_ + bytes_transferred,
0131 sizeof(s_.buf_) - bytes_transferred);
0132 }
0133 else
0134 {
0135 BOOST_ASIO_CORO_YIELD
0136 {
0137 BOOST_ASIO_HANDLER_LOCATION((
0138 __FILE__, __LINE__,
0139 "http::icy_stream::async_read_some"));
0140
0141 s_.next_layer().async_read_some(
0142 b_, std::move(*this));
0143 }
0144 }
0145 upcall:
0146 if(! cont)
0147 {
0148 ec_ = ec;
0149 n_ = bytes_transferred;
0150 BOOST_ASIO_CORO_YIELD
0151 {
0152 BOOST_ASIO_HANDLER_LOCATION((
0153 __FILE__, __LINE__,
0154 "http::icy_stream::async_read_some"));
0155
0156 s_.next_layer().async_read_some(
0157 net::mutable_buffer{},
0158 std::move(*this));
0159 }
0160 BOOST_BEAST_ASSIGN_EC(ec, ec_);
0161 bytes_transferred = n_;
0162 }
0163 this->complete_now(ec, bytes_transferred);
0164 }
0165 }
0166 };
0167
0168 struct run_read_op
0169 {
0170 template<class ReadHandler, class Buffers>
0171 void
0172 operator()(
0173 ReadHandler&& h,
0174 icy_stream* s,
0175 Buffers const& b)
0176 {
0177
0178
0179
0180
0181 static_assert(
0182 beast::detail::is_invocable<ReadHandler,
0183 void(error_code, std::size_t)>::value,
0184 "ReadHandler type requirements not met");
0185
0186 read_op<
0187 Buffers,
0188 typename std::decay<ReadHandler>::type>(
0189 std::forward<ReadHandler>(h), *s, b);
0190 }
0191 };
0192
0193 };
0194
0195
0196
0197 template<class NextLayer>
0198 template<class... Args>
0199 icy_stream<NextLayer>::
0200 icy_stream(Args&&... args)
0201 : stream_(std::forward<Args>(args)...)
0202 {
0203 std::memset(buf_, 0, sizeof(buf_));
0204 }
0205
0206 template<class NextLayer>
0207 template<class MutableBufferSequence>
0208 std::size_t
0209 icy_stream<NextLayer>::
0210 read_some(MutableBufferSequence const& buffers)
0211 {
0212 static_assert(is_sync_read_stream<next_layer_type>::value,
0213 "SyncReadStream type requirements not met");
0214 static_assert(net::is_mutable_buffer_sequence<
0215 MutableBufferSequence>::value,
0216 "MutableBufferSequence type requirements not met");
0217 error_code ec;
0218 auto n = read_some(buffers, ec);
0219 if(ec)
0220 BOOST_THROW_EXCEPTION(system_error{ec});
0221 return n;
0222 }
0223
0224 template<class NextLayer>
0225 template<class MutableBufferSequence>
0226 std::size_t
0227 icy_stream<NextLayer>::
0228 read_some(MutableBufferSequence const& buffers, error_code& ec)
0229 {
0230 static_assert(is_sync_read_stream<next_layer_type>::value,
0231 "SyncReadStream type requirements not met");
0232 static_assert(net::is_mutable_buffer_sequence<
0233 MutableBufferSequence>::value,
0234 "MutableBufferSequence type requirements not met");
0235 std::size_t bytes_transferred;
0236 if(detect_)
0237 {
0238 BOOST_ASSERT(n_ == 0);
0239 for(;;)
0240 {
0241
0242 bytes_transferred = next_layer().read_some(
0243 net::mutable_buffer(buf_ + n_, 3 - n_), ec);
0244 n_ += static_cast<char>(bytes_transferred);
0245 if(ec)
0246 return 0;
0247 auto result = detail::is_icy(
0248 net::const_buffer(buf_, n_));
0249 if(boost::indeterminate(result))
0250 continue;
0251 if(result)
0252 n_ = static_cast<char>(net::buffer_copy(
0253 net::buffer(buf_, sizeof(buf_)),
0254 icy_stream::version()));
0255 break;
0256 }
0257 detect_ = false;
0258 }
0259 if(n_ > 0)
0260 {
0261 bytes_transferred = net::buffer_copy(
0262 buffers, net::const_buffer(buf_, n_));
0263 n_ -= static_cast<char>(bytes_transferred);
0264 std::memmove(
0265 buf_,
0266 buf_ + bytes_transferred,
0267 sizeof(buf_) - bytes_transferred);
0268 }
0269 else
0270 {
0271 bytes_transferred =
0272 next_layer().read_some(buffers, ec);
0273 }
0274 return bytes_transferred;
0275 }
0276
0277 template<class NextLayer>
0278 template<
0279 class MutableBufferSequence,
0280 BOOST_BEAST_ASYNC_TPARAM2 ReadHandler>
0281 BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
0282 icy_stream<NextLayer>::
0283 async_read_some(
0284 MutableBufferSequence const& buffers,
0285 ReadHandler&& handler)
0286 {
0287 static_assert(is_async_read_stream<next_layer_type>::value,
0288 "AsyncReadStream type requirements not met");
0289 static_assert(net::is_mutable_buffer_sequence<
0290 MutableBufferSequence >::value,
0291 "MutableBufferSequence type requirements not met");
0292 return net::async_initiate<
0293 ReadHandler,
0294 void(error_code, std::size_t)>(
0295 typename ops::run_read_op{},
0296 handler,
0297 this,
0298 buffers);
0299 }
0300
0301 template<class NextLayer>
0302 template<class MutableBufferSequence>
0303 std::size_t
0304 icy_stream<NextLayer>::
0305 write_some(MutableBufferSequence const& buffers)
0306 {
0307 static_assert(is_sync_write_stream<next_layer_type>::value,
0308 "SyncWriteStream type requirements not met");
0309 static_assert(net::is_const_buffer_sequence<
0310 MutableBufferSequence>::value,
0311 "MutableBufferSequence type requirements not met");
0312 return stream_.write_some(buffers);
0313 }
0314
0315 template<class NextLayer>
0316 template<class MutableBufferSequence>
0317 std::size_t
0318 icy_stream<NextLayer>::
0319 write_some(MutableBufferSequence const& buffers, error_code& ec)
0320 {
0321 static_assert(is_sync_write_stream<next_layer_type>::value,
0322 "SyncWriteStream type requirements not met");
0323 static_assert(net::is_const_buffer_sequence<
0324 MutableBufferSequence>::value,
0325 "MutableBufferSequence type requirements not met");
0326 return stream_.write_some(buffers, ec);
0327 }
0328
0329 template<class NextLayer>
0330 template<
0331 class MutableBufferSequence,
0332 BOOST_BEAST_ASYNC_TPARAM2 WriteHandler>
0333 BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
0334 icy_stream<NextLayer>::
0335 async_write_some(
0336 MutableBufferSequence const& buffers,
0337 WriteHandler&& handler)
0338 {
0339 static_assert(is_async_write_stream<next_layer_type>::value,
0340 "AsyncWriteStream type requirements not met");
0341 static_assert(net::is_const_buffer_sequence<
0342 MutableBufferSequence>::value,
0343 "MutableBufferSequence type requirements not met");
0344 return stream_.async_write_some(
0345 buffers, std::forward<WriteHandler>(handler));
0346 }
0347
0348 }
0349 }
0350 }
0351
0352 #endif