mirror of
https://github.com/XRPLF/rippled.git
synced 2026-04-29 15:37:57 +00:00
adds UTF8 validation state, better closing handshake logic, fixes misc other error conditions
This commit is contained in:
2
Makefile
2
Makefile
@@ -44,7 +44,7 @@ cxxflags_debug = -c -g
|
||||
cxxflags_shared = -f$(PIC)
|
||||
libname = libwebsocketpp
|
||||
libname_hdr = websocketpp
|
||||
libname_debug = $(libname)_dbg
|
||||
libname_debug = $(libname)
|
||||
suffix_shared = so
|
||||
suffix_shared_darwin = dylib
|
||||
suffix_static = a
|
||||
|
||||
@@ -45,5 +45,4 @@ uint64_t ntohll(uint64_t src);
|
||||
std::string lookup_http_error_string(int code);
|
||||
std::string lookup_ws_close_status_string(uint16_t code);
|
||||
|
||||
|
||||
#endif // NETWORK_UTILITIES_HPP
|
||||
#endif // NETWORK_UTILITIES_HPP
|
||||
|
||||
@@ -84,4 +84,4 @@ public:
|
||||
|
||||
|
||||
}
|
||||
#endif // WEBSOCKET_CONNECTION_HANDLER_HPP
|
||||
#endif // WEBSOCKET_CONNECTION_HANDLER_HPP
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "websocket_session.hpp"
|
||||
|
||||
#include "websocket_frame.hpp"
|
||||
#include "utf8_validator/utf8_validator.hpp"
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
@@ -45,7 +46,9 @@ session::session (server_ptr s,boost::asio::io_service& io_service,
|
||||
: m_status(CONNECTING),
|
||||
m_server(s),
|
||||
m_socket(io_service),
|
||||
m_local_interface(defc) {}
|
||||
m_local_interface(defc),
|
||||
m_utf8_state(utf8_validator::UTF8_ACCEPT),
|
||||
m_utf8_codepoint(0) {}
|
||||
|
||||
tcp::socket& session::socket() {
|
||||
return m_socket;
|
||||
@@ -105,6 +108,10 @@ std::string session::get_origin() const {
|
||||
}
|
||||
|
||||
void session::send(const std::string &msg) {
|
||||
if (m_status != OPEN) {
|
||||
// error?
|
||||
return;
|
||||
}
|
||||
m_write_frame.set_fin(true);
|
||||
m_write_frame.set_opcode(frame::TEXT_FRAME);
|
||||
m_write_frame.set_payload(msg);
|
||||
@@ -114,6 +121,10 @@ void session::send(const std::string &msg) {
|
||||
|
||||
// send binary frame
|
||||
void session::send(const std::vector<unsigned char> &data) {
|
||||
if (m_status != OPEN) {
|
||||
// error?
|
||||
return;
|
||||
}
|
||||
m_write_frame.set_fin(true);
|
||||
m_write_frame.set_opcode(frame::BINARY_FRAME);
|
||||
m_write_frame.set_payload(data);
|
||||
@@ -125,10 +136,17 @@ void session::send(const std::vector<unsigned char> &data) {
|
||||
void session::disconnect(uint16_t status,const std::string &message) {
|
||||
m_write_frame.set_fin(true);
|
||||
m_write_frame.set_opcode(frame::CONNECTION_CLOSE);
|
||||
m_write_frame.set_status(status,message);
|
||||
|
||||
if (status == 1005 || status == 1006) {
|
||||
m_write_frame.set_status(CLOSE_STATUS_NORMAL,"");
|
||||
} else {
|
||||
m_write_frame.set_status(status,message);
|
||||
}
|
||||
|
||||
write_frame();
|
||||
|
||||
|
||||
m_status = CLOSING;
|
||||
|
||||
if (m_local_interface) {
|
||||
m_local_interface->disconnect(shared_from_this(),status,message);
|
||||
}
|
||||
@@ -487,7 +505,7 @@ void session::handle_read_payload (const boost::system::error_code& error) {
|
||||
}
|
||||
|
||||
// check if there was an error processing this frame and fail the connection
|
||||
if (m_error) {
|
||||
if (m_error || m_status == CLOSED) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -518,7 +536,11 @@ void session::process_pong() {
|
||||
}
|
||||
|
||||
void session::process_text() {
|
||||
// text is binary.
|
||||
if (!m_read_frame.validate_utf8(&m_utf8_state,&m_utf8_codepoint)) {
|
||||
disconnect(CLOSE_STATUS_INVALID_PAYLOAD,"Invalid UTF8 Data");
|
||||
return;
|
||||
}
|
||||
|
||||
process_binary();
|
||||
}
|
||||
|
||||
@@ -547,6 +569,13 @@ void session::process_continuation() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_current_opcode == frame::TEXT_FRAME) {
|
||||
if (!m_read_frame.validate_utf8(&m_utf8_state,&m_utf8_codepoint)) {
|
||||
disconnect(CLOSE_STATUS_INVALID_PAYLOAD,"Invalid UTF8 Data");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
extract_payload();
|
||||
|
||||
// check if we are done
|
||||
@@ -564,22 +593,15 @@ void session::process_close() {
|
||||
uint16_t status = m_read_frame.get_close_status();
|
||||
std::string message = m_read_frame.get_close_msg();
|
||||
|
||||
msg << "[Connection " << this << "] Received connection close request from client. Close status:" << status << " (" << lookup_ws_close_status_string(status) << "), close message: " << message;
|
||||
msg << "[Connection " << this
|
||||
<< "] Received connection close request from client. Close status:"
|
||||
<< status << " (" << lookup_ws_close_status_string(status)
|
||||
<< "), close message: " << message;
|
||||
m_server->access_log(msg.str());
|
||||
|
||||
m_status = CLOSED;
|
||||
|
||||
// send acknowledgement
|
||||
m_write_frame.set_fin(true);
|
||||
m_write_frame.set_opcode(frame::CONNECTION_CLOSE);
|
||||
|
||||
write_frame();
|
||||
|
||||
// let our local interface know that the remote client has
|
||||
// disconnected
|
||||
if (m_local_interface) {
|
||||
m_local_interface->disconnect(shared_from_this(),status,message);
|
||||
}
|
||||
disconnect(status,message);
|
||||
} else if (m_status == CLOSING) {
|
||||
// this is an ack of our close message
|
||||
|
||||
@@ -604,6 +626,12 @@ void session::deliver_message() {
|
||||
} else if (m_current_opcode == frame::TEXT_FRAME) {
|
||||
std::string msg;
|
||||
|
||||
// make sure the finished frame is valid utf8
|
||||
if (m_utf8_state != utf8_validator::UTF8_ACCEPT) {
|
||||
disconnect(CLOSE_STATUS_INVALID_PAYLOAD,"Invalid UTF8 Data");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_fragmented) {
|
||||
msg.append(m_current_message.begin(),m_current_message.end());
|
||||
} else {
|
||||
@@ -660,6 +688,9 @@ void session::reset_message() {
|
||||
m_error = false;
|
||||
m_fragmented = false;
|
||||
m_current_message.clear();
|
||||
|
||||
m_utf8_state = utf8_validator::UTF8_ACCEPT;
|
||||
m_utf8_codepoint = 0;
|
||||
}
|
||||
|
||||
void session::handle_error(std::string msg,
|
||||
@@ -675,4 +706,4 @@ void session::handle_error(std::string msg,
|
||||
}
|
||||
|
||||
m_error = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +65,8 @@ namespace websocketpp {
|
||||
|
||||
class session : public boost::enable_shared_from_this<session> {
|
||||
public:
|
||||
friend class handshake_error;
|
||||
|
||||
enum ws_status {
|
||||
CONNECTING,
|
||||
OPEN,
|
||||
@@ -74,7 +76,16 @@ public:
|
||||
|
||||
typedef enum ws_status status_code;
|
||||
|
||||
friend class handshake_error;
|
||||
static const uint16_t CLOSE_STATUS_NORMAL = 1000;
|
||||
static const uint16_t CLOSE_STATUS_GOING_AWAY = 1001;
|
||||
static const uint16_t CLOSE_STATUS_PROTOCOL_ERROR = 1002;
|
||||
static const uint16_t CLOSE_STATUS_UNSUPPORTED_DATA = 1003;
|
||||
static const uint16_t CLOSE_STATUS_NO_STATUS = 1005;
|
||||
static const uint16_t CLOSE_STATUS_ABNORMAL_CLOSE = 1006;
|
||||
static const uint16_t CLOSE_STATUS_INVALID_PAYLOAD = 1007;
|
||||
static const uint16_t CLOSE_STATUS_POLICY_VIOLATION = 1008;
|
||||
static const uint16_t CLOSE_STATUS_MESSAGE_TOO_BIG = 1009;
|
||||
static const uint16_t CLOSE_STATUS_EXTENSION_REQUIRE = 1010;
|
||||
|
||||
session (server_ptr s,
|
||||
boost::asio::io_service& io_service,
|
||||
@@ -209,6 +220,10 @@ private:
|
||||
// Buffers
|
||||
boost::asio::streambuf m_buf;
|
||||
|
||||
// utf8 validation state
|
||||
uint32_t m_utf8_state;
|
||||
uint32_t m_utf8_codepoint;
|
||||
|
||||
// unorganized
|
||||
std::string m_handshake;
|
||||
frame m_read_frame;
|
||||
|
||||
Reference in New Issue
Block a user