File Coverage

src/panda/protocol/websocket/ConnectRequest.cc
Criterion Covered Total %
statement 60 68 88.2
branch 87 144 60.4
condition n/a
subroutine n/a
pod n/a
total 147 212 69.3


line stmt bran cond sub pod time code
1             #include "ConnectRequest.h"
2             #include "Error.h"
3             #include "ConnectResponse.h"
4             #include
5             #include
6              
7             namespace panda { namespace protocol { namespace websocket {
8              
9 241           void ConnectRequest::process_headers () {
10             bool ok;
11              
12 241 100         if (_method != Method::GET) {
13 1           error = errc::method_mustbe_get;
14 241           return;
15             }
16              
17 240 50         if (http_version != 11) {
18 0           error = errc::http_1_1_required;
19 0           return;
20             }
21              
22 240 50         if (!body.empty()) {
    50          
23 0           error = errc::body_prohibited;
24 0           return;
25             }
26              
27 240 50         auto it = headers.find("Connection");
28 720 50         if (it == headers.end() || !string_contains_ci(it->value, "upgrade")) {
    50          
    50          
    50          
    50          
    50          
    0          
    0          
29 0           error = errc::connection_mustbe_upgrade;
30 0           return;
31             }
32              
33 240 50         it = headers.find("Upgrade");
34 720 50         if (it == headers.end() || !string_contains_ci(it->value, "websocket")) {
    50          
    100          
    50          
    50          
    100          
    0          
    0          
35 2           error = errc::upgrade_mustbe_websocket;
36 2           return;
37             }
38              
39 238           ok = false;
40 238 50         it = headers.find("Sec-WebSocket-Key");
41 476 50         if (it != headers.end()) {
42 238 50         ws_key = it->value;
43 476 50         auto decoded = panda::encode::decode_base64(ws_key);
44 238 50         if (decoded.length() == 16) ok = true;
45             }
46 238 50         if (!ok) {
47 0           error = errc::sec_accept_missing;
48 0           return;
49             }
50              
51 238           _ws_version_supported = false;
52 238 50         it = headers.find("Sec-WebSocket-Version");
53 476 50         if (it != headers.end()) {
54 238 50         it->value.to_number(ws_version);
55 476 100         for (int v : supported_ws_versions) {
56 238 100         if (ws_version != v) continue;
57 235           _ws_version_supported = true;
58 235           break;
59             }
60             }
61 238 100         if (!_ws_version_supported) {
62 3           error = errc::unsupported_version;
63 3           return;
64             }
65              
66 235 50         auto ext_range = headers.get_multi("Sec-WebSocket-Extensions");
67 324 50         for (auto& val : ext_range) {
    50          
    50          
    100          
    50          
    50          
68 89 50         parse_header_value(val, _ws_extensions);
69             }
70              
71 235 50         ws_protocol = headers.get("Sec-WebSocket-Protocol");
    50          
72             }
73              
74 88           void ConnectRequest::add_deflate(const DeflateExt::Config& cfg) {
75 88           DeflateExt::request(_ws_extensions, cfg);
76 88           }
77              
78 105           string ConnectRequest::to_string() {
79 105 50         if (!uri || !uri->host()) {
    100          
    100          
80 1           throw Error("HTTPRequest[to_string] uri with net location must be defined");
81             }
82 104 50         if (uri && uri->scheme() && uri->scheme() != "ws" && uri->scheme() != "wss") {
    50          
    100          
    100          
    100          
83 1           throw Error("ConnectRequest[to_string] uri scheme must be 'ws' or 'wss'");
84             }
85 103 100         if (body.length()) {
86 1           throw Error("ConnectRequest[to_string] http body is not allowed for websocket handshake request");
87             }
88              
89 102           _method = Request::Method::GET;
90              
91 102 100         if (!ws_key) {
92 23           int32_t keybuf[] = {std::rand(), std::rand(), std::rand(), std::rand()};
93 23 50         ws_key = panda::encode::encode_base64(string_view((const char*)keybuf, sizeof(keybuf)), false, true);
    50          
94             }
95 102 50         headers.set("Sec-WebSocket-Key", ws_key);
96              
97 102 100         if (ws_protocol) headers.set("Sec-WebSocket-Protocol", ws_protocol);
    50          
98              
99 102 100         if (!ws_version) ws_version = 13;
100 102 50         headers.set("Sec-WebSocket-Version", string::from_number(ws_version));
101              
102 102 100         if (_ws_extensions.size()) headers.set("Sec-WebSocket-Extensions", compile_header_value(_ws_extensions));
    50          
103              
104 102 50         headers.set("Connection", "Upgrade");
105 102 50         headers.set("Upgrade", "websocket");
106              
107 102 50         if (!headers.has("User-Agent")) headers.add("User-Agent", "Panda-WebSocket");
    100          
    50          
108 102 50         if (!headers.has("Host")) headers.add("Host", uri->host());
    100          
    50          
109              
110 102           return http::Request::to_string();
111             }
112              
113 90           http::ResponseSP ConnectRequest::new_response() const{
114 90 50         return new ConnectResponse();
115             }
116              
117              
118             }}}