mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-03 16:56:48 +00:00
284 lines
9.2 KiB
C++
284 lines
9.2 KiB
C++
/*
|
|
* Copyright (c) 2013, Peter Thorson. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* * Neither the name of the WebSocket++ Project nor the
|
|
* names of its contributors may be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
|
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
*/
|
|
|
|
#ifndef WEBSOCKETPP_PROCESSOR_HYBI00_HPP
|
|
#define WEBSOCKETPP_PROCESSOR_HYBI00_HPP
|
|
|
|
#include <cstdlib>
|
|
|
|
// For htonl
|
|
#if defined(WIN32)
|
|
#include <winsock2.h>
|
|
#else
|
|
#include <arpa/inet.h>
|
|
#endif
|
|
|
|
#include <websocketpp/processors/processor.hpp>
|
|
|
|
#include <websocketpp/md5/md5.hpp>
|
|
|
|
namespace websocketpp {
|
|
namespace processor {
|
|
|
|
/// Processor for Hybi Draft version 00
|
|
/**
|
|
* There are many differences between Hybi 00 and Hybi 13
|
|
*/
|
|
template <typename config>
|
|
class hybi00 : public processor<config> {
|
|
public:
|
|
typedef processor<config> base;
|
|
|
|
typedef typename config::request_type request_type;
|
|
typedef typename config::response_type response_type;
|
|
|
|
typedef typename config::message_type message_type;
|
|
typedef typename message_type::ptr message_ptr;
|
|
|
|
typedef typename config::con_msg_manager_type::ptr msg_manager_ptr;
|
|
|
|
explicit hybi00(bool secure, bool server, msg_manager_ptr manager)
|
|
: processor<config>(secure, server) {}
|
|
|
|
int get_version() const {
|
|
return 0;
|
|
}
|
|
|
|
lib::error_code validate_handshake(const request_type& r) const {
|
|
if (r.get_method() != "GET") {
|
|
return make_error_code(error::invalid_http_method);
|
|
}
|
|
|
|
if (r.get_version() != "HTTP/1.1") {
|
|
return make_error_code(error::invalid_http_version);
|
|
}
|
|
|
|
// required headers
|
|
// Host is required by HTTP/1.1
|
|
// Connection is required by is_websocket_handshake
|
|
// Upgrade is required by is_websocket_handshake
|
|
if (r.get_header("Sec-WebSocket-Key1") == "" ||
|
|
r.get_header("Sec-WebSocket-Key2") == "" ||
|
|
r.get_header("Sec-WebSocket-Key3") == "")
|
|
{
|
|
return make_error_code(error::missing_required_header);
|
|
}
|
|
|
|
return lib::error_code();
|
|
}
|
|
|
|
lib::error_code process_handshake(const request_type& req, const
|
|
std::string & subprotocol, response_type& res) const
|
|
{
|
|
char key_final[16];
|
|
|
|
// copy key1 into final key
|
|
decode_client_key(req.get_header("Sec-WebSocket-Key1"), &key_final[0]);
|
|
|
|
// copy key2 into final key
|
|
decode_client_key(req.get_header("Sec-WebSocket-Key2"), &key_final[4]);
|
|
|
|
// copy key3 into final key
|
|
// key3 should be exactly 8 bytes. If it is more it will be truncated
|
|
// if it is less the final key will almost certainly be wrong.
|
|
// TODO: decide if it is best to silently fail here or produce some sort
|
|
// of warning or exception.
|
|
const std::string& key3 = req.get_header("Sec-WebSocket-Key3");
|
|
std::copy(key3.c_str(),
|
|
key3.c_str()+std::min(static_cast<size_t>(8), key3.size()),
|
|
&key_final[8]);
|
|
|
|
res.append_header(
|
|
"Sec-WebSocket-Key3",
|
|
md5::md5_hash_string(std::string(key_final,16))
|
|
);
|
|
|
|
res.append_header("Upgrade","websocket");
|
|
res.append_header("Connection","Upgrade");
|
|
|
|
// Echo back client's origin unless our local application set a
|
|
// more restrictive one.
|
|
if (res.get_header("Sec-WebSocket-Origin") == "") {
|
|
res.append_header("Sec-WebSocket-Origin",req.get_header("Origin"));
|
|
}
|
|
|
|
// Echo back the client's request host unless our local application
|
|
// set a different one.
|
|
if (res.get_header("Sec-WebSocket-Location") == "") {
|
|
uri_ptr uri = get_uri(req);
|
|
res.append_header("Sec-WebSocket-Location",uri->str());
|
|
}
|
|
|
|
return lib::error_code();
|
|
}
|
|
|
|
// outgoing client connection processing is not supported for this version
|
|
lib::error_code client_handshake_request(request_type& req, uri_ptr uri,
|
|
const std::vector<std::string> & subprotocols) const
|
|
{
|
|
return error::make_error_code(error::no_protocol_support);
|
|
}
|
|
|
|
lib::error_code validate_server_handshake_response(const request_type& req,
|
|
response_type& res) const
|
|
{
|
|
return error::make_error_code(error::no_protocol_support);
|
|
}
|
|
|
|
std::string get_raw(const response_type& res) const {
|
|
return res.raw() + res.get_header("Sec-WebSocket-Key3");
|
|
}
|
|
|
|
const std::string& get_origin(const request_type& r) const {
|
|
return r.get_header("Origin");
|
|
}
|
|
|
|
// hybi00 doesn't support subprotocols so there never will be any requested
|
|
lib::error_code extract_subprotocols(const request_type & req,
|
|
std::vector<std::string> & subprotocol_list)
|
|
{
|
|
return lib::error_code();
|
|
}
|
|
|
|
uri_ptr get_uri(const request_type& request) const {
|
|
std::string h = request.get_header("Host");
|
|
|
|
size_t last_colon = h.rfind(":");
|
|
size_t last_sbrace = h.rfind("]");
|
|
|
|
// no : = hostname with no port
|
|
// last : before ] = ipv6 literal with no port
|
|
// : with no ] = hostname with port
|
|
// : after ] = ipv6 literal with port
|
|
|
|
if (last_colon == std::string::npos ||
|
|
(last_sbrace != std::string::npos && last_sbrace > last_colon))
|
|
{
|
|
return uri_ptr(new uri(base::m_secure, h, request.get_uri()));
|
|
} else {
|
|
return uri_ptr(new uri(base::m_secure,
|
|
h.substr(0,last_colon),
|
|
h.substr(last_colon+1),
|
|
request.get_uri()));
|
|
}
|
|
|
|
// TODO: check if get_uri is a full uri
|
|
}
|
|
|
|
std::string get_key3() const {
|
|
return "";
|
|
}
|
|
|
|
/// Process new websocket connection bytes
|
|
size_t consume(uint8_t * buf, size_t len, lib::error_code & ec) {
|
|
ec = make_error_code(error::not_implimented);
|
|
return 0;
|
|
}
|
|
|
|
bool ready() const {
|
|
return false;
|
|
}
|
|
|
|
bool get_error() const {
|
|
return false;
|
|
}
|
|
|
|
message_ptr get_message() {
|
|
return message_ptr();
|
|
}
|
|
|
|
/// Prepare a message for writing
|
|
/**
|
|
* Performs validation, masking, compression, etc. will return an error if
|
|
* there was an error, otherwise msg will be ready to be written
|
|
*/
|
|
virtual lib::error_code prepare_data_frame(message_ptr in, message_ptr out)
|
|
{
|
|
// assert msg
|
|
|
|
// check if the message is prepared already
|
|
|
|
// validate opcode
|
|
// validate payload utf8
|
|
|
|
// if we are a client generate a masking key
|
|
|
|
// generate header
|
|
// perform compression
|
|
// perform masking
|
|
|
|
return lib::error_code();
|
|
}
|
|
|
|
lib::error_code prepare_ping(const std::string & in, message_ptr out) const
|
|
{
|
|
return lib::error_code(error::no_protocol_support);
|
|
}
|
|
|
|
lib::error_code prepare_pong(const std::string & in, message_ptr out) const
|
|
{
|
|
return lib::error_code(error::no_protocol_support);
|
|
}
|
|
|
|
lib::error_code prepare_close(close::status::value code,
|
|
const std::string & reason, message_ptr out) const
|
|
{
|
|
return lib::error_code(error::no_protocol_support);
|
|
}
|
|
private:
|
|
void decode_client_key(const std::string& key, char* result) const {
|
|
int spaces = 0;
|
|
std::string digits = "";
|
|
uint32_t num;
|
|
|
|
// key2
|
|
for (size_t i = 0; i < key.size(); i++) {
|
|
if (key[i] == ' ') {
|
|
spaces++;
|
|
} else if (key[i] >= '0' && key[i] <= '9') {
|
|
digits += key[i];
|
|
}
|
|
}
|
|
|
|
num = strtoul(digits.c_str(), NULL, 10);
|
|
if (spaces > 0 && num > 0) {
|
|
num = htonl(num/spaces);
|
|
std::copy(reinterpret_cast<char*>(&num),
|
|
reinterpret_cast<char*>(&num)+4,
|
|
result);
|
|
} else {
|
|
std::fill(result,result+4,0);
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
} // namespace processor
|
|
} // namespace websocketpp
|
|
|
|
#endif //WEBSOCKETPP_PROCESSOR_HYBI00_HPP
|