ultimatepp/uppsrc/Core/WebSocket.cpp
cxl be8d86f8e2 Core: WebSocket fixes
git-svn-id: svn://ultimatepp.org/upp/trunk@6717 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2014-01-04 16:19:16 +00:00

167 lines
3.2 KiB
C++

#include "Core.h"
#define LLOG(x) // DLOG(x)
NAMESPACE_UPP
bool WebSocket::WebAccept(TcpSocket& socket_, HttpHeader& hdr)
{
socket = &socket_;
String key = hdr["sec-websocket-key"];
if(IsNull(key))
return false;
byte sha1[20];
SHA1(sha1, key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
return socket->PutAll(
"HTTP/1.1 101 Switching Protocols\r\n"
"Upgrade: websocket\r\n"
"Connection: Upgrade\r\n"
"Sec-WebSocket-Accept: " + Base64Encode((char *)sha1, 20) + "\r\n\r\n"
);
}
bool WebSocket::WebAccept(TcpSocket& socket)
{
HttpHeader hdr;
if(!hdr.Read(socket))
return false;
return WebAccept(socket, hdr);
}
int64 WebSocket::ReadLen(int n)
{
int64 len = 0;
while(n-- > 0)
len = (len << 8) | (byte)socket->Get();
return len;
}
bool WebSocket::RecieveRaw()
{
if(IsError())
return false;
opcode = socket->Get();
if(opcode < 0)
return false;
int64 len = socket->Get();
bool mask = len & 128;
len &= 127;
if(len == 127)
len = ReadLen(8);
if(len == 126)
len = ReadLen(2);
byte key[4];
if(mask)
socket->Get(key, 4);
if(IsError()) {
socket->SetSockError("websocket recieve", ERROR_DATA, "Invalid data");
return false;
}
if(len > maxlen || len < 0) {
socket->SetSockError("websocket recieve", ERROR_LEN_LIMIT, "Frame limit exceeded, size " + AsString(len));
return false;
}
StringBuffer frame((int)len); // TODO int64
char *buffer = ~frame;
if(!socket->GetAll(buffer, (int)len)) {
socket->SetSockError("websocket recieve", ERROR_DATA, "Invalid data");
return false;
}
if(mask)
for(int i = 0; i < len; i++)
buffer[i] ^= key[i & 3];
data = frame;
return true;
}
String WebSocket::Recieve()
{
LLOG("WebSocket::Recieve");
for(;;) {
if(!RecieveRaw()) {
LLOG("WebSocket::Recieve failed");
return String::GetVoid();
}
if(GetOpCode() == PING)
SendRaw(PONG, ~data, data.GetLength());
else {
if(GetOpCode() == CLOSE)
SendRaw(CLOSE, ~data, data.GetLength());
break;
}
}
LLOG("WebSocket::Recieve len: " << data.GetLength());
return data;
}
bool WebSocket::SendRaw(int hdr, const void *data, int64 len)
{
if(IsError())
return false;
ASSERT(len < INT_MAX); // temporary, todo
String b;
b.Cat(hdr);
if(len > 65535) {
b.Cat(127);
b.Cat(byte(len >> 56));
b.Cat(byte(len >> 48));
b.Cat(byte(len >> 40));
b.Cat(byte(len >> 32));
b.Cat(byte(len >> 24));
b.Cat(byte(len >> 16));
b.Cat(byte(len >> 8));
b.Cat(byte(len));
}
else
if(len > 125) {
b.Cat(126);
b.Cat(byte(len >> 8));
b.Cat(byte(len));
}
else
b.Cat((int)len);
LLOG("WebSocket::SendRaw hdr: " << hdr << ", len: " << len);
if(IsError() || !socket->PutAll(~b, b.GetLength()) || !socket->PutAll(data, (int)len)) {
socket->SetSockError("websocket send", ERROR_SEND, "Failed to send data");
LLOG("WebSocket::SendRaw FAILED");
return false;
}
LLOG("WebSocket::SendRaw OK");
return true;
}
void WebSocket::Reset()
{
opcode = 0;
data.Clear();
maxlen = 10 * 1024 * 1024;
socket = NULL;
}
void WebSocket::Close()
{
if(socket) {
socket->Close();
opcode = 0;
data.Clear();
socket = NULL;
}
}
END_UPP_NAMESPACE