File indexing completed on 2025-07-05 08:27:59
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #ifndef BOOST_BEAST_HTTP_IMPL_FILE_BODY_WIN32_HPP
0011 #define BOOST_BEAST_HTTP_IMPL_FILE_BODY_WIN32_HPP
0012
0013 #if BOOST_BEAST_USE_WIN32_FILE
0014
0015 #include <boost/beast/core/async_base.hpp>
0016 #include <boost/beast/core/buffers_range.hpp>
0017 #include <boost/beast/core/detail/clamp.hpp>
0018 #include <boost/beast/core/detail/is_invocable.hpp>
0019 #include <boost/beast/http/error.hpp>
0020 #include <boost/beast/http/write.hpp>
0021 #include <boost/beast/http/serializer.hpp>
0022 #include <boost/asio/async_result.hpp>
0023 #include <boost/asio/basic_stream_socket.hpp>
0024 #include <boost/asio/windows/overlapped_ptr.hpp>
0025 #include <boost/make_unique.hpp>
0026 #include <boost/smart_ptr/make_shared_array.hpp>
0027 #include <boost/winapi/basic_types.hpp>
0028 #include <boost/winapi/error_codes.hpp>
0029 #include <boost/winapi/get_last_error.hpp>
0030 #include <algorithm>
0031 #include <cstring>
0032
0033 namespace boost {
0034 namespace beast {
0035 namespace http {
0036
0037 namespace detail {
0038 template<class, class, bool, class, class>
0039 class write_some_win32_op;
0040 }
0041
0042 template<>
0043 struct basic_file_body<file_win32>
0044 {
0045 using file_type = file_win32;
0046
0047 class writer;
0048 class reader;
0049
0050
0051
0052 class value_type
0053 {
0054 friend class writer;
0055 friend class reader;
0056 friend struct basic_file_body<file_win32>;
0057
0058 template<class, class, bool, class, class>
0059 friend class detail::write_some_win32_op;
0060 template<
0061 class Protocol, class Executor,
0062 bool isRequest, class Fields>
0063 friend
0064 std::size_t
0065 write_some(
0066 net::basic_stream_socket<Protocol, Executor>& sock,
0067 serializer<isRequest,
0068 basic_file_body<file_win32>, Fields>& sr,
0069 error_code& ec);
0070
0071 file_win32 file_;
0072 std::uint64_t size_ = 0;
0073 std::uint64_t first_;
0074 std::uint64_t last_;
0075
0076 public:
0077 ~value_type() = default;
0078 value_type() = default;
0079 value_type(value_type&& other) = default;
0080 value_type& operator=(value_type&& other) = default;
0081
0082 file_win32& file()
0083 {
0084 return file_;
0085 }
0086
0087 bool
0088 is_open() const
0089 {
0090 return file_.is_open();
0091 }
0092
0093 std::uint64_t
0094 size() const
0095 {
0096 return last_ - first_;
0097 }
0098
0099 void
0100 close();
0101
0102 void
0103 open(char const* path, file_mode mode, error_code& ec);
0104
0105 void
0106 reset(file_win32&& file, error_code& ec);
0107
0108 void
0109 seek(std::uint64_t offset, error_code& ec);
0110 };
0111
0112
0113
0114 class writer
0115 {
0116 template<class, class, bool, class, class>
0117 friend class detail::write_some_win32_op;
0118 template<
0119 class Protocol, class Executor,
0120 bool isRequest, class Fields>
0121 friend
0122 std::size_t
0123 write_some(
0124 net::basic_stream_socket<Protocol, Executor>& sock,
0125 serializer<isRequest,
0126 basic_file_body<file_win32>, Fields>& sr,
0127 error_code& ec);
0128
0129 value_type& body_;
0130 std::uint64_t pos_;
0131 char buf_[BOOST_BEAST_FILE_BUFFER_SIZE];
0132
0133 public:
0134 using const_buffers_type =
0135 net::const_buffer;
0136
0137 template<bool isRequest, class Fields>
0138 writer(header<isRequest, Fields>&, value_type& b)
0139 : body_(b)
0140 , pos_(body_.first_)
0141 {
0142 BOOST_ASSERT(body_.file_.is_open());
0143 }
0144
0145 void
0146 init(error_code& ec)
0147 {
0148 BOOST_ASSERT(body_.file_.is_open());
0149 ec.clear();
0150 }
0151
0152 boost::optional<std::pair<const_buffers_type, bool>>
0153 get(error_code& ec)
0154 {
0155 std::size_t const n = (std::min)(sizeof(buf_),
0156 beast::detail::clamp(body_.last_ - pos_));
0157 if(n == 0)
0158 {
0159 ec = {};
0160 return boost::none;
0161 }
0162 auto const nread = body_.file_.read(buf_, n, ec);
0163 if(ec)
0164 return boost::none;
0165 if (nread == 0)
0166 {
0167 BOOST_BEAST_ASSIGN_EC(ec, error::short_read);
0168 return boost::none;
0169 }
0170 BOOST_ASSERT(nread != 0);
0171 pos_ += nread;
0172 ec = {};
0173 return {{
0174 {buf_, nread},
0175 pos_ < body_.last_}};
0176 }
0177 };
0178
0179
0180
0181 class reader
0182 {
0183 value_type& body_;
0184
0185 public:
0186 template<bool isRequest, class Fields>
0187 explicit
0188 reader(header<isRequest, Fields>&, value_type& b)
0189 : body_(b)
0190 {
0191 }
0192
0193 void
0194 init(boost::optional<
0195 std::uint64_t> const& content_length,
0196 error_code& ec)
0197 {
0198
0199 boost::ignore_unused(content_length);
0200 BOOST_ASSERT(body_.file_.is_open());
0201 ec = {};
0202 }
0203
0204 template<class ConstBufferSequence>
0205 std::size_t
0206 put(ConstBufferSequence const& buffers,
0207 error_code& ec)
0208 {
0209 std::size_t nwritten = 0;
0210 for(auto buffer : beast::buffers_range_ref(buffers))
0211 {
0212 nwritten += body_.file_.write(
0213 buffer.data(), buffer.size(), ec);
0214 if(ec)
0215 return nwritten;
0216 }
0217 ec = {};
0218 return nwritten;
0219 }
0220
0221 void
0222 finish(error_code& ec)
0223 {
0224 ec = {};
0225 }
0226 };
0227
0228
0229
0230 static
0231 std::uint64_t
0232 size(value_type const& body)
0233 {
0234 return body.size();
0235 }
0236 };
0237
0238
0239
0240 inline
0241 void
0242 basic_file_body<file_win32>::
0243 value_type::
0244 close()
0245 {
0246 error_code ignored;
0247 file_.close(ignored);
0248 }
0249
0250 inline
0251 void
0252 basic_file_body<file_win32>::
0253 value_type::
0254 open(char const* path, file_mode mode, error_code& ec)
0255 {
0256 file_.open(path, mode, ec);
0257 if(ec)
0258 return;
0259 size_ = file_.size(ec);
0260 if(ec)
0261 {
0262 close();
0263 return;
0264 }
0265 first_ = 0;
0266 last_ = size_;
0267 }
0268
0269 inline
0270 void
0271 basic_file_body<file_win32>::
0272 value_type::
0273 reset(file_win32&& file, error_code& ec)
0274 {
0275 if(file_.is_open())
0276 {
0277 error_code ignored;
0278 file_.close(ignored);
0279 }
0280 file_ = std::move(file);
0281 if(file_.is_open())
0282 {
0283 size_ = file_.size(ec);
0284 if(ec)
0285 {
0286 close();
0287 return;
0288 }
0289
0290 first_ = file_.pos(ec);
0291 if(ec)
0292 {
0293 close();
0294 return;
0295 }
0296
0297 last_ = size_;
0298 }
0299 }
0300
0301
0302 inline
0303 void
0304 basic_file_body<file_win32>::
0305 value_type::
0306 seek(std::uint64_t offset, error_code& ec)
0307 {
0308 first_ = offset;
0309 file_.seek(offset, ec);
0310 }
0311
0312
0313
0314 namespace detail {
0315
0316 template<class Unsigned>
0317 boost::winapi::DWORD_
0318 lowPart(Unsigned n)
0319 {
0320 return static_cast<
0321 boost::winapi::DWORD_>(
0322 n & 0xffffffff);
0323 }
0324
0325 template<class Unsigned>
0326 boost::winapi::DWORD_
0327 highPart(Unsigned n, std::true_type)
0328 {
0329 return static_cast<
0330 boost::winapi::DWORD_>(
0331 (n>>32)&0xffffffff);
0332 }
0333
0334 template<class Unsigned>
0335 boost::winapi::DWORD_
0336 highPart(Unsigned, std::false_type)
0337 {
0338 return 0;
0339 }
0340
0341 template<class Unsigned>
0342 boost::winapi::DWORD_
0343 highPart(Unsigned n)
0344 {
0345 return highPart(n, std::integral_constant<
0346 bool, (sizeof(Unsigned)>4)>{});
0347 }
0348
0349 class null_lambda
0350 {
0351 public:
0352 template<class ConstBufferSequence>
0353 void
0354 operator()(error_code&,
0355 ConstBufferSequence const&) const
0356 {
0357 BOOST_ASSERT(false);
0358 }
0359 };
0360
0361
0362
0363
0364
0365
0366
0367 inline
0368 error_code
0369 make_win32_error(
0370 boost::winapi::DWORD_ dwError) noexcept
0371 {
0372
0373
0374 switch(dwError)
0375 {
0376 case boost::winapi::ERROR_NETNAME_DELETED_:
0377 return net::error::connection_reset;
0378 case boost::winapi::ERROR_PORT_UNREACHABLE_:
0379 return net::error::connection_refused;
0380 case boost::winapi::WSAEMSGSIZE_:
0381 case boost::winapi::ERROR_MORE_DATA_:
0382 return {};
0383 }
0384 return error_code(
0385 static_cast<int>(dwError),
0386 system_category());
0387 }
0388
0389 inline
0390 error_code
0391 make_win32_error(
0392 error_code ec) noexcept
0393 {
0394 if(ec.category() !=
0395 system_category())
0396 return ec;
0397 return make_win32_error(
0398 static_cast<boost::winapi::DWORD_>(
0399 ec.value()));
0400 }
0401
0402
0403
0404 #if BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR
0405
0406 template<
0407 class Protocol, class Executor,
0408 bool isRequest, class Fields,
0409 class Handler>
0410 class write_some_win32_op
0411 : public beast::async_base<Handler, Executor>
0412 {
0413 net::basic_stream_socket<
0414 Protocol, Executor>& sock_;
0415 serializer<isRequest,
0416 basic_file_body<file_win32>, Fields>& sr_;
0417 bool header_ = false;
0418
0419 public:
0420 template<class Handler_>
0421 write_some_win32_op(
0422 Handler_&& h,
0423 net::basic_stream_socket<
0424 Protocol, Executor>& s,
0425 serializer<isRequest,
0426 basic_file_body<file_win32>,Fields>& sr)
0427 : async_base<
0428 Handler, Executor>(
0429 std::forward<Handler_>(h),
0430 s.get_executor())
0431 , sock_(s)
0432 , sr_(sr)
0433 {
0434 (*this)();
0435 }
0436
0437 void
0438 operator()()
0439 {
0440 if(! sr_.is_header_done())
0441 {
0442 header_ = true;
0443 sr_.split(true);
0444 return detail::async_write_some_impl(
0445 sock_, sr_, std::move(*this));
0446 }
0447 if(sr_.get().chunked())
0448 {
0449 return detail::async_write_some_impl(
0450 sock_, sr_, std::move(*this));
0451 }
0452 auto& w = sr_.writer_impl();
0453 boost::winapi::DWORD_ const nNumberOfBytesToWrite =
0454 static_cast<boost::winapi::DWORD_>(
0455 (std::min<std::uint64_t>)(
0456 (std::min<std::uint64_t>)(w.body_.last_ - w.pos_, sr_.limit()),
0457 (std::numeric_limits<boost::winapi::INT_>::max)() - 1));
0458 net::windows::overlapped_ptr overlapped{
0459 sock_.get_executor(), std::move(*this)};
0460
0461
0462
0463 auto& ov = *overlapped.get();
0464 ov.Offset = lowPart(w.pos_);
0465 ov.OffsetHigh = highPart(w.pos_);
0466 auto const bSuccess = ::TransmitFile(
0467 sock_.native_handle(),
0468 sr_.get().body().file_.native_handle(),
0469 nNumberOfBytesToWrite,
0470 0,
0471 overlapped.get(),
0472 nullptr,
0473 0);
0474 auto const dwError = boost::winapi::GetLastError();
0475 if(! bSuccess && dwError !=
0476 boost::winapi::ERROR_IO_PENDING_)
0477 {
0478
0479
0480 overlapped.complete(
0481 make_win32_error(dwError), 0);
0482 return;
0483 }
0484 overlapped.release();
0485 }
0486
0487 void
0488 operator()(
0489 error_code ec,
0490 std::size_t bytes_transferred = 0)
0491 {
0492 if(ec)
0493 {
0494 BOOST_BEAST_ASSIGN_EC(ec, make_win32_error(ec));
0495 }
0496 else if(! ec && ! header_)
0497 {
0498 auto& w = sr_.writer_impl();
0499 w.pos_ += bytes_transferred;
0500 BOOST_ASSERT(w.pos_ <= w.body_.last_);
0501 if(w.pos_ >= w.body_.last_)
0502 {
0503 sr_.next(ec, null_lambda{});
0504 BOOST_ASSERT(! ec);
0505 BOOST_ASSERT(sr_.is_done());
0506 }
0507 }
0508 this->complete_now(ec, bytes_transferred);
0509 }
0510 };
0511
0512 template<class Protocol, class Executor>
0513 struct run_write_some_win32_op
0514 {
0515 net::basic_stream_socket<Protocol, Executor>* stream;
0516
0517 using executor_type = typename net::basic_stream_socket<Protocol, Executor>::executor_type;
0518
0519 executor_type
0520 get_executor() const noexcept
0521 {
0522 return stream->get_executor();
0523 }
0524
0525 template<bool isRequest, class Fields, class WriteHandler>
0526 void
0527 operator()(
0528 WriteHandler&& h,
0529 serializer<isRequest,
0530 basic_file_body<file_win32>, Fields>* sr)
0531 {
0532
0533
0534
0535
0536 static_assert(
0537 beast::detail::is_invocable<WriteHandler,
0538 void(error_code, std::size_t)>::value,
0539 "WriteHandler type requirements not met");
0540
0541 write_some_win32_op<
0542 Protocol, Executor,
0543 isRequest, Fields,
0544 typename std::decay<WriteHandler>::type>(
0545 std::forward<WriteHandler>(h), *stream, *sr);
0546 }
0547 };
0548
0549 #endif
0550
0551 }
0552
0553
0554
0555 template<
0556 class Protocol, class Executor,
0557 bool isRequest, class Fields>
0558 std::size_t
0559 write_some(
0560 net::basic_stream_socket<
0561 Protocol, Executor>& sock,
0562 serializer<isRequest,
0563 basic_file_body<file_win32>, Fields>& sr,
0564 error_code& ec)
0565 {
0566 if(! sr.is_header_done())
0567 {
0568 sr.split(true);
0569 auto const bytes_transferred =
0570 detail::write_some_impl(sock, sr, ec);
0571 if(ec)
0572 return bytes_transferred;
0573 return bytes_transferred;
0574 }
0575 if(sr.get().chunked())
0576 {
0577 auto const bytes_transferred =
0578 detail::write_some_impl(sock, sr, ec);
0579 if(ec)
0580 return bytes_transferred;
0581 return bytes_transferred;
0582 }
0583 auto& w = sr.writer_impl();
0584 w.body_.file_.seek(w.pos_, ec);
0585 if(ec)
0586 return 0;
0587 boost::winapi::DWORD_ const nNumberOfBytesToWrite =
0588 static_cast<boost::winapi::DWORD_>(
0589 (std::min<std::uint64_t>)(
0590 (std::min<std::uint64_t>)(w.body_.last_ - w.pos_, sr.limit()),
0591 (std::numeric_limits<boost::winapi::INT_>::max)() - 1));
0592 auto const bSuccess = ::TransmitFile(
0593 sock.native_handle(),
0594 w.body_.file_.native_handle(),
0595 nNumberOfBytesToWrite,
0596 0,
0597 nullptr,
0598 nullptr,
0599 0);
0600 if(! bSuccess)
0601 {
0602 BOOST_BEAST_ASSIGN_EC(ec, detail::make_win32_error(
0603 boost::winapi::GetLastError()));
0604 return 0;
0605 }
0606 w.pos_ += nNumberOfBytesToWrite;
0607 BOOST_ASSERT(w.pos_ <= w.body_.last_);
0608 if(w.pos_ < w.body_.last_)
0609 {
0610 ec = {};
0611 }
0612 else
0613 {
0614 sr.next(ec, detail::null_lambda{});
0615 BOOST_ASSERT(! ec);
0616 BOOST_ASSERT(sr.is_done());
0617 }
0618 return nNumberOfBytesToWrite;
0619 }
0620
0621 #if BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR
0622
0623 template<
0624 class Protocol, class Executor,
0625 bool isRequest, class Fields,
0626 BOOST_BEAST_ASYNC_TPARAM2 WriteHandler>
0627 BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
0628 async_write_some(
0629 net::basic_stream_socket<
0630 Protocol, Executor>& sock,
0631 serializer<isRequest,
0632 basic_file_body<file_win32>, Fields>& sr,
0633 WriteHandler&& handler)
0634 {
0635 return net::async_initiate<
0636 WriteHandler,
0637 void(error_code, std::size_t)>(
0638 detail::run_write_some_win32_op<Protocol, Executor>{&sock},
0639 handler,
0640 &sr);
0641 }
0642
0643 #endif
0644
0645 }
0646 }
0647 }
0648
0649 #endif
0650
0651 #endif