lib::error_code process_handshake(request_type const & req, std::string const & subprotocol, response_type & res) const { std::array<char, 16> key_final; // copy key1 into final key decode_client_key(req.get_header("Sec-WebSocket-Key1"), &key_final[0]); // copy key2 into final key decode_client_key(req.get_header("Sec-WebSocket-Key2"), &key_final[4]); // copy key3 into final key // key3 should be exactly 8 bytes. If it is more it will be truncated // if it is less the final key will almost certainly be wrong. // TODO: decide if it is best to silently fail here or produce some sort // of warning or exception. const std::string& key3 = req.get_header("Sec-WebSocket-Key3"); auto sz = std::min(size_t(8), key3.size()); std::copy(key3.begin(), key3.begin() + sz, key_final.begin() + 8); res.append_header( "Sec-WebSocket-Key3", md5::md5_hash_string(std::string(key_final.begin(), key_final.end())) ); res.append_header("Upgrade","WebSocket"); res.append_header("Connection","Upgrade"); // Echo back client's origin unless our local application set a // more restrictive one. if (res.get_header("Sec-WebSocket-Origin") == "") { res.append_header("Sec-WebSocket-Origin",req.get_header("Origin")); } // Echo back the client's request host unless our local application // set a different one. if (res.get_header("Sec-WebSocket-Location") == "") { uri_ptr uri = get_uri(req); res.append_header("Sec-WebSocket-Location",uri->str()); } if (subprotocol != "") { res.replace_header("Sec-WebSocket-Protocol",subprotocol); } return lib::error_code(); }
/** * @param req The original request sent * @param res The reponse to generate * @return An error code, 0 on success, non-zero for other errors */ lib::error_code validate_server_handshake_response(request_type const & req, response_type& res) const { // A valid response has an HTTP 101 switching protocols code if (res.get_status_code() != http::status_code::switching_protocols) { return error::make_error_code(error::invalid_http_status); } // And the upgrade token in an upgrade header std::string const & upgrade_header = res.get_header("Upgrade"); if (utility::ci_find_substr(upgrade_header, constants::upgrade_token, sizeof(constants::upgrade_token)-1) == upgrade_header.end()) { return error::make_error_code(error::missing_required_header); } // And the websocket token in the connection header std::string const & con_header = res.get_header("Connection"); if (utility::ci_find_substr(con_header, constants::connection_token, sizeof(constants::connection_token)-1) == con_header.end()) { return error::make_error_code(error::missing_required_header); } // And has a valid Sec-WebSocket-Accept value std::string key = req.get_header("Sec-WebSocket-Key"); lib::error_code ec = process_handshake_key(key); if (ec || key != res.get_header("Sec-WebSocket-Accept")) { return error::make_error_code(error::missing_required_header); } return lib::error_code(); }
request_type (request_type & packet) { setPCode (packet.getPCode ()); server_flag = packet.server_flag; area = packet.area; key.clone (packet.key); }
lib::error_code extract_subprotocols(request_type const & req, std::vector<std::string> & subprotocol_list) { if (!req.get_header("Sec-WebSocket-Protocol").empty()) { http::parameter_list p; if (!req.get_header_as_plist("Sec-WebSocket-Protocol",p)) { http::parameter_list::const_iterator it; for (it = p.begin(); it != p.end(); ++it) { subprotocol_list.push_back(it->first); } } else { return error::make_error_code(error::subprotocol_parse_error); } } return lib::error_code(); }
lib::error_code validate_handshake(request_type const & r) const { if (r.get_method() != "GET") { return make_error_code(error::invalid_http_method); } if (r.get_version() != "HTTP/1.1") { return make_error_code(error::invalid_http_version); } // required headers // Host is required by HTTP/1.1 // Connection is required by is_websocket_handshake // Upgrade is required by is_websocket_handshake if (r.get_header("Sec-WebSocket-Key") == "") { return make_error_code(error::missing_required_header); } return lib::error_code(); }
lib::error_code validate_handshake(request_type const & r) const { if (r.get_method() != "get") { return make_error_code(error::invalid_http_method); } if (r.get_version() != "http/1.1") { return make_error_code(error::invalid_http_version); } // required headers // host is required by http/1.1 // connection is required by is_websocket_handshake // upgrade is required by is_websocket_handshake if (r.get_header("sec-websocket-key") == "") { return make_error_code(error::missing_required_header); } return lib::error_code(); }
uri_ptr get_uri(request_type const & request) const { std::string h = request.get_header("Host"); size_t last_colon = h.rfind(":"); size_t last_sbrace = h.rfind("]"); // no : = hostname with no port // last : before ] = ipv6 literal with no port // : with no ] = hostname with port // : after ] = ipv6 literal with port if (last_colon == std::string::npos || (last_sbrace != std::string::npos && last_sbrace > last_colon)) { return uri_ptr(new uri(base::m_secure, h, request.get_uri())); } else { return uri_ptr(new uri(base::m_secure, h.substr(0,last_colon), h.substr(last_colon+1), request.get_uri())); } // TODO: check if get_uri is a full uri }
lib::error_code client_handshake_request(request_type& req, uri_ptr uri, std::vector<std::string> const & subprotocols) const { req.set_method("GET"); req.set_uri(uri->get_resource()); req.set_version("HTTP/1.1"); req.append_header("Upgrade", "websocket"); req.append_header("Connection", "Upgrade"); req.replace_header("Sec-WebSocket-Version", "13"); req.replace_header("Host", uri->get_host_port()); if (!subprotocols.empty()) { std::ostringstream result; std::vector<std::string>::const_iterator it = subprotocols.begin(); result << *it++; while (it != subprotocols.end()) { result << ", " << *it++; } req.replace_header("Sec-WebSocket-Protocol", result.str()); } // Generate handshake key frame::uint32_converter conv; unsigned char raw_key[16]; for (int i = 0; i < 4; i++) { conv.i = m_rng(); std::copy(conv.c, conv.c + 4, &raw_key[i * 4]); } req.replace_header("Sec-WebSocket-Key", base64_encode(raw_key, 16)); return lib::error_code(); }
/* TODO: the 'subprotocol' parameter may need to be expanded into a more * generic struct if other user input parameters to the processed handshake * are found. */ lib::error_code process_handshake(request_type const & request, std::string const & subprotocol, response_type & response) const { std::string server_key = request.get_header("Sec-WebSocket-Key"); lib::error_code ec = process_handshake_key(server_key); if (ec) { return ec; } response.replace_header("Sec-WebSocket-Accept",server_key); response.append_header("Upgrade",constants::upgrade_token); response.append_header("Connection",constants::connection_token); if (!subprotocol.empty()) { response.replace_header("Sec-WebSocket-Protocol",subprotocol); } return lib::error_code(); }
void prepare_request(request_type &packet) { set_state(has_request); payload_length_ = packet.get_payload_length(); buffer_ = packet.get_buffer(); }
void prepare_request(request_type &packet) { set_state(has_request); buffer_ = packet.write(); }