Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:29:30

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/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 } // detail
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;    // cached file size
0074         std::uint64_t first_;       // starting offset of the range
0075         std::uint64_t last_;        // ending offset of the range
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_;                       // The body we are reading from
0131         std::uint64_t pos_;                      // The current position in the file
0132         char buf_[BOOST_BEAST_FILE_BUFFER_SIZE]; // Small buffer for reading
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},          // buffer to return.
0176                 pos_ < body_.last_}};   // `true` if there are more buffers.
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             // VFALCO We could reserve space in the file
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 // https://github.com/boostorg/beast/issues/1815
0363 // developer commentary:
0364 // This function mimics the behaviour of ASIO.
0365 // Perhaps the correct fix is to insist on the use
0366 // of an appropriate error_condition to detect
0367 // connection_reset and connection_refused?
0368 inline
0369 error_code
0370 make_win32_error(
0371     boost::winapi::DWORD_ dwError) noexcept
0372 {
0373     // from
0374     // https://github.com/boostorg/asio/blob/6534af41b471288091ae39f9ab801594189b6fc9/include/boost/asio/detail/impl/socket_ops.ipp#L842
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         // Note that we have moved *this, so we cannot access
0462         // the handler since it is now moved-from. We can still
0463         // access simple things like references and built-in types.
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             // VFALCO This needs review, is 0 the right number?
0480             // completed immediately (with error?)
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         // If you get an error on the following line it means
0528         // that your handler does not meet the documented type
0529         // requirements for the handler.
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 } // detail
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 } // http
0642 } // beast
0643 } // boost
0644 
0645 #endif
0646 
0647 #endif