28 #ifndef WEBSOCKETPP_CONNECTION_IMPL_HPP 29 #define WEBSOCKETPP_CONNECTION_IMPL_HPP 31 #include <websocketpp/processors/hybi00.hpp> 32 #include <websocketpp/processors/hybi07.hpp> 33 #include <websocketpp/processors/hybi08.hpp> 34 #include <websocketpp/processors/hybi13.hpp> 36 #include <websocketpp/processors/processor.hpp> 38 #include <websocketpp/common/platforms.hpp> 39 #include <websocketpp/common/system_error.hpp> 50 namespace istate = session::internal_state;
52 template <
typename config>
54 termination_handler new_handler)
57 "connection set_termination_handler");
61 m_termination_handler = new_handler;
64 template <
typename config>
67 return m_processor->get_origin(m_request);
70 template <
typename config>
73 return m_send_buffer_size;
76 template <
typename config>
82 template <
typename config>
84 frame::opcode::value op)
86 message_ptr msg = m_msg_manager->get_message(op,payload.size());
87 msg->append_payload(payload);
88 msg->set_compressed(
true);
93 template <
typename config>
95 frame::opcode::value op)
97 message_ptr msg = m_msg_manager->get_message(op,len);
98 msg->append_payload(payload,len);
103 template <
typename config>
111 scoped_lock_type lock(m_connection_state_lock);
112 if (m_state != session::state::open) {
117 message_ptr outgoing_msg;
118 bool needs_writing =
false;
120 if (msg->get_prepared()) {
123 scoped_lock_type lock(m_write_lock);
124 write_push(outgoing_msg);
125 needs_writing = !m_write_flag && !m_send_queue.empty();
127 outgoing_msg = m_msg_manager->get_message();
133 scoped_lock_type lock(m_write_lock);
134 lib::error_code ec = m_processor->prepare_data_frame(msg,outgoing_msg);
140 write_push(outgoing_msg);
141 needs_writing = !m_write_flag && !m_send_queue.empty();
145 transport_con_type::dispatch(lib::bind(
151 return lib::error_code();
154 template <
typename config>
161 scoped_lock_type lock(m_connection_state_lock);
162 if (m_state != session::state::open) {
163 std::stringstream ss;
164 ss <<
"connection::ping called from invalid state " << m_state;
171 message_ptr msg = m_msg_manager->get_message();
177 ec = m_processor->prepare_ping(payload,msg);
181 if (m_pong_timeout_handler) {
184 m_ping_timer->cancel();
187 if (m_pong_timeout_dur > 0) {
188 m_ping_timer = transport_con_type::set_timer(
191 &type::handle_pong_timeout,
194 lib::placeholders::_1
202 set but the transport in use does not support timeouts.");
206 bool needs_writing =
false;
208 scoped_lock_type lock(m_write_lock);
210 needs_writing = !m_write_flag && !m_send_queue.empty();
214 transport_con_type::dispatch(lib::bind(
220 ec = lib::error_code();
223 template<
typename config>
232 template<
typename config>
234 lib::error_code
const & ec)
246 if (m_pong_timeout_handler) {
247 m_pong_timeout_handler(m_connection_hdl,payload);
251 template <
typename config>
258 scoped_lock_type lock(m_connection_state_lock);
259 if (m_state != session::state::open) {
260 std::stringstream ss;
261 ss <<
"connection::pong called from invalid state " << m_state;
268 message_ptr msg = m_msg_manager->get_message();
274 ec = m_processor->prepare_pong(payload,msg);
277 bool needs_writing =
false;
279 scoped_lock_type lock(m_write_lock);
281 needs_writing = !m_write_flag && !m_send_queue.empty();
285 transport_con_type::dispatch(lib::bind(
291 ec = lib::error_code();
294 template<
typename config>
303 template <
typename config>
305 std::string
const & reason, lib::error_code & ec)
312 std::string tr(reason,0,std::min<size_t>(reason.size(),
315 scoped_lock_type lock(m_connection_state_lock);
317 if (m_state != session::state::open) {
325 template<
typename config>
327 std::string
const & reason)
330 close(code,reason,ec);
340 template <
typename config>
343 return transport_con_type::interrupt(
345 &type::handle_interrupt,
352 template <
typename config>
354 if (m_interrupt_handler) {
355 m_interrupt_handler(m_connection_hdl);
359 template <
typename config>
362 return transport_con_type::dispatch(
364 &type::handle_pause_reading,
371 template <
typename config>
377 template <
typename config>
380 return transport_con_type::dispatch(
382 &type::handle_resume_reading,
389 template <
typename config>
405 template <
typename config>
408 return m_uri->get_secure();
411 template <
typename config>
414 return m_uri->get_host();
417 template <
typename config>
420 return m_uri->get_resource();
423 template <
typename config>
426 return m_uri->get_port();
429 template <
typename config>
435 template <
typename config>
446 template <
typename config>
448 return m_subprotocol;
451 template <
typename config>
452 std::vector<std::string>
const &
454 return m_requested_subprotocols;
457 template <
typename config>
459 lib::error_code & ec)
467 if (value.empty() || std::find_if(value.begin(),value.end(),
474 m_requested_subprotocols.push_back(value);
477 template <
typename config>
480 this->add_subprotocol(value,ec);
487 template <
typename config>
489 lib::error_code & ec)
497 ec = lib::error_code();
501 std::vector<std::string>::iterator it;
503 it = std::find(m_requested_subprotocols.begin(),
504 m_requested_subprotocols.end(),
507 if (it == m_requested_subprotocols.end()) {
512 m_subprotocol =
value;
515 template <
typename config>
518 this->select_subprotocol(value,ec);
525 template <
typename config>
528 return m_request.get_header(key);
531 template <
typename config>
534 return m_request.get_body();
537 template <
typename config>
540 return m_response.get_header(key);
544 template <
typename config>
547 if (m_internal_state != istate::PROCESS_HTTP_REQUEST) {
548 throw exception(
"Call to set_status from invalid state",
551 m_response.set_status(code);
555 template <
typename config>
557 std::string
const & msg)
559 if (m_internal_state != istate::PROCESS_HTTP_REQUEST) {
560 throw exception(
"Call to set_status from invalid state",
564 m_response.set_status(code,msg);
568 template <
typename config>
570 if (m_internal_state != istate::PROCESS_HTTP_REQUEST) {
571 throw exception(
"Call to set_status from invalid state",
575 m_response.set_body(value);
579 template <
typename config>
581 std::string
const & val)
584 if (m_internal_state == istate::PROCESS_HTTP_REQUEST) {
586 m_response.append_header(key,val);
588 throw exception(
"Call to append_header from invalid state",
592 if (m_internal_state == istate::USER_INIT) {
594 m_request.append_header(key,val);
596 throw exception(
"Call to append_header from invalid state",
603 template <
typename config>
605 std::string
const & val)
608 if (m_internal_state == istate::PROCESS_HTTP_REQUEST) {
610 m_response.replace_header(key,val);
612 throw exception(
"Call to replace_header from invalid state",
616 if (m_internal_state == istate::USER_INIT) {
618 m_request.replace_header(key,val);
620 throw exception(
"Call to replace_header from invalid state",
627 template <
typename config>
631 if (m_internal_state == istate::PROCESS_HTTP_REQUEST) {
633 m_response.remove_header(key);
635 throw exception(
"Call to remove_header from invalid state",
639 if (m_internal_state == istate::USER_INIT) {
641 m_request.remove_header(key);
643 throw exception(
"Call to remove_header from invalid state",
660 template <
typename config>
664 if (m_handshake_timer) {
665 m_handshake_timer->cancel();
666 m_handshake_timer.reset();
670 m_http_state = session::http_state::deferred;
672 return lib::error_code();
685 template <
typename config>
688 scoped_lock_type lock(m_connection_state_lock);
689 if (m_http_state != session::http_state::deferred) {
694 m_http_state = session::http_state::body_written;
697 this->write_http_response(lib::error_code());
698 ec = lib::error_code();
701 template <
typename config>
704 this->send_http_response(ec);
715 template <
typename config>
719 if (m_internal_state != istate::USER_INIT) {
725 m_internal_state = istate::TRANSPORT_INIT;
730 transport_con_type::init(
732 &type::handle_transport_init,
734 lib::placeholders::_1
739 template <
typename config>
743 lib::error_code ecm = ec;
745 if (m_internal_state != istate::TRANSPORT_INIT) {
747 "handle_transport_init must be called from transport init state");
753 s <<
"handle_transport_init received error: "<< ecm.message();
756 this->terminate(ecm);
762 m_internal_state = istate::READ_HTTP_REQUEST;
763 this->read_handshake(1);
767 m_internal_state = istate::WRITE_HTTP_REQUEST;
768 m_processor = get_processor(config::client_version);
769 this->send_http_request();
773 template <
typename config>
777 if (m_open_handshake_timeout_dur > 0) {
778 m_handshake_timer = transport_con_type::set_timer(
779 m_open_handshake_timeout_dur,
781 &type::handle_open_handshake_timeout,
783 lib::placeholders::_1
788 transport_con_type::async_read_at_least(
791 config::connection_read_buffer_size,
793 &type::handle_read_handshake,
795 lib::placeholders::_1,
796 lib::placeholders::_2
803 template <
typename config>
805 size_t bytes_transferred)
809 lib::error_code ecm = ec;
812 scoped_lock_type lock(m_connection_state_lock);
814 if (m_state == session::state::connecting) {
815 if (m_internal_state != istate::READ_HTTP_REQUEST) {
818 }
else if (m_state == session::state::closed) {
823 "handle_read_handshake invoked after connection was closed");
834 "got (expected) eof/state error from closed con");
839 this->terminate(ecm);
844 if (bytes_transferred > config::connection_read_buffer_size) {
850 size_t bytes_processed = 0;
852 bytes_processed = m_request.consume(m_buf,bytes_transferred);
856 m_response.set_status(e.m_error_code,e.m_error_msg);
863 if (bytes_processed > bytes_transferred) {
871 s <<
"bytes_transferred: " << bytes_transferred
872 <<
" bytes, bytes processed: " << bytes_processed <<
" bytes";
876 if (m_request.ready()) {
877 lib::error_code processor_ec = this->initialize_processor();
879 this->write_http_response_error(processor_ec);
883 if (m_processor && m_processor->get_version() == 0) {
886 if (bytes_transferred-bytes_processed >= 8) {
887 m_request.replace_header(
888 "Sec-WebSocket-Key3",
889 std::string(m_buf+bytes_processed,m_buf+bytes_processed+8)
891 bytes_processed += 8;
895 m_response.set_status(http::status_code::internal_server_error);
903 if (!m_request.get_header(
"Sec-WebSocket-Key3").empty()) {
912 std::copy(m_buf+bytes_processed,m_buf+bytes_transferred,m_buf);
913 m_buf_cursor = bytes_transferred-bytes_processed;
916 m_internal_state = istate::PROCESS_HTTP_REQUEST;
919 lib::error_code handshake_ec = this->process_handshake_request();
924 if (!m_is_http || m_http_state == session::http_state::init) {
925 this->write_http_response(handshake_ec);
929 transport_con_type::async_read_at_least(
932 config::connection_read_buffer_size,
934 &type::handle_read_handshake,
936 lib::placeholders::_1,
937 lib::placeholders::_2
948 template <
typename config>
950 if (m_internal_state != istate::READ_HTTP_REQUEST) {
952 "write_http_response_error called in invalid state");
957 m_internal_state = istate::PROCESS_HTTP_REQUEST;
959 this->write_http_response(ec);
964 template <
typename config>
966 size_t bytes_transferred)
970 lib::error_code ecm = ec;
972 if (!ecm && m_internal_state != istate::PROCESS_CONNECTION) {
980 if (m_state == session::state::closed) {
985 }
else if (m_state == session::state::closing && !m_is_server) {
989 terminate(lib::error_code());
997 if (m_state == session::state::closed) {
999 "handle_read_frame: got invalid istate in closed state");
1003 if (m_state == session::state::closed) {
1007 terminate(lib::error_code());
1015 log_err(echannel,
"handle_read_frame", ecm);
1016 this->terminate(ecm);
1030 std::stringstream s;
1031 s <<
"p = " << p <<
" bytes transferred = " << bytes_transferred;
1035 while (p < bytes_transferred) {
1037 std::stringstream s;
1038 s <<
"calling consume with " << bytes_transferred-p <<
" bytes";
1042 lib::error_code consume_ec;
1045 std::stringstream s;
1046 s <<
"Processing Bytes: " <<
utility::to_hex(reinterpret_cast<uint8_t*>(m_buf)+p,bytes_transferred-p);
1050 p += m_processor->consume(
1051 reinterpret_cast<uint8_t*>(m_buf)+p,
1052 bytes_transferred-p,
1057 std::stringstream s;
1058 s <<
"bytes left after consume: " << bytes_transferred-p;
1064 if (config::drop_on_protocol_error) {
1065 this->terminate(consume_ec);
1068 lib::error_code close_ec;
1071 consume_ec.message(),
1077 this->terminate(close_ec);
1084 if (m_processor->ready()) {
1086 std::stringstream s;
1087 s <<
"Complete message received. Dispatching";
1091 message_ptr msg = m_processor->get_message();
1095 }
else if (!is_control(msg->get_opcode())) {
1097 if (m_state != session::state::open) {
1099 }
else if (m_message_handler) {
1100 m_message_handler(m_connection_hdl, msg);
1103 process_control_frame(msg);
1112 template <
typename config>
1118 transport_con_type::async_read_at_least(
1128 config::connection_read_buffer_size,
1133 template <
typename config>
1139 return lib::error_code();
1146 m_response.set_status(http::status_code::bad_request);
1150 m_processor = get_processor(version);
1154 return lib::error_code();
1160 m_response.set_status(http::status_code::bad_request);
1162 std::stringstream ss;
1164 std::vector<int>::const_iterator it;
1171 m_response.replace_header(
"Sec-WebSocket-Version",ss.str());
1175 template <
typename config>
1186 (transport_con_type::is_secure() ?
"https" :
"http")
1189 if (!m_uri->get_valid()) {
1191 m_response.set_status(http::status_code::bad_request);
1195 if (m_http_handler) {
1197 m_http_handler(m_connection_hdl);
1199 if (m_state == session::state::closed) {
1203 set_status(http::status_code::upgrade_required);
1207 return lib::error_code();
1210 lib::error_code ec = m_processor->validate_handshake(m_request);
1216 m_response.set_status(http::status_code::bad_request);
1222 std::pair<lib::error_code,std::string> neg_results;
1223 neg_results = m_processor->negotiate_extensions(m_request);
1225 if (neg_results.first) {
1229 m_response.set_status(http::status_code::bad_request);
1230 return neg_results.first;
1235 if (neg_results.second.size() > 0) {
1236 m_response.replace_header(
"Sec-WebSocket-Extensions",
1237 neg_results.second);
1242 m_uri = m_processor->get_uri(m_request);
1245 if (!m_uri->get_valid()) {
1247 m_response.set_status(http::status_code::bad_request);
1252 lib::error_code subp_ec = m_processor->extract_subprotocols(m_request,
1253 m_requested_subprotocols);
1260 if (!m_validate_handler || m_validate_handler(m_connection_hdl)) {
1261 m_response.set_status(http::status_code::switching_protocols);
1265 ec = m_processor->process_handshake(m_request,m_subprotocol,m_response);
1268 std::stringstream s;
1269 s <<
"Processing error: " << ec <<
"(" << ec.message() <<
")";
1272 m_response.set_status(http::status_code::internal_server_error);
1282 if (m_response.get_status_code() == http::status_code::uninitialized) {
1283 m_response.set_status(http::status_code::bad_request);
1289 return lib::error_code();
1292 template <
typename config>
1301 if (m_response.get_status_code() == http::status_code::uninitialized) {
1302 m_response.
set_status(http::status_code::internal_server_error);
1308 m_response.set_version(
"HTTP/1.1");
1311 if (m_response.get_header(
"Server").empty()) {
1312 if (!m_user_agent.empty()) {
1313 m_response.replace_header(
"Server",m_user_agent);
1315 m_response.remove_header(
"Server");
1321 m_handshake_buffer = m_processor->get_raw(m_response);
1324 m_handshake_buffer = m_response.raw();
1329 if (!m_response.get_header(
"Sec-WebSocket-Key3").empty()) {
1336 transport_con_type::async_write(
1337 m_handshake_buffer.data(),
1338 m_handshake_buffer.size(),
1340 &type::handle_write_http_response,
1342 lib::placeholders::_1
1347 template <
typename config>
1351 lib::error_code ecm = ec;
1354 scoped_lock_type lock(m_connection_state_lock);
1356 if (m_state == session::state::connecting) {
1357 if (m_internal_state != istate::PROCESS_HTTP_REQUEST) {
1360 }
else if (m_state == session::state::closed) {
1365 "handle_write_http_response invoked after connection was closed");
1376 "got (expected) eof/state error from closed con");
1381 this->terminate(ecm);
1385 if (m_handshake_timer) {
1386 m_handshake_timer->cancel();
1387 m_handshake_timer.reset();
1390 if (m_response.get_status_code() != http::status_code::switching_protocols)
1397 std::stringstream s;
1398 s <<
"Handshake ended with HTTP error: " 1399 << m_response.get_status_code();
1405 this->log_http_result();
1409 "got to writing HTTP results with m_ec set: "+m_ec.message());
1414 this->terminate(m_ec);
1418 this->log_open_result();
1420 m_internal_state = istate::PROCESS_CONNECTION;
1421 m_state = session::state::open;
1423 if (m_open_handler) {
1424 m_open_handler(m_connection_hdl);
1427 this->handle_read_frame(lib::error_code(), m_buf_cursor);
1430 template <
typename config>
1440 ec = m_processor->client_handshake_request(m_request,m_uri,
1441 m_requested_subprotocols);
1453 if (m_request.get_header(
"User-Agent").empty()) {
1454 if (!m_user_agent.empty()) {
1455 m_request.replace_header(
"User-Agent",m_user_agent);
1457 m_request.remove_header(
"User-Agent");
1461 m_handshake_buffer = m_request.raw();
1467 if (m_open_handshake_timeout_dur > 0) {
1468 m_handshake_timer = transport_con_type::set_timer(
1469 m_open_handshake_timeout_dur,
1471 &type::handle_open_handshake_timeout,
1473 lib::placeholders::_1
1478 transport_con_type::async_write(
1479 m_handshake_buffer.data(),
1480 m_handshake_buffer.size(),
1482 &type::handle_send_http_request,
1484 lib::placeholders::_1
1489 template <
typename config>
1493 lib::error_code ecm = ec;
1496 scoped_lock_type lock(m_connection_state_lock);
1498 if (m_state == session::state::connecting) {
1499 if (m_internal_state != istate::WRITE_HTTP_REQUEST) {
1502 m_internal_state = istate::READ_HTTP_RESPONSE;
1504 }
else if (m_state == session::state::closed) {
1509 "handle_send_http_request invoked after connection was closed");
1520 "got (expected) eof/state error from closed con");
1525 this->terminate(ecm);
1529 transport_con_type::async_read_at_least(
1532 config::connection_read_buffer_size,
1534 &type::handle_read_http_response,
1536 lib::placeholders::_1,
1537 lib::placeholders::_2
1542 template <
typename config>
1544 size_t bytes_transferred)
1548 lib::error_code ecm = ec;
1551 scoped_lock_type lock(m_connection_state_lock);
1553 if (m_state == session::state::connecting) {
1554 if (m_internal_state != istate::READ_HTTP_RESPONSE) {
1557 }
else if (m_state == session::state::closed) {
1562 "handle_read_http_response invoked after connection was closed");
1573 "got (expected) eof/state error from closed con");
1578 this->terminate(ecm);
1582 size_t bytes_processed = 0;
1585 bytes_processed = m_response.consume(m_buf,bytes_transferred);
1588 std::string(
"error in handle_read_http_response: ")+e.what());
1595 if (m_response.headers_ready()) {
1596 if (m_handshake_timer) {
1597 m_handshake_timer->cancel();
1598 m_handshake_timer.reset();
1601 lib::error_code validate_ec = m_processor->validate_server_handshake_response(
1607 this->terminate(validate_ec);
1613 std::pair<lib::error_code,std::string> neg_results;
1614 neg_results = m_processor->negotiate_extensions(m_response);
1616 if (neg_results.first) {
1625 + neg_results.first.message());
1631 m_internal_state = istate::PROCESS_CONNECTION;
1632 m_state = session::state::open;
1634 this->log_open_result();
1636 if (m_open_handler) {
1637 m_open_handler(m_connection_hdl);
1643 std::copy(m_buf+bytes_processed,m_buf+bytes_transferred,m_buf);
1644 m_buf_cursor = bytes_transferred-bytes_processed;
1646 this->handle_read_frame(lib::error_code(), m_buf_cursor);
1648 transport_con_type::async_read_at_least(
1651 config::connection_read_buffer_size,
1653 &type::handle_read_http_response,
1655 lib::placeholders::_1,
1656 lib::placeholders::_2
1662 template <
typename config>
1664 lib::error_code
const & ec)
1670 "open handle_open_handshake_timeout error: "+ec.message());
1678 template <
typename config>
1680 lib::error_code
const & ec)
1686 "asio open handle_close_handshake_timeout error: "+ec.message());
1694 template <
typename config>
1701 if (m_handshake_timer) {
1702 m_handshake_timer->cancel();
1703 m_handshake_timer.reset();
1706 terminate_status tstat = unknown;
1710 m_local_close_reason = ec.message();
1715 m_http_state = session::http_state::closed;
1717 if (m_state == session::state::connecting) {
1718 m_state = session::state::closed;
1726 }
else if (m_state != session::state::closed) {
1727 m_state = session::state::closed;
1731 "terminate called on connection that was already terminated");
1737 transport_con_type::async_shutdown(
1739 &type::handle_terminate,
1742 lib::placeholders::_1
1747 template <
typename config>
1749 lib::error_code
const & ec)
1761 if (tstat == failed) {
1763 if (m_fail_handler) {
1764 m_fail_handler(m_connection_hdl);
1767 }
else if (tstat == closed) {
1768 if (m_close_handler) {
1769 m_close_handler(m_connection_hdl);
1779 if (m_termination_handler) {
1781 m_termination_handler(type::get_shared());
1782 }
catch (std::exception
const & e) {
1784 std::string(
"termination_handler call failed. Reason was: ")+e.what());
1789 template <
typename config>
1794 scoped_lock_type lock(m_write_lock);
1806 message_ptr next_message = write_pop();
1807 while (next_message) {
1808 m_current_msgs.push_back(next_message);
1809 if (!next_message->get_terminal()) {
1810 next_message = write_pop();
1812 next_message = message_ptr();
1816 if (m_current_msgs.empty()) {
1823 m_write_flag =
true;
1827 typename std::vector<message_ptr>::iterator it;
1828 for (it = m_current_msgs.begin(); it != m_current_msgs.end(); ++it) {
1829 std::string
const & header = (*it)->get_header();
1830 std::string
const & payload = (*it)->get_payload();
1839 std::stringstream general,header,payload;
1841 general <<
"Dispatching write containing " << m_current_msgs.size()
1842 <<
" message(s) containing ";
1843 header <<
"Header Bytes: \n";
1844 payload <<
"Payload Bytes: \n";
1849 for (
size_t i = 0; i < m_current_msgs.size(); i++) {
1850 hbytes += m_current_msgs[i]->get_header().size();
1851 pbytes += m_current_msgs[i]->get_payload().size();
1854 header <<
"[" << i <<
"] (" 1855 << m_current_msgs[i]->get_header().size() <<
") " 1860 payload <<
"[" << i <<
"] (" 1861 << m_current_msgs[i]->get_payload().size() <<
") ["<<m_current_msgs[i]->get_opcode()<<
"] " 1862 << (m_current_msgs[i]->get_opcode() == frame::opcode::text ?
1863 m_current_msgs[i]->get_payload() :
1871 general << hbytes <<
" header bytes and " << pbytes <<
" payload bytes";
1879 transport_con_type::async_write(
1881 m_write_frame_handler
1885 template <
typename config>
1892 bool terminal = m_current_msgs.back()->get_terminal();
1894 m_send_buffer.clear();
1895 m_current_msgs.clear();
1900 this->terminate(ec);
1905 this->terminate(lib::error_code());
1909 bool needs_writing =
false;
1911 scoped_lock_type lock(m_write_lock);
1914 m_write_flag =
false;
1916 needs_writing = !m_send_queue.empty();
1919 if (needs_writing) {
1920 transport_con_type::dispatch(lib::bind(
1927 template <
typename config>
1933 template <
typename config>
1938 frame::opcode::value op = msg->get_opcode();
1941 std::stringstream s;
1942 s <<
"Control frame received with opcode " << op;
1945 if (m_state == session::state::closed) {
1949 if (op != frame::opcode::CLOSE && m_state != session::state::open) {
1954 if (op == frame::opcode::PING) {
1955 bool should_reply =
true;
1957 if (m_ping_handler) {
1958 should_reply = m_ping_handler(m_connection_hdl, msg->get_payload());
1962 this->pong(msg->get_payload(),ec);
1967 }
else if (op == frame::opcode::PONG) {
1968 if (m_pong_handler) {
1969 m_pong_handler(m_connection_hdl, msg->get_payload());
1972 m_ping_timer->cancel();
1974 }
else if (op == frame::opcode::CLOSE) {
1981 if (config::drop_on_protocol_error) {
1982 s <<
"Received invalid close code " << m_remote_close_code
1983 <<
" dropping connection per config.";
1985 this->terminate(ec);
1987 s <<
"Received invalid close code " << m_remote_close_code
1988 <<
" sending acknowledgement and closing";
1991 "Invalid close code");
2001 if (config::drop_on_protocol_error) {
2003 "Received invalid close reason. Dropping connection per config");
2004 this->terminate(ec);
2007 "Received invalid close reason. Sending acknowledgement and closing");
2009 "Invalid close reason");
2017 if (m_state == session::state::open) {
2019 s <<
"Received close frame with code " << m_remote_close_code
2020 <<
" and reason " << m_remote_close_reason;
2023 ec = send_close_ack();
2027 }
else if (m_state == session::state::closing && !m_was_clean) {
2041 terminate(lib::error_code());
2054 template <
typename config>
2056 std::string
const & reason)
2058 return send_close_frame(code,reason,
true,m_is_server);
2061 template <
typename config>
2063 std::string
const & reason,
bool ack,
bool terminal)
2075 if (config::silent_close) {
2078 m_local_close_reason.clear();
2081 m_local_close_code = code;
2082 m_local_close_reason = reason;
2086 m_local_close_reason.clear();
2089 "acknowledging a no-status close with normal code");
2091 m_local_close_reason.clear();
2094 m_local_close_code = m_remote_close_code;
2095 m_local_close_reason = m_remote_close_reason;
2098 std::stringstream s;
2099 s <<
"Closing with code: " << m_local_close_code <<
", and reason: " 2100 << m_local_close_reason;
2103 message_ptr msg = m_msg_manager->get_message();
2108 lib::error_code ec = m_processor->prepare_close(m_local_close_code,
2109 m_local_close_reason,msg);
2118 msg->set_terminal(
true);
2121 m_state = session::state::closing;
2129 if (m_close_handshake_timeout_dur > 0) {
2130 m_handshake_timer = transport_con_type::set_timer(
2131 m_close_handshake_timeout_dur,
2133 &type::handle_close_handshake_timeout,
2135 lib::placeholders::_1
2140 bool needs_writing =
false;
2142 scoped_lock_type lock(m_write_lock);
2144 needs_writing = !m_write_flag && !m_send_queue.empty();
2147 if (needs_writing) {
2148 transport_con_type::dispatch(lib::bind(
2154 return lib::error_code();
2157 template <
typename config>
2158 typename connection<config>::processor_ptr
2166 p = lib::make_shared<processor::hybi00<config> >(
2167 transport_con_type::is_secure(),
2173 p = lib::make_shared<processor::hybi07<config> >(
2174 transport_con_type::is_secure(),
2181 p = lib::make_shared<processor::hybi08<config> >(
2182 transport_con_type::is_secure(),
2189 p = lib::make_shared<processor::hybi13<config> >(
2190 transport_con_type::is_secure(),
2206 template <
typename config>
2213 m_send_buffer_size += msg->get_payload().size();
2214 m_send_queue.push(msg);
2217 std::stringstream s;
2218 s <<
"write_push: message count: " << m_send_queue.size()
2219 <<
" buffer size: " << m_send_buffer_size;
2224 template <
typename config>
2229 if (m_send_queue.empty()) {
2233 msg = m_send_queue.front();
2235 m_send_buffer_size -= msg->get_payload().size();
2239 std::stringstream s;
2240 s <<
"write_pop: message count: " << m_send_queue.size()
2241 <<
" buffer size: " << m_send_buffer_size;
2247 template <
typename config>
2250 std::stringstream s;
2260 s << (version == -1 ?
"HTTP" :
"WebSocket") <<
" Connection ";
2263 s << transport_con_type::get_remote_endpoint() <<
" ";
2266 if (version != -1) {
2267 s <<
"v" << version <<
" ";
2271 std::string ua = m_request.get_header(
"User-Agent");
2280 s << (m_uri ? m_uri->get_resource() :
"NULL") <<
" ";
2283 s << m_response.get_status_code();
2288 template <
typename config>
2291 std::stringstream s;
2294 <<
"close local:[" << m_local_close_code
2295 << (m_local_close_reason.empty() ?
"" :
","+m_local_close_reason)
2296 <<
"] remote:[" << m_remote_close_code
2297 << (m_remote_close_reason.empty() ?
"" :
","+m_remote_close_reason) <<
"]";
2302 template <
typename config>
2305 std::stringstream s;
2310 s <<
"WebSocket Connection ";
2313 s << transport_con_type::get_remote_endpoint();
2317 s <<
" v" << version;
2321 std::string ua = m_request.get_header(
"User-Agent");
2330 s << (m_uri ? m_uri->get_resource() :
"-");
2333 s <<
" " << m_response.get_status_code();
2336 s <<
" " << m_ec <<
" " << m_ec.message();
2341 template <
typename config>
2343 std::stringstream s;
2351 s << (m_request.get_header(
"host").empty() ?
"-" : m_request.get_header(
"host"))
2352 <<
" " << transport_con_type::get_remote_endpoint()
2353 <<
" \"" << m_request.get_method()
2354 <<
" " << (m_uri ? m_uri->get_resource() :
"-")
2355 <<
" " << m_request.get_version() <<
"\" " << m_response.get_status_code()
2356 <<
" " << m_response.get_body().size();
2359 std::string ua = m_request.get_header(
"User-Agent");
2372 #endif // WEBSOCKETPP_CONNECTION_IMPL_HPP lib::error_code process_handshake_request()
void add_subprotocol(std::string const &request, lib::error_code &ec)
Adds the given subprotocol string to the request list (exception free)
void set_termination_handler(termination_handler new_handler)
void read_frame()
Issue a new transport read unless reading is paused.
std::vector< std::string > const & get_requested_subprotocols() const
Gets all of the subprotocols requested by the client.
uint16_t value
The type of a close code value.
static level const control
One line per control frame.
std::string const & get_subprotocol() const
Gets the negotated subprotocol.
bool terminal(value code)
Determine if the code represents an unrecoverable error.
uri_ptr get_uri_from_host(request_type &request, std::string scheme)
Extract a URI ptr from the host header of the request.
lib::error_code pause_reading()
Pause reading of new data.
bool is_websocket_handshake(request_type &r)
Determine whether or not a generic HTTP request is a WebSocket handshake.
Attempted to use a client specific feature on a server endpoint.
session::state::value get_state() const
Return the connection state.
static std::vector< int > const versions_supported(helper, helper+4)
Container that stores the list of protocol versions supported.
Selected subprotocol was not requested by the client.
int get_websocket_version(request_type &r)
Extract the version from a WebSocket handshake request.
uri_ptr get_uri() const
Gets the connection URI.
void replace_header(std::string const &key, std::string const &val)
Replace a header.
void ping(std::string const &payload)
Send a ping.
Represents an individual WebSocket connection.
size_t get_buffered_amount() const
Get the size of the outgoing write buffer (in payload bytes)
static level const frame_payload
One line per frame, includes the full message payload (warning: chatty)
static value const protocol_error
A protocol error occurred.
static value const normal
static level const devel
Low level debugging information (warning: very chatty)
std::string string_replace_all(std::string subject, std::string const &search, std::string const &replace)
Replace all occurrances of a substring with another.
status::value extract_code(std::string const &payload, lib::error_code &ec)
Extract a close code value from a close payload.
void select_subprotocol(std::string const &value, lib::error_code &ec)
Select a subprotocol to use (exception free)
std::string to_hex(std::string const &input)
Convert std::string to ascii printed string of hex digits.
void pong(std::string const &payload)
Send a pong.
void send_http_response()
Send deferred HTTP Response.
bool is_not_token_char(unsigned char c)
Is the character a non-token.
void handle_resume_reading()
Resume reading callback.
static level const frame_header
One line per frame, includes the full frame header.
lib::error_code initialize_processor()
static level const devel
Development messages (warning: very chatty)
std::string const & get_request_header(std::string const &key) const
Retrieve a request header.
static level const disconnect
One line for each closed connection. Includes closing codes and reasons.
lib::error_code resume_reading()
Resume reading of new data.
void start()
Start the connection state machine.
void close(close::status::value const code, std::string const &reason)
Close the connection.
lib::error_code defer_http_response()
Defer HTTP Response until later (Exception free)
Invalid WebSocket protocol version.
void set_status(http::status_code::value code)
Set response status code and message.
void handle_pong_timeout(std::string payload, lib::error_code const &ec)
Utility method that gets called back when the ping timer expires.
close::status::value to_ws(lib::error_code ec)
Converts a processor error_code into a websocket close code.
lib::error_code make_error_code(error::processor_errors e)
Create an error code with the given value and the processor category.
void append_header(std::string const &key, std::string const &val)
Append a header.
lib::error_code send(std::string const &payload, frame::opcode::value op=frame::opcode::text)
Create a message and then add it to the outgoing send queue.
The connection was in the wrong state for this operation.
void write_frame()
Checks if there are frames in the send queue and if there are sends one.
void handle_write_frame(lib::error_code const &ec)
Process the results of a frame write operation and start the next write.
Namespace for the WebSocket++ project.
void set_max_message_size(size_t new_value)
Set maximum message size.
Extension negotiation failed.
std::string const & get_origin() const
Return the same origin policy origin value from the opening request.
std::string const & get_response_header(std::string const &key) const
Retrieve a response header.
uint16_t get_port() const
Returns the port component of the connection URI.
std::string const & get_resource() const
Returns the resource component of the connection URI.
A simple utility buffer class.
std::vector< int > const & get_supported_versions() const
Get array of WebSocket protocol versions that this connection supports.
The endpoint is out of outgoing message buffers.
lib::shared_ptr< uri > uri_ptr
Pointer to a URI.
void handle_interrupt()
Transport inturrupt callback.
static value const no_status
A dummy value to indicate that no status code was received.
void handle_pause_reading()
Pause reading callback.
WebSocket close handshake timed out.
bool get_secure() const
Returns the secure flag from the connection URI.
static level const fail
One line for each failed WebSocket connection with details.
static value const abnormal_close
A dummy value to indicate that the connection was closed abnormally.
std::string const & get_request_body() const
Retrieve a request body.
static uint8_t const close_reason_size
Maximum size of close frame reason.
read or write after shutdown
void set_uri(uri_ptr uri)
Sets the connection URI.
WebSocket opening handshake timed out.
std::string const & get_host() const
Returns the host component of the connection URI.
Attempted to use a server specific feature on a client endpoint.
lib::error_code interrupt()
Asyncronously invoke handler::on_inturrupt.
std::string extract_reason(std::string const &payload, lib::error_code &ec)
Extract the reason string from a close payload.
static level const rerror
An invalid uri was supplied.
Unsupported WebSocket protocol version.
static value const blank
A blank value for internal use.
static level const connect
Information about new connections.
static level const http
Access related to HTTP requests.
void remove_header(std::string const &key)
Remove a header.
void set_body(std::string const &value)
Set response body content.