mirror of
https://github.com/boostorg/beast.git
synced 2025-07-30 21:07:26 +02:00
Refine FieldsReader concept (API Change)
* FieldsReader now requires chunked() and keep_alive() * serializer logic calls into the reader to calculate the message metadata * Removed some of the previous requirements of FieldsReader Actions Required: * Implement chunked() and keep_alive() for user defined FieldsReader types.
This commit is contained in:
@ -11,6 +11,7 @@ Version 62:
|
|||||||
API Changes:
|
API Changes:
|
||||||
|
|
||||||
* parser requires basic_fields
|
* parser requires basic_fields
|
||||||
|
* Refine FieldsReader concept
|
||||||
|
|
||||||
Actions Required:
|
Actions Required:
|
||||||
|
|
||||||
@ -18,6 +19,8 @@ Actions Required:
|
|||||||
will need to create their own subclass of basic_parser to work
|
will need to create their own subclass of basic_parser to work
|
||||||
with their custom fields type.
|
with their custom fields type.
|
||||||
|
|
||||||
|
* Implement chunked() and keep_alive() for user defined FieldsReader types.
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
Version 61:
|
Version 61:
|
||||||
|
@ -67,9 +67,10 @@ In this table:
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
Exemplar:
|
[heading Exemplar]
|
||||||
|
|
||||||
```
|
```
|
||||||
struct body
|
struct Body
|
||||||
{
|
{
|
||||||
using value_type = implementation_defined;
|
using value_type = implementation_defined;
|
||||||
|
|
||||||
|
@ -118,9 +118,10 @@ In this table:
|
|||||||
the implementation.
|
the implementation.
|
||||||
]
|
]
|
||||||
|
|
||||||
Exemplar:
|
[heading Exemplar]
|
||||||
|
|
||||||
```
|
```
|
||||||
struct reader
|
struct BodyReader
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/** Controls when the implementation requests buffers.
|
/** Controls when the implementation requests buffers.
|
||||||
@ -140,7 +141,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
template<bool isRequest, class Body, class Headers>
|
template<bool isRequest, class Body, class Headers>
|
||||||
explicit
|
explicit
|
||||||
reader(message<isRequest, Body, Headers> const& msg);
|
BodyReader(message<isRequest, Body, Headers> const& msg);
|
||||||
|
|
||||||
/** Initialization.
|
/** Initialization.
|
||||||
|
|
||||||
|
@ -94,9 +94,10 @@ In the table below:
|
|||||||
the implementation.
|
the implementation.
|
||||||
]
|
]
|
||||||
|
|
||||||
Exemplar:
|
[heading Exemplar]
|
||||||
|
|
||||||
```
|
```
|
||||||
struct writer
|
struct BodyWriter
|
||||||
{
|
{
|
||||||
/** Construct the writer.
|
/** Construct the writer.
|
||||||
|
|
||||||
@ -104,7 +105,7 @@ struct writer
|
|||||||
*/
|
*/
|
||||||
template<bool isRequest, class Body, class Fields>
|
template<bool isRequest, class Body, class Fields>
|
||||||
explicit
|
explicit
|
||||||
writer(message<isRequest, Body, Fields>& msg);
|
BodyWriter(message<isRequest, Body, Fields>& msg);
|
||||||
|
|
||||||
/** Initialization.
|
/** Initialization.
|
||||||
|
|
||||||
|
@ -33,24 +33,6 @@ In this table:
|
|||||||
[
|
[
|
||||||
A type which meets the requirements of __FieldsReader__.
|
A type which meets the requirements of __FieldsReader__.
|
||||||
]
|
]
|
||||||
][
|
|
||||||
[`c.has_close_impl()`]
|
|
||||||
[`bool`]
|
|
||||||
[
|
|
||||||
Returns `true` if the value for Connection has "close" in the list.
|
|
||||||
]
|
|
||||||
][
|
|
||||||
[`c.has_chunked_impl()`]
|
|
||||||
[`bool`]
|
|
||||||
[
|
|
||||||
Returns `true` if "chunked" is the last Transfer-Encoding.
|
|
||||||
]
|
|
||||||
][
|
|
||||||
[`c.has_content_length_impl()`]
|
|
||||||
[`bool`]
|
|
||||||
[
|
|
||||||
Returns `true` if the Content-Length field is present.
|
|
||||||
]
|
|
||||||
][
|
][
|
||||||
[`c.get_method_impl()`]
|
[`c.get_method_impl()`]
|
||||||
[`string_view`]
|
[`string_view`]
|
||||||
@ -109,4 +91,48 @@ In this table:
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[heading Exemplar]
|
||||||
|
|
||||||
|
```
|
||||||
|
class Fields
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
/** Set or clear the method string.
|
||||||
|
|
||||||
|
@note Only called for requests.
|
||||||
|
*/
|
||||||
|
void set_method_impl(string_view s);
|
||||||
|
|
||||||
|
/** Set or clear the target string.
|
||||||
|
|
||||||
|
@note Only called for requests.
|
||||||
|
*/
|
||||||
|
void set_target_impl(string_view s);
|
||||||
|
|
||||||
|
/** Set or clear the reason string.
|
||||||
|
|
||||||
|
@note Only called for responses.
|
||||||
|
*/
|
||||||
|
void set_reason_impl(string_view s);
|
||||||
|
|
||||||
|
/** Returns the request-method string.
|
||||||
|
|
||||||
|
@note Only called for requests.
|
||||||
|
*/
|
||||||
|
string_view get_method_impl() const;
|
||||||
|
|
||||||
|
/** Returns the request-target string.
|
||||||
|
|
||||||
|
@note Only called for requests.
|
||||||
|
*/
|
||||||
|
string_view get_target_impl() const;
|
||||||
|
|
||||||
|
/** Returns the response reason-phrase string.
|
||||||
|
|
||||||
|
@note Only called for responses.
|
||||||
|
*/
|
||||||
|
string_view get_reason_impl() const;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
@ -56,6 +56,27 @@ In this table:
|
|||||||
response. The lifetime of `f` is guaranteed
|
response. The lifetime of `f` is guaranteed
|
||||||
to end no earlier than after the `X` is destroyed.
|
to end no earlier than after the `X` is destroyed.
|
||||||
]
|
]
|
||||||
|
][
|
||||||
|
[`a.chunked()`]
|
||||||
|
[`bool`]
|
||||||
|
[
|
||||||
|
Called once after construction, this function returns `true`
|
||||||
|
if the [*Transfer-Encoding] field is present, and the last
|
||||||
|
token in its value is [*"chunked"].
|
||||||
|
]
|
||||||
|
][
|
||||||
|
[`a.keep_alive()`]
|
||||||
|
[`bool`]
|
||||||
|
[
|
||||||
|
Called once after construction, this function returns `true`
|
||||||
|
if the semantics of the mesage indicate that the connection
|
||||||
|
should remain open after processing the message. When the
|
||||||
|
HTTP version is below 1.1, `keep_alive` returns `true` when
|
||||||
|
the [*Connection] field is present, and its value contains the
|
||||||
|
"keep-alive" token. Otherwise, `keep_alive` returns `true`
|
||||||
|
when either the [*Connection] field is absent, or if the
|
||||||
|
value does not contain the "close" token.
|
||||||
|
]
|
||||||
][
|
][
|
||||||
[`a.get()`]
|
[`a.get()`]
|
||||||
[X::const_buffers_type]
|
[X::const_buffers_type]
|
||||||
@ -75,7 +96,8 @@ In this table:
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
Exemplar:
|
[heading Exemplar]
|
||||||
|
|
||||||
```
|
```
|
||||||
struct FieldsReader
|
struct FieldsReader
|
||||||
{
|
{
|
||||||
@ -88,6 +110,14 @@ struct FieldsReader
|
|||||||
// Constructor for responses
|
// Constructor for responses
|
||||||
FieldsReader(F const& f, unsigned version, unsigned status);
|
FieldsReader(F const& f, unsigned version, unsigned status);
|
||||||
|
|
||||||
|
// Returns `true` if the payload uses the chunked Transfer-Encoding
|
||||||
|
bool
|
||||||
|
chunked();
|
||||||
|
|
||||||
|
// Returns `true` if keep-alive is indicated
|
||||||
|
bool
|
||||||
|
keep_alive();
|
||||||
|
|
||||||
// Returns the serialized header buffers
|
// Returns the serialized header buffers
|
||||||
const_buffers_type
|
const_buffers_type
|
||||||
get();
|
get();
|
||||||
|
@ -555,15 +555,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// Returns `true` if the value for Connection has "close" in the list.
|
|
||||||
bool has_close_impl() const;
|
|
||||||
|
|
||||||
/// Returns `true` if "chunked" is the last Transfer-Encoding
|
|
||||||
bool has_chunked_impl() const;
|
|
||||||
|
|
||||||
/// Returns `true` if the Content-Length field is present
|
|
||||||
bool has_content_length_impl() const;
|
|
||||||
|
|
||||||
/** Set or clear the method string.
|
/** Set or clear the method string.
|
||||||
|
|
||||||
@note Only called for requests.
|
@note Only called for requests.
|
||||||
|
@ -132,6 +132,12 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool
|
||||||
|
get_chunked() const;
|
||||||
|
|
||||||
|
bool
|
||||||
|
get_keep_alive(int version) const;
|
||||||
|
|
||||||
template<class String>
|
template<class String>
|
||||||
void
|
void
|
||||||
prepare(String& s, basic_fields const& f,
|
prepare(String& s, basic_fields const& f,
|
||||||
@ -146,6 +152,8 @@ public:
|
|||||||
static_string<max_static_start_line> ss_;
|
static_string<max_static_start_line> ss_;
|
||||||
string_view sv_;
|
string_view sv_;
|
||||||
std::string s_;
|
std::string s_;
|
||||||
|
bool chunked_;
|
||||||
|
bool keep_alive_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using const_buffers_type =
|
using const_buffers_type =
|
||||||
@ -160,6 +168,18 @@ public:
|
|||||||
reader(basic_fields const& f,
|
reader(basic_fields const& f,
|
||||||
unsigned version, unsigned code);
|
unsigned version, unsigned code);
|
||||||
|
|
||||||
|
bool
|
||||||
|
chunked()
|
||||||
|
{
|
||||||
|
return chunked_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
keep_alive()
|
||||||
|
{
|
||||||
|
return keep_alive_;
|
||||||
|
}
|
||||||
|
|
||||||
const_buffers_type
|
const_buffers_type
|
||||||
get() const
|
get() const
|
||||||
{
|
{
|
||||||
@ -170,6 +190,41 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
bool
|
||||||
|
basic_fields<Allocator>::reader::
|
||||||
|
get_chunked() const
|
||||||
|
{
|
||||||
|
auto const te = token_list{
|
||||||
|
f_[field::transfer_encoding]};
|
||||||
|
for(auto it = te.begin(); it != te.end();)
|
||||||
|
{
|
||||||
|
auto next = std::next(it);
|
||||||
|
if(next == te.end())
|
||||||
|
return iequals(*it, "chunked");
|
||||||
|
it = next;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
bool
|
||||||
|
basic_fields<Allocator>::reader::
|
||||||
|
get_keep_alive(int version) const
|
||||||
|
{
|
||||||
|
if(version < 11)
|
||||||
|
{
|
||||||
|
auto const it = f_.find(field::connection);
|
||||||
|
if(it == f_.end())
|
||||||
|
return false;
|
||||||
|
return token_list{it->value()}.exists("keep-alive");
|
||||||
|
}
|
||||||
|
auto const it = f_.find(field::connection);
|
||||||
|
if(it == f_.end())
|
||||||
|
return true;
|
||||||
|
return ! token_list{it->value()}.exists("close");
|
||||||
|
}
|
||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
template<class String>
|
template<class String>
|
||||||
void
|
void
|
||||||
@ -258,6 +313,8 @@ basic_fields<Allocator>::reader::
|
|||||||
reader(basic_fields const& f,
|
reader(basic_fields const& f,
|
||||||
unsigned version, verb v)
|
unsigned version, verb v)
|
||||||
: f_(f)
|
: f_(f)
|
||||||
|
, chunked_(get_chunked())
|
||||||
|
, keep_alive_(get_keep_alive(version))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -276,6 +333,8 @@ basic_fields<Allocator>::reader::
|
|||||||
reader(basic_fields const& f,
|
reader(basic_fields const& f,
|
||||||
unsigned version, unsigned code)
|
unsigned version, unsigned code)
|
||||||
: f_(f)
|
: f_(f)
|
||||||
|
, chunked_(get_chunked())
|
||||||
|
, keep_alive_(get_keep_alive(version))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -753,49 +812,6 @@ equal_range(string_view name) const ->
|
|||||||
|
|
||||||
// Fields
|
// Fields
|
||||||
|
|
||||||
template<class Allocator>
|
|
||||||
bool
|
|
||||||
basic_fields<Allocator>::
|
|
||||||
has_close_impl() const
|
|
||||||
{
|
|
||||||
auto const fit = set_.find(
|
|
||||||
to_string(field::connection), key_compare{});
|
|
||||||
if(fit == set_.end())
|
|
||||||
return false;
|
|
||||||
return token_list{fit->value()}.exists("close");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Allocator>
|
|
||||||
bool
|
|
||||||
basic_fields<Allocator>::
|
|
||||||
has_chunked_impl() const
|
|
||||||
{
|
|
||||||
auto const fit = set_.find(to_string(
|
|
||||||
field::transfer_encoding), key_compare{});
|
|
||||||
if(fit == set_.end())
|
|
||||||
return false;
|
|
||||||
token_list const v{fit->value()};
|
|
||||||
auto it = v.begin();
|
|
||||||
if(it == v.end())
|
|
||||||
return false;
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
auto cur = it++;
|
|
||||||
if(it == v.end())
|
|
||||||
return iequals(*cur, "chunked");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Allocator>
|
|
||||||
bool
|
|
||||||
basic_fields<Allocator>::
|
|
||||||
has_content_length_impl() const
|
|
||||||
{
|
|
||||||
auto const fit = set_.find(
|
|
||||||
to_string(field::content_length), key_compare{});
|
|
||||||
return fit != set_.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
inline
|
inline
|
||||||
void
|
void
|
||||||
|
@ -249,33 +249,6 @@ message(std::piecewise_construct_t,
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template<bool isRequest, class Body, class Fields>
|
|
||||||
inline
|
|
||||||
bool
|
|
||||||
message<isRequest, Body, Fields>::
|
|
||||||
has_close() const
|
|
||||||
{
|
|
||||||
return this->has_close_impl();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<bool isRequest, class Body, class Fields>
|
|
||||||
inline
|
|
||||||
bool
|
|
||||||
message<isRequest, Body, Fields>::
|
|
||||||
has_chunked() const
|
|
||||||
{
|
|
||||||
return this->has_chunked_impl();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<bool isRequest, class Body, class Fields>
|
|
||||||
inline
|
|
||||||
bool
|
|
||||||
message<isRequest, Body, Fields>::
|
|
||||||
has_content_length() const
|
|
||||||
{
|
|
||||||
return this->has_content_length_impl();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<bool isRequest, class Body, class Fields>
|
template<bool isRequest, class Body, class Fields>
|
||||||
boost::optional<std::uint64_t>
|
boost::optional<std::uint64_t>
|
||||||
message<isRequest, Body, Fields>::
|
message<isRequest, Body, Fields>::
|
||||||
|
@ -59,10 +59,8 @@ get(error_code& ec, Visit&& visit)
|
|||||||
{
|
{
|
||||||
frdinit(std::integral_constant<bool,
|
frdinit(std::integral_constant<bool,
|
||||||
isRequest>{});
|
isRequest>{});
|
||||||
close_ = m_.has_close() || (
|
close_ = ! frd_->keep_alive();
|
||||||
m_.version < 11 &&
|
if(frd_->chunked())
|
||||||
! m_.has_content_length());
|
|
||||||
if(m_.has_chunked())
|
|
||||||
goto go_init_c;
|
goto go_init_c;
|
||||||
s_ = do_init;
|
s_ = do_init;
|
||||||
BOOST_FALLTHROUGH;
|
BOOST_FALLTHROUGH;
|
||||||
|
@ -483,24 +483,6 @@ struct message : header<isRequest, Fields>
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if "close" is specified in the Connection field.
|
|
||||||
bool
|
|
||||||
has_close() const;
|
|
||||||
|
|
||||||
/// Returns `true` if "chunked" is the last Transfer-Encoding.
|
|
||||||
bool
|
|
||||||
has_chunked() const;
|
|
||||||
|
|
||||||
/** Returns `true` if the Content-Length field is present.
|
|
||||||
|
|
||||||
This function checks the fields to determine if the content
|
|
||||||
length field is present, regardless of the actual value.
|
|
||||||
|
|
||||||
@note The contents of the body payload are not inspected.
|
|
||||||
*/
|
|
||||||
bool
|
|
||||||
has_content_length() const;
|
|
||||||
|
|
||||||
/** Returns the payload size of the body in octets if possible.
|
/** Returns the payload size of the body in octets if possible.
|
||||||
|
|
||||||
This function invokes the @b Body algorithm to measure
|
This function invokes the @b Body algorithm to measure
|
||||||
|
@ -303,7 +303,10 @@ public:
|
|||||||
str(message<isRequest, Body, Fields> const& m)
|
str(message<isRequest, Body, Fields> const& m)
|
||||||
{
|
{
|
||||||
test::string_ostream ss(ios_);
|
test::string_ostream ss(ios_);
|
||||||
write(ss, m);
|
error_code ec;
|
||||||
|
write(ss, m, ec);
|
||||||
|
if(ec && ec != error::end_of_stream)
|
||||||
|
BOOST_THROW_EXCEPTION(system_error{ec});
|
||||||
return ss.str;
|
return ss.str;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -321,7 +324,7 @@ public:
|
|||||||
error_code ec;
|
error_code ec;
|
||||||
test::string_ostream ss{ios_};
|
test::string_ostream ss{ios_};
|
||||||
async_write(ss, m, do_yield[ec]);
|
async_write(ss, m, do_yield[ec]);
|
||||||
if(BEAST_EXPECTS(! ec, ec.message()))
|
if(BEAST_EXPECTS(ec == error::end_of_stream, ec.message()))
|
||||||
BEAST_EXPECT(ss.str ==
|
BEAST_EXPECT(ss.str ==
|
||||||
"HTTP/1.0 200 OK\r\n"
|
"HTTP/1.0 200 OK\r\n"
|
||||||
"Server: test\r\n"
|
"Server: test\r\n"
|
||||||
@ -368,7 +371,8 @@ public:
|
|||||||
m.target("/");
|
m.target("/");
|
||||||
m.version = 10;
|
m.version = 10;
|
||||||
m.insert(field::user_agent, "test");
|
m.insert(field::user_agent, "test");
|
||||||
m.insert("Content-Length", "5");
|
m.set(field::connection, "keep-alive");
|
||||||
|
m.set(field::content_length, "5");
|
||||||
m.body = "*****";
|
m.body = "*****";
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -376,6 +380,7 @@ public:
|
|||||||
BEAST_EXPECT(fs.next_layer().str ==
|
BEAST_EXPECT(fs.next_layer().str ==
|
||||||
"GET / HTTP/1.0\r\n"
|
"GET / HTTP/1.0\r\n"
|
||||||
"User-Agent: test\r\n"
|
"User-Agent: test\r\n"
|
||||||
|
"Connection: keep-alive\r\n"
|
||||||
"Content-Length: 5\r\n"
|
"Content-Length: 5\r\n"
|
||||||
"\r\n"
|
"\r\n"
|
||||||
"*****"
|
"*****"
|
||||||
@ -465,7 +470,8 @@ public:
|
|||||||
m.target("/");
|
m.target("/");
|
||||||
m.version = 10;
|
m.version = 10;
|
||||||
m.insert(field::user_agent, "test");
|
m.insert(field::user_agent, "test");
|
||||||
m.insert("Content-Length", "5");
|
m.set(field::connection, "keep-alive");
|
||||||
|
m.set(field::content_length, "5");
|
||||||
m.body = "*****";
|
m.body = "*****";
|
||||||
error_code ec = test::error::fail_error;
|
error_code ec = test::error::fail_error;
|
||||||
write(fs, m, ec);
|
write(fs, m, ec);
|
||||||
@ -474,6 +480,7 @@ public:
|
|||||||
BEAST_EXPECT(fs.next_layer().str ==
|
BEAST_EXPECT(fs.next_layer().str ==
|
||||||
"GET / HTTP/1.0\r\n"
|
"GET / HTTP/1.0\r\n"
|
||||||
"User-Agent: test\r\n"
|
"User-Agent: test\r\n"
|
||||||
|
"Connection: keep-alive\r\n"
|
||||||
"Content-Length: 5\r\n"
|
"Content-Length: 5\r\n"
|
||||||
"\r\n"
|
"\r\n"
|
||||||
"*****"
|
"*****"
|
||||||
@ -493,7 +500,8 @@ public:
|
|||||||
m.target("/");
|
m.target("/");
|
||||||
m.version = 10;
|
m.version = 10;
|
||||||
m.insert(field::user_agent, "test");
|
m.insert(field::user_agent, "test");
|
||||||
m.insert("Content-Length", "5");
|
m.set(field::connection, "keep-alive");
|
||||||
|
m.set(field::content_length, "5");
|
||||||
m.body = "*****";
|
m.body = "*****";
|
||||||
error_code ec = test::error::fail_error;
|
error_code ec = test::error::fail_error;
|
||||||
async_write(fs, m, do_yield[ec]);
|
async_write(fs, m, do_yield[ec]);
|
||||||
@ -502,6 +510,7 @@ public:
|
|||||||
BEAST_EXPECT(fs.next_layer().str ==
|
BEAST_EXPECT(fs.next_layer().str ==
|
||||||
"GET / HTTP/1.0\r\n"
|
"GET / HTTP/1.0\r\n"
|
||||||
"User-Agent: test\r\n"
|
"User-Agent: test\r\n"
|
||||||
|
"Connection: keep-alive\r\n"
|
||||||
"Content-Length: 5\r\n"
|
"Content-Length: 5\r\n"
|
||||||
"\r\n"
|
"\r\n"
|
||||||
"*****"
|
"*****"
|
||||||
@ -858,10 +867,8 @@ public:
|
|||||||
|
|
||||||
void run() override
|
void run() override
|
||||||
{
|
{
|
||||||
yield_to([&](yield_context yield){
|
yield_to([&](yield_context yield){ testAsyncWrite(yield); });
|
||||||
testAsyncWrite(yield); });
|
yield_to([&](yield_context yield){ testFailures(yield); });
|
||||||
yield_to([&](yield_context yield){
|
|
||||||
testFailures(yield); });
|
|
||||||
testOutput();
|
testOutput();
|
||||||
test_std_ostream();
|
test_std_ostream();
|
||||||
testIoService();
|
testIoService();
|
||||||
|
@ -1004,7 +1004,7 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
// wrong version
|
// wrong version
|
||||||
check(error::handshake_failed,
|
check(http::error::end_of_stream,
|
||||||
"GET / HTTP/1.0\r\n"
|
"GET / HTTP/1.0\r\n"
|
||||||
"Host: localhost:80\r\n"
|
"Host: localhost:80\r\n"
|
||||||
"Upgrade: WebSocket\r\n"
|
"Upgrade: WebSocket\r\n"
|
||||||
|
Reference in New Issue
Block a user