File Coverage

src/panda/protocol/websocket/ServerParser.cc
Criterion Covered Total %
statement 78 81 96.3
branch 81 146 55.4
condition n/a
subroutine n/a
pod n/a
total 159 227 70.0


line stmt bran cond sub pod time code
1             #include "ServerParser.h"
2             #include
3             #include
4              
5             namespace panda { namespace protocol { namespace websocket {
6              
7             struct RequestFactory : http::RequestParser::IFactory {
8 244           http::RequestSP new_request () override {
9 244           return make_iptr();
10             }
11             };
12              
13             static RequestFactory request_factory;
14              
15 238 50         ServerParser::ServerParser (const Parser::Config& cfg) : Parser(true, cfg), _connect_parser(&request_factory) {
    50          
    50          
    0          
    0          
    0          
16 119           _connect_parser.max_body_size = 0;
17 119           }
18              
19 316           ConnectRequestSP ServerParser::accept (string& buf) {
20 316 50         if (_flags[ACCEPT_PARSED]) throw Error("already parsed accept");
21 316           _connect_parser.max_headers_size = _max_handshake_size;
22              
23 632 50         http::RequestParser::Result res = _connect_parser.parse(buf);
24 316 50         _connect_request = dynamic_pointer_cast(res.request);
25              
26 316 100         if (res.error) {
27 3 50         _flags.set(ACCEPT_PARSED);
28 3 50         _connect_request->error = res.error;
29 3           return _connect_request;
30 313 100         } else if (res.state != http::State::done) {
31 72           return nullptr;
32             }
33              
34 241 50         _connect_request->process_headers();
35 241 50         _flags.set(ACCEPT_PARSED);
36              
37 241 100         if (!_connect_request->error) {
38 235 50         if (res.position != buf.size()) {
39 0           _connect_request->error = errc::garbage_after_connect;
40             } else {
41 235 50         _flags.set(ACCEPTED);
42             }
43             }
44              
45 241           return _connect_request;
46             }
47              
48 7           string ServerParser::accept_error () {
49 7 50         if (!_flags[ACCEPT_PARSED]) throw Error("accept not parsed yet");
50 7 50         if (established()) throw Error("already established");
51 7 50         if (!_connect_request->error) throw Error("no errors found");
52              
53 14 50         http::ResponseSP res = new http::Response();
    50          
54 7 50         res->headers.add("Content-Type", "text/plain");
55              
56 7 100         if (!_connect_request->ws_version_supported()) {
57 3           res->code = 426;
58 3 50         res->message = "Upgrade Required";
59 6           res->body.parts.push_back("426 Upgrade Required");
60              
61 6 50         string svers(50);
62 6 100         for (int v : supported_ws_versions) {
63 3 50         svers += string::from_number(v);
    50          
64 3 50         svers += ", ";
65             }
66 3 50         if (svers) svers.length(svers.length()-2);
67 3 50         res->headers.add("Sec-WebSocket-Version", svers);
68             }
69             else {
70 4           res->code = 400;
71 4 50         res->message = "Bad Request";
72 8           res->body.parts.push_back("400 Bad Request\n");
73 8 50         res->body.parts.push_back(_connect_request->error.what());
74             }
75 7 50         res->headers.set("Content-Length", panda::to_string(res->body.length()));
    50          
    50          
76              
77 14 50         return res->to_string(_connect_request);
78             }
79              
80 3           string ServerParser::accept_error (http::Response* res) {
81 3 50         if (!_flags[ACCEPT_PARSED]) throw Error("accept not parsed yet");
82 3 50         if (established()) throw Error("already established");
83 3 100         if (_connect_request->error) return accept_error();
84              
85 2 50         if (!res->code) {
86 0           res->code = 400;
87 0           res->message = "Bad Request";
88             }
89 2 50         else if (!res->message) res->message = "Unknown";
90              
91 2 100         if (res->body.empty()) {
92 2 50         res->body.parts.push_back(string::from_number(res->code) + ' ' + res->message);
    50          
93             }
94              
95 2 50         if (!res->headers.has("Content-Type")) res->headers.add("Content-Type", "text/plain");
    50          
    50          
96 2 50         if (!res->headers.has("Content-Length")) res->headers.add("Content-Length", panda::to_string(res->body.length()));
    50          
    50          
97              
98 3           return res->to_string(_connect_request);
99             }
100              
101 228           string ServerParser::accept_response (ConnectResponse* res) {
102 228 50         if (!accepted()) throw Error("client has not been accepted");
103 228 50         if (established()) throw Error("already established");
104              
105 228 50         res->_ws_key = _connect_request->ws_key;
106 228 100         if (!res->ws_protocol) res->ws_protocol = _connect_request->ws_protocol;
    50          
107 228 100         if (!res->ws_extensions_set()) res->ws_extensions(_connect_request->ws_extensions());
    50          
108              
109 228           const auto& exts = res->ws_extensions();
110 456           HeaderValues used_extensions;
111 228 100         if (_deflate_cfg && exts.size()) {
    100          
    100          
112             // filter extensions
113 87           auto role = DeflateExt::Role::SERVER;
114 87 50         auto deflate_matches = DeflateExt::select(exts, *_deflate_cfg, role);
115 87 100         if (deflate_matches) {
116 87 50         _deflate_ext.reset(DeflateExt::uplift(deflate_matches, used_extensions, role));
117             }
118             }
119 228 50         res->ws_extensions(std::move(used_extensions));
120              
121 228 50         _flags.set(ESTABLISHED);
122 228           _connect_request = NULL;
123 456 50         return res->to_string();
124             }
125              
126 131           void ServerParser::reset () {
127 131           _connect_request = NULL;
128 131           _connect_parser.reset();
129 131           Parser::reset();
130 131           }
131              
132 432 50         ServerParser::~ServerParser() {}
    50          
    0          
    0          
133              
134             }}}