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); } };