Core: WebSocket improvements

git-svn-id: svn://ultimatepp.org/upp/trunk@11798 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2018-02-24 16:04:24 +00:00
parent 7d44556c1a
commit 0f93a62163
3 changed files with 55 additions and 22 deletions

View file

@ -607,6 +607,7 @@ class WebSocket {
String host;
IpAddrInfo addrinfo;
bool ssl;
String request_header;
String data;
int data_pos;
@ -646,6 +647,8 @@ class WebSocket {
CLOSE = 0x8,
PING = 0x9,
PONG = 0xa,
MASK = 0x80,
};
void Clear();
@ -667,13 +670,14 @@ class WebSocket {
int GetFinIndex() const;
void SendRaw(int hdr, const String& data);
void SendRaw(int hdr, const String& data, dword mask = 0);
void Do0();
static String FormatBlock(const String& s);
public:
WebSocket& NonBlocking(bool b = true) { socket->Timeout(b ? 0 : Null); return *this; }
WebSocket& RequestHeader(const String& s) { request_header = s; return *this; }
bool IsBlocking() const { return IsNull(socket->GetTimeout()); }
@ -691,6 +695,7 @@ public:
bool IsBinary() const { return current_opcode & BINARY; }
void SendText(const String& data) { SendRaw(FIN|TEXT, data); }
void SendTextMasked(const String& data) { SendRaw(FIN|TEXT, data, MASK); }
void SendBinary(const String& data) { SendRaw(FIN|BINARY, data); }
void Ping(const String& data) { SendRaw(FIN|PING, data); }
@ -699,7 +704,7 @@ public:
void Continue(const String& data) { SendRaw(0, data); }
void Fin(const String& data) { SendRaw(FIN, data); }
void Close(const String& msg = Null);
void Close(const String& msg = Null, bool wait_reply = false);
bool IsOpen() const { return socket->IsOpen(); }
bool IsClosed() const { return !IsOpen(); }

View file

@ -104,17 +104,18 @@ void WebSocket::SendRequest()
for(int i = 0; i < 20; i++)
h.Cat(Random());
Out( // needs to be the first thing to sent after the connection is established
"GET " + uri + " HTTP/1.1\r\n"
"Host: " + host + "\r\n"
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n"
"Accept-Language: cs,en-US;q=0.7,en;q=0.3\r\n"
"Sec-WebSocket-Version: 13\r\n"
"Sec-WebSocket-Extensions: permessage-deflate\r\n"
"Sec-WebSocket-Key: " + Base64Encode(h) + "\r\n"
"Connection: keep-alive, Upgrade\r\n"
"Pragma: no-cache\r\n"
"Cache-Control: no-cache\r\n"
"Upgrade: websocket\r\n\r\n"
Nvl(request_header,
"GET " + uri + " HTTP/1.1\r\n"
"Host: " + host + "\r\n"
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n"
"Accept-Language: cs,en-US;q=0.7,en;q=0.3\r\n"
"Sec-WebSocket-Version: 13\r\n"
"Sec-WebSocket-Extensions: permessage-deflate\r\n"
"Sec-WebSocket-Key: " + Base64Encode(h) + "\r\n"
"Connection: keep-alive, Upgrade\r\n"
"Pragma: no-cache\r\n"
"Cache-Control: no-cache\r\n"
"Upgrade: websocket\r\n\r\n")
);
opcode = HTTP_RESPONSE_HEADER;
}
@ -291,13 +292,13 @@ void WebSocket::FrameHeader()
}
}
void WebSocket::Close(const String& msg)
void WebSocket::Close(const String& msg, bool wait_reply)
{
LLOG("Sending CLOSE");
SendRaw(CLOSE|FIN, msg);
close_sent = true;
if(IsBlocking())
while(!IsClosed() && !IsError() && socket->IsOpen())
while((wait_reply ? IsOpen() : out_queue.GetCount()) && !IsError() && socket->IsOpen())
Do0();
}
@ -425,7 +426,7 @@ void WebSocket::Output()
}
}
void WebSocket::SendRaw(int hdr, const String& data)
void WebSocket::SendRaw(int hdr, const String& data, dword mask)
{
if(IsError())
return;
@ -437,7 +438,7 @@ void WebSocket::SendRaw(int hdr, const String& data)
header.Cat(hdr);
int len = data.GetCount();
if(len > 65535) {
header.Cat(127);
header.Cat(127 | mask);
header.Cat(0);
header.Cat(0);
header.Cat(0);
@ -456,11 +457,28 @@ void WebSocket::SendRaw(int hdr, const String& data)
else
header.Cat((int)len);
Out(header);
if(mask) {
byte Cle[4];
for(int i = 0; i < 4; i++)
header.Cat(Cle[i] = (byte)Random());
if(data.GetCount() == 0)
return;
Out(data);
Out(header);
if(data.GetCount()) {
StringBuffer buf(data.GetCount());
int n = data.GetCount();
for(int i = 0; i < n; i++)
buf[i] = data[i] ^ Cle[i & 3];
Out(buf);
}
}
else {
Out(header);
if(data.GetCount() == 0)
return;
Out(data);
}
}
bool WebSocket::WebAccept(TcpSocket& socket_, HttpHeader& hdr)

View file

@ -1,4 +1,5 @@
topic "WebSocket";
[2 $$0,0#00000000000000000000000000000000:Default]
[i448;a25;kKO9;2 $$1,0#37138531426314131252341829483380:class]
[l288;2 $$2,2#27521748481378242620020725143825:desc]
[0 $$3,0#96390100711032703541132217272105:end]
@ -8,7 +9,6 @@ topic "WebSocket";
[l288;i1121;b17;O9;~~~.1408;2 $$7,0#10431211400427159095818037425705:param]
[i448;b42;O9;2 $$8,8#61672508125594000341940100500538:tparam]
[b42;2 $$9,9#13035079074754324216151401829390:normal]
[2 $$0,0#00000000000000000000000000000000:Default]
[{_}
[ {{10000@(113.42.0) [s0;%% [*@7;4 WebSocket]]}}&]
[s3; &]
@ -24,6 +24,11 @@ topic "WebSocket";
is blocking mode.&]
[s3; &]
[s4; &]
[s5;:Upp`:`:WebSocket`:`:RequestHeader`(const Upp`:`:String`&`): WbeSocket[@(0.0.255) `&
]_[* RequestHeader]([@(0.0.255) const]_[_^Upp`:`:String^ String][@(0.0.255) `&]_[*@3 s])&]
[s2;%% Overrides the HTTP the header to be used with Connect.&]
[s3;%% &]
[s4; &]
[s5;:Upp`:`:WebSocket`:`:IsBlocking`(`)const: [@(0.0.255) bool]_[* IsBlocking]()_[@(0.0.255) c
onst]&]
[s2;%% Returns true if WebSocket is in the blocking mode.&]
@ -82,6 +87,11 @@ calls Do, so there is no need to call it separately.&]
[s2;%% Sends a single frame (non`-fragmented) text message.&]
[s3;%% &]
[s4; &]
[s5;:Upp`:`:WebSocket`:`:SendTextMasked`(const Upp`:`:String`&`): [@(0.0.255) void]_[* Se
ndTextMasked]([@(0.0.255) const]_[_^Upp`:`:String^ String][@(0.0.255) `&]_[*@3 data])&]
[s2;%% Sends masked text message.&]
[s3;%% &]
[s4; &]
[s5;:Upp`:`:WebSocket`:`:SendBinary`(const Upp`:`:String`&`): [@(0.0.255) void]_[* SendBi
nary]([@(0.0.255) const]_[_^Upp`:`:String^ String][@(0.0.255) `&]_[*@3 data])&]
[s2;%% Sends a single frame (non`-fragmented) binary message.&]