Fixes, fail testing:

Core:

* Test buffer_cat iterator move members

HTTP:

* Fixed yield / resume in writer
* Fixed message serialization with chunked encoding

* Test yield / resume in writer
* Test all conditional branches during message serialization
* Test chunked encoding
* Increase coverage on parse_error
* Add parse_error::general

WebSocket:

* Add error::general
* Increase coverage in error
This commit is contained in:
Vinnie Falco
2016-05-07 17:06:46 -04:00
parent c49cde844b
commit b62d1b2164
44 changed files with 1064 additions and 688 deletions

View File

@@ -49,10 +49,10 @@ HTTP:
* Fix prepare() calling content_length() without init() * Fix prepare() calling content_length() without init()
* Use construct,destroy allocator routines in basic_headers * Use construct,destroy allocator routines in basic_headers
* Complete allocator testing in basic_streambuf, basic_headers * Complete allocator testing in basic_streambuf, basic_headers
* Fix http::async_write op, case 3 should break at the end.
* Add tests for writer using the resume function / coros * Add tests for writer using the resume function / coros
* Custom HTTP error codes for various situations * Custom HTTP error codes for various situations
* Make empty_body write-only, remove reader nested type * Make empty_body write-only, remove reader nested type
* Add concepts WritableBody ReadableBody with type checks, * Add concepts WritableBody ReadableBody with type checks,
check them in read and write functions check them in read and write functions
* Branch prediction hints in parser * Branch prediction hints in parser
* Check basic_parser_v1 against rfc7230 for leading message whitespace

View File

@@ -1,21 +1,9 @@
//------------------------------------------------------------------------------ //
/* // Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
This file is part of Beast: https://github.com/vinniefalco/Beast //
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.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)
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_EXAMPLE_FILE_BODY_H_INCLUDED #ifndef BEAST_EXAMPLE_FILE_BODY_H_INCLUDED
#define BEAST_EXAMPLE_FILE_BODY_H_INCLUDED #define BEAST_EXAMPLE_FILE_BODY_H_INCLUDED

View File

@@ -1,21 +1,9 @@
//------------------------------------------------------------------------------ //
/* // Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
This file is part of Beast: https://github.com/vinniefalco/Beast //
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.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)
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_EXAMPLE_HTTP_ASYNC_SERVER_H_INCLUDED #ifndef BEAST_EXAMPLE_HTTP_ASYNC_SERVER_H_INCLUDED
#define BEAST_EXAMPLE_HTTP_ASYNC_SERVER_H_INCLUDED #define BEAST_EXAMPLE_HTTP_ASYNC_SERVER_H_INCLUDED

View File

@@ -1,21 +1,9 @@
//------------------------------------------------------------------------------ //
/* // Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
This file is part of Beast: https://github.com/vinniefalco/Beast //
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.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)
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.
*/
//==============================================================================
#include "http_stream.hpp" #include "http_stream.hpp"
#include "urls_large_data.hpp" #include "urls_large_data.hpp"

View File

@@ -1,21 +1,9 @@
//------------------------------------------------------------------------------ //
/* // Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
This file is part of Beast: https://github.com/vinniefalco/Beast //
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.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)
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.
*/
//==============================================================================
#include "http_async_server.hpp" #include "http_async_server.hpp"
#include "http_sync_server.hpp" #include "http_sync_server.hpp"

View File

@@ -1,21 +1,9 @@
//------------------------------------------------------------------------------ //
/* // Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
This file is part of Beast: https://github.com/vinniefalco/Beast //
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.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)
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_HTTP_STREAM_H_INCLUDED #ifndef BEAST_HTTP_STREAM_H_INCLUDED
#define BEAST_HTTP_STREAM_H_INCLUDED #define BEAST_HTTP_STREAM_H_INCLUDED

View File

@@ -1,21 +1,9 @@
//------------------------------------------------------------------------------ //
/* // Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
This file is part of Beast: https://github.com/vinniefalco/Beast //
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.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)
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_HTTP_STREAM_IPP_INCLUDED #ifndef BEAST_HTTP_STREAM_IPP_INCLUDED
#define BEAST_HTTP_STREAM_IPP_INCLUDED #define BEAST_HTTP_STREAM_IPP_INCLUDED

View File

@@ -1,21 +1,9 @@
//------------------------------------------------------------------------------ //
/* // Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
This file is part of Beast: https://github.com/vinniefalco/Beast //
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.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)
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_EXAMPLE_HTTP_SYNC_SERVER_H_INCLUDED #ifndef BEAST_EXAMPLE_HTTP_SYNC_SERVER_H_INCLUDED
#define BEAST_EXAMPLE_HTTP_SYNC_SERVER_H_INCLUDED #define BEAST_EXAMPLE_HTTP_SYNC_SERVER_H_INCLUDED

View File

@@ -1,21 +1,9 @@
//------------------------------------------------------------------------------ //
/* // Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
This file is part of Beast: https://github.com/vinniefalco/Beast //
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.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)
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.
*/
//==============================================================================
#include "urls_large_data.hpp" #include "urls_large_data.hpp"

View File

@@ -1,21 +1,9 @@
//------------------------------------------------------------------------------ //
/* // Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
This file is part of Beast: https://github.com/vinniefalco/Beast //
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.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)
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 URLS_LARGE_DATA_H_INCLUDED #ifndef URLS_LARGE_DATA_H_INCLUDED
#define URLS_LARGE_DATA_H_INCLUDED #define URLS_LARGE_DATA_H_INCLUDED

View File

@@ -0,0 +1,69 @@
//
// 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_TEST_FAIL_COUNTER_HPP
#define BEAST_TEST_FAIL_COUNTER_HPP
#include <beast/core/error.hpp>
namespace beast {
namespace test {
/** A countdown to simulated failure.
On the Nth operation, the class will fail with the specified
error code, or the default error code of invalid_argument.
*/
class fail_counter
{
std::size_t n_;
error_code ec_;
public:
fail_counter(fail_counter&&) = default;
/** Construct a counter.
@param The 0-based index of the operation to fail on or after.
*/
explicit
fail_counter(std::size_t n = 0)
: n_(n)
, ec_(boost::system::errc::make_error_code(
boost::system::errc::errc_t::invalid_argument))
{
}
/// Throw an exception on the Nth failure
void
fail()
{
if(n_ > 0)
--n_;
if(! n_)
throw system_error{ec_};
}
/// Set an error code on the Nth failure
bool
fail(error_code& ec)
{
if(n_ > 0)
--n_;
if(! n_)
{
ec = ec_;
return true;
}
return false;
}
};
} // test
} // beast
#endif

View File

