mirror of
https://github.com/boostorg/beast.git
synced 2025-07-29 20:37: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)
|
||||
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()
|
||||
set(Boost_USE_STATIC_LIBS ON)
|
||||
set(Boost_USE_MULTITHREADED ON)
|
||||
|
1
Jamroot
1
Jamroot
@ -51,6 +51,7 @@ project beast
|
||||
<include>./include
|
||||
#<use>/boost//headers
|
||||
<library>/boost/system//boost_system
|
||||
<library>/boost/coroutine//boost_coroutine
|
||||
<library>/boost/filesystem//boost_filesystem
|
||||
<library>/boost/program_options//boost_program_options
|
||||
# <library>ssl
|
||||
|
59
TODO.txt
59
TODO.txt
@ -1,28 +1,39 @@
|
||||
* Replace Jamroot with Jamfile
|
||||
* Complete allocator testing in basic_streambuf, basic_headers
|
||||
* 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
|
||||
General:
|
||||
* Use SFINAE on return values (search for "class =")
|
||||
|
||||
Boost.Http
|
||||
* Use enum instead of bool in isRequest
|
||||
* 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">
|
||||
<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_AsyncStream">is_AsyncStream</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_Handler">is_Handler</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_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>
|
||||
</simplelist>
|
||||
</entry>
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
GroupSources(include/beast)
|
||||
GroupSources(examples)
|
||||
GroupSources(test)
|
||||
|
||||
add_executable (http-crawl
|
||||
${BEAST_INCLUDES}
|
||||
@ -21,7 +22,7 @@ add_executable (http-server
|
||||
http_stream.hpp
|
||||
http_stream.ipp
|
||||
http_sync_server.hpp
|
||||
sig_wait.hpp
|
||||
../test/sig_wait.hpp
|
||||
http_server.cpp
|
||||
)
|
||||
|
||||
@ -38,18 +39,6 @@ if (NOT WIN32)
|
||||
target_link_libraries(http-example ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
||||
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
|
||||
${BEAST_INCLUDES}
|
||||
websocket_example.cpp
|
||||
|
@ -7,24 +7,20 @@
|
||||
|
||||
import os ;
|
||||
|
||||
exe http_crawl :
|
||||
exe http-crawl :
|
||||
http_crawl.cpp
|
||||
urls_large_data.cpp
|
||||
;
|
||||
|
||||
exe http_server :
|
||||
exe http-server :
|
||||
http_server.cpp
|
||||
;
|
||||
|
||||
exe http_example :
|
||||
exe http-example :
|
||||
http_example.cpp
|
||||
;
|
||||
|
||||
exe websocket_echo :
|
||||
websocket_echo.cpp
|
||||
;
|
||||
|
||||
exe websocket_example :
|
||||
exe websocket-example :
|
||||
websocket_example.cpp
|
||||
;
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
|
||||
#include "http_async_server.hpp"
|
||||
#include "http_sync_server.hpp"
|
||||
#include "sig_wait.hpp"
|
||||
#include "../test/sig_wait.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};
|
||||
|
||||
if(sync)
|
||||
{
|
||||
http_sync_server server(ep, root);
|
||||
sig_wait();
|
||||
}
|
||||
else
|
||||
{
|
||||
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/handler_alloc.hpp>
|
||||
#include <beast/type_check.hpp>
|
||||
|
||||
namespace beast {
|
||||
|
||||
@ -158,8 +157,6 @@ streambuf_readstream<Stream, Streambuf>::
|
||||
streambuf_readstream(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,
|
||||
"Streambuf requirements not met");
|
||||
}
|
||||
@ -173,6 +170,8 @@ async_write_some(ConstBufferSequence const& buffers,
|
||||
typename async_completion<
|
||||
WriteHandler, void(error_code)>::result_type
|
||||
{
|
||||
static_assert(is_AsyncWriteStream<next_layer_type>::value,
|
||||
"AsyncWriteStream requirements not met");
|
||||
static_assert(is_ConstBufferSequence<
|
||||
ConstBufferSequence>::value,
|
||||
"ConstBufferSequence requirements not met");
|
||||
@ -190,6 +189,8 @@ streambuf_readstream<Stream, Streambuf>::
|
||||
read_some(
|
||||
MutableBufferSequence const& buffers)
|
||||
{
|
||||
static_assert(is_SyncReadStream<next_layer_type>::value,
|
||||
"SyncReadStream requirements not met");
|
||||
static_assert(is_MutableBufferSequence<
|
||||
MutableBufferSequence>::value,
|
||||
"MutableBufferSequence requirements not met");
|
||||
@ -207,6 +208,8 @@ streambuf_readstream<Stream, Streambuf>::
|
||||
read_some(MutableBufferSequence const& buffers,
|
||||
error_code& ec)
|
||||
{
|
||||
static_assert(is_SyncReadStream<next_layer_type>::value,
|
||||
"SyncReadStream requirements not met");
|
||||
static_assert(is_MutableBufferSequence<
|
||||
MutableBufferSequence>::value,
|
||||
"MutableBufferSequence requirements not met");
|
||||
@ -239,6 +242,8 @@ async_read_some(
|
||||
typename async_completion<
|
||||
ReadHandler, void(error_code)>::result_type
|
||||
{
|
||||
static_assert(is_AsyncReadStream<next_layer_type>::value,
|
||||
"Stream requirements not met");
|
||||
static_assert(is_MutableBufferSequence<
|
||||
MutableBufferSequence>::value,
|
||||
"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/streambuf.hpp>
|
||||
#include <beast/type_check.hpp>
|
||||
#include <beast/detail/get_lowest_layer.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
@ -83,8 +85,7 @@ namespace beast {
|
||||
|
||||
@tparam Streambuf The type of stream buffer to use.
|
||||
*/
|
||||
template<class Stream,
|
||||
class Streambuf = streambuf>
|
||||
template<class Stream, class Streambuf>
|
||||
class streambuf_readstream
|
||||
{
|
||||
using error_code = boost::system::error_code;
|
||||
@ -106,11 +107,23 @@ public:
|
||||
|
||||
/// The type of the lowest layer.
|
||||
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;
|
||||
|
||||
/** 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.
|
||||
|
||||
@param args Parameters forwarded to the `Stream` constructor.
|
||||
@ -200,6 +213,8 @@ public:
|
||||
std::size_t
|
||||
write_some(ConstBufferSequence const& buffers)
|
||||
{
|
||||
static_assert(is_SyncWriteStream<next_layer_type>::value,
|
||||
"SyncWriteStream requirements not met");
|
||||
return next_layer_.write_some(buffers);
|
||||
}
|
||||
|
||||
@ -210,6 +225,8 @@ public:
|
||||
write_some(ConstBufferSequence const& buffers,
|
||||
error_code& ec)
|
||||
{
|
||||
static_assert(is_SyncWriteStream<next_layer_type>::value,
|
||||
"SyncWriteStream requirements not met");
|
||||
return next_layer_.write_some(buffers, ec);
|
||||
}
|
||||
|
||||
|
@ -272,18 +272,26 @@ public:
|
||||
};
|
||||
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>
|
||||
struct is_Stream
|
||||
struct is_SyncStream
|
||||
{
|
||||
/// `true` if `T` meets the requirements.
|
||||
/// `true` if `T` meets the requirements.
|
||||
static bool const value =
|
||||
is_AsyncReadStream<T>::value &&
|
||||
is_AsyncWriteStream<T>::value &&
|
||||
is_SyncReadStream<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`.
|
||||
template<class T>
|
||||
class is_Streambuf
|
||||
|
@ -24,7 +24,6 @@
|
||||
#include <beast/websocket/option.hpp>
|
||||
#include <beast/websocket/rfc6455.hpp>
|
||||
#include <beast/websocket/stream.hpp>
|
||||
#include <beast/websocket/static_string.hpp>
|
||||
#include <beast/websocket/teardown.hpp>
|
||||
|
||||
#endif
|
||||
|
@ -9,11 +9,11 @@
|
||||
#define BEAST_WEBSOCKET_DETAIL_FRAME_HPP
|
||||
|
||||
#include <beast/websocket/rfc6455.hpp>
|
||||
#include <beast/websocket/static_string.hpp>
|
||||
#include <beast/websocket/detail/endian.hpp>
|
||||
#include <beast/websocket/detail/utf8_checker.hpp>
|
||||
#include <beast/consuming_buffers.hpp>
|
||||
#include <beast/static_streambuf.hpp>
|
||||
#include <beast/static_string.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/endian/buffers.hpp>
|
||||
#include <cassert>
|
||||
@ -70,10 +70,9 @@ is_control(opcode op)
|
||||
// Returns `true` if a close code is valid
|
||||
inline
|
||||
bool
|
||||
is_valid(close_code code)
|
||||
is_valid(close_code::value code)
|
||||
{
|
||||
auto const v = static_cast<
|
||||
std::uint16_t>(code);
|
||||
auto const v = code;
|
||||
switch(v)
|
||||
{
|
||||
case 1000:
|
||||
@ -154,7 +153,7 @@ write(Streambuf& sb, frame_header const& fh)
|
||||
template<class Streambuf>
|
||||
std::size_t
|
||||
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_copy;
|
||||
@ -171,7 +170,8 @@ read_fh1(frame_header& fh, Streambuf& sb,
|
||||
default:
|
||||
need = 0;
|
||||
}
|
||||
if((fh.mask = (b[1] & 0x80) != 0))
|
||||
fh.mask = (b[1] & 0x80) != 0;
|
||||
if(fh.mask)
|
||||
need += 4;
|
||||
fh.op = static_cast<opcode>(b[0] & 0x0f);
|
||||
fh.fin = (b[0] & 0x80) != 0;
|
||||
@ -230,7 +230,7 @@ read_fh1(frame_header& fh, Streambuf& sb,
|
||||
template<class Streambuf>
|
||||
void
|
||||
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_copy;
|
||||
@ -301,7 +301,7 @@ read_fh2(frame_header& fh, Streambuf& sb,
|
||||
template<class Buffers>
|
||||
void
|
||||
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_size;
|
||||
@ -318,7 +318,7 @@ read(ping_payload_type& data,
|
||||
template<class Buffers>
|
||||
void
|
||||
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_copy;
|
||||
@ -341,15 +341,7 @@ read(close_reason& cr,
|
||||
{
|
||||
std::uint8_t b[2];
|
||||
buffer_copy(buffer(b), cb);
|
||||
#if 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
|
||||
cr.code = big_uint16_to_native(&b[0]);
|
||||
cb.consume(2);
|
||||
n -= 2;
|
||||
if(! is_valid(cr.code))
|
||||
|
@ -85,8 +85,6 @@ public:
|
||||
#endif
|
||||
|
||||
invokable() = default;
|
||||
invokable(invokable const&) = delete;
|
||||
invokable& operator=(invokable const&) = delete;
|
||||
|
||||
invokable(invokable&& other)
|
||||
{
|
||||
|
@ -41,9 +41,6 @@ class maskgen_t
|
||||
public:
|
||||
using result_type = typename std::mt19937::result_type;
|
||||
|
||||
maskgen_t(maskgen_t const&) = delete;
|
||||
maskgen_t& operator=(maskgen_t const&) = delete;
|
||||
|
||||
maskgen_t();
|
||||
|
||||
result_type
|
||||
|
@ -108,7 +108,7 @@ protected:
|
||||
|
||||
template<class = void>
|
||||
void
|
||||
prepare_fh(close_code& code);
|
||||
prepare_fh(close_code::value& code);
|
||||
|
||||
template<class Streambuf>
|
||||
void
|
||||
|
@ -73,12 +73,6 @@ class utf8_checker_t
|
||||
std::uint32_t codepoint_ = 0;
|
||||
|
||||
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
|
||||
reset();
|
||||
|
||||
|
@ -124,7 +124,7 @@ operator()(error_code const& ec,
|
||||
case 0:
|
||||
// read message
|
||||
d.state = 1;
|
||||
http::async_read(d.ws.next_layer_,
|
||||
http::async_read(d.ws.next_layer(),
|
||||
d.ws.stream_.buffer(), d.req,
|
||||
std::move(*this));
|
||||
return;
|
||||
|
@ -134,7 +134,7 @@ stream<NextLayer>::handshake_op<
|
||||
case 1:
|
||||
// read http response
|
||||
d.state = 2;
|
||||
http::async_read(d.ws.next_layer_,
|
||||
http::async_read(d.ws.next_layer(),
|
||||
d.ws.stream_.buffer(), d.resp,
|
||||
std::move(*this));
|
||||
return;
|
||||
|
@ -132,7 +132,7 @@ operator()(error_code ec,std::size_t bytes_transferred, bool again)
|
||||
{
|
||||
auto& d = *d_;
|
||||
d.cont = d.cont || again;
|
||||
close_code code;
|
||||
close_code::value code = close_code::none;
|
||||
while(! ec && d.state != 99)
|
||||
{
|
||||
switch(d.state)
|
||||
@ -195,7 +195,7 @@ operator()(error_code ec,std::size_t bytes_transferred, bool again)
|
||||
d.state = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// call handler
|
||||
case 4:
|
||||
d.state = 99;
|
||||
@ -397,7 +397,7 @@ operator()(error_code ec,std::size_t bytes_transferred, bool again)
|
||||
case 11:
|
||||
d.state = 12;
|
||||
wsproto_helpers::call_async_teardown(
|
||||
d.ws.next_layer_, std::move(*this));
|
||||
d.ws.next_layer(), std::move(*this));
|
||||
return;
|
||||
|
||||
case 12:
|
||||
@ -483,7 +483,7 @@ operator()(error_code ec,std::size_t bytes_transferred, bool again)
|
||||
case 19:
|
||||
d.state = 20;
|
||||
wsproto_helpers::call_async_teardown(
|
||||
d.ws.next_layer_, std::move(*this));
|
||||
d.ws.next_layer(), std::move(*this));
|
||||
return;
|
||||
|
||||
case 20:
|
||||
|
@ -113,7 +113,7 @@ operator()(error_code ec, bool again)
|
||||
case 0:
|
||||
// send response
|
||||
d.state = 1;
|
||||
http::async_write(d.ws.next_layer_,
|
||||
http::async_write(d.ws.next_layer(),
|
||||
d.resp, std::move(*this));
|
||||
return;
|
||||
|
||||
|
@ -41,7 +41,7 @@ namespace detail {
|
||||
|
||||
template<class _>
|
||||
void
|
||||
stream_base::prepare_fh(close_code& code)
|
||||
stream_base::prepare_fh(close_code::value& code)
|
||||
{
|
||||
// continuation without an active message
|
||||
if(! rd_cont_ && rd_fh_.op == opcode::cont)
|
||||
@ -170,11 +170,20 @@ template<class NextLayer>
|
||||
template<class... Args>
|
||||
stream<NextLayer>::
|
||||
stream(Args&&... args)
|
||||
: next_layer_(std::forward<Args>(args)...)
|
||||
, stream_(next_layer_)
|
||||
: stream_(std::forward<Args>(args)...)
|
||||
{
|
||||
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>
|
||||
@ -182,6 +191,8 @@ void
|
||||
stream<NextLayer>::
|
||||
accept(error_code& ec)
|
||||
{
|
||||
static_assert(is_SyncStream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
accept(boost::asio::null_buffers{}, ec);
|
||||
}
|
||||
|
||||
@ -192,6 +203,8 @@ typename async_completion<
|
||||
stream<NextLayer>::
|
||||
async_accept(AcceptHandler&& handler)
|
||||
{
|
||||
static_assert(is_AsyncStream<next_layer_type>::value,
|
||||
"AsyncStream requirements requirements not met");
|
||||
return async_accept(boost::asio::null_buffers{},
|
||||
std::forward<AcceptHandler>(handler));
|
||||
}
|
||||
@ -202,6 +215,8 @@ void
|
||||
stream<NextLayer>::
|
||||
accept(ConstBufferSequence const& buffers)
|
||||
{
|
||||
static_assert(is_SyncStream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(is_ConstBufferSequence<
|
||||
ConstBufferSequence>::value,
|
||||
"ConstBufferSequence requirements not met");
|
||||
@ -216,6 +231,8 @@ void
|
||||
stream<NextLayer>::
|
||||
accept(ConstBufferSequence const& buffers, error_code& ec)
|
||||
{
|
||||
static_assert(is_SyncStream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(beast::is_ConstBufferSequence<
|
||||
ConstBufferSequence>::value,
|
||||
"ConstBufferSequence requirements not met");
|
||||
@ -225,7 +242,7 @@ accept(ConstBufferSequence const& buffers, error_code& ec)
|
||||
stream_.buffer().prepare(
|
||||
buffer_size(buffers)), buffers));
|
||||
http::request<http::empty_body> m;
|
||||
http::read(next_layer_, stream_.buffer(), m, ec);
|
||||
http::read(next_layer(), stream_.buffer(), m, ec);
|
||||
if(ec)
|
||||
return;
|
||||
accept(m, ec);
|
||||
@ -238,6 +255,8 @@ typename async_completion<
|
||||
stream<NextLayer>::
|
||||
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<
|
||||
ConstBufferSequence>::value,
|
||||
"ConstBufferSequence requirements not met");
|
||||
@ -255,6 +274,8 @@ void
|
||||
stream<NextLayer>::
|
||||
accept(http::message<true, Body, Headers> const& request)
|
||||
{
|
||||
static_assert(is_SyncStream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
error_code ec;
|
||||
accept(request, ec);
|
||||
detail::maybe_throw(ec, "accept");
|
||||
@ -267,6 +288,8 @@ stream<NextLayer>::
|
||||
accept(http::message<true, Body, Headers> const& req,
|
||||
error_code& ec)
|
||||
{
|
||||
static_assert(is_SyncStream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
auto resp = build_response(req);
|
||||
http::write(stream_, resp, ec);
|
||||
if(resp.status != 101)
|
||||
@ -287,6 +310,8 @@ stream<NextLayer>::
|
||||
async_accept(http::message<true, Body, Headers> const& req,
|
||||
AcceptHandler&& handler)
|
||||
{
|
||||
static_assert(is_AsyncStream<next_layer_type>::value,
|
||||
"AsyncStream requirements requirements not met");
|
||||
beast::async_completion<
|
||||
AcceptHandler, void(error_code)
|
||||
> completion(handler);
|
||||
@ -297,19 +322,34 @@ async_accept(http::message<true, Body, Headers> const& req,
|
||||
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>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
handshake(boost::string_ref const& host,
|
||||
boost::string_ref const& resource, error_code& ec)
|
||||
{
|
||||
static_assert(is_SyncStream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
std::string key;
|
||||
http::write(stream_,
|
||||
build_request(host, resource, key), ec);
|
||||
if(ec)
|
||||
return;
|
||||
http::response<http::string_body> resp;
|
||||
http::read(next_layer_, stream_.buffer(), resp, ec);
|
||||
http::read(next_layer(), stream_.buffer(), resp, ec);
|
||||
if(ec)
|
||||
return;
|
||||
do_response(resp, key, ec);
|
||||
@ -323,6 +363,8 @@ stream<NextLayer>::
|
||||
async_handshake(boost::string_ref const& host,
|
||||
boost::string_ref const& resource, HandshakeHandler&& handler)
|
||||
{
|
||||
static_assert(is_AsyncStream<next_layer_type>::value,
|
||||
"AsyncStream requirements not met");
|
||||
beast::async_completion<
|
||||
HandshakeHandler, void(error_code)
|
||||
> completion(handler);
|
||||
@ -331,11 +373,25 @@ async_handshake(boost::string_ref const& host,
|
||||
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>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
close(close_reason const& cr, error_code& ec)
|
||||
{
|
||||
static_assert(is_SyncStream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
assert(! wr_close_);
|
||||
wr_close_ = true;
|
||||
detail::frame_streambuf fb;
|
||||
@ -351,6 +407,8 @@ typename async_completion<
|
||||
stream<NextLayer>::
|
||||
async_close(close_reason const& cr, CloseHandler&& handler)
|
||||
{
|
||||
static_assert(is_AsyncStream<next_layer_type>::value,
|
||||
"AsyncStream requirements not met");
|
||||
beast::async_completion<
|
||||
CloseHandler, void(error_code)
|
||||
> completion(handler);
|
||||
@ -359,12 +417,27 @@ async_close(close_reason const& cr, CloseHandler&& handler)
|
||||
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 Streambuf>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
read(opcode& op, Streambuf& streambuf, error_code& ec)
|
||||
{
|
||||
static_assert(is_SyncStream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
frame_info fi;
|
||||
for(;;)
|
||||
{
|
||||
@ -385,6 +458,8 @@ stream<NextLayer>::
|
||||
async_read(opcode& op,
|
||||
Streambuf& streambuf, ReadHandler&& handler)
|
||||
{
|
||||
static_assert(is_AsyncStream<next_layer_type>::value,
|
||||
"AsyncStream requirements requirements not met");
|
||||
static_assert(beast::is_Streambuf<Streambuf>::value,
|
||||
"Streambuf requirements not met");
|
||||
beast::async_completion<
|
||||
@ -395,13 +470,28 @@ async_read(opcode& op,
|
||||
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 Streambuf>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
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(;;)
|
||||
{
|
||||
if(rd_need_ == 0)
|
||||
@ -409,7 +499,8 @@ read_frame(frame_info& fi, Streambuf& streambuf, error_code& ec)
|
||||
// read header
|
||||
detail::frame_streambuf fb;
|
||||
do_read_fh(fb, code, ec);
|
||||
if((error_ = ec != 0))
|
||||
error_ = ec != 0;
|
||||
if(error_)
|
||||
return;
|
||||
if(code != close_code::none)
|
||||
break;
|
||||
@ -421,7 +512,8 @@ read_frame(frame_info& fi, Streambuf& streambuf, error_code& ec)
|
||||
auto const mb = fb.prepare(
|
||||
static_cast<std::size_t>(rd_fh_.len));
|
||||
fb.commit(boost::asio::read(stream_, mb, ec));
|
||||
if((error_ = ec != 0))
|
||||
error_ = ec != 0;
|
||||
if(error_)
|
||||
return;
|
||||
if(rd_fh_.mask)
|
||||
detail::mask_inplace(mb, rd_key_);
|
||||
@ -437,7 +529,8 @@ read_frame(frame_info& fi, Streambuf& streambuf, error_code& ec)
|
||||
write_ping<static_streambuf>(
|
||||
fb, opcode::pong, data);
|
||||
boost::asio::write(stream_, fb.data(), ec);
|
||||
if((error_ = ec != 0))
|
||||
error_ = ec != 0;
|
||||
if(error_)
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
@ -445,7 +538,7 @@ read_frame(frame_info& fi, Streambuf& streambuf, error_code& ec)
|
||||
{
|
||||
ping_payload_type data;
|
||||
detail::read(data, fb.data(), code);
|
||||
if((error_ = ec != 0))
|
||||
if(code != close_code::none)
|
||||
break;
|
||||
// VFALCO How to notify callers using
|
||||
// the synchronous interface?
|
||||
@ -466,7 +559,8 @@ read_frame(frame_info& fi, Streambuf& streambuf, error_code& ec)
|
||||
wr_close_ = true;
|
||||
write_close<static_streambuf>(fb, cr);
|
||||
boost::asio::write(stream_, fb.data(), ec);
|
||||
if((error_ = ec != 0))
|
||||
error_ = ec != 0;
|
||||
if(error_)
|
||||
return;
|
||||
}
|
||||
break;
|
||||
@ -483,7 +577,8 @@ read_frame(frame_info& fi, Streambuf& streambuf, error_code& ec)
|
||||
detail::clamp(rd_need_));
|
||||
auto const bytes_transferred =
|
||||
stream_.read_some(smb, ec);
|
||||
if((error_ = ec != 0))
|
||||
error_ = ec != 0;
|
||||
if(error_)
|
||||
return;
|
||||
rd_need_ -= bytes_transferred;
|
||||
auto const pb = prepare_buffers(
|
||||
@ -514,18 +609,20 @@ read_frame(frame_info& fi, Streambuf& streambuf, error_code& ec)
|
||||
detail::frame_streambuf fb;
|
||||
write_close<static_streambuf>(fb, code);
|
||||
boost::asio::write(stream_, fb.data(), ec);
|
||||
if((error_ = ec != 0))
|
||||
error_ = ec != 0;
|
||||
if(error_)
|
||||
return;
|
||||
}
|
||||
wsproto_helpers::call_teardown(next_layer_, ec);
|
||||
if((error_ = ec != 0))
|
||||
wsproto_helpers::call_teardown(next_layer(), ec);
|
||||
error_ = ec != 0;
|
||||
if(error_)
|
||||
return;
|
||||
ec = error::failed;
|
||||
error_ = true;
|
||||
return;
|
||||
}
|
||||
if(! ec)
|
||||
wsproto_helpers::call_teardown(next_layer_, ec);
|
||||
wsproto_helpers::call_teardown(next_layer(), ec);
|
||||
if(! ec)
|
||||
ec = error::closed;
|
||||
error_ = ec != 0;
|
||||
@ -539,6 +636,8 @@ stream<NextLayer>::
|
||||
async_read_frame(frame_info& fi,
|
||||
Streambuf& streambuf, ReadHandler&& handler)
|
||||
{
|
||||
static_assert(is_AsyncStream<next_layer_type>::value,
|
||||
"AsyncStream requirements requirements not met");
|
||||
static_assert(beast::is_Streambuf<Streambuf>::value,
|
||||
"Streambuf requirements not met");
|
||||
beast::async_completion<
|
||||
@ -548,12 +647,27 @@ async_read_frame(frame_info& fi,
|
||||
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 ConstBufferSequence>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
write(ConstBufferSequence const& bs, error_code& ec)
|
||||
{
|
||||
static_assert(is_SyncStream<next_layer_type>::value,
|
||||
"SyncStream requirements not met");
|
||||
static_assert(beast::is_ConstBufferSequence<
|
||||
ConstBufferSequence>::value,
|
||||
"ConstBufferSequence requirements not met");
|
||||
@ -582,6 +696,8 @@ typename async_completion<
|
||||
stream<NextLayer>::
|
||||
async_write(ConstBufferSequence const& bs, WriteHandler&& handler)
|
||||
{
|
||||
static_assert(is_AsyncStream<next_layer_type>::value,
|
||||
"AsyncStream requirements not met");
|
||||
static_assert(beast::is_ConstBufferSequence<
|
||||
ConstBufferSequence>::value,
|
||||
"ConstBufferSequence requirements not met");
|
||||
@ -592,12 +708,27 @@ async_write(ConstBufferSequence const& bs, WriteHandler&& handler)
|
||||
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 ConstBufferSequence>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
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<
|
||||
ConstBufferSequence>::value,
|
||||
"ConstBufferSequence requirements not met");
|
||||
@ -678,6 +809,8 @@ stream<NextLayer>::
|
||||
async_write_frame(bool fin,
|
||||
ConstBufferSequence const& bs, WriteHandler&& handler)
|
||||
{
|
||||
static_assert(is_AsyncStream<next_layer_type>::value,
|
||||
"AsyncStream requirements not met");
|
||||
static_assert(beast::is_ConstBufferSequence<
|
||||
ConstBufferSequence>::value,
|
||||
"ConstBufferSequence requirements not met");
|
||||
@ -792,7 +925,7 @@ template<class NextLayer>
|
||||
void
|
||||
stream<NextLayer>::
|
||||
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(
|
||||
stream_, fb.prepare(2), ec));
|
||||
|
@ -61,7 +61,8 @@ class stream<NextLayer>::write_frame_op
|
||||
fh.rsv2 = 0;
|
||||
fh.rsv3 = 0;
|
||||
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_();
|
||||
detail::prepare_key(key, fh.key);
|
||||
|
@ -8,7 +8,7 @@
|
||||
#ifndef 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 <array>
|
||||
#include <cstdint>
|
||||
@ -44,7 +44,9 @@ enum class opcode : std::uint8_t
|
||||
@see RFC 6455 7.4.1 Defined Status Codes
|
||||
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"
|
||||
none = 0,
|
||||
@ -69,6 +71,7 @@ enum class close_code : std::uint16_t
|
||||
|
||||
last = 5000 // satisfy warnings
|
||||
};
|
||||
} // close_code
|
||||
|
||||
#if ! GENERATING_DOCS
|
||||
|
||||
@ -89,7 +92,7 @@ using ping_payload_type =
|
||||
struct close_reason
|
||||
{
|
||||
/// The close code.
|
||||
close_code code = close_code::none;
|
||||
close_code::value code = close_code::none;
|
||||
|
||||
/// The optional utf8-encoded reason string.
|
||||
reason_string_type reason;
|
||||
@ -102,7 +105,7 @@ struct close_reason
|
||||
close_reason() = default;
|
||||
|
||||
/// Construct from a code.
|
||||
close_reason(close_code code_)
|
||||
close_reason(close_code::value code_)
|
||||
: code(code_)
|
||||
{
|
||||
}
|
||||
@ -117,7 +120,7 @@ struct close_reason
|
||||
|
||||
/// Construct from a code and reason.
|
||||
template<class CharT>
|
||||
close_reason(close_code code_,
|
||||
close_reason(close_code::value code_,
|
||||
CharT const* reason_)
|
||||
: code(code_)
|
||||
, 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/streambuf_readstream.hpp>
|
||||
#include <beast/async_completion.hpp>
|
||||
#include <beast/detail/get_lowest_layer.hpp>
|
||||
#include <beast/http/message.hpp>
|
||||
#include <beast/http/string_body.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
@ -80,8 +81,7 @@ class stream : public detail::stream_base
|
||||
{
|
||||
friend class ws_test;
|
||||
|
||||
NextLayer next_layer_;
|
||||
streambuf_readstream<NextLayer&, streambuf> stream_;
|
||||
streambuf_readstream<NextLayer, streambuf> stream_;
|
||||
|
||||
public:
|
||||
/// The type of the next layer.
|
||||
@ -90,26 +90,26 @@ public:
|
||||
|
||||
/// The type of the lowest layer.
|
||||
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.
|
||||
using endpoint_type =
|
||||
typename lowest_layer_type::endpoint_type;
|
||||
/** Move-construct a stream.
|
||||
|
||||
/// The protocol of the next layer.
|
||||
using protocol_type =
|
||||
typename lowest_layer_type::protocol_type;
|
||||
If @c NextLayer is move constructible, this function
|
||||
will move-construct a new stream from the existing stream.
|
||||
|
||||
/// The type of resolver of the next layer.
|
||||
using resolver_type =
|
||||
typename protocol_type::resolver;
|
||||
|
||||
/// Move constructor.
|
||||
@note The behavior of move assignment on or from streams
|
||||
with active or pending operations is undefined.
|
||||
*/
|
||||
stream(stream&&) = default;
|
||||
|
||||
/** 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;
|
||||
|
||||
@ -217,7 +217,7 @@ public:
|
||||
boost::asio::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.
|
||||
@ -231,7 +231,7 @@ public:
|
||||
next_layer_type&
|
||||
next_layer()
|
||||
{
|
||||
return next_layer_;
|
||||
return stream_.next_layer();
|
||||
}
|
||||
|
||||
/** Get a reference to the next layer.
|
||||
@ -245,7 +245,7 @@ public:
|
||||
next_layer_type const&
|
||||
next_layer() const
|
||||
{
|
||||
return next_layer_;
|
||||
return stream_.next_layer();
|
||||
}
|
||||
|
||||
/** Get a reference to the lowest layer.
|
||||
@ -259,7 +259,7 @@ public:
|
||||
lowest_layer_type&
|
||||
lowest_layer()
|
||||
{
|
||||
return next_layer_.lowest_layer();
|
||||
return stream_.lowest_layer();
|
||||
}
|
||||
|
||||
/** Get a reference to the lowest layer.
|
||||
@ -273,7 +273,7 @@ public:
|
||||
lowest_layer_type const&
|
||||
lowest_layer() const
|
||||
{
|
||||
return next_layer_.lowest_layer();
|
||||
return stream_.lowest_layer();
|
||||
}
|
||||
|
||||
/** Returns the close reason received from the peer.
|
||||
@ -309,12 +309,7 @@ public:
|
||||
@throws boost::system::system_error Thrown on failure.
|
||||
*/
|
||||
void
|
||||
accept()
|
||||
{
|
||||
error_code ec;
|
||||
accept(boost::asio::null_buffers{}, ec);
|
||||
detail::maybe_throw(ec, "accept");
|
||||
}
|
||||
accept();
|
||||
|
||||
/** Read and respond to a WebSocket HTTP Upgrade request.
|
||||
|
||||
@ -603,12 +598,7 @@ public:
|
||||
*/
|
||||
void
|
||||
handshake(boost::string_ref const& host,
|
||||
boost::string_ref const& resource)
|
||||
{
|
||||
error_code ec;
|
||||
handshake(host, resource, ec);
|
||||
detail::maybe_throw(ec, "upgrade");
|
||||
}
|
||||
boost::string_ref const& resource);
|
||||
|
||||
/** Send a WebSocket Upgrade request.
|
||||
|
||||
@ -692,12 +682,7 @@ public:
|
||||
@param cr The reason for the close.
|
||||
*/
|
||||
void
|
||||
close(close_reason const& cr)
|
||||
{
|
||||
error_code ec;
|
||||
close(cr, ec);
|
||||
detail::maybe_throw(ec, "close");
|
||||
}
|
||||
close(close_reason const& cr);
|
||||
|
||||
/** Perform a WebSocket close.
|
||||
|
||||
@ -773,12 +758,7 @@ public:
|
||||
*/
|
||||
template<class Streambuf>
|
||||
void
|
||||
read(opcode& op, Streambuf& streambuf)
|
||||
{
|
||||
error_code ec;
|
||||
read(op, streambuf, ec);
|
||||
detail::maybe_throw(ec, "read");
|
||||
}
|
||||
read(opcode& op, Streambuf& streambuf);
|
||||
|
||||
/** Read a message.
|
||||
|
||||
@ -868,12 +848,7 @@ public:
|
||||
*/
|
||||
template<class Streambuf>
|
||||
void
|
||||
read_frame(frame_info& fi, Streambuf& streambuf)
|
||||
{
|
||||
error_code ec;
|
||||
read_frame(fi, streambuf, ec);
|
||||
detail::maybe_throw(ec, "read_some");
|
||||
}
|
||||
read_frame(frame_info& fi, Streambuf& streambuf);
|
||||
|
||||
/** Read a message frame.
|
||||
|
||||
@ -978,12 +953,7 @@ public:
|
||||
*/
|
||||
template<class ConstBufferSequence>
|
||||
void
|
||||
write(ConstBufferSequence const& buffers)
|
||||
{
|
||||
error_code ec;
|
||||
write(buffers, ec);
|
||||
detail::maybe_throw(ec, "write");
|
||||
}
|
||||
write(ConstBufferSequence const& buffers);
|
||||
|
||||
/** Send a message.
|
||||
|
||||
@ -1081,12 +1051,7 @@ public:
|
||||
*/
|
||||
template<class ConstBufferSequence>
|
||||
void
|
||||
write_frame(bool fin, ConstBufferSequence const& buffers)
|
||||
{
|
||||
error_code ec;
|
||||
write_frame(fin, buffers, ec);
|
||||
detail::maybe_throw(ec, "write");
|
||||
}
|
||||
write_frame(bool fin, ConstBufferSequence const& buffers);
|
||||
|
||||
/** Send a frame.
|
||||
|
||||
@ -1180,7 +1145,7 @@ private:
|
||||
|
||||
void
|
||||
do_read_fh(detail::frame_streambuf& fb,
|
||||
close_code& code, error_code& ec);
|
||||
close_code::value& code, error_code& ec);
|
||||
};
|
||||
|
||||
} // websocket
|
||||
|
@ -7,5 +7,3 @@ echo "using toolset: $CC"
|
||||
echo "using 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
|
||||
prepare_buffers.cpp
|
||||
static_streambuf.cpp
|
||||
static_string.cpp
|
||||
streambuf.cpp
|
||||
streambuf_readstream.cpp
|
||||
to_string.cpp
|
||||
@ -54,21 +55,6 @@ if (NOT WIN32)
|
||||
target_link_libraries(http-tests ${Boost_LIBRARIES})
|
||||
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
|
||||
${BEAST_INCLUDES}
|
||||
main.cpp
|
||||
@ -80,3 +66,31 @@ if (NOT WIN32)
|
||||
target_link_libraries(parser-bench ${Boost_LIBRARIES})
|
||||
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
|
||||
prepare_buffers.cpp
|
||||
static_streambuf.cpp
|
||||
static_string.cpp
|
||||
streambuf.cpp
|
||||
streambuf_readstream.cpp
|
||||
to_string.cpp
|
||||
@ -48,18 +49,23 @@ unit-test http-tests :
|
||||
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 :
|
||||
main.cpp
|
||||
http/nodejs_parser.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.
|
||||
#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;
|
||||
acceptor_.open(ep.protocol(), ec);
|
||||
maybe_throw(ec, "open");
|
||||
acceptor_.set_option(
|
||||
boost::asio::socket_base::reuse_address{true});
|
||||
acceptor_.bind(ep, ec);
|
||||
maybe_throw(ec, "bind");
|
||||
acceptor_.listen(
|
||||
@ -87,6 +89,12 @@ public:
|
||||
t.join();
|
||||
}
|
||||
|
||||
endpoint_type
|
||||
local_endpoint() const
|
||||
{
|
||||
return acceptor_.local_endpoint();
|
||||
}
|
||||
|
||||
private:
|
||||
class Peer
|
||||
{
|
@ -19,7 +19,7 @@
|
||||
|
||||
#include "websocket_async_echo_peer.hpp"
|
||||
#include "websocket_sync_echo_peer.hpp"
|
||||
#include "sig_wait.hpp"
|
||||
#include "../sig_wait.hpp"
|
||||
|
||||
int main()
|
||||
{
|
@ -17,8 +17,8 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_WSPROTO_SYNC_ECHO_PEER_H_INCLUDED
|
||||
#define BEAST_WSPROTO_SYNC_ECHO_PEER_H_INCLUDED
|
||||
#ifndef BEAST_WEBSOCKET_SYNC_ECHO_PEER_H_INCLUDED
|
||||
#define BEAST_WEBSOCKET_SYNC_ECHO_PEER_H_INCLUDED
|
||||
|
||||
#include <beast/streambuf.hpp>
|
||||
#include <beast/websocket.hpp>
|
||||
@ -55,6 +55,8 @@ public:
|
||||
error_code ec;
|
||||
acceptor_.open(ep.protocol(), ec);
|
||||
maybe_throw(ec, "open");
|
||||
acceptor_.set_option(
|
||||
boost::asio::socket_base::reuse_address{true});
|
||||
acceptor_.bind(ep, ec);
|
||||
maybe_throw(ec, "bind");
|
||||
acceptor_.listen(
|
||||
@ -74,6 +76,12 @@ public:
|
||||
thread_.join();
|
||||
}
|
||||
|
||||
endpoint_type
|
||||
local_endpoint() const
|
||||
{
|
||||
return acceptor_.local_endpoint();
|
||||
}
|
||||
|
||||
private:
|
||||
static
|
||||
void
|
Reference in New Issue
Block a user