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 632 : std::optional<url_components> parse_websocket_url(const std::string& url) {
12 : // Longer URLs are refused before the regex, whose matching recurses per character in
13 : // libstdc++
14 632 : if (url.size() > 8192) return std::nullopt;
15 : // Compiled once (thread-safe), not on every call
16 629 : static const std::regex url_regex(R"(^(wss?)://([^/:]+)(?::(\d+))?(/.*)?$)", std::regex::icase);
17 629 : std::smatch match;
18 :
19 629 : if (!std::regex_match(url, match, url_regex)) {
20 316 : return std::nullopt;
21 : }
22 :
23 313 : url_components result;
24 313 : result.scheme = match[1].str();
25 313 : result.host = match[2].str();
26 313 : result.secure = (result.scheme == "wss" || result.scheme == "WSS");
27 355 : result.port = match[3].matched ? match[3].str() : (result.secure ? "443" : "80");
28 313 : result.path = match[4].matched ? match[4].str() : "/";
29 :
30 313 : return result;
31 629 : }
32 :
33 310 : std::string generate_websocket_key() {
34 310 : std::random_device rd;
35 310 : std::mt19937 gen(rd());
36 310 : std::uniform_int_distribution<> dis(0, 255);
37 :
38 : std::array<uint8_t, 16> bytes;
39 5270 : for (auto& b : bytes) {
40 4960 : b = static_cast<uint8_t>(dis(gen));
41 : }
42 :
43 930 : return ::thinger::util::base64::encode(bytes.data(), bytes.size());
44 310 : }
45 :
46 307 : std::string accept_key(const std::string& sent_key) {
47 307 : std::string sha1_hash = ::thinger::util::sha1::hash(sent_key + WS_GUID);
48 : return ::thinger::util::base64::encode(
49 307 : reinterpret_cast<const unsigned char*>(sha1_hash.data()),
50 : sha1_hash.size()
51 921 : );
52 307 : }
53 :
54 265 : bool validate_accept_key(const std::string& accept_key, const std::string& sent_key) {
55 265 : return accept_key == websocket_util::accept_key(sent_key);
56 : }
57 :
58 : } // namespace thinger::http::websocket_util
|