adds UTF8 validation state, better closing handshake logic, fixes misc other error conditions

This commit is contained in:
Peter Thorson
2011-09-15 07:00:33 -05:00
parent 2408d67ffe
commit 5eeae56ca7
5 changed files with 68 additions and 23 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -84,4 +84,4 @@ public:
}
#endif // WEBSOCKET_CONNECTION_HANDLER_HPP
#endif // WEBSOCKET_CONNECTION_HANDLER_HPP

View File

@@ -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;
}
}

View File

@@ -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;