#include "ClientParser.h"
#include <ctime>
#include <cstdlib>
#include <exception>
namespace panda { namespace protocol { namespace websocket {
static bool _init () {
std::srand(std::time(NULL));
return true;
}
static const bool _inited = _init();
string ClientParser::connect_request (const ConnectRequestSP& req) {
if (_flags[CONNECTION_REQUESTED]) throw Error("already requested connection");
_flags.set(CONNECTION_REQUESTED);
_connect_request = req;
_connect_response_parser.set_context_request(req);
if (_deflate_cfg) req->add_deflate(*_deflate_cfg);
return req->to_string();
}
ConnectResponseSP ClientParser::connect (const string& buf) {
if (!_flags[CONNECTION_REQUESTED]) throw Error("has not requested connection");
if (_flags[CONNECTION_RESPONSE_PARSED]) throw Error("already parsed connect response");
_connect_response_parser.max_headers_size = _max_handshake_size;
http::ResponseParser::Result res = _connect_response_parser.parse(buf);
_connect_response = dynamic_pointer_cast<ConnectResponse>(res.response);
if (res.error) {
_connect_response->error(res.error);
_flags.set(CONNECTION_RESPONSE_PARSED);
ConnectResponseSP ret(_connect_response);
_connect_request = NULL;
_connect_response = NULL;
return ret;
}
else if (res.state != http::State::done) {
return nullptr;
}
_connect_response->_ws_key = _connect_request->ws_key();
_connect_response->process_headers();
_flags.set(CONNECTION_RESPONSE_PARSED);
if (!_connect_response->error() && _deflate_cfg) {
using result_t = DeflateExt::EffectiveConfig::NegotiationsResult;
auto& exts = _connect_response->ws_extensions();
HeaderValues used_extensions;
auto role = DeflateExt::Role::CLIENT;
auto deflate_matches = DeflateExt::select(exts, *_deflate_cfg, role);
switch (deflate_matches.result) {
case result_t::Success:
_deflate_ext.reset(DeflateExt::uplift(deflate_matches, used_extensions, role));
_connect_response->ws_extensions(used_extensions);
break;
case result_t::NotFound:
/* NOOP */
break;
case result_t::Error:
_connect_response->error(errc::deflate_negotiation_failed);
}
}
if (!_connect_response->error()) {
_buffer = buf.substr(res.position);// if something remains in buf, user can get it via get_frames() or get_messages() without buf param.
_flags.set(ESTABLISHED);
}
ConnectResponseSP ret(_connect_response);
_connect_request = NULL;
_connect_response = NULL;
return ret;
}
void ClientParser::reset () {
_connect_request = NULL;
_connect_response_parser.reset();
Parser::reset();
}
}}}