mirror of
https://github.com/oatpp/oatpp.git
synced 2025-03-31 18:30:22 +08:00
WebSocket API draft
This commit is contained in:
parent
2bc7e882c6
commit
8f542a6f11
@ -127,7 +127,7 @@ HttpRequestExecutor::execute(const String& method,
|
||||
|
||||
return Response::createShared(result.startingLine.statusCode,
|
||||
result.startingLine.description.toString(),
|
||||
result.headers, bodyStream, m_bodyDecoder, connection);
|
||||
result.headers, bodyStream, m_bodyDecoder);
|
||||
|
||||
}
|
||||
|
||||
@ -214,7 +214,7 @@ oatpp::async::Action HttpRequestExecutor::executeAsync(oatpp::async::AbstractCor
|
||||
|
||||
return _return(Response::createShared(result.startingLine.statusCode,
|
||||
result.startingLine.description.toString(),
|
||||
result.headers, bodyStream, m_bodyDecoder, m_connection));
|
||||
result.headers, bodyStream, m_bodyDecoder));
|
||||
|
||||
}
|
||||
|
||||
|
63
web/client/WebSocketConnector.cpp
Normal file
63
web/client/WebSocketConnector.cpp
Normal file
@ -0,0 +1,63 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* Project _____ __ ____ _ _
|
||||
* ( _ ) /__\ (_ _)_| |_ _| |_
|
||||
* )(_)( /(__)\ )( (_ _)(_ _)
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi, <lganzzzo@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include "WebSocketConnector.hpp"
|
||||
|
||||
#include "oatpp/web/protocol/websocket/Handshaker.hpp"
|
||||
|
||||
namespace oatpp { namespace web { namespace client {
|
||||
|
||||
std::shared_ptr<WebSocketConnector::IOStream> WebSocketConnector::connectAndHandshake(const oatpp::String& path) {
|
||||
|
||||
auto connection = m_connectionProvider->getConnection();
|
||||
auto connectionHandle = std::make_shared<HttpRequestExecutor::HttpConnectionHandle>(connection);
|
||||
|
||||
protocol::websocket::Handshaker::Headers headers;
|
||||
protocol::websocket::Handshaker::clientsideHandshake(headers);
|
||||
|
||||
auto response = m_requestExecutor.execute("GET", path, headers, nullptr, connectionHandle);
|
||||
auto res = protocol::websocket::Handshaker::clientsideConfirmHandshake(headers, response);
|
||||
if(res == protocol::websocket::Handshaker::STATUS_OK) {
|
||||
return connection;
|
||||
} else if(res == protocol::websocket::Handshaker::STATUS_SERVER_ERROR) {
|
||||
throw std::runtime_error("[oatpp::web::client::WebSocketConnector::connectAndHandshake()]: Server responded with invalid code");
|
||||
} else if(res == protocol::websocket::Handshaker::STATUS_SERVER_WRONG_KEY) {
|
||||
throw std::runtime_error("[oatpp::web::client::WebSocketConnector::connectAndHandshake()]: Server wrong handshake key");
|
||||
} else if(res == protocol::websocket::Handshaker::STATUS_UNKNOWN_PROTOCOL_SUGGESTED) {
|
||||
throw std::runtime_error("[oatpp::web::client::WebSocketConnector::connectAndHandshake()]: Server response contains unexpected headers");
|
||||
} else {
|
||||
throw std::runtime_error("[oatpp::web::client::WebSocketConnector::connectAndHandshake()]: Unknown error");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
WebSocketConnector::WebSocket WebSocketConnector::connect(const oatpp::String& path) {
|
||||
return WebSocket(connectAndHandshake(path), true);
|
||||
}
|
||||
|
||||
std::shared_ptr<WebSocketConnector::WebSocket> WebSocketConnector::connectShared(const oatpp::String& path) {
|
||||
return std::make_shared<WebSocketConnector::WebSocket>(connectAndHandshake(path), true);
|
||||
}
|
||||
|
||||
}}}
|
70
web/client/WebSocketConnector.hpp
Normal file
70
web/client/WebSocketConnector.hpp
Normal file
@ -0,0 +1,70 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* Project _____ __ ____ _ _
|
||||
* ( _ ) /__\ (_ _)_| |_ _| |_
|
||||
* )(_)( /(__)\ )( (_ _)(_ _)
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi, <lganzzzo@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef oatpp_web_client_WebSocketConnector_hpp
|
||||
#define oatpp_web_client_WebSocketConnector_hpp
|
||||
|
||||
#include "./HttpRequestExecutor.hpp"
|
||||
#include "oatpp/web/protocol/websocket/WebSocket.hpp"
|
||||
|
||||
namespace oatpp { namespace web { namespace client {
|
||||
|
||||
class WebSocketConnector {
|
||||
public:
|
||||
typedef protocol::websocket::WebSocket WebSocket;
|
||||
typedef oatpp::data::stream::IOStream IOStream;
|
||||
private:
|
||||
std::shared_ptr<oatpp::network::ClientConnectionProvider> m_connectionProvider;
|
||||
HttpRequestExecutor m_requestExecutor;
|
||||
private:
|
||||
std::shared_ptr<IOStream> connectAndHandshake(const oatpp::String& path);
|
||||
public:
|
||||
|
||||
WebSocketConnector(const std::shared_ptr<oatpp::network::ClientConnectionProvider>& connectionProvider)
|
||||
: m_connectionProvider(connectionProvider)
|
||||
, m_requestExecutor(connectionProvider)
|
||||
{}
|
||||
|
||||
public:
|
||||
|
||||
static std::shared_ptr<WebSocketConnector> createShared(const std::shared_ptr<oatpp::network::ClientConnectionProvider>& connectionProvider) {
|
||||
return std::make_shared<WebSocketConnector>(connectionProvider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to server, do websocket-handshake and return WebSocket
|
||||
* (Blocking call)
|
||||
*/
|
||||
WebSocket connect(const oatpp::String& path);
|
||||
|
||||
/**
|
||||
* Same as connect() but return std::shared_ptr<WebSocket>
|
||||
*/
|
||||
std::shared_ptr<WebSocket> connectShared(const oatpp::String& path);
|
||||
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#endif /* oatpp_web_client_WebSocketConnector_hpp */
|
@ -54,14 +54,12 @@ public:
|
||||
const oatpp::String& statusDescription,
|
||||
const http::Protocol::Headers& headers,
|
||||
const std::shared_ptr<oatpp::data::stream::InputStream>& bodyStream,
|
||||
const std::shared_ptr<const http::incoming::BodyDecoder>& bodyDecoder,
|
||||
const std::shared_ptr<oatpp::data::stream::IOStream>& connection)
|
||||
const std::shared_ptr<const http::incoming::BodyDecoder>& bodyDecoder)
|
||||
: m_statusCode(statusCode)
|
||||
, m_statusDescription(statusDescription)
|
||||
, m_headers(headers)
|
||||
, m_bodyStream(bodyStream)
|
||||
, m_bodyDecoder(bodyDecoder)
|
||||
, m_connection(connection)
|
||||
{}
|
||||
public:
|
||||
|
||||
@ -69,9 +67,8 @@ public:
|
||||
const oatpp::String& statusDescription,
|
||||
const http::Protocol::Headers& headers,
|
||||
const std::shared_ptr<oatpp::data::stream::InputStream>& bodyStream,
|
||||
const std::shared_ptr<const http::incoming::BodyDecoder>& bodyDecoder,
|
||||
const std::shared_ptr<oatpp::data::stream::IOStream>& connection) {
|
||||
return Shared_Incoming_Response_Pool::allocateShared(statusCode, statusDescription, headers, bodyStream, bodyDecoder, connection);
|
||||
const std::shared_ptr<const http::incoming::BodyDecoder>& bodyDecoder) {
|
||||
return Shared_Incoming_Response_Pool::allocateShared(statusCode, statusDescription, headers, bodyStream, bodyDecoder);
|
||||
}
|
||||
|
||||
v_int32 getStatusCode() const {
|
||||
@ -93,10 +90,6 @@ public:
|
||||
std::shared_ptr<const http::incoming::BodyDecoder> getBodyDecoder() const {
|
||||
return m_bodyDecoder;
|
||||
}
|
||||
|
||||
std::shared_ptr<oatpp::data::stream::IOStream> getConnection() const {
|
||||
return m_connection;
|
||||
}
|
||||
|
||||
void streamBody(const std::shared_ptr<oatpp::data::stream::OutputStream>& toStream) const {
|
||||
m_bodyDecoder->decode(m_headers, m_bodyStream, toStream);
|
||||
|
@ -22,19 +22,19 @@
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include "Connector.hpp"
|
||||
#include "Handshaker.hpp"
|
||||
|
||||
#include "oatpp/algorithm/SHA1.hpp"
|
||||
#include "oatpp/encoding/Base64.hpp"
|
||||
|
||||
namespace oatpp { namespace web { namespace protocol { namespace websocket {
|
||||
|
||||
const char* const Connector::MAGIC_UUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||
const char* const Handshaker::MAGIC_UUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||
|
||||
thread_local std::mt19937 Connector::RANDOM_GENERATOR (std::random_device{}());
|
||||
thread_local std::uniform_int_distribution<size_t> Connector::RANDOM_DISTRIBUTION (0, 255);
|
||||
thread_local std::mt19937 Handshaker::RANDOM_GENERATOR (std::random_device{}());
|
||||
thread_local std::uniform_int_distribution<size_t> Handshaker::RANDOM_DISTRIBUTION (0, 255);
|
||||
|
||||
oatpp::String Connector::generateKey() {
|
||||
oatpp::String Handshaker::generateKey() {
|
||||
v_int32 keySize = 16;
|
||||
oatpp::String key(keySize);
|
||||
for(v_int32 i = 0; i < keySize; i ++) {
|
||||
@ -43,7 +43,7 @@ oatpp::String Connector::generateKey() {
|
||||
return oatpp::encoding::Base64::encode(key);
|
||||
}
|
||||
|
||||
oatpp::String Connector::getHeader(const Headers& headers, const oatpp::data::share::StringKeyLabelCI_FAST& key) {
|
||||
oatpp::String Handshaker::getHeader(const Headers& headers, const oatpp::data::share::StringKeyLabelCI_FAST& key) {
|
||||
|
||||
auto it = headers.find(key);
|
||||
if(it != headers.end()) {
|
||||
@ -54,7 +54,7 @@ oatpp::String Connector::getHeader(const Headers& headers, const oatpp::data::sh
|
||||
|
||||
}
|
||||
|
||||
std::shared_ptr<Connector::OutgoingResponse> Connector::serversideHandshake(const Headers& requestHeaders, const std::shared_ptr<ConnectionHandler>& connectionUpgradeHandler) {
|
||||
std::shared_ptr<Handshaker::OutgoingResponse> Handshaker::serversideHandshake(const Headers& requestHeaders, const std::shared_ptr<ConnectionHandler>& connectionUpgradeHandler) {
|
||||
|
||||
auto version = getHeader(requestHeaders, "Sec-WebSocket-Version");
|
||||
auto upgrade = getHeader(requestHeaders, oatpp::web::protocol::http::Header::UPGRADE);
|
||||
@ -89,14 +89,14 @@ std::shared_ptr<Connector::OutgoingResponse> Connector::serversideHandshake(cons
|
||||
|
||||
}
|
||||
|
||||
void Connector::clientsideHandshake(Headers& requestHeaders) {
|
||||
void Handshaker::clientsideHandshake(Headers& requestHeaders) {
|
||||
requestHeaders[oatpp::web::protocol::http::Header::UPGRADE] = "websocket";
|
||||
requestHeaders[oatpp::web::protocol::http::Header::CONNECTION] = oatpp::web::protocol::http::Header::Value::CONNECTION_UPGRADE;
|
||||
requestHeaders["Sec-WebSocket-Version"] = "13";
|
||||
requestHeaders["Sec-WebSocket-Key"] = generateKey();
|
||||
}
|
||||
|
||||
std::shared_ptr<WebSocket> Connector::clientConnect(const Headers& clientHandshakeHeaders, const std::shared_ptr<IncomingResponse>& serverResponse) {
|
||||
v_int32 Handshaker::clientsideConfirmHandshake(const Headers& clientHandshakeHeaders, const std::shared_ptr<IncomingResponse>& serverResponse) {
|
||||
|
||||
if(serverResponse->getStatusCode() == 101) {
|
||||
|
||||
@ -119,15 +119,19 @@ std::shared_ptr<WebSocket> Connector::clientConnect(const Headers& clientHandsha
|
||||
auto clientWebsocketAccept = oatpp::encoding::Base64::encode(sha1.finalBinary());
|
||||
|
||||
if(clientWebsocketAccept == websocketAccept) {
|
||||
return std::make_shared<WebSocket>(serverResponse->getConnection(), true);
|
||||
return STATUS_OK;
|
||||
} else {
|
||||
return STATUS_SERVER_WRONG_KEY;
|
||||
}
|
||||
|
||||
} else {
|
||||
return STATUS_UNKNOWN_PROTOCOL_SUGGESTED;
|
||||
}
|
||||
|
||||
} else {
|
||||
return STATUS_SERVER_ERROR;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
|
||||
}}}}
|
@ -22,8 +22,8 @@
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef oatpp_web_protocol_websocket_Connector_hpp
|
||||
#define oatpp_web_protocol_websocket_Connector_hpp
|
||||
#ifndef oatpp_web_protocol_websocket_Handshaker_hpp
|
||||
#define oatpp_web_protocol_websocket_Handshaker_hpp
|
||||
|
||||
#include "./WebSocket.hpp"
|
||||
|
||||
@ -36,18 +36,21 @@
|
||||
|
||||
namespace oatpp { namespace web { namespace protocol { namespace websocket {
|
||||
|
||||
class Connector {
|
||||
class Handshaker {
|
||||
public:
|
||||
static const char* const MAGIC_UUID;
|
||||
public:
|
||||
static constexpr v_int32 STATUS_OK = 0;
|
||||
static constexpr v_int32 STATUS_SERVER_ERROR = 1; // Server response-code != 101
|
||||
static constexpr v_int32 STATUS_SERVER_WRONG_KEY = 2; // Server response "Sec-WebSocket-Accept" header is wrong
|
||||
static constexpr v_int32 STATUS_UNKNOWN_PROTOCOL_SUGGESTED = 3; // Server's response contains unexpected headers values
|
||||
private:
|
||||
/* Random used to generate "Sec-WebSocket-Key" */
|
||||
static thread_local std::mt19937 RANDOM_GENERATOR;
|
||||
static thread_local std::uniform_int_distribution<size_t> RANDOM_DISTRIBUTION;
|
||||
public:
|
||||
typedef oatpp::web::protocol::http::outgoing::Response OutgoingResponse;
|
||||
typedef oatpp::web::protocol::http::outgoing::Request OutgoingRequest;
|
||||
typedef oatpp::web::protocol::http::incoming::Response IncomingResponse;
|
||||
typedef oatpp::web::protocol::http::incoming::Request IncomingRequest;
|
||||
typedef oatpp::web::protocol::http::Protocol::Headers Headers;
|
||||
typedef oatpp::network::server::ConnectionHandler ConnectionHandler;
|
||||
private:
|
||||
@ -66,12 +69,14 @@ public:
|
||||
static void clientsideHandshake(Headers& requestHeaders);
|
||||
|
||||
/**
|
||||
*
|
||||
* Check if client's handshake corresponds to server's handshake
|
||||
* returns one of values
|
||||
* (STATUS_OK=0, STATUS_SERVER_ERROR=1, STATUS_SERVER_WRONG_KEY=2, STATUS_UNKNOWN_PROTOCOL_SUGGESTED=3);
|
||||
*/
|
||||
static std::shared_ptr<WebSocket> clientConnect(const Headers& clientHandshakeHeaders, const std::shared_ptr<IncomingResponse>& serverResponse);
|
||||
static v_int32 clientsideConfirmHandshake(const Headers& clientHandshakeHeaders, const std::shared_ptr<IncomingResponse>& serverResponse);
|
||||
|
||||
};
|
||||
|
||||
}}}}
|
||||
|
||||
#endif /* oatpp_web_protocol_websocket_Connector_hpp */
|
||||
#endif /* oatpp_web_protocol_websocket_Handshaker_hpp */
|
@ -32,8 +32,6 @@ namespace oatpp { namespace web { namespace server {
|
||||
class WebSocketConnectionHandler : public oatpp::network::server::ConnectionHandler {
|
||||
public:
|
||||
|
||||
|
||||
|
||||
void handleConnection(const std::shared_ptr<oatpp::data::stream::IOStream>& connection) override {
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user