mirror of
https://github.com/boostorg/beast.git
synced 2025-08-02 14:24:31 +02:00
Enable more split compilation in websocket and http
Signed-off-by: Damian Jarek <damian.jarek93@gmail.com>
This commit is contained in:
committed by
Vinnie Falco
parent
d2041c0322
commit
dc52df351a
@@ -86,12 +86,12 @@ private:
|
|||||||
increment();
|
increment();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class = void>
|
BOOST_BEAST_DECL
|
||||||
static
|
static
|
||||||
std::string
|
std::string
|
||||||
unquote(string_view sr);
|
unquote(string_view sr);
|
||||||
|
|
||||||
template<class = void>
|
BOOST_BEAST_DECL
|
||||||
void
|
void
|
||||||
increment();
|
increment();
|
||||||
};
|
};
|
||||||
@@ -132,46 +132,6 @@ cend() const ->
|
|||||||
return const_iterator{s_.end(), s_.end()};
|
return const_iterator{s_.end(), s_.end()};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class>
|
|
||||||
std::string
|
|
||||||
param_list::const_iterator::
|
|
||||||
unquote(string_view sr)
|
|
||||||
{
|
|
||||||
std::string s;
|
|
||||||
s.reserve(sr.size());
|
|
||||||
auto it = sr.begin() + 1;
|
|
||||||
auto end = sr.end() - 1;
|
|
||||||
while(it != end)
|
|
||||||
{
|
|
||||||
if(*it == '\\')
|
|
||||||
++it;
|
|
||||||
s.push_back(*it);
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class>
|
|
||||||
void
|
|
||||||
param_list::const_iterator::
|
|
||||||
increment()
|
|
||||||
{
|
|
||||||
s_.clear();
|
|
||||||
pi_.increment();
|
|
||||||
if(pi_.empty())
|
|
||||||
{
|
|
||||||
pi_.it = pi_.last;
|
|
||||||
pi_.first = pi_.last;
|
|
||||||
}
|
|
||||||
else if(! pi_.v.second.empty() &&
|
|
||||||
pi_.v.second.front() == '"')
|
|
||||||
{
|
|
||||||
s_ = unquote(pi_.v.second);
|
|
||||||
pi_.v.second = string_view{
|
|
||||||
s_.data(), s_.size()};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
class ext_list::const_iterator
|
class ext_list::const_iterator
|
||||||
@@ -243,7 +203,7 @@ private:
|
|||||||
increment();
|
increment();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class = void>
|
BOOST_BEAST_DECL
|
||||||
void
|
void
|
||||||
increment();
|
increment();
|
||||||
};
|
};
|
||||||
@@ -305,74 +265,6 @@ exists(T const& s)
|
|||||||
return find(s) != end();
|
return find(s) != end();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class>
|
|
||||||
void
|
|
||||||
ext_list::const_iterator::
|
|
||||||
increment()
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
ext-list = *( "," OWS ) ext *( OWS "," [ OWS ext ] )
|
|
||||||
ext = token param-list
|
|
||||||
param-list = *( OWS ";" OWS param )
|
|
||||||
param = token OWS "=" OWS ( token / quoted-string )
|
|
||||||
|
|
||||||
chunked;a=b;i=j;gzip;windowBits=12
|
|
||||||
x,y
|
|
||||||
,,,,,chameleon
|
|
||||||
*/
|
|
||||||
auto const err =
|
|
||||||
[&]
|
|
||||||
{
|
|
||||||
it_ = last_;
|
|
||||||
first_ = last_;
|
|
||||||
};
|
|
||||||
auto need_comma = it_ != first_;
|
|
||||||
v_.first = {};
|
|
||||||
first_ = it_;
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
detail::skip_ows(it_, last_);
|
|
||||||
if(it_ == last_)
|
|
||||||
return err();
|
|
||||||
auto const c = *it_;
|
|
||||||
if(detail::is_token_char(c))
|
|
||||||
{
|
|
||||||
if(need_comma)
|
|
||||||
return err();
|
|
||||||
auto const p0 = it_;
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
++it_;
|
|
||||||
if(it_ == last_)
|
|
||||||
break;
|
|
||||||
if(! detail::is_token_char(*it_))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
v_.first = string_view{&*p0,
|
|
||||||
static_cast<std::size_t>(it_ - p0)};
|
|
||||||
if (it_ == last_)
|
|
||||||
return;
|
|
||||||
detail::param_iter pi;
|
|
||||||
pi.it = it_;
|
|
||||||
pi.first = it_;
|
|
||||||
pi.last = last_;
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
pi.increment();
|
|
||||||
if(pi.empty())
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
v_.second = param_list{string_view{&*it_,
|
|
||||||
static_cast<std::size_t>(pi.it - it_)}};
|
|
||||||
it_ = pi.it;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(c != ',')
|
|
||||||
return err();
|
|
||||||
need_comma = false;
|
|
||||||
++it_;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -445,7 +337,7 @@ private:
|
|||||||
increment();
|
increment();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class = void>
|
BOOST_BEAST_DECL
|
||||||
void
|
void
|
||||||
increment();
|
increment();
|
||||||
};
|
};
|
||||||
@@ -486,53 +378,6 @@ cend() const ->
|
|||||||
return const_iterator{s_.end(), s_.end()};
|
return const_iterator{s_.end(), s_.end()};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class>
|
|
||||||
void
|
|
||||||
token_list::const_iterator::
|
|
||||||
increment()
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
token-list = *( "," OWS ) token *( OWS "," [ OWS ext ] )
|
|
||||||
*/
|
|
||||||
auto const err =
|
|
||||||
[&]
|
|
||||||
{
|
|
||||||
it_ = last_;
|
|
||||||
first_ = last_;
|
|
||||||
};
|
|
||||||
auto need_comma = it_ != first_;
|
|
||||||
v_ = {};
|
|
||||||
first_ = it_;
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
detail::skip_ows(it_, last_);
|
|
||||||
if(it_ == last_)
|
|
||||||
return err();
|
|
||||||
auto const c = *it_;
|
|
||||||
if(detail::is_token_char(c))
|
|
||||||
{
|
|
||||||
if(need_comma)
|
|
||||||
return err();
|
|
||||||
auto const p0 = it_;
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
++it_;
|
|
||||||
if(it_ == last_)
|
|
||||||
break;
|
|
||||||
if(! detail::is_token_char(*it_))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
v_ = string_view{&*p0,
|
|
||||||
static_cast<std::size_t>(it_ - p0)};
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(c != ',')
|
|
||||||
return err();
|
|
||||||
need_comma = false;
|
|
||||||
++it_;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
bool
|
bool
|
||||||
token_list::
|
token_list::
|
||||||
@@ -570,5 +415,9 @@ validate_list(detail::basic_parsed_list<
|
|||||||
} // beast
|
} // beast
|
||||||
} // boost
|
} // boost
|
||||||
|
|
||||||
|
#ifdef BOOST_BEAST_HEADER_ONLY
|
||||||
|
#include <boost/beast/http/impl/rfc7230.ipp>
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
176
include/boost/beast/http/impl/rfc7230.ipp
Normal file
176
include/boost/beast/http/impl/rfc7230.ipp
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2016-2019 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)
|
||||||
|
//
|
||||||
|
// Official repository: https://github.com/boostorg/beast
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef BOOST_BEAST_HTTP_IMPL_RFC7230_IPP
|
||||||
|
#define BOOST_BEAST_HTTP_IMPL_RFC7230_IPP
|
||||||
|
|
||||||
|
#include <boost/beast/http/rfc7230.hpp>
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
|
||||||
|
|
||||||
|
std::string
|
||||||
|
param_list::const_iterator::
|
||||||
|
unquote(string_view sr)
|
||||||
|
{
|
||||||
|
std::string s;
|
||||||
|
s.reserve(sr.size());
|
||||||
|
auto it = sr.begin() + 1;
|
||||||
|
auto end = sr.end() - 1;
|
||||||
|
while(it != end)
|
||||||
|
{
|
||||||
|
if(*it == '\\')
|
||||||
|
++it;
|
||||||
|
s.push_back(*it);
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
param_list::const_iterator::
|
||||||
|
increment()
|
||||||
|
{
|
||||||
|
s_.clear();
|
||||||
|
pi_.increment();
|
||||||
|
if(pi_.empty())
|
||||||
|
{
|
||||||
|
pi_.it = pi_.last;
|
||||||
|
pi_.first = pi_.last;
|
||||||
|
}
|
||||||
|
else if(! pi_.v.second.empty() &&
|
||||||
|
pi_.v.second.front() == '"')
|
||||||
|
{
|
||||||
|
s_ = unquote(pi_.v.second);
|
||||||
|
pi_.v.second = string_view{
|
||||||
|
s_.data(), s_.size()};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ext_list::const_iterator::
|
||||||
|
increment()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
ext-list = *( "," OWS ) ext *( OWS "," [ OWS ext ] )
|
||||||
|
ext = token param-list
|
||||||
|
param-list = *( OWS ";" OWS param )
|
||||||
|
param = token OWS "=" OWS ( token / quoted-string )
|
||||||
|
|
||||||
|
chunked;a=b;i=j;gzip;windowBits=12
|
||||||
|
x,y
|
||||||
|
,,,,,chameleon
|
||||||
|
*/
|
||||||
|
auto const err =
|
||||||
|
[&]
|
||||||
|
{
|
||||||
|
it_ = last_;
|
||||||
|
first_ = last_;
|
||||||
|
};
|
||||||
|
auto need_comma = it_ != first_;
|
||||||
|
v_.first = {};
|
||||||
|
first_ = it_;
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
detail::skip_ows(it_, last_);
|
||||||
|
if(it_ == last_)
|
||||||
|
return err();
|
||||||
|
auto const c = *it_;
|
||||||
|
if(detail::is_token_char(c))
|
||||||
|
{
|
||||||
|
if(need_comma)
|
||||||
|
return err();
|
||||||
|
auto const p0 = it_;
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
++it_;
|
||||||
|
if(it_ == last_)
|
||||||
|
break;
|
||||||
|
if(! detail::is_token_char(*it_))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
v_.first = string_view{&*p0,
|
||||||
|
static_cast<std::size_t>(it_ - p0)};
|
||||||
|
if (it_ == last_)
|
||||||
|
return;
|
||||||
|
detail::param_iter pi;
|
||||||
|
pi.it = it_;
|
||||||
|
pi.first = it_;
|
||||||
|
pi.last = last_;
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
pi.increment();
|
||||||
|
if(pi.empty())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
v_.second = param_list{string_view{&*it_,
|
||||||
|
static_cast<std::size_t>(pi.it - it_)}};
|
||||||
|
it_ = pi.it;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(c != ',')
|
||||||
|
return err();
|
||||||
|
need_comma = false;
|
||||||
|
++it_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
token_list::const_iterator::
|
||||||
|
increment()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
token-list = *( "," OWS ) token *( OWS "," [ OWS ext ] )
|
||||||
|
*/
|
||||||
|
auto const err =
|
||||||
|
[&]
|
||||||
|
{
|
||||||
|
it_ = last_;
|
||||||
|
first_ = last_;
|
||||||
|
};
|
||||||
|
auto need_comma = it_ != first_;
|
||||||
|
v_ = {};
|
||||||
|
first_ = it_;
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
detail::skip_ows(it_, last_);
|
||||||
|
if(it_ == last_)
|
||||||
|
return err();
|
||||||
|
auto const c = *it_;
|
||||||
|
if(detail::is_token_char(c))
|
||||||
|
{
|
||||||
|
if(need_comma)
|
||||||
|
return err();
|
||||||
|
auto const p0 = it_;
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
++it_;
|
||||||
|
if(it_ == last_)
|
||||||
|
break;
|
||||||
|
if(! detail::is_token_char(*it_))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
v_ = string_view{&*p0,
|
||||||
|
static_cast<std::size_t>(it_ - p0)};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(c != ',')
|
||||||
|
return err();
|
||||||
|
need_comma = false;
|
||||||
|
++it_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // http
|
||||||
|
} // beast
|
||||||
|
} // boost
|
||||||
|
|
||||||
|
#endif // BOOST_BEAST_HTTP_IMPL_RFC7230_IPP
|
@@ -43,11 +43,15 @@ the program, with the macro BOOST_BEAST_SPLIT_COMPILATION defined.
|
|||||||
#include <boost/beast/http/impl/basic_parser.ipp>
|
#include <boost/beast/http/impl/basic_parser.ipp>
|
||||||
#include <boost/beast/http/impl/error.ipp>
|
#include <boost/beast/http/impl/error.ipp>
|
||||||
#include <boost/beast/http/impl/field.ipp>
|
#include <boost/beast/http/impl/field.ipp>
|
||||||
|
#include <boost/beast/http/impl/rfc7230.ipp>
|
||||||
#include <boost/beast/http/impl/status.ipp>
|
#include <boost/beast/http/impl/status.ipp>
|
||||||
#include <boost/beast/http/impl/verb.ipp>
|
#include <boost/beast/http/impl/verb.ipp>
|
||||||
|
|
||||||
|
#include <boost/beast/websocket/detail/hybi13.ipp>
|
||||||
|
#include <boost/beast/websocket/detail/pmd_extension.ipp>
|
||||||
#include <boost/beast/websocket/detail/prng.ipp>
|
#include <boost/beast/websocket/detail/prng.ipp>
|
||||||
#include <boost/beast/websocket/detail/service.ipp>
|
#include <boost/beast/websocket/detail/service.ipp>
|
||||||
|
#include <boost/beast/websocket/detail/utf8_checker.ipp>
|
||||||
#include <boost/beast/websocket/impl/error.ipp>
|
#include <boost/beast/websocket/impl/error.ipp>
|
||||||
|
|
||||||
#include <boost/beast/zlib/detail/deflate_stream.ipp>
|
#include <boost/beast/zlib/detail/deflate_stream.ipp>
|
||||||
|
@@ -13,13 +13,7 @@
|
|||||||
#include <boost/beast/core/static_string.hpp>
|
#include <boost/beast/core/static_string.hpp>
|
||||||
#include <boost/beast/core/string.hpp>
|
#include <boost/beast/core/string.hpp>
|
||||||
#include <boost/beast/core/detail/base64.hpp>
|
#include <boost/beast/core/detail/base64.hpp>
|
||||||
#include <boost/beast/core/detail/sha1.hpp>
|
|
||||||
#include <boost/beast/websocket/detail/prng.hpp>
|
|
||||||
#include <boost/assert.hpp>
|
|
||||||
#include <array>
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
namespace boost {
|
namespace boost {
|
||||||
namespace beast {
|
namespace beast {
|
||||||
@@ -32,47 +26,23 @@ using sec_ws_key_type = static_string<
|
|||||||
using sec_ws_accept_type = static_string<
|
using sec_ws_accept_type = static_string<
|
||||||
beast::detail::base64::encoded_size(20)>;
|
beast::detail::base64::encoded_size(20)>;
|
||||||
|
|
||||||
inline
|
BOOST_BEAST_DECL
|
||||||
void
|
void
|
||||||
make_sec_ws_key(sec_ws_key_type& key)
|
make_sec_ws_key(sec_ws_key_type& key);
|
||||||
{
|
|
||||||
auto g = make_prng(true);
|
|
||||||
char a[16];
|
|
||||||
for(int i = 0; i < 16; i += 4)
|
|
||||||
{
|
|
||||||
auto const v = g();
|
|
||||||
a[i ] = v & 0xff;
|
|
||||||
a[i+1] = (v >> 8) & 0xff;
|
|
||||||
a[i+2] = (v >> 16) & 0xff;
|
|
||||||
a[i+3] = (v >> 24) & 0xff;
|
|
||||||
}
|
|
||||||
key.resize(key.max_size());
|
|
||||||
key.resize(beast::detail::base64::encode(
|
|
||||||
key.data(), &a[0], 16));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class = void>
|
BOOST_BEAST_DECL
|
||||||
void
|
void
|
||||||
make_sec_ws_accept(
|
make_sec_ws_accept(
|
||||||
sec_ws_accept_type& accept,
|
sec_ws_accept_type& accept,
|
||||||
string_view key)
|
string_view key);
|
||||||
{
|
|
||||||
BOOST_ASSERT(key.size() <= sec_ws_key_type::max_size_n);
|
|
||||||
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::init(ctx);
|
|
||||||
beast::detail::update(ctx, m.data(), m.size());
|
|
||||||
char digest[beast::detail::sha1_context::digest_size];
|
|
||||||
beast::detail::finish(ctx, &digest[0]);
|
|
||||||
accept.resize(accept.max_size());
|
|
||||||
accept.resize(beast::detail::base64::encode(
|
|
||||||
accept.data(), &digest[0], sizeof(digest)));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // detail
|
} // detail
|
||||||
} // websocket
|
} // websocket
|
||||||
} // beast
|
} // beast
|
||||||
} // boost
|
} // boost
|
||||||
|
|
||||||
|
#if BOOST_BEAST_HEADER_ONLY
|
||||||
|
#include <boost/beast/websocket/detail/hybi13.ipp>
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
67
include/boost/beast/websocket/detail/hybi13.ipp
Normal file
67
include/boost/beast/websocket/detail/hybi13.ipp
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2016-2019 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)
|
||||||
|
//
|
||||||
|
// Official repository: https://github.com/boostorg/beast
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef BOOST_BEAST_WEBSOCKET_DETAIL_HYBI13_IPP
|
||||||
|
#define BOOST_BEAST_WEBSOCKET_DETAIL_HYBI13_IPP
|
||||||
|
|
||||||
|
#include <boost/beast/websocket/detail/hybi13.hpp>
|
||||||
|
#include <boost/beast/core/detail/sha1.hpp>
|
||||||
|
#include <boost/beast/websocket/detail/prng.hpp>
|
||||||
|
|
||||||
|
#include <boost/assert.hpp>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
namespace beast {
|
||||||
|
namespace websocket {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
void
|
||||||
|
make_sec_ws_key(sec_ws_key_type& key)
|
||||||
|
{
|
||||||
|
auto g = make_prng(true);
|
||||||
|
char a[16];
|
||||||
|
for(int i = 0; i < 16; i += 4)
|
||||||
|
{
|
||||||
|
auto const v = g();
|
||||||
|
a[i ] = v & 0xff;
|
||||||
|
a[i+1] = (v >> 8) & 0xff;
|
||||||
|
a[i+2] = (v >> 16) & 0xff;
|
||||||
|
a[i+3] = (v >> 24) & 0xff;
|
||||||
|
}
|
||||||
|
key.resize(key.max_size());
|
||||||
|
key.resize(beast::detail::base64::encode(
|
||||||
|
key.data(), &a[0], 16));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
make_sec_ws_accept(
|
||||||
|
sec_ws_accept_type& accept,
|
||||||
|
string_view key)
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(key.size() <= sec_ws_key_type::max_size_n);
|
||||||
|
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::init(ctx);
|
||||||
|
beast::detail::update(ctx, m.data(), m.size());
|
||||||
|
char digest[beast::detail::sha1_context::digest_size];
|
||||||
|
beast::detail::finish(ctx, &digest[0]);
|
||||||
|
accept.resize(accept.max_size());
|
||||||
|
accept.resize(beast::detail::base64::encode(
|
||||||
|
accept.data(), &digest[0], sizeof(digest)));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // detail
|
||||||
|
} // websocket
|
||||||
|
} // beast
|
||||||
|
} // boost
|
||||||
|
|
||||||
|
#endif // BOOST_BEAST_WEBSOCKET_DETAIL_HYBI13_IPP
|
@@ -11,13 +11,8 @@
|
|||||||
#define BOOST_BEAST_WEBSOCKET_DETAIL_PMD_EXTENSION_HPP
|
#define BOOST_BEAST_WEBSOCKET_DETAIL_PMD_EXTENSION_HPP
|
||||||
|
|
||||||
#include <boost/beast/core/error.hpp>
|
#include <boost/beast/core/error.hpp>
|
||||||
#include <boost/beast/core/buffers_suffix.hpp>
|
|
||||||
#include <boost/beast/core/read_size.hpp>
|
|
||||||
#include <boost/beast/zlib/deflate_stream.hpp>
|
|
||||||
#include <boost/beast/zlib/inflate_stream.hpp>
|
|
||||||
#include <boost/beast/websocket/option.hpp>
|
#include <boost/beast/websocket/option.hpp>
|
||||||
#include <boost/beast/http/rfc7230.hpp>
|
#include <boost/beast/http/rfc7230.hpp>
|
||||||
#include <boost/asio/buffer.hpp>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
@@ -48,28 +43,24 @@ struct pmd_offer
|
|||||||
bool client_no_context_takeover;
|
bool client_no_context_takeover;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class = void>
|
BOOST_BEAST_DECL
|
||||||
int
|
int
|
||||||
parse_bits(string_view s)
|
parse_bits(string_view s);
|
||||||
{
|
|
||||||
if(s.size() == 0)
|
BOOST_BEAST_DECL
|
||||||
return -1;
|
void
|
||||||
if(s.size() > 2)
|
pmd_read_impl(pmd_offer& offer, http::ext_list const& list);
|
||||||
return -1;
|
|
||||||
if(s[0] < '1' || s[0] > '9')
|
BOOST_BEAST_DECL
|
||||||
return -1;
|
static_string<512>
|
||||||
unsigned i = 0;
|
pmd_write_impl(pmd_offer const& offer);
|
||||||
for(auto c : s)
|
|
||||||
{
|
BOOST_BEAST_DECL
|
||||||
if(c < '0' || c > '9')
|
static_string<512>
|
||||||
return -1;
|
pmd_negotiate_impl(
|
||||||
auto const i0 = i;
|
pmd_offer& config,
|
||||||
i = 10 * i + (c - '0');
|
pmd_offer const& offer,
|
||||||
if(i < i0)
|
permessage_deflate const& o);
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return static_cast<int>(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse permessage-deflate request fields
|
// Parse permessage-deflate request fields
|
||||||
//
|
//
|
||||||
@@ -78,126 +69,9 @@ void
|
|||||||
pmd_read(pmd_offer& offer,
|
pmd_read(pmd_offer& offer,
|
||||||
http::basic_fields<Allocator> const& fields)
|
http::basic_fields<Allocator> const& fields)
|
||||||
{
|
{
|
||||||
offer.accept = false;
|
|
||||||
offer.server_max_window_bits= 0;
|
|
||||||
offer.client_max_window_bits = 0;
|
|
||||||
offer.server_no_context_takeover = false;
|
|
||||||
offer.client_no_context_takeover = false;
|
|
||||||
|
|
||||||
http::ext_list list{
|
http::ext_list list{
|
||||||
fields["Sec-WebSocket-Extensions"]};
|
fields["Sec-WebSocket-Extensions"]};
|
||||||
for(auto const& ext : list)
|
detail::pmd_read_impl(offer, list);
|
||||||
{
|
|
||||||
if(iequals(ext.first, "permessage-deflate"))
|
|
||||||
{
|
|
||||||
for(auto const& param : ext.second)
|
|
||||||
{
|
|
||||||
if(iequals(param.first,
|
|
||||||
"server_max_window_bits"))
|
|
||||||
{
|
|
||||||
if(offer.server_max_window_bits != 0)
|
|
||||||
{
|
|
||||||
// The negotiation offer contains multiple
|
|
||||||
// extension parameters with the same name.
|
|
||||||
//
|
|
||||||
return; // MUST decline
|
|
||||||
}
|
|
||||||
if(param.second.empty())
|
|
||||||
{
|
|
||||||
// The negotiation offer extension
|
|
||||||
// parameter is missing the value.
|
|
||||||
//
|
|
||||||
return; // MUST decline
|
|
||||||
}
|
|
||||||
offer.server_max_window_bits =
|
|
||||||
parse_bits(param.second);
|
|
||||||
if( offer.server_max_window_bits < 8 ||
|
|
||||||
offer.server_max_window_bits > 15)
|
|
||||||
{
|
|
||||||
// The negotiation offer contains an
|
|
||||||
// extension parameter with an invalid value.
|
|
||||||
//
|
|
||||||
return; // MUST decline
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(iequals(param.first,
|
|
||||||
"client_max_window_bits"))
|
|
||||||
{
|
|
||||||
if(offer.client_max_window_bits != 0)
|
|
||||||
{
|
|
||||||
// The negotiation offer contains multiple
|
|
||||||
// extension parameters with the same name.
|
|
||||||
//
|
|
||||||
return; // MUST decline
|
|
||||||
}
|
|
||||||
if(! param.second.empty())
|
|
||||||
{
|
|
||||||
offer.client_max_window_bits =
|
|
||||||
parse_bits(param.second);
|
|
||||||
if( offer.client_max_window_bits < 8 ||
|
|
||||||
offer.client_max_window_bits > 15)
|
|
||||||
{
|
|
||||||
// The negotiation offer contains an
|
|
||||||
// extension parameter with an invalid value.
|
|
||||||
//
|
|
||||||
return; // MUST decline
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
offer.client_max_window_bits = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(iequals(param.first,
|
|
||||||
"server_no_context_takeover"))
|
|
||||||
{
|
|
||||||
if(offer.server_no_context_takeover)
|
|
||||||
{
|
|
||||||
// The negotiation offer contains multiple
|
|
||||||
// extension parameters with the same name.
|
|
||||||
//
|
|
||||||
return; // MUST decline
|
|
||||||
}
|
|
||||||
if(! param.second.empty())
|
|
||||||
{
|
|
||||||
// The negotiation offer contains an
|
|
||||||
// extension parameter with an invalid value.
|
|
||||||
//
|
|
||||||
return; // MUST decline
|
|
||||||
}
|
|
||||||
offer.server_no_context_takeover = true;
|
|
||||||
}
|
|
||||||
else if(iequals(param.first,
|
|
||||||
"client_no_context_takeover"))
|
|
||||||
{
|
|
||||||
if(offer.client_no_context_takeover)
|
|
||||||
{
|
|
||||||
// The negotiation offer contains multiple
|
|
||||||
// extension parameters with the same name.
|
|
||||||
//
|
|
||||||
return; // MUST decline
|
|
||||||
}
|
|
||||||
if(! param.second.empty())
|
|
||||||
{
|
|
||||||
// The negotiation offer contains an
|
|
||||||
// extension parameter with an invalid value.
|
|
||||||
//
|
|
||||||
return; // MUST decline
|
|
||||||
}
|
|
||||||
offer.client_no_context_takeover = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// The negotiation offer contains an extension
|
|
||||||
// parameter not defined for use in an offer.
|
|
||||||
//
|
|
||||||
return; // MUST decline
|
|
||||||
}
|
|
||||||
}
|
|
||||||
offer.accept = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set permessage-deflate fields for a client offer
|
// Set permessage-deflate fields for a client offer
|
||||||
@@ -207,42 +81,7 @@ void
|
|||||||
pmd_write(http::basic_fields<Allocator>& fields,
|
pmd_write(http::basic_fields<Allocator>& fields,
|
||||||
pmd_offer const& offer)
|
pmd_offer const& offer)
|
||||||
{
|
{
|
||||||
static_string<512> s;
|
auto s = detail::pmd_write_impl(offer);
|
||||||
s = "permessage-deflate";
|
|
||||||
if(offer.server_max_window_bits != 0)
|
|
||||||
{
|
|
||||||
if(offer.server_max_window_bits != -1)
|
|
||||||
{
|
|
||||||
s += "; server_max_window_bits=";
|
|
||||||
s += to_static_string(
|
|
||||||
offer.server_max_window_bits);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
s += "; server_max_window_bits";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(offer.client_max_window_bits != 0)
|
|
||||||
{
|
|
||||||
if(offer.client_max_window_bits != -1)
|
|
||||||
{
|
|
||||||
s += "; client_max_window_bits=";
|
|
||||||
s += to_static_string(
|
|
||||||
offer.client_max_window_bits);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
s += "; client_max_window_bits";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(offer.server_no_context_takeover)
|
|
||||||
{
|
|
||||||
s += "; server_no_context_takeover";
|
|
||||||
}
|
|
||||||
if(offer.client_no_context_takeover)
|
|
||||||
{
|
|
||||||
s += "; client_no_context_takeover";
|
|
||||||
}
|
|
||||||
fields.set(http::field::sec_websocket_extensions, s);
|
fields.set(http::field::sec_websocket_extensions, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,102 +102,24 @@ pmd_negotiate(
|
|||||||
}
|
}
|
||||||
config.accept = true;
|
config.accept = true;
|
||||||
|
|
||||||
static_string<512> s = "permessage-deflate";
|
auto s = detail::pmd_negotiate_impl(config, offer, o);
|
||||||
|
|
||||||
config.server_no_context_takeover =
|
|
||||||
offer.server_no_context_takeover ||
|
|
||||||
o.server_no_context_takeover;
|
|
||||||
if(config.server_no_context_takeover)
|
|
||||||
s += "; server_no_context_takeover";
|
|
||||||
|
|
||||||
config.client_no_context_takeover =
|
|
||||||
o.client_no_context_takeover ||
|
|
||||||
offer.client_no_context_takeover;
|
|
||||||
if(config.client_no_context_takeover)
|
|
||||||
s += "; client_no_context_takeover";
|
|
||||||
|
|
||||||
if(offer.server_max_window_bits != 0)
|
|
||||||
config.server_max_window_bits = (std::min)(
|
|
||||||
offer.server_max_window_bits,
|
|
||||||
o.server_max_window_bits);
|
|
||||||
else
|
|
||||||
config.server_max_window_bits =
|
|
||||||
o.server_max_window_bits;
|
|
||||||
if(config.server_max_window_bits < 15)
|
|
||||||
{
|
|
||||||
// ZLib's deflateInit silently treats 8 as
|
|
||||||
// 9 due to a bug, so prevent 8 from being used.
|
|
||||||
//
|
|
||||||
if(config.server_max_window_bits < 9)
|
|
||||||
config.server_max_window_bits = 9;
|
|
||||||
|
|
||||||
s += "; server_max_window_bits=";
|
|
||||||
s += to_static_string(
|
|
||||||
config.server_max_window_bits);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(offer.client_max_window_bits)
|
|
||||||
{
|
|
||||||
case -1:
|
|
||||||
// extension parameter is present with no value
|
|
||||||
config.client_max_window_bits =
|
|
||||||
o.client_max_window_bits;
|
|
||||||
if(config.client_max_window_bits < 15)
|
|
||||||
{
|
|
||||||
s += "; client_max_window_bits=";
|
|
||||||
s += to_static_string(
|
|
||||||
config.client_max_window_bits);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0:
|
|
||||||
/* extension parameter is absent.
|
|
||||||
|
|
||||||
If a received extension negotiation offer doesn't have the
|
|
||||||
"client_max_window_bits" extension parameter, the corresponding
|
|
||||||
extension negotiation response to the offer MUST NOT include the
|
|
||||||
"client_max_window_bits" extension parameter.
|
|
||||||
*/
|
|
||||||
if(o.client_max_window_bits == 15)
|
|
||||||
config.client_max_window_bits = 15;
|
|
||||||
else
|
|
||||||
config.accept = false;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
// extension parameter has value in [8..15]
|
|
||||||
config.client_max_window_bits = (std::min)(
|
|
||||||
o.client_max_window_bits,
|
|
||||||
offer.client_max_window_bits);
|
|
||||||
s += "; client_max_window_bits=";
|
|
||||||
s += to_static_string(
|
|
||||||
config.client_max_window_bits);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(config.accept)
|
if(config.accept)
|
||||||
fields.set(http::field::sec_websocket_extensions, s);
|
fields.set(http::field::sec_websocket_extensions, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normalize the server's response
|
// Normalize the server's response
|
||||||
//
|
//
|
||||||
inline
|
BOOST_BEAST_DECL
|
||||||
void
|
void
|
||||||
pmd_normalize(pmd_offer& offer)
|
pmd_normalize(pmd_offer& offer);
|
||||||
{
|
|
||||||
if(offer.accept)
|
|
||||||
{
|
|
||||||
if( offer.server_max_window_bits == 0)
|
|
||||||
offer.server_max_window_bits = 15;
|
|
||||||
|
|
||||||
if( offer.client_max_window_bits == 0 ||
|
|
||||||
offer.client_max_window_bits == -1)
|
|
||||||
offer.client_max_window_bits = 15;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // detail
|
} // detail
|
||||||
} // websocket
|
} // websocket
|
||||||
} // beast
|
} // beast
|
||||||
} // boost
|
} // boost
|
||||||
|
|
||||||
|
#if BOOST_BEAST_HEADER_ONLY
|
||||||
|
#include <boost/beast/websocket/detail/pmd_extension.ipp>
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
310
include/boost/beast/websocket/detail/pmd_extension.ipp
Normal file
310
include/boost/beast/websocket/detail/pmd_extension.ipp
Normal file
@@ -0,0 +1,310 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2016-2019 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)
|
||||||
|
//
|
||||||
|
// Official repository: https://github.com/boostorg/beast
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef BOOST_BEAST_WEBSOCKET_DETAIL_PMD_EXTENSION_IPP
|
||||||
|
#define BOOST_BEAST_WEBSOCKET_DETAIL_PMD_EXTENSION_IPP
|
||||||
|
|
||||||
|
#include <boost/beast/websocket/detail/pmd_extension.hpp>
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
namespace beast {
|
||||||
|
namespace websocket {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
int
|
||||||
|
parse_bits(string_view s)
|
||||||
|
{
|
||||||
|
if(s.size() == 0)
|
||||||
|
return -1;
|
||||||
|
if(s.size() > 2)
|
||||||
|
return -1;
|
||||||
|
if(s[0] < '1' || s[0] > '9')
|
||||||
|
return -1;
|
||||||
|
unsigned i = 0;
|
||||||
|
for(auto c : s)
|
||||||
|
{
|
||||||
|
if(c < '0' || c > '9')
|
||||||
|
return -1;
|
||||||
|
auto const i0 = i;
|
||||||
|
i = 10 * i + (c - '0');
|
||||||
|
if(i < i0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return static_cast<int>(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse permessage-deflate request fields
|
||||||
|
//
|
||||||
|
void
|
||||||
|
pmd_read_impl(pmd_offer& offer, http::ext_list const& list)
|
||||||
|
{
|
||||||
|
offer.accept = false;
|
||||||
|
offer.server_max_window_bits= 0;
|
||||||
|
offer.client_max_window_bits = 0;
|
||||||
|
offer.server_no_context_takeover = false;
|
||||||
|
offer.client_no_context_takeover = false;
|
||||||
|
|
||||||
|
for(auto const& ext : list)
|
||||||
|
{
|
||||||
|
if(iequals(ext.first, "permessage-deflate"))
|
||||||
|
{
|
||||||
|
for(auto const& param : ext.second)
|
||||||
|
{
|
||||||
|
if(iequals(param.first,
|
||||||
|
"server_max_window_bits"))
|
||||||
|
{
|
||||||
|
if(offer.server_max_window_bits != 0)
|
||||||
|
{
|
||||||
|
// The negotiation offer contains multiple
|
||||||
|
// extension parameters with the same name.
|
||||||
|
//
|
||||||
|
return; // MUST decline
|
||||||
|
}
|
||||||
|
if(param.second.empty())
|
||||||
|
{
|
||||||
|
// The negotiation offer extension
|
||||||
|
// parameter is missing the value.
|
||||||
|
//
|
||||||
|
return; // MUST decline
|
||||||
|
}
|
||||||
|
offer.server_max_window_bits =
|
||||||
|
parse_bits(param.second);
|
||||||
|
if( offer.server_max_window_bits < 8 ||
|
||||||
|
offer.server_max_window_bits > 15)
|
||||||
|
{
|
||||||
|
// The negotiation offer contains an
|
||||||
|
// extension parameter with an invalid value.
|
||||||
|
//
|
||||||
|
return; // MUST decline
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(iequals(param.first,
|
||||||
|
"client_max_window_bits"))
|
||||||
|
{
|
||||||
|
if(offer.client_max_window_bits != 0)
|
||||||
|
{
|
||||||
|
// The negotiation offer contains multiple
|
||||||
|
// extension parameters with the same name.
|
||||||
|
//
|
||||||
|
return; // MUST decline
|
||||||
|
}
|
||||||
|
if(! param.second.empty())
|
||||||
|
{
|
||||||
|
offer.client_max_window_bits =
|
||||||
|
parse_bits(param.second);
|
||||||
|
if( offer.client_max_window_bits < 8 ||
|
||||||
|
offer.client_max_window_bits > 15)
|
||||||
|
{
|
||||||
|
// The negotiation offer contains an
|
||||||
|
// extension parameter with an invalid value.
|
||||||
|
//
|
||||||
|
return; // MUST decline
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
offer.client_max_window_bits = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(iequals(param.first,
|
||||||
|
"server_no_context_takeover"))
|
||||||
|
{
|
||||||
|
if(offer.server_no_context_takeover)
|
||||||
|
{
|
||||||
|
// The negotiation offer contains multiple
|
||||||
|
// extension parameters with the same name.
|
||||||
|
//
|
||||||
|
return; // MUST decline
|
||||||
|
}
|
||||||
|
if(! param.second.empty())
|
||||||
|
{
|
||||||
|
// The negotiation offer contains an
|
||||||
|
// extension parameter with an invalid value.
|
||||||
|
//
|
||||||
|
return; // MUST decline
|
||||||
|
}
|
||||||
|
offer.server_no_context_takeover = true;
|
||||||
|
}
|
||||||
|
else if(iequals(param.first,
|
||||||
|
"client_no_context_takeover"))
|
||||||
|
{
|
||||||
|
if(offer.client_no_context_takeover)
|
||||||
|
{
|
||||||
|
// The negotiation offer contains multiple
|
||||||
|
// extension parameters with the same name.
|
||||||
|
//
|
||||||
|
return; // MUST decline
|
||||||
|
}
|
||||||
|
if(! param.second.empty())
|
||||||
|
{
|
||||||
|
// The negotiation offer contains an
|
||||||
|
// extension parameter with an invalid value.
|
||||||
|
//
|
||||||
|
return; // MUST decline
|
||||||
|
}
|
||||||
|
offer.client_no_context_takeover = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// The negotiation offer contains an extension
|
||||||
|
// parameter not defined for use in an offer.
|
||||||
|
//
|
||||||
|
return; // MUST decline
|
||||||
|
}
|
||||||
|
}
|
||||||
|
offer.accept = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static_string<512>
|
||||||
|
pmd_write_impl(pmd_offer const& offer)
|
||||||
|
{
|
||||||
|
static_string<512> s = "permessage-deflate";
|
||||||
|
if(offer.server_max_window_bits != 0)
|
||||||
|
{
|
||||||
|
if(offer.server_max_window_bits != -1)
|
||||||
|
{
|
||||||
|
s += "; server_max_window_bits=";
|
||||||
|
s += to_static_string(
|
||||||
|
offer.server_max_window_bits);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s += "; server_max_window_bits";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(offer.client_max_window_bits != 0)
|
||||||
|
{
|
||||||
|
if(offer.client_max_window_bits != -1)
|
||||||
|
{
|
||||||
|
s += "; client_max_window_bits=";
|
||||||
|
s += to_static_string(
|
||||||
|
offer.client_max_window_bits);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s += "; client_max_window_bits";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(offer.server_no_context_takeover)
|
||||||
|
{
|
||||||
|
s += "; server_no_context_takeover";
|
||||||
|
}
|
||||||
|
if(offer.client_no_context_takeover)
|
||||||
|
{
|
||||||
|
s += "; client_no_context_takeover";
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static_string<512>
|
||||||
|
pmd_negotiate_impl(
|
||||||
|
pmd_offer& config,
|
||||||
|
pmd_offer const& offer,
|
||||||
|
permessage_deflate const& o)
|
||||||
|
{
|
||||||
|
static_string<512> s = "permessage-deflate";
|
||||||
|
|
||||||
|
config.server_no_context_takeover =
|
||||||
|
offer.server_no_context_takeover ||
|
||||||
|
o.server_no_context_takeover;
|
||||||
|
if(config.server_no_context_takeover)
|
||||||
|
s += "; server_no_context_takeover";
|
||||||
|
|
||||||
|
config.client_no_context_takeover =
|
||||||
|
o.client_no_context_takeover ||
|
||||||
|
offer.client_no_context_takeover;
|
||||||
|
if(config.client_no_context_takeover)
|
||||||
|
s += "; client_no_context_takeover";
|
||||||
|
|
||||||
|
if(offer.server_max_window_bits != 0)
|
||||||
|
config.server_max_window_bits = (std::min)(
|
||||||
|
offer.server_max_window_bits,
|
||||||
|
o.server_max_window_bits);
|
||||||
|
else
|
||||||
|
config.server_max_window_bits =
|
||||||
|
o.server_max_window_bits;
|
||||||
|
if(config.server_max_window_bits < 15)
|
||||||
|
{
|
||||||
|
// ZLib's deflateInit silently treats 8 as
|
||||||
|
// 9 due to a bug, so prevent 8 from being used.
|
||||||
|
//
|
||||||
|
if(config.server_max_window_bits < 9)
|
||||||
|
config.server_max_window_bits = 9;
|
||||||
|
|
||||||
|
s += "; server_max_window_bits=";
|
||||||
|
s += to_static_string(
|
||||||
|
config.server_max_window_bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(offer.client_max_window_bits)
|
||||||
|
{
|
||||||
|
case -1:
|
||||||
|
// extension parameter is present with no value
|
||||||
|
config.client_max_window_bits =
|
||||||
|
o.client_max_window_bits;
|
||||||
|
if(config.client_max_window_bits < 15)
|
||||||
|
{
|
||||||
|
s += "; client_max_window_bits=";
|
||||||
|
s += to_static_string(
|
||||||
|
config.client_max_window_bits);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
/* extension parameter is absent.
|
||||||
|
|
||||||
|
If a received extension negotiation offer doesn't have the
|
||||||
|
"client_max_window_bits" extension parameter, the corresponding
|
||||||
|
extension negotiation response to the offer MUST NOT include the
|
||||||
|
"client_max_window_bits" extension parameter.
|
||||||
|
*/
|
||||||
|
if(o.client_max_window_bits == 15)
|
||||||
|
config.client_max_window_bits = 15;
|
||||||
|
else
|
||||||
|
config.accept = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// extension parameter has value in [8..15]
|
||||||
|
config.client_max_window_bits = (std::min)(
|
||||||
|
o.client_max_window_bits,
|
||||||
|
offer.client_max_window_bits);
|
||||||
|
s += "; client_max_window_bits=";
|
||||||
|
s += to_static_string(
|
||||||
|
config.client_max_window_bits);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pmd_normalize(pmd_offer& offer)
|
||||||
|
{
|
||||||
|
if(offer.accept)
|
||||||
|
{
|
||||||
|
if( offer.server_max_window_bits == 0)
|
||||||
|
offer.server_max_window_bits = 15;
|
||||||
|
|
||||||
|
if( offer.client_max_window_bits == 0 ||
|
||||||
|
offer.client_max_window_bits == -1)
|
||||||
|
offer.client_max_window_bits = 15;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // detail
|
||||||
|
} // websocket
|
||||||
|
} // beast
|
||||||
|
} // boost
|
||||||
|
|
||||||
|
#endif // BOOST_BEAST_WEBSOCKET_DETAIL_PMD_EXTENSION_IPP
|
@@ -12,8 +12,7 @@
|
|||||||
|
|
||||||
#include <boost/beast/core/buffers_range.hpp>
|
#include <boost/beast/core/buffers_range.hpp>
|
||||||
#include <boost/asio/buffer.hpp>
|
#include <boost/asio/buffer.hpp>
|
||||||
#include <boost/assert.hpp>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
namespace boost {
|
namespace boost {
|
||||||
@@ -27,8 +26,7 @@ namespace detail {
|
|||||||
valid. The write function may be called incrementally with segmented UTF8
|
valid. The write function may be called incrementally with segmented UTF8
|
||||||
sequences. The finish function determines if all processed text is valid.
|
sequences. The finish function determines if all processed text is valid.
|
||||||
*/
|
*/
|
||||||
template<class = void>
|
class utf8_checker
|
||||||
class utf8_checker_t
|
|
||||||
{
|
{
|
||||||
std::size_t need_ = 0; // chars we need to finish the code point
|
std::size_t need_ = 0; // chars we need to finish the code point
|
||||||
std::uint8_t* p_ = cp_; // current position in temp buffer
|
std::uint8_t* p_ = cp_; // current position in temp buffer
|
||||||
@@ -37,11 +35,13 @@ class utf8_checker_t
|
|||||||
public:
|
public:
|
||||||
/** Prepare to process text as valid utf8
|
/** Prepare to process text as valid utf8
|
||||||
*/
|
*/
|
||||||
|
BOOST_BEAST_DECL
|
||||||
void
|
void
|
||||||
reset();
|
reset();
|
||||||
|
|
||||||
/** Check that all processed text is valid utf8
|
/** Check that all processed text is valid utf8
|
||||||
*/
|
*/
|
||||||
|
BOOST_BEAST_DECL
|
||||||
bool
|
bool
|
||||||
finish();
|
finish();
|
||||||
|
|
||||||
@@ -49,6 +49,7 @@ public:
|
|||||||
|
|
||||||
@return `true` if the text is valid utf8 or false otherwise.
|
@return `true` if the text is valid utf8 or false otherwise.
|
||||||
*/
|
*/
|
||||||
|
BOOST_BEAST_DECL
|
||||||
bool
|
bool
|
||||||
write(std::uint8_t const* in, std::size_t size);
|
write(std::uint8_t const* in, std::size_t size);
|
||||||
|
|
||||||
@@ -61,29 +62,10 @@ public:
|
|||||||
write(ConstBufferSequence const& bs);
|
write(ConstBufferSequence const& bs);
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class _>
|
|
||||||
void
|
|
||||||
utf8_checker_t<_>::
|
|
||||||
reset()
|
|
||||||
{
|
|
||||||
need_ = 0;
|
|
||||||
p_ = cp_;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class _>
|
|
||||||
bool
|
|
||||||
utf8_checker_t<_>::
|
|
||||||
finish()
|
|
||||||
{
|
|
||||||
auto const success = need_ == 0;
|
|
||||||
reset();
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class _>
|
|
||||||
template<class ConstBufferSequence>
|
template<class ConstBufferSequence>
|
||||||
bool
|
bool
|
||||||
utf8_checker_t<_>::
|
utf8_checker::
|
||||||
write(ConstBufferSequence const& buffers)
|
write(ConstBufferSequence const& buffers)
|
||||||
{
|
{
|
||||||
static_assert(
|
static_assert(
|
||||||
@@ -97,300 +79,18 @@ write(ConstBufferSequence const& buffers)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class _>
|
|
||||||
|
BOOST_BEAST_DECL
|
||||||
bool
|
bool
|
||||||
utf8_checker_t<_>::
|
check_utf8(char const* p, std::size_t n);
|
||||||
write(std::uint8_t const* in, std::size_t size)
|
|
||||||
{
|
|
||||||
auto const valid =
|
|
||||||
[](std::uint8_t const*& p)
|
|
||||||
{
|
|
||||||
if(p[0] < 128)
|
|
||||||
{
|
|
||||||
++p;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if((p[0] & 0xe0) == 0xc0)
|
|
||||||
{
|
|
||||||
if( (p[1] & 0xc0) != 0x80 ||
|
|
||||||
(p[0] & 0x1e) == 0) // overlong
|
|
||||||
return false;
|
|
||||||
p += 2;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if((p[0] & 0xf0) == 0xe0)
|
|
||||||
{
|
|
||||||
if( (p[1] & 0xc0) != 0x80
|
|
||||||
|| (p[2] & 0xc0) != 0x80
|
|
||||||
|| (p[0] == 0xe0 && (p[1] & 0x20) == 0) // overlong
|
|
||||||
|| (p[0] == 0xed && (p[1] & 0x20) == 0x20) // surrogate
|
|
||||||
//|| (p[0] == 0xef && p[1] == 0xbf && (p[2] & 0xfe) == 0xbe) // U+FFFE or U+FFFF
|
|
||||||
)
|
|
||||||
return false;
|
|
||||||
p += 3;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if((p[0] & 0xf8) == 0xf0)
|
|
||||||
{
|
|
||||||
if( (p[0] & 0x07) >= 0x05 // invalid F5...FF characters
|
|
||||||
|| (p[1] & 0xc0) != 0x80
|
|
||||||
|| (p[2] & 0xc0) != 0x80
|
|
||||||
|| (p[3] & 0xc0) != 0x80
|
|
||||||
|| (p[0] == 0xf0 && (p[1] & 0x30) == 0) // overlong
|
|
||||||
|| (p[0] == 0xf4 && p[1] > 0x8f) || p[0] > 0xf4 // > U+10FFFF
|
|
||||||
)
|
|
||||||
return false;
|
|
||||||
p += 4;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
auto const fail_fast =
|
|
||||||
[&]()
|
|
||||||
{
|
|
||||||
if(cp_[0] < 128)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto& p = cp_; // alias, only to keep this code similar to valid() above
|
|
||||||
const auto known_only = p_ - cp_;
|
|
||||||
if (known_only == 1)
|
|
||||||
{
|
|
||||||
if((p[0] & 0xe0) == 0xc0)
|
|
||||||
{
|
|
||||||
return ((p[0] & 0x1e) == 0); // overlong
|
|
||||||
}
|
|
||||||
if((p[0] & 0xf0) == 0xe0)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if((p[0] & 0xf8) == 0xf0)
|
|
||||||
{
|
|
||||||
return ((p[0] & 0x07) >= 0x05); // invalid F5...FF characters
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (known_only == 2)
|
|
||||||
{
|
|
||||||
if((p[0] & 0xe0) == 0xc0)
|
|
||||||
{
|
|
||||||
return ((p[1] & 0xc0) != 0x80 ||
|
|
||||||
(p[0] & 0x1e) == 0); // overlong
|
|
||||||
}
|
|
||||||
if((p[0] & 0xf0) == 0xe0)
|
|
||||||
{
|
|
||||||
return ( (p[1] & 0xc0) != 0x80
|
|
||||||
|| (p[0] == 0xe0 && (p[1] & 0x20) == 0) // overlong
|
|
||||||
|| (p[0] == 0xed && (p[1] & 0x20) == 0x20)); // surrogate
|
|
||||||
}
|
|
||||||
if((p[0] & 0xf8) == 0xf0)
|
|
||||||
{
|
|
||||||
return ( (p[0] & 0x07) >= 0x05 // invalid F5...FF characters
|
|
||||||
|| (p[1] & 0xc0) != 0x80
|
|
||||||
|| (p[0] == 0xf0 && (p[1] & 0x30) == 0) // overlong
|
|
||||||
|| (p[0] == 0xf4 && p[1] > 0x8f) || p[0] > 0xf4); // > U+10FFFF
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (known_only == 3)
|
|
||||||
{
|
|
||||||
if((p[0] & 0xe0) == 0xc0)
|
|
||||||
{
|
|
||||||
return ( (p[1] & 0xc0) != 0x80
|
|
||||||
|| (p[0] & 0x1e) == 0); // overlong
|
|
||||||
}
|
|
||||||
if((p[0] & 0xf0) == 0xe0)
|
|
||||||
{
|
|
||||||
return ( (p[1] & 0xc0) != 0x80
|
|
||||||
|| (p[2] & 0xc0) != 0x80
|
|
||||||
|| (p[0] == 0xe0 && (p[1] & 0x20) == 0) // overlong
|
|
||||||
|| (p[0] == 0xed && (p[1] & 0x20) == 0x20)); // surrogate
|
|
||||||
//|| (p[0] == 0xef && p[1] == 0xbf && (p[2] & 0xfe) == 0xbe) // U+FFFE or U+FFFF
|
|
||||||
}
|
|
||||||
if((p[0] & 0xf8) == 0xf0)
|
|
||||||
{
|
|
||||||
return ( (p[0] & 0x07) >= 0x05 // invalid F5...FF characters
|
|
||||||
|| (p[1] & 0xc0) != 0x80
|
|
||||||
|| (p[2] & 0xc0) != 0x80
|
|
||||||
|| (p[0] == 0xf0 && (p[1] & 0x30) == 0) // overlong
|
|
||||||
|| (p[0] == 0xf4 && p[1] > 0x8f) || p[0] > 0xf4); // > U+10FFFF
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
auto const needed =
|
|
||||||
[](std::uint8_t const v)
|
|
||||||
{
|
|
||||||
if(v < 128)
|
|
||||||
return 1;
|
|
||||||
if(v < 192)
|
|
||||||
return 0;
|
|
||||||
if(v < 224)
|
|
||||||
return 2;
|
|
||||||
if(v < 240)
|
|
||||||
return 3;
|
|
||||||
if(v < 248)
|
|
||||||
return 4;
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto const end = in + size;
|
|
||||||
|
|
||||||
// Finish up any incomplete code point
|
|
||||||
if(need_ > 0)
|
|
||||||
{
|
|
||||||
// Calculate what we have
|
|
||||||
auto n = (std::min)(size, need_);
|
|
||||||
size -= n;
|
|
||||||
need_ -= n;
|
|
||||||
|
|
||||||
// Add characters to the code point
|
|
||||||
while(n--)
|
|
||||||
*p_++ = *in++;
|
|
||||||
BOOST_ASSERT(p_ <= cp_ + 4);
|
|
||||||
|
|
||||||
// Still incomplete?
|
|
||||||
if(need_ > 0)
|
|
||||||
{
|
|
||||||
// Incomplete code point
|
|
||||||
BOOST_ASSERT(in == end);
|
|
||||||
|
|
||||||
// Do partial validation on the incomplete
|
|
||||||
// code point, this is called "Fail fast"
|
|
||||||
// in Autobahn|Testsuite parlance.
|
|
||||||
return ! fail_fast();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Complete code point, validate it
|
|
||||||
std::uint8_t const* p = &cp_[0];
|
|
||||||
if(! valid(p))
|
|
||||||
return false;
|
|
||||||
p_ = cp_;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(size <= sizeof(std::size_t))
|
|
||||||
goto slow;
|
|
||||||
|
|
||||||
// Align `in` to sizeof(std::size_t) boundary
|
|
||||||
{
|
|
||||||
auto const in0 = in;
|
|
||||||
auto last = reinterpret_cast<std::uint8_t const*>(
|
|
||||||
((reinterpret_cast<std::uintptr_t>(in) + sizeof(std::size_t) - 1) /
|
|
||||||
sizeof(std::size_t)) * sizeof(std::size_t));
|
|
||||||
|
|
||||||
// Check one character at a time for low-ASCII
|
|
||||||
while(in < last)
|
|
||||||
{
|
|
||||||
if(*in & 0x80)
|
|
||||||
{
|
|
||||||
// Not low-ASCII so switch to slow loop
|
|
||||||
size = size - (in - in0);
|
|
||||||
goto slow;
|
|
||||||
}
|
|
||||||
++in;
|
|
||||||
}
|
|
||||||
size = size - (in - in0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fast loop: Process 4 or 8 low-ASCII characters at a time
|
|
||||||
{
|
|
||||||
auto const in0 = in;
|
|
||||||
auto last = in + size - 7;
|
|
||||||
auto constexpr mask = static_cast<
|
|
||||||
std::size_t>(0x8080808080808080 & ~std::size_t{0});
|
|
||||||
while(in < last)
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
std::size_t temp;
|
|
||||||
std::memcpy(&temp, in, sizeof(temp));
|
|
||||||
if((temp & mask) != 0)
|
|
||||||
#else
|
|
||||||
// Technically UB but works on all known platforms
|
|
||||||
if((*reinterpret_cast<std::size_t const*>(in) & mask) != 0)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
size = size - (in - in0);
|
|
||||||
goto slow;
|
|
||||||
}
|
|
||||||
in += sizeof(std::size_t);
|
|
||||||
}
|
|
||||||
// There's at least one more full code point left
|
|
||||||
last += 4;
|
|
||||||
while(in < last)
|
|
||||||
if(! valid(in))
|
|
||||||
return false;
|
|
||||||
goto tail;
|
|
||||||
}
|
|
||||||
|
|
||||||
slow:
|
|
||||||
// Slow loop: Full validation on one code point at a time
|
|
||||||
{
|
|
||||||
auto last = in + size - 3;
|
|
||||||
while(in < last)
|
|
||||||
if(! valid(in))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
tail:
|
|
||||||
// Handle the remaining bytes. The last
|
|
||||||
// characters could split a code point so
|
|
||||||
// we save the partial code point for later.
|
|
||||||
//
|
|
||||||
// On entry to the loop, `in` points to the
|
|
||||||
// beginning of a code point.
|
|
||||||
//
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
// Number of chars left
|
|
||||||
auto n = end - in;
|
|
||||||
if(! n)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Chars we need to finish this code point
|
|
||||||
auto const need = needed(*in);
|
|
||||||
if(need == 0)
|
|
||||||
return false;
|
|
||||||
if(need <= n)
|
|
||||||
{
|
|
||||||
// Check a whole code point
|
|
||||||
if(! valid(in))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Calculate how many chars we need
|
|
||||||
// to finish this partial code point
|
|
||||||
need_ = need - n;
|
|
||||||
|
|
||||||
// Save the partial code point
|
|
||||||
while(n--)
|
|
||||||
*p_++ = *in++;
|
|
||||||
BOOST_ASSERT(in == end);
|
|
||||||
BOOST_ASSERT(p_ <= cp_ + 4);
|
|
||||||
|
|
||||||
// Do partial validation on the incomplete
|
|
||||||
// code point, this is called "Fail fast"
|
|
||||||
// in Autobahn|Testsuite parlance.
|
|
||||||
return ! fail_fast();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
using utf8_checker = utf8_checker_t<>;
|
|
||||||
|
|
||||||
template<class = void>
|
|
||||||
bool
|
|
||||||
check_utf8(char const* p, std::size_t n)
|
|
||||||
{
|
|
||||||
utf8_checker c;
|
|
||||||
if(! c.write(reinterpret_cast<const uint8_t*>(p), n))
|
|
||||||
return false;
|
|
||||||
return c.finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // detail
|
} // detail
|
||||||
} // websocket
|
} // websocket
|
||||||
} // beast
|
} // beast
|
||||||
} // boost
|
} // boost
|
||||||
|
|
||||||
|
#if BOOST_BEAST_HEADER_ONLY
|
||||||
|
#include <boost/beast/websocket/detail/utf8_checker.ipp>
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
331
include/boost/beast/websocket/detail/utf8_checker.ipp
Normal file
331
include/boost/beast/websocket/detail/utf8_checker.ipp
Normal file
@@ -0,0 +1,331 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2016-2019 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)
|
||||||
|
//
|
||||||
|
// Official repository: https://github.com/boostorg/beast
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef BOOST_BEAST_WEBSOCKET_DETAIL_UTF8_CHECKER_IPP
|
||||||
|
#define BOOST_BEAST_WEBSOCKET_DETAIL_UTF8_CHECKER_IPP
|
||||||
|
|
||||||
|
#include <boost/beast/websocket/detail/utf8_checker.hpp>
|
||||||
|
|
||||||
|
#include <boost/assert.hpp>
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
namespace beast {
|
||||||
|
namespace websocket {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
void
|
||||||
|
utf8_checker::
|
||||||
|
reset()
|
||||||
|
{
|
||||||
|
need_ = 0;
|
||||||
|
p_ = cp_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
utf8_checker::
|
||||||
|
finish()
|
||||||
|
{
|
||||||
|
auto const success = need_ == 0;
|
||||||
|
reset();
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
utf8_checker::
|
||||||
|
write(std::uint8_t const* in, std::size_t size)
|
||||||
|
{
|
||||||
|
auto const valid =
|
||||||
|
[](std::uint8_t const*& p)
|
||||||
|
{
|
||||||
|
if(p[0] < 128)
|
||||||
|
{
|
||||||
|
++p;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if((p[0] & 0xe0) == 0xc0)
|
||||||
|
{
|
||||||
|
if( (p[1] & 0xc0) != 0x80 ||
|
||||||
|
(p[0] & 0x1e) == 0) // overlong
|
||||||
|
return false;
|
||||||
|
p += 2;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if((p[0] & 0xf0) == 0xe0)
|
||||||
|
{
|
||||||
|
if( (p[1] & 0xc0) != 0x80
|
||||||
|
|| (p[2] & 0xc0) != 0x80
|
||||||
|
|| (p[0] == 0xe0 && (p[1] & 0x20) == 0) // overlong
|
||||||
|
|| (p[0] == 0xed && (p[1] & 0x20) == 0x20) // surrogate
|
||||||
|
//|| (p[0] == 0xef && p[1] == 0xbf && (p[2] & 0xfe) == 0xbe) // U+FFFE or U+FFFF
|
||||||
|
)
|
||||||
|
return false;
|
||||||
|
p += 3;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if((p[0] & 0xf8) == 0xf0)
|
||||||
|
{
|
||||||
|
if( (p[0] & 0x07) >= 0x05 // invalid F5...FF characters
|
||||||
|
|| (p[1] & 0xc0) != 0x80
|
||||||
|
|| (p[2] & 0xc0) != 0x80
|
||||||
|
|| (p[3] & 0xc0) != 0x80
|
||||||
|
|| (p[0] == 0xf0 && (p[1] & 0x30) == 0) // overlong
|
||||||
|
|| (p[0] == 0xf4 && p[1] > 0x8f) || p[0] > 0xf4 // > U+10FFFF
|
||||||
|
)
|
||||||
|
return false;
|
||||||
|
p += 4;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
auto const fail_fast =
|
||||||
|
[&]()
|
||||||
|
{
|
||||||
|
if(cp_[0] < 128)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& p = cp_; // alias, only to keep this code similar to valid() above
|
||||||
|
const auto known_only = p_ - cp_;
|
||||||
|
if (known_only == 1)
|
||||||
|
{
|
||||||
|
if((p[0] & 0xe0) == 0xc0)
|
||||||
|
{
|
||||||
|
return ((p[0] & 0x1e) == 0); // overlong
|
||||||
|
}
|
||||||
|
if((p[0] & 0xf0) == 0xe0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if((p[0] & 0xf8) == 0xf0)
|
||||||
|
{
|
||||||
|
return ((p[0] & 0x07) >= 0x05); // invalid F5...FF characters
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (known_only == 2)
|
||||||
|
{
|
||||||
|
if((p[0] & 0xe0) == 0xc0)
|
||||||
|
{
|
||||||
|
return ((p[1] & 0xc0) != 0x80 ||
|
||||||
|
(p[0] & 0x1e) == 0); // overlong
|
||||||
|
}
|
||||||
|
if((p[0] & 0xf0) == 0xe0)
|
||||||
|
{
|
||||||
|
return ( (p[1] & 0xc0) != 0x80
|
||||||
|
|| (p[0] == 0xe0 && (p[1] & 0x20) == 0) // overlong
|
||||||
|
|| (p[0] == 0xed && (p[1] & 0x20) == 0x20)); // surrogate
|
||||||
|
}
|
||||||
|
if((p[0] & 0xf8) == 0xf0)
|
||||||
|
{
|
||||||
|
return ( (p[0] & 0x07) >= 0x05 // invalid F5...FF characters
|
||||||
|
|| (p[1] & 0xc0) != 0x80
|
||||||
|
|| (p[0] == 0xf0 && (p[1] & 0x30) == 0) // overlong
|
||||||
|
|| (p[0] == 0xf4 && p[1] > 0x8f) || p[0] > 0xf4); // > U+10FFFF
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (known_only == 3)
|
||||||
|
{
|
||||||
|
if((p[0] & 0xe0) == 0xc0)
|
||||||
|
{
|
||||||
|
return ( (p[1] & 0xc0) != 0x80
|
||||||
|
|| (p[0] & 0x1e) == 0); // overlong
|
||||||
|
}
|
||||||
|
if((p[0] & 0xf0) == 0xe0)
|
||||||
|
{
|
||||||
|
return ( (p[1] & 0xc0) != 0x80
|
||||||
|
|| (p[2] & 0xc0) != 0x80
|
||||||
|
|| (p[0] == 0xe0 && (p[1] & 0x20) == 0) // overlong
|
||||||
|
|| (p[0] == 0xed && (p[1] & 0x20) == 0x20)); // surrogate
|
||||||
|
//|| (p[0] == 0xef && p[1] == 0xbf && (p[2] & 0xfe) == 0xbe) // U+FFFE or U+FFFF
|
||||||
|
}
|
||||||
|
if((p[0] & 0xf8) == 0xf0)
|
||||||
|
{
|
||||||
|
return ( (p[0] & 0x07) >= 0x05 // invalid F5...FF characters
|
||||||
|
|| (p[1] & 0xc0) != 0x80
|
||||||
|
|| (p[2] & 0xc0) != 0x80
|
||||||
|
|| (p[0] == 0xf0 && (p[1] & 0x30) == 0) // overlong
|
||||||
|
|| (p[0] == 0xf4 && p[1] > 0x8f) || p[0] > 0xf4); // > U+10FFFF
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
auto const needed =
|
||||||
|
[](std::uint8_t const v)
|
||||||
|
{
|
||||||
|
if(v < 128)
|
||||||
|
return 1;
|
||||||
|
if(v < 192)
|
||||||
|
return 0;
|
||||||
|
if(v < 224)
|
||||||
|
return 2;
|
||||||
|
if(v < 240)
|
||||||
|
return 3;
|
||||||
|
if(v < 248)
|
||||||
|
return 4;
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto const end = in + size;
|
||||||
|
|
||||||
|
// Finish up any incomplete code point
|
||||||
|
if(need_ > 0)
|
||||||
|
{
|
||||||
|
// Calculate what we have
|
||||||
|
auto n = (std::min)(size, need_);
|
||||||
|
size -= n;
|
||||||
|
need_ -= n;
|
||||||
|
|
||||||
|
// Add characters to the code point
|
||||||
|
while(n--)
|
||||||
|
*p_++ = *in++;
|
||||||
|
BOOST_ASSERT(p_ <= cp_ + 4);
|
||||||
|
|
||||||
|
// Still incomplete?
|
||||||
|
if(need_ > 0)
|
||||||
|
{
|
||||||
|
// Incomplete code point
|
||||||
|
BOOST_ASSERT(in == end);
|
||||||
|
|
||||||
|
// Do partial validation on the incomplete
|
||||||
|
// code point, this is called "Fail fast"
|
||||||
|
// in Autobahn|Testsuite parlance.
|
||||||
|
return ! fail_fast();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Complete code point, validate it
|
||||||
|
std::uint8_t const* p = &cp_[0];
|
||||||
|
if(! valid(p))
|
||||||
|
return false;
|
||||||
|
p_ = cp_;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(size <= sizeof(std::size_t))
|
||||||
|
goto slow;
|
||||||
|
|
||||||
|
// Align `in` to sizeof(std::size_t) boundary
|
||||||
|
{
|
||||||
|
auto const in0 = in;
|
||||||
|
auto last = reinterpret_cast<std::uint8_t const*>(
|
||||||
|
((reinterpret_cast<std::uintptr_t>(in) + sizeof(std::size_t) - 1) /
|
||||||
|
sizeof(std::size_t)) * sizeof(std::size_t));
|
||||||
|
|
||||||
|
// Check one character at a time for low-ASCII
|
||||||
|
while(in < last)
|
||||||
|
{
|
||||||
|
if(*in & 0x80)
|
||||||
|
{
|
||||||
|
// Not low-ASCII so switch to slow loop
|
||||||
|
size = size - (in - in0);
|
||||||
|
goto slow;
|
||||||
|
}
|
||||||
|
++in;
|
||||||
|
}
|
||||||
|
size = size - (in - in0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fast loop: Process 4 or 8 low-ASCII characters at a time
|
||||||
|
{
|
||||||
|
auto const in0 = in;
|
||||||
|
auto last = in + size - 7;
|
||||||
|
auto constexpr mask = static_cast<
|
||||||
|
std::size_t>(0x8080808080808080 & ~std::size_t{0});
|
||||||
|
while(in < last)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
std::size_t temp;
|
||||||
|
std::memcpy(&temp, in, sizeof(temp));
|
||||||
|
if((temp & mask) != 0)
|
||||||
|
#else
|
||||||
|
// Technically UB but works on all known platforms
|
||||||
|
if((*reinterpret_cast<std::size_t const*>(in) & mask) != 0)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
size = size - (in - in0);
|
||||||
|
goto slow;
|
||||||
|
}
|
||||||
|
in += sizeof(std::size_t);
|
||||||
|
}
|
||||||
|
// There's at least one more full code point left
|
||||||
|
last += 4;
|
||||||
|
while(in < last)
|
||||||
|
if(! valid(in))
|
||||||
|
return false;
|
||||||
|
goto tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
slow:
|
||||||
|
// Slow loop: Full validation on one code point at a time
|
||||||
|
{
|
||||||
|
auto last = in + size - 3;
|
||||||
|
while(in < last)
|
||||||
|
if(! valid(in))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
tail:
|
||||||
|
// Handle the remaining bytes. The last
|
||||||
|
// characters could split a code point so
|
||||||
|
// we save the partial code point for later.
|
||||||
|
//
|
||||||
|
// On entry to the loop, `in` points to the
|
||||||
|
// beginning of a code point.
|
||||||
|
//
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
// Number of chars left
|
||||||
|
auto n = end - in;
|
||||||
|
if(! n)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Chars we need to finish this code point
|
||||||
|
auto const need = needed(*in);
|
||||||
|
if(need == 0)
|
||||||
|
return false;
|
||||||
|
if(need <= n)
|
||||||
|
{
|
||||||
|
// Check a whole code point
|
||||||
|
if(! valid(in))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Calculate how many chars we need
|
||||||
|
// to finish this partial code point
|
||||||
|
need_ = need - n;
|
||||||
|
|
||||||
|
// Save the partial code point
|
||||||
|
while(n--)
|
||||||
|
*p_++ = *in++;
|
||||||
|
BOOST_ASSERT(in == end);
|
||||||
|
BOOST_ASSERT(p_ <= cp_ + 4);
|
||||||
|
|
||||||
|
// Do partial validation on the incomplete
|
||||||
|
// code point, this is called "Fail fast"
|
||||||
|
// in Autobahn|Testsuite parlance.
|
||||||
|
return ! fail_fast();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
check_utf8(char const* p, std::size_t n)
|
||||||
|
{
|
||||||
|
utf8_checker c;
|
||||||
|
if(! c.write(reinterpret_cast<const uint8_t*>(p), n))
|
||||||
|
return false;
|
||||||
|
return c.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // detail
|
||||||
|
} // websocket
|
||||||
|
} // beast
|
||||||
|
} // boost
|
||||||
|
|
||||||
|
#endif // BOOST_BEAST_WEBSOCKET_DETAIL_UTF8_CHECKER_IPP
|
@@ -19,6 +19,7 @@
|
|||||||
#include <boost/beast/core/buffers_prefix.hpp>
|
#include <boost/beast/core/buffers_prefix.hpp>
|
||||||
#include <boost/beast/core/buffers_suffix.hpp>
|
#include <boost/beast/core/buffers_suffix.hpp>
|
||||||
#include <boost/beast/core/flat_static_buffer.hpp>
|
#include <boost/beast/core/flat_static_buffer.hpp>
|
||||||
|
#include <boost/beast/core/read_size.hpp>
|
||||||
#include <boost/beast/core/stream_traits.hpp>
|
#include <boost/beast/core/stream_traits.hpp>
|
||||||
#include <boost/beast/core/detail/bind_continuation.hpp>
|
#include <boost/beast/core/detail/bind_continuation.hpp>
|
||||||
#include <boost/beast/core/detail/buffer.hpp>
|
#include <boost/beast/core/detail/buffer.hpp>
|
||||||
|
@@ -19,6 +19,7 @@
|
|||||||
#include <boost/beast/websocket/detail/hybi13.hpp>
|
#include <boost/beast/websocket/detail/hybi13.hpp>
|
||||||
#include <boost/beast/websocket/detail/impl_base.hpp>
|
#include <boost/beast/websocket/detail/impl_base.hpp>
|
||||||
#include <boost/beast/websocket/detail/pmd_extension.hpp>
|
#include <boost/beast/websocket/detail/pmd_extension.hpp>
|
||||||
|
#include <boost/beast/websocket/detail/prng.hpp>
|
||||||
#include <boost/beast/core/role.hpp>
|
#include <boost/beast/core/role.hpp>
|
||||||
#include <boost/beast/core/stream_traits.hpp>
|
#include <boost/beast/core/stream_traits.hpp>
|
||||||
#include <boost/beast/core/string.hpp>
|
#include <boost/beast/core/string.hpp>
|
||||||
@@ -33,6 +34,7 @@
|
|||||||
#include <limits>
|
#include <limits>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
namespace boost {
|
namespace boost {
|
||||||
namespace beast {
|
namespace beast {
|
||||||
|
Reference in New Issue
Block a user