mirror of
				https://github.com/pocoproject/poco.git
				synced 2025-10-27 19:10:20 +01:00 
			
		
		
		
	Add WebSocket::receiveFrame() that appends to a Poco::Buffer<char>
This commit is contained in:
		| @@ -29,6 +29,7 @@ | ||||
| #include "Poco/String.h" | ||||
| #include "Poco/Random.h" | ||||
| #include "Poco/StreamCopier.h" | ||||
| #include "Poco/Buffer.h" | ||||
| #include <sstream> | ||||
|  | ||||
|  | ||||
| @@ -114,6 +115,14 @@ int WebSocket::receiveFrame(void* buffer, int length, int& flags) | ||||
| } | ||||
|  | ||||
| 	 | ||||
| int WebSocket::receiveFrame(Poco::Buffer<char>& buffer, int& flags) | ||||
| { | ||||
| 	int n = static_cast<WebSocketImpl*>(impl())->receiveBytes(buffer, 0); | ||||
| 	flags = static_cast<WebSocketImpl*>(impl())->frameFlags(); | ||||
| 	return n; | ||||
| } | ||||
|  | ||||
|  | ||||
| WebSocket::Mode WebSocket::mode() const | ||||
| { | ||||
| 	return static_cast<WebSocketImpl*>(impl())->mustMaskPayload() ? WS_CLIENT : WS_SERVER; | ||||
|   | ||||
| @@ -104,7 +104,7 @@ int WebSocketImpl::sendBytes(const void* buffer, int length, int flags) | ||||
| } | ||||
|  | ||||
| 	 | ||||
| int WebSocketImpl::receiveBytes(void* buffer, int length, int) | ||||
| int WebSocketImpl::receiveHeader(char mask[4], bool& useMask) | ||||
| { | ||||
| 	char header[MAX_HEADER_LENGTH]; | ||||
| 	int n = receiveNBytes(header, 2); | ||||
| @@ -114,82 +114,100 @@ int WebSocketImpl::receiveBytes(void* buffer, int length, int) | ||||
| 		return n; | ||||
| 	} | ||||
| 	poco_assert (n == 2); | ||||
| 	Poco::UInt8 lengthByte = static_cast<Poco::UInt8>(header[1]); | ||||
| 	int maskOffset = 0; | ||||
| 	if (lengthByte & FRAME_FLAG_MASK) maskOffset += 4; | ||||
| 	lengthByte &= 0x7f; | ||||
| 	if (lengthByte > 0 || maskOffset > 0) | ||||
| 	{ | ||||
| 		if (lengthByte + 2 + maskOffset < MAX_HEADER_LENGTH) | ||||
| 		{ | ||||
| 			n = receiveNBytes(header + 2, lengthByte + maskOffset); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			n = receiveNBytes(header + 2, MAX_HEADER_LENGTH - 2); | ||||
| 		} | ||||
| 		if (n <= 0) throw WebSocketException("Incomplete header received", WebSocket::WS_ERR_INCOMPLETE_FRAME); | ||||
| 		n += 2; | ||||
| 	} | ||||
| 	Poco::MemoryInputStream istr(header, n); | ||||
| 	Poco::BinaryReader reader(istr, Poco::BinaryReader::NETWORK_BYTE_ORDER); | ||||
| 	Poco::UInt8 flags; | ||||
| 	char mask[4]; | ||||
| 	reader >> flags >> lengthByte; | ||||
| 	Poco::UInt8 flags = static_cast<Poco::UInt8>(header[0]); | ||||
| 	_frameFlags = flags; | ||||
| 	int payloadLength = 0; | ||||
| 	int payloadOffset = 2; | ||||
| 	if ((lengthByte & 0x7f) == 127) | ||||
| 	Poco::UInt8 lengthByte = static_cast<Poco::UInt8>(header[1]); | ||||
| 	useMask = ((lengthByte & FRAME_FLAG_MASK) != 0); | ||||
| 	int payloadLength; | ||||
| 	lengthByte &= 0x7f; | ||||
| 	if (lengthByte == 127) | ||||
| 	{ | ||||
| 		n = receiveNBytes(header + 2, 8); | ||||
| 		if (n <= 0) | ||||
| 		{ | ||||
| 			_frameFlags = 0; | ||||
| 			return n; | ||||
| 		} | ||||
| 		Poco::MemoryInputStream istr(header + 2, 8); | ||||
| 		Poco::BinaryReader reader(istr, Poco::BinaryReader::NETWORK_BYTE_ORDER); | ||||
| 		Poco::UInt64 l; | ||||
| 		reader >> l; | ||||
| 		if (l > length) throw WebSocketException(Poco::format("Insufficient buffer for payload size %Lu", l), WebSocket::WS_ERR_PAYLOAD_TOO_BIG); | ||||
| 		payloadLength = static_cast<int>(l); | ||||
| 		payloadOffset += 8; | ||||
| 	} | ||||
| 	else if ((lengthByte & 0x7f) == 126) | ||||
| 	} else if (lengthByte == 126) | ||||
| 	{ | ||||
| 		n = receiveNBytes(header + 2, 2); | ||||
| 		if (n <= 0) | ||||
| 		{ | ||||
| 			_frameFlags = 0; | ||||
| 			return n; | ||||
| 		} | ||||
| 		Poco::MemoryInputStream istr(header + 2, 2); | ||||
| 		Poco::BinaryReader reader(istr, Poco::BinaryReader::NETWORK_BYTE_ORDER); | ||||
| 		Poco::UInt16 l; | ||||
| 		reader >> l; | ||||
| 		if (l > length) throw WebSocketException(Poco::format("Insufficient buffer for payload size %hu", l), WebSocket::WS_ERR_PAYLOAD_TOO_BIG); | ||||
| 		payloadLength = static_cast<int>(l); | ||||
| 		payloadOffset += 2; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		Poco::UInt8 l = lengthByte & 0x7f; | ||||
| 		if (l > length) throw WebSocketException(Poco::format("Insufficient buffer for payload size %u", unsigned(l)), WebSocket::WS_ERR_PAYLOAD_TOO_BIG); | ||||
| 		payloadLength = static_cast<int>(l); | ||||
| 		payloadLength = lengthByte; | ||||
| 	} | ||||
| 	if (lengthByte & FRAME_FLAG_MASK) | ||||
|  | ||||
| 	if (useMask) | ||||
| 	{ | ||||
| 		reader.readRaw(mask, 4); | ||||
| 		payloadOffset += 4; | ||||
| 		n = receiveNBytes(mask, 4); | ||||
| 		if (n <= 0) | ||||
| 		{ | ||||
| 			_frameFlags = 0; | ||||
| 			return n; | ||||
| 		} | ||||
| 	} | ||||
| 	int received = 0; | ||||
| 	if (payloadOffset < n) | ||||
|  | ||||
| 	return payloadLength; | ||||
| } | ||||
|  | ||||
|  | ||||
| int WebSocketImpl::receivePayload(char *buffer, int payloadLength, char mask[4], bool useMask) | ||||
| { | ||||
| 	int received = receiveNBytes(reinterpret_cast<char*>(buffer), payloadLength); | ||||
| 	if (received <= 0) throw WebSocketException("Incomplete frame received", WebSocket::WS_ERR_INCOMPLETE_FRAME); | ||||
|  | ||||
| 	if (useMask) | ||||
| 	{ | ||||
| 		std::memcpy(buffer, header + payloadOffset, n - payloadOffset); | ||||
| 		received = n - payloadOffset; | ||||
| 	} | ||||
| 	if (received < payloadLength) | ||||
| 	{ | ||||
| 		n = receiveNBytes(reinterpret_cast<char*>(buffer) + received, payloadLength - received); | ||||
| 		if (n <= 0) throw WebSocketException("Incomplete frame received", WebSocket::WS_ERR_INCOMPLETE_FRAME); | ||||
| 		received += n; | ||||
| 	} | ||||
| 	if (lengthByte & FRAME_FLAG_MASK) | ||||
| 	{ | ||||
| 		char* p = reinterpret_cast<char*>(buffer); | ||||
| 		for (int i = 0; i < received; i++) | ||||
| 		{ | ||||
| 			p[i] ^= mask[i % 4]; | ||||
| 			buffer[i] ^= mask[i % 4]; | ||||
| 		} | ||||
| 	} | ||||
| 	return received; | ||||
| } | ||||
|  | ||||
|  | ||||
| int WebSocketImpl::receiveBytes(void* buffer, int length, int) | ||||
| { | ||||
| 	char mask[4]; | ||||
| 	bool useMask; | ||||
| 	int payloadLength = receiveHeader(mask, useMask); | ||||
| 	if (payloadLength <= 0) | ||||
| 		return payloadLength; | ||||
| 	if (payloadLength > length) | ||||
| 		throw WebSocketException(Poco::format("Insufficient buffer for payload size %hu", payloadLength), WebSocket::WS_ERR_PAYLOAD_TOO_BIG); | ||||
| 	return receivePayload(reinterpret_cast<char*>(buffer), payloadLength, mask, useMask); | ||||
| } | ||||
|  | ||||
|  | ||||
| int WebSocketImpl::receiveBytes(Poco::Buffer<char>& buffer, int) | ||||
| { | ||||
| 	char mask[4]; | ||||
| 	bool useMask; | ||||
| 	int payloadLength = receiveHeader(mask, useMask); | ||||
| 	if (payloadLength <= 0) | ||||
| 		return payloadLength; | ||||
| 	int oldSize = buffer.size(); | ||||
| 	buffer.resize(oldSize + payloadLength); | ||||
| 	return receivePayload(buffer.begin() + oldSize, payloadLength, mask, useMask); | ||||
| } | ||||
|  | ||||
|  | ||||
| int WebSocketImpl::receiveNBytes(void* buffer, int bytes) | ||||
| { | ||||
| 	int received = _pStreamSocketImpl->receiveBytes(reinterpret_cast<char*>(buffer), bytes); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Tor Lillqvist
					Tor Lillqvist