diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d23f538..698ada85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ Version 74: * Add file_stdio and File concept * Add file_win32 * Add file_body +* Remove common/file_body.hpp -------------------------------------------------------------------------------- diff --git a/doc/2_examples.qbk b/doc/2_examples.qbk index 6ecd97aa..f4a87325 100644 --- a/doc/2_examples.qbk +++ b/doc/2_examples.qbk @@ -154,7 +154,6 @@ stand alone can be directly included in your projects. * [repo_file example/common/const_body.hpp] * [repo_file example/common/detect_ssl.hpp] -* [repo_file example/common/file_body.hpp] * [repo_file example/common/helpers.hpp] * [repo_file example/common/mime_types.hpp] * [repo_file example/common/mutable_body.hpp] diff --git a/example/common/file_body.hpp b/example/common/file_body.hpp deleted file mode 100644 index ba9004b5..00000000 --- a/example/common/file_body.hpp +++ /dev/null @@ -1,392 +0,0 @@ -// -// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// 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) -// - -#ifndef BEAST_EXAMPLE_COMMON_FILE_BODY_HPP -#define BEAST_EXAMPLE_COMMON_FILE_BODY_HPP - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -//[example_http_file_body_1 - -/** 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. -*/ -struct file_body -{ - /** 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; - - /** The type of the @ref message::body member. - - Messages declared using `file_body` will have this - type for the body member. This rich class interface - allow the file to be opened with the file handle - maintained directly in the object, which is attached - to the message. - */ - class value_type; -}; - -//] - -//[example_http_file_body_2 - -// The body container holds a handle to the file if -// it is open, and we also cache the size upon opening. -// -class file_body::value_type -{ - friend class reader; - friend class writer; - - FILE* file_ = nullptr; - std::uint64_t size_; - -public: - /** Destructor. - - If the file handle is open, it is closed first. - */ - ~value_type() - { - if(file_) - fclose(file_); - } - - /// Default constructor - value_type() = default; - - /// Move constructor - value_type(value_type&& other) - : file_(other.file_) - , size_(other.size_) - { - other.file_ = nullptr; - } - - /// Move assignment - value_type& operator=(value_type&& other) - { - file_ = other.file_; - size_ = other.size_; - other.file_ = nullptr; - return *this; - } - - /// Returns `true` if the file is open - bool - is_open() const - { - return file_ != nullptr; - } - - /** Open a file for reading or writing. - - @param path The path to the file - - @param mode The open mode used with fopen() - - @param ec Set to the error, if any occurred - */ - void - open(boost::filesystem::path const& path, - char const* mode, beast::error_code& ec) - { - // Attempt to open the file for reading - file_ = fopen(path.string().c_str(), mode); - - if(! file_) - { - // Convert the old-school `errno` into - // an error code using the generic category. - ec = beast::error_code{errno, beast::generic_category()}; - return; - } - - // The file was opened successfully. - // If we are reading, cache the file size. - if(std::string{mode} == "rb") - { - size_ = boost::filesystem::file_size(path, ec); - } - else - { - // This is required by the error_code specification - ec = {}; - } - } - - /** Returns the size of the file. - - Preconditions: - - * The file must be open for binary reading (mode=="rb") - - @return The size of the file if a file is open, else undefined. - */ - std::uint64_t - size() const - { - return size_; - } -}; - -//] - -//[example_http_file_body_3 - -class file_body::reader -{ - FILE* file_; // The file handle - std::uint64_t remain_; // The number of unread bytes - char buf_[4096]; // Small buffer for reading - -public: - // The type of buffer sequence returned by `get`. - // - using const_buffers_type = - boost::asio::const_buffers_1; - - // Constructor. - // - // `m` holds the message we are sending, which will - // always have the `file_body` as the body type. - // - template - reader(beast::http::message const& m, - beast::error_code& ec); - - // 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> - get(beast::error_code& ec); -}; - -//] - -//[example_http_file_body_4 - -// 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 -file_body::reader:: -reader(beast::http::message const& m, - beast::error_code& ec) - : file_(m.body.file_) - , remain_(m.body.size()) -{ - // The file must already be open - BOOST_ASSERT(file_ != nullptr); - - // This is required by the error_code specification - ec = {}; -} - -// 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:: -get(beast::error_code& ec) -> - boost::optional> -{ - // Calculate the smaller of our buffer size, - // or the amount of unread data in the file. - auto const amount = remain_ > sizeof(buf_) ? - sizeof(buf_) : static_cast(remain_); - - // Check for an empty file - if(amount == 0) - { - ec = {}; - return boost::none; - } - - // Now read the next buffer - auto const nread = fread(buf_, 1, amount, file_); - - // Handle any errors - if(ferror(file_)) - { - // Convert the old-school `errno` into - // an error code using the generic category. - ec = beast::error_code{errno, beast::generic_category()}; - return boost::none; - } - - // Make sure there is forward progress - BOOST_ASSERT(nread != 0); - BOOST_ASSERT(nread <= remain_); - - // Update the amount remaining based on what we got - remain_ -= nread; - - // 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. - // - ec = {}; - return {{ - const_buffers_type{buf_, nread}, // buffer to return. - remain_ > 0 // `true` if there are more buffers. - }}; -} - -//] - -//[example_http_file_body_5 - -class file_body::writer -{ - FILE* file_; // 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 - explicit - writer(beast::http::message& m, - boost::optional const& content_length, - beast::error_code& ec); - - // This function is called one or more times to store - // buffer sequences corresponding to the incoming body. - // - template - std::size_t - put(ConstBufferSequence const& buffers, beast::error_code& ec); - - // 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 - finish(beast::error_code& ec); -}; - -//] - -//[example_http_file_body_6 - -// Just stash a reference to the path so we can open the file later. -template -file_body::writer:: -writer(beast::http::message& m, - boost::optional const& content_length, - beast::error_code& ec) - : file_(m.body.file_) -{ - // We don't do anything with this but a sophisticated - // application might check available space on the device - // to see if there is enough room to store the body. - boost::ignore_unused(content_length); - - // The file must already be open for writing - BOOST_ASSERT(file_ != nullptr); - - // This is required by the error_code specification - ec = {}; -} - -// This will get called one or more times with body buffers -// -template -std::size_t -file_body::writer:: -put(ConstBufferSequence const& buffers, beast::error_code& ec) -{ - // This function must return the total number of - // bytes transferred from the input buffers. - std::size_t bytes_transferred = 0; - - // Loop over all the buffers in the sequence, - // and write each one to the file. - for(boost::asio::const_buffer buffer : buffers) - { - // Write this buffer to the file - bytes_transferred += fwrite( - boost::asio::buffer_cast(buffer), 1, - boost::asio::buffer_size(buffer), - file_); - - // Handle any errors - if(ferror(file_)) - { - // Convert the old-school `errno` into - // an error code using the generic category. - ec = beast::error_code{errno, beast::generic_category()}; - return bytes_transferred; - } - } - - // Indicate success - ec = {}; - - return bytes_transferred; -} - -// Called after writing is done when there's no error. -inline -void -file_body::writer:: -finish(beast::error_code& ec) -{ - // This has to be cleared before returning, to - // indicate no error. The specification requires it. - ec = {}; -} - -//] - -#endif diff --git a/example/http-server-threaded/http_server_threaded.cpp b/example/http-server-threaded/http_server_threaded.cpp index 310c3412..2b2924fc 100644 --- a/example/http-server-threaded/http_server_threaded.cpp +++ b/example/http-server-threaded/http_server_threaded.cpp @@ -5,7 +5,6 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#include "../common/file_body.hpp" #include "../common/mime_types.hpp" #include @@ -71,12 +70,12 @@ private: // Return an HTTP Not Found response // - beast::http::response + http::response not_found() const { - beast::http::response res{beast::http::status::not_found, 11}; - res.set(beast::http::field::server, BEAST_VERSION_STRING); - res.set(beast::http::field::content_type, "text/html"); + http::response res{http::status::not_found, 11}; + res.set(http::field::server, BEAST_VERSION_STRING); + res.set(http::field::content_type, "text/html"); res.set(http::field::connection, "close"); res.body = "The file was not found"; res.prepare_payload(); @@ -85,12 +84,12 @@ private: // Return an HTTP Server Error // - beast::http::response + http::response server_error(beast::error_code const& ec) const { - beast::http::response res{beast::http::status::internal_server_error, 11}; - res.set(beast::http::field::server, BEAST_VERSION_STRING); - res.set(beast::http::field::content_type, "text/html"); + http::response res{http::status::internal_server_error, 11}; + res.set(http::field::server, BEAST_VERSION_STRING); + res.set(http::field::content_type, "text/html"); res.set(http::field::connection, "close"); res.body = "Error: " + ec.message(); res.prepare_payload(); @@ -99,18 +98,18 @@ private: // Return a file response to an HTTP GET request // - beast::http::response + http::response get(boost::filesystem::path const& full_path, beast::error_code& ec) const { - beast::http::response res; - res.set(beast::http::field::server, BEAST_VERSION_STRING); - res.set(beast::http::field::content_type, mime_type(full_path)); + http::response res; + res.set(http::field::server, BEAST_VERSION_STRING); + res.set(http::field::content_type, mime_type(full_path)); res.set(http::field::connection, "close"); - res.body.open(full_path, "rb", ec); + res.body.open(full_path.string().c_str(), beast::file_mode::scan, ec); if(ec) return res; - res.set(beast::http::field::content_length, res.body.size()); + res.set(http::field::content_length, res.body.size()); return res; } diff --git a/example/server-framework/file_service.hpp b/example/server-framework/file_service.hpp index 7110e355..8c7056d8 100644 --- a/example/server-framework/file_service.hpp +++ b/example/server-framework/file_service.hpp @@ -9,11 +9,11 @@ #define BEAST_EXAMPLE_SERVER_FILE_SERVICE_HPP #include "framework.hpp" -#include "../common/file_body.hpp" #include "../common/mime_types.hpp" #include #include +#include #include #include @@ -233,17 +233,17 @@ private: // Return a file response to an HTTP GET request // template - boost::optional> + boost::optional> get( beast::http::request const& req, boost::filesystem::path const& full_path, beast::error_code& ec) const { - beast::http::response res; + beast::http::response res; res.version = req.version; res.set(beast::http::field::server, server_); res.set(beast::http::field::content_type, mime_type(full_path)); - res.body.open(full_path, "rb", ec); + res.body.open(full_path.string().c_str(), beast::file_mode::scan, ec); if(ec) return boost::none; res.set(beast::http::field::content_length, res.body.size()); @@ -265,8 +265,8 @@ private: res.set(beast::http::field::content_type, mime_type(full_path)); // Use a manual file body here - file_body::value_type body; - body.open(full_path, "rb", ec); + beast::http::file_body::value_type body; + body.open(full_path.string().c_str(), beast::file_mode::scan, ec); if(ec) return boost::none; res.set(beast::http::field::content_length, body.size()); diff --git a/test/common/CMakeLists.txt b/test/common/CMakeLists.txt index 0f7910bb..7f75cb9d 100644 --- a/test/common/CMakeLists.txt +++ b/test/common/CMakeLists.txt @@ -9,7 +9,6 @@ add_executable (common-test ${BEAST_INCLUDES} ${COMMON_INCLUDES} detect_ssl.cpp - file_body.cpp const_body.cpp mutable_body.cpp mime_types.cpp diff --git a/test/common/Jamfile b/test/common/Jamfile index ca992351..282b842b 100644 --- a/test/common/Jamfile +++ b/test/common/Jamfile @@ -7,7 +7,6 @@ exe common-test : detect_ssl.cpp - file_body.cpp mime_types.cpp rfc7231.cpp ssl_stream.cpp diff --git a/test/common/file_body.cpp b/test/common/file_body.cpp deleted file mode 100644 index ab4e80cc..00000000 --- a/test/common/file_body.cpp +++ /dev/null @@ -1,10 +0,0 @@ -// -// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// 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) -// - -// Test that header file is self-contained. -#include "../../example/common/file_body.hpp" -