File indexing completed on 2025-07-05 08:27:52
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 icy_stream* self;
0171
0172 using executor_type = typename icy_stream::executor_type;
0173
0174 executor_type
0175 get_executor() const noexcept
0176 {
0177 return self->get_executor();
0178 }
0179
0180 template<class ReadHandler, class Buffers>
0181 void
0182 operator()(
0183 ReadHandler&& h,
0184 Buffers const& b)
0185 {
0186
0187
0188
0189
0190 static_assert(
0191 beast::detail::is_invocable<ReadHandler,
0192 void(error_code, std::size_t)>::value,
0193 "ReadHandler type requirements not met");
0194
0195 read_op<
0196 Buffers,
0197 typename std::decay<ReadHandler>::type>(
0198 std::forward<ReadHandler>(h), *self, b);
0199 }
0200 };
0201
0202 };
0203
0204
0205
0206 template<class NextLayer>
0207 template<class... Args>
0208 icy_stream<NextLayer>::
0209 icy_stream(Args&&... args)
0210 : stream_(std::forward<Args>(args)...)
0211 {
0212 std::memset(buf_, 0, sizeof(buf_));
0213 }
0214
0215 template<class NextLayer>
0216 template<class MutableBufferSequence>
0217 std::size_t
0218 icy_stream<NextLayer>::
0219 read_some(MutableBufferSequence const& buffers)
0220 {
0221 static_assert(is_sync_read_stream<next_layer_type>::value,
0222 "SyncReadStream type requirements not met");
0223 static_assert(net::is_mutable_buffer_sequence<
0224 MutableBufferSequence>::value,
0225 "MutableBufferSequence type requirements not met");
0226 error_code ec;
0227 auto n = read_some(buffers, ec);
0228 if(ec)
0229 BOOST_THROW_EXCEPTION(system_error{ec});
0230 return n;
0231 }
0232
0233 template<class NextLayer>
0234 template<class MutableBufferSequence>
0235 std::size_t
0236 icy_stream<NextLayer>::
0237 read_some(MutableBufferSequence const& buffers, error_code& ec)
0238 {
0239 static_assert(is_sync_read_stream<next_layer_type>::value,
0240 "SyncReadStream type requirements not met");
0241 static_assert(net::is_mutable_buffer_sequence<
0242 MutableBufferSequence>::value,
0243 "MutableBufferSequence type requirements not met");
0244 std::size_t bytes_transferred;
0245 if(detect_)
0246 {
0247 BOOST_ASSERT(n_ == 0);
0248 for(;;)
0249 {
0250
0251 bytes_transferred = next_layer().read_some(
0252 net::mutable_buffer(buf_ + n_, 3 - n_), ec);
0253 n_ += static_cast<char>(bytes_transferred);
0254 if(ec)
0255 return 0;
0256 auto result = detail::is_icy(
0257 net::const_buffer(buf_, n_));
0258 if(boost::indeterminate(result))
0259 continue;
0260 if(result)
0261 n_ = static_cast<char>(net::buffer_copy(
0262 net::buffer(buf_, sizeof(buf_)),
0263 icy_stream::version()));
0264 break;
0265 }
0266 detect_ = false;
0267 }
0268 if(n_ > 0)
0269 {
0270 bytes_transferred = net::buffer_copy(
0271 buffers, net::const_buffer(buf_, n_));
0272 n_ -= static_cast<char>(bytes_transferred);
0273 std::memmove(
0274 buf_,
0275 buf_ + bytes_transferred,
0276 sizeof(buf_) - bytes_transferred);
0277 }
0278 else
0279 {
0280 bytes_transferred =
0281 next_layer().read_some(buffers, ec);
0282 }
0283 return bytes_transferred;
0284 }
0285
0286 template<class NextLayer>
0287 template<
0288 class MutableBufferSequence,
0289 BOOST_BEAST_ASYNC_TPARAM2 ReadHandler>
0290 BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
0291 icy_stream<NextLayer>::
0292 async_read_some(
0293 MutableBufferSequence const& buffers,
0294 ReadHandler&& handler)
0295 {
0296 static_assert(is_async_read_stream<next_layer_type>::value,
0297 "AsyncReadStream type requirements not met");
0298 static_assert(net::is_mutable_buffer_sequence<
0299 MutableBufferSequence >::value,
0300 "MutableBufferSequence type requirements not met");
0301 return net::async_initiate<
0302 ReadHandler,
0303 void(error_code, std::size_t)>(
0304 typename ops::run_read_op{this},
0305 handler,
0306 buffers);
0307 }
0308
0309 template<class NextLayer>
0310 template<class MutableBufferSequence>
0311 std::size_t
0312 icy_stream<NextLayer>::
0313 write_some(MutableBufferSequence const& buffers)
0314 {
0315 static_assert(is_sync_write_stream<next_layer_type>::value,
0316 "SyncWriteStream type requirements not met");
0317 static_assert(net::is_const_buffer_sequence<
0318 MutableBufferSequence>::value,
0319 "MutableBufferSequence type requirements not met");
0320 return stream_.write_some(buffers);
0321 }
0322
0323 template<class NextLayer>
0324 template<class MutableBufferSequence>
0325 std::size_t
0326 icy_stream<NextLayer>::
0327 write_some(MutableBufferSequence const& buffers, error_code& ec)
0328 {
0329 static_assert(is_sync_write_stream<next_layer_type>::value,
0330 "SyncWriteStream type requirements not met");
0331 static_assert(net::is_const_buffer_sequence<
0332 MutableBufferSequence>::value,
0333 "MutableBufferSequence type requirements not met");
0334 return stream_.write_some(buffers, ec);
0335 }
0336
0337 template<class NextLayer>
0338 template<
0339 class MutableBufferSequence,
0340 BOOST_BEAST_ASYNC_TPARAM2 WriteHandler>
0341 BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
0342 icy_stream<NextLayer>::
0343 async_write_some(
0344 MutableBufferSequence const& buffers,
0345 WriteHandler&& handler)
0346 {
0347 static_assert(is_async_write_stream<next_layer_type>::value,
0348 "AsyncWriteStream type requirements not met");
0349 static_assert(net::is_const_buffer_sequence<
0350 MutableBufferSequence>::value,
0351 "MutableBufferSequence type requirements not met");
0352 return stream_.async_write_some(
0353 buffers, std::forward<WriteHandler>(handler));
0354 }
0355
0356 }
0357 }
0358 }
0359
0360 #endif