| 
									
										
										
										
											2016-05-07 17:06:46 -04:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-02-06 20:07:03 -05:00
										 |  |  | // Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
 | 
					
						
							| 
									
										
										
										
											2016-05-07 17:06:46 -04:00
										 |  |  | //
 | 
					
						
							|  |  |  | // Distributed under the Boost Software License, Version 1.0. (See accompanying
 | 
					
						
							|  |  |  | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-07-20 08:01:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-12 19:16:39 -07:00
										 |  |  | #ifndef BEAST_EXAMPLE_HTTP_SERVER_FILE_BODY_HPP
 | 
					
						
							|  |  |  | #define BEAST_EXAMPLE_HTTP_SERVER_FILE_BODY_HPP
 | 
					
						
							| 
									
										
										
										
											2017-07-20 08:01:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-10 05:34:49 -05:00
										 |  |  | #include <beast/core/error.hpp>
 | 
					
						
							|  |  |  | #include <beast/http/message.hpp>
 | 
					
						
							| 
									
										
										
										
											2017-07-20 08:01:46 -07:00
										 |  |  | #include <boost/filesystem.hpp>
 | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  | #include <boost/assert.hpp>
 | 
					
						
							| 
									
										
										
										
											2017-05-08 12:41:45 -07:00
										 |  |  | #include <boost/optional.hpp>
 | 
					
						
							| 
									
										
										
										
											2017-06-08 05:43:57 -07:00
										 |  |  | #include <algorithm>
 | 
					
						
							| 
									
										
										
										
											2017-07-20 08:01:46 -07:00
										 |  |  | #include <cstdio>
 | 
					
						
							|  |  |  | #include <cstdint>
 | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  | #include <utility>
 | 
					
						
							| 
									
										
										
										
											2017-07-20 08:01:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-14 20:26:44 -07:00
										 |  |  | //[example_http_file_body_1
 | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-12 19:16:39 -07:00
										 |  |  | /** A message body represented by a file on the filesystem.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Messages with this type have bodies represented by a | 
					
						
							|  |  |  |     file on the file system. When parsing a message using | 
					
						
							|  |  |  |     this body type, the data is stored in the file pointed | 
					
						
							|  |  |  |     to by the path, which must be writable. When serializing, | 
					
						
							|  |  |  |     the implementation will read the file and present those | 
					
						
							|  |  |  |     octets as the body content. This may be used to serve | 
					
						
							|  |  |  |     content from a directory as part of a web service. | 
					
						
							|  |  |  | */ | 
					
						
							| 
									
										
										
										
											2017-07-20 08:01:46 -07:00
										 |  |  | struct file_body | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  |     /** The type of the @ref message::body member.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Messages declared using `file_body` will have this | 
					
						
							|  |  |  |         type for the body member. We use a path indicating | 
					
						
							|  |  |  |         the location on the file system for which the data | 
					
						
							|  |  |  |         will be read or written.   | 
					
						
							|  |  |  |     */ | 
					
						
							|  |  |  |     using value_type = boost::filesystem::path; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** Returns the content length of the body in a message.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         This optional static function returns the size of the | 
					
						
							|  |  |  |         body in bytes. It is called from @ref message::size to | 
					
						
							|  |  |  |         return the payload size, and from @ref message::prepare | 
					
						
							|  |  |  |         to automatically set the Content-Length field. If this | 
					
						
							|  |  |  |         function is omitted from a body type, calls to | 
					
						
							|  |  |  |         @ref message::prepare will set the chunked transfer | 
					
						
							|  |  |  |         encoding. | 
					
						
							| 
									
										
										
										
											2017-07-20 08:01:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  |         @param m The message containing a file body to check. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         @return The size of the file in bytes. | 
					
						
							|  |  |  |     */ | 
					
						
							| 
									
										
										
										
											2017-06-05 21:11:33 -07:00
										 |  |  |     static | 
					
						
							|  |  |  |     std::uint64_t | 
					
						
							| 
									
										
										
										
											2017-06-15 19:30:43 -07:00
										 |  |  |     size(value_type const& v); | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /** Algorithm for retrieving buffers when serializing.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Objects of this type are created during serialization | 
					
						
							|  |  |  |         to extract the buffers representing the body. | 
					
						
							|  |  |  |     */ | 
					
						
							|  |  |  |     class reader; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** Algorithm for storing buffers when parsing.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Objects of this type are created during parsing | 
					
						
							|  |  |  |         to store incoming buffers representing the body. | 
					
						
							|  |  |  |     */ | 
					
						
							|  |  |  |     class writer; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //]
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-14 20:26:44 -07:00
										 |  |  | //[example_http_file_body_2
 | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-12 19:16:39 -07:00
										 |  |  | inline | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  | std::uint64_t | 
					
						
							|  |  |  | file_body:: | 
					
						
							| 
									
										
										
										
											2017-06-15 19:30:43 -07:00
										 |  |  | size(value_type const& v) | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2017-06-15 19:30:43 -07:00
										 |  |  |     return boost::filesystem::file_size(v); | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //]
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-14 20:26:44 -07:00
										 |  |  | //[example_http_file_body_3
 | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | class file_body::reader | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     value_type const& path_;    // Path of the file
 | 
					
						
							|  |  |  |     FILE* file_ = nullptr;      // File handle
 | 
					
						
							|  |  |  |     std::uint64_t remain_ = 0;  // The number of unread bytes
 | 
					
						
							|  |  |  |     char buf_[4096];            // Small buffer for reading
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     // This nested type informs the serializer that it should
 | 
					
						
							|  |  |  |     // wait until after sending the header to initialize the
 | 
					
						
							|  |  |  |     // reader. We set this to true, otherwise opening the file
 | 
					
						
							|  |  |  |     // during `init` could introduce latency which delays
 | 
					
						
							|  |  |  |     // the remote endpoint from receiving the header quickly.
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     using is_deferred = std::true_type; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // The type of buffer sequence returned by `get`.
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     using const_buffers_type = | 
					
						
							|  |  |  |         boost::asio::const_buffers_1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Constructor.
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     // This is called after the header is serialized, because
 | 
					
						
							|  |  |  |     // we declared `is_deferred` to be `std::true_type`.
 | 
					
						
							|  |  |  |     // `m` holds the message we are sending, which will
 | 
					
						
							|  |  |  |     // always have the `file_body` as the body type.
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     template<bool isRequest, class Fields> | 
					
						
							| 
									
										
										
										
											2017-06-12 19:16:39 -07:00
										 |  |  |     reader(beast::http::message<isRequest, file_body, Fields> const& m); | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Destructor
 | 
					
						
							|  |  |  |     ~reader(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // This function is called once before serialization
 | 
					
						
							|  |  |  |     // of the body is started.
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     void | 
					
						
							| 
									
										
										
										
											2017-06-12 19:16:39 -07:00
										 |  |  |     init(beast::error_code& ec); | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // This function is called zero or more times to
 | 
					
						
							|  |  |  |     // retrieve buffers. A return value of `boost::none`
 | 
					
						
							|  |  |  |     // means there are no more buffers. Otherwise,
 | 
					
						
							|  |  |  |     // the contained pair will have the next buffer
 | 
					
						
							|  |  |  |     // to serialize, and a `bool` indicating whether
 | 
					
						
							|  |  |  |     // or not there may be additional buffers.
 | 
					
						
							|  |  |  |     boost::optional<std::pair<const_buffers_type, bool>> | 
					
						
							| 
									
										
										
										
											2017-06-12 19:16:39 -07:00
										 |  |  |     get(beast::error_code& ec); | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // This function is called when reading is complete.
 | 
					
						
							|  |  |  |     // It is an opportunity to perform any final actions
 | 
					
						
							|  |  |  |     // which might fail, in order to return an error code.
 | 
					
						
							|  |  |  |     // Operations that might fail should not be attemped in
 | 
					
						
							|  |  |  |     // destructors, since an exception thrown from there
 | 
					
						
							|  |  |  |     // would terminate the program.
 | 
					
						
							|  |  |  |     void | 
					
						
							| 
									
										
										
										
											2017-06-12 19:16:39 -07:00
										 |  |  |     finish(beast::error_code& ec); | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //]
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-14 20:26:44 -07:00
										 |  |  | //[example_http_file_body_4
 | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Here we just stash a reference to the path for later.
 | 
					
						
							|  |  |  | // Rather than dealing with messy constructor exceptions,
 | 
					
						
							|  |  |  | // we save the things that might fail for the call to `init`.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | template<bool isRequest, class Fields> | 
					
						
							|  |  |  | file_body::reader:: | 
					
						
							| 
									
										
										
										
											2017-06-12 19:16:39 -07:00
										 |  |  | reader(beast::http::message<isRequest, file_body, Fields> const& m) | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  |     : path_(m.body) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // This gets called right after construction, and provides
 | 
					
						
							|  |  |  | // the opportunity to return an error code. The error code
 | 
					
						
							|  |  |  | // will be propagated to the serializer and eventually
 | 
					
						
							|  |  |  | // returned to the caller.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | inline | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | file_body::reader:: | 
					
						
							| 
									
										
										
										
											2017-06-12 19:16:39 -07:00
										 |  |  | init(beast::error_code& ec) | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  | { | 
					
						
							|  |  |  |     // Attempt to open the file for reading
 | 
					
						
							|  |  |  |     file_ = fopen(path_.string().c_str(), "rb"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if(! file_) | 
					
						
							| 
									
										
										
										
											2017-06-05 21:11:33 -07:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  |         // Convert the old-school `errno` into
 | 
					
						
							| 
									
										
										
										
											2017-06-17 08:35:09 -07:00
										 |  |  |         // an error code using the generic category.
 | 
					
						
							|  |  |  |         ec = beast::error_code{errno, beast::generic_category()}; | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  |         return; | 
					
						
							| 
									
										
										
										
											2017-06-05 21:11:33 -07:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  |     // The file was opened successfully, get the size
 | 
					
						
							|  |  |  |     // of the file to know how much we need to read.
 | 
					
						
							| 
									
										
										
										
											2017-06-13 07:08:52 -07:00
										 |  |  |     ec = {}; | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  |     remain_ = boost::filesystem::file_size(path_); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // This function is called repeatedly by the serializer to
 | 
					
						
							|  |  |  | // retrieve the buffers representing the body. Our strategy
 | 
					
						
							|  |  |  | // is to read into our buffer and return it until we have
 | 
					
						
							|  |  |  | // read through the whole file.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | inline | 
					
						
							|  |  |  | auto | 
					
						
							|  |  |  | file_body::reader:: | 
					
						
							| 
									
										
										
										
											2017-06-12 19:16:39 -07:00
										 |  |  | get(beast::error_code& ec) -> | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  |     boost::optional<std::pair<const_buffers_type, bool>> | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // Calculate the smaller of our buffer size,
 | 
					
						
							|  |  |  |     // or the amount of unread data in the file.
 | 
					
						
							| 
									
										
										
										
											2017-06-17 13:04:01 -07:00
										 |  |  |     auto const amount =  remain_ > sizeof(buf_) ? | 
					
						
							|  |  |  |         sizeof(buf_) : static_cast<std::size_t>(remain_); | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Check for an empty file
 | 
					
						
							|  |  |  |     if(amount == 0) | 
					
						
							| 
									
										
										
										
											2017-06-13 07:08:52 -07:00
										 |  |  |     { | 
					
						
							|  |  |  |         ec = {}; | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  |         return boost::none; | 
					
						
							| 
									
										
										
										
											2017-06-13 07:08:52 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Now read the next buffer
 | 
					
						
							|  |  |  |     auto const nread = fread(buf_, 1, amount, file_); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Handle any errors
 | 
					
						
							|  |  |  |     if(ferror(file_)) | 
					
						
							| 
									
										
										
										
											2017-07-20 08:01:46 -07:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2017-06-17 08:35:09 -07:00
										 |  |  |         // Convert the old-school `errno` into
 | 
					
						
							|  |  |  |         // an error code using the generic category.
 | 
					
						
							|  |  |  |         ec = beast::error_code{errno, beast::generic_category()}; | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  |         return boost::none; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-07-20 08:01:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  |     // Make sure there is forward progress
 | 
					
						
							|  |  |  |     BOOST_ASSERT(nread != 0); | 
					
						
							|  |  |  |     BOOST_ASSERT(nread <= remain_); | 
					
						
							| 
									
										
										
										
											2017-07-20 08:01:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  |     // Update the amount remaining based on what we got
 | 
					
						
							|  |  |  |     remain_ -= nread; | 
					
						
							| 
									
										
										
										
											2017-07-20 08:01:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  |     // Return the buffer to the caller.
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     // The second element of the pair indicates whether or
 | 
					
						
							|  |  |  |     // not there is more data. As long as there is some
 | 
					
						
							|  |  |  |     // unread bytes, there will be more data. Otherwise,
 | 
					
						
							|  |  |  |     // we set this bool to `false` so we will not be called
 | 
					
						
							|  |  |  |     // again.
 | 
					
						
							|  |  |  |     //
 | 
					
						
							| 
									
										
										
										
											2017-06-13 07:08:52 -07:00
										 |  |  |     ec = {}; | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  |     return {{ | 
					
						
							|  |  |  |         const_buffers_type{buf_, nread},    // buffer to return.
 | 
					
						
							|  |  |  |         remain_ > 0                         // `true` if there are more buffers.
 | 
					
						
							|  |  |  |         }}; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Called after reading is done when there's no error.
 | 
					
						
							|  |  |  | inline | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | file_body::reader:: | 
					
						
							| 
									
										
										
										
											2017-06-12 19:16:39 -07:00
										 |  |  | finish(beast::error_code& ec) | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2017-06-13 07:08:52 -07:00
										 |  |  |     // Functions which pass back errors are
 | 
					
						
							|  |  |  |     // responsible for clearing the error code.
 | 
					
						
							|  |  |  |     ec = {}; | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // The destructor is always invoked if construction succeeds.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | inline | 
					
						
							|  |  |  | file_body::reader:: | 
					
						
							|  |  |  | ~reader() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // Just close the file if its open
 | 
					
						
							|  |  |  |     if(file_) | 
					
						
							|  |  |  |         fclose(file_); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // In theory fclose() can fail but how would we handle it?
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //]
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-14 20:26:44 -07:00
										 |  |  | //[example_http_file_body_5
 | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | class file_body::writer | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     value_type const& path_;    // A path to the file
 | 
					
						
							|  |  |  |     FILE* file_ = nullptr;      // The file handle
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     // Constructor.
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     // This is called after the header is parsed and
 | 
					
						
							|  |  |  |     // indicates that a non-zero sized body may be present.
 | 
					
						
							|  |  |  |     // `m` holds the message we are receiving, which will
 | 
					
						
							|  |  |  |     // always have the `file_body` as the body type.
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     template<bool isRequest, class Fields> | 
					
						
							|  |  |  |     explicit | 
					
						
							| 
									
										
										
										
											2017-06-12 19:16:39 -07:00
										 |  |  |     writer(beast::http::message<isRequest, file_body, Fields>& m); | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // This function is called once before parsing
 | 
					
						
							|  |  |  |     // of the body is started.
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     void | 
					
						
							| 
									
										
										
										
											2017-06-12 19:16:39 -07:00
										 |  |  |     init(boost::optional<std::uint64_t> const& content_length, beast::error_code& ec); | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // This function is called one or more times to store
 | 
					
						
							|  |  |  |     // buffer sequences corresponding to the incoming body.
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     template<class ConstBufferSequence> | 
					
						
							|  |  |  |     void | 
					
						
							| 
									
										
										
										
											2017-06-12 19:16:39 -07:00
										 |  |  |     put(ConstBufferSequence const& buffers, beast::error_code& ec); | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // This function is called when writing is complete.
 | 
					
						
							|  |  |  |     // It is an opportunity to perform any final actions
 | 
					
						
							|  |  |  |     // which might fail, in order to return an error code.
 | 
					
						
							|  |  |  |     // Operations that might fail should not be attemped in
 | 
					
						
							|  |  |  |     // destructors, since an exception thrown from there
 | 
					
						
							|  |  |  |     // would terminate the program.
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     void | 
					
						
							| 
									
										
										
										
											2017-06-12 19:16:39 -07:00
										 |  |  |     finish(beast::error_code& ec); | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Destructor.
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     // Avoid calling anything that might fail here.
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     ~writer(); | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2017-06-09 14:55:44 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  | //]
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-14 20:26:44 -07:00
										 |  |  | //[example_http_file_body_6
 | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Just stash a reference to the path so we can open the file later.
 | 
					
						
							|  |  |  | template<bool isRequest, class Fields> | 
					
						
							|  |  |  | file_body::writer:: | 
					
						
							| 
									
										
										
										
											2017-06-12 19:16:39 -07:00
										 |  |  | writer(beast::http::message<isRequest, file_body, Fields>& m) | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  |     : path_(m.body) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // This gets called once when we know there's a body.
 | 
					
						
							|  |  |  | // If the content_length is set, it lets us know the exact size
 | 
					
						
							|  |  |  | // of the body. An implementation could use this to optimize its
 | 
					
						
							|  |  |  | // storage strategy. For example by attempting to reserve space
 | 
					
						
							|  |  |  | // ahead of time.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | inline | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | file_body::writer:: | 
					
						
							| 
									
										
										
										
											2017-06-12 19:16:39 -07:00
										 |  |  | init(boost::optional<std::uint64_t> const& content_length, beast::error_code& ec) | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2017-06-22 10:27:45 -07:00
										 |  |  |     boost::ignore_unused(content_length); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  |     // Attempt to open the file for writing
 | 
					
						
							|  |  |  |     file_ = fopen(path_.string().c_str(), "wb"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if(! file_) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // Convert the old-school `errno` into
 | 
					
						
							| 
									
										
										
										
											2017-06-17 08:35:09 -07:00
										 |  |  |         // an error code using the generic category.
 | 
					
						
							|  |  |  |         ec = beast::error_code{errno, beast::generic_category()}; | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-06-13 07:08:52 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Indicate success
 | 
					
						
							|  |  |  |     ec = {}; | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // This will get called one or more times with body buffers
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | template<class ConstBufferSequence> | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | file_body::writer:: | 
					
						
							| 
									
										
										
										
											2017-06-12 19:16:39 -07:00
										 |  |  | put(ConstBufferSequence const& buffers, beast::error_code& ec) | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  | { | 
					
						
							|  |  |  |     // Loop over all the buffers in the sequence,
 | 
					
						
							|  |  |  |     // and write each one to the file.
 | 
					
						
							| 
									
										
										
										
											2017-06-13 11:53:06 -07:00
										 |  |  |     for(boost::asio::const_buffer buffer : buffers) | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  |     { | 
					
						
							|  |  |  |         // Write this buffer to the file
 | 
					
						
							|  |  |  |         fwrite( | 
					
						
							|  |  |  |             boost::asio::buffer_cast<void const*>(buffer), 1, | 
					
						
							|  |  |  |             boost::asio::buffer_size(buffer), | 
					
						
							|  |  |  |             file_); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Handle any errors
 | 
					
						
							|  |  |  |         if(ferror(file_)) | 
					
						
							| 
									
										
										
										
											2017-06-09 14:55:44 -07:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2017-06-17 08:35:09 -07:00
										 |  |  |             // Convert the old-school `errno` into
 | 
					
						
							|  |  |  |             // an error code using the generic category.
 | 
					
						
							|  |  |  |             ec = beast::error_code{errno, beast::generic_category()}; | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  |             return; | 
					
						
							| 
									
										
										
										
											2017-06-09 14:55:44 -07:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-06-13 07:08:52 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Indicate success
 | 
					
						
							|  |  |  |     ec = {}; | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Called after writing is done when there's no error.
 | 
					
						
							|  |  |  | inline | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | file_body::writer:: | 
					
						
							| 
									
										
										
										
											2017-06-12 19:16:39 -07:00
										 |  |  | finish(beast::error_code& ec) | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2017-06-12 19:16:39 -07:00
										 |  |  |     // This has to be cleared before returning, to
 | 
					
						
							|  |  |  |     // indicate no error. The specification requires it.
 | 
					
						
							| 
									
										
										
										
											2017-06-13 07:08:52 -07:00
										 |  |  |     ec = {}; | 
					
						
							| 
									
										
										
										
											2017-06-08 22:03:58 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // The destructor is always invoked if construction succeeds
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | inline | 
					
						
							|  |  |  | file_body::writer:: | 
					
						
							|  |  |  | ~writer() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // Just close the file if its open
 | 
					
						
							|  |  |  |     if(file_) | 
					
						
							|  |  |  |         fclose(file_); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // In theory fclose() can fail but how would we handle it?
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //]
 | 
					
						
							| 
									
										
										
										
											2017-07-20 08:01:46 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | #endif
 |