mirror of
https://github.com/boostorg/beast.git
synced 2025-07-30 12:57:31 +02:00
WebSocket refactoring and tests:
websocket: * Move echo server to test/ * Fix warnings * Fix maskgen being uncopyable * Simplify utf8_checker special member declarations * Fix stream move assignable when owning the next layer * Add javadocs for stream special members * Add stream unit tests * Move throwing member definitions to the .ipp file * Use get_lowest_layer in stream declaration * Perform type checks at each call site instead of constructor * Demote close_code to a non-class enum: Otherwise, application specific close codes cannot be assigned without using static_cast. core: * Add streambuf_readstream special members tests * Add move assignment operator to streambuf_readstream * Add detail/get_lowest_layer trait * Add static_string tests * Move static_string from websocket to core
This commit is contained in:
@ -8,6 +8,7 @@ set_property (GLOBAL PROPERTY USE_FOLDERS ON)
|
|||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /W4 /wd4100 /D_SCL_SECURE_NO_WARNINGS=1 /D_CRT_SECURE_NO_WARNINGS=1")
|
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /W4 /wd4100 /D_SCL_SECURE_NO_WARNINGS=1 /D_CRT_SECURE_NO_WARNINGS=1")
|
||||||
|
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO")
|
||||||
else()
|
else()
|
||||||
set(Boost_USE_STATIC_LIBS ON)
|
set(Boost_USE_STATIC_LIBS ON)
|
||||||
set(Boost_USE_MULTITHREADED ON)
|
set(Boost_USE_MULTITHREADED ON)
|
||||||
|
1
Jamroot
1
Jamroot
@ -51,6 +51,7 @@ project beast
|
|||||||
<include>./include
|
<include>./include
|
||||||
#<use>/boost//headers
|
#<use>/boost//headers
|
||||||
<library>/boost/system//boost_system
|
<library>/boost/system//boost_system
|
||||||
|
<library>/boost/coroutine//boost_coroutine
|
||||||
<library>/boost/filesystem//boost_filesystem
|
<library>/boost/filesystem//boost_filesystem
|
||||||
<library>/boost/program_options//boost_program_options
|
<library>/boost/program_options//boost_program_options
|
||||||
# <library>ssl
|
# <library>ssl
|
||||||
|
59
TODO.txt
59
TODO.txt
@ -1,28 +1,39 @@
|
|||||||
* Replace Jamroot with Jamfile
|
General:
|
||||||
* Complete allocator testing in basic_streambuf, basic_headers
|
* Use SFINAE on return values (search for "class =")
|
||||||
* Tidy up type_checks
|
|
||||||
- Derive from std::integral_constant
|
|
||||||
* Check DOXYGEN, GENERATIC_DOCS directives in source
|
|
||||||
- See if we can include them now that xsl is fixed
|
|
||||||
* Make buffers_debug a detail
|
|
||||||
* Define Parser concept in HTTP
|
|
||||||
* melpon sandbox?
|
|
||||||
* invokable unit test
|
|
||||||
* trim public interface of rfc2616.h to essentials only
|
|
||||||
* Fix index in docs
|
|
||||||
* Figure out why namespace rfc2616 is included in docs
|
|
||||||
(currently disabled via GENERATING_DOCS macro)
|
|
||||||
* Include Example program listings in the docs
|
|
||||||
* Update for rfc7230
|
|
||||||
* HTTP parser size limit with test (configurable?)
|
|
||||||
* HTTP parser trailers with test
|
|
||||||
* URL parser, strong URL checking in HTTP parser
|
|
||||||
* More fine grained parser errors
|
|
||||||
* Fix bidirectional buffers iterators operator->()
|
|
||||||
* http type_check, e.g. is_WritableBody
|
|
||||||
* add bool should_close(message_v1 const&) to replace the use
|
|
||||||
of eof return value from write and async_write
|
|
||||||
|
|
||||||
Boost.Http
|
Boost.Http
|
||||||
* Use enum instead of bool in isRequest
|
* Use enum instead of bool in isRequest
|
||||||
* move version to a subclass of message
|
* move version to a subclass of message
|
||||||
|
|
||||||
|
Docs:
|
||||||
|
* Include Example program listings in the docs
|
||||||
|
* Fix index in docs
|
||||||
|
* Figure out why namespace rfc2616 is included in docs
|
||||||
|
(currently disabled via GENERATING_DOCS macro)
|
||||||
|
* melpon sandbox?
|
||||||
|
* Check DOXYGEN, GENERATIC_DOCS directives in source
|
||||||
|
- See if we can include them now that xsl is fixed
|
||||||
|
|
||||||
|
Core:
|
||||||
|
* Replace Jamroot with Jamfile
|
||||||
|
* Fix bidirectional buffers iterators operator->()
|
||||||
|
* Tidy up type_checks
|
||||||
|
- Derive from std::integral_constant
|
||||||
|
* Complete allocator testing in basic_streambuf, basic_headers
|
||||||
|
|
||||||
|
WebSocket:
|
||||||
|
* optimized versions of key/masking, choose prepared_key size
|
||||||
|
* invokable unit test
|
||||||
|
* Finish up all of static_string including tests
|
||||||
|
|
||||||
|
HTTP:
|
||||||
|
* Define Parser concept in HTTP
|
||||||
|
* trim public interface of rfc2616.h to essentials only
|
||||||
|
* add bool should_close(message_v1 const&) to replace the use
|
||||||
|
of eof return value from write and async_write
|
||||||
|
* http type_check, e.g. is_WritableBody
|
||||||
|
* More fine grained parser errors
|
||||||
|
* HTTP parser size limit with test (configurable?)
|
||||||
|
* HTTP parser trailers with test
|
||||||
|
* URL parser, strong URL checking in HTTP parser
|
||||||
|
* Update for rfc7230
|
||||||
|
@ -138,13 +138,14 @@
|
|||||||
<simplelist type="vert" columns="1">
|
<simplelist type="vert" columns="1">
|
||||||
<member><link linkend="beast.ref.is_AsyncReadStream">is_AsyncReadStream</link></member>
|
<member><link linkend="beast.ref.is_AsyncReadStream">is_AsyncReadStream</link></member>
|
||||||
<member><link linkend="beast.ref.is_AsyncWriteStream">is_AsyncWriteStream</link></member>
|
<member><link linkend="beast.ref.is_AsyncWriteStream">is_AsyncWriteStream</link></member>
|
||||||
|
<member><link linkend="beast.ref.is_AsyncStream">is_AsyncStream</link></member>
|
||||||
<member><link linkend="beast.ref.is_BufferSequence">is_BufferSequence</link></member>
|
<member><link linkend="beast.ref.is_BufferSequence">is_BufferSequence</link></member>
|
||||||
<member><link linkend="beast.ref.is_ConstBufferSequence">is_ConstBufferSequence</link></member>
|
<member><link linkend="beast.ref.is_ConstBufferSequence">is_ConstBufferSequence</link></member>
|
||||||
<member><link linkend="beast.ref.is_Handler">is_Handler</link></member>
|
<member><link linkend="beast.ref.is_Handler">is_Handler</link></member>
|
||||||
<member><link linkend="beast.ref.is_MutableBufferSequence">is_MutableBufferSequence</link></member>
|
<member><link linkend="beast.ref.is_MutableBufferSequence">is_MutableBufferSequence</link></member>
|
||||||
<member><link linkend="beast.ref.is_Stream">is_Stream</link></member>
|
|
||||||
<member><link linkend="beast.ref.is_Streambuf">is_Streambuf</link></member>
|
<member><link linkend="beast.ref.is_Streambuf">is_Streambuf</link></member>
|
||||||
<member><link linkend="beast.ref.is_SyncReadStream">is_SyncReadStream</link></member>
|
<member><link linkend="beast.ref.is_SyncReadStream">is_SyncReadStream</link></member>
|
||||||
|
<member><link linkend="beast.ref.is_SyncStream">is_SyncStream</link></member>
|
||||||
<member><link linkend="beast.ref.is_SyncWriteStream">is_SyncWriteStream</link></member>
|
<member><link linkend="beast.ref.is_SyncWriteStream">is_SyncWriteStream</link></member>
|
||||||
</simplelist>
|
</simplelist>
|
||||||
</entry>
|
</entry>
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
GroupSources(include/beast)
|
GroupSources(include/beast)
|
||||||
GroupSources(examples)
|
GroupSources(examples)
|
||||||
|
GroupSources(test)
|
||||||
|
|
||||||
add_executable (http-crawl
|
add_executable (http-crawl
|
||||||
${BEAST_INCLUDES}
|
${BEAST_INCLUDES}
|
||||||
@ -21,7 +22,7 @@ add_executable (http-server
|
|||||||
http_stream.hpp
|
http_stream.hpp
|
||||||
http_stream.ipp
|
http_stream.ipp
|
||||||
http_sync_server.hpp
|
http_sync_server.hpp
|
||||||
sig_wait.hpp
|
../test/sig_wait.hpp
|
||||||
http_server.cpp
|
http_server.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -38,18 +39,6 @@ if (NOT WIN32)
|
|||||||
target_link_libraries(http-example ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
target_link_libraries(http-example ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_executable (websocket-echo
|
|
||||||
${BEAST_INCLUDES}
|
|
||||||
sig_wait.hpp
|
|
||||||
websocket_async_echo_peer.hpp
|
|
||||||
websocket_sync_echo_peer.hpp
|
|
||||||
websocket_echo.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
if (NOT WIN32)
|
|
||||||
target_link_libraries(websocket-echo ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_executable (websocket-example
|
add_executable (websocket-example
|
||||||
${BEAST_INCLUDES}
|
${BEAST_INCLUDES}
|
||||||
websocket_example.cpp
|
websocket_example.cpp
|
||||||
|
@ -7,24 +7,20 @@
|
|||||||
|
|
||||||
import os ;
|
import os ;
|
||||||
|
|
||||||
exe http_crawl :
|
exe http-crawl :
|
||||||
http_crawl.cpp
|
http_crawl.cpp
|
||||||
urls_large_data.cpp
|
urls_large_data.cpp
|
||||||
;
|
;
|
||||||
|
|
||||||
exe http_server :
|
exe http-server :
|
||||||
http_server.cpp
|
http_server.cpp
|
||||||
;
|
;
|
||||||
|
|
||||||
exe http_example :
|
exe http-example :
|
||||||
http_example.cpp
|
http_example.cpp
|
||||||
;
|
;
|
||||||
|
|
||||||
exe websocket_echo :
|
exe websocket-example :
|
||||||
websocket_echo.cpp
|
|
||||||
;
|
|
||||||
|
|
||||||
exe websocket_example :
|
|
||||||
websocket_example.cpp
|
websocket_example.cpp
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#include "http_async_server.hpp"
|
#include "http_async_server.hpp"
|
||||||
#include "http_sync_server.hpp"
|
#include "http_sync_server.hpp"
|
||||||
#include "sig_wait.hpp"
|
#include "../test/sig_wait.hpp"
|
||||||
|
|
||||||
#include <boost/program_options.hpp>
|
#include <boost/program_options.hpp>
|
||||||
|
|
||||||
@ -69,13 +69,8 @@ int main(int ac, char const* av[])
|
|||||||
endpoint_type ep{address_type::from_string(ip), port};
|
endpoint_type ep{address_type::from_string(ip), port};
|
||||||
|
|
||||||
if(sync)
|
if(sync)
|
||||||
{
|
|
||||||
http_sync_server server(ep, root);
|
http_sync_server server(ep, root);
|
||||||
sig_wait();
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
http_async_server server(ep, threads, root);
|
http_async_server server(ep, threads, root);
|
||||||
sig_wait();
|
sig_wait();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
53
include/beast/detail/get_lowest_layer.hpp
Normal file
53
include/beast/detail/get_lowest_layer.hpp
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
//
|
||||||
|
// 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_DETAIL_GET_LOWEST_LAYER_HPP
|
||||||
|
#define BEAST_DETAIL_GET_LOWEST_LAYER_HPP
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
class has_lowest_layer
|
||||||
|
{
|
||||||
|
template<class U, class R =
|
||||||
|
typename U::lowest_layer_type>
|
||||||
|
static std::true_type check(int);
|
||||||
|
template<class>
|
||||||
|
static std::false_type check(...);
|
||||||
|
using type = decltype(check<T>(0));
|
||||||
|
public:
|
||||||
|
static bool constexpr value = type::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, bool B>
|
||||||
|
struct maybe_get_lowest_layer
|
||||||
|
{
|
||||||
|
using type = T;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct maybe_get_lowest_layer<T, true>
|
||||||
|
{
|
||||||
|
using type = typename T::lowest_layer_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
// If T has a nested type lowest_layer_type,
|
||||||
|
// returns that, else returns T.
|
||||||
|
template<class T>
|
||||||
|
struct get_lowest_layer
|
||||||
|
{
|
||||||
|
using type = typename maybe_get_lowest_layer<T,
|
||||||
|
has_lowest_layer<T>::value>::type;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // detail
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
@ -10,7 +10,6 @@
|
|||||||
|
|
||||||
#include <beast/bind_handler.hpp>
|
#include <beast/bind_handler.hpp>
|
||||||
#include <beast/handler_alloc.hpp>
|
#include <beast/handler_alloc.hpp>
|
||||||
#include <beast/type_check.hpp>
|
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
|
|
||||||
@ -158,8 +157,6 @@ streambuf_readstream<Stream, Streambuf>::
|
|||||||
streambuf_readstream(Args&&... args)
|
streambuf_readstream(Args&&... args)
|
||||||
: next_layer_(std::forward<Args>(args)...)
|
: next_layer_(std::forward<Args>(args)...)
|
||||||
{
|
{
|
||||||
static_assert(is_Stream<next_layer_type>::value,
|
|
||||||
"Stream requirements not met");
|
|
||||||
static_assert(is_Streambuf<Streambuf>::value,
|
static_assert(is_Streambuf<Streambuf>::value,
|
||||||
"Streambuf requirements not met");
|
"Streambuf requirements not met");
|
||||||
}
|
}
|
||||||
@ -173,6 +170,8 @@ async_write_some(ConstBufferSequence const& buffers,
|
|||||||
typename async_completion<
|
typename async_completion<
|
||||||
WriteHandler, void(error_code)>::result_type
|
WriteHandler, void(error_code)>::result_type
|
||||||
{
|
{
|
||||||
|
static_assert(is_AsyncWriteStream<next_layer_type>::value,
|
||||||
|
"AsyncWriteStream requirements not met");
|
||||||
static_assert(is_ConstBufferSequence<
|
static_assert(is_ConstBufferSequence<
|
||||||
ConstBufferSequence>::value,
|
ConstBufferSequence>::value,
|
||||||
"ConstBufferSequence requirements not met");
|
"ConstBufferSequence requirements not met");
|
||||||
@ -190,6 +189,8 @@ streambuf_readstream<Stream, Streambuf>::
|
|||||||
read_some(
|
read_some(
|
||||||
MutableBufferSequence const& buffers)
|
MutableBufferSequence const& buffers)
|
||||||
{
|
{
|
||||||
|
static_assert(is_SyncReadStream<next_layer_type>::value,
|
||||||
|
"SyncReadStream requirements not met");
|
||||||
static_assert(is_MutableBufferSequence<
|
static_assert(is_MutableBufferSequence<
|
||||||
MutableBufferSequence>::value,
|
MutableBufferSequence>::value,
|
||||||
"MutableBufferSequence requirements not met");
|
"MutableBufferSequence requirements not met");
|
||||||
@ -207,6 +208,8 @@ streambuf_readstream<Stream, Streambuf>::
|
|||||||
read_some(MutableBufferSequence const& buffers,
|
read_some(MutableBufferSequence const& buffers,
|
||||||
error_code& ec)
|
error_code& ec)
|
||||||
{
|
{
|
||||||
|
static_assert(is_SyncReadStream<next_layer_type>::value,
|
||||||
|
"SyncReadStream requirements not met");
|
||||||
static_assert(is_MutableBufferSequence<
|
static_assert(is_MutableBufferSequence<
|
||||||
MutableBufferSequence>::value,
|
MutableBufferSequence>::value,
|
||||||
"MutableBufferSequence requirements not met");
|
"MutableBufferSequence requirements not met");
|
||||||
@ -239,6 +242,8 @@ async_read_some(
|
|||||||
typename async_completion<
|
typename async_completion<
|
||||||
ReadHandler, void(error_code)>::result_type
|
ReadHandler, void(error_code)>::result_type
|
||||||
{
|
{
|
||||||
|
static_assert(is_AsyncReadStream<next_layer_type>::value,
|
||||||
|
"Stream requirements not met");
|
||||||
static_assert(is_MutableBufferSequence<
|
static_assert(is_MutableBufferSequence<
|
||||||
MutableBufferSequence>::value,
|
MutableBufferSequence>::value,
|
||||||
"MutableBufferSequence requirements not met");
|
"MutableBufferSequence requirements not met");
|
||||||
|
696
include/beast/static_string.hpp
Normal file
696
include/beast/static_string.hpp
Normal file
@ -0,0 +1,696 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_WEBSOCKET_STATIC_STRING_HPP
|
||||||
|
#define BEAST_WEBSOCKET_STATIC_STRING_HPP
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <iterator>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace websocket {
|
||||||
|
|
||||||
|
/** A string with a fixed-size storage area.
|
||||||
|
|
||||||
|
`static_string` objects behave like `std::string` except that
|
||||||
|
the storage is not dynamically allocated but rather fixed in
|
||||||
|
size.
|
||||||
|
|
||||||
|
These strings offer performance advantages when a protocol
|
||||||
|
imposes a natural small upper limit on the size of a value.
|
||||||
|
|
||||||
|
@note The stored string is always null-terminated.
|
||||||
|
*/
|
||||||
|
template<
|
||||||
|
std::size_t N,
|
||||||
|
class CharT = char,
|
||||||
|
class Traits = std::char_traits<CharT>>
|
||||||
|
class static_string
|
||||||
|
{
|
||||||
|
template<std::size_t, class, class>
|
||||||
|
friend class static_string;
|
||||||
|
|
||||||
|
std::size_t n_;
|
||||||
|
std::array<CharT, N+1> s_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using traits_type = Traits;
|
||||||
|
using value_type = typename Traits::char_type;
|
||||||
|
using size_type = std::size_t;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using pointer = value_type*;
|
||||||
|
using reference = value_type&;
|
||||||
|
using const_pointer = value_type const*;
|
||||||
|
using const_reference = value_type const&;
|
||||||
|
using iterator = value_type*;
|
||||||
|
using const_iterator = value_type const*;
|
||||||
|
using reverse_iterator =
|
||||||
|
std::reverse_iterator<iterator>;
|
||||||
|
using const_reverse_iterator =
|
||||||
|
std::reverse_iterator<const_iterator>;
|
||||||
|
|
||||||
|
/** Default constructor.
|
||||||
|
|
||||||
|
The string is initially empty, and null terminated.
|
||||||
|
*/
|
||||||
|
static_string();
|
||||||
|
|
||||||
|
/// Copy constructor.
|
||||||
|
static_string(static_string const& s);
|
||||||
|
|
||||||
|
/// Copy constructor.
|
||||||
|
template<std::size_t M>
|
||||||
|
static_string(static_string<M, CharT, Traits> const& s);
|
||||||
|
|
||||||
|
/// Copy assignment.
|
||||||
|
static_string&
|
||||||
|
operator=(static_string const& s);
|
||||||
|
|
||||||
|
/// Copy assignment.
|
||||||
|
template<std::size_t M>
|
||||||
|
static_string&
|
||||||
|
operator=(static_string<M, CharT, Traits> const& s);
|
||||||
|
|
||||||
|
/// Construct from string literal.
|
||||||
|
template<std::size_t M>
|
||||||
|
static_string(const CharT (&s)[M]);
|
||||||
|
|
||||||
|
/// Assign from string literal.
|
||||||
|
template<std::size_t M>
|
||||||
|
static_string& operator=(const CharT (&s)[M]);
|
||||||
|
|
||||||
|
/// Access specified character with bounds checking.
|
||||||
|
reference
|
||||||
|
at(size_type pos);
|
||||||
|
|
||||||
|
/// Access specified character with bounds checking.
|
||||||
|
const_reference
|
||||||
|
at(size_type pos) const;
|
||||||
|
|
||||||
|
/// Access specified character.
|
||||||
|
reference
|
||||||
|
operator[](size_type pos)
|
||||||
|
{
|
||||||
|
return s_[pos];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Access specified character.
|
||||||
|
const_reference
|
||||||
|
operator[](size_type pos) const
|
||||||
|
{
|
||||||
|
return s_[pos];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Accesses the first character.
|
||||||
|
CharT&
|
||||||
|
front()
|
||||||
|
{
|
||||||
|
return s_[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Accesses the first character.
|
||||||
|
CharT const&
|
||||||
|
front() const
|
||||||
|
{
|
||||||
|
return s_[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Accesses the last character.
|
||||||
|
CharT&
|
||||||
|
back()
|
||||||
|
{
|
||||||
|
return s_[n_-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Accesses the last character.
|
||||||
|
CharT const&
|
||||||
|
back() const
|
||||||
|
{
|
||||||
|
return s_[n_-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a pointer to the first character of a string.
|
||||||
|
CharT*
|
||||||
|
data()
|
||||||
|
{
|
||||||
|
return &s_[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a pointer to the first character of a string.
|
||||||
|
CharT const*
|
||||||
|
data() const
|
||||||
|
{
|
||||||
|
return &s_[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a non-modifiable standard C character array version of the string.
|
||||||
|
CharT const*
|
||||||
|
c_str() const
|
||||||
|
{
|
||||||
|
return &s_[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an iterator to the beginning.
|
||||||
|
iterator
|
||||||
|
begin()
|
||||||
|
{
|
||||||
|
return &s_[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an iterator to the beginning.
|
||||||
|
const_iterator
|
||||||
|
begin() const
|
||||||
|
{
|
||||||
|
return &s_[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an iterator to the beginning.
|
||||||
|
const_iterator
|
||||||
|
cbegin() const
|
||||||
|
{
|
||||||
|
return &s_[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an iterator to the end.
|
||||||
|
iterator
|
||||||
|
end()
|
||||||
|
{
|
||||||
|
return &s_[n_];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an iterator to the end.
|
||||||
|
const_iterator
|
||||||
|
end() const
|
||||||
|
{
|
||||||
|
return &s_[n_];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an iterator to the end.
|
||||||
|
const_iterator
|
||||||
|
cend() const
|
||||||
|
{
|
||||||
|
return &s_[n_];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a reverse iterator to the beginning.
|
||||||
|
reverse_iterator
|
||||||
|
rbegin()
|
||||||
|
{
|
||||||
|
return reverse_iterator{end()};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a reverse iterator to the beginning.
|
||||||
|
const_reverse_iterator
|
||||||
|
rbegin() const
|
||||||
|
{
|
||||||
|
return const_reverse_iterator{cend()};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a reverse iterator to the beginning.
|
||||||
|
const_reverse_iterator
|
||||||
|
crbegin() const
|
||||||
|
{
|
||||||
|
return const_reverse_iterator{cend()};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a reverse iterator to the end.
|
||||||
|
reverse_iterator
|
||||||
|
rend()
|
||||||
|
{
|
||||||
|
return reverse_iterator{begin()};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a reverse iterator to the end.
|
||||||
|
const_reverse_iterator
|
||||||
|
rend() const
|
||||||
|
{
|
||||||
|
return const_reverse_iterator{cbegin()};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a reverse iterator to the end.
|
||||||
|
const_reverse_iterator
|
||||||
|
crend() const
|
||||||
|
{
|
||||||
|
return const_reverse_iterator{cbegin()};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if the string is empty.
|
||||||
|
bool
|
||||||
|
empty() const
|
||||||
|
{
|
||||||
|
return n_ == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the number of characters, excluding the null terminator.
|
||||||
|
size_type
|
||||||
|
size() const
|
||||||
|
{
|
||||||
|
return n_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the maximum number of characters that can be stored, excluding the null terminator.
|
||||||
|
size_type constexpr
|
||||||
|
max_size() const
|
||||||
|
{
|
||||||
|
return N;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the number of characters that can be held in currently allocated storage.
|
||||||
|
size_type
|
||||||
|
capacity() const
|
||||||
|
{
|
||||||
|
return N;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reduces memory usage by freeing unused memory.
|
||||||
|
void
|
||||||
|
shrink_to_fit()
|
||||||
|
{
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clears the contents.
|
||||||
|
void
|
||||||
|
clear()
|
||||||
|
{
|
||||||
|
resize(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Changes the number of characters stored.
|
||||||
|
|
||||||
|
@note No value-initialization is performed.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
resize(std::size_t n);
|
||||||
|
|
||||||
|
/** Changes the number of characters stored.
|
||||||
|
|
||||||
|
If the resulting string is larger, the new
|
||||||
|
characters are initialized to the value of `c`.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
resize(std::size_t n, CharT c);
|
||||||
|
|
||||||
|
/// Compare two character sequences.
|
||||||
|
template<std::size_t M>
|
||||||
|
int compare(static_string<M, CharT, Traits> const& rhs) const;
|
||||||
|
|
||||||
|
/// Return the characters as a `basic_string`.
|
||||||
|
std::basic_string<CharT, Traits>
|
||||||
|
to_string() const
|
||||||
|
{
|
||||||
|
return std::basic_string<
|
||||||
|
CharT, Traits>{&s_[0], n_};
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void
|
||||||
|
assign(CharT const* s);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<std::size_t N, class CharT, class Traits>
|
||||||
|
static_string<N, CharT, Traits>::
|
||||||
|
static_string()
|
||||||
|
: n_(0)
|
||||||
|
{
|
||||||
|
s_[0] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t N, class CharT, class Traits>
|
||||||
|
static_string<N, CharT, Traits>::
|
||||||
|
static_string(static_string const& s)
|
||||||
|
: n_(s.n_)
|
||||||
|
{
|
||||||
|
Traits::copy(&s_[0], &s.s_[0], n_ + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t N, class CharT, class Traits>
|
||||||
|
template<std::size_t M>
|
||||||
|
static_string<N, CharT, Traits>::
|
||||||
|
static_string(static_string<M, CharT, Traits> const& s)
|
||||||
|
{
|
||||||
|
if(s.size() > N)
|
||||||
|
throw std::length_error("static_string overflow");
|
||||||
|
n_ = s.size();
|
||||||
|
Traits::copy(&s_[0], &s.s_[0], n_ + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t N, class CharT, class Traits>
|
||||||
|
auto
|
||||||
|
static_string<N, CharT, Traits>::
|
||||||
|
operator=(static_string const& s) ->
|
||||||
|
static_string&
|
||||||
|
{
|
||||||
|
n_ = s.n_;
|
||||||
|
Traits::copy(&s_[0], &s.s_[0], n_ + 1);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t N, class CharT, class Traits>
|
||||||
|
template<std::size_t M>
|
||||||
|
auto
|
||||||
|
static_string<N, CharT, Traits>::
|
||||||
|
operator=(static_string<M, CharT, Traits> const& s) ->
|
||||||
|
static_string&
|
||||||
|
{
|
||||||
|
if(s.size() > N)
|
||||||
|
throw std::length_error("static_string overflow");
|
||||||
|
n_ = s.size();
|
||||||
|
Traits::copy(&s_[0], &s.s_[0], n_ + 1);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t N, class CharT, class Traits>
|
||||||
|
template<std::size_t M>
|
||||||
|
static_string<N, CharT, Traits>::
|
||||||
|
static_string(const CharT (&s)[M])
|
||||||
|
: n_(M-1)
|
||||||
|
{
|
||||||
|
static_assert(M-1 <= N,
|
||||||
|
"static_string overflow");
|
||||||
|
Traits::copy(&s_[0], &s[0], M);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t N, class CharT, class Traits>
|
||||||
|
template<std::size_t M>
|
||||||
|
auto
|
||||||
|
static_string<N, CharT, Traits>::
|
||||||
|
operator=(const CharT (&s)[M]) ->
|
||||||
|
static_string&
|
||||||
|
{
|
||||||
|
static_assert(M-1 <= N,
|
||||||
|
"static_string overflow");
|
||||||
|
n_ = M-1;
|
||||||
|
std::copy(&s[0], &s[M], &s_[0]);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t N, class CharT, class Traits>
|
||||||
|
auto
|
||||||
|
static_string<N, CharT, Traits>::
|
||||||
|
at(size_type pos) ->
|
||||||
|
reference
|
||||||
|
{
|
||||||
|
if(pos >= n_)
|
||||||
|
throw std::out_of_range("static_string::at");
|
||||||
|
return s_[pos];
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t N, class CharT, class Traits>
|
||||||
|
auto
|
||||||
|
static_string<N, CharT, Traits>::
|
||||||
|
at(size_type pos) const ->
|
||||||
|
const_reference
|
||||||
|
{
|
||||||
|
if(pos >= n_)
|
||||||
|
throw std::out_of_range("static_string::at");
|
||||||
|
return s_[pos];
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t N, class CharT, class Traits>
|
||||||
|
void
|
||||||
|
static_string<N, CharT, Traits>::
|
||||||
|
resize(std::size_t n)
|
||||||
|
{
|
||||||
|
if(n > N)
|
||||||
|
throw std::length_error("static_string overflow");
|
||||||
|
n_ = n;
|
||||||
|
s_[n_] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t N, class CharT, class Traits>
|
||||||
|
void
|
||||||
|
static_string<N, CharT, Traits>::
|
||||||
|
resize(std::size_t n, CharT c)
|
||||||
|
{
|
||||||
|
if(n > N)
|
||||||
|
throw std::length_error("static_string overflow");
|
||||||
|
if(n > n_)
|
||||||
|
Traits::assign(&s_[n_], n - n_, c);
|
||||||
|
n_ = n;
|
||||||
|
s_[n_] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t N, class CharT, class Traits>
|
||||||
|
template<std::size_t M>
|
||||||
|
int
|
||||||
|
static_string<N, CharT, Traits>::
|
||||||
|
compare(static_string<M, CharT, Traits> const& rhs) const
|
||||||
|
{
|
||||||
|
if(size() < rhs.size())
|
||||||
|
{
|
||||||
|
auto const v = Traits::compare(
|
||||||
|
data(), rhs.data(), size());
|
||||||
|
if(v == 0)
|
||||||
|
return -1;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
else if(size() > rhs.size())
|
||||||
|
{
|
||||||
|
auto const v = Traits::compare(
|
||||||
|
data(), rhs.data(), rhs.size());
|
||||||
|
if(v == 0)
|
||||||
|
return 1;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
return Traits::compare(data(), rhs.data(), size());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t N, class CharT, class Traits>
|
||||||
|
void
|
||||||
|
static_string<N, CharT, Traits>::
|
||||||
|
assign(CharT const* s)
|
||||||
|
{
|
||||||
|
auto const n = Traits::length(s);
|
||||||
|
if(n > N)
|
||||||
|
throw std::out_of_range("too large");
|
||||||
|
n_ = n;
|
||||||
|
Traits::copy(&s_[0], s, n_ + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||||
|
int compare(
|
||||||
|
static_string<N, CharT, Traits> const& lhs,
|
||||||
|
const CharT (&s)[M])
|
||||||
|
{
|
||||||
|
if(lhs.size() < M-1)
|
||||||
|
{
|
||||||
|
auto const v = Traits::compare(
|
||||||
|
lhs.data(), &s[0], lhs.size());
|
||||||
|
if(v == 0)
|
||||||
|
return -1;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
else if(lhs.size() > M-1)
|
||||||
|
{
|
||||||
|
auto const v = Traits::compare(
|
||||||
|
lhs.data(), &s[0], M-1);
|
||||||
|
if(v == 0)
|
||||||
|
return 1;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
return Traits::compare(lhs.data(), &s[0], lhs.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||||
|
int compare(
|
||||||
|
const CharT (&s)[M],
|
||||||
|
static_string<N, CharT, Traits> const& rhs)
|
||||||
|
{
|
||||||
|
if(M-1 < rhs.size())
|
||||||
|
{
|
||||||
|
auto const v = Traits::compare(
|
||||||
|
&s[0], rhs.data(), M-1);
|
||||||
|
if(v == 0)
|
||||||
|
return -1;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
else if(M-1 > rhs.size())
|
||||||
|
{
|
||||||
|
auto const v = Traits::compare(
|
||||||
|
&s[0], rhs.data(), rhs.size());
|
||||||
|
if(v == 0)
|
||||||
|
return 1;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
return Traits::compare(&s[0], rhs.data(), M-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // detail
|
||||||
|
|
||||||
|
#if ! GENERATING_DOCS
|
||||||
|
|
||||||
|
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||||
|
bool operator==(
|
||||||
|
static_string<N, CharT, Traits> const& lhs,
|
||||||
|
static_string<M, CharT, Traits> const& rhs)
|
||||||
|
{
|
||||||
|
return lhs.compare(rhs) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||||
|
bool operator!=(
|
||||||
|
static_string<N, CharT, Traits> const& lhs,
|
||||||
|
static_string<M, CharT, Traits> const& rhs)
|
||||||
|
{
|
||||||
|
return lhs.compare(rhs) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||||
|
bool operator<(
|
||||||
|
static_string<N, CharT, Traits> const& lhs,
|
||||||
|
static_string<M, CharT, Traits> const& rhs)
|
||||||
|
{
|
||||||
|
return lhs.compare(rhs) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||||
|
bool operator<=(
|
||||||
|
static_string<N, CharT, Traits> const& lhs,
|
||||||
|
static_string<M, CharT, Traits> const& rhs)
|
||||||
|
{
|
||||||
|
return lhs.compare(rhs) <= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||||
|
bool operator>(
|
||||||
|
static_string<N, CharT, Traits> const& lhs,
|
||||||
|
static_string<M, CharT, Traits> const& rhs)
|
||||||
|
{
|
||||||
|
return lhs.compare(rhs) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||||
|
bool operator>=(
|
||||||
|
static_string<N, CharT, Traits> const& lhs,
|
||||||
|
static_string<M, CharT, Traits> const& rhs)
|
||||||
|
{
|
||||||
|
return lhs.compare(rhs) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---
|
||||||
|
|
||||||
|
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||||
|
bool operator==(
|
||||||
|
const CharT (&s)[N],
|
||||||
|
static_string<M, CharT, Traits> const& rhs)
|
||||||
|
{
|
||||||
|
return detail::compare(s, rhs) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t N, class CharT, class Traits, std::size_t M>
|
||||||
|
bool operator==(
|
||||||
|
static_string<N, CharT, Traits> const& lhs,
|
||||||
|
const CharT (&s)[M])
|
||||||
|
{
|
||||||
|
return detail::compare(lhs, s) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||||
|
bool operator!=(
|
||||||
|
const CharT (&s)[N],
|
||||||
|
static_string<M, CharT, Traits> const& rhs)
|
||||||
|
{
|
||||||
|
return detail::compare(s, rhs) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t N, class CharT, class Traits, std::size_t M>
|
||||||
|
bool operator!=(
|
||||||
|
static_string<N, CharT, Traits> const& lhs,
|
||||||
|
const CharT (&s)[M])
|
||||||
|
{
|
||||||
|
return detail::compare(lhs, s) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||||
|
bool operator<(
|
||||||
|
const CharT (&s)[N],
|
||||||
|
static_string<M, CharT, Traits> const& rhs)
|
||||||
|
{
|
||||||
|
return detail::compare(s, rhs) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t N, class CharT, class Traits, std::size_t M>
|
||||||
|
bool operator<(
|
||||||
|
static_string<N, CharT, Traits> const& lhs,
|
||||||
|
const CharT (&s)[M])
|
||||||
|
{
|
||||||
|
return detail::compare(lhs, s) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||||
|
bool operator<=(
|
||||||
|
const CharT (&s)[N],
|
||||||
|
static_string<M, CharT, Traits> const& rhs)
|
||||||
|
{
|
||||||
|
return detail::compare(s, rhs) <= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t N, class CharT, class Traits, std::size_t M>
|
||||||
|
bool operator<=(
|
||||||
|
static_string<N, CharT, Traits> const& lhs,
|
||||||
|
const CharT (&s)[M])
|
||||||
|
{
|
||||||
|
return detail::compare(lhs, s) <= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||||
|
bool operator>(
|
||||||
|
const CharT (&s)[N],
|
||||||
|
static_string<M, CharT, Traits> const& rhs)
|
||||||
|
{
|
||||||
|
return detail::compare(s, rhs) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t N, class CharT, class Traits, std::size_t M>
|
||||||
|
bool operator>(
|
||||||
|
static_string<N, CharT, Traits> const& lhs,
|
||||||
|
const CharT (&s)[M])
|
||||||
|
{
|
||||||
|
return detail::compare(lhs, s) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t N, std::size_t M, class CharT, class Traits>
|
||||||
|
bool operator>=(
|
||||||
|
const CharT (&s)[N],
|
||||||
|
static_string<M, CharT, Traits> const& rhs)
|
||||||
|
{
|
||||||
|
return detail::compare(s, rhs) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t N, class CharT, class Traits, std::size_t M>
|
||||||
|
bool operator>=(
|
||||||
|
static_string<N, CharT, Traits> const& lhs,
|
||||||
|
const CharT (&s)[M])
|
||||||
|
{
|
||||||
|
return detail::compare(lhs, s) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // websocket
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
#endif
|
@ -10,6 +10,8 @@
|
|||||||
|
|
||||||
#include <beast/async_completion.hpp>
|
#include <beast/async_completion.hpp>
|
||||||
#include <beast/streambuf.hpp>
|
#include <beast/streambuf.hpp>
|
||||||
|
#include <beast/type_check.hpp>
|
||||||
|
#include <beast/detail/get_lowest_layer.hpp>
|
||||||
#include <boost/asio/buffer.hpp>
|
#include <boost/asio/buffer.hpp>
|
||||||
#include <boost/asio/io_service.hpp>
|
#include <boost/asio/io_service.hpp>
|
||||||
#include <boost/system/error_code.hpp>
|
#include <boost/system/error_code.hpp>
|
||||||
@ -83,8 +85,7 @@ namespace beast {
|
|||||||
|
|
||||||
@tparam Streambuf The type of stream buffer to use.
|
@tparam Streambuf The type of stream buffer to use.
|
||||||
*/
|
*/
|
||||||
template<class Stream,
|
template<class Stream, class Streambuf>
|
||||||
class Streambuf = streambuf>
|
|
||||||
class streambuf_readstream
|
class streambuf_readstream
|
||||||
{
|
{
|
||||||
using error_code = boost::system::error_code;
|
using error_code = boost::system::error_code;
|
||||||
@ -106,11 +107,23 @@ public:
|
|||||||
|
|
||||||
/// The type of the lowest layer.
|
/// The type of the lowest layer.
|
||||||
using lowest_layer_type =
|
using lowest_layer_type =
|
||||||
typename next_layer_type::lowest_layer_type;
|
typename detail::get_lowest_layer<
|
||||||
|
next_layer_type>::type;
|
||||||
|
|
||||||
/// Move constructor.
|
/** Move constructor.
|
||||||
|
|
||||||
|
@note The behavior of move assignment on or from streams
|
||||||
|
with active or pending operations is undefined.
|
||||||
|
*/
|
||||||
streambuf_readstream(streambuf_readstream&&) = default;
|
streambuf_readstream(streambuf_readstream&&) = default;
|
||||||
|
|
||||||
|
/** Move assignment.
|
||||||
|
|
||||||
|
@note The behavior of move assignment on or from streams
|
||||||
|
with active or pending operations is undefined.
|
||||||
|
*/
|
||||||
|
streambuf_readstream& operator=(streambuf_readstream&&) = default;
|
||||||
|
|
||||||
/** Construct the wrapping stream.
|
/** Construct the wrapping stream.
|
||||||
|
|
||||||
@param args Parameters forwarded to the `Stream` constructor.
|
@param args Parameters forwarded to the `Stream` constructor.
|
||||||
@ -200,6 +213,8 @@ public:
|
|||||||
std::size_t
|
std::size_t
|
||||||
write_some(ConstBufferSequence const& buffers)
|
write_some(ConstBufferSequence const& buffers)
|
||||||
{
|
{
|
||||||
|
static_assert(is_SyncWriteStream<next_layer_type>::value,
|
||||||
|
"SyncWriteStream requirements not met");
|
||||||
return next_layer_.write_some(buffers);
|
return next_layer_.write_some(buffers);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,6 +225,8 @@ public:
|
|||||||
write_some(ConstBufferSequence const& buffers,
|
write_some(ConstBufferSequence const& buffers,
|
||||||
error_code& ec)
|
error_code& ec)
|
||||||
{
|
{
|
||||||
|
static_assert(is_SyncWriteStream<next_layer_type>::value,
|
||||||
|
"SyncWriteStream requirements not met");
|
||||||
return next_layer_.write_some(buffers, ec);
|
return next_layer_.write_some(buffers, ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,18 +272,26 @@ public:
|
|||||||
};
|
};
|
||||||
static_assert(! is_SyncWriteStream<int>::value, "");
|
static_assert(! is_SyncWriteStream<int>::value, "");
|
||||||
|
|
||||||
/// Determine if `T` meets the requirements of `Stream`.
|
/// Determine if `T` meets the requirements of `SyncStream`.
|
||||||
template<class T>
|
template<class T>
|
||||||
struct is_Stream
|
struct is_SyncStream
|
||||||
{
|
{
|
||||||
/// `true` if `T` meets the requirements.
|
/// `true` if `T` meets the requirements.
|
||||||
static bool const value =
|
static bool const value =
|
||||||
is_AsyncReadStream<T>::value &&
|
|
||||||
is_AsyncWriteStream<T>::value &&
|
|
||||||
is_SyncReadStream<T>::value &&
|
is_SyncReadStream<T>::value &&
|
||||||
is_SyncWriteStream<T>::value;
|
is_SyncWriteStream<T>::value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Determine if `T` meets the requirements of `SyncStream`.
|
||||||
|
template<class T>
|
||||||
|
struct is_AsyncStream
|
||||||
|
{
|
||||||
|
/// `true` if `T` meets the requirements.
|
||||||
|
static bool const value =
|
||||||
|
is_AsyncReadStream<T>::value &&
|
||||||
|
is_AsyncWriteStream<T>::value;
|
||||||
|
};
|
||||||
|
|
||||||
/// Determine if `T` meets the requirements of `Streambuf`.
|
/// Determine if `T` meets the requirements of `Streambuf`.
|
||||||
template<class T>
|
template<class T>
|
||||||
class is_Streambuf
|
class is_Streambuf
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
#include <beast/websocket/option.hpp>
|
#include <beast/websocket/option.hpp>
|
||||||
#include <beast/websocket/rfc6455.hpp>
|
#include <beast/websocket/rfc6455.hpp>
|
||||||
#include <beast/websocket/stream.hpp>
|
#include <beast/websocket/stream.hpp>
|
||||||
#include <beast/websocket/static_string.hpp>
|
|
||||||
#include <beast/websocket/teardown.hpp>
|
#include <beast/websocket/teardown.hpp>
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -9,11 +9,11 @@
|
|||||||
#define BEAST_WEBSOCKET_DETAIL_FRAME_HPP
|
#define BEAST_WEBSOCKET_DETAIL_FRAME_HPP
|
||||||
|
|
||||||
#include <beast/websocket/rfc6455.hpp>
|
#include <beast/websocket/rfc6455.hpp>
|
||||||
#include <beast/websocket/static_string.hpp>
|
|
||||||
#include <beast/websocket/detail/endian.hpp>
|
#include <beast/websocket/detail/endian.hpp>
|
||||||
#include <beast/websocket/detail/utf8_checker.hpp>
|
#include <beast/websocket/detail/utf8_checker.hpp>
|
||||||
#include <beast/consuming_buffers.hpp>
|
#include <beast/consuming_buffers.hpp>
|
||||||
#include <beast/static_streambuf.hpp>
|
#include <beast/static_streambuf.hpp>
|
||||||
|
#include <beast/static_string.hpp>
|
||||||
#include <boost/asio/buffer.hpp>
|
#include <boost/asio/buffer.hpp>
|
||||||
#include <boost/endian/buffers.hpp>
|
#include <boost/endian/buffers.hpp>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
@ -70,10 +70,9 @@ is_control(opcode op)
|
|||||||
// Returns `true` if a close code is valid
|
// Returns `true` if a close code is valid
|
||||||
inline
|
inline
|
||||||
bool
|
bool
|
||||||
is_valid(close_code code)
|
is_valid(close_code::value code)
|
||||||
{
|
{
|
||||||
auto const v = static_cast<
|
auto const v = code;
|
||||||
std::uint16_t>(code);
|
|
||||||
switch(v)
|
switch(v)
|
||||||
{
|
{
|
||||||
case 1000:
|
case 1000:
|
||||||
@ -154,7 +153,7 @@ write(Streambuf& sb, frame_header const& fh)
|
|||||||
template<class Streambuf>
|
template<class Streambuf>
|
||||||
std::size_t
|
std::size_t
|
||||||
read_fh1(frame_header& fh, Streambuf& sb,
|
read_fh1(frame_header& fh, Streambuf& sb,
|
||||||
role_type role, close_code& code)
|
role_type role, close_code::value& code)
|
||||||
{
|
{
|
||||||
using boost::asio::buffer;
|
using boost::asio::buffer;
|
||||||
using boost::asio::buffer_copy;
|
using boost::asio::buffer_copy;
|
||||||
@ -171,7 +170,8 @@ read_fh1(frame_header& fh, Streambuf& sb,
|
|||||||
default:
|
default:
|
||||||
need = 0;
|
need = 0;
|
||||||
}
|
}
|
||||||
if((fh.mask = (b[1] & 0x80) != 0))
|
fh.mask = (b[1] & 0x80) != 0;
|
||||||
|
if(fh.mask)
|
||||||
need += 4;
|
need += 4;
|
||||||
fh.op = static_cast<opcode>(b[0] & 0x0f);
|
fh.op = static_cast<opcode>(b[0] & 0x0f);
|
||||||
fh.fin = (b[0] & 0x80) != 0;
|
fh.fin = (b[0] & 0x80) != 0;
|
||||||
@ -230,7 +230,7 @@ read_fh1(frame_header& fh, Streambuf& sb,
|
|||||||
template<class Streambuf>
|
template<class Streambuf>
|
||||||
void
|
void
|
||||||
read_fh2(frame_header& fh, Streambuf& sb,
|
read_fh2(frame_header& fh, Streambuf& sb,
|
||||||
role_type role, close_code& code)
|
role_type role, close_code::value& code)
|
||||||
{
|
{
|
||||||
using boost::asio::buffer;
|
using boost::asio::buffer;
|
||||||
using boost::asio::buffer_copy;
|
using boost::asio::buffer_copy;
|
||||||
@ -301,7 +301,7 @@ read_fh2(frame_header& fh, Streambuf& sb,
|
|||||||
template<class Buffers>
|
template<class Buffers>
|
||||||
void
|
void
|
||||||
read(ping_payload_type& data,
|
read(ping_payload_type& data,
|
||||||
Buffers const& bs, close_code& code)
|
Buffers const& bs, close_code::value& code)
|
||||||
{
|
{
|
||||||
using boost::asio::buffer_copy;
|
using boost::asio::buffer_copy;
|
||||||
using boost::asio::buffer_size;
|
using boost::asio::buffer_size;
|
||||||
@ -318,7 +318,7 @@ read(ping_payload_type& data,
|
|||||||
template<class Buffers>
|
template<class Buffers>
|
||||||
void
|
void
|
||||||
read(close_reason& cr,
|
read(close_reason& cr,
|
||||||
Buffers const& bs, close_code& code)
|
Buffers const& bs, close_code::value& code)
|
||||||
{
|
{
|
||||||
using boost::asio::buffer;
|
using boost::asio::buffer;
|
||||||
using boost::asio::buffer_copy;
|
using boost::asio::buffer_copy;
|
||||||
@ -341,15 +341,7 @@ read(close_reason& cr,
|
|||||||
{
|
{
|
||||||
std::uint8_t b[2];
|
std::uint8_t b[2];
|
||||||
buffer_copy(buffer(b), cb);
|
buffer_copy(buffer(b), cb);
|
||||||
#if 0
|
cr.code = big_uint16_to_native(&b[0]);
|
||||||
// Causes strict-aliasing warning in gcc
|
|
||||||
cr.code = static_cast<close_code>(
|
|
||||||
reinterpret_cast<
|
|
||||||
big_uint16_buf_t const*>(&b[0])->value());
|
|
||||||
#else
|
|
||||||
cr.code = static_cast<close_code>(
|
|
||||||
big_uint16_to_native(&b[0]));
|
|
||||||
#endif
|
|
||||||
cb.consume(2);
|
cb.consume(2);
|
||||||
n -= 2;
|
n -= 2;
|
||||||
if(! is_valid(cr.code))
|
if(! is_valid(cr.code))
|
||||||
|
@ -85,8 +85,6 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
invokable() = default;
|
invokable() = default;
|
||||||
invokable(invokable const&) = delete;
|
|
||||||
invokable& operator=(invokable const&) = delete;
|
|
||||||
|
|
||||||
invokable(invokable&& other)
|
invokable(invokable&& other)
|
||||||
{
|
{
|
||||||
|
@ -41,9 +41,6 @@ class maskgen_t
|
|||||||
public:
|
public:
|
||||||
using result_type = typename std::mt19937::result_type;
|
using result_type = typename std::mt19937::result_type;
|
||||||
|
|
||||||
maskgen_t(maskgen_t const&) = delete;
|
|
||||||
maskgen_t& operator=(maskgen_t const&) = delete;
|
|
||||||
|
|
||||||
maskgen_t();
|
maskgen_t();
|
||||||
|
|
||||||
result_type
|
result_type
|
||||||
|
@ -108,7 +108,7 @@ protected:
|
|||||||
|
|
||||||
template<class = void>
|
template<class = void>
|
||||||
void
|
void
|
||||||
prepare_fh(close_code& code);
|
prepare_fh(close_code::value& code);
|
||||||
|
|
||||||
template<class Streambuf>
|
template<class Streambuf>
|
||||||
void
|
void
|
||||||
|
@ -73,12 +73,6 @@ class utf8_checker_t
|
|||||||
std::uint32_t codepoint_ = 0;
|
std::uint32_t codepoint_ = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
utf8_checker_t() = default;
|
|
||||||
utf8_checker_t(utf8_checker_t&&) = default;
|
|
||||||
utf8_checker_t(utf8_checker_t const&) = default;
|
|
||||||
utf8_checker_t& operator=(utf8_checker_t&&) = default;
|
|
||||||
utf8_checker_t& operator=(utf8_checker_t const&) = default;
|
|
||||||
|
|
||||||
void
|
void
|
||||||
reset();
|
reset();
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ operator()(error_code const& ec,
|
|||||||
case 0:
|
case 0:
|
||||||
// read message
|
// read message
|
||||||
d.state = 1;
|
d.state = 1;
|
||||||
http::async_read(d.ws.next_layer_,
|
http::async_read(d.ws.next_layer(),
|
||||||
d.ws.stream_.buffer(), d.req,
|
d.ws.stream_.buffer(), d.req,
|
||||||
std::move(*this));
|
std::move(*this));
|
||||||
return;
|
return;
|
||||||
|
@ -134,7 +134,7 @@ stream<NextLayer>::handshake_op<
|
|||||||
case 1:
|
case 1:
|
||||||
// read http response
|
// read http response
|
||||||
d.state = 2;
|
d.state = 2;
|
||||||
http::async_read(d.ws.next_layer_,
|
http::async_read(d.ws.next_layer(),
|
||||||
d.ws.stream_.buffer(), d.resp,
|
d.ws.stream_.buffer(), d.resp,
|
||||||
std::move(*this));
|
std::move(*this));
|
||||||
return;
|
return;
|
||||||
|
@ -132,7 +132,7 @@ operator()(error_code ec,std::size_t bytes_transferred, bool again)
|
|||||||
{
|
{
|
||||||
auto& d = *d_;
|
auto& d = *d_;
|
||||||
d.cont = d.cont || again;
|
d.cont = d.cont || again;
|
||||||
close_code code;
|
close_code::value code = close_code::none;
|
||||||
while(! ec && d.state != 99)
|
while(! ec && d.state != 99)
|
||||||
{
|
{
|
||||||
switch(d.state)
|
switch(d.state)
|
||||||
@ -195,7 +195,7 @@ operator()(error_code ec,std::size_t bytes_transferred, bool again)
|
|||||||
d.state = 4;
|
d.state = 4;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// call handler
|
// call handler
|
||||||
case 4:
|
case 4:
|
||||||
d.state = 99;
|
d.state = 99;
|
||||||
@ -397,7 +397,7 @@ operator()(error_code ec,std::size_t bytes_transferred, bool again)
|
|||||||
case 11:
|
case 11:
|
||||||
d.state = 12;
|
d.state = 12;
|
||||||
wsproto_helpers::call_async_teardown(
|
wsproto_helpers::call_async_teardown(
|
||||||
d.ws.next_layer_, std::move(*this));
|
d.ws.next_layer(), std::move(*this));
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 12:
|
case 12:
|
||||||
@ -483,7 +483,7 @@ operator()(error_code ec,std::size_t bytes_transferred, bool again)
|
|||||||
case 19:
|
case 19:
|
||||||
d.state = 20;
|
d.state = 20;
|
||||||
wsproto_helpers::call_async_teardown(
|
wsproto_helpers::call_async_teardown(
|
||||||
d.ws.next_layer_, std::move(*this));
|
d.ws.next_layer(), std::move(*this));
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 20:
|
case 20:
|
||||||
|
@ -113,7 +113,7 @@ operator()(error_code ec, bool again)
|
|||||||
case 0:
|
case 0:
|
||||||
// send response
|
// send response
|
||||||
d.state = 1;
|
d.state = 1;
|
||||||
http::async_write(d.ws.next_layer_,
|
http::async_write(d.ws.next_layer(),
|
||||||
d.resp, std::move(*this));
|
d.resp, std::move(*this));
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ namespace detail {
|
|||||||
|
|
||||||
template<class _>
|
template<class _>
|
||||||
void
|
void
|
||||||
stream_base::prepare_fh(close_code& code)
|
stream_base::prepare_fh(close_code::value& code)
|
||||||
{
|
{
|
||||||
// continuation without an active message
|
// continuation without an active message
|
||||||
if(! rd_cont_ && rd_fh_.op == opcode::cont)
|
if(! rd_cont_ && rd_fh_.op == opcode::cont)
|
||||||
@ -170,11 +170,20 @@ template<class NextLayer>
|
|||||||
template<class... Args>
|
template<class... Args>
|
||||||
stream<NextLayer>::
|
stream<NextLayer>::
|
||||||
stream(Args&&... args)
|
stream(Args&&... args)
|
||||||
: next_layer_(std::forward<Args>(args)...)
|
: stream_(std::forward<Args>(args)...)
|
||||||
, stream_(next_layer_)
|
|
||||||
{
|
{
|
||||||
static_assert(is_Stream<next_layer_type>::value,
|
}
|
||||||
"Stream requirements not met");
|
|
||||||
|
template<class NextLayer>
|
||||||
|
void
|
||||||
|
stream<NextLayer>::
|
||||||
|
accept()
|
||||||
|
{
|
||||||
|
static_assert(is_SyncStream<next_layer_type>::value,
|
||||||
|
"SyncStream requirements not met");
|
||||||
|
error_code ec;
|
||||||
|
accept(boost::asio::null_buffers{}, ec);
|
||||||
|
detail::maybe_throw(ec, "accept");
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class NextLayer>
|
template<class NextLayer>
|
||||||
@ -182,6 +191,8 @@ void
|
|||||||
stream<NextLayer>::
|
stream<NextLayer>::
|
||||||
accept(error_code& ec)
|
accept(error_code& ec)
|
||||||
{
|
{
|
||||||
|
static_assert(is_SyncStream<next_layer_type>::value,
|
||||||
|
"SyncStream requirements not met");
|
||||||
accept(boost::asio::null_buffers{}, ec);
|
accept(boost::asio::null_buffers{}, ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,6 +203,8 @@ typename async_completion<
|
|||||||
stream<NextLayer>::
|
stream<NextLayer>::
|
||||||
async_accept(AcceptHandler&& handler)
|
async_accept(AcceptHandler&& handler)
|
||||||
{
|
{
|
||||||
|
static_assert(is_AsyncStream<next_layer_type>::value,
|
||||||
|
"AsyncStream requirements requirements not met");
|
||||||
return async_accept(boost::asio::null_buffers{},
|
return async_accept(boost::asio::null_buffers{},
|
||||||
std::forward<AcceptHandler>(handler));
|
std::forward<AcceptHandler>(handler));
|
||||||
}
|
}
|
||||||
@ -202,6 +215,8 @@ void
|
|||||||
stream<NextLayer>::
|
stream<NextLayer>::
|
||||||
accept(ConstBufferSequence const& buffers)
|
accept(ConstBufferSequence const& buffers)
|
||||||
{
|
{
|
||||||
|
static_assert(is_SyncStream<next_layer_type>::value,
|
||||||
|
"SyncStream requirements not met");
|
||||||
static_assert(is_ConstBufferSequence<
|
static_assert(is_ConstBufferSequence<
|
||||||
ConstBufferSequence>::value,
|
ConstBufferSequence>::value,
|
||||||
"ConstBufferSequence requirements not met");
|
"ConstBufferSequence requirements not met");
|
||||||
@ -216,6 +231,8 @@ void
|
|||||||
stream<NextLayer>::
|
stream<NextLayer>::
|
||||||
accept(ConstBufferSequence const& buffers, error_code& ec)
|
accept(ConstBufferSequence const& buffers, error_code& ec)
|
||||||
{
|
{
|
||||||
|
static_assert(is_SyncStream<next_layer_type>::value,
|
||||||
|
"SyncStream requirements not met");
|
||||||
static_assert(beast::is_ConstBufferSequence<
|
static_assert(beast::is_ConstBufferSequence<
|
||||||
ConstBufferSequence>::value,
|
ConstBufferSequence>::value,
|
||||||
"ConstBufferSequence requirements not met");
|
"ConstBufferSequence requirements not met");
|
||||||
@ -225,7 +242,7 @@ accept(ConstBufferSequence const& buffers, error_code& ec)
|
|||||||
stream_.buffer().prepare(
|
stream_.buffer().prepare(
|
||||||
buffer_size(buffers)), buffers));
|
buffer_size(buffers)), buffers));
|
||||||
http::request<http::empty_body> m;
|
http::request<http::empty_body> m;
|
||||||
http::read(next_layer_, stream_.buffer(), m, ec);
|
http::read(next_layer(), stream_.buffer(), m, ec);
|
||||||
if(ec)
|
if(ec)
|
||||||
return;
|
return;
|
||||||
accept(m, ec);
|
accept(m, ec);
|
||||||
@ -238,6 +255,8 @@ typename async_completion<
|
|||||||
stream<NextLayer>::
|
stream<NextLayer>::
|
||||||
async_accept(ConstBufferSequence const& bs, AcceptHandler&& handler)
|
async_accept(ConstBufferSequence const& bs, AcceptHandler&& handler)
|
||||||
{
|
{
|
||||||
|
static_assert(is_AsyncStream<next_layer_type>::value,
|
||||||
|
"AsyncStream requirements requirements not met");
|
||||||
static_assert(beast::is_ConstBufferSequence<
|
static_assert(beast::is_ConstBufferSequence<
|
||||||
ConstBufferSequence>::value,
|
ConstBufferSequence>::value,
|
||||||
"ConstBufferSequence requirements not met");
|
"ConstBufferSequence requirements not met");
|
||||||
@ -255,6 +274,8 @@ void
|
|||||||
stream<NextLayer>::
|
stream<NextLayer>::
|
||||||
accept(http::message<true, Body, Headers> const& request)
|
accept(http::message<true, Body, Headers> const& request)
|
||||||
{
|
{
|
||||||
|
static_assert(is_SyncStream<next_layer_type>::value,
|
||||||
|
"SyncStream requirements not met");
|
||||||
error_code ec;
|
error_code ec;
|
||||||
accept(request, ec);
|
accept(request, ec);
|
||||||
detail::maybe_throw(ec, "accept");
|
detail::maybe_throw(ec, "accept");
|
||||||
@ -267,6 +288,8 @@ stream<NextLayer>::
|
|||||||
accept(http::message<true, Body, Headers> const& req,
|
accept(http::message<true, Body, Headers> const& req,
|
||||||
error_code& ec)
|
error_code& ec)
|
||||||
{
|
{
|
||||||
|
static_assert(is_SyncStream<next_layer_type>::value,
|
||||||
|
"SyncStream requirements not met");
|
||||||
auto resp = build_response(req);
|
auto resp = build_response(req);
|
||||||
http::write(stream_, resp, ec);
|
http::write(stream_, resp, ec);
|
||||||
if(resp.status != 101)
|
if(resp.status != 101)
|
||||||
@ -287,6 +310,8 @@ stream<NextLayer>::
|
|||||||
async_accept(http::message<true, Body, Headers> const& req,
|
async_accept(http::message<true, Body, Headers> const& req,
|
||||||
AcceptHandler&& handler)
|
AcceptHandler&& handler)
|
||||||
{
|
{
|
||||||
|
static_assert(is_AsyncStream<next_layer_type>::value,
|
||||||
|
"AsyncStream requirements requirements not met");
|
||||||
beast::async_completion<
|
beast::async_completion<
|
||||||
AcceptHandler, void(error_code)
|
AcceptHandler, void(error_code)
|
||||||
> completion(handler);
|
> completion(handler);
|
||||||
@ -297,19 +322,34 @@ async_accept(http::message<true, Body, Headers> const& req,
|
|||||||
return completion.result.get();
|
return completion.result.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class NextLayer>
|
||||||
|
void
|
||||||
|
stream<NextLayer>::
|
||||||
|
handshake(boost::string_ref const& host,
|
||||||
|
boost::string_ref const& resource)
|
||||||
|
{
|
||||||
|
static_assert(is_SyncStream<next_layer_type>::value,
|
||||||
|
"SyncStream requirements not met");
|
||||||
|
error_code ec;
|
||||||
|
handshake(host, resource, ec);
|
||||||
|
detail::maybe_throw(ec, "upgrade");
|
||||||
|
}
|
||||||
|
|
||||||
template<class NextLayer>
|
template<class NextLayer>
|
||||||
void
|
void
|
||||||
stream<NextLayer>::
|
stream<NextLayer>::
|
||||||
handshake(boost::string_ref const& host,
|
handshake(boost::string_ref const& host,
|
||||||
boost::string_ref const& resource, error_code& ec)
|
boost::string_ref const& resource, error_code& ec)
|
||||||
{
|
{
|
||||||
|
static_assert(is_SyncStream<next_layer_type>::value,
|
||||||
|
"SyncStream requirements not met");
|
||||||
std::string key;
|
std::string key;
|
||||||
http::write(stream_,
|
http::write(stream_,
|
||||||
build_request(host, resource, key), ec);
|
build_request(host, resource, key), ec);
|
||||||
if(ec)
|
if(ec)
|
||||||
return;
|
return;
|
||||||
http::response<http::string_body> resp;
|
http::response<http::string_body> resp;
|
||||||
http::read(next_layer_, stream_.buffer(), resp, ec);
|
http::read(next_layer(), stream_.buffer(), resp, ec);
|
||||||
if(ec)
|
if(ec)
|
||||||
return;
|
return;
|
||||||
do_response(resp, key, ec);
|
do_response(resp, key, ec);
|
||||||
@ -323,6 +363,8 @@ stream<NextLayer>::
|
|||||||
async_handshake(boost::string_ref const& host,
|
async_handshake(boost::string_ref const& host,
|
||||||
boost::string_ref const& resource, HandshakeHandler&& handler)
|
boost::string_ref const& resource, HandshakeHandler&& handler)
|
||||||
{
|
{
|
||||||
|
static_assert(is_AsyncStream<next_layer_type>::value,
|
||||||
|
"AsyncStream requirements not met");
|
||||||
beast::async_completion<
|
beast::async_completion<
|
||||||
HandshakeHandler, void(error_code)
|
HandshakeHandler, void(error_code)
|
||||||
> completion(handler);
|
> completion(handler);
|
||||||
@ -331,11 +373,25 @@ async_handshake(boost::string_ref const& host,
|
|||||||
return completion.result.get();
|
return completion.result.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class NextLayer>
|
||||||
|
void
|
||||||
|
stream<NextLayer>::
|
||||||
|
close(close_reason const& cr)
|
||||||
|
{
|
||||||
|
static_assert(is_SyncStream<next_layer_type>::value,
|
||||||
|
"SyncStream requirements not met");
|
||||||
|
error_code ec;
|
||||||
|
close(cr, ec);
|
||||||
|
detail::maybe_throw(ec, "close");
|
||||||
|
}
|
||||||
|
|
||||||
template<class NextLayer>
|
template<class NextLayer>
|
||||||
void
|
void
|
||||||
stream<NextLayer>::
|
stream<NextLayer>::
|
||||||
close(close_reason const& cr, error_code& ec)
|
close(close_reason const& cr, error_code& ec)
|
||||||
{
|
{
|
||||||
|
static_assert(is_SyncStream<next_layer_type>::value,
|
||||||
|
"SyncStream requirements not met");
|
||||||
assert(! wr_close_);
|
assert(! wr_close_);
|
||||||
wr_close_ = true;
|
wr_close_ = true;
|
||||||
detail::frame_streambuf fb;
|
detail::frame_streambuf fb;
|
||||||
@ -351,6 +407,8 @@ typename async_completion<
|
|||||||
stream<NextLayer>::
|
stream<NextLayer>::
|
||||||
async_close(close_reason const& cr, CloseHandler&& handler)
|
async_close(close_reason const& cr, CloseHandler&& handler)
|
||||||
{
|
{
|
||||||
|
static_assert(is_AsyncStream<next_layer_type>::value,
|
||||||
|
"AsyncStream requirements not met");
|
||||||
beast::async_completion<
|
beast::async_completion<
|
||||||
CloseHandler, void(error_code)
|
CloseHandler, void(error_code)
|
||||||
> completion(handler);
|
> completion(handler);
|
||||||
@ -359,12 +417,27 @@ async_close(close_reason const& cr, CloseHandler&& handler)
|
|||||||
return completion.result.get();
|
return completion.result.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class NextLayer>
|
||||||
|
template<class Streambuf>
|
||||||
|
void
|
||||||
|
stream<NextLayer>::
|
||||||
|
read(opcode& op, Streambuf& streambuf)
|
||||||
|
{
|
||||||
|
static_assert(is_SyncStream<next_layer_type>::value,
|
||||||
|
"SyncStream requirements not met");
|
||||||
|
error_code ec;
|
||||||
|
read(op, streambuf, ec);
|
||||||
|
detail::maybe_throw(ec, "read");
|
||||||
|
}
|
||||||
|
|
||||||
template<class NextLayer>
|
template<class NextLayer>
|
||||||
template<class Streambuf>
|
template<class Streambuf>
|
||||||
void
|
void
|
||||||
stream<NextLayer>::
|
stream<NextLayer>::
|
||||||
read(opcode& op, Streambuf& streambuf, error_code& ec)
|
read(opcode& op, Streambuf& streambuf, error_code& ec)
|
||||||
{
|
{
|
||||||
|
static_assert(is_SyncStream<next_layer_type>::value,
|
||||||
|
"SyncStream requirements not met");
|
||||||
frame_info fi;
|
frame_info fi;
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
@ -385,6 +458,8 @@ stream<NextLayer>::
|
|||||||
async_read(opcode& op,
|
async_read(opcode& op,
|
||||||
Streambuf& streambuf, ReadHandler&& handler)
|
Streambuf& streambuf, ReadHandler&& handler)
|
||||||
{
|
{
|
||||||
|
static_assert(is_AsyncStream<next_layer_type>::value,
|
||||||
|
"AsyncStream requirements requirements not met");
|
||||||
static_assert(beast::is_Streambuf<Streambuf>::value,
|
static_assert(beast::is_Streambuf<Streambuf>::value,
|
||||||
"Streambuf requirements not met");
|
"Streambuf requirements not met");
|
||||||
beast::async_completion<
|
beast::async_completion<
|
||||||
@ -395,13 +470,28 @@ async_read(opcode& op,
|
|||||||
return completion.result.get();
|
return completion.result.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class NextLayer>
|
||||||
|
template<class Streambuf>
|
||||||
|
void
|
||||||
|
stream<NextLayer>::
|
||||||
|
read_frame(frame_info& fi, Streambuf& streambuf)
|
||||||
|
{
|
||||||
|
static_assert(is_SyncStream<next_layer_type>::value,
|
||||||
|
"SyncStream requirements not met");
|
||||||
|
error_code ec;
|
||||||
|
read_frame(fi, streambuf, ec);
|
||||||
|
detail::maybe_throw(ec, "read_some");
|
||||||
|
}
|
||||||
|
|
||||||
template<class NextLayer>
|
template<class NextLayer>
|
||||||
template<class Streambuf>
|
template<class Streambuf>
|
||||||
void
|
void
|
||||||
stream<NextLayer>::
|
stream<NextLayer>::
|
||||||
read_frame(frame_info& fi, Streambuf& streambuf, error_code& ec)
|
read_frame(frame_info& fi, Streambuf& streambuf, error_code& ec)
|
||||||
{
|
{
|
||||||
close_code code{};
|
static_assert(is_SyncStream<next_layer_type>::value,
|
||||||
|
"SyncStream requirements not met");
|
||||||
|
close_code::value code{};
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
if(rd_need_ == 0)
|
if(rd_need_ == 0)
|
||||||
@ -409,7 +499,8 @@ read_frame(frame_info& fi, Streambuf& streambuf, error_code& ec)
|
|||||||
// read header
|
// read header
|
||||||
detail::frame_streambuf fb;
|
detail::frame_streambuf fb;
|
||||||
do_read_fh(fb, code, ec);
|
do_read_fh(fb, code, ec);
|
||||||
if((error_ = ec != 0))
|
error_ = ec != 0;
|
||||||
|
if(error_)
|
||||||
return;
|
return;
|
||||||
if(code != close_code::none)
|
if(code != close_code::none)
|
||||||
break;
|
break;
|
||||||
@ -421,7 +512,8 @@ read_frame(frame_info& fi, Streambuf& streambuf, error_code& ec)
|
|||||||
auto const mb = fb.prepare(
|
auto const mb = fb.prepare(
|
||||||
static_cast<std::size_t>(rd_fh_.len));
|
static_cast<std::size_t>(rd_fh_.len));
|
||||||
fb.commit(boost::asio::read(stream_, mb, ec));
|
fb.commit(boost::asio::read(stream_, mb, ec));
|
||||||
if((error_ = ec != 0))
|
error_ = ec != 0;
|
||||||
|
if(error_)
|
||||||
return;
|
return;
|
||||||
if(rd_fh_.mask)
|
if(rd_fh_.mask)
|
||||||
detail::mask_inplace(mb, rd_key_);
|
detail::mask_inplace(mb, rd_key_);
|
||||||
@ -437,7 +529,8 @@ read_frame(frame_info& fi, Streambuf& streambuf, error_code& ec)
|
|||||||
write_ping<static_streambuf>(
|
write_ping<static_streambuf>(
|
||||||
fb, opcode::pong, data);
|
fb, opcode::pong, data);
|
||||||
boost::asio::write(stream_, fb.data(), ec);
|
boost::asio::write(stream_, fb.data(), ec);
|
||||||
if((error_ = ec != 0))
|
error_ = ec != 0;
|
||||||
|
if(error_)
|
||||||
return;
|
return;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -445,7 +538,7 @@ read_frame(frame_info& fi, Streambuf& streambuf, error_code& ec)
|
|||||||
{
|
{
|
||||||
ping_payload_type data;
|
ping_payload_type data;
|
||||||
detail::read(data, fb.data(), code);
|
detail::read(data, fb.data(), code);
|
||||||
if((error_ = ec != 0))
|
if(code != close_code::none)
|
||||||
break;
|
break;
|
||||||
// VFALCO How to notify callers using
|
// VFALCO How to notify callers using
|
||||||
// the synchronous interface?
|
// the synchronous interface?
|
||||||
@ -466,7 +559,8 @@ read_frame(frame_info& fi, Streambuf& streambuf, error_code& ec)
|
|||||||
wr_close_ = true;
|
wr_close_ = true;
|
||||||
write_close<static_streambuf>(fb, cr);
|
write_close<static_streambuf>(fb, cr);
|
||||||
boost::asio::write(stream_, fb.data(), ec);
|
boost::asio::write(stream_, fb.data(), ec);
|
||||||
if((error_ = ec != 0))
|
error_ = ec != 0;
|
||||||
|
if(error_)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -483,7 +577,8 @@ read_frame(frame_info& fi, Streambuf& streambuf, error_code& ec)
|
|||||||
detail::clamp(rd_need_));
|
detail::clamp(rd_need_));
|
||||||
auto const bytes_transferred =
|
auto const bytes_transferred =
|
||||||
stream_.read_some(smb, ec);
|
stream_.read_some(smb, ec);
|
||||||
if((error_ = ec != 0))
|
error_ = ec != 0;
|
||||||
|
if(error_)
|
||||||
return;
|
return;
|
||||||
rd_need_ -= bytes_transferred;
|
rd_need_ -= bytes_transferred;
|
||||||
auto const pb = prepare_buffers(
|
auto const pb = prepare_buffers(
|
||||||
@ -514,18 +609,20 @@ read_frame(frame_info& fi, Streambuf& streambuf, error_code& ec)
|
|||||||
detail::frame_streambuf fb;
|
detail::frame_streambuf fb;
|
||||||
write_close<static_streambuf>(fb, code);
|
write_close<static_streambuf>(fb, code);
|
||||||
boost::asio::write(stream_, fb.data(), ec);
|
boost::asio::write(stream_, fb.data(), ec);
|
||||||
if((error_ = ec != 0))
|
error_ = ec != 0;
|
||||||
|
if(error_)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
wsproto_helpers::call_teardown(next_layer_, ec);
|
wsproto_helpers::call_teardown(next_layer(), ec);
|
||||||
if((error_ = ec != 0))
|
error_ = ec != 0;
|
||||||
|
if(error_)
|
||||||
return;
|
return;
|
||||||
ec = error::failed;
|
ec = error::failed;
|
||||||
error_ = true;
|
error_ = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(! ec)
|
if(! ec)
|
||||||
wsproto_helpers::call_teardown(next_layer_, ec);
|
wsproto_helpers::call_teardown(next_layer(), ec);
|
||||||
if(! ec)
|
if(! ec)
|
||||||
ec = error::closed;
|
ec = error::closed;
|
||||||
error_ = ec != 0;
|
error_ = ec != 0;
|
||||||
@ -539,6 +636,8 @@ stream<NextLayer>::
|
|||||||
async_read_frame(frame_info& fi,
|
async_read_frame(frame_info& fi,
|
||||||
Streambuf& streambuf, ReadHandler&& handler)
|
Streambuf& streambuf, ReadHandler&& handler)
|
||||||
{
|
{
|
||||||
|
static_assert(is_AsyncStream<next_layer_type>::value,
|
||||||
|
"AsyncStream requirements requirements not met");
|
||||||
static_assert(beast::is_Streambuf<Streambuf>::value,
|
static_assert(beast::is_Streambuf<Streambuf>::value,
|
||||||
"Streambuf requirements not met");
|
"Streambuf requirements not met");
|
||||||
beast::async_completion<
|
beast::async_completion<
|
||||||
@ -548,12 +647,27 @@ async_read_frame(frame_info& fi,
|
|||||||
return completion.result.get();
|
return completion.result.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class NextLayer>
|
||||||
|
template<class ConstBufferSequence>
|
||||||
|
void
|
||||||
|
stream<NextLayer>::
|
||||||
|
write(ConstBufferSequence const& buffers)
|
||||||
|
{
|
||||||
|
static_assert(is_SyncStream<next_layer_type>::value,
|
||||||
|
"SyncStream requirements not met");
|
||||||
|
error_code ec;
|
||||||
|
write(buffers, ec);
|
||||||
|
detail::maybe_throw(ec, "write");
|
||||||
|
}
|
||||||
|
|
||||||
template<class NextLayer>
|
template<class NextLayer>
|
||||||
template<class ConstBufferSequence>
|
template<class ConstBufferSequence>
|
||||||
void
|
void
|
||||||
stream<NextLayer>::
|
stream<NextLayer>::
|
||||||
write(ConstBufferSequence const& bs, error_code& ec)
|
write(ConstBufferSequence const& bs, error_code& ec)
|
||||||
{
|
{
|
||||||
|
static_assert(is_SyncStream<next_layer_type>::value,
|
||||||
|
"SyncStream requirements not met");
|
||||||
static_assert(beast::is_ConstBufferSequence<
|
static_assert(beast::is_ConstBufferSequence<
|
||||||
ConstBufferSequence>::value,
|
ConstBufferSequence>::value,
|
||||||
"ConstBufferSequence requirements not met");
|
"ConstBufferSequence requirements not met");
|
||||||
@ -582,6 +696,8 @@ typename async_completion<
|
|||||||
stream<NextLayer>::
|
stream<NextLayer>::
|
||||||
async_write(ConstBufferSequence const& bs, WriteHandler&& handler)
|
async_write(ConstBufferSequence const& bs, WriteHandler&& handler)
|
||||||
{
|
{
|
||||||
|
static_assert(is_AsyncStream<next_layer_type>::value,
|
||||||
|
"AsyncStream requirements not met");
|
||||||
static_assert(beast::is_ConstBufferSequence<
|
static_assert(beast::is_ConstBufferSequence<
|
||||||
ConstBufferSequence>::value,
|
ConstBufferSequence>::value,
|
||||||
"ConstBufferSequence requirements not met");
|
"ConstBufferSequence requirements not met");
|
||||||
@ -592,12 +708,27 @@ async_write(ConstBufferSequence const& bs, WriteHandler&& handler)
|
|||||||
return completion.result.get();
|
return completion.result.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class NextLayer>
|
||||||
|
template<class ConstBufferSequence>
|
||||||
|
void
|
||||||
|
stream<NextLayer>::
|
||||||
|
write_frame(bool fin, ConstBufferSequence const& buffers)
|
||||||
|
{
|
||||||
|
static_assert(is_SyncStream<next_layer_type>::value,
|
||||||
|
"SyncStream requirements not met");
|
||||||
|
error_code ec;
|
||||||
|
write_frame(fin, buffers, ec);
|
||||||
|
detail::maybe_throw(ec, "write");
|
||||||
|
}
|
||||||
|
|
||||||
template<class NextLayer>
|
template<class NextLayer>
|
||||||
template<class ConstBufferSequence>
|
template<class ConstBufferSequence>
|
||||||
void
|
void
|
||||||
stream<NextLayer>::
|
stream<NextLayer>::
|
||||||
write_frame(bool fin, ConstBufferSequence const& bs, error_code& ec)
|
write_frame(bool fin, ConstBufferSequence const& bs, error_code& ec)
|
||||||
{
|
{
|
||||||
|
static_assert(is_SyncStream<next_layer_type>::value,
|
||||||
|
"SyncStream requirements not met");
|
||||||
static_assert(beast::is_ConstBufferSequence<
|
static_assert(beast::is_ConstBufferSequence<
|
||||||
ConstBufferSequence>::value,
|
ConstBufferSequence>::value,
|
||||||
"ConstBufferSequence requirements not met");
|
"ConstBufferSequence requirements not met");
|
||||||
@ -678,6 +809,8 @@ stream<NextLayer>::
|
|||||||
async_write_frame(bool fin,
|
async_write_frame(bool fin,
|
||||||
ConstBufferSequence const& bs, WriteHandler&& handler)
|
ConstBufferSequence const& bs, WriteHandler&& handler)
|
||||||
{
|
{
|
||||||
|
static_assert(is_AsyncStream<next_layer_type>::value,
|
||||||
|
"AsyncStream requirements not met");
|
||||||
static_assert(beast::is_ConstBufferSequence<
|
static_assert(beast::is_ConstBufferSequence<
|
||||||
ConstBufferSequence>::value,
|
ConstBufferSequence>::value,
|
||||||
"ConstBufferSequence requirements not met");
|
"ConstBufferSequence requirements not met");
|
||||||
@ -792,7 +925,7 @@ template<class NextLayer>
|
|||||||
void
|
void
|
||||||
stream<NextLayer>::
|
stream<NextLayer>::
|
||||||
do_read_fh(detail::frame_streambuf& fb,
|
do_read_fh(detail::frame_streambuf& fb,
|
||||||
close_code& code, error_code& ec)
|
close_code::value& code, error_code& ec)
|
||||||
{
|
{
|
||||||
fb.commit(boost::asio::read(
|
fb.commit(boost::asio::read(
|
||||||
stream_, fb.prepare(2), ec));
|
stream_, fb.prepare(2), ec));
|
||||||
|
@ -61,7 +61,8 @@ class stream<NextLayer>::write_frame_op
|
|||||||
fh.rsv2 = 0;
|
fh.rsv2 = 0;
|
||||||
fh.rsv3 = 0;
|
fh.rsv3 = 0;
|
||||||
fh.len = boost::asio::buffer_size(cb);
|
fh.len = boost::asio::buffer_size(cb);
|
||||||
if((fh.mask = (ws.role_ == role_type::client)))
|
fh.mask = ws.role_ == role_type::client;
|
||||||
|
if(fh.mask)
|
||||||
{
|
{
|
||||||
fh.key = ws.maskgen_();
|
fh.key = ws.maskgen_();
|
||||||
detail::prepare_key(key, fh.key);
|
detail::prepare_key(key, fh.key);
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
#ifndef BEAST_WEBSOCKET_RFC6455_HPP
|
#ifndef BEAST_WEBSOCKET_RFC6455_HPP
|
||||||
#define BEAST_WEBSOCKET_RFC6455_HPP
|
#define BEAST_WEBSOCKET_RFC6455_HPP
|
||||||
|
|
||||||
#include <beast/websocket/static_string.hpp>
|
#include <beast/static_string.hpp>
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
@ -44,7 +44,9 @@ enum class opcode : std::uint8_t
|
|||||||
@see RFC 6455 7.4.1 Defined Status Codes
|
@see RFC 6455 7.4.1 Defined Status Codes
|
||||||
https://tools.ietf.org/html/rfc6455#section-7.4.1
|
https://tools.ietf.org/html/rfc6455#section-7.4.1
|
||||||
*/
|
*/
|
||||||
enum class close_code : std::uint16_t
|
namespace close_code {
|
||||||
|
using value = std::uint16_t;
|
||||||
|
enum
|
||||||
{
|
{
|
||||||
// used internally to mean "no error"
|
// used internally to mean "no error"
|
||||||
none = 0,
|
none = 0,
|
||||||
@ -69,6 +71,7 @@ enum class close_code : std::uint16_t
|
|||||||
|
|
||||||
last = 5000 // satisfy warnings
|
last = 5000 // satisfy warnings
|
||||||
};
|
};
|
||||||
|
} // close_code
|
||||||
|
|
||||||
#if ! GENERATING_DOCS
|
#if ! GENERATING_DOCS
|
||||||
|
|
||||||
@ -89,7 +92,7 @@ using ping_payload_type =
|
|||||||
struct close_reason
|
struct close_reason
|
||||||
{
|
{
|
||||||
/// The close code.
|
/// The close code.
|
||||||
close_code code = close_code::none;
|
close_code::value code = close_code::none;
|
||||||
|
|
||||||
/// The optional utf8-encoded reason string.
|
/// The optional utf8-encoded reason string.
|
||||||
reason_string_type reason;
|
reason_string_type reason;
|
||||||
@ -102,7 +105,7 @@ struct close_reason
|
|||||||
close_reason() = default;
|
close_reason() = default;
|
||||||
|
|
||||||
/// Construct from a code.
|
/// Construct from a code.
|
||||||
close_reason(close_code code_)
|
close_reason(close_code::value code_)
|
||||||
: code(code_)
|
: code(code_)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -117,7 +120,7 @@ struct close_reason
|
|||||||
|
|
||||||
/// Construct from a code and reason.
|
/// Construct from a code and reason.
|
||||||
template<class CharT>
|
template<class CharT>
|
||||||
close_reason(close_code code_,
|
close_reason(close_code::value code_,
|
||||||
CharT const* reason_)
|
CharT const* reason_)
|
||||||
: code(code_)
|
: code(code_)
|
||||||
, reason(reason_)
|
, reason(reason_)
|
||||||
|
@ -1,337 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
|
||||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for any
|
|
||||||
purpose with or without fee is hereby granted, provided that the above
|
|
||||||
copyright notice and this permission notice appear in all copies.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
//==============================================================================
|
|
||||||
|
|
||||||
#ifndef BEAST_WEBSOCKET_STATIC_STRING_HPP
|
|
||||||
#define BEAST_WEBSOCKET_STATIC_STRING_HPP
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <array>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <iterator>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace beast {
|
|
||||||
namespace websocket {
|
|
||||||
|
|
||||||
/** A string with a fixed-size storage area.
|
|
||||||
|
|
||||||
`static_string` objects behave like `std::string` except that
|
|
||||||
the storage is not dynamically allocated but rather fixed in
|
|
||||||
size.
|
|
||||||
|
|
||||||
These strings offer performance advantages when a protocol
|
|
||||||
imposes a natural small upper limit on the size of a value.
|
|
||||||
*/
|
|
||||||
template<std::size_t N, class CharT,
|
|
||||||
class Traits = std::char_traits<CharT>>
|
|
||||||
class static_string
|
|
||||||
{
|
|
||||||
std::size_t n_;
|
|
||||||
std::array<CharT, N+1> s_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
using traits_type = Traits;
|
|
||||||
using value_type = typename Traits::char_type;
|
|
||||||
using size_type = std::size_t;
|
|
||||||
using difference_type = std::ptrdiff_t;
|
|
||||||
using pointer = value_type*;
|
|
||||||
using reference = value_type&;
|
|
||||||
using const_pointer = value_type const*;
|
|
||||||
using const_reference = value_type const&;
|
|
||||||
using iterator = value_type*;
|
|
||||||
using const_iterator = value_type const*;
|
|
||||||
using reverse_iterator =
|
|
||||||
std::reverse_iterator<iterator>;
|
|
||||||
using const_reverse_iterator =
|
|
||||||
std::reverse_iterator<const_iterator>;
|
|
||||||
|
|
||||||
static_string()
|
|
||||||
{
|
|
||||||
resize(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static_string(static_string const& s)
|
|
||||||
: n_(s.n_)
|
|
||||||
{
|
|
||||||
std::copy(&s.s_[0], &s.s_[0]+s.n_+1, &s_[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static_string&
|
|
||||||
operator=(static_string const& s)
|
|
||||||
{
|
|
||||||
n_ = s.n_;
|
|
||||||
std::copy(&s.s_[0], &s.s_[0]+s.n_+1, &s_[0]);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
static_string(CharT const* s)
|
|
||||||
{
|
|
||||||
assign(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
static_string& operator=(CharT const* s)
|
|
||||||
{
|
|
||||||
assign(s);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
reference
|
|
||||||
at(size_type pos)
|
|
||||||
{
|
|
||||||
if(pos >= n_)
|
|
||||||
throw std::out_of_range("static_string::at");
|
|
||||||
return s_[pos];
|
|
||||||
}
|
|
||||||
|
|
||||||
const_reference
|
|
||||||
at(size_type pos) const
|
|
||||||
{
|
|
||||||
if(pos >= n_)
|
|
||||||
throw std::out_of_range("static_string::at");
|
|
||||||
return s_[pos];
|
|
||||||
}
|
|
||||||
|
|
||||||
reference
|
|
||||||
operator[](size_type pos);
|
|
||||||
|
|
||||||
const_reference
|
|
||||||
operator[](size_type pos) const;
|
|
||||||
|
|
||||||
CharT&
|
|
||||||
front()
|
|
||||||
{
|
|
||||||
return s_[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
CharT const&
|
|
||||||
front() const
|
|
||||||
{
|
|
||||||
return s_[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
CharT&
|
|
||||||
back()
|
|
||||||
{
|
|
||||||
return s_[n_-1];
|
|
||||||
}
|
|
||||||
|
|
||||||
CharT const&
|
|
||||||
back() const
|
|
||||||
{
|
|
||||||
return s_[n_-1];
|
|
||||||
}
|
|
||||||
|
|
||||||
CharT*
|
|
||||||
data()
|
|
||||||
{
|
|
||||||
return &s_[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
CharT const*
|
|
||||||
data() const
|
|
||||||
{
|
|
||||||
return &s_[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
CharT const*
|
|
||||||
c_str() const
|
|
||||||
{
|
|
||||||
s_[n_] = 0;
|
|
||||||
return &s_[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator
|
|
||||||
begin()
|
|
||||||
{
|
|
||||||
return &s_[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
const_iterator
|
|
||||||
begin() const
|
|
||||||
{
|
|
||||||
return &s_[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
const_iterator
|
|
||||||
cbegin() const
|
|
||||||
{
|
|
||||||
return &s_[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator
|
|
||||||
end()
|
|
||||||
{
|
|
||||||
return &s_[n_];
|
|
||||||
}
|
|
||||||
|
|
||||||
const_iterator
|
|
||||||
end() const
|
|
||||||
{
|
|
||||||
return &s_[n_];
|
|
||||||
}
|
|
||||||
|
|
||||||
const_iterator
|
|
||||||
cend() const
|
|
||||||
{
|
|
||||||
return &s_[n_];
|
|
||||||
}
|
|
||||||
|
|
||||||
reverse_iterator
|
|
||||||
rbegin()
|
|
||||||
{
|
|
||||||
return reverse_iterator{end()};
|
|
||||||
}
|
|
||||||
|
|
||||||
const_reverse_iterator
|
|
||||||
rbegin() const
|
|
||||||
{
|
|
||||||
return reverse_iterator{end()};
|
|
||||||
}
|
|
||||||
|
|
||||||
const_reverse_iterator
|
|
||||||
crbegin() const
|
|
||||||
{
|
|
||||||
return reverse_iterator{cend()};
|
|
||||||
}
|
|
||||||
|
|
||||||
reverse_iterator
|
|
||||||
rend()
|
|
||||||
{
|
|
||||||
return reverse_iterator{begin()};
|
|
||||||
}
|
|
||||||
|
|
||||||
const_reverse_iterator
|
|
||||||
rend() const
|
|
||||||
{
|
|
||||||
return reverse_iterator{begin()};
|
|
||||||
}
|
|
||||||
|
|
||||||
const_reverse_iterator
|
|
||||||
crend() const
|
|
||||||
{
|
|
||||||
return reverse_iterator{cbegin()};
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
empty() const
|
|
||||||
{
|
|
||||||
return n_ == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_type
|
|
||||||
size() const
|
|
||||||
{
|
|
||||||
return n_;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_type constexpr
|
|
||||||
max_size() const
|
|
||||||
{
|
|
||||||
return N;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_type
|
|
||||||
capacity() const
|
|
||||||
{
|
|
||||||
return N;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
shrink_to_fit()
|
|
||||||
{
|
|
||||||
// no-op
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
clear()
|
|
||||||
{
|
|
||||||
resize(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Does not perform value-initialization
|
|
||||||
void
|
|
||||||
resize(std::size_t n);
|
|
||||||
|
|
||||||
std::basic_string<CharT, Traits>
|
|
||||||
to_string() const
|
|
||||||
{
|
|
||||||
return std::basic_string<
|
|
||||||
CharT, Traits>{&s_[0], n_};
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void
|
|
||||||
assign(CharT const* s);
|
|
||||||
};
|
|
||||||
|
|
||||||
template<std::size_t N, class CharT, class Traits>
|
|
||||||
auto
|
|
||||||
static_string<N, CharT, Traits>::
|
|
||||||
operator[](size_type pos) ->
|
|
||||||
reference
|
|
||||||
{
|
|
||||||
static CharT null{0};
|
|
||||||
if(pos == n_)
|
|
||||||
return null;
|
|
||||||
return s_[pos];
|
|
||||||
}
|
|
||||||
|
|
||||||
template<std::size_t N, class CharT, class Traits>
|
|
||||||
auto
|
|
||||||
static_string<N, CharT, Traits>::
|
|
||||||
operator[](size_type pos) const ->
|
|
||||||
const_reference
|
|
||||||
{
|
|
||||||
static CharT constexpr null{0};
|
|
||||||
if(pos == n_)
|
|
||||||
return null;
|
|
||||||
return s_[pos];
|
|
||||||
}
|
|
||||||
|
|
||||||
template<std::size_t N, class CharT, class Traits>
|
|
||||||
void
|
|
||||||
static_string<N, CharT, Traits>::
|
|
||||||
resize(std::size_t n)
|
|
||||||
{
|
|
||||||
if(n > N)
|
|
||||||
throw std::length_error(
|
|
||||||
"static_string overflow");
|
|
||||||
n_ = n;
|
|
||||||
s_[n_] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<std::size_t N, class CharT, class Traits>
|
|
||||||
void
|
|
||||||
static_string<N, CharT, Traits>::
|
|
||||||
assign(CharT const* s)
|
|
||||||
{
|
|
||||||
size_type n = 0;
|
|
||||||
for(auto p = s; *p; ++p)
|
|
||||||
++n;
|
|
||||||
if(n > N)
|
|
||||||
throw std::out_of_range(
|
|
||||||
"too large");
|
|
||||||
std::copy(s, s+n, s_.begin());
|
|
||||||
}
|
|
||||||
|
|
||||||
} // websocket
|
|
||||||
} // beast
|
|
||||||
|
|
||||||
#endif
|
|
@ -12,6 +12,7 @@
|
|||||||
#include <beast/websocket/detail/stream_base.hpp>
|
#include <beast/websocket/detail/stream_base.hpp>
|
||||||
#include <beast/streambuf_readstream.hpp>
|
#include <beast/streambuf_readstream.hpp>
|
||||||
#include <beast/async_completion.hpp>
|
#include <beast/async_completion.hpp>
|
||||||
|
#include <beast/detail/get_lowest_layer.hpp>
|
||||||
#include <beast/http/message.hpp>
|
#include <beast/http/message.hpp>
|
||||||
#include <beast/http/string_body.hpp>
|
#include <beast/http/string_body.hpp>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
@ -80,8 +81,7 @@ class stream : public detail::stream_base
|
|||||||
{
|
{
|
||||||
friend class ws_test;
|
friend class ws_test;
|
||||||
|
|
||||||
NextLayer next_layer_;
|
streambuf_readstream<NextLayer, streambuf> stream_;
|
||||||
streambuf_readstream<NextLayer&, streambuf> stream_;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// The type of the next layer.
|
/// The type of the next layer.
|
||||||
@ -90,26 +90,26 @@ public:
|
|||||||
|
|
||||||
/// The type of the lowest layer.
|
/// The type of the lowest layer.
|
||||||
using lowest_layer_type =
|
using lowest_layer_type =
|
||||||
typename next_layer_type::lowest_layer_type;
|
typename beast::detail::get_lowest_layer<
|
||||||
|
next_layer_type>::type;
|
||||||
|
|
||||||
/// The type of endpoint of the lowest layer.
|
/** Move-construct a stream.
|
||||||
using endpoint_type =
|
|
||||||
typename lowest_layer_type::endpoint_type;
|
|
||||||
|
|
||||||
/// The protocol of the next layer.
|
If @c NextLayer is move constructible, this function
|
||||||
using protocol_type =
|
will move-construct a new stream from the existing stream.
|
||||||
typename lowest_layer_type::protocol_type;
|
|
||||||
|
|
||||||
/// The type of resolver of the next layer.
|
@note The behavior of move assignment on or from streams
|
||||||
using resolver_type =
|
with active or pending operations is undefined.
|
||||||
typename protocol_type::resolver;
|
*/
|
||||||
|
|
||||||
/// Move constructor.
|
|
||||||
stream(stream&&) = default;
|
stream(stream&&) = default;
|
||||||
|
|
||||||
/** Move assignment.
|
/** Move assignment.
|
||||||
|
|
||||||
Undefined behavior if operations are active or pending.
|
If @c NextLayer is move constructible, this function
|
||||||
|
will move-construct a new stream from the existing stream.
|
||||||
|
|
||||||
|
@note The behavior of move assignment on or from streams
|
||||||
|
with active or pending operations is undefined.
|
||||||
*/
|
*/
|
||||||
stream& operator=(stream&&) = default;
|
stream& operator=(stream&&) = default;
|
||||||
|
|
||||||
@ -217,7 +217,7 @@ public:
|
|||||||
boost::asio::io_service&
|
boost::asio::io_service&
|
||||||
get_io_service()
|
get_io_service()
|
||||||
{
|
{
|
||||||
return next_layer_.lowest_layer().get_io_service();
|
return stream_.get_io_service();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get a reference to the next layer.
|
/** Get a reference to the next layer.
|
||||||
@ -231,7 +231,7 @@ public:
|
|||||||
next_layer_type&
|
next_layer_type&
|
||||||
next_layer()
|
next_layer()
|
||||||
{
|
{
|
||||||
return next_layer_;
|
return stream_.next_layer();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get a reference to the next layer.
|
/** Get a reference to the next layer.
|
||||||
@ -245,7 +245,7 @@ public:
|
|||||||
next_layer_type const&
|
next_layer_type const&
|
||||||
next_layer() const
|
next_layer() const
|
||||||
{
|
{
|
||||||
return next_layer_;
|
return stream_.next_layer();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get a reference to the lowest layer.
|
/** Get a reference to the lowest layer.
|
||||||
@ -259,7 +259,7 @@ public:
|
|||||||
lowest_layer_type&
|
lowest_layer_type&
|
||||||
lowest_layer()
|
lowest_layer()
|
||||||
{
|
{
|
||||||
return next_layer_.lowest_layer();
|
return stream_.lowest_layer();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get a reference to the lowest layer.
|
/** Get a reference to the lowest layer.
|
||||||
@ -273,7 +273,7 @@ public:
|
|||||||
lowest_layer_type const&
|
lowest_layer_type const&
|
||||||
lowest_layer() const
|
lowest_layer() const
|
||||||
{
|
{
|
||||||
return next_layer_.lowest_layer();
|
return stream_.lowest_layer();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the close reason received from the peer.
|
/** Returns the close reason received from the peer.
|
||||||
@ -309,12 +309,7 @@ public:
|
|||||||
@throws boost::system::system_error Thrown on failure.
|
@throws boost::system::system_error Thrown on failure.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
accept()
|
accept();
|
||||||
{
|
|
||||||
error_code ec;
|
|
||||||
accept(boost::asio::null_buffers{}, ec);
|
|
||||||
detail::maybe_throw(ec, "accept");
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Read and respond to a WebSocket HTTP Upgrade request.
|
/** Read and respond to a WebSocket HTTP Upgrade request.
|
||||||
|
|
||||||
@ -603,12 +598,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
handshake(boost::string_ref const& host,
|
handshake(boost::string_ref const& host,
|
||||||
boost::string_ref const& resource)
|
boost::string_ref const& resource);
|
||||||
{
|
|
||||||
error_code ec;
|
|
||||||
handshake(host, resource, ec);
|
|
||||||
detail::maybe_throw(ec, "upgrade");
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Send a WebSocket Upgrade request.
|
/** Send a WebSocket Upgrade request.
|
||||||
|
|
||||||
@ -692,12 +682,7 @@ public:
|
|||||||
@param cr The reason for the close.
|
@param cr The reason for the close.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
close(close_reason const& cr)
|
close(close_reason const& cr);
|
||||||
{
|
|
||||||
error_code ec;
|
|
||||||
close(cr, ec);
|
|
||||||
detail::maybe_throw(ec, "close");
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Perform a WebSocket close.
|
/** Perform a WebSocket close.
|
||||||
|
|
||||||
@ -773,12 +758,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
template<class Streambuf>
|
template<class Streambuf>
|
||||||
void
|
void
|
||||||
read(opcode& op, Streambuf& streambuf)
|
read(opcode& op, Streambuf& streambuf);
|
||||||
{
|
|
||||||
error_code ec;
|
|
||||||
read(op, streambuf, ec);
|
|
||||||
detail::maybe_throw(ec, "read");
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Read a message.
|
/** Read a message.
|
||||||
|
|
||||||
@ -868,12 +848,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
template<class Streambuf>
|
template<class Streambuf>
|
||||||
void
|
void
|
||||||
read_frame(frame_info& fi, Streambuf& streambuf)
|
read_frame(frame_info& fi, Streambuf& streambuf);
|
||||||
{
|
|
||||||
error_code ec;
|
|
||||||
read_frame(fi, streambuf, ec);
|
|
||||||
detail::maybe_throw(ec, "read_some");
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Read a message frame.
|
/** Read a message frame.
|
||||||
|
|
||||||
@ -978,12 +953,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
template<class ConstBufferSequence>
|
template<class ConstBufferSequence>
|
||||||
void
|
void
|
||||||
write(ConstBufferSequence const& buffers)
|
write(ConstBufferSequence const& buffers);
|
||||||
{
|
|
||||||
error_code ec;
|
|
||||||
write(buffers, ec);
|
|
||||||
detail::maybe_throw(ec, "write");
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Send a message.
|
/** Send a message.
|
||||||
|
|
||||||
@ -1081,12 +1051,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
template<class ConstBufferSequence>
|
template<class ConstBufferSequence>
|
||||||
void
|
void
|
||||||
write_frame(bool fin, ConstBufferSequence const& buffers)
|
write_frame(bool fin, ConstBufferSequence const& buffers);
|
||||||
{
|
|
||||||
error_code ec;
|
|
||||||
write_frame(fin, buffers, ec);
|
|
||||||
detail::maybe_throw(ec, "write");
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Send a frame.
|
/** Send a frame.
|
||||||
|
|
||||||
@ -1180,7 +1145,7 @@ private:
|
|||||||
|
|
||||||
void
|
void
|
||||||
do_read_fh(detail::frame_streambuf& fb,
|
do_read_fh(detail::frame_streambuf& fb,
|
||||||
close_code& code, error_code& ec);
|
close_code::value& code, error_code& ec);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // websocket
|
} // websocket
|
||||||
|
@ -7,5 +7,3 @@ echo "using toolset: $CC"
|
|||||||
echo "using variant: $VARIANT"
|
echo "using variant: $VARIANT"
|
||||||
|
|
||||||
$BOOST_ROOT/bjam toolset=$CC variant=$VARIANT
|
$BOOST_ROOT/bjam toolset=$CC variant=$VARIANT
|
||||||
`find . -name "core_tests"`
|
|
||||||
`find . -name "http_tests"`
|
|
||||||
|
@ -16,6 +16,7 @@ add_executable (core-tests
|
|||||||
placeholders.cpp
|
placeholders.cpp
|
||||||
prepare_buffers.cpp
|
prepare_buffers.cpp
|
||||||
static_streambuf.cpp
|
static_streambuf.cpp
|
||||||
|
static_string.cpp
|
||||||
streambuf.cpp
|
streambuf.cpp
|
||||||
streambuf_readstream.cpp
|
streambuf_readstream.cpp
|
||||||
to_string.cpp
|
to_string.cpp
|
||||||
@ -54,21 +55,6 @@ if (NOT WIN32)
|
|||||||
target_link_libraries(http-tests ${Boost_LIBRARIES})
|
target_link_libraries(http-tests ${Boost_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_executable (websocket-tests
|
|
||||||
${BEAST_INCLUDES}
|
|
||||||
main.cpp
|
|
||||||
websocket/error.cpp
|
|
||||||
websocket/option.cpp
|
|
||||||
websocket/rfc6455.cpp
|
|
||||||
websocket/static_string.cpp
|
|
||||||
websocket/teardown.cpp
|
|
||||||
websocket/utf8_checker.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
if (NOT WIN32)
|
|
||||||
target_link_libraries(websocket-tests ${Boost_LIBRARIES})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_executable (parser-bench
|
add_executable (parser-bench
|
||||||
${BEAST_INCLUDES}
|
${BEAST_INCLUDES}
|
||||||
main.cpp
|
main.cpp
|
||||||
@ -80,3 +66,31 @@ if (NOT WIN32)
|
|||||||
target_link_libraries(parser-bench ${Boost_LIBRARIES})
|
target_link_libraries(parser-bench ${Boost_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
add_executable (websocket-tests
|
||||||
|
${BEAST_INCLUDES}
|
||||||
|
websocket/websocket_async_echo_peer.hpp
|
||||||
|
websocket/websocket_sync_echo_peer.hpp
|
||||||
|
main.cpp
|
||||||
|
websocket/error.cpp
|
||||||
|
websocket/option.cpp
|
||||||
|
websocket/rfc6455.cpp
|
||||||
|
websocket/stream.cpp
|
||||||
|
websocket/teardown.cpp
|
||||||
|
websocket/utf8_checker.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
if (NOT WIN32)
|
||||||
|
target_link_libraries(websocket-tests ${Boost_LIBRARIES})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_executable (websocket-echo
|
||||||
|
${BEAST_INCLUDES}
|
||||||
|
sig_wait.hpp
|
||||||
|
websocket/websocket_async_echo_peer.hpp
|
||||||
|
websocket/websocket_sync_echo_peer.hpp
|
||||||
|
websocket/websocket_echo.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
if (NOT WIN32)
|
||||||
|
target_link_libraries(websocket-echo ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
||||||
|
endif()
|
||||||
|
26
test/Jamfile
26
test/Jamfile
@ -19,6 +19,7 @@ unit-test core-tests :
|
|||||||
placeholders.cpp
|
placeholders.cpp
|
||||||
prepare_buffers.cpp
|
prepare_buffers.cpp
|
||||||
static_streambuf.cpp
|
static_streambuf.cpp
|
||||||
|
static_string.cpp
|
||||||
streambuf.cpp
|
streambuf.cpp
|
||||||
streambuf_readstream.cpp
|
streambuf_readstream.cpp
|
||||||
to_string.cpp
|
to_string.cpp
|
||||||
@ -48,18 +49,23 @@ unit-test http-tests :
|
|||||||
http/write.cpp
|
http/write.cpp
|
||||||
;
|
;
|
||||||
|
|
||||||
unit-test websocket-tests :
|
|
||||||
main.cpp
|
|
||||||
websocket/error.cpp
|
|
||||||
websocket/option.cpp
|
|
||||||
websocket/rfc6455.cpp
|
|
||||||
websocket/static_string.cpp
|
|
||||||
websocket/teardown.cpp
|
|
||||||
websocket/utf8_checker.cpp
|
|
||||||
;
|
|
||||||
|
|
||||||
unit-test parser-bench :
|
unit-test parser-bench :
|
||||||
main.cpp
|
main.cpp
|
||||||
http/nodejs_parser.cpp
|
http/nodejs_parser.cpp
|
||||||
http/parser_bench.cpp
|
http/parser_bench.cpp
|
||||||
;
|
;
|
||||||
|
|
||||||
|
unit-test websocket-tests :
|
||||||
|
main.cpp
|
||||||
|
websocket/error.cpp
|
||||||
|
websocket/option.cpp
|
||||||
|
websocket/rfc6455.cpp
|
||||||
|
websocket/stream.cpp
|
||||||
|
websocket/teardown.cpp
|
||||||
|
websocket/utf8_checker.cpp
|
||||||
|
;
|
||||||
|
|
||||||
|
exe websocket-echo :
|
||||||
|
websocket/websocket_echo.cpp
|
||||||
|
;
|
||||||
|
|
||||||
|
191
test/static_string.cpp
Normal file
191
test/static_string.cpp
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
//
|
||||||
|
// 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)
|
||||||
|
//
|
||||||
|
|
||||||
|
// Test that header file is self-contained.
|
||||||
|
#include <beast/static_string.hpp>
|
||||||
|
|
||||||
|
#include <beast/detail/unit_test/suite.hpp>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace websocket {
|
||||||
|
|
||||||
|
class static_string_test : public beast::detail::unit_test::suite
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void testMembers()
|
||||||
|
{
|
||||||
|
using str1 = static_string<1>;
|
||||||
|
using str2 = static_string<2>;
|
||||||
|
{
|
||||||
|
str1 s1;
|
||||||
|
expect(s1 == "");
|
||||||
|
expect(s1.empty());
|
||||||
|
expect(s1.size() == 0);
|
||||||
|
expect(s1.max_size() == 1);
|
||||||
|
expect(s1.capacity() == 1);
|
||||||
|
expect(s1.begin() == s1.end());
|
||||||
|
expect(s1.cbegin() == s1.cend());
|
||||||
|
expect(s1.rbegin() == s1.rend());
|
||||||
|
expect(s1.crbegin() == s1.crend());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
expect(s1.at(0) == 0);
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
catch(std::exception const&)
|
||||||
|
{
|
||||||
|
pass();
|
||||||
|
}
|
||||||
|
expect(s1.data()[0] == 0);
|
||||||
|
expect(*s1.c_str() == 0);
|
||||||
|
expect(std::distance(s1.begin(), s1.end()) == 0);
|
||||||
|
expect(std::distance(s1.cbegin(), s1.cend()) == 0);
|
||||||
|
expect(std::distance(s1.rbegin(), s1.rend()) == 0);
|
||||||
|
expect(std::distance(s1.crbegin(), s1.crend()) == 0);
|
||||||
|
expect(s1.compare(s1) == 0);
|
||||||
|
expect(s1.to_string() == std::string{});
|
||||||
|
}
|
||||||
|
{
|
||||||
|
str1 const s1;
|
||||||
|
expect(s1 == "");
|
||||||
|
expect(s1.empty());
|
||||||
|
expect(s1.size() == 0);
|
||||||
|
expect(s1.max_size() == 1);
|
||||||
|
expect(s1.capacity() == 1);
|
||||||
|
expect(s1.begin() == s1.end());
|
||||||
|
expect(s1.cbegin() == s1.cend());
|
||||||
|
expect(s1.rbegin() == s1.rend());
|
||||||
|
expect(s1.crbegin() == s1.crend());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
expect(s1.at(0) == 0);
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
catch(std::exception const&)
|
||||||
|
{
|
||||||
|
pass();
|
||||||
|
}
|
||||||
|
expect(s1.data()[0] == 0);
|
||||||
|
expect(*s1.c_str() == 0);
|
||||||
|
expect(std::distance(s1.begin(), s1.end()) == 0);
|
||||||
|
expect(std::distance(s1.cbegin(), s1.cend()) == 0);
|
||||||
|
expect(std::distance(s1.rbegin(), s1.rend()) == 0);
|
||||||
|
expect(std::distance(s1.crbegin(), s1.crend()) == 0);
|
||||||
|
expect(s1.compare(s1) == 0);
|
||||||
|
expect(s1.to_string() == std::string{});
|
||||||
|
}
|
||||||
|
{
|
||||||
|
str1 s1;
|
||||||
|
str1 s2("x");
|
||||||
|
expect(s2 == "x");
|
||||||
|
expect(s2[0] == 'x');
|
||||||
|
expect(s2.at(0) == 'x');
|
||||||
|
expect(s2.front() == 'x');
|
||||||
|
expect(s2.back() == 'x');
|
||||||
|
str1 const s3(s2);
|
||||||
|
expect(s3 == "x");
|
||||||
|
expect(s3[0] == 'x');
|
||||||
|
expect(s3.at(0) == 'x');
|
||||||
|
expect(s3.front() == 'x');
|
||||||
|
expect(s3.back() == 'x');
|
||||||
|
s2 = "y";
|
||||||
|
expect(s2 == "y");
|
||||||
|
s1 = s2;
|
||||||
|
expect(s1 == "y");
|
||||||
|
s1.clear();
|
||||||
|
expect(s1.empty());
|
||||||
|
expect(s1.size() == 0);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
str2 s1("x");
|
||||||
|
str1 s2(s1);
|
||||||
|
expect(s2 == "x");
|
||||||
|
str1 s3;
|
||||||
|
s3 = s2;
|
||||||
|
expect(s3 == "x");
|
||||||
|
s1 = "xy";
|
||||||
|
expect(s1.size() == 2);
|
||||||
|
expect(s1[0] == 'x');
|
||||||
|
expect(s1[1] == 'y');
|
||||||
|
expect(s1.at(0) == 'x');
|
||||||
|
expect(s1.at(1) == 'y');
|
||||||
|
expect(s1.front() == 'x');
|
||||||
|
expect(s1.back() == 'y');
|
||||||
|
auto const s4 = s1;
|
||||||
|
expect(s4[0] == 'x');
|
||||||
|
expect(s4[1] == 'y');
|
||||||
|
expect(s4.at(0) == 'x');
|
||||||
|
expect(s4.at(1) == 'y');
|
||||||
|
expect(s4.front() == 'x');
|
||||||
|
expect(s4.back() == 'y');
|
||||||
|
try
|
||||||
|
{
|
||||||
|
s3 = s1;
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
catch(std::exception const&)
|
||||||
|
{
|
||||||
|
pass();
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
str1 s5(s1);
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
catch(std::exception const&)
|
||||||
|
{
|
||||||
|
pass();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
str2 s1("x");
|
||||||
|
str2 s2("x");
|
||||||
|
expect(s1 == s2);
|
||||||
|
expect(s1 <= s2);
|
||||||
|
expect(s1 >= s2);
|
||||||
|
expect(! (s1 < s2));
|
||||||
|
expect(! (s1 > s2));
|
||||||
|
expect(! (s1 != s2));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
str1 s1("x");
|
||||||
|
str2 s2("x");
|
||||||
|
expect(s1 == s2);
|
||||||
|
expect(s1 <= s2);
|
||||||
|
expect(s1 >= s2);
|
||||||
|
expect(! (s1 < s2));
|
||||||
|
expect(! (s1 > s2));
|
||||||
|
expect(! (s1 != s2));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
str2 s("x");
|
||||||
|
expect(s == "x");
|
||||||
|
expect(s <= "x");
|
||||||
|
expect(s >= "x");
|
||||||
|
expect(! (s < "x"));
|
||||||
|
expect(! (s > "x"));
|
||||||
|
expect(! (s != "x"));
|
||||||
|
expect("x" == s);
|
||||||
|
expect("x" <= s);
|
||||||
|
expect("x" >= s);
|
||||||
|
expect(! ("x" < s));
|
||||||
|
expect(! ("x" > s));
|
||||||
|
expect(! ("x" != s));
|
||||||
|
}
|
||||||
|
pass();
|
||||||
|
}
|
||||||
|
|
||||||
|
void run() override
|
||||||
|
{
|
||||||
|
testMembers();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BEAST_DEFINE_TESTSUITE(static_string,websocket,beast);
|
||||||
|
|
||||||
|
} // websocket
|
||||||
|
} // beast
|
@ -7,3 +7,40 @@
|
|||||||
|
|
||||||
// Test that header file is self-contained.
|
// Test that header file is self-contained.
|
||||||
#include <beast/streambuf_readstream.hpp>
|
#include <beast/streambuf_readstream.hpp>
|
||||||
|
|
||||||
|
#include <beast/streambuf.hpp>
|
||||||
|
#include <beast/detail/unit_test/suite.hpp>
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
|
||||||
|
class streambuf_readstream_test : public beast::detail::unit_test::suite
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void testSpecial()
|
||||||
|
{
|
||||||
|
using socket_type = boost::asio::ip::tcp::socket;
|
||||||
|
boost::asio::io_service ios;
|
||||||
|
{
|
||||||
|
streambuf_readstream<socket_type, streambuf> srs(ios);
|
||||||
|
streambuf_readstream<socket_type, streambuf> srs2(std::move(srs));
|
||||||
|
srs = std::move(srs2);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
socket_type sock(ios);
|
||||||
|
streambuf_readstream<socket_type&, streambuf> srs(sock);
|
||||||
|
streambuf_readstream<socket_type&, streambuf> srs2(std::move(srs));
|
||||||
|
}
|
||||||
|
pass();
|
||||||
|
}
|
||||||
|
|
||||||
|
void run() override
|
||||||
|
{
|
||||||
|
testSpecial();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BEAST_DEFINE_TESTSUITE(streambuf_readstream,core,beast);
|
||||||
|
|
||||||
|
} // beast
|
||||||
|
|
||||||
|
@ -1,9 +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)
|
|
||||||
//
|
|
||||||
|
|
||||||
// Test that header file is self-contained.
|
|
||||||
#include <beast/websocket/static_string.hpp>
|
|
454
test/websocket/stream.cpp
Normal file
454
test/websocket/stream.cpp
Normal file
@ -0,0 +1,454 @@
|
|||||||
|
//
|
||||||
|
// 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)
|
||||||
|
//
|
||||||
|
|
||||||
|
// Test that header file is self-contained.
|
||||||
|
#include <beast/websocket/stream.hpp>
|
||||||
|
|
||||||
|
#include "websocket_async_echo_peer.hpp"
|
||||||
|
#include "websocket_sync_echo_peer.hpp"
|
||||||
|
|
||||||
|
#include <beast/bind_handler.hpp>
|
||||||
|
#include <beast/streambuf.hpp>
|
||||||
|
#include <beast/detail/unit_test/suite.hpp>
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include <boost/asio/spawn.hpp>
|
||||||
|
#include <boost/optional.hpp>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <functional>
|
||||||
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include <beast/http/parser.hpp>
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace websocket {
|
||||||
|
|
||||||
|
class stream_test : public beast::detail::unit_test::suite
|
||||||
|
{
|
||||||
|
boost::asio::io_service ios_;
|
||||||
|
boost::optional<boost::asio::io_service::work> work_;
|
||||||
|
std::thread thread_;
|
||||||
|
std::mutex m_;
|
||||||
|
std::condition_variable cv_;
|
||||||
|
bool running_ = false;;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using endpoint_type = boost::asio::ip::tcp::endpoint;
|
||||||
|
using address_type = boost::asio::ip::address;
|
||||||
|
using socket_type = boost::asio::ip::tcp::socket;
|
||||||
|
|
||||||
|
// meets the requirements of AsyncStream, SyncStream
|
||||||
|
class string_Stream
|
||||||
|
{
|
||||||
|
std::string s_;
|
||||||
|
boost::asio::io_service& ios_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
string_Stream(boost::asio::io_service& ios,
|
||||||
|
std::string s)
|
||||||
|
: s_(s)
|
||||||
|
, ios_(ios)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::asio::io_service&
|
||||||
|
get_io_service()
|
||||||
|
{
|
||||||
|
return ios_;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class MutableBufferSequence>
|
||||||
|
std::size_t
|
||||||
|
read_some(MutableBufferSequence const& buffers)
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
auto const n = read_some(buffers, ec);
|
||||||
|
if(ec)
|
||||||
|
throw boost::system::system_error{ec};
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class MutableBufferSequence>
|
||||||
|
std::size_t
|
||||||
|
read_some(MutableBufferSequence const& buffers,
|
||||||
|
error_code& ec)
|
||||||
|
{
|
||||||
|
auto const n = boost::asio::buffer_copy(
|
||||||
|
buffers, boost::asio::buffer(s_));
|
||||||
|
s_.erase(0, n);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class MutableBufferSequence, class ReadHandler>
|
||||||
|
typename async_completion<ReadHandler,
|
||||||
|
void(std::size_t, error_code)>::result_type
|
||||||
|
async_read_some(MutableBufferSequence const& buffers,
|
||||||
|
ReadHandler&& handler)
|
||||||
|
{
|
||||||
|
auto const n = boost::asio::buffer_copy(
|
||||||
|
buffers, boost::asio::buffer(s_));
|
||||||
|
s_.erase(0, n);
|
||||||
|
async_completion<ReadHandler,
|
||||||
|
void(error_code, std::size_t)> completion(handler);
|
||||||
|
ios_.post(bind_handler(
|
||||||
|
completion.handler, error_code{}, n));
|
||||||
|
return completion.result.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ConstBufferSequence>
|
||||||
|
std::size_t
|
||||||
|
write_some(ConstBufferSequence const& buffers)
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
auto const n = write_some(buffers, ec);
|
||||||
|
if(ec)
|
||||||
|
throw boost::system::system_error{ec};
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ConstBufferSequence>
|
||||||
|
std::size_t
|
||||||
|
write_some(ConstBufferSequence const& buffers,
|
||||||
|
error_code&)
|
||||||
|
{
|
||||||
|
return boost::asio::buffer_size(buffers);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ConstBuffeSequence, class WriteHandler>
|
||||||
|
typename async_completion<WriteHandler,
|
||||||
|
void(std::size_t, error_code)>::result_type
|
||||||
|
async_write_some(ConstBuffeSequence const& buffers,
|
||||||
|
WriteHandler&& handler)
|
||||||
|
{
|
||||||
|
async_completion<WriteHandler,
|
||||||
|
void(error_code, std::size_t)> completion(handler);
|
||||||
|
ios_.post(bind_handler(completion.handler,
|
||||||
|
error_code{}, boost::asio::buffer_size(buffers)));
|
||||||
|
return completion.result.get();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
stream_test()
|
||||||
|
: work_(ios_)
|
||||||
|
, thread_([&]{ ios_.run(); })
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~stream_test()
|
||||||
|
{
|
||||||
|
work_ = boost::none;
|
||||||
|
thread_.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Function>
|
||||||
|
void exec(Function&& f)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(m_);
|
||||||
|
running_ = true;
|
||||||
|
}
|
||||||
|
boost::asio::spawn(ios_,
|
||||||
|
[&](boost::asio::yield_context do_yield)
|
||||||
|
{
|
||||||
|
f(do_yield);
|
||||||
|
std::lock_guard<std::mutex> lock(m_);
|
||||||
|
running_ = false;
|
||||||
|
cv_.notify_all();
|
||||||
|
}
|
||||||
|
, boost::coroutines::attributes(2 * 1024 * 1024));
|
||||||
|
|
||||||
|
std::unique_lock<std::mutex> lock(m_);
|
||||||
|
cv_.wait(lock, [&]{ return ! running_; });
|
||||||
|
}
|
||||||
|
|
||||||
|
void testSpecialMembers()
|
||||||
|
{
|
||||||
|
stream<socket_type> ws(ios_);
|
||||||
|
{
|
||||||
|
stream<socket_type> ws2(std::move(ws));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
stream<socket_type> ws2(ios_);
|
||||||
|
ws = std::move(ws2);
|
||||||
|
}
|
||||||
|
pass();
|
||||||
|
}
|
||||||
|
|
||||||
|
void testOptions()
|
||||||
|
{
|
||||||
|
stream<socket_type> ws(ios_);
|
||||||
|
ws.set_option(message_type(opcode::binary));
|
||||||
|
ws.set_option(read_buffer_size(8192));
|
||||||
|
ws.set_option(read_message_max(1 * 1024 * 1024));
|
||||||
|
ws.set_option(write_buffer_size(2048));
|
||||||
|
pass();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t N>
|
||||||
|
static
|
||||||
|
boost::asio::const_buffers_1
|
||||||
|
strbuf(const char (&s)[N])
|
||||||
|
{
|
||||||
|
return boost::asio::const_buffers_1(&s[0], N-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void testAccept(boost::asio::yield_context do_yield)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
stream<string_Stream> ws(ios_,
|
||||||
|
"GET / HTTP/1.1\r\n"
|
||||||
|
"Host: localhost:80\r\n"
|
||||||
|
"Upgrade: WebSocket\r\n"
|
||||||
|
"Connection: upgrade\r\n"
|
||||||
|
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
||||||
|
"Sec-WebSocket-Version: 13\r\n"
|
||||||
|
"\r\n");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ws.accept();
|
||||||
|
pass();
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
stream<string_Stream> ws(ios_,
|
||||||
|
"GET / HTTP/1.1\r\n"
|
||||||
|
"\r\n");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ws.accept();
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
pass();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
stream<string_Stream> ws(ios_,
|
||||||
|
"GET / HTTP/1.1\r\n"
|
||||||
|
"Host: localhost:80\r\n"
|
||||||
|
"Upgrade: WebSocket\r\n"
|
||||||
|
"Connection: upgrade\r\n"
|
||||||
|
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
||||||
|
"Sec-WebSocket-Version: 13\r\n"
|
||||||
|
"\r\n");
|
||||||
|
error_code ec;
|
||||||
|
ws.accept(ec);
|
||||||
|
expect(! ec, ec.message());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
stream<string_Stream> ws(ios_,
|
||||||
|
"GET / HTTP/1.1\r\n"
|
||||||
|
"\r\n");
|
||||||
|
error_code ec;
|
||||||
|
ws.accept(ec);
|
||||||
|
expect(ec);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
stream<string_Stream> ws(ios_,
|
||||||
|
"GET / HTTP/1.1\r\n"
|
||||||
|
"Host: localhost:80\r\n"
|
||||||
|
"Upgrade: WebSocket\r\n"
|
||||||
|
"Connection: upgrade\r\n"
|
||||||
|
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
||||||
|
"Sec-WebSocket-Version: 13\r\n"
|
||||||
|
"\r\n");
|
||||||
|
error_code ec;
|
||||||
|
ws.async_accept(do_yield[ec]);
|
||||||
|
expect(! ec, ec.message());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
stream<string_Stream> ws(ios_,
|
||||||
|
"GET / HTTP/1.1\r\n"
|
||||||
|
"\r\n");
|
||||||
|
error_code ec;
|
||||||
|
ws.async_accept(do_yield[ec]);
|
||||||
|
expect(ec);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
stream<string_Stream> ws(ios_,
|
||||||
|
"Host: localhost:80\r\n"
|
||||||
|
"Upgrade: WebSocket\r\n"
|
||||||
|
"Connection: upgrade\r\n"
|
||||||
|
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
||||||
|
"Sec-WebSocket-Version: 13\r\n"
|
||||||
|
"\r\n");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ws.accept(strbuf(
|
||||||
|
"GET / HTTP/1.1\r\n"));
|
||||||
|
pass();
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
stream<string_Stream> ws(ios_,
|
||||||
|
"\r\n");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ws.accept(strbuf(
|
||||||
|
"GET / HTTP/1.1\r\n"));
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
pass();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
stream<string_Stream> ws(ios_,
|
||||||
|
"Host: localhost:80\r\n"
|
||||||
|
"Upgrade: WebSocket\r\n"
|
||||||
|
"Connection: upgrade\r\n"
|
||||||
|
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
||||||
|
"Sec-WebSocket-Version: 13\r\n"
|
||||||
|
"\r\n");
|
||||||
|
error_code ec;
|
||||||
|
ws.accept(strbuf(
|
||||||
|
"GET / HTTP/1.1\r\n"), ec);
|
||||||
|
expect(! ec, ec.message());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
stream<string_Stream> ws(ios_,
|
||||||
|
"GET / HTTP/1.1\r\n"
|
||||||
|
"\r\n");
|
||||||
|
error_code ec;
|
||||||
|
ws.accept(ec);
|
||||||
|
expect(ec);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
stream<string_Stream> ws(ios_,
|
||||||
|
"Host: localhost:80\r\n"
|
||||||
|
"Upgrade: WebSocket\r\n"
|
||||||
|
"Connection: upgrade\r\n"
|
||||||
|
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
|
||||||
|
"Sec-WebSocket-Version: 13\r\n"
|
||||||
|
"\r\n");
|
||||||
|
error_code ec;
|
||||||
|
ws.async_accept(strbuf(
|
||||||
|
"GET / HTTP/1.1\r\n"), do_yield[ec]);
|
||||||
|
expect(! ec, ec.message());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
stream<string_Stream> ws(ios_,
|
||||||
|
"\r\n");
|
||||||
|
error_code ec;
|
||||||
|
ws.async_accept(strbuf(
|
||||||
|
"GET / HTTP/1.1\r\n"), do_yield[ec]);
|
||||||
|
expect(ec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void testHandshake(endpoint_type const& ep,
|
||||||
|
boost::asio::yield_context do_yield)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
// disconnected socket
|
||||||
|
socket_type sock(ios_);
|
||||||
|
stream<decltype(sock)&> ws(sock);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ws.handshake("localhost", "/");
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
catch(boost::system::system_error const&)
|
||||||
|
{
|
||||||
|
pass();
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
error_code ec;
|
||||||
|
ws.handshake("localhost", "/", ec);
|
||||||
|
if(! expect(ec))
|
||||||
|
return;
|
||||||
|
ws.async_handshake("localhost", "/", do_yield[ec]);
|
||||||
|
if(! expect(ec))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
socket_type sock(ios_);
|
||||||
|
sock.connect(ep, ec);
|
||||||
|
if(! expect(! ec, ec.message()))
|
||||||
|
return;
|
||||||
|
stream<decltype(sock)&> ws(sock);
|
||||||
|
ws.handshake("localhost", "/", ec);
|
||||||
|
if(! expect(! ec, ec.message()))
|
||||||
|
return;
|
||||||
|
ws.close({}, ec);
|
||||||
|
if(! expect(! ec, ec.message()))
|
||||||
|
return;
|
||||||
|
streambuf sb;
|
||||||
|
opcode op;
|
||||||
|
ws.read(op, sb, ec);
|
||||||
|
if(! expect(ec == error::closed, ec.message()))
|
||||||
|
return;
|
||||||
|
expect(ws.reason().code == close_code::normal);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
socket_type sock(ios_);
|
||||||
|
sock.connect(ep, ec);
|
||||||
|
if(! expect(! ec, ec.message()))
|
||||||
|
return;
|
||||||
|
stream<decltype(sock)&> ws(sock);
|
||||||
|
ws.async_handshake("localhost", "/", do_yield[ec]);
|
||||||
|
if(! expect(! ec, ec.message()))
|
||||||
|
return;
|
||||||
|
ws.async_close({}, do_yield[ec]);
|
||||||
|
if(! expect(! ec, ec.message()))
|
||||||
|
return;
|
||||||
|
streambuf sb;
|
||||||
|
opcode op;
|
||||||
|
ws.async_read(op, sb, do_yield[ec]);
|
||||||
|
if(! expect(ec == error::closed, ec.message()))
|
||||||
|
return;
|
||||||
|
expect(ws.reason().code == close_code::normal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void run() override
|
||||||
|
{
|
||||||
|
testSpecialMembers();
|
||||||
|
|
||||||
|
testOptions();
|
||||||
|
|
||||||
|
exec(std::bind(&stream_test::testAccept,
|
||||||
|
this, std::placeholders::_1));
|
||||||
|
|
||||||
|
auto const any = endpoint_type{
|
||||||
|
address_type::from_string("127.0.0.1"), 0};
|
||||||
|
{
|
||||||
|
sync_echo_peer server(true, any);
|
||||||
|
exec(std::bind(&stream_test::testHandshake,
|
||||||
|
this, server.local_endpoint(),
|
||||||
|
std::placeholders::_1));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
async_echo_peer server(true, any, 1);
|
||||||
|
exec(std::bind(&stream_test::testHandshake,
|
||||||
|
this, server.local_endpoint(),
|
||||||
|
std::placeholders::_1));
|
||||||
|
}
|
||||||
|
|
||||||
|
pass();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BEAST_DEFINE_TESTSUITE(stream,websocket,beast);
|
||||||
|
|
||||||
|
} // websocket
|
||||||
|
} // beast
|
@ -59,6 +59,8 @@ public:
|
|||||||
error_code ec;
|
error_code ec;
|
||||||
acceptor_.open(ep.protocol(), ec);
|
acceptor_.open(ep.protocol(), ec);
|
||||||
maybe_throw(ec, "open");
|
maybe_throw(ec, "open");
|
||||||
|
acceptor_.set_option(
|
||||||
|
boost::asio::socket_base::reuse_address{true});
|
||||||
acceptor_.bind(ep, ec);
|
acceptor_.bind(ep, ec);
|
||||||
maybe_throw(ec, "bind");
|
maybe_throw(ec, "bind");
|
||||||
acceptor_.listen(
|
acceptor_.listen(
|
||||||
@ -87,6 +89,12 @@ public:
|
|||||||
t.join();
|
t.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
endpoint_type
|
||||||
|
local_endpoint() const
|
||||||
|
{
|
||||||
|
return acceptor_.local_endpoint();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class Peer
|
class Peer
|
||||||
{
|
{
|
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#include "websocket_async_echo_peer.hpp"
|
#include "websocket_async_echo_peer.hpp"
|
||||||
#include "websocket_sync_echo_peer.hpp"
|
#include "websocket_sync_echo_peer.hpp"
|
||||||
#include "sig_wait.hpp"
|
#include "../sig_wait.hpp"
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
@ -17,8 +17,8 @@
|
|||||||
*/
|
*/
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#ifndef BEAST_WSPROTO_SYNC_ECHO_PEER_H_INCLUDED
|
#ifndef BEAST_WEBSOCKET_SYNC_ECHO_PEER_H_INCLUDED
|
||||||
#define BEAST_WSPROTO_SYNC_ECHO_PEER_H_INCLUDED
|
#define BEAST_WEBSOCKET_SYNC_ECHO_PEER_H_INCLUDED
|
||||||
|
|
||||||
#include <beast/streambuf.hpp>
|
#include <beast/streambuf.hpp>
|
||||||
#include <beast/websocket.hpp>
|
#include <beast/websocket.hpp>
|
||||||
@ -55,6 +55,8 @@ public:
|
|||||||
error_code ec;
|
error_code ec;
|
||||||
acceptor_.open(ep.protocol(), ec);
|
acceptor_.open(ep.protocol(), ec);
|
||||||
maybe_throw(ec, "open");
|
maybe_throw(ec, "open");
|
||||||
|
acceptor_.set_option(
|
||||||
|
boost::asio::socket_base::reuse_address{true});
|
||||||
acceptor_.bind(ep, ec);
|
acceptor_.bind(ep, ec);
|
||||||
maybe_throw(ec, "bind");
|
maybe_throw(ec, "bind");
|
||||||
acceptor_.listen(
|
acceptor_.listen(
|
||||||
@ -74,6 +76,12 @@ public:
|
|||||||
thread_.join();
|
thread_.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
endpoint_type
|
||||||
|
local_endpoint() const
|
||||||
|
{
|
||||||
|
return acceptor_.local_endpoint();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static
|
static
|
||||||
void
|
void
|
Reference in New Issue
Block a user