diff --git a/doc/quickref.xml b/doc/quickref.xml
index 2aa0bcea..8aec0524 100644
--- a/doc/quickref.xml
+++ b/doc/quickref.xml
@@ -41,7 +41,10 @@
Type Traits
+ is_Body
is_Parser
+ is_ReadableBody
+ is_WritableBody
diff --git a/doc/types/Field.qbk b/doc/types/Field.qbk
index a83309a1..e5d8b22c 100644
--- a/doc/types/Field.qbk
+++ b/doc/types/Field.qbk
@@ -22,7 +22,7 @@ In this table:
[`boost::string_ref`]
[
This function returns a value implicitly convertible to
- `boost::string_ref` containing the case-insensitve field
+ `boost::string_ref` containing the case-insensitive field
name, without leading or trailing white space.
]
]
diff --git a/doc/types/Parser.qbk b/doc/types/Parser.qbk
index fa2b1e9e..0690f23f 100644
--- a/doc/types/Parser.qbk
+++ b/doc/types/Parser.qbk
@@ -38,7 +38,7 @@ In this table:
an error occurs, the end of the buffer is reached, or a complete
HTTP/1 message has been parsed. If an error occurs, `ec` is set
to the error code and parsing stops. This function returns the
- number of bytes consumed in the input buffer.
+ number of bytes consumed from the input buffer.
]
]
[
diff --git a/include/beast/http/concepts.hpp b/include/beast/http/concepts.hpp
new file mode 100644
index 00000000..d8641050
--- /dev/null
+++ b/include/beast/http/concepts.hpp
@@ -0,0 +1,156 @@
+//
+// Copyright (c) 2013-2016 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_TYPE_CHECK_HPP
+#define BEAST_HTTP_TYPE_CHECK_HPP
+
+#include
+#include
+#include
+#include
+
+namespace beast {
+namespace http {
+
+namespace detail {
+
+template
+class has_value_type
+{
+ template
+ static std::true_type check(int);
+ template
+ static std::false_type check(...);
+ using type = decltype(check(0));
+public:
+ static bool constexpr value = type::value;
+};
+
+template::value>
+struct extract_value_type
+{
+ using type = void;
+};
+
+template
+struct extract_value_type
+{
+ using type = typename T::value_type;
+};
+
+template
+class has_reader
+{
+ template
+ static std::true_type check(int);
+ template
+ static std::false_type check(...);
+public:
+ using type = decltype(check(0));
+};
+
+template
+class has_writer
+{
+ template
+ static std::true_type check(int);
+ template
+ static std::false_type check(...);
+public:
+ using type = decltype(check(0));
+};
+
+template
+struct is_Body
+{
+ using type = std::integral_constant::value &&
+ std::is_default_constructible<
+ typename extract_value_type::type>::value
+ >;
+};
+
+template
+class is_Parser
+{
+ template().complete()),
+ bool>>
+ static R check1(int);
+ template
+ static std::false_type check1(...);
+ using type1 = decltype(check1(0));
+
+ template().write(
+ std::declval(),
+ std::declval())),
+ std::size_t>>
+ static R check2(int);
+ template
+ static std::false_type check2(...);
+ using type2 = decltype(check2(0));
+
+ template().write_eof(std::declval()),
+ std::true_type{})>
+ static R check3(int);
+ template
+ static std::false_type check3(...);
+ using type3 = decltype(check3(0));
+
+public:
+ using type = std::integral_constant;
+};
+
+} // detail
+
+/// Determine if `T` meets the requirements of `Body`.
+template
+#if GENERATING_DOCS
+struct is_Body : std::integral_constant{};
+#else
+using is_Body = typename detail::is_Body::type;
+#endif
+
+/// Determine if `T` meets the requirements of `ReadableBody`.
+template
+#if GENERATING_DOCS
+struct is_ReadableBody : std::integral_constant{};
+#else
+using is_ReadableBody = typename detail::has_reader::type;
+#endif
+
+/// Determine if `T` meets the requirements of `WritableBody`.
+template
+#if GENERATING_DOCS
+struct is_WritableBody : std::integral_constant{};
+#else
+using is_WritableBody = typename detail::has_writer::type;
+#endif
+
+/// Determine if `T` meets the requirements of `Parser`.
+template
+#if GENERATING_DOCS
+struct is_Parser : std::integral_constant{};
+#else
+using is_Parser = typename detail::is_Parser::type;
+#endif
+
+} // http
+} // beast
+
+#endif
diff --git a/include/beast/http/empty_body.hpp b/include/beast/http/empty_body.hpp
index 885a5605..8eb44064 100644
--- a/include/beast/http/empty_body.hpp
+++ b/include/beast/http/empty_body.hpp
@@ -34,20 +34,6 @@ struct empty_body
private:
#endif
- struct reader
- {
- template
- explicit
- reader(message&)
- {
- }
-
- void
- write(void const*, std::size_t, error_code&)
- {
- }
- };
-
struct writer
{
writer(writer const&) = delete;
diff --git a/include/beast/http/impl/read.ipp b/include/beast/http/impl/read.ipp
index 87c0af4c..0d22a4b5 100644
--- a/include/beast/http/impl/read.ipp
+++ b/include/beast/http/impl/read.ipp
@@ -8,8 +8,8 @@
#ifndef BEAST_HTTP_IMPL_READ_IPP_HPP
#define BEAST_HTTP_IMPL_READ_IPP_HPP
+#include
#include
-#include
#include
#include
#include
@@ -323,6 +323,12 @@ void
parse(SyncReadStream& stream,
Streambuf& streambuf, Parser& parser)
{
+ static_assert(is_SyncReadStream::value,
+ "SyncReadStream requirements not met");
+ static_assert(is_Streambuf::value,
+ "Streambuf requirements not met");
+ static_assert(is_Parser::value,
+ "Parser requirements not met");
error_code ec;
parse(stream, streambuf, parser, ec);
if(ec)
@@ -403,6 +409,8 @@ read(SyncReadStream& stream, Streambuf& streambuf,
"SyncReadStream requirements not met");
static_assert(is_Streambuf::value,
"Streambuf requirements not met");
+ static_assert(is_ReadableBody::value,
+ "ReadableBody requirements not met");
error_code ec;
read(stream, streambuf, msg, ec);
if(ec)
@@ -420,6 +428,8 @@ read(SyncReadStream& stream, Streambuf& streambuf,
"SyncReadStream requirements not met");
static_assert(is_Streambuf::value,
"Streambuf requirements not met");
+ static_assert(is_ReadableBody::value,
+ "ReadableBody requirements not met");
parser_v1 p;
parse(stream, streambuf, p, ec);
if(ec)
@@ -441,6 +451,8 @@ async_read(AsyncReadStream& stream, Streambuf& streambuf,
"AsyncReadStream requirements not met");
static_assert(is_Streambuf::value,
"Streambuf requirements not met");
+ static_assert(is_ReadableBody::value,
+ "ReadableBody requirements not met");
beast::async_completion completion(handler);
detail::read_op
#include
#include
#include
@@ -448,6 +449,8 @@ write(SyncWriteStream& stream,
{
static_assert(is_SyncWriteStream::value,
"SyncWriteStream requirements not met");
+ static_assert(is_WritableBody::value,
+ "WritableBody requirements not met");
error_code ec;
write(stream, msg, ec);
if(ec)
@@ -463,6 +466,8 @@ write(SyncWriteStream& stream,
{
static_assert(is_SyncWriteStream::value,
"SyncWriteStream requirements not met");
+ static_assert(is_WritableBody::value,
+ "WritableBody requirements not met");
detail::write_preparation wp(msg);
wp.init(ec);
if(ec)
@@ -546,6 +551,8 @@ async_write(AsyncWriteStream& stream,
static_assert(
is_AsyncWriteStream::value,
"AsyncWriteStream requirements not met");
+ static_assert(is_WritableBody::value,
+ "WritableBody requirements not met");
beast::async_completion completion(handler);
detail::write_op const& msg)
{
+ static_assert(is_WritableBody::value,
+ "WritableBody requirements not met");
detail::ostream_SyncStream oss(os);
error_code ec;
write(oss, msg, ec);
diff --git a/include/beast/http/parser_v1.hpp b/include/beast/http/parser_v1.hpp
index 8831297a..46f8dee8 100644
--- a/include/beast/http/parser_v1.hpp
+++ b/include/beast/http/parser_v1.hpp
@@ -9,6 +9,7 @@
#define BEAST_HTTP_PARSER_V1_HPP
#include
+#include
#include
#include
#include
@@ -54,6 +55,9 @@ public:
message_v1;
private:
+ static_assert(is_ReadableBody::value,
+ "ReadableBody requirements not met");
+
std::string field_;
std::string value_;
message_type m_;
diff --git a/include/beast/http/type_check.hpp b/include/beast/http/type_check.hpp
deleted file mode 100644
index 180e1b7d..00000000
--- a/include/beast/http/type_check.hpp
+++ /dev/null
@@ -1,60 +0,0 @@
-//
-// Copyright (c) 2013-2016 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_TYPE_CHECK_HPP
-#define BEAST_HTTP_TYPE_CHECK_HPP
-
-#include
-#include
-#include
-#include
-
-namespace beast {
-namespace http {
-
-/// Determine if `T` meets the requirements of `Parser`.
-template
-class is_Parser
-{
- template().complete()),
- bool>>
- static R check1(int);
- template
- static std::false_type check1(...);
- using type1 = decltype(check1(0));
-
- template().write(
- std::declval(),
- std::declval())),
- std::size_t>>
- static R check2(int);
- template
- static std::false_type check2(...);
- using type2 = decltype(check2(0));
-
- template().write_eof(std::declval()),
- std::true_type{})>
- static R check3(int);
- template
- static std::false_type check3(...);
- using type3 = decltype(check3(0));
-
-public:
- /// `true` if `T` meets the requirements.
- static bool const value =
- type1::value && type2::value && type3::value;
-};
-
-} // http
-} // beast
-
-#endif
diff --git a/include/beast/websocket/impl/accept_op.ipp b/include/beast/websocket/impl/accept_op.ipp
index e575f2f8..bc94ac35 100644
--- a/include/beast/websocket/impl/accept_op.ipp
+++ b/include/beast/websocket/impl/accept_op.ipp
@@ -33,7 +33,7 @@ class stream::accept_op
struct data
{
stream& ws;
- http::request_v1 req;
+ http::request_v1 req;
Handler h;
bool cont;
int state = 0;
diff --git a/include/beast/websocket/impl/stream.ipp b/include/beast/websocket/impl/stream.ipp
index d914542a..569f43b6 100644
--- a/include/beast/websocket/impl/stream.ipp
+++ b/include/beast/websocket/impl/stream.ipp
@@ -253,7 +253,7 @@ accept(ConstBufferSequence const& buffers, error_code& ec)
stream_.buffer().commit(buffer_copy(
stream_.buffer().prepare(
buffer_size(buffers)), buffers));
- http::request_v1 m;
+ http::request_v1 m;
http::read(next_layer(), stream_.buffer(), m, ec);
if(ec)
return;
diff --git a/test/Jamfile b/test/Jamfile
index a5821367..02fb70a1 100644
--- a/test/Jamfile
+++ b/test/Jamfile
@@ -44,6 +44,7 @@ unit-test http-tests :
http/basic_headers.cpp
http/basic_parser_v1.cpp
http/body_type.cpp
+ http/concepts.cpp
http/empty_body.cpp
http/headers.cpp
http/message.cpp
@@ -58,7 +59,6 @@ unit-test http-tests :
http/status.cpp
http/streambuf_body.cpp
http/string_body.cpp
- http/type_check.cpp
http/write.cpp
http/detail/chunk_encode.cpp
;
diff --git a/test/core/buffer_cat.cpp b/test/core/buffer_cat.cpp
index c943e416..c78f75c6 100644
--- a/test/core/buffer_cat.cpp
+++ b/test/core/buffer_cat.cpp
@@ -66,6 +66,14 @@ public:
expect(buffer_size(buffer_cat(
sb1.data(), sb2.data())) == 12);
}
+ for(auto it = bs.begin(); it != bs.end(); ++it)
+ {
+ decltype(bs)::const_iterator copy;
+ copy = it;
+ expect(copy == it);
+ copy = copy;
+ expect(copy == it);
+ }
}
void testIterators()
diff --git a/test/http/CMakeLists.txt b/test/http/CMakeLists.txt
index f3959b5b..6b2b8c37 100644
--- a/test/http/CMakeLists.txt
+++ b/test/http/CMakeLists.txt
@@ -10,6 +10,7 @@ add_executable (http-tests
basic_headers.cpp
basic_parser_v1.cpp
body_type.cpp
+ concepts.cpp
empty_body.cpp
headers.cpp
message.cpp
@@ -24,7 +25,6 @@ add_executable (http-tests
status.cpp
streambuf_body.cpp
string_body.cpp
- type_check.cpp
write.cpp
detail/chunk_encode.cpp
)
diff --git a/test/http/type_check.cpp b/test/http/concepts.cpp
similarity index 88%
rename from test/http/type_check.cpp
rename to test/http/concepts.cpp
index 82020206..e540397b 100644
--- a/test/http/type_check.cpp
+++ b/test/http/concepts.cpp
@@ -6,4 +6,4 @@
//
// Test that header file is self-contained.
-#include
+#include
diff --git a/test/http/streambuf_body.cpp b/test/http/streambuf_body.cpp
index a036af6b..33ac29b7 100644
--- a/test/http/streambuf_body.cpp
+++ b/test/http/streambuf_body.cpp
@@ -12,8 +12,10 @@
#include
#include
#include
+#include
#include
#include
+#include
namespace beast {
namespace http {
@@ -25,16 +27,18 @@ class streambuf_body_test : public beast::unit_test::suite
public:
void run() override
{
- test::string_stream ss(ios_,
+ std::string const s =
"HTTP/1.1 200 OK\r\n"
"Server: test\r\n"
"Content-Length: 3\r\n"
"\r\n"
- "xyz");
+ "xyz";
+ test::string_stream ss(ios_, s);
parser_v1 p;
streambuf sb;
parse(ss, sb, p);
expect(to_string(p.get().body.data()) == "xyz");
+ expect(boost::lexical_cast(p.get()) == s);
}
};