diff --git a/CHANGELOG.md b/CHANGELOG.md index ac15d75b..e623521e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ * Add missing rebind to handler_alloc * Fix error handling in http server examples * Fix CMake scripts for MinGW +* Better WebSocket decorator -------------------------------------------------------------------------------- diff --git a/include/beast/websocket/detail/decorator.hpp b/include/beast/websocket/detail/decorator.hpp index c0492477..4bf1a54a 100644 --- a/include/beast/websocket/detail/decorator.hpp +++ b/include/beast/websocket/detail/decorator.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include namespace beast { @@ -40,6 +41,32 @@ class decorator : public abstract_decorator { T t_; + class call_req_possible + { + template().operator()( + std::declval()), + std::true_type{})> + static R check(int); + template + static std::false_type check(...); + public: + using type = decltype(check(0)); + }; + + class call_res_possible + { + template().operator()( + std::declval()), + std::true_type{})> + static R check(int); + template + static std::false_type check(...); + public: + using type = decltype(check(0)); + }; + public: decorator() = default; @@ -56,38 +83,45 @@ public: void operator()(request_type& req) override { - t_(req); + (*this)(req, typename call_req_possible::type{}); } void operator()(response_type& resp) override { - t_(resp); + (*this)(resp, typename call_res_possible::type{}); + } + +private: + void + operator()(request_type& req, std::true_type) + { + t_(req); + } + + void + operator()(request_type& req, std::false_type) + { + req.headers.replace("User-Agent", + std::string{"Beast/"} + BEAST_VERSION_STRING); + } + + void + operator()(response_type& res, std::true_type) + { + t_(res); + } + + void + operator()(response_type& res, std::false_type) + { + res.headers.replace("Server", + std::string{"Beast/"} + BEAST_VERSION_STRING); } }; struct default_decorator { - static - char const* - version() - { - return "Beast.WSProto/1.0"; - } - - template - void - operator()(http::message& req) - { - req.headers.replace("User-Agent", version()); - } - - template - void - operator()(http::message& resp) - { - resp.headers.replace("Server", version()); - } }; using decorator_type = diff --git a/include/beast/websocket/stream.hpp b/include/beast/websocket/stream.hpp index dcc5f75d..b3dee5d7 100644 --- a/include/beast/websocket/stream.hpp +++ b/include/beast/websocket/stream.hpp @@ -177,9 +177,29 @@ public: wr_frag_size_ = o.value; } - /// Set the decorator used for HTTP messages + /** Set the decorator used for HTTP messages. + + The value for this option is a callable type with two + optional signatures: + + @code + void(request_type&); + + void(response_type&); + @endcode + + If a matching signature is provided, the callable type + will be invoked with the HTTP request or HTTP response + object as appropriate. When a signature is omitted, + a default consisting of the string Beast followed by + the version number is used. + */ void +#if GENERATING_DOCS + set_option(implementation_defined o) +#else set_option(detail::decorator_type o) +#endif { d_ = std::move(o); }