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