#include "ConnectResponse.h"
#include "Error.h"
#include "utils.h"
#include <openssl/sha.h>
#include <panda/encode/base64.h>
namespace panda { namespace protocol { namespace websocket {
void ConnectResponse::process_headers () {
if (code == 426) {
_ws_version = headers.get("Sec-WebSocket-Version");
_error = errc::unsupported_version;
return;
}
if (code != 101) {
_error = errc::response_code_101;
return;
}
auto it = headers.find("Connection");
if (it == headers.end() || !string_contains_ci(it->value, "upgrade")) {
_error = errc::connection_mustbe_upgrade;
return;
}
it = headers.find("Upgrade");
if (it == headers.end() || !string_contains_ci(it->value, "websocket")) {
_error = errc::upgrade_mustbe_websocket;
return;
}
it = headers.find("Sec-WebSocket-Accept");
if (it == headers.end() || it->value != _calc_accept_key(_ws_key)) {
_error = errc::sec_accept_missing;
return;
}
else _ws_accept_key = it->value;
auto ext_range = headers.get_multi("Sec-WebSocket-Extensions");
for (auto& val : ext_range) {
parse_header_value(val, _ws_extensions);
}
_ws_protocol = headers.get("Sec-WebSocket-Protocol");
}
string ConnectResponse::_calc_accept_key (string ws_key) {
auto key_base = ws_key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
unsigned char sha1bin[21];
SHA1((const unsigned char*)key_base.data(), key_base.length(), sha1bin);
return panda::encode::encode_base64(string_view((const char*)sha1bin, 20), false, true);
}
string ConnectResponse::to_string() {
code = 101;
message = "Switching Protocols";
headers.add("Upgrade", "websocket");
headers.add("Connection", "Upgrade");
if (_ws_protocol) headers.add("Sec-WebSocket-Protocol", _ws_protocol);
headers.add("Sec-WebSocket-Accept", _calc_accept_key(_ws_key));
if (!headers.has("Server")) headers.add("Server", "Panda-WebSocket");
if (_ws_extensions.size()) headers.add("Sec-WebSocket-Extensions", compile_header_value(_ws_extensions));
body.parts.clear(); // body not supported in WS responses
return http::Response::to_string();
}
}}}