@@ -1,21 +1,9 @@
//------------------------------------------------------------------------------ //
/* // Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
This file is part of Beast: https://github.com/vinniefalco/Beast //
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.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)
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_TEST_FAIL_STREAM_HPP #ifndef BEAST_TEST_FAIL_STREAM_HPP
#define BEAST_TEST_FAIL_STREAM_HPP #define BEAST_TEST_FAIL_STREAM_HPP
@@ -25,6 +13,7 @@
#include <beast/core/error.hpp> #include <beast/core/error.hpp>
#include <beast/core/detail/get_lowest_layer.hpp> #include <beast/core/detail/get_lowest_layer.hpp>
#include <beast/websocket/teardown.hpp> #include <beast/websocket/teardown.hpp>
#include <beast/test/fail_counter.hpp>
namespace beast { namespace beast {
namespace test { namespace test {
@@ -37,32 +26,10 @@ namespace test {
template<class NextLayer> template<class NextLayer>
class fail_stream class fail_stream
{ {
error_code ec_; fail_counter* pfc_;
std::size_t n_ = 0; fail_counter fc_;
NextLayer next_layer_; NextLayer next_layer_;
void
fail()
{
if(n_ > 0)
--n_;
if(! n_)
throw system_error{ec_};
}
bool
fail(error_code& ec)
{
if(n_ > 0)
--n_;
if(! n_)
{
ec = ec_;
return true;
}
return false;
}
public: public:
using next_layer_type = using next_layer_type =
typename std::remove_reference<NextLayer>::type; typename std::remove_reference<NextLayer>::type;
@@ -71,15 +38,24 @@ public:
typename beast::detail::get_lowest_layer< typename beast::detail::get_lowest_layer<
next_layer_type>::type; next_layer_type>::type;
fail_stream(fail_stream&&) = default; fail_stream(fail_stream&&) = delete;
fail_stream& operator=(fail_stream&&) = default; fail_stream(fail_stream const&) = delete;
fail_stream& operator=(fail_stream&&) = delete;
fail_stream& operator=(fail_stream const&) = delete;
template<class... Args> template<class... Args>
explicit explicit
fail_stream(std::size_t n, Args&&... args) fail_stream(std::size_t n, Args&&... args)
: ec_(boost::system::errc::make_error_code( : pfc_(&fc_)
boost::system::errc::errc_t::invalid_argument)) , fc_(n)
, n_(n) , next_layer_(std::forward<Args>(args)...)
{
}
template<class... Args>
explicit
fail_stream(fail_counter& fc, Args&&... args)
: pfc_(&fc)
, next_layer_(std::forward<Args>(args)...) , next_layer_(std::forward<Args>(args)...)
{ {
} }
@@ -112,7 +88,7 @@ public:
std::size_t std::size_t
read_some(MutableBufferSequence const& buffers) read_some(MutableBufferSequence const& buffers)
{ {
fail(); pfc_->fail();
return next_layer_.read_some(buffers); return next_layer_.read_some(buffers);
} }
@@ -120,7 +96,7 @@ public:
std::size_t std::size_t
read_some(MutableBufferSequence const& buffers, error_code& ec) read_some(MutableBufferSequence const& buffers, error_code& ec)
{ {
if(fail(ec)) if(pfc_->fail(ec))
return 0; return 0;
return next_layer_.read_some(buffers, ec); return next_layer_.read_some(buffers, ec);
} }
@@ -132,7 +108,7 @@ public:
ReadHandler&& handler) ReadHandler&& handler)
{ {
error_code ec; error_code ec;
if(fail(ec)) if(pfc_->fail(ec))
{ {
async_completion< async_completion<
ReadHandler, void(error_code, std::size_t) ReadHandler, void(error_code, std::size_t)
@@ -149,7 +125,7 @@ public:
std::size_t std::size_t
write_some(ConstBufferSequence const& buffers) write_some(ConstBufferSequence const& buffers)
{ {
fail(); pfc_->fail();
return next_layer_.write_some(buffers); return next_layer_.write_some(buffers);
} }
@@ -157,7 +133,7 @@ public:
std::size_t std::size_t
write_some(ConstBufferSequence const& buffers, error_code& ec) write_some(ConstBufferSequence const& buffers, error_code& ec)
{ {
if(fail(ec)) if(pfc_->fail(ec))
return 0; return 0;
return next_layer_.write_some(buffers, ec); return next_layer_.write_some(buffers, ec);
} }
@@ -169,7 +145,7 @@ public:
WriteHandler&& handler) WriteHandler&& handler)
{ {
error_code ec; error_code ec;
if(fail(ec)) if(pfc_->fail(ec))
{ {
async_completion< async_completion<
WriteHandler, void(error_code, std::size_t) WriteHandler, void(error_code, std::size_t)

View File

@@ -60,7 +60,10 @@ public:
{ {
auto const n = boost::asio::buffer_copy( auto const n = boost::asio::buffer_copy(
buffers, boost::asio::buffer(s_)); buffers, boost::asio::buffer(s_));
if(n > 0)
s_.erase(0, n); s_.erase(0, n);
else
ec = boost::asio::error::eof;
return n; return n;
} }
@@ -72,11 +75,15 @@ public:
{ {
auto const n = boost::asio::buffer_copy( auto const n = boost::asio::buffer_copy(
buffers, boost::asio::buffer(s_)); buffers, boost::asio::buffer(s_));
error_code ec;
if(n > 0)
s_.erase(0, n); s_.erase(0, n);
else
ec = boost::asio::error::eof;
async_completion<ReadHandler, async_completion<ReadHandler,
void(error_code, std::size_t)> completion(handler); void(error_code, std::size_t)> completion(handler);
ios_.post(bind_handler( ios_.post(bind_handler(
completion.handler, error_code{}, n)); completion.handler, ec, n));
return completion.result.get(); return completion.result.get();
} }

View File

@@ -37,7 +37,7 @@ private:
std::condition_variable cv_; std::condition_variable cv_;
bool running_ = false;; bool running_ = false;;
protected: public:
/// The type of yield context passed to functions. /// The type of yield context passed to functions.
using yield_context = using yield_context =
boost::asio::yield_context; boost::asio::yield_context;
@@ -58,6 +58,13 @@ protected:
thread_.join(); thread_.join();
} }
/// Return the `io_service` associated with the object
boost::asio::io_service&
get_io_service()
{
return ios_;
}
/** Run a function in a coroutine. /** Run a function in a coroutine.
This call will block until the coroutine terminates. This call will block until the coroutine terminates.

View File

@@ -1,21 +1,9 @@
//------------------------------------------------------------------------------ //
/* // Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
This file is part of Beast: https://github.com/vinniefalco/Beast //
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.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)
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.
*/
//==============================================================================
#include <beast/unit_test/amount.hpp> #include <beast/unit_test/amount.hpp>
#include <beast/unit_test/global_suites.hpp> #include <beast/unit_test/global_suites.hpp>

View File

@@ -197,7 +197,6 @@ private:
void void
move(C<sizeof...(Bs)>, const_iterator&&) move(C<sizeof...(Bs)>, const_iterator&&)
{ {
return;
} }
template<std::size_t I> template<std::size_t I>
@@ -216,7 +215,6 @@ private:
void void
copy(C<sizeof...(Bs)>, const_iterator const&) copy(C<sizeof...(Bs)>, const_iterator const&)
{ {
return;
} }
template<std::size_t I> template<std::size_t I>

View File

