mirror of
https://github.com/pocoproject/poco.git
synced 2025-01-06 00:31:10 +01:00
fixed GH #1212: Lost WebSocket Frames after Client Websocket Handshake is complete
This commit is contained in:
parent
6a8020b967
commit
65626774e1
@ -81,6 +81,9 @@ public:
|
|||||||
StreamSocket detachSocket();
|
StreamSocket detachSocket();
|
||||||
/// Returns the underlying socket after detaching
|
/// Returns the underlying socket after detaching
|
||||||
/// it from the server session.
|
/// it from the server session.
|
||||||
|
|
||||||
|
HTTPServerSession& session();
|
||||||
|
/// Returns the underlying HTTPServerSession.
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static const std::string EXPECT;
|
static const std::string EXPECT;
|
||||||
@ -130,6 +133,12 @@ inline HTTPServerResponse& HTTPServerRequestImpl::response() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline HTTPServerSession& HTTPServerRequestImpl::session()
|
||||||
|
{
|
||||||
|
return _session;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::Net
|
} } // namespace Poco::Net
|
||||||
|
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include "Poco/Timespan.h"
|
#include "Poco/Timespan.h"
|
||||||
#include "Poco/Exception.h"
|
#include "Poco/Exception.h"
|
||||||
#include "Poco/Any.h"
|
#include "Poco/Any.h"
|
||||||
|
#include "Poco/Buffer.h"
|
||||||
#include <ios>
|
#include <ios>
|
||||||
|
|
||||||
|
|
||||||
@ -100,6 +101,14 @@ public:
|
|||||||
|
|
||||||
StreamSocket& socket();
|
StreamSocket& socket();
|
||||||
/// Returns a reference to the underlying socket.
|
/// Returns a reference to the underlying socket.
|
||||||
|
|
||||||
|
void drainBuffer(Poco::Buffer<char>& buffer);
|
||||||
|
/// Copies all bytes remaining in the internal buffer to the
|
||||||
|
/// given Poco::Buffer, resizing it as necessary.
|
||||||
|
///
|
||||||
|
/// This is usually used together with detachSocket() to
|
||||||
|
/// obtain any data already read from the socket, but not
|
||||||
|
/// yet processed.
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
HTTPSession();
|
HTTPSession();
|
||||||
|
@ -22,19 +22,23 @@
|
|||||||
|
|
||||||
#include "Poco/Net/StreamSocketImpl.h"
|
#include "Poco/Net/StreamSocketImpl.h"
|
||||||
#include "Poco/Random.h"
|
#include "Poco/Random.h"
|
||||||
|
#include "Poco/Buffer.h"
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco {
|
||||||
namespace Net {
|
namespace Net {
|
||||||
|
|
||||||
|
|
||||||
|
class HTTPSession;
|
||||||
|
|
||||||
|
|
||||||
class Net_API WebSocketImpl: public StreamSocketImpl
|
class Net_API WebSocketImpl: public StreamSocketImpl
|
||||||
/// This class implements a WebSocket, according
|
/// This class implements a WebSocket, according
|
||||||
/// to the WebSocket protocol described in RFC 6455.
|
/// to the WebSocket protocol described in RFC 6455.
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
WebSocketImpl(StreamSocketImpl* pStreamSocketImpl, bool mustMaskPayload);
|
WebSocketImpl(StreamSocketImpl* pStreamSocketImpl, HTTPSession& session, bool mustMaskPayload);
|
||||||
/// Creates a StreamSocketImpl using the given native socket.
|
/// Creates a WebSocketImpl.
|
||||||
|
|
||||||
// StreamSocketImpl
|
// StreamSocketImpl
|
||||||
virtual int sendBytes(const void* buffer, int length, int flags);
|
virtual int sendBytes(const void* buffer, int length, int flags);
|
||||||
@ -79,12 +83,15 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
int receiveNBytes(void* buffer, int bytes);
|
int receiveNBytes(void* buffer, int bytes);
|
||||||
|
int receiveSomeBytes(char* buffer, int bytes);
|
||||||
virtual ~WebSocketImpl();
|
virtual ~WebSocketImpl();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
WebSocketImpl();
|
WebSocketImpl();
|
||||||
|
|
||||||
StreamSocketImpl* _pStreamSocketImpl;
|
StreamSocketImpl* _pStreamSocketImpl;
|
||||||
|
Poco::Buffer<char> _buffer;
|
||||||
|
int _bufferOffset;
|
||||||
int _frameFlags;
|
int _frameFlags;
|
||||||
bool _mustMaskPayload;
|
bool _mustMaskPayload;
|
||||||
Poco::Random _rnd;
|
Poco::Random _rnd;
|
||||||
|
@ -238,4 +238,11 @@ void HTTPSession::attachSessionData(const Poco::Any& data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void HTTPSession::drainBuffer(Poco::Buffer<char>& buffer)
|
||||||
|
{
|
||||||
|
buffer.assign(_pCurrent, static_cast<std::size_t>(_pEnd - _pCurrent));
|
||||||
|
_pCurrent = _pEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::Net
|
} } // namespace Poco::Net
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include "Poco/Net/HTTPServerRequestImpl.h"
|
#include "Poco/Net/HTTPServerRequestImpl.h"
|
||||||
#include "Poco/Net/HTTPServerResponse.h"
|
#include "Poco/Net/HTTPServerResponse.h"
|
||||||
#include "Poco/Net/HTTPClientSession.h"
|
#include "Poco/Net/HTTPClientSession.h"
|
||||||
|
#include "Poco/Net/HTTPServerSession.h"
|
||||||
#include "Poco/Net/NetException.h"
|
#include "Poco/Net/NetException.h"
|
||||||
#include "Poco/Buffer.h"
|
#include "Poco/Buffer.h"
|
||||||
#include "Poco/MemoryStream.h"
|
#include "Poco/MemoryStream.h"
|
||||||
@ -137,7 +138,9 @@ WebSocketImpl* WebSocket::accept(HTTPServerRequest& request, HTTPServerResponse&
|
|||||||
response.set("Sec-WebSocket-Accept", computeAccept(key));
|
response.set("Sec-WebSocket-Accept", computeAccept(key));
|
||||||
response.setContentLength(0);
|
response.setContentLength(0);
|
||||||
response.send().flush();
|
response.send().flush();
|
||||||
return new WebSocketImpl(static_cast<StreamSocketImpl*>(static_cast<HTTPServerRequestImpl&>(request).detachSocket().impl()), false);
|
|
||||||
|
HTTPServerRequestImpl& requestImpl = static_cast<HTTPServerRequestImpl&>(request);
|
||||||
|
return new WebSocketImpl(static_cast<StreamSocketImpl*>(requestImpl.detachSocket().impl()), requestImpl.session(), false);
|
||||||
}
|
}
|
||||||
else throw WebSocketException("No WebSocket handshake", WS_ERR_NO_HANDSHAKE);
|
else throw WebSocketException("No WebSocket handshake", WS_ERR_NO_HANDSHAKE);
|
||||||
}
|
}
|
||||||
@ -205,7 +208,7 @@ WebSocketImpl* WebSocket::completeHandshake(HTTPClientSession& cs, HTTPResponse&
|
|||||||
std::string accept = response.get("Sec-WebSocket-Accept", "");
|
std::string accept = response.get("Sec-WebSocket-Accept", "");
|
||||||
if (accept != computeAccept(key))
|
if (accept != computeAccept(key))
|
||||||
throw WebSocketException("Invalid or missing Sec-WebSocket-Accept header in handshake response", WS_ERR_HANDSHAKE_ACCEPT);
|
throw WebSocketException("Invalid or missing Sec-WebSocket-Accept header in handshake response", WS_ERR_HANDSHAKE_ACCEPT);
|
||||||
return new WebSocketImpl(static_cast<StreamSocketImpl*>(cs.detachSocket().impl()), true);
|
return new WebSocketImpl(static_cast<StreamSocketImpl*>(cs.detachSocket().impl()), cs, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "Poco/Net/WebSocketImpl.h"
|
#include "Poco/Net/WebSocketImpl.h"
|
||||||
#include "Poco/Net/NetException.h"
|
#include "Poco/Net/NetException.h"
|
||||||
#include "Poco/Net/WebSocket.h"
|
#include "Poco/Net/WebSocket.h"
|
||||||
|
#include "Poco/Net/HTTPSession.h"
|
||||||
#include "Poco/Buffer.h"
|
#include "Poco/Buffer.h"
|
||||||
#include "Poco/BinaryWriter.h"
|
#include "Poco/BinaryWriter.h"
|
||||||
#include "Poco/BinaryReader.h"
|
#include "Poco/BinaryReader.h"
|
||||||
@ -29,14 +30,17 @@ namespace Poco {
|
|||||||
namespace Net {
|
namespace Net {
|
||||||
|
|
||||||
|
|
||||||
WebSocketImpl::WebSocketImpl(StreamSocketImpl* pStreamSocketImpl, bool mustMaskPayload):
|
WebSocketImpl::WebSocketImpl(StreamSocketImpl* pStreamSocketImpl, HTTPSession& session, bool mustMaskPayload):
|
||||||
StreamSocketImpl(pStreamSocketImpl->sockfd()),
|
StreamSocketImpl(pStreamSocketImpl->sockfd()),
|
||||||
_pStreamSocketImpl(pStreamSocketImpl),
|
_pStreamSocketImpl(pStreamSocketImpl),
|
||||||
|
_buffer(0),
|
||||||
|
_bufferOffset(0),
|
||||||
_frameFlags(0),
|
_frameFlags(0),
|
||||||
_mustMaskPayload(mustMaskPayload)
|
_mustMaskPayload(mustMaskPayload)
|
||||||
{
|
{
|
||||||
poco_check_ptr(pStreamSocketImpl);
|
poco_check_ptr(pStreamSocketImpl);
|
||||||
_pStreamSocketImpl->duplicate();
|
_pStreamSocketImpl->duplicate();
|
||||||
|
session.drainBuffer(_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -192,12 +196,12 @@ int WebSocketImpl::receiveBytes(void* buffer, int length, int)
|
|||||||
|
|
||||||
int WebSocketImpl::receiveNBytes(void* buffer, int bytes)
|
int WebSocketImpl::receiveNBytes(void* buffer, int bytes)
|
||||||
{
|
{
|
||||||
int received = _pStreamSocketImpl->receiveBytes(reinterpret_cast<char*>(buffer), bytes);
|
int received = receiveSomeBytes(reinterpret_cast<char*>(buffer), bytes);
|
||||||
if (received > 0)
|
if (received > 0)
|
||||||
{
|
{
|
||||||
while (received < bytes)
|
while (received < bytes)
|
||||||
{
|
{
|
||||||
int n = _pStreamSocketImpl->receiveBytes(reinterpret_cast<char*>(buffer) + received, bytes - received);
|
int n = receiveSomeBytes(reinterpret_cast<char*>(buffer) + received, bytes - received);
|
||||||
if (n > 0)
|
if (n > 0)
|
||||||
received += n;
|
received += n;
|
||||||
else
|
else
|
||||||
@ -208,6 +212,23 @@ int WebSocketImpl::receiveNBytes(void* buffer, int bytes)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int WebSocketImpl::receiveSomeBytes(char* buffer, int bytes)
|
||||||
|
{
|
||||||
|
int n = _buffer.size() - _bufferOffset;
|
||||||
|
if (n > 0)
|
||||||
|
{
|
||||||
|
if (bytes < n) n = bytes;
|
||||||
|
std::memcpy(buffer, _buffer.begin() + _bufferOffset, n);
|
||||||
|
_bufferOffset += n;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return _pStreamSocketImpl->receiveBytes(buffer, bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
SocketImpl* WebSocketImpl::acceptConnection(SocketAddress& clientAddr)
|
SocketImpl* WebSocketImpl::acceptConnection(SocketAddress& clientAddr)
|
||||||
{
|
{
|
||||||
throw Poco::InvalidAccessException("Cannot acceptConnection() on a WebSocketImpl");
|
throw Poco::InvalidAccessException("Cannot acceptConnection() on a WebSocketImpl");
|
||||||
|
Loading…
Reference in New Issue
Block a user