mirror of
https://github.com/CrowCpp/Crow.git
synced 2024-06-07 21:10:44 +00:00
Merge branch 'master' into static_dir
This commit is contained in:
commit
50670c290b
4
Doxyfile
4
Doxyfile
@ -38,13 +38,13 @@ PROJECT_NAME = Crow
|
|||||||
# could be handy for archiving the generated documentation or if some version
|
# could be handy for archiving the generated documentation or if some version
|
||||||
# control system is used.
|
# control system is used.
|
||||||
|
|
||||||
PROJECT_NUMBER = 0.1
|
PROJECT_NUMBER = 0.2
|
||||||
|
|
||||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||||
# for a project that appears at the top of each page and should give viewer a
|
# for a project that appears at the top of each page and should give viewer a
|
||||||
# quick idea about the purpose of the project. Keep the description short.
|
# quick idea about the purpose of the project. Keep the description short.
|
||||||
|
|
||||||
PROJECT_BRIEF = "C++ microframework for the web"
|
PROJECT_BRIEF = "A C++ microframework for the web"
|
||||||
|
|
||||||
# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
|
# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
|
||||||
# in the documentation. The maximum height of the logo should not exceed 55
|
# in the documentation. The maximum height of the logo should not exceed 55
|
||||||
|
@ -121,12 +121,12 @@ namespace crow
|
|||||||
///Set the server's log level
|
///Set the server's log level
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Possible values are:
|
/// Possible values are:<br>
|
||||||
/// crow::LogLevel::Debug (0)
|
/// crow::LogLevel::Debug (0)<br>
|
||||||
/// crow::LogLevel::Info (1)
|
/// crow::LogLevel::Info (1)<br>
|
||||||
/// crow::LogLevel::Warning (2)
|
/// crow::LogLevel::Warning (2)<br>
|
||||||
/// crow::LogLevel::Error (3)
|
/// crow::LogLevel::Error (3)<br>
|
||||||
/// crow::LogLevel::Critical (4)
|
/// crow::LogLevel::Critical (4)<br>
|
||||||
self_t& loglevel(crow::LogLevel level)
|
self_t& loglevel(crow::LogLevel level)
|
||||||
{
|
{
|
||||||
crow::logger::setLogLevel(level);
|
crow::logger::setLogLevel(level);
|
||||||
|
@ -108,31 +108,43 @@ namespace crow
|
|||||||
|
|
||||||
bool is_open()
|
bool is_open()
|
||||||
{
|
{
|
||||||
return raw_socket().is_open();
|
return ssl_socket_ ? raw_socket().is_open() : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void close()
|
void close()
|
||||||
{
|
{
|
||||||
boost::system::error_code ec;
|
if (is_open())
|
||||||
raw_socket().close(ec);
|
{
|
||||||
|
boost::system::error_code ec;
|
||||||
|
raw_socket().close(ec);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void shutdown_readwrite()
|
void shutdown_readwrite()
|
||||||
{
|
{
|
||||||
boost::system::error_code ec;
|
if (is_open())
|
||||||
raw_socket().shutdown(boost::asio::socket_base::shutdown_type::shutdown_both, ec);
|
{
|
||||||
|
boost::system::error_code ec;
|
||||||
|
raw_socket().shutdown(boost::asio::socket_base::shutdown_type::shutdown_both, ec);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void shutdown_write()
|
void shutdown_write()
|
||||||
{
|
{
|
||||||
boost::system::error_code ec;
|
if (is_open())
|
||||||
raw_socket().shutdown(boost::asio::socket_base::shutdown_type::shutdown_send, ec);
|
{
|
||||||
|
boost::system::error_code ec;
|
||||||
|
raw_socket().shutdown(boost::asio::socket_base::shutdown_type::shutdown_send, ec);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void shutdown_read()
|
void shutdown_read()
|
||||||
{
|
{
|
||||||
boost::system::error_code ec;
|
if (is_open())
|
||||||
raw_socket().shutdown(boost::asio::socket_base::shutdown_type::shutdown_receive, ec);
|
{
|
||||||
|
boost::system::error_code ec;
|
||||||
|
raw_socket().shutdown(boost::asio::socket_base::shutdown_type::shutdown_receive, ec);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::asio::io_service& get_io_service()
|
boost::asio::io_service& get_io_service()
|
||||||
|
@ -18,10 +18,13 @@ namespace crow
|
|||||||
Payload,
|
Payload,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
///A base class for websocket connection.
|
||||||
struct connection
|
struct connection
|
||||||
{
|
{
|
||||||
virtual void send_binary(const std::string& msg) = 0;
|
virtual void send_binary(const std::string& msg) = 0;
|
||||||
virtual void send_text(const std::string& msg) = 0;
|
virtual void send_text(const std::string& msg) = 0;
|
||||||
|
virtual void send_ping(const std::string& msg) = 0;
|
||||||
|
virtual void send_pong(const std::string& msg) = 0;
|
||||||
virtual void close(const std::string& msg = "quit") = 0;
|
virtual void close(const std::string& msg = "quit") = 0;
|
||||||
virtual ~connection(){}
|
virtual ~connection(){}
|
||||||
|
|
||||||
@ -32,10 +35,35 @@ namespace crow
|
|||||||
void* userdata_;
|
void* userdata_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 0 1 2 3 -byte
|
||||||
|
// 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 -bit
|
||||||
|
// +-+-+-+-+-------+-+-------------+-------------------------------+
|
||||||
|
// |F|R|R|R| opcode|M| Payload len | Extended payload length |
|
||||||
|
// |I|S|S|S| (4) |A| (7) | (16/64) |
|
||||||
|
// |N|V|V|V| |S| | (if payload len==126/127) |
|
||||||
|
// | |1|2|3| |K| | |
|
||||||
|
// +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
|
||||||
|
// | Extended payload length continued, if payload len == 127 |
|
||||||
|
// + - - - - - - - - - - - - - - - +-------------------------------+
|
||||||
|
// | |Masking-key, if MASK set to 1 |
|
||||||
|
// +-------------------------------+-------------------------------+
|
||||||
|
// | Masking-key (continued) | Payload Data |
|
||||||
|
// +-------------------------------- - - - - - - - - - - - - - - - +
|
||||||
|
// : Payload Data continued ... :
|
||||||
|
// + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
|
||||||
|
// | Payload Data continued ... |
|
||||||
|
// +---------------------------------------------------------------+
|
||||||
|
|
||||||
|
/// A websocket connection.
|
||||||
template <typename Adaptor>
|
template <typename Adaptor>
|
||||||
class Connection : public connection
|
class Connection : public connection
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/// Constructor for a connection.
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Requires a request with an "Upgrade: websocket" header.<br>
|
||||||
|
/// Automatically handles the handshake.
|
||||||
Connection(const crow::request& req, Adaptor&& adaptor,
|
Connection(const crow::request& req, Adaptor&& adaptor,
|
||||||
std::function<void(crow::websocket::connection&)> open_handler,
|
std::function<void(crow::websocket::connection&)> open_handler,
|
||||||
std::function<void(crow::websocket::connection&, const std::string&, bool)> message_handler,
|
std::function<void(crow::websocket::connection&, const std::string&, bool)> message_handler,
|
||||||
@ -72,29 +100,49 @@ namespace crow
|
|||||||
start(crow::utility::base64encode((char*)digest, 20));
|
start(crow::utility::base64encode((char*)digest, 20));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Send data through the socket.
|
||||||
template<typename CompletionHandler>
|
template<typename CompletionHandler>
|
||||||
void dispatch(CompletionHandler handler)
|
void dispatch(CompletionHandler handler)
|
||||||
{
|
{
|
||||||
adaptor_.get_io_service().dispatch(handler);
|
adaptor_.get_io_service().dispatch(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Send data through the socket and return immediately.
|
||||||
template<typename CompletionHandler>
|
template<typename CompletionHandler>
|
||||||
void post(CompletionHandler handler)
|
void post(CompletionHandler handler)
|
||||||
{
|
{
|
||||||
adaptor_.get_io_service().post(handler);
|
adaptor_.get_io_service().post(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
void send_pong(const std::string& msg)
|
/// Send a "Ping" message.
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Usually invoked to check if the other point is still online.
|
||||||
|
void send_ping(const std::string& msg) override
|
||||||
{
|
{
|
||||||
dispatch([this, msg]{
|
dispatch([this, msg]{
|
||||||
char buf[3] = "\x8A\x00";
|
auto header = build_header(0x9, msg.size());
|
||||||
buf[1] += msg.size();
|
write_buffers_.emplace_back(std::move(header));
|
||||||
write_buffers_.emplace_back(buf, buf+2);
|
|
||||||
write_buffers_.emplace_back(msg);
|
write_buffers_.emplace_back(msg);
|
||||||
do_write();
|
do_write();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Send a "Pong" message.
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Usually automatically invoked as a response to a "Ping" message.
|
||||||
|
void send_pong(const std::string& msg) override
|
||||||
|
{
|
||||||
|
dispatch([this, msg]{
|
||||||
|
auto header = build_header(0xA, msg.size());
|
||||||
|
write_buffers_.emplace_back(std::move(header));
|
||||||
|
write_buffers_.emplace_back(msg);
|
||||||
|
do_write();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Send a binary encoded message.
|
||||||
void send_binary(const std::string& msg) override
|
void send_binary(const std::string& msg) override
|
||||||
{
|
{
|
||||||
dispatch([this, msg]{
|
dispatch([this, msg]{
|
||||||
@ -105,6 +153,7 @@ namespace crow
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Send a plaintext message.
|
||||||
void send_text(const std::string& msg) override
|
void send_text(const std::string& msg) override
|
||||||
{
|
{
|
||||||
dispatch([this, msg]{
|
dispatch([this, msg]{
|
||||||
@ -115,6 +164,10 @@ namespace crow
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Send a close signal.
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Sets a flag to destroy the object once the message is sent.
|
||||||
void close(const std::string& msg) override
|
void close(const std::string& msg) override
|
||||||
{
|
{
|
||||||
dispatch([this, msg]{
|
dispatch([this, msg]{
|
||||||
@ -134,6 +187,7 @@ namespace crow
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
/// Generate the websocket headers using an opcode and the message size (in bytes).
|
||||||
std::string build_header(int opcode, size_t size)
|
std::string build_header(int opcode, size_t size)
|
||||||
{
|
{
|
||||||
char buf[2+8] = "\x80\x00";
|
char buf[2+8] = "\x80\x00";
|
||||||
@ -157,6 +211,10 @@ namespace crow
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Send the HTTP upgrade response.
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Finishes the handshake process, then starts reading messages from the socket.
|
||||||
void start(std::string&& hello)
|
void start(std::string&& hello)
|
||||||
{
|
{
|
||||||
static std::string header = "HTTP/1.1 101 Switching Protocols\r\n"
|
static std::string header = "HTTP/1.1 101 Switching Protocols\r\n"
|
||||||
@ -174,6 +232,13 @@ namespace crow
|
|||||||
do_read();
|
do_read();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Read a websocket message.
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Involves:<br>
|
||||||
|
/// Handling headers (opcodes, size).<br>
|
||||||
|
/// Unmasking the payload.<br>
|
||||||
|
/// Reading the actual payload.<br>
|
||||||
void do_read()
|
void do_read()
|
||||||
{
|
{
|
||||||
is_reading = true;
|
is_reading = true;
|
||||||
@ -181,6 +246,7 @@ namespace crow
|
|||||||
{
|
{
|
||||||
case WebSocketReadState::MiniHeader:
|
case WebSocketReadState::MiniHeader:
|
||||||
{
|
{
|
||||||
|
mini_header_ = 0;
|
||||||
//boost::asio::async_read(adaptor_.socket(), boost::asio::buffer(&mini_header_, 1),
|
//boost::asio::async_read(adaptor_.socket(), boost::asio::buffer(&mini_header_, 1),
|
||||||
adaptor_.socket().async_read_some(boost::asio::buffer(&mini_header_, 2),
|
adaptor_.socket().async_read_some(boost::asio::buffer(&mini_header_, 2),
|
||||||
[this](const boost::system::error_code& ec, std::size_t
|
[this](const boost::system::error_code& ec, std::size_t
|
||||||
@ -200,8 +266,11 @@ namespace crow
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!ec && ((mini_header_ & 0x80) == 0x80))
|
if (!ec)
|
||||||
{
|
{
|
||||||
|
if ((mini_header_ & 0x80) == 0x80)
|
||||||
|
has_mask_ = true;
|
||||||
|
|
||||||
if ((mini_header_ & 0x7f) == 127)
|
if ((mini_header_ & 0x7f) == 127)
|
||||||
{
|
{
|
||||||
state_ = WebSocketReadState::Len64;
|
state_ = WebSocketReadState::Len64;
|
||||||
@ -300,34 +369,42 @@ namespace crow
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case WebSocketReadState::Mask:
|
case WebSocketReadState::Mask:
|
||||||
boost::asio::async_read(adaptor_.socket(), boost::asio::buffer((char*)&mask_, 4),
|
if (has_mask_)
|
||||||
[this](const boost::system::error_code& ec, std::size_t
|
{
|
||||||
|
boost::asio::async_read(adaptor_.socket(), boost::asio::buffer((char*)&mask_, 4),
|
||||||
|
[this](const boost::system::error_code& ec, std::size_t
|
||||||
#ifdef CROW_ENABLE_DEBUG
|
#ifdef CROW_ENABLE_DEBUG
|
||||||
bytes_transferred
|
bytes_transferred
|
||||||
#endif
|
#endif
|
||||||
)
|
)
|
||||||
{
|
|
||||||
is_reading = false;
|
|
||||||
#ifdef CROW_ENABLE_DEBUG
|
|
||||||
if (!ec && bytes_transferred != 4)
|
|
||||||
{
|
{
|
||||||
throw std::runtime_error("WebSocket:Mask:async_read fail:asio bug?");
|
is_reading = false;
|
||||||
}
|
#ifdef CROW_ENABLE_DEBUG
|
||||||
|
if (!ec && bytes_transferred != 4)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("WebSocket:Mask:async_read fail:asio bug?");
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!ec)
|
if (!ec)
|
||||||
{
|
{
|
||||||
state_ = WebSocketReadState::Payload;
|
state_ = WebSocketReadState::Payload;
|
||||||
do_read();
|
do_read();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
close_connection_ = true;
|
close_connection_ = true;
|
||||||
if (error_handler_)
|
if (error_handler_)
|
||||||
error_handler_(*this);
|
error_handler_(*this);
|
||||||
adaptor_.close();
|
adaptor_.close();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
state_ = WebSocketReadState::Payload;
|
||||||
|
do_read();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case WebSocketReadState::Payload:
|
case WebSocketReadState::Payload:
|
||||||
{
|
{
|
||||||
@ -365,21 +442,30 @@ namespace crow
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if the FIN bit is set.
|
||||||
bool is_FIN()
|
bool is_FIN()
|
||||||
{
|
{
|
||||||
return mini_header_ & 0x8000;
|
return mini_header_ & 0x8000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extract the opcode from the header.
|
||||||
int opcode()
|
int opcode()
|
||||||
{
|
{
|
||||||
return (mini_header_ & 0x0f00) >> 8;
|
return (mini_header_ & 0x0f00) >> 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Process the payload fragment.
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Unmasks the fragment, checks the opcode, merges fragments into 1 message body, and calls the appropriate handler.
|
||||||
void handle_fragment()
|
void handle_fragment()
|
||||||
{
|
{
|
||||||
for(decltype(fragment_.length()) i = 0; i < fragment_.length(); i ++)
|
if (has_mask_)
|
||||||
{
|
{
|
||||||
fragment_[i] ^= ((char*)&mask_)[i%4];
|
for(decltype(fragment_.length()) i = 0; i < fragment_.length(); i ++)
|
||||||
|
{
|
||||||
|
fragment_[i] ^= ((char*)&mask_)[i%4];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
switch(opcode())
|
switch(opcode())
|
||||||
{
|
{
|
||||||
@ -454,6 +540,10 @@ namespace crow
|
|||||||
fragment_.clear();
|
fragment_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Send the buffers' data through the socket.
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Also destroyes the object if the Close flag is set.
|
||||||
void do_write()
|
void do_write()
|
||||||
{
|
{
|
||||||
if (sending_buffers_.empty())
|
if (sending_buffers_.empty())
|
||||||
@ -485,6 +575,7 @@ namespace crow
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Destroy the Connection.
|
||||||
void check_destroy()
|
void check_destroy()
|
||||||
{
|
{
|
||||||
//if (has_sent_close_ && has_recv_close_)
|
//if (has_sent_close_ && has_recv_close_)
|
||||||
@ -509,6 +600,7 @@ namespace crow
|
|||||||
uint64_t remaining_length_{0};
|
uint64_t remaining_length_{0};
|
||||||
bool close_connection_{false};
|
bool close_connection_{false};
|
||||||
bool is_reading{false};
|
bool is_reading{false};
|
||||||
|
bool has_mask_{false};
|
||||||
uint32_t mask_;
|
uint32_t mask_;
|
||||||
uint16_t mini_header_;
|
uint16_t mini_header_;
|
||||||
bool has_sent_close_{false};
|
bool has_sent_close_{false};
|
||||||
|
@ -1371,3 +1371,137 @@ TEST_CASE("stream_response")
|
|||||||
});
|
});
|
||||||
runTest.join();
|
runTest.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("websocket")
|
||||||
|
{
|
||||||
|
static std::string http_message = "GET /ws HTTP/1.1\r\nConnection: keep-alive, Upgrade\r\nupgrade: websocket\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\nSec-WebSocket-Version: 13\r\n\r\n";
|
||||||
|
|
||||||
|
static bool connected{false};
|
||||||
|
|
||||||
|
SimpleApp app;
|
||||||
|
|
||||||
|
CROW_ROUTE(app, "/ws").websocket()
|
||||||
|
.onopen([&](websocket::connection&){
|
||||||
|
connected = true;
|
||||||
|
CROW_LOG_INFO << "Connected websocket and value is " << connected;
|
||||||
|
})
|
||||||
|
.onmessage([&](websocket::connection& conn, const std::string& message, bool isbin){
|
||||||
|
CROW_LOG_INFO << "Message is \"" << message << '\"';
|
||||||
|
if (!isbin && message == "PINGME")
|
||||||
|
conn.send_ping("");
|
||||||
|
else if (!isbin && message == "Hello")
|
||||||
|
conn.send_text("Hello back");
|
||||||
|
else if (isbin && message == "Hello bin")
|
||||||
|
conn.send_binary("Hello back bin");
|
||||||
|
})
|
||||||
|
.onclose([&](websocket::connection&, const std::string&){
|
||||||
|
CROW_LOG_INFO << "Closing websocket";
|
||||||
|
});
|
||||||
|
|
||||||
|
app.validate();
|
||||||
|
|
||||||
|
auto _ = async(launch::async,
|
||||||
|
[&] { app.bindaddr(LOCALHOST_ADDRESS).port(45451).run(); });
|
||||||
|
app.wait_for_server_start();
|
||||||
|
asio::io_service is;
|
||||||
|
|
||||||
|
asio::ip::tcp::socket c(is);
|
||||||
|
c.connect(asio::ip::tcp::endpoint(
|
||||||
|
asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
|
||||||
|
|
||||||
|
|
||||||
|
char buf[2048];
|
||||||
|
|
||||||
|
//----------Handshake----------
|
||||||
|
{
|
||||||
|
std::fill_n (buf, 2048, 0);
|
||||||
|
c.send(asio::buffer(http_message));
|
||||||
|
|
||||||
|
c.receive(asio::buffer(buf, 2048));
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||||
|
CHECK(connected);
|
||||||
|
}
|
||||||
|
//----------Pong----------
|
||||||
|
{
|
||||||
|
std::fill_n (buf, 2048, 0);
|
||||||
|
char ping_message[2]("\x89");
|
||||||
|
|
||||||
|
c.send(asio::buffer(ping_message, 2));
|
||||||
|
c.receive(asio::buffer(buf, 2048));
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||||
|
CHECK((int)(unsigned char)buf[0] == 0x8A);
|
||||||
|
}
|
||||||
|
//----------Ping----------
|
||||||
|
{
|
||||||
|
std::fill_n (buf, 2048, 0);
|
||||||
|
char not_ping_message[2+6+1]("\x81\x06"
|
||||||
|
"PINGME");
|
||||||
|
|
||||||
|
c.send(asio::buffer(not_ping_message, 8));
|
||||||
|
c.receive(asio::buffer(buf, 2048));
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||||
|
CHECK((int)(unsigned char)buf[0] == 0x89);
|
||||||
|
}
|
||||||
|
//----------Text----------
|
||||||
|
{
|
||||||
|
std::fill_n (buf, 2048, 0);
|
||||||
|
char text_message[2+5+1]("\x81\x05"
|
||||||
|
"Hello");
|
||||||
|
|
||||||
|
c.send(asio::buffer(text_message, 7));
|
||||||
|
c.receive(asio::buffer(buf, 2048));
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||||
|
std::string checkstring(std::string(buf).substr(0, 12));
|
||||||
|
CHECK(checkstring == "\x81\x0AHello back");
|
||||||
|
}
|
||||||
|
//----------Binary----------
|
||||||
|
{
|
||||||
|
std::fill_n (buf, 2048, 0);
|
||||||
|
char bin_message[2+9+1]("\x82\x09"
|
||||||
|
"Hello bin");
|
||||||
|
|
||||||
|
c.send(asio::buffer(bin_message, 11));
|
||||||
|
c.receive(asio::buffer(buf, 2048));
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||||
|
std::string checkstring2(std::string(buf).substr(0, 16));
|
||||||
|
CHECK(checkstring2 == "\x82\x0EHello back bin");
|
||||||
|
}
|
||||||
|
//----------Masked Text----------
|
||||||
|
{
|
||||||
|
std::fill_n (buf, 2048, 0);
|
||||||
|
char text_masked_message[2+4+5+1]("\x81\x85"
|
||||||
|
"\x67\xc6\x69\x73"
|
||||||
|
"\x2f\xa3\x05\x1f\x08");
|
||||||
|
|
||||||
|
c.send(asio::buffer(text_masked_message, 11));
|
||||||
|
c.receive(asio::buffer(buf, 2048));
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||||
|
std::string checkstring3(std::string(buf).substr(0, 12));
|
||||||
|
CHECK(checkstring3 == "\x81\x0AHello back");
|
||||||
|
}
|
||||||
|
//----------Masked Binary----------
|
||||||
|
{
|
||||||
|
std::fill_n (buf, 2048, 0);
|
||||||
|
char bin_masked_message[2+4+9+1]("\x82\x89"
|
||||||
|
"\x67\xc6\x69\x73"
|
||||||
|
"\x2f\xa3\x05\x1f\x08\xe6\x0b\x1a\x09");
|
||||||
|
|
||||||
|
c.send(asio::buffer(bin_masked_message, 15));
|
||||||
|
c.receive(asio::buffer(buf, 2048));
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||||
|
std::string checkstring4(std::string(buf).substr(0, 16));
|
||||||
|
CHECK(checkstring4 == "\x82\x0EHello back bin");
|
||||||
|
}
|
||||||
|
//----------Close----------
|
||||||
|
{
|
||||||
|
std::fill_n (buf, 2048, 0);
|
||||||
|
char close_message[10]("\x88"); //I do not know why, but the websocket code does not read this unless it's longer than 4 or so bytes
|
||||||
|
|
||||||
|
c.send(asio::buffer(close_message, 10));
|
||||||
|
c.receive(asio::buffer(buf, 2048));
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||||
|
CHECK((int)(unsigned char)buf[0] == 0x88);
|
||||||
|
}
|
||||||
|
|
||||||
|
app.stop();
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user