diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5072297b..bd010d0f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,7 @@ Version 80:
* Add basic_dynamic_body.hpp
* Shrink buffer_prefix_view
* Remove unused file_path
+* Add basic_file_body.hpp
--------------------------------------------------------------------------------
diff --git a/doc/0_main.qbk b/doc/0_main.qbk
index 90de1b15..91b6c803 100644
--- a/doc/0_main.qbk
+++ b/doc/0_main.qbk
@@ -84,7 +84,7 @@
[import ../example/http-client/http_client.cpp]
[import ../example/websocket-client/websocket_client.cpp]
-[import ../include/beast/http/file_body.hpp]
+[import ../include/beast/http/basic_file_body.hpp]
[import ../test/exemplars.cpp]
[import ../test/core/doc_snippets.cpp]
diff --git a/doc/5_02_message.qbk b/doc/5_02_message.qbk
index 6101fdc4..df82773f 100644
--- a/doc/5_02_message.qbk
+++ b/doc/5_02_message.qbk
@@ -146,6 +146,8 @@ meet the requirements, or use the ones that come with the library:
]]
[[
[link beast.ref.beast__http__file_body `file_body`]
+
+ [link beast.ref.beast__http__basic_file_body `basic_file_body`]
][
This body is represented by a file opened for either reading or
writing. Messages with this body may be serialized and parsed.
diff --git a/doc/quickref.xml b/doc/quickref.xml
index 3a0f5961..569c27cd 100644
--- a/doc/quickref.xml
+++ b/doc/quickref.xml
@@ -30,14 +30,15 @@
Classesbasic_dynamic_body
- basic_file_bodybasic_fields
+ basic_file_bodybasic_parserbasic_string_bodybuffer_bodydynamic_bodyempty_bodyfields
+ file_bodyheadermessageparser
diff --git a/include/beast/http/basic_file_body.hpp b/include/beast/http/basic_file_body.hpp
new file mode 100644
index 00000000..8fcc2916
--- /dev/null
+++ b/include/beast/http/basic_file_body.hpp
@@ -0,0 +1,528 @@
+//
+// 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_HTTP_BASIC_FILE_BODY_HPP
+#define BEAST_HTTP_BASIC_FILE_BODY_HPP
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace beast {
+namespace http {
+
+//[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.
+
+ @tparam File The implementation to use for accessing files.
+ This type must meet the requirements of @b File.
+*/
+template
+struct basic_file_body
+{
+ // Make sure the type meets the requirements
+ static_assert(is_file::value,
+ "File requirements not met");
+
+ /// The type of File this body uses
+ using file_type = File;
+
+ // Algorithm for retrieving buffers when serializing.
+ class reader;
+
+ // Algorithm for storing buffers when parsing.
+ class writer;
+
+ // The type of the @ref message::body member.
+ class value_type;
+
+ /** Returns the size of the body
+
+ @param body The file body to use
+ */
+ static
+ std::uint64_t
+ size(value_type const& body);
+};
+
+//]
+
+//[example_http_file_body_2
+
+/** The type of the @ref message::body member.
+
+ Messages declared using `basic_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.
+*/
+template
+class basic_file_body::value_type
+{
+ // This body container holds a handle to the file
+ // when it is open, and also caches the size when set.
+
+ friend class reader;
+ friend class writer;
+ friend struct basic_file_body;
+
+ // This represents the open file
+ File file_;
+
+ // The cached file size
+ std::uint64_t file_size_ = 0;
+
+public:
+ /** Destructor.
+
+ If the file is open, it is closed first.
+ */
+ ~value_type() = default;
+
+ /// Constructor
+ value_type() = default;
+
+ /// Constructor
+ value_type(value_type&& other) = default;
+
+ /// Move assignment
+ value_type& operator=(value_type&& other) = default;
+
+ /// Returns `true` if the file is open
+ bool
+ is_open() const
+ {
+ return file_.is_open();
+ }
+
+ /// Returns the size of the file if open
+ std::uint64_t
+ size() const
+ {
+ return file_size_;
+ }
+
+ /// Close the file if open
+ void
+ close();
+
+ /** Open a file at the given path with the specified mode
+
+ @param path The utf-8 encoded path to the file
+
+ @param mode The file mode to use
+
+ @param ec Set to the error, if any occurred
+ */
+ void
+ open(char const* path, file_mode mode, error_code& ec);
+
+ /** Set the open file
+
+ This function is used to set the open
+ */
+ void
+ reset(File&& file, error_code& ec);
+};
+
+template
+void
+basic_file_body::
+value_type::
+close()
+{
+ error_code ignored;
+ file_.close(ignored);
+}
+
+template
+void
+basic_file_body::
+value_type::
+open(char const* path, file_mode mode, error_code& ec)
+{
+ // Open the file
+ file_.open(path, mode, ec);
+ if(ec)
+ return;
+
+ // Cache the size
+ file_size_ = file_.size(ec);
+ if(ec)
+ {
+ close();
+ return;
+ }
+}
+
+template
+void
+basic_file_body::
+value_type::
+reset(File&& file, error_code& ec)
+{
+ // First close the file if open
+ if(file_.is_open())
+ {
+ error_code ignored;
+ file_.close(ignored);
+ }
+
+ // Take ownership of the new file
+ file_ = std::move(file);
+
+ // Cache the size
+ file_size_ = file_.size(ec);
+}
+
+// This is called from message::payload_size
+template
+std::uint64_t
+basic_file_body::
+size(value_type const& body)
+{
+ // Forward the call to the body
+ return body.size();
+}
+
+//]
+
+//[example_http_file_body_3
+
+/** Algorithm for retrieving buffers when serializing.
+
+ Objects of this type are created during serialization
+ to extract the buffers representing the body.
+*/
+template
+class basic_file_body::reader
+{
+ value_type& body_; // The body we are reading from
+ 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.
+ //
+ // Note that the message is passed by non-const reference.
+ // This is intentional, because reading from the file
+ // changes its "current position" which counts makes the
+ // operation logically not-const (although it is bitwise
+ // const).
+ //
+ // The BodyReader concept allows the reader to choose
+ // whether to take the message by const reference or
+ // non-const reference. Depending on the choice, a
+ // serializer constructed using that body type will
+ // require the same const or non-const reference to
+ // construct.
+ //
+ // Readers which accept const messages usually allow
+ // the same body to be serialized by multiple threads
+ // concurrently, while readers accepting non-const
+ // messages may only be serialized by one thread at
+ // a time.
+ //
+ template
+ reader(message<
+ isRequest, basic_file_body, Fields>& m);
+
+ // Initializer
+ //
+ // This is called before the body is serialized and
+ // gives the reader a chance to do something that might
+ // need to return an error code.
+ //
+ void
+ init(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(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
+template
+basic_file_body::
+reader::
+reader(message& m)
+ : body_(m.body)
+{
+ // The file must already be open
+ BOOST_ASSERT(body_.file_.is_open());
+
+ // Get the size of the file
+ remain_ = body_.file_size_;
+}
+
+// Initializer
+template
+void
+basic_file_body::
+reader::
+init(error_code& ec)
+{
+ // The error_code specification requires that we
+ // either set the error to some value, or set it
+ // to indicate no error.
+ //
+ // We don't do anything fancy so set "no error"
+ ec.assign(0, ec.category());
+}
+
+// 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.
+//
+template
+auto
+basic_file_body::
+reader::
+get(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_);
+
+ // Handle the case where the file is zero length
+ if(amount == 0)
+ {
+ // Modify the error code to indicate success
+ // This is required by the error_code specification.
+ //
+ // NOTE We use the existing category instead of calling
+ // into the library to get the generic category because
+ // that saves us a possibly expensive atomic operation.
+ //
+ ec.assign(0, ec.category());
+ return boost::none;
+ }
+
+ // Now read the next buffer
+ auto const nread = body_.file_.read(buf_, amount, ec);
+ if(ec)
+ 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.assign(0, ec.category());
+ return {{
+ const_buffers_type{buf_, nread}, // buffer to return.
+ remain_ > 0 // `true` if there are more buffers.
+ }};
+}
+
+//]
+
+//[example_http_file_body_5
+
+/** Algorithm for storing buffers when parsing.
+
+ Objects of this type are created during parsing
+ to store incoming buffers representing the body.
+*/
+template
+class basic_file_body::writer
+{
+ value_type& body_; // The body we are writing to
+
+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(
+ message& m);
+
+ // Initializer
+ //
+ // This is called before the body is parsed and
+ // gives the writer a chance to do something that might
+ // need to return an error code. It informs us of
+ // the payload size (`content_length`) which we can
+ // optionally use for optimization.
+ //
+ void
+ init(boost::optional const&, 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,
+ 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(error_code& ec);
+};
+
+//]
+
+//[example_http_file_body_6
+
+// We don't do much in the writer constructor since the
+// file is already open.
+//
+template
+template
+basic_file_body::
+writer::
+writer(message& m)
+ : body_(m.body)
+{
+}
+
+template
+void
+basic_file_body::
+writer::
+init(
+ boost::optional const& content_length,
+ error_code& ec)
+{
+ // The file must already be open for writing
+ BOOST_ASSERT(body_.file_.is_open());
+
+ // 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 error_code specification requires that we
+ // either set the error to some value, or set it
+ // to indicate no error.
+ //
+ // We don't do anything fancy so set "no error"
+ ec.assign(0, ec.category());
+}
+
+// This will get called one or more times with body buffers
+//
+template
+template
+std::size_t
+basic_file_body::
+writer::
+put(ConstBufferSequence const& buffers, error_code& ec)
+{
+ // This function must return the total number of
+ // bytes transferred from the input buffers.
+ std::size_t nwritten = 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
+ nwritten += body_.file_.write(
+ boost::asio::buffer_cast(buffer),
+ boost::asio::buffer_size(buffer),
+ ec);
+ if(ec)
+ return nwritten;
+ }
+
+ // Indicate success
+ // This is required by the error_code specification
+ ec.assign(0, ec.category());
+
+ return nwritten;
+}
+
+// Called after writing is done when there's no error.
+template
+void
+basic_file_body::
+writer::
+finish(error_code& ec)
+{
+ // This has to be cleared before returning, to
+ // indicate no error. The specification requires it.
+ ec.assign(0, ec.category());
+}
+
+//]
+
+#if ! BEAST_DOXYGEN
+// operator<< is not supported for file_body
+template
+std::ostream&
+operator<<(std::ostream& os, message<
+ isRequest, basic_file_body, Fields> const& msg) = delete;
+#endif
+
+} // http
+} // beast
+
+#endif
diff --git a/include/beast/http/file_body.hpp b/include/beast/http/file_body.hpp
index 2986c904..7e98643d 100644
--- a/include/beast/http/file_body.hpp
+++ b/include/beast/http/file_body.hpp
@@ -8,11 +8,8 @@
#ifndef BEAST_HTTP_FILE_BODY_HPP
#define BEAST_HTTP_FILE_BODY_HPP
-#include
-#include
#include
-#include
-#include
+#include
#include
#include
#include
@@ -23,505 +20,9 @@
namespace beast {
namespace http {
-//[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.
-
- @tparam File The implementation to use for accessing files.
- This type must meet the requirements of @b File.
-*/
-template
-struct basic_file_body
-{
- static_assert(is_file::value,
- "File requirements not met");
-
- /// The type of File this body uses
- using file_type = File;
-
- /** 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 `basic_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;
-
- /** Returns the size of the body
-
- @param v The file body to use
- */
- static
- std::uint64_t
- size(value_type const& v);
-};
-
-//]
-
-//[example_http_file_body_2
-
-// The body container holds a handle to the file when
-// it is open, and also caches the size when set.
-//
-template
-class basic_file_body::value_type
-{
- friend class reader;
- friend class writer;
- friend struct basic_file_body;
-
- // This represents the open file
- File file_;
-
- // The cached file size
- std::uint64_t file_size_ = 0;
-
-public:
- /** Destructor.
-
- If the file is open, it is closed first.
- */
- ~value_type() = default;
-
- /// Constructor
- value_type() = default;
-
- /// Constructor
- value_type(value_type&& other) = default;
-
- /// Move assignment
- value_type& operator=(value_type&& other) = default;
-
- /// Returns `true` if the file is open
- bool
- is_open() const
- {
- return file_.is_open();
- }
-
- /// Returns the size of the file if open
- std::uint64_t
- size() const
- {
- return file_size_;
- }
-
- /// Close the file if open
- void
- close();
-
- /** Open a file at the given path with the specified mode
-
- @param path The utf-8 encoded path to the file
-
- @param mode The file mode to use
-
- @param ec Set to the error, if any occurred
- */
- void
- open(char const* path, file_mode mode, error_code& ec);
-
- /** Set the open file
-
- This function is used to set the open
- */
- void
- reset(File&& file, error_code& ec);
-};
-
-template
-void
-basic_file_body::
-value_type::
-close()
-{
- error_code ignored;
- file_.close(ignored);
-}
-
-template
-void
-basic_file_body::
-value_type::
-open(char const* path, file_mode mode, error_code& ec)
-{
- // Open the file
- file_.open(path, mode, ec);
- if(ec)
- return;
-
- // Cache the size
- file_size_ = file_.size(ec);
- if(ec)
- {
- close();
- return;
- }
-}
-
-template
-void
-basic_file_body::
-value_type::
-reset(File&& file, error_code& ec)
-{
- // First close the file if open
- if(file_.is_open())
- {
- error_code ignored;
- file_.close(ignored);
- }
-
- // Take ownership of the new file
- file_ = std::move(file);
-
- // Cache the size
- file_size_ = file_.size(ec);
-}
-
-// This is called from message::payload_size
-template
-std::uint64_t
-basic_file_body::
-size(value_type const& v)
-{
- // Forward the call to the body
- return v.size();
-}
-
-//]
-
-//[example_http_file_body_3
-
-template
-class basic_file_body::reader
-{
- value_type& body_; // The body we are reading from
- 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.
- //
- // Note that the message is passed by non-const reference.
- // This is intentional, because reading from the file
- // changes its "current position" which counts makes the
- // operation logically not-const (although it is bitwise
- // const).
- //
- // The BodyReader concept allows the reader to choose
- // whether to take the message by const reference or
- // non-const reference. Depending on the choice, a
- // serializer constructed using that body type will
- // require the same const or non-const reference to
- // construct.
- //
- // Readers which accept const messages usually allow
- // the same body to be serialized by multiple threads
- // concurrently, while readers accepting non-const
- // messages may only be serialized by one thread at
- // a time.
- //
- template
- reader(message<
- isRequest, basic_file_body, Fields>& m);
-
- // Initializer
- //
- // This is called before the body is serialized and
- // gives the reader a chance to do something that might
- // need to return an error code.
- //
- void
- init(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(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
-template
-basic_file_body::
-reader::
-reader(message& m)
- : body_(m.body)
-{
- // The file must already be open
- BOOST_ASSERT(body_.file_.is_open());
-
- // Get the size of the file
- remain_ = body_.file_size_;
-}
-
-// Initializer
-template
-void
-basic_file_body::
-reader::
-init(error_code& ec)
-{
- // The error_code specification requires that we
- // either set the error to some value, or set it
- // to indicate no error.
- //
- // We don't do anything fancy so set "no error"
- ec.assign(0, ec.category());
-}
-
-// 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.
-//
-template
-auto
-basic_file_body::
-reader::
-get(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_);
-
- // Handle the case where the file is zero length
- if(amount == 0)
- {
- // Modify the error code to indicate success
- // This is required by the error_code specification.
- //
- // NOTE We use the existing category instead of calling
- // into the library to get the generic category because
- // that saves us a possibly expensive atomic operation.
- //
- ec.assign(0, ec.category());
- return boost::none;
- }
-
- // Now read the next buffer
- auto const nread = body_.file_.read(buf_, amount, ec);
- if(ec)
- 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.assign(0, ec.category());
- return {{
- const_buffers_type{buf_, nread}, // buffer to return.
- remain_ > 0 // `true` if there are more buffers.
- }};
-}
-
-//]
-
-//[example_http_file_body_5
-
-template
-class basic_file_body::writer
-{
- value_type& body_; // The body we are writing to
-
-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(
- message& m);
-
- // Initializer
- //
- // This is called before the body is parsed and
- // gives the writer a chance to do something that might
- // need to return an error code. It informs us of
- // the payload size (`content_length`) which we can
- // optionally use for optimization.
- //
- void
- init(boost::optional const&, 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,
- 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(error_code& ec);
-};
-
-//]
-
-//[example_http_file_body_6
-
-// We don't do much in the writer constructor since the
-// file is already open.
-//
-template
-template
-basic_file_body::
-writer::
-writer(message& m)
- : body_(m.body)
-{
-}
-
-template
-void
-basic_file_body::
-writer::
-init(
- boost::optional const& content_length,
- error_code& ec)
-{
- // The file must already be open for writing
- BOOST_ASSERT(body_.file_.is_open());
-
- // 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 error_code specification requires that we
- // either set the error to some value, or set it
- // to indicate no error.
- //
- // We don't do anything fancy so set "no error"
- ec.assign(0, ec.category());
-}
-
-// This will get called one or more times with body buffers
-//
-template
-template
-std::size_t
-basic_file_body::
-writer::
-put(ConstBufferSequence const& buffers, error_code& ec)
-{
- // This function must return the total number of
- // bytes transferred from the input buffers.
- std::size_t nwritten = 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
- nwritten += body_.file_.write(
- boost::asio::buffer_cast(buffer),
- boost::asio::buffer_size(buffer),
- ec);
- if(ec)
- return nwritten;
- }
-
- // Indicate success
- // This is required by the error_code specification
- ec.assign(0, ec.category());
-
- return nwritten;
-}
-
-// Called after writing is done when there's no error.
-template
-void
-basic_file_body::
-writer::
-finish(error_code& ec)
-{
- // This has to be cleared before returning, to
- // indicate no error. The specification requires it.
- ec.assign(0, ec.category());
-}
-
-//]
-
/// A message body represented by a file on the filesystem.
using file_body = basic_file_body;
-#if ! BEAST_DOXYGEN
-// operator<< is not supported for file_body
-template
-std::ostream&
-operator<<(std::ostream& os, message<
- isRequest, basic_file_body, Fields> const& msg) = delete;
-#endif
-
} // http
} // beast
diff --git a/test/http/CMakeLists.txt b/test/http/CMakeLists.txt
index b74e0eb6..74628edb 100644
--- a/test/http/CMakeLists.txt
+++ b/test/http/CMakeLists.txt
@@ -14,6 +14,7 @@ add_executable (http-tests
test_parser.hpp
../../extras/beast/unit_test/main.cpp
basic_dynamic_body.cpp
+ basic_file_body.cpp
basic_parser.cpp
buffer_body.cpp
doc_examples.cpp
diff --git a/test/http/Jamfile b/test/http/Jamfile
index 2145d832..4c99df1c 100644
--- a/test/http/Jamfile
+++ b/test/http/Jamfile
@@ -8,6 +8,7 @@
unit-test http-tests :
../../extras/beast/unit_test/main.cpp
basic_dynamic_body.cpp
+ basic_file_body.cpp
basic_parser.cpp
buffer_body.cpp
doc_examples.cpp
diff --git a/test/http/basic_file_body.cpp b/test/http/basic_file_body.cpp
new file mode 100644
index 00000000..c6047ffa
--- /dev/null
+++ b/test/http/basic_file_body.cpp
@@ -0,0 +1,9 @@
+//
+// 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