Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-05 08:27:59

0001 //
0002 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 //
0007 // Official repository: https://github.com/boostorg/beast
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 } // detail
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;    // cached file size
0073         std::uint64_t first_;       // starting offset of the range
0074         std::uint64_t last_;        // ending offset of the range
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_;                       // The body we are reading from
0130         std::uint64_t pos_;                      // The current position in the file
0131         char buf_[BOOST_BEAST_FILE_BUFFER_SIZE]; // Small buffer for reading
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},          // buffer to return.
0175                 pos_ < body_.last_}};   // `true` if there are more buffers.
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             // VFALCO We could reserve space in the file
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 // https://github.com/boostorg/beast/issues/1815
0362 // developer commentary:
0363 // This function mimics the behaviour of ASIO.
0364 // Perhaps the correct fix is to insist on the use
0365 // of an appropriate error_condition to detect
0366 // connection_reset and connection_refused?
0367 inline
0368 error_code
0369 make_win32_error(
0370     boost::winapi::DWORD_ dwError) noexcept
0371 {
0372     // from
0373     // https://github.com/boostorg/asio/blob/6534af41b471288091ae39f9ab801594189b6fc9/include/boost/asio/detail/impl/socket_ops.ipp#L842
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         // Note that we have moved *this, so we cannot access
0461         // the handler since it is now moved-from. We can still
0462         // access simple things like references and built-in types.
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             // VFALCO This needs review, is 0 the right number?
0479             // completed immediately (with error?)
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         // If you get an error on the following line it means
0533         // that your handler does not meet the documented type
0534         // requirements for the handler.
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 } // detail
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 } // http
0646 } // beast
0647 } // boost
0648 
0649 #endif
0650 
0651 #endif