Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-15 08:30:17

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_BASIC_FILE_BODY_HPP
0011 #define BOOST_BEAST_HTTP_BASIC_FILE_BODY_HPP
0012 
0013 #include <boost/beast/http/basic_file_body_fwd.hpp>
0014 
0015 #include <boost/beast/core/detail/config.hpp>
0016 #include <boost/beast/core/error.hpp>
0017 #include <boost/beast/core/file_base.hpp>
0018 #include <boost/beast/http/message.hpp>
0019 #include <boost/assert.hpp>
0020 #include <boost/optional.hpp>
0021 #include <algorithm>
0022 #include <cstdio>
0023 #include <cstdint>
0024 #include <utility>
0025 
0026 namespace boost {
0027 namespace beast {
0028 namespace http {
0029 
0030 //[example_http_file_body_1
0031 
0032 /** A message body represented by a file on the filesystem.
0033 
0034     Messages with this type have bodies represented by a
0035     file on the file system. When parsing a message using
0036     this body type, the data is stored in the file pointed
0037     to by the path, which must be writable. When serializing,
0038     the implementation will read the file and present those
0039     octets as the body content. This may be used to serve
0040     content from a directory as part of a web service.
0041 
0042     @tparam File The implementation to use for accessing files.
0043     This type must meet the requirements of <em>File</em>.
0044 */
0045 template<class File>
0046 struct basic_file_body
0047 {
0048     // Make sure the type meets the requirements
0049     static_assert(is_file<File>::value,
0050         "File type requirements not met");
0051 
0052     /// The type of File this body uses
0053     using file_type = File;
0054 
0055     // Algorithm for storing buffers when parsing.
0056     class reader;
0057 
0058     // Algorithm for retrieving buffers when serializing.
0059     class writer;
0060 
0061     // The type of the @ref message::body member.
0062     class value_type;
0063 
0064     /** Returns the size of the body
0065 
0066         @param body The file body to use
0067     */
0068     static
0069     std::uint64_t
0070     size(value_type const& body);
0071 };
0072 
0073 //]
0074 
0075 //[example_http_file_body_2
0076 
0077 /** The type of the @ref message::body member.
0078 
0079     Messages declared using `basic_file_body` will have this type for
0080     the body member. This rich class interface allow the file to be
0081     opened with the file handle maintained directly in the object,
0082     which is attached to the message.
0083 */
0084 template<class File>
0085 class basic_file_body<File>::value_type
0086 {
0087     // This body container holds a handle to the file
0088     // when it is open, and also caches the size when set.
0089 
0090 #ifndef BOOST_BEAST_DOXYGEN
0091     friend class reader;
0092     friend class writer;
0093     friend struct basic_file_body;
0094 #endif
0095 
0096     // This represents the open file
0097     File file_;
0098 
0099     // The cached file size
0100     std::uint64_t file_size_ = 0;
0101 
0102 public:
0103     /** Destructor.
0104 
0105         If the file is open, it is closed first.
0106     */
0107     ~value_type() = default;
0108 
0109     /// Constructor
0110     value_type() = default;
0111 
0112     /// Constructor
0113     value_type(value_type&& other) = default;
0114 
0115     /// Move assignment
0116     value_type& operator=(value_type&& other) = default;
0117 
0118     /// Return the file
0119     File& file()
0120     {
0121         return file_;
0122     }
0123 
0124     /// Returns `true` if the file is open
0125     bool
0126     is_open() const
0127     {
0128         return file_.is_open();
0129     }
0130 
0131     /// Returns the size of the file if open
0132     std::uint64_t
0133     size() const
0134     {
0135         return file_size_;
0136     }
0137 
0138     /// Close the file if open
0139     void
0140     close();
0141 
0142     /** Open a file at the given path with the specified mode
0143 
0144         @param path The utf-8 encoded path to the file
0145 
0146         @param mode The file mode to use
0147 
0148         @param ec Set to the error, if any occurred
0149     */
0150     void
0151     open(char const* path, file_mode mode, error_code& ec);
0152 
0153     /** Set the open file
0154 
0155         This function is used to set the open file. Any previously
0156         set file will be closed.
0157 
0158         @param file The file to set. The file must be open or else
0159         an error occurs
0160 
0161         @param ec Set to the error, if any occurred
0162     */
0163     void
0164     reset(File&& file, error_code& ec);
0165 
0166     /** Set the cursor position of the file.
0167 
0168         This function can be used to move the cursor of the file ahead
0169         so that only a part gets read. This file will also adjust the
0170         value_type, in case the file is already part of a body.
0171 
0172         @param offset The offset in bytes from the beginning of the file
0173 
0174         @param ec Set to the error, if any occurred
0175     */
0176 
0177     void seek(std::uint64_t offset, error_code& ec);
0178 };
0179 
0180 template<class File>
0181 void
0182 basic_file_body<File>::
0183 value_type::
0184 close()
0185 {
0186     error_code ignored;
0187     file_.close(ignored);
0188 }
0189 
0190 template<class File>
0191 void
0192 basic_file_body<File>::
0193 value_type::
0194 open(char const* path, file_mode mode, error_code& ec)
0195 {
0196     // Open the file
0197     file_.open(path, mode, ec);
0198     if(ec)
0199         return;
0200 
0201     // Cache the size
0202     file_size_ = file_.size(ec);
0203     if(ec)
0204     {
0205         close();
0206         return;
0207     }
0208 }
0209 
0210 template<class File>
0211 void
0212 basic_file_body<File>::
0213 value_type::
0214 reset(File&& file, error_code& ec)
0215 {
0216     // First close the file if open
0217     if(file_.is_open())
0218     {
0219         error_code ignored;
0220         file_.close(ignored);
0221     }
0222 
0223     // Take ownership of the new file
0224     file_ = std::move(file);
0225 
0226     // Cache the size
0227     file_size_ = file_.size(ec);
0228 
0229     // Consider the offset
0230     if (!ec)
0231         file_size_ -= file_.pos(ec);
0232 }
0233 
0234 template<class File>
0235 void
0236 basic_file_body<File>::
0237 value_type::
0238 seek(std::uint64_t offset, error_code& ec)
0239 {
0240     file_.seek(offset, ec);
0241     // Cache the size
0242     if (!ec)
0243         file_size_ = file_.size(ec);
0244 
0245     // Consider the offset
0246     if (!ec)
0247         file_size_ -= file_.pos(ec);
0248 }
0249 
0250 
0251 // This is called from message::payload_size
0252 template<class File>
0253 std::uint64_t
0254 basic_file_body<File>::
0255 size(value_type const& body)
0256 {
0257     // Forward the call to the body
0258     return body.size();
0259 }
0260 
0261 //]
0262 
0263 //[example_http_file_body_3
0264 
0265 /** Algorithm for retrieving buffers when serializing.
0266 
0267     Objects of this type are created during serialization
0268     to extract the buffers representing the body.
0269 */
0270 template<class File>
0271 class basic_file_body<File>::writer
0272 {
0273     value_type& body_;                       // The body we are reading from
0274     std::uint64_t remain_;                   // The number of unread bytes
0275     char buf_[BOOST_BEAST_FILE_BUFFER_SIZE]; // Small buffer for reading
0276 
0277 public:
0278     // The type of buffer sequence returned by `get`.
0279     //
0280     using const_buffers_type =
0281         net::const_buffer;
0282 
0283     // Constructor.
0284     //
0285     // `h` holds the headers of the message we are
0286     // serializing, while `b` holds the body.
0287     //
0288     // Note that the message is passed by non-const reference.
0289     // This is intentional, because reading from the file
0290     // changes its "current position" which counts makes the
0291     // operation logically not-const (although it is bitwise
0292     // const).
0293     //
0294     // The BodyWriter concept allows the writer to choose
0295     // whether to take the message by const reference or
0296     // non-const reference. Depending on the choice, a
0297     // serializer constructed using that body type will
0298     // require the same const or non-const reference to
0299     // construct.
0300     //
0301     // Readers which accept const messages usually allow
0302     // the same body to be serialized by multiple threads
0303     // concurrently, while readers accepting non-const
0304     // messages may only be serialized by one thread at
0305     // a time.
0306     //
0307     template<bool isRequest, class Fields>
0308     writer(header<isRequest, Fields>& h, value_type& b);
0309 
0310     // Initializer
0311     //
0312     // This is called before the body is serialized and
0313     // gives the writer a chance to do something that might
0314     // need to return an error code.
0315     //
0316     void
0317     init(error_code& ec);
0318 
0319     // This function is called zero or more times to
0320     // retrieve buffers. A return value of `boost::none`
0321     // means there are no more buffers. Otherwise,
0322     // the contained pair will have the next buffer
0323     // to serialize, and a `bool` indicating whether
0324     // or not there may be additional buffers.
0325     boost::optional<std::pair<const_buffers_type, bool>>
0326     get(error_code& ec);
0327 };
0328 
0329 //]
0330 
0331 //[example_http_file_body_4
0332 
0333 // Here we just stash a reference to the path for later.
0334 // Rather than dealing with messy constructor exceptions,
0335 // we save the things that might fail for the call to `init`.
0336 //
0337 template<class File>
0338 template<bool isRequest, class Fields>
0339 basic_file_body<File>::
0340 writer::
0341 writer(header<isRequest, Fields>& h, value_type& b)
0342     : body_(b)
0343 {
0344     boost::ignore_unused(h);
0345 
0346     // The file must already be open
0347     BOOST_ASSERT(body_.file_.is_open());
0348 
0349     // Get the size of the file
0350     remain_ = body_.file_size_;
0351 }
0352 
0353 // Initializer
0354 template<class File>
0355 void
0356 basic_file_body<File>::
0357 writer::
0358 init(error_code& ec)
0359 {
0360     // The error_code specification requires that we
0361     // either set the error to some value, or set it
0362     // to indicate no error.
0363     //
0364     // We don't do anything fancy so set "no error"
0365     ec = {};
0366 }
0367 
0368 // This function is called repeatedly by the serializer to
0369 // retrieve the buffers representing the body. Our strategy
0370 // is to read into our buffer and return it until we have
0371 // read through the whole file.
0372 //
0373 template<class File>
0374 auto
0375 basic_file_body<File>::
0376 writer::
0377 get(error_code& ec) ->
0378     boost::optional<std::pair<const_buffers_type, bool>>
0379 {
0380     // Calculate the smaller of our buffer size,
0381     // or the amount of unread data in the file.
0382     auto const amount =  remain_ > sizeof(buf_) ?
0383         sizeof(buf_) : static_cast<std::size_t>(remain_);
0384 
0385     // Handle the case where the file is zero length
0386     if(amount == 0)
0387     {
0388         // Modify the error code to indicate success
0389         // This is required by the error_code specification.
0390         //
0391         // NOTE We use the existing category instead of calling
0392         //      into the library to get the generic category because
0393         //      that saves us a possibly expensive atomic operation.
0394         //
0395         ec = {};
0396         return boost::none;
0397     }
0398 
0399     // Now read the next buffer
0400     auto const nread = body_.file_.read(buf_, amount, ec);
0401     if(ec)
0402         return boost::none;
0403 
0404     if (nread == 0)
0405     {
0406         BOOST_BEAST_ASSIGN_EC(ec, error::short_read);
0407         return boost::none;
0408     }
0409 
0410     // Make sure there is forward progress
0411     BOOST_ASSERT(nread != 0);
0412     BOOST_ASSERT(nread <= remain_);
0413 
0414     // Update the amount remaining based on what we got
0415     remain_ -= nread;
0416 
0417     // Return the buffer to the caller.
0418     //
0419     // The second element of the pair indicates whether or
0420     // not there is more data. As long as there is some
0421     // unread bytes, there will be more data. Otherwise,
0422     // we set this bool to `false` so we will not be called
0423     // again.
0424     //
0425     ec = {};
0426     return {{
0427         const_buffers_type{buf_, nread},    // buffer to return.
0428         remain_ > 0                         // `true` if there are more buffers.
0429         }};
0430 }
0431 
0432 //]
0433 
0434 //[example_http_file_body_5
0435 
0436 /** Algorithm for storing buffers when parsing.
0437 
0438     Objects of this type are created during parsing
0439     to store incoming buffers representing the body.
0440 */
0441 template<class File>
0442 class basic_file_body<File>::reader
0443 {
0444     value_type& body_;  // The body we are writing to
0445 
0446 public:
0447     // Constructor.
0448     //
0449     // This is called after the header is parsed and
0450     // indicates that a non-zero sized body may be present.
0451     // `h` holds the received message headers.
0452     // `b` is an instance of `basic_file_body`.
0453     //
0454     template<bool isRequest, class Fields>
0455     explicit
0456     reader(header<isRequest, Fields>&h, value_type& b);
0457 
0458     // Initializer
0459     //
0460     // This is called before the body is parsed and
0461     // gives the reader a chance to do something that might
0462     // need to return an error code. It informs us of
0463     // the payload size (`content_length`) which we can
0464     // optionally use for optimization.
0465     //
0466     void
0467     init(boost::optional<std::uint64_t> const&, error_code& ec);
0468 
0469     // This function is called one or more times to store
0470     // buffer sequences corresponding to the incoming body.
0471     //
0472     template<class ConstBufferSequence>
0473     std::size_t
0474     put(ConstBufferSequence const& buffers,
0475         error_code& ec);
0476 
0477     // This function is called when writing is complete.
0478     // It is an opportunity to perform any final actions
0479     // which might fail, in order to return an error code.
0480     // Operations that might fail should not be attempted in
0481     // destructors, since an exception thrown from there
0482     // would terminate the program.
0483     //
0484     void
0485     finish(error_code& ec);
0486 };
0487 
0488 //]
0489 
0490 //[example_http_file_body_6
0491 
0492 // We don't do much in the reader constructor since the
0493 // file is already open.
0494 //
0495 template<class File>
0496 template<bool isRequest, class Fields>
0497 basic_file_body<File>::
0498 reader::
0499 reader(header<isRequest, Fields>& h, value_type& body)
0500     : body_(body)
0501 {
0502     boost::ignore_unused(h);
0503 }
0504 
0505 template<class File>
0506 void
0507 basic_file_body<File>::
0508 reader::
0509 init(
0510     boost::optional<std::uint64_t> const& content_length,
0511     error_code& ec)
0512 {
0513     // The file must already be open for writing
0514     BOOST_ASSERT(body_.file_.is_open());
0515 
0516     // We don't do anything with this but a sophisticated
0517     // application might check available space on the device
0518     // to see if there is enough room to store the body.
0519     boost::ignore_unused(content_length);
0520 
0521     // The error_code specification requires that we
0522     // either set the error to some value, or set it
0523     // to indicate no error.
0524     //
0525     // We don't do anything fancy so set "no error"
0526     ec = {};
0527 }
0528 
0529 // This will get called one or more times with body buffers
0530 //
0531 template<class File>
0532 template<class ConstBufferSequence>
0533 std::size_t
0534 basic_file_body<File>::
0535 reader::
0536 put(ConstBufferSequence const& buffers, error_code& ec)
0537 {
0538     // This function must return the total number of
0539     // bytes transferred from the input buffers.
0540     std::size_t nwritten = 0;
0541 
0542     // Loop over all the buffers in the sequence,
0543     // and write each one to the file.
0544     for(auto it = net::buffer_sequence_begin(buffers);
0545         it != net::buffer_sequence_end(buffers); ++it)
0546     {
0547         // Write this buffer to the file
0548         net::const_buffer buffer = *it;
0549         nwritten += body_.file_.write(
0550             buffer.data(), buffer.size(), ec);
0551         if(ec)
0552             return nwritten;
0553     }
0554 
0555     // Indicate success
0556     // This is required by the error_code specification
0557     ec = {};
0558 
0559     return nwritten;
0560 }
0561 
0562 // Called after writing is done when there's no error.
0563 template<class File>
0564 void
0565 basic_file_body<File>::
0566 reader::
0567 finish(error_code& ec)
0568 {
0569     // This has to be cleared before returning, to
0570     // indicate no error. The specification requires it.
0571     ec = {};
0572 }
0573 
0574 //]
0575 
0576 #if ! BOOST_BEAST_DOXYGEN
0577 // operator<< is not supported for file_body
0578 template<bool isRequest, class File, class Fields>
0579 std::ostream&
0580 operator<<(std::ostream&, message<
0581     isRequest, basic_file_body<File>, Fields> const&) = delete;
0582 #endif
0583 
0584 } // http
0585 } // beast
0586 } // boost
0587 
0588 #endif