@@ -110,7 +110,7 @@ read_some_op<MutableBufferSequence, Handler>::operator()(
if(d.srs.sb_.size() == 0) if(d.srs.sb_.size() == 0)
{ {
d.state = d.state =
d.srs.size_ > 0 ? 2 : 1; d.srs.capacity_ > 0 ? 2 : 1;
break; break;
} }
d.state = 4; d.state = 4;
@@ -129,7 +129,7 @@ read_some_op<MutableBufferSequence, Handler>::operator()(
// read // read
d.state = 3; d.state = 3;
d.srs.next_layer_.async_read_some( d.srs.next_layer_.async_read_some(
d.srs.sb_.prepare(d.srs.size_), d.srs.sb_.prepare(d.srs.capacity_),
std::move(*this)); std::move(*this));
return; return;
@@ -217,14 +217,12 @@ read_some(MutableBufferSequence const& buffers,
"MutableBufferSequence requirements not met"); "MutableBufferSequence requirements not met");
using boost::asio::buffer_size; using boost::asio::buffer_size;
using boost::asio::buffer_copy; using boost::asio::buffer_copy;
if(buffer_size(buffers) == 0)
return 0;
if(size_ == 0)
return next_layer_.read_some(buffers, ec);
if(sb_.size() == 0) if(sb_.size() == 0)
{ {
if(capacity_ == 0)
return next_layer_.read_some(buffers, ec);
sb_.commit(next_layer_.read_some( sb_.commit(next_layer_.read_some(
sb_.prepare(size_), ec)); sb_.prepare(capacity_), ec));
if(ec) if(ec)
return 0; return 0;
} }

View File

@@ -1,21 +1,9 @@
//------------------------------------------------------------------------------ //
/* // Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
This file is part of Beast: https://github.com/vinniefalco/Beast //
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.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)
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 #ifndef BEAST_WEBSOCKET_STATIC_STRING_HPP
#define BEAST_WEBSOCKET_STATIC_STRING_HPP #define BEAST_WEBSOCKET_STATIC_STRING_HPP

View File

@@ -99,7 +99,7 @@ class streambuf_readstream
class read_some_op; class read_some_op;
Streambuf sb_; Streambuf sb_;
std::size_t size_ = 0; std::size_t capacity_ = 0;
Stream next_layer_; Stream next_layer_;
public: public:
@@ -211,9 +211,9 @@ public:
than the amount of data in the buffer, no bytes are discarded. than the amount of data in the buffer, no bytes are discarded.
*/ */
void void
reserve(std::size_t size) capacity(std::size_t size)
{ {
size_ = size; capacity_ = size;
} }
/// Write the given data to the stream. Returns the number of bytes written. /// Write the given data to the stream. Returns the number of bytes written.

View File

@@ -8,7 +8,9 @@
#ifndef BEAST_HTTP_DETAIL_CHUNK_ENCODE_HPP #ifndef BEAST_HTTP_DETAIL_CHUNK_ENCODE_HPP
#define BEAST_HTTP_DETAIL_CHUNK_ENCODE_HPP #define BEAST_HTTP_DETAIL_CHUNK_ENCODE_HPP
#include <beast/core/buffer_cat.hpp>
#include <boost/asio/buffer.hpp> #include <boost/asio/buffer.hpp>
#include <boost/logic/tribool.hpp>
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <cassert> #include <cassert>
@@ -20,244 +22,94 @@ namespace beast {
namespace http { namespace http {
namespace detail { namespace detail {
template <class Buffers> class chunk_encode_text
class chunk_encoded_buffers
{ {
private: boost::asio::const_buffer cb_;
using const_buffer = boost::asio::const_buffer;
Buffers buffers_;
const_buffer head_;
const_buffer tail_;
// Storage for the longest hex string we might need, plus delimiters. // Storage for the longest hex string we might need, plus delimiters.
std::array<char, 2 * sizeof(std::size_t) + 2> data_; std::array<char, 2 * sizeof(std::size_t) + 2> buf_;
template <class OutIter>
static
OutIter
to_hex(OutIter last, std::size_t n)
{
if(n == 0)
{
*--last = '0';
return last;
}
while(n)
{
*--last = "0123456789abcdef"[n&0xf];
n>>=4;
}
return last;
}
public: public:
using value_type = boost::asio::const_buffer; using value_type = boost::asio::const_buffer;
class const_iterator; using const_iterator = value_type const*;
chunk_encoded_buffers() = delete; chunk_encode_text(chunk_encode_text const& other)
chunk_encoded_buffers (chunk_encoded_buffers const&) = default; {
chunk_encoded_buffers& operator= (chunk_encoded_buffers const&) = default; auto const n =
boost::asio::buffer_size(other.cb_);
buf_ = other.buf_;
cb_ = boost::asio::const_buffer(
&buf_[buf_.size() - n], n);
}
chunk_encoded_buffers (Buffers const& buffers, bool final_chunk); explicit
chunk_encode_text(std::size_t n)
{
buf_[buf_.size() - 2] = '\r';
buf_[buf_.size() - 1] = '\n';
auto it = to_hex(buf_.end() - 2, n);
cb_ = boost::asio::const_buffer{&*it,
static_cast<std::size_t>(
std::distance(it, buf_.end()))};
}
const_iterator const_iterator
begin() const begin() const
{ {
return const_iterator(*this, false); return &cb_;
} }
const_iterator const_iterator
end() const end() const
{ {
return const_iterator(*this, true); return begin() + 1;
} }
private:
// Unchecked conversion of unsigned to hex string
template<class OutIter, class Unsigned>
static
typename std::enable_if<
std::is_unsigned<Unsigned>::value, OutIter>::type
to_hex(OutIter const first, OutIter const last, Unsigned n);
}; };
template <class Buffers> /** Returns a chunk-encoded ConstBufferSequence.
class chunk_encoded_buffers<Buffers>::const_iterator
: public std::iterator<std::bidirectional_iterator_tag, const_buffer>
{
private:
using iterator = typename Buffers::const_iterator;
enum class Where { head, input, end };
chunk_encoded_buffers const* buffers_;
Where where_;
iterator iter_;
public: This returns a buffer sequence representing the
const_iterator(); first chunk of a chunked transfer coded body.
const_iterator (const_iterator const&) = default;
const_iterator& operator= (const_iterator const&) = default;
bool operator== (const_iterator const& other) const;
bool operator!= (const_iterator const& other) const;
const_iterator& operator++();
const_iterator& operator--();
const_iterator operator++(int) const;
const_iterator operator--(int) const;
const_buffer operator*() const;
private:
friend class chunk_encoded_buffers;
const_iterator(chunk_encoded_buffers const& buffers, bool past_the_end);
};
//------------------------------------------------------------------------------
template <class Buffers>
chunk_encoded_buffers<Buffers>::chunk_encoded_buffers (
Buffers const& buffers, bool final_chunk)
: buffers_(buffers)
{
auto const size = boost::asio::buffer_size(buffers);
data_[data_.size() - 2] = '\r';
data_[data_.size() - 1] = '\n';
auto pos = to_hex(data_.begin(), data_.end() - 2, size);
head_ = const_buffer(&*pos,
std::distance(pos, data_.end()));
if (size > 0 && final_chunk)
tail_ = const_buffer("\r\n0\r\n\r\n", 7);
else
tail_ = const_buffer("\r\n", 2);
}
template <class Buffers>
template <class OutIter, class Unsigned>
typename std::enable_if<
std::is_unsigned<Unsigned>::value, OutIter>::type
chunk_encoded_buffers<Buffers>::to_hex(
OutIter const first, OutIter const last, Unsigned n)
{
assert(first != last);
OutIter iter = last;
if(n == 0)
{
*--iter = '0';
return iter;
}
while(n)
{
assert(iter != first);
*--iter = "0123456789abcdef"[n&0xf];
n>>=4;
}
return iter;
}
template <class Buffers>
chunk_encoded_buffers<Buffers>::const_iterator::const_iterator()
: buffers_(nullptr)
, where_(Where::end)
{
}
template <class Buffers>
bool
chunk_encoded_buffers<Buffers>::const_iterator::operator==(
const_iterator const& other) const
{
return buffers_ == other.buffers_ &&
where_ == other.where_ && iter_ == other.iter_;
}
template <class Buffers>
bool
chunk_encoded_buffers<Buffers>::const_iterator::operator!=(
const_iterator const& other) const
{
return buffers_ != other.buffers_ ||
where_ != other.where_ || iter_ != other.iter_;
}
template <class Buffers>
auto
chunk_encoded_buffers<Buffers>::const_iterator::operator++() ->
const_iterator&
{
assert(buffers_);
assert(where_ != Where::end);
if (where_ == Where::head)
where_ = Where::input;
else if (iter_ != buffers_->buffers_.end())
++iter_;
else
where_ = Where::end;
return *this;
}
template <class Buffers>
auto
chunk_encoded_buffers<Buffers>::const_iterator::operator--() ->
const_iterator&
{
assert(buffers_);
assert(where_ != Where::head);
if (where_ == Where::end)
where_ = Where::input;
else if (iter_ != buffers_->buffers_.begin())
--iter_;
else
where_ = Where::head;
return *this;
}
template <class Buffers>
auto
chunk_encoded_buffers<Buffers>::const_iterator::operator++(int) const ->
const_iterator
{
auto iter = *this;
++iter;
return iter;
}
template <class Buffers>
auto
chunk_encoded_buffers<Buffers>::const_iterator::operator--(int) const ->
const_iterator
{
auto iter = *this;
--iter;
return iter;
}
template <class Buffers>
auto
chunk_encoded_buffers<Buffers>::const_iterator::operator*() const ->
const_buffer
{
assert(buffers_);
assert(where_ != Where::end);
if (where_ == Where::head)
return buffers_->head_;
if (iter_ != buffers_->buffers_.end())
return *iter_;
return buffers_->tail_;
}
template <class Buffers>
chunk_encoded_buffers<Buffers>::const_iterator::const_iterator(
chunk_encoded_buffers const& buffers, bool past_the_end)
: buffers_(&buffers)
, where_(past_the_end ? Where::end : Where::head)
, iter_(past_the_end ? buffers_->buffers_.end() :
buffers_->buffers_.begin())
{
}
/* Returns a chunk-encoded BufferSequence.
See:
http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6.1
@param buffers The input buffer sequence. @param buffers The input buffer sequence.
@param final_chunk `true` If this should include a final-chunk.
@return A chunk-encoded ConstBufferSequence representing the input. @return A chunk-encoded ConstBufferSequence representing the input.
@see <a href=https://tools.ietf.org/html/rfc7230#section-4.1.3>rfc7230 section 4.1.3</a>
*/ */
template<class ConstBufferSequence> template<class ConstBufferSequence>
#if GENERATING_DOCS #if GENERATING_DOCS
implementation_defined implementation_defined
#else #else
detail::chunk_encoded_buffers<ConstBufferSequence> beast::detail::buffer_cat_helper<boost::asio::const_buffer,
chunk_encode_text, ConstBufferSequence, boost::asio::const_buffers_1>
#endif #endif
chunk_encode(ConstBufferSequence const& buffers, chunk_encode(ConstBufferSequence const& buffers)
bool final_chunk = false)
{ {
return detail::chunk_encoded_buffers< using boost::asio::buffer_size;
ConstBufferSequence>{buffers, final_chunk}; return buffer_cat(
chunk_encode_text{buffer_size(buffers)},
buffers,
boost::asio::const_buffers_1{"\r\n", 2});
} }
/// Returns a chunked encoding final chunk. /// Returns a chunked encoding final chunk.

View File

@@ -148,13 +148,13 @@ class write_op
} }
}; };
class writef0 class writef0_lambda
{ {
write_op& self_; write_op& self_;
public: public:
explicit explicit
writef0(write_op& self) writef0_lambda(write_op& self)
: self_(self) : self_(self)
{ {
} }
@@ -176,13 +176,13 @@ class write_op
} }
}; };
class writef class writef_lambda
{ {
write_op& self_; write_op& self_;
public: public:
explicit explicit
writef(write_op& self) writef_lambda(write_op& self)
: self_(self) : self_(self)
{ {
} }
@@ -300,7 +300,7 @@ operator()(error_code ec, std::size_t, bool again)
case 1: case 1:
{ {
auto const result = d.wp.w( auto const result = d.wp.w(
std::move(d.copy), ec, writef0{*this}); std::move(d.copy), ec, writef0_lambda{*this});
if(ec) if(ec)
{ {
// call handler // call handler
@@ -331,7 +331,7 @@ operator()(error_code ec, std::size_t, bool again)
case 3: case 3:
{ {
auto const result = d.wp.w( auto const result = d.wp.w(
std::move(d.copy), ec, writef{*this}); std::move(d.copy), ec, writef_lambda{*this});
if(ec) if(ec)
{ {
// call handler // call handler
@@ -378,7 +378,7 @@ operator()(error_code ec, std::size_t, bool again)
} }
template<class SyncWriteStream, class Streambuf> template<class SyncWriteStream, class Streambuf>
class writef0_write class writef0_lambda
{ {
Streambuf const& sb_; Streambuf const& sb_;
SyncWriteStream& stream_; SyncWriteStream& stream_;
@@ -386,7 +386,7 @@ class writef0_write
error_code& ec_; error_code& ec_;
public: public:
writef0_write(SyncWriteStream& stream, writef0_lambda(SyncWriteStream& stream,
Streambuf const& sb, bool chunked, error_code& ec) Streambuf const& sb, bool chunked, error_code& ec)
: sb_(sb) : sb_(sb)
, stream_(stream) , stream_(stream)
@@ -409,14 +409,14 @@ public:
}; };
template<class SyncWriteStream> template<class SyncWriteStream>
class writef_write class writef_lambda
{ {
SyncWriteStream& stream_; SyncWriteStream& stream_;
bool chunked_; bool chunked_;
error_code& ec_; error_code& ec_;
public: public:
writef_write(SyncWriteStream& stream, writef_lambda(SyncWriteStream& stream,
bool chunked, error_code& ec) bool chunked, error_code& ec)
: stream_(stream) : stream_(stream)
, chunked_(chunked) , chunked_(chunked)
@@ -478,47 +478,45 @@ write(SyncWriteStream& stream,
cv.notify_one(); cv.notify_one();
}}; }};
auto copy = resume; auto copy = resume;
for(;;) boost::tribool result;
{ result = wp.w(std::move(copy), ec,
{ detail::writef0_lambda<SyncWriteStream, decltype(wp.sb)>{
auto result = wp.w(std::move(copy), ec,
detail::writef0_write<SyncWriteStream, decltype(wp.sb)>{
stream, wp.sb, wp.chunked, ec}); stream, wp.sb, wp.chunked, ec});
if(ec) if(ec)
return; return;
if(result)
break;
if(boost::indeterminate(result)) if(boost::indeterminate(result))
{ {
boost::asio::write(stream, wp.sb.data(), ec);
if(ec)
return;
wp.sb.consume(wp.sb.size());
copy = resume; copy = resume;
{
std::unique_lock<std::mutex> lock(m); std::unique_lock<std::mutex> lock(m);
cv.wait(lock, [&]{ return ready; }); cv.wait(lock, [&]{ return ready; });
ready = false; ready = false;
} }
boost::asio::write(stream, wp.sb.data(), ec);
if(ec)
return;
result = false;
} }
wp.sb.consume(wp.sb.size()); wp.sb.consume(wp.sb.size());
if(! result)
{
for(;;) for(;;)
{ {
auto result = wp.w(std::move(copy), ec, result = wp.w(std::move(copy), ec,
detail::writef_write<SyncWriteStream>{ detail::writef_lambda<SyncWriteStream>{
stream, wp.chunked, ec}); stream, wp.chunked, ec});
if(ec) if(ec)
return; return;
if(result) if(result)
break; break;
if(boost::indeterminate(result)) if(! result)
{ continue;
copy = resume; copy = resume;
std::unique_lock<std::mutex> lock(m); std::unique_lock<std::mutex> lock(m);
cv.wait(lock, [&]{ return ready; }); cv.wait(lock, [&]{ return ready; });
ready = false; ready = false;
} }
} }
}
if(wp.chunked) if(wp.chunked)
{ {
// VFALCO Unfortunately the current interface to the // VFALCO Unfortunately the current interface to the

View File

@@ -34,7 +34,9 @@ enum class parse_error
invalid_chunk_size, invalid_chunk_size,
short_read short_read,
general
}; };
class parse_error_category : public boost::system::error_category class parse_error_category : public boost::system::error_category
@@ -97,7 +99,7 @@ public:
return "unexpected end of data"; return "unexpected end of data";
default: default:
return "beast::http::parser error"; return "parse error";
} }
} }

View File

@@ -1,21 +1,9 @@
//------------------------------------------------------------------------------ //
/* // Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
This file is part of Beast: https://github.com/vinniefalco/Beast //
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.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)
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_HPP #ifndef BEAST_WEBSOCKET_HPP
#define BEAST_WEBSOCKET_HPP #define BEAST_WEBSOCKET_HPP

View File

@@ -44,7 +44,10 @@ enum class error
request_invalid, request_invalid,
/// Upgrade request denied /// Upgrade request denied
request_denied request_denied,
/// General WebSocket error
general
}; };
#if ! GENERATING_DOCS #if ! GENERATING_DOCS

View File

@@ -861,6 +861,7 @@ build_response(http::request_v1<Body, Headers> const& req)
res.version = req.version; res.version = req.version;
res.body = text; res.body = text;
// VFALCO TODO respect keep-alive here // VFALCO TODO respect keep-alive here
prepare(res);
return res; return res;
}; };
if(req.version < 11) if(req.version < 11)

View File

@@ -202,7 +202,7 @@ public:
void void
set_option(read_buffer_size const& o) set_option(read_buffer_size const& o)
{ {
stream_.reserve(o.value); stream_.capacity(o.value);
} }
/// Set the maximum incoming message size allowed /// Set the maximum incoming message size allowed
@@ -217,7 +217,7 @@ public:
set_option(write_buffer_size const& o) set_option(write_buffer_size const& o)
{ {
wr_buf_size_ = std::max<std::size_t>(o.value, 1024); wr_buf_size_ = std::max<std::size_t>(o.value, 1024);
stream_.reserve(o.value); stream_.capacity(o.value);
} }
/** Get the io_service associated with the stream. /** Get the io_service associated with the stream.

View File

@@ -1,21 +1,9 @@
//------------------------------------------------------------------------------ //
/* // Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
This file is part of Beast: https://github.com/vinniefalco/Beast //
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.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)
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_TEARDOWN_HPP #ifndef BEAST_WEBSOCKET_TEARDOWN_HPP
#define BEAST_WEBSOCKET_TEARDOWN_HPP #define BEAST_WEBSOCKET_TEARDOWN_HPP

View File

@@ -3,6 +3,7 @@ set -e
gdb --silent \ gdb --silent \
--batch \ --batch \
--return-child-result \ --return-child-result \
-ex="set print thread-events off" \
-ex=run \ -ex=run \
-ex="thread apply all bt full" \ -ex="thread apply all bt full" \
--args $@ --args $@

View File

@@ -59,6 +59,7 @@ unit-test http-tests :
http/string_body.cpp http/string_body.cpp
http/type_check.cpp http/type_check.cpp
http/write.cpp http/write.cpp
http/detail/chunk_encode.cpp
; ;
unit-test bench-tests : unit-test bench-tests :

View File

@@ -81,7 +81,15 @@ public:
const_buffer{buf+4, 2}, const_buffer{buf+4, 2},
const_buffer{buf+6, 3}}}; const_buffer{buf+6, 3}}};
auto bs = buffer_cat(b1, b2); auto bs = buffer_cat(b1, b2);
for(int n = 0;
n <= std::distance(bs.begin(), bs.end()); ++n)
{
auto it = std::next(bs.begin(), n);
decltype(it) it2(std::move(it));
it = std::move(it2);
auto pit = &it;
it = std::move(*pit);
}
try try
{ {
std::size_t n = 0; std::size_t n = 0;

View File

@@ -9,15 +9,22 @@
#include <beast/core/streambuf_readstream.hpp> #include <beast/core/streambuf_readstream.hpp>
#include <beast/core/streambuf.hpp> #include <beast/core/streambuf.hpp>
#include <beast/test/fail_stream.hpp>
#include <beast/test/string_stream.hpp>
#include <beast/test/yield_to.hpp>
#include <beast/unit_test/suite.hpp> #include <beast/unit_test/suite.hpp>
#include <boost/asio.hpp> #include <boost/asio.hpp>
namespace beast { namespace beast {
class streambuf_readstream_test : public beast::unit_test::suite class streambuf_readstream_test
: public unit_test::suite
, public test::enable_yield_to
{ {
using self = streambuf_readstream_test;
public: public:
void testSpecial() void testSpecialMembers()
{ {
using socket_type = boost::asio::ip::tcp::socket; using socket_type = boost::asio::ip::tcp::socket;
boost::asio::io_service ios; boost::asio::io_service ios;
@@ -33,12 +40,100 @@ public:
streambuf_readstream<socket_type&, streambuf> srs(sock); streambuf_readstream<socket_type&, streambuf> srs(sock);
streambuf_readstream<socket_type&, streambuf> srs2(std::move(srs)); streambuf_readstream<socket_type&, streambuf> srs2(std::move(srs));
} }
pass(); }
void testRead(yield_context do_yield)
{
using boost::asio::buffer;
using boost::asio::buffer_copy;
static std::size_t constexpr limit = 100;
std::size_t n;
std::string s;
s.resize(13);
for(n = 0; n < limit; ++n)
{
test::fail_stream<
test::string_stream> fs(n, ios_, ", world!");
streambuf_readstream<
decltype(fs)&, streambuf> srs(fs);
srs.buffer().commit(buffer_copy(
srs.buffer().prepare(5), buffer("Hello", 5)));
boost::system::error_code ec;
boost::asio::read(srs, buffer(&s[0], s.size()), ec);
if(! ec)
{
expect(s == "Hello, world!");
break;
}
}
expect(n < limit);
for(n = 0; n < limit; ++n)
{
test::fail_stream<
test::string_stream> fs(n, ios_, ", world!");
streambuf_readstream<
decltype(fs)&, streambuf> srs(fs);
srs.capacity(3);
srs.buffer().commit(buffer_copy(
srs.buffer().prepare(5), buffer("Hello", 5)));
boost::system::error_code ec;
boost::asio::read(srs, buffer(&s[0], s.size()), ec);
if(! ec)
{
expect(s == "Hello, world!");
break;
}
}
expect(n < limit);
for(n = 0; n < limit; ++n)
{
test::fail_stream<
test::string_stream> fs(n, ios_, ", world!");
streambuf_readstream<
decltype(fs)&, streambuf> srs(fs);
srs.buffer().commit(buffer_copy(
srs.buffer().prepare(5), buffer("Hello", 5)));
boost::system::error_code ec;
boost::asio::async_read(
srs, buffer(&s[0], s.size()), do_yield[ec]);
if(! ec)
{
expect(s == "Hello, world!");
break;
}
}
expect(n < limit);
for(n = 0; n < limit; ++n)
{
test::fail_stream<
test::string_stream> fs(n, ios_, ", world!");
streambuf_readstream<
decltype(fs)&, streambuf> srs(fs);
srs.capacity(3);
srs.buffer().commit(buffer_copy(
srs.buffer().prepare(5), buffer("Hello", 5)));
boost::system::error_code ec;
boost::asio::async_read(
srs, buffer(&s[0], s.size()), do_yield[ec]);
if(! ec)
{
expect(s == "Hello, world!");
break;
}
}
expect(n < limit);
} }
void run() override void run() override
{ {
testSpecial(); testSpecialMembers();
yield_to(std::bind(&self::testRead,
this, std::placeholders::_1));
} }
}; };

View File

@@ -26,6 +26,7 @@ add_executable (http-tests
string_body.cpp string_body.cpp
type_check.cpp type_check.cpp
write.cpp write.cpp
detail/chunk_encode.cpp
) )
if (NOT WIN32) if (NOT WIN32)

View File

@@ -58,5 +58,5 @@ public:
BEAST_DEFINE_TESTSUITE(basic_headers,http,beast); BEAST_DEFINE_TESTSUITE(basic_headers,http,beast);
} // asio } // http
} // beast } // beast

View File

@@ -573,11 +573,14 @@ public:
parse_ev<true>("GET / HTTP/1.1\r\nf :", parse_error::bad_field); parse_ev<true>("GET / HTTP/1.1\r\nf :", parse_error::bad_field);
} }
void testCorrupt() void testInvalidMatrix()
{ {
using boost::asio::buffer; using boost::asio::buffer;
static std::size_t constexpr limit = 200;
std::string s; std::string s;
for(std::size_t n = 0;;++n) std::size_t n;
for(n = 0; n < limit; ++n)
{ {
// Create a request and set one octet to an invalid char // Create a request and set one octet to an invalid char
s = s =
@@ -607,6 +610,41 @@ public:
expect(ec); expect(ec);
} }
} }
expect(n < limit);
for(n = 0; n < limit; ++n)
{
// Create a response and set one octet to an invalid char
s =
"HTTP/1.1 200 OK\r\n"
"Server: test\r\n"
"Transer-Encoding: chunked\r\n"
"\r\n"
"10\r\n"
"****************\r\n"
"0\r\n\r\n";
auto const len = s.size();
if(n >= s.size())
{
pass();
break;
}
s[n] = 0;
for(std::size_t m = 1; m < len - 1; ++m)
{
null_parser<true> p;
error_code ec;
p.write(buffer(s.data(), m), ec);
if(ec)
{
pass();
continue;
}
p.write(buffer(s.data() + m, len - m), ec);
expect(ec);
}
}
expect(n < limit);
} }
void void
@@ -758,7 +796,7 @@ public:
testFlags(); testFlags();
testUpgrade(); testUpgrade();
testBad(); testBad();
testCorrupt(); testInvalidMatrix();
testRandomReq(100); testRandomReq(100);
testRandomResp(100); testRandomResp(100);
testBody(); testBody();

View File

@@ -0,0 +1,132 @@
//
// 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)
//
#include <beast/http/detail/chunk_encode.hpp>
#include <beast/core/to_string.hpp>
#include <beast/unit_test/suite.hpp>
namespace beast {
namespace http {
namespace detail {
class chunk_encode_test : public beast::unit_test::suite
{
public:
struct final_chunk
{
std::string s;
final_chunk() = default;
explicit
final_chunk(std::string s_)
: s(std::move(s_))
{
}
};
static
void
encode1(std::string& s, final_chunk const& fc)
{
using boost::asio::buffer;
if(! fc.s.empty())
s.append(to_string(
chunk_encode(buffer(fc.s.data(), fc.s.size()))));
s.append(to_string(chunk_encode_final()));
}
static
void
encode1(std::string& s, std::string const& piece)
{
using boost::asio::buffer;
s.append(to_string(
chunk_encode(buffer(piece.data(), piece.size()))));
}
static
inline
void
encode(std::string&)
{
}
template<class Arg, class... Args>
static
void
encode(std::string& s, Arg const& arg, Args const&... args)
{
encode1(s, arg);
encode(s, args...);
}
template<class... Args>
void
check(std::string const& answer, Args const&... args)
{
std::string s;
encode(s, args...);
expect(s == answer);
}
void run() override
{
check(
"0\r\n\r\n"
"0\r\n\r\n",
"", final_chunk{});
check(
"1\r\n"
"*\r\n"
"0\r\n\r\n",
final_chunk("*"));
check(
"2\r\n"
"**\r\n"
"0\r\n\r\n",
final_chunk("**"));
check(
"1\r\n"
"*\r\n"
"1\r\n"
"*\r\n"
"0\r\n\r\n",
"*", final_chunk("*"));
check(
"5\r\n"
"*****\r\n"
"7\r\n"
"*******\r\n"
"0\r\n\r\n",
"*****", final_chunk("*******"));
check(
"1\r\n"
"*\r\n"
"1\r\n"
"*\r\n"
"0\r\n\r\n",
"*", "*", final_chunk{});
check(
"4\r\n"
"****\r\n"
"0\r\n\r\n",
"****", final_chunk{});
}
};
BEAST_DEFINE_TESTSUITE(chunk_encode,http,beast);
} // detail
} // http
} // beast

View File

@@ -47,6 +47,7 @@ public:
check("http", parse_error::bad_on_headers_rv); check("http", parse_error::bad_on_headers_rv);
check("http", parse_error::invalid_chunk_size); check("http", parse_error::invalid_chunk_size);
check("http", parse_error::short_read); check("http", parse_error::short_read);
check("http", parse_error::general);
} }
}; };

View File

@@ -27,7 +27,8 @@ public:
{ {
static std::size_t constexpr limit = 100; static std::size_t constexpr limit = 100;
std::size_t n; std::size_t n;
for(n = 1; n < limit; ++n)
for(n = 0; n < limit; ++n)
{ {
streambuf sb; streambuf sb;
test::fail_stream<test::string_stream> fs(n, ios_, test::fail_stream<test::string_stream> fs(n, ios_,
@@ -48,7 +49,8 @@ public:
} }
} }
expect(n < limit); expect(n < limit);
for(n = 1; n < limit; ++n)
for(n = 0; n < limit; ++n)
{ {
streambuf sb; streambuf sb;
test::fail_stream<test::string_stream> fs(n, ios_, test::fail_stream<test::string_stream> fs(n, ios_,
@@ -65,11 +67,8 @@ public:
break; break;
} }
expect(n < limit); expect(n < limit);
ios_.post(
[&]{ for(n = 0; n < limit; ++n)
n = 1;
});
for(n = 1; n < limit; ++n)
{ {
streambuf sb; streambuf sb;
test::fail_stream<test::string_stream> fs(n, ios_, test::fail_stream<test::string_stream> fs(n, ios_,

View File

@@ -16,20 +16,40 @@
#include <beast/core/error.hpp> #include <beast/core/error.hpp>
#include <beast/core/streambuf.hpp> #include <beast/core/streambuf.hpp>
#include <beast/core/to_string.hpp> #include <beast/core/to_string.hpp>
#include <beast/test/fail_stream.hpp>
#include <beast/test/yield_to.hpp>
#include <beast/unit_test/suite.hpp> #include <beast/unit_test/suite.hpp>
#include <boost/asio/error.hpp> #include <boost/asio/error.hpp>
#include <sstream>
#include <string> #include <string>
namespace beast { namespace beast {
namespace http { namespace http {
class write_test : public beast::unit_test::suite class write_test
: public beast::unit_test::suite
, public test::enable_yield_to
{ {
public: public:
struct string_SyncStream class string_write_stream
{ {
boost::asio::io_service& ios_;
public:
std::string str; std::string str;
explicit
string_write_stream(boost::asio::io_service& ios)
: ios_(ios)
{
}
boost::asio::io_service&
get_io_service()
{
return ios_;
}
template<class ConstBufferSequence> template<class ConstBufferSequence>
std::size_t std::size_t
write_some(ConstBufferSequence const& buffers) write_some(ConstBufferSequence const& buffers)
@@ -42,7 +62,8 @@ public:
} }
template<class ConstBufferSequence> template<class ConstBufferSequence>
std::size_t write_some( std::size_t
write_some(
ConstBufferSequence const& buffers, error_code& ec) ConstBufferSequence const& buffers, error_code& ec)
{ {
auto const n = buffer_size(buffers); auto const n = buffer_size(buffers);
@@ -54,9 +75,25 @@ public:
buffer_size(buffer)); buffer_size(buffer));
return n; return n;
} }
template<class ConstBufferSequence, class WriteHandler>
typename async_completion<
WriteHandler, void(error_code)>::result_type
async_write_some(ConstBufferSequence const& buffers,
WriteHandler&& handler)
{
error_code ec;
auto const bytes_transferred = write_some(buffers, ec);
async_completion<
WriteHandler, void(error_code, std::size_t)
> completion(handler);
get_io_service().post(
bind_handler(completion.handler, ec, bytes_transferred));
return completion.result.get();
}
}; };
struct fail_body struct unsized_body
{ {
using value_type = std::string; using value_type = std::string;
@@ -64,6 +101,70 @@ public:
{ {
value_type const& body_; value_type const& body_;
public:
template<bool isRequest, class Allocator>
explicit
writer(message<isRequest, unsized_body, Allocator> const& msg)
: body_(msg.body)
{
}
void
init(error_code& ec)
{
}
template<class Write>
boost::tribool
operator()(resume_context&&, error_code&, Write&& write)
{
write(boost::asio::buffer(body_));
return true;
}
};
};
struct fail_body
{
class writer;
class value_type
{
friend class writer;
std::string s_;
test::fail_counter& fc_;
boost::asio::io_service& ios_;
public:
value_type(test::fail_counter& fc,
boost::asio::io_service& ios)
: fc_(fc)
, ios_(ios)
{
}
boost::asio::io_service&
get_io_service() const
{
return ios_;
}
value_type&
operator=(std::string s)
{
s_ = std::move(s);
return *this;
}
};
class writer
{
std::size_t n_ = 0;
value_type const& body_;
bool suspend_ = false;
enable_yield_to yt_;
public: public:
template<bool isRequest, class Allocator> template<bool isRequest, class Allocator>
explicit explicit
@@ -75,48 +176,44 @@ public:
void void
init(error_code& ec) init(error_code& ec)
{ {
ec = boost::system::errc::make_error_code( body_.fc_.fail(ec);
boost::system::errc::errc_t::invalid_argument);
} }
template<class Write> class do_resume
boost::tribool
operator()(resume_context&&, error_code&, Write&& write)
{ {
write(boost::asio::buffer(body_)); resume_context rc_;
return true;
}
};
};
struct test_body
{
using value_type = std::string;
class writer
{
std::size_t pos_ = 0;
value_type const& body_;
public: public:
template<bool isRequest, class Allocator>
explicit explicit
writer(message<isRequest, test_body, Allocator> const& msg) do_resume(resume_context&& rc)
: body_(msg.body) : rc_(std::move(rc))
{ {
} }
void void
init(error_code& ec) operator()()
{ {
rc_();
} }
};
template<class Write> template<class Write>
boost::tribool boost::tribool
operator()(resume_context&&, error_code&, Write&& write) operator()(resume_context&& rc, error_code& ec, Write&& write)
{ {
write(boost::asio::buffer(body_)); if(body_.fc_.fail(ec))
return false;
suspend_ = ! suspend_;
if(suspend_)
{
yt_.get_io_service().post(do_resume{std::move(rc)});
return boost::indeterminate;
}
if(n_ >= body_.s_.size())
return true; return true;
write(boost::asio::buffer(body_.s_.data() + n_, 1));
++n_;
return n_ == body_.s_.size();
} }
}; };
}; };
@@ -125,13 +222,228 @@ public:
std::string std::string
str(message_v1<isRequest, Body, Headers> const& m) str(message_v1<isRequest, Body, Headers> const& m)
{ {
string_SyncStream ss; string_write_stream ss(ios_);
write(ss, m); write(ss, m);
return ss.str; return ss.str;
} }
void void
testWrite() testAsyncWrite(yield_context do_yield)
{
{
message_v1<false, string_body, headers> m;
m.version = 10;
m.status = 200;
m.reason = "OK";
m.headers.insert("Server", "test");
m.headers.insert("Content-Length", "5");
m.body = "*****";
error_code ec;
string_write_stream ss(ios_);
async_write(ss, m, do_yield[ec]);
if(expect(! ec, ec.message()))
expect(ss.str ==
"HTTP/1.0 200 OK\r\n"
"Server: test\r\n"
"Content-Length: 5\r\n"
"\r\n"
"*****");
}
{
message_v1<false, string_body, headers> m;
m.version = 11;
m.status = 200;
m.reason = "OK";
m.headers.insert("Server", "test");
m.headers.insert("Transfer-Encoding", "chunked");
m.body = "*****";
error_code ec;
string_write_stream ss(ios_);
async_write(ss, m, do_yield[ec]);
if(expect(! ec, ec.message()))
expect(ss.str ==
"HTTP/1.1 200 OK\r\n"
"Server: test\r\n"
"Transfer-Encoding: chunked\r\n"
"\r\n"
"5\r\n"
"*****\r\n"
"0\r\n\r\n");
}
}
void
testFailures(yield_context do_yield)
{
static std::size_t constexpr limit = 100;
std::size_t n;
for(n = 0; n < limit; ++n)
{
test::fail_counter fc(n);
test::fail_stream<
string_write_stream> fs(fc, ios_);
message_v1<true, fail_body, headers> m(
std::piecewise_construct,
std::forward_as_tuple(fc, ios_));
m.method = "GET";
m.url = "/";
m.version = 10;
m.headers.insert("User-Agent", "test");
m.headers.insert("Content-Length", "5");
m.body = "*****";
try
{
write(fs, m);
expect(fs.next_layer().str ==
"GET / HTTP/1.0\r\n"
"User-Agent: test\r\n"
"Content-Length: 5\r\n"
"\r\n"
"*****"
);
pass();
break;
}
catch(std::exception const&)
{
}
}
expect(n < limit);
for(n = 0; n < limit; ++n)
{
test::fail_counter fc(n);
test::fail_stream<
string_write_stream> fs(fc, ios_);
message_v1<true, fail_body, headers> m(
std::piecewise_construct,
std::forward_as_tuple(fc, ios_));
m.method = "GET";
m.url = "/";
m.version = 10;
m.headers.insert("User-Agent", "test");
m.headers.insert("Transfer-Encoding", "chunked");
m.body = "*****";
error_code ec;
write(fs, m, ec);
if(ec == boost::asio::error::eof)
{
expect(fs.next_layer().str ==
"GET / HTTP/1.0\r\n"
"User-Agent: test\r\n"
"Transfer-Encoding: chunked\r\n"
"\r\n"
"1\r\n*\r\n"
"1\r\n*\r\n"
"1\r\n*\r\n"
"1\r\n*\r\n"
"1\r\n*\r\n"
"0\r\n\r\n"
);
break;
}
}
expect(n < limit);
for(n = 0; n < limit; ++n)
{
test::fail_counter fc(n);
test::fail_stream<
string_write_stream> fs(fc, ios_);
message_v1<true, fail_body, headers> m(
std::piecewise_construct,
std::forward_as_tuple(fc, ios_));
m.method = "GET";
m.url = "/";
m.version = 10;
m.headers.insert("User-Agent", "test");
m.headers.insert("Transfer-Encoding", "chunked");
m.body = "*****";
error_code ec;
async_write(fs, m, do_yield[ec]);
if(ec == boost::asio::error::eof)
{
expect(fs.next_layer().str ==
"GET / HTTP/1.0\r\n"
"User-Agent: test\r\n"
"Transfer-Encoding: chunked\r\n"
"\r\n"
"1\r\n*\r\n"
"1\r\n*\r\n"
"1\r\n*\r\n"
"1\r\n*\r\n"
"1\r\n*\r\n"
"0\r\n\r\n"
);
break;
}
}
expect(n < limit);
for(n = 0; n < limit; ++n)
{
test::fail_counter fc(n);
test::fail_stream<
string_write_stream> fs(fc, ios_);
message_v1<true, fail_body, headers> m(
std::piecewise_construct,
std::forward_as_tuple(fc, ios_));
m.method = "GET";
m.url = "/";
m.version = 10;
m.headers.insert("User-Agent", "test");
m.headers.insert("Content-Length", "5");
m.body = "*****";
error_code ec;
write(fs, m, ec);
if(! ec)
{
expect(fs.next_layer().str ==
"GET / HTTP/1.0\r\n"
"User-Agent: test\r\n"
"Content-Length: 5\r\n"
"\r\n"
"*****"
);
break;
}
}
expect(n < limit);
for(n = 0; n < limit; ++n)
{
test::fail_counter fc(n);
test::fail_stream<
string_write_stream> fs(fc, ios_);
message_v1<true, fail_body, headers> m(
std::piecewise_construct,
std::forward_as_tuple(fc, ios_));
m.method = "GET";
m.url = "/";
m.version = 10;
m.headers.insert("User-Agent", "test");
m.headers.insert("Content-Length", "5");
m.body = "*****";
error_code ec;
async_write(fs, m, do_yield[ec]);
if(! ec)
{
expect(fs.next_layer().str ==
"GET / HTTP/1.0\r\n"
"User-Agent: test\r\n"
"Content-Length: 5\r\n"
"\r\n"
"*****"
);
break;
}
}
expect(n < limit);
}
void
testOutput()
{ {
// auto content-length HTTP/1.0 // auto content-length HTTP/1.0
{ {
@@ -188,14 +500,14 @@ public:
} }
// no content-length HTTP/1.0 // no content-length HTTP/1.0
{ {
message_v1<true, test_body, headers> m; message_v1<true, unsized_body, headers> m;
m.method = "GET"; m.method = "GET";
m.url = "/"; m.url = "/";
m.version = 10; m.version = 10;
m.headers.insert("User-Agent", "test"); m.headers.insert("User-Agent", "test");
m.body = "*"; m.body = "*";
prepare(m); prepare(m);
string_SyncStream ss; string_write_stream ss(ios_);
error_code ec; error_code ec;
write(ss, m, ec); write(ss, m, ec);
expect(ec == boost::asio::error::eof); expect(ec == boost::asio::error::eof);
@@ -232,7 +544,7 @@ public:
m.headers.insert("User-Agent", "test"); m.headers.insert("User-Agent", "test");
m.body = "*"; m.body = "*";
prepare(m, connection::close); prepare(m, connection::close);
string_SyncStream ss; string_write_stream ss(ios_);
error_code ec; error_code ec;
write(ss, m, ec); write(ss, m, ec);
expect(ec == boost::asio::error::eof); expect(ec == boost::asio::error::eof);
@@ -262,14 +574,14 @@ public:
} }
// no content-length HTTP/1.1 // no content-length HTTP/1.1
{ {
message_v1<true, test_body, headers> m; message_v1<true, unsized_body, headers> m;
m.method = "GET"; m.method = "GET";
m.url = "/"; m.url = "/";
m.version = 11; m.version = 11;
m.headers.insert("User-Agent", "test"); m.headers.insert("User-Agent", "test");
m.body = "*"; m.body = "*";
prepare(m); prepare(m);
string_SyncStream ss; string_write_stream ss(ios_);
error_code ec; error_code ec;
write(ss, m, ec); write(ss, m, ec);
expect(ss.str == expect(ss.str ==
@@ -297,10 +609,38 @@ public:
"GET / HTTP/1.1\r\nUser-Agent: test\r\nContent-Length: 1\r\n\r\n*"); "GET / HTTP/1.1\r\nUser-Agent: test\r\nContent-Length: 1\r\n\r\n*");
} }
void testOstream()
{
message_v1<true, string_body, headers> m;
m.method = "GET";
m.url = "/";
m.version = 11;
m.headers.insert("User-Agent", "test");
m.body = "*";
prepare(m);
std::stringstream ss;
ss.setstate(ss.rdstate() |
std::stringstream::failbit);
try
{
ss << m;
fail();
}
catch(std::exception const&)
{
pass();
}
}
void run() override void run() override
{ {
testWrite(); yield_to(std::bind(&write_test::testAsyncWrite,
this, std::placeholders::_1));
yield_to(std::bind(&write_test::testFailures,
this, std::placeholders::_1));
testOutput();
testConvert(); testConvert();
testOstream();
} }
}; };

View File

@@ -154,6 +154,14 @@ public:
check(fh); check(fh);
fh.rsv1 = false; fh.rsv1 = false;
fh.rsv2 = true;
check(fh);
fh.rsv2 = false;
fh.rsv3 = true;
check(fh);
fh.rsv3 = false;
fh.op = opcode::rsv3; fh.op = opcode::rsv3;
check(fh); check(fh);
fh.op = opcode::text; fh.op = opcode::text;

View File

@@ -42,6 +42,7 @@ public:
check("websocket", error::request_malformed); check("websocket", error::request_malformed);
check("websocket", error::request_invalid); check("websocket", error::request_invalid);
check("websocket", error::request_denied); check("websocket", error::request_denied);
check("websocket", error::general);
} }
}; };

View File

@@ -33,6 +33,13 @@ public:
using address_type = boost::asio::ip::address; using address_type = boost::asio::ip::address;
using socket_type = boost::asio::ip::tcp::socket; using socket_type = boost::asio::ip::tcp::socket;
void testClamp()
{
expect(detail::clamp(
std::numeric_limits<std::uint64_t>::max()) ==
std::numeric_limits<std::size_t>::max());
}
void testSpecialMembers() void testSpecialMembers()
{ {
stream<socket_type> ws(ios_); stream<socket_type> ws(ios_);
@@ -304,7 +311,7 @@ public:
std::size_t n; std::size_t n;
// synchronous, exceptions // synchronous, exceptions
for(n = 1; n < limit; ++n) for(n = 0; n < limit; ++n)
{ {
error_code ec; error_code ec;
socket_type sock(ios_); socket_type sock(ios_);
@@ -343,7 +350,7 @@ public:
expect(n < limit); expect(n < limit);
// synchronous, error codes // synchronous, error codes
for(n = 1; n < limit; ++n) for(n = 0; n < limit; ++n)
{ {
error_code ec; error_code ec;
socket_type sock(ios_); socket_type sock(ios_);
@@ -378,7 +385,7 @@ public:
expect(n < limit); expect(n < limit);
// asynchronous // asynchronous
for(n = 1; n < limit; ++n) for(n = 0; n < limit; ++n)
{ {
error_code ec; error_code ec;
socket_type sock(ios_); socket_type sock(ios_);
@@ -470,8 +477,35 @@ public:
} }
} }
void testWriteFrame(endpoint_type const& ep)
{
for(;;)
{
boost::asio::io_service ios;
error_code ec;
socket_type sock(ios);
sock.connect(ep, ec);
if(! expect(! ec, ec.message()))
break;
stream<socket_type&> ws(sock);
ws.handshake("localhost", "/", ec);
if(! expect(! ec, ec.message()))
break;
ws.async_write_frame(false,
boost::asio::null_buffers{},
[](error_code){ });
//
// Destruction of the io_service will cause destruction
// of the write_frame_op without invoking the final handler.
//
break;
}
}
void run() override void run() override
{ {
testClamp();
testSpecialMembers(); testSpecialMembers();
testOptions(); testOptions();
@@ -483,33 +517,31 @@ public:
address_type::from_string("127.0.0.1"), 0}; address_type::from_string("127.0.0.1"), 0};
{ {
sync_echo_peer server(true, any); sync_echo_peer server(true, any);
auto const ep = server.local_endpoint();
yield_to(std::bind(&stream_test::testHandshake, yield_to(std::bind(&stream_test::testHandshake,
this, server.local_endpoint(), this, ep, std::placeholders::_1));
std::placeholders::_1));
yield_to(std::bind(&stream_test::testErrorHandling, yield_to(std::bind(&stream_test::testErrorHandling,
this, server.local_endpoint(), this, ep, std::placeholders::_1));
std::placeholders::_1));
yield_to(std::bind(&stream_test::testMask, yield_to(std::bind(&stream_test::testMask,
this, server.local_endpoint(), this, ep, std::placeholders::_1));
std::placeholders::_1));
testWriteFrame(ep);
} }
{ {
async_echo_peer server(true, any, 1); async_echo_peer server(true, any, 1);
auto const ep = server.local_endpoint();
yield_to(std::bind(&stream_test::testHandshake, yield_to(std::bind(&stream_test::testHandshake,
this, server.local_endpoint(), this, ep, std::placeholders::_1));
std::placeholders::_1));
yield_to(std::bind(&stream_test::testErrorHandling, yield_to(std::bind(&stream_test::testErrorHandling,
this, server.local_endpoint(), this, ep, std::placeholders::_1));
std::placeholders::_1));
yield_to(std::bind(&stream_test::testMask, yield_to(std::bind(&stream_test::testMask,
this, server.local_endpoint(), this, ep, std::placeholders::_1));
std::placeholders::_1));
} }
pass(); pass();

View File

@@ -1,21 +1,9 @@
//------------------------------------------------------------------------------ //
/* // Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
This file is part of Beast: https://github.com/vinniefalco/Beast //
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.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)
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_ASYNC_ECHO_PEER_H_INCLUDED #ifndef BEAST_WEBSOCKET_ASYNC_ECHO_PEER_H_INCLUDED
#define BEAST_WEBSOCKET_ASYNC_ECHO_PEER_H_INCLUDED #define BEAST_WEBSOCKET_ASYNC_ECHO_PEER_H_INCLUDED

View File

@@ -1,21 +1,9 @@
//------------------------------------------------------------------------------ //
/* // Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
This file is part of Beast: https://github.com/vinniefalco/Beast //
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.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)
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.
*/
//==============================================================================
#include "websocket_async_echo_peer.hpp" #include "websocket_async_echo_peer.hpp"
#include "websocket_sync_echo_peer.hpp" #include "websocket_sync_echo_peer.hpp"

View File

@@ -1,21 +1,9 @@
//------------------------------------------------------------------------------ //
/* // Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
This file is part of Beast: https://github.com/vinniefalco/Beast //
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.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)
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_SYNC_ECHO_PEER_H_INCLUDED #ifndef BEAST_WEBSOCKET_SYNC_ECHO_PEER_H_INCLUDED
#define BEAST_WEBSOCKET_SYNC_ECHO_PEER_H_INCLUDED #define BEAST_WEBSOCKET_SYNC_ECHO_PEER_H_INCLUDED