From 4b3a21efeca1e564e8238651570bc6898ca8b4b9 Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Wed, 26 Apr 2017 18:20:59 -0700 Subject: [PATCH] Add is_upgrade() free function: fix #195 This function returns `true` when the passed HTTP Request indicates a WebSocket Upgrade. It does not validate the contents of the fields: it just trivially accepts requests which can only be a WebSocket Upgrade message. Callers who wish to manually read HTTP requests in their server implementation can use this function to determine if the request should be routed to an instance of websocket::stream. --- CHANGELOG.md | 4 +++ doc/quickref.xml | 1 + include/beast/websocket/impl/rfc6455.ipp | 36 +++++++++++++++++++++ include/beast/websocket/rfc6455.hpp | 25 ++++++++++++++- test/websocket/rfc6455.cpp | 40 ++++++++++++++++++++++++ 5 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 include/beast/websocket/impl/rfc6455.ipp diff --git a/CHANGELOG.md b/CHANGELOG.md index 40698038..72e922bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ * CMake hide command lines in .vcxproj Output windows" +WebSocket: + +* Add is_upgrade() free function + API Changes: * Provide websocket::stream accept() overloads diff --git a/doc/quickref.xml b/doc/quickref.xml index a1afe585..f623a339 100644 --- a/doc/quickref.xml +++ b/doc/quickref.xml @@ -107,6 +107,7 @@ Functions async_teardown + is_upgrade teardown Options diff --git a/include/beast/websocket/impl/rfc6455.ipp b/include/beast/websocket/impl/rfc6455.ipp new file mode 100644 index 00000000..684112bb --- /dev/null +++ b/include/beast/websocket/impl/rfc6455.ipp @@ -0,0 +1,36 @@ +// +// 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_WEBSOCKET_IMPL_RFC6455_IPP +#define BEAST_WEBSOCKET_IMPL_RFC6455_IPP + +#include + +namespace beast { +namespace websocket { + +template +bool +is_upgrade(http::header const& req) +{ + if(req.version < 11) + return false; + if(req.method != "GET") + return false; + if(! http::is_upgrade(req)) + return false; + if(! http::token_list{req.fields["Upgrade"]}.exists("websocket")) + return false; + if(! req.fields.exists("Sec-WebSocket-Version")) + return false; + return true; +} + +} // websocket +} // beast + +#endif diff --git a/include/beast/websocket/rfc6455.hpp b/include/beast/websocket/rfc6455.hpp index 6051ebff..6813ed3f 100644 --- a/include/beast/websocket/rfc6455.hpp +++ b/include/beast/websocket/rfc6455.hpp @@ -10,13 +10,34 @@ #include #include -#include +#include #include #include namespace beast { namespace websocket { +/** Returns `true` if the specified HTTP request is a WebSocket Upgrade. + + This function returns `true` when the passed HTTP Request + indicates a WebSocket Upgrade. It does not validate the + contents of the fields: it just trivially accepts requests + which could only possibly be a valid or invalid WebSocket + Upgrade message. + + Callers who wish to manually read HTTP requests in their + server implementation can use this function to determine if + the request should be routed to an instance of + @ref websocket::stream. + + @param req The HTTP Request object to check. + + @return `true` if the request is a WebSocket Upgrade. +*/ +template +bool +is_upgrade(beast::http::header const& req); + /** WebSocket frame header opcodes. */ enum class opcode : std::uint8_t { @@ -186,4 +207,6 @@ struct close_reason } // websocket } // beast +#include + #endif diff --git a/test/websocket/rfc6455.cpp b/test/websocket/rfc6455.cpp index c34daf31..080b5f43 100644 --- a/test/websocket/rfc6455.cpp +++ b/test/websocket/rfc6455.cpp @@ -7,3 +7,43 @@ // Test that header file is self-contained. #include + +#include + +namespace beast { +namespace websocket { + +class rfc6455_test + : public beast::unit_test::suite +{ +public: + void + test_is_upgrade() + { + http::request_header req; + req.version = 10; + BEAST_EXPECT(! is_upgrade(req)); + req.version = 11; + req.method = "POST"; + req.url = "/"; + BEAST_EXPECT(! is_upgrade(req)); + req.method = "GET"; + req.fields.insert("Connection", "upgrade"); + BEAST_EXPECT(! is_upgrade(req)); + req.fields.insert("Upgrade", "websocket"); + BEAST_EXPECT(! is_upgrade(req)); + req.fields.insert("Sec-WebSocket-Version", "13"); + BEAST_EXPECT(is_upgrade(req)); + } + + void + run() override + { + test_is_upgrade(); + } +}; + +BEAST_DEFINE_TESTSUITE(rfc6455,websocket,beast); + +} // websocket +} // beast