mirror of
https://github.com/boostorg/beast.git
synced 2025-08-03 14:54:32 +02:00
Use static_string for WebSocket handshakes:
fix #328 This replaces usages of std::string with static_string when performing WebSocket handshakes.
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
* Refactor static_string
|
* Refactor static_string
|
||||||
* Refactor base64
|
* Refactor base64
|
||||||
|
* Use static_string for WebSocket handshakes
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@@ -8,8 +8,10 @@
|
|||||||
#ifndef BEAST_WEBSOCKET_DETAIL_HYBI13_HPP
|
#ifndef BEAST_WEBSOCKET_DETAIL_HYBI13_HPP
|
||||||
#define BEAST_WEBSOCKET_DETAIL_HYBI13_HPP
|
#define BEAST_WEBSOCKET_DETAIL_HYBI13_HPP
|
||||||
|
|
||||||
|
#include <beast/core/static_string.hpp>
|
||||||
#include <beast/core/detail/base64.hpp>
|
#include <beast/core/detail/base64.hpp>
|
||||||
#include <beast/core/detail/sha1.hpp>
|
#include <beast/core/detail/sha1.hpp>
|
||||||
|
#include <boost/assert.hpp>
|
||||||
#include <boost/utility/string_ref.hpp>
|
#include <boost/utility/string_ref.hpp>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
@@ -20,11 +22,17 @@ namespace beast {
|
|||||||
namespace websocket {
|
namespace websocket {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
|
using sec_ws_key_type = static_string<
|
||||||
|
beast::detail::base64::encoded_size(16)>;
|
||||||
|
|
||||||
|
using sec_ws_accept_type = static_string<
|
||||||
|
beast::detail::base64::encoded_size(20)>;
|
||||||
|
|
||||||
template<class Gen>
|
template<class Gen>
|
||||||
std::string
|
void
|
||||||
make_sec_ws_key(Gen& g)
|
make_sec_ws_key(sec_ws_key_type& key, Gen& g)
|
||||||
{
|
{
|
||||||
std::array<std::uint8_t, 16> a;
|
char a[16];
|
||||||
for(int i = 0; i < 16; i += 4)
|
for(int i = 0; i < 16; i += 4)
|
||||||
{
|
{
|
||||||
auto const v = g();
|
auto const v = g();
|
||||||
@@ -33,24 +41,27 @@ make_sec_ws_key(Gen& g)
|
|||||||
a[i+2] = (v >> 16) & 0xff;
|
a[i+2] = (v >> 16) & 0xff;
|
||||||
a[i+3] = (v >> 24) & 0xff;
|
a[i+3] = (v >> 24) & 0xff;
|
||||||
}
|
}
|
||||||
return beast::detail::base64_encode(
|
key.resize(key.max_size());
|
||||||
a.data(), a.size());
|
key.resize(beast::detail::base64::encode(
|
||||||
|
key.data(), &a[0], 16));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class = void>
|
template<class = void>
|
||||||
std::string
|
void
|
||||||
make_sec_ws_accept(boost::string_ref const& key)
|
make_sec_ws_accept(sec_ws_accept_type& accept,
|
||||||
|
boost::string_ref key)
|
||||||
{
|
{
|
||||||
std::string s(key.data(), key.size());
|
BOOST_ASSERT(key.size() <= sec_ws_key_type::max_size_n);
|
||||||
s += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
static_string<sec_ws_key_type::max_size_n + 36> m(key);
|
||||||
|
m.append("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
|
||||||
beast::detail::sha1_context ctx;
|
beast::detail::sha1_context ctx;
|
||||||
beast::detail::init(ctx);
|
beast::detail::init(ctx);
|
||||||
beast::detail::update(ctx, s.data(), s.size());
|
beast::detail::update(ctx, m.data(), m.size());
|
||||||
std::array<std::uint8_t,
|
char digest[beast::detail::sha1_context::digest_size];
|
||||||
beast::detail::sha1_context::digest_size> digest;
|
beast::detail::finish(ctx, &digest[0]);
|
||||||
beast::detail::finish(ctx, digest.data());
|
accept.resize(accept.max_size());
|
||||||
return beast::detail::base64_encode(
|
accept.resize(beast::detail::base64::encode(
|
||||||
digest.data(), digest.size());
|
accept.data(), &digest[0], sizeof(digest)));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // detail
|
} // detail
|
||||||
|
@@ -34,7 +34,7 @@ class stream<NextLayer>::handshake_op
|
|||||||
bool cont;
|
bool cont;
|
||||||
stream<NextLayer>& ws;
|
stream<NextLayer>& ws;
|
||||||
response_type* res_p;
|
response_type* res_p;
|
||||||
std::string key;
|
detail::sec_ws_key_type key;
|
||||||
request_type req;
|
request_type req;
|
||||||
response_type res;
|
response_type res;
|
||||||
int state = 0;
|
int state = 0;
|
||||||
|
@@ -134,7 +134,7 @@ do_handshake(response_type* res_p,
|
|||||||
{
|
{
|
||||||
response_type res;
|
response_type res;
|
||||||
reset();
|
reset();
|
||||||
std::string key;
|
detail::sec_ws_key_type key;
|
||||||
{
|
{
|
||||||
auto const req = build_request(
|
auto const req = build_request(
|
||||||
key, host, resource, decorator);
|
key, host, resource, decorator);
|
||||||
@@ -155,7 +155,7 @@ template<class NextLayer>
|
|||||||
template<class Decorator>
|
template<class Decorator>
|
||||||
request_type
|
request_type
|
||||||
stream<NextLayer>::
|
stream<NextLayer>::
|
||||||
build_request(std::string& key,
|
build_request(detail::sec_ws_key_type& key,
|
||||||
boost::string_ref const& host,
|
boost::string_ref const& host,
|
||||||
boost::string_ref const& resource,
|
boost::string_ref const& resource,
|
||||||
Decorator const& decorator)
|
Decorator const& decorator)
|
||||||
@@ -167,7 +167,7 @@ build_request(std::string& key,
|
|||||||
req.fields.insert("Host", host);
|
req.fields.insert("Host", host);
|
||||||
req.fields.insert("Upgrade", "websocket");
|
req.fields.insert("Upgrade", "websocket");
|
||||||
req.fields.insert("Connection", "upgrade");
|
req.fields.insert("Connection", "upgrade");
|
||||||
key = detail::make_sec_ws_key(maskgen_);
|
detail::make_sec_ws_key(key, maskgen_);
|
||||||
req.fields.insert("Sec-WebSocket-Key", key);
|
req.fields.insert("Sec-WebSocket-Key", key);
|
||||||
req.fields.insert("Sec-WebSocket-Version", "13");
|
req.fields.insert("Sec-WebSocket-Version", "13");
|
||||||
if(pmd_opts_.client_enable)
|
if(pmd_opts_.client_enable)
|
||||||
@@ -186,6 +186,7 @@ build_request(std::string& key,
|
|||||||
req.fields, config);
|
req.fields, config);
|
||||||
}
|
}
|
||||||
decorator(req);
|
decorator(req);
|
||||||
|
// VFALCO Use static_string here
|
||||||
if(! req.fields.exists("User-Agent"))
|
if(! req.fields.exists("User-Agent"))
|
||||||
req.fields.insert("User-Agent",
|
req.fields.insert("User-Agent",
|
||||||
std::string("Beast/") + BEAST_VERSION_STRING);
|
std::string("Beast/") + BEAST_VERSION_STRING);
|
||||||
@@ -203,6 +204,7 @@ build_response(request_type const& req,
|
|||||||
[&decorator](response_type& res)
|
[&decorator](response_type& res)
|
||||||
{
|
{
|
||||||
decorator(res);
|
decorator(res);
|
||||||
|
// VFALCO Use static_string here
|
||||||
if(! res.fields.exists("Server"))
|
if(! res.fields.exists("Server"))
|
||||||
res.fields.insert("Server",
|
res.fields.insert("Server",
|
||||||
std::string("Beast/") +
|
std::string("Beast/") +
|
||||||
@@ -235,6 +237,9 @@ build_response(request_type const& req,
|
|||||||
return err("Missing Sec-WebSocket-Key");
|
return err("Missing Sec-WebSocket-Key");
|
||||||
if(! http::token_list{req.fields["Upgrade"]}.exists("websocket"))
|
if(! http::token_list{req.fields["Upgrade"]}.exists("websocket"))
|
||||||
return err("Missing websocket Upgrade token");
|
return err("Missing websocket Upgrade token");
|
||||||
|
auto const key = req.fields["Sec-WebSocket-Key"];
|
||||||
|
if(key.size() > detail::sec_ws_key_type::max_size_n)
|
||||||
|
return err("Invalid Sec-WebSocket-Key");
|
||||||
{
|
{
|
||||||
auto const version =
|
auto const version =
|
||||||
req.fields["Sec-WebSocket-Version"];
|
req.fields["Sec-WebSocket-Version"];
|
||||||
@@ -255,6 +260,7 @@ build_response(request_type const& req,
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
response_type res;
|
response_type res;
|
||||||
{
|
{
|
||||||
detail::pmd_offer offer;
|
detail::pmd_offer offer;
|
||||||
@@ -269,10 +275,9 @@ build_response(request_type const& req,
|
|||||||
res.fields.insert("Upgrade", "websocket");
|
res.fields.insert("Upgrade", "websocket");
|
||||||
res.fields.insert("Connection", "upgrade");
|
res.fields.insert("Connection", "upgrade");
|
||||||
{
|
{
|
||||||
auto const key =
|
detail::sec_ws_accept_type accept;
|
||||||
req.fields["Sec-WebSocket-Key"];
|
detail::make_sec_ws_accept(accept, key);
|
||||||
res.fields.insert("Sec-WebSocket-Accept",
|
res.fields.insert("Sec-WebSocket-Accept", accept);
|
||||||
detail::make_sec_ws_accept(key));
|
|
||||||
}
|
}
|
||||||
decorate(res);
|
decorate(res);
|
||||||
return res;
|
return res;
|
||||||
@@ -282,7 +287,7 @@ template<class NextLayer>
|
|||||||
void
|
void
|
||||||
stream<NextLayer>::
|
stream<NextLayer>::
|
||||||
do_response(http::response_header const& res,
|
do_response(http::response_header const& res,
|
||||||
boost::string_ref const& key, error_code& ec)
|
detail::sec_ws_key_type const& key, error_code& ec)
|
||||||
{
|
{
|
||||||
// VFALCO Review these error codes
|
// VFALCO Review these error codes
|
||||||
auto fail = [&]{ ec = error::response_failed; };
|
auto fail = [&]{ ec = error::response_failed; };
|
||||||
@@ -296,8 +301,10 @@ do_response(http::response_header const& res,
|
|||||||
return fail();
|
return fail();
|
||||||
if(! res.fields.exists("Sec-WebSocket-Accept"))
|
if(! res.fields.exists("Sec-WebSocket-Accept"))
|
||||||
return fail();
|
return fail();
|
||||||
if(res.fields["Sec-WebSocket-Accept"] !=
|
detail::sec_ws_accept_type accept;
|
||||||
detail::make_sec_ws_accept(key))
|
detail::make_sec_ws_accept(accept, key);
|
||||||
|
if(accept.compare(
|
||||||
|
res.fields["Sec-WebSocket-Accept"]) != 0)
|
||||||
return fail();
|
return fail();
|
||||||
detail::pmd_offer offer;
|
detail::pmd_offer offer;
|
||||||
pmd_read(offer, res.fields);
|
pmd_read(offer, res.fields);
|
||||||
|
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include <beast/config.hpp>
|
#include <beast/config.hpp>
|
||||||
#include <beast/websocket/option.hpp>
|
#include <beast/websocket/option.hpp>
|
||||||
|
#include <beast/websocket/detail/hybi13.hpp>
|
||||||
#include <beast/websocket/detail/stream_base.hpp>
|
#include <beast/websocket/detail/stream_base.hpp>
|
||||||
#include <beast/http/message.hpp>
|
#include <beast/http/message.hpp>
|
||||||
#include <beast/http/string_body.hpp>
|
#include <beast/http/string_body.hpp>
|
||||||
@@ -2981,7 +2982,7 @@ private:
|
|||||||
|
|
||||||
template<class Decorator>
|
template<class Decorator>
|
||||||
request_type
|
request_type
|
||||||
build_request(std::string& key,
|
build_request(detail::sec_ws_key_type& key,
|
||||||
boost::string_ref const& host,
|
boost::string_ref const& host,
|
||||||
boost::string_ref const& resource,
|
boost::string_ref const& resource,
|
||||||
Decorator const& decorator);
|
Decorator const& decorator);
|
||||||
@@ -2993,7 +2994,7 @@ private:
|
|||||||
|
|
||||||
void
|
void
|
||||||
do_response(http::response_header const& resp,
|
do_response(http::response_header const& resp,
|
||||||
boost::string_ref const& key, error_code& ec);
|
detail::sec_ws_key_type const& key, error_code& ec);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // websocket
|
} // websocket
|
||||||
|
Reference in New Issue
Block a user