Line data Source code
1 : #include "websocket_util.hpp"
2 : #include "../../util/base64.hpp"
3 : #include "../../util/sha1.hpp"
4 :
5 : #include <random>
6 : #include <regex>
7 : #include <array>
8 :
9 : namespace thinger::http::websocket_util {
10 :
11 84 : std::optional<url_components> parse_websocket_url(const std::string& url) {
12 84 : std::regex url_regex(R"(^(wss?)://([^/:]+)(?::(\d+))?(/.*)?$)", std::regex::icase);
13 84 : std::smatch match;
14 :
15 84 : if (!std::regex_match(url, match, url_regex)) {
16 42 : return std::nullopt;
17 : }
18 :
19 42 : url_components result;
20 42 : result.scheme = match[1].str();
21 42 : result.host = match[2].str();
22 42 : result.secure = (result.scheme == "wss" || result.scheme == "WSS");
23 42 : result.port = match[3].matched ? match[3].str() : (result.secure ? "443" : "80");
24 42 : result.path = match[4].matched ? match[4].str() : "/";
25 :
26 42 : return result;
27 84 : }
28 :
29 38 : std::string generate_websocket_key() {
30 38 : std::random_device rd;
31 38 : std::mt19937 gen(rd());
32 38 : std::uniform_int_distribution<> dis(0, 255);
33 :
34 : std::array<uint8_t, 16> bytes;
35 646 : for (auto& b : bytes) {
36 608 : b = static_cast<uint8_t>(dis(gen));
37 : }
38 :
39 114 : return ::thinger::util::base64::encode(bytes.data(), bytes.size());
40 38 : }
41 :
42 38 : bool validate_accept_key(const std::string& accept_key, const std::string& sent_key) {
43 38 : std::string combined = sent_key + WS_GUID;
44 38 : std::string sha1_hash = ::thinger::util::sha1::hash(combined);
45 : std::string expected = ::thinger::util::base64::encode(
46 38 : reinterpret_cast<const unsigned char*>(sha1_hash.data()),
47 : sha1_hash.size()
48 76 : );
49 76 : return accept_key == expected;
50 38 : }
51 :
52 : } // namespace thinger::http::websocket_util
|