websocketpp  0.4.0
C++/Boost Asio based websocket client/server library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
hybi13.hpp
1 /*
2  * Copyright (c) 2014, Peter Thorson. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  * * Redistributions of source code must retain the above copyright
7  * notice, this list of conditions and the following disclaimer.
8  * * Redistributions in binary form must reproduce the above copyright
9  * notice, this list of conditions and the following disclaimer in the
10  * documentation and/or other materials provided with the distribution.
11  * * Neither the name of the WebSocket++ Project nor the
12  * names of its contributors may be used to endorse or promote products
13  * derived from this software without specific prior written permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
19  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  */
27 
28 #ifndef WEBSOCKETPP_PROCESSOR_HYBI13_HPP
29 #define WEBSOCKETPP_PROCESSOR_HYBI13_HPP
30 
31 #include <cassert>
32 
33 #include <websocketpp/frame.hpp>
34 #include <websocketpp/utf8_validator.hpp>
35 #include <websocketpp/common/network.hpp>
36 #include <websocketpp/common/platforms.hpp>
37 #include <websocketpp/http/constants.hpp>
38 
39 #include <websocketpp/processors/processor.hpp>
40 
41 #include <websocketpp/sha1/sha1.hpp>
42 #include <websocketpp/base64/base64.hpp>
43 
44 #include <string>
45 #include <vector>
46 #include <utility>
47 
48 namespace websocketpp {
49 namespace processor {
50 
52 template <typename config>
53 class hybi13 : public processor<config> {
54 public:
55  typedef processor<config> base;
56 
57  typedef typename config::request_type request_type;
58  typedef typename config::response_type response_type;
59 
60  typedef typename config::message_type message_type;
61  typedef typename message_type::ptr message_ptr;
62 
63  typedef typename config::con_msg_manager_type msg_manager_type;
64  typedef typename msg_manager_type::ptr msg_manager_ptr;
65  typedef typename config::rng_type rng_type;
66 
67  typedef typename config::permessage_deflate_type permessage_deflate_type;
68 
69  typedef std::pair<lib::error_code,std::string> err_str_pair;
70 
71  explicit hybi13(bool secure, bool p_is_server, msg_manager_ptr manager, rng_type& rng)
72  : processor<config>(secure, p_is_server)
73  , m_msg_manager(manager)
74  , m_rng(rng)
75  {
76  reset_headers();
77  }
78 
79  int get_version() const {
80  return 13;
81  }
82 
83  bool has_permessage_deflate() const {
84  return m_permessage_deflate.is_implemented();
85  }
86 
87  err_str_pair negotiate_extensions(request_type const & req) {
88  err_str_pair ret;
89 
90  // Respect blanket disabling of all extensions and don't even parse
91  // the extension header
92  if (!config::enable_extensions) {
93  ret.first = make_error_code(error::extensions_disabled);
94  return ret;
95  }
96 
98 
99  bool error = req.get_header_as_plist("Sec-WebSocket-Extensions",p);
100 
101  if (error) {
102  ret.first = make_error_code(error::extension_parse_error);
103  return ret;
104  }
105 
106  // If there are no extensions parsed then we are done!
107  if (p.size() == 0) {
108  return ret;
109  }
110 
111  http::parameter_list::const_iterator it;
112 
113  if (m_permessage_deflate.is_implemented()) {
114  err_str_pair neg_ret;
115  for (it = p.begin(); it != p.end(); ++it) {
116  // look through each extension, if the key is permessage-deflate
117  if (it->first == "permessage-deflate") {
118  neg_ret = m_permessage_deflate.negotiate(it->second);
119 
120  if (neg_ret.first) {
121  // Figure out if this is an error that should halt all
122  // extension negotiations or simply cause negotiation of
123  // this specific extension to fail.
124  //std::cout << "permessage-compress negotiation failed: "
125  // << neg_ret.first.message() << std::endl;
126  } else {
127  // Note: this list will need commas if WebSocket++ ever
128  // supports more than one extension
129  ret.second += neg_ret.second;
130  continue;
131  }
132  }
133  }
134  }
135 
136  return ret;
137  }
138 
139  lib::error_code validate_handshake(request_type const & r) const {
140  if (r.get_method() != "GET") {
141  return make_error_code(error::invalid_http_method);
142  }
143 
144  if (r.get_version() != "HTTP/1.1") {
145  return make_error_code(error::invalid_http_version);
146  }
147 
148  // required headers
149  // Host is required by HTTP/1.1
150  // Connection is required by is_websocket_handshake
151  // Upgrade is required by is_websocket_handshake
152  if (r.get_header("Sec-WebSocket-Key") == "") {
153  return make_error_code(error::missing_required_header);
154  }
155 
156  return lib::error_code();
157  }
158 
159  /* TODO: the 'subprotocol' parameter may need to be expanded into a more
160  * generic struct if other user input parameters to the processed handshake
161  * are found.
162  */
163  lib::error_code process_handshake(request_type const & request, const
164  std::string & subprotocol, response_type& response) const
165  {
166  std::string server_key = request.get_header("Sec-WebSocket-Key");
167 
168  lib::error_code ec = process_handshake_key(server_key);
169 
170  if (ec) {
171  return ec;
172  }
173 
174  response.replace_header("Sec-WebSocket-Accept",server_key);
175  response.append_header("Upgrade",constants::upgrade_token);
176  response.append_header("Connection",constants::connection_token);
177 
178  if (!subprotocol.empty()) {
179  response.replace_header("Sec-WebSocket-Protocol",subprotocol);
180  }
181 
182  return lib::error_code();
183  }
184 
186 
191  lib::error_code client_handshake_request(request_type & req, uri_ptr
192  uri, std::vector<std::string> const & subprotocols) const
193  {
194  req.set_method("GET");
195  req.set_uri(uri->get_resource());
196  req.set_version("HTTP/1.1");
197 
198  req.append_header("Upgrade","websocket");
199  req.append_header("Connection","Upgrade");
200  req.replace_header("Sec-WebSocket-Version","13");
201  req.replace_header("Host",uri->get_host_port());
202 
203  if (!subprotocols.empty()) {
204  std::ostringstream result;
205  std::vector<std::string>::const_iterator it = subprotocols.begin();
206  result << *it++;
207  while (it != subprotocols.end()) {
208  result << ", " << *it++;
209  }
210 
211  req.replace_header("Sec-WebSocket-Protocol",result.str());
212  }
213 
214  // Generate handshake key
216  unsigned char raw_key[16];
217 
218  for (int i = 0; i < 4; i++) {
219  conv.i = m_rng();
220  std::copy(conv.c,conv.c+4,&raw_key[i*4]);
221  }
222 
223  req.replace_header("Sec-WebSocket-Key",base64_encode(raw_key, 16));
224 
225  return lib::error_code();
226  }
227 
229 
234  lib::error_code validate_server_handshake_response(request_type const & req,
235  response_type& res) const
236  {
237  // A valid response has an HTTP 101 switching protocols code
238  if (res.get_status_code() != http::status_code::switching_protocols) {
240  }
241 
242  // And the upgrade token in an upgrade header
243  std::string const & upgrade_header = res.get_header("Upgrade");
244  if (utility::ci_find_substr(upgrade_header, constants::upgrade_token,
245  sizeof(constants::upgrade_token)-1) == upgrade_header.end())
246  {
248  }
249 
250  // And the websocket token in the connection header
251  std::string const & con_header = res.get_header("Connection");
252  if (utility::ci_find_substr(con_header, constants::connection_token,
253  sizeof(constants::connection_token)-1) == con_header.end())
254  {
256  }
257 
258  // And has a valid Sec-WebSocket-Accept value
259  std::string key = req.get_header("Sec-WebSocket-Key");
260  lib::error_code ec = process_handshake_key(key);
261 
262  if (ec || key != res.get_header("Sec-WebSocket-Accept")) {
264  }
265 
266  return lib::error_code();
267  }
268 
269  std::string get_raw(response_type const & res) const {
270  return res.raw();
271  }
272 
273  std::string const & get_origin(request_type const & r) const {
274  return r.get_header("Origin");
275  }
276 
277  lib::error_code extract_subprotocols(request_type const & req,
278  std::vector<std::string> & subprotocol_list)
279  {
280  if (!req.get_header("Sec-WebSocket-Protocol").empty()) {
282 
283  if (!req.get_header_as_plist("Sec-WebSocket-Protocol",p)) {
284  http::parameter_list::const_iterator it;
285 
286  for (it = p.begin(); it != p.end(); ++it) {
287  subprotocol_list.push_back(it->first);
288  }
289  } else {
291  }
292  }
293  return lib::error_code();
294  }
295 
296  uri_ptr get_uri(request_type const & request) const {
297  return get_uri_from_host(request,(base::m_secure ? "wss" : "ws"));
298  }
299 
301 
327  size_t consume(uint8_t * buf, size_t len, lib::error_code & ec) {
328  size_t p = 0;
329 
330  ec = lib::error_code();
331 
332  //std::cout << "consume: " << utility::to_hex(buf,len) << std::endl;
333 
334  // Loop while we don't have a message ready and we still have bytes
335  // left to process.
336  while (m_state != READY && m_state != FATAL_ERROR &&
337  (p < len || m_bytes_needed == 0))
338  {
339  if (m_state == HEADER_BASIC) {
340  p += this->copy_basic_header_bytes(buf+p,len-p);
341 
342  if (m_bytes_needed > 0) {
343  continue;
344  }
345 
347  m_basic_header, base::m_server, !m_data_msg.msg_ptr
348  );
349  if (ec) {break;}
350 
351  // extract full header size and adjust consume state accordingly
352  m_state = HEADER_EXTENDED;
353  m_cursor = 0;
354  m_bytes_needed = frame::get_header_len(m_basic_header) -
356  } else if (m_state == HEADER_EXTENDED) {
357  p += this->copy_extended_header_bytes(buf+p,len-p);
358 
359  if (m_bytes_needed > 0) {
360  continue;
361  }
362 
363  ec = validate_incoming_extended_header(m_basic_header,m_extended_header);
364  if (ec){break;}
365 
366  m_state = APPLICATION;
367  m_bytes_needed = static_cast<size_t>(get_payload_size(m_basic_header,m_extended_header));
368 
369  // check if this frame is the start of a new message and set up
370  // the appropriate message metadata.
371  frame::opcode::value op = frame::get_opcode(m_basic_header);
372 
373  // TODO: get_message failure conditions
374 
375  if (frame::opcode::is_control(op)) {
376  m_control_msg = msg_metadata(
377  m_msg_manager->get_message(op,m_bytes_needed),
378  frame::get_masking_key(m_basic_header,m_extended_header)
379  );
380 
381  m_current_msg = &m_control_msg;
382  } else {
383  if (!m_data_msg.msg_ptr) {
384  if (m_bytes_needed > base::m_max_message_size) {
385  ec = make_error_code(error::message_too_big);
386  break;
387  }
388 
389  m_data_msg = msg_metadata(
390  m_msg_manager->get_message(op,m_bytes_needed),
391  frame::get_masking_key(m_basic_header,m_extended_header)
392  );
393  } else {
394  // Fetch the underlying payload buffer from the data message we
395  // are writing into.
396  std::string & out = m_data_msg.msg_ptr->get_raw_payload();
397 
398  if (out.size() + m_bytes_needed > base::m_max_message_size) {
399  ec = make_error_code(error::message_too_big);
400  break;
401  }
402 
403  // Each frame starts a new masking key. All other state
404  // remains between frames.
405  m_data_msg.prepared_key = prepare_masking_key(
407  m_basic_header,
408  m_extended_header
409  )
410  );
411 
412  out.reserve(out.size() + m_bytes_needed);
413  }
414  m_current_msg = &m_data_msg;
415  }
416  } else if (m_state == EXTENSION) {
417  m_state = APPLICATION;
418  } else if (m_state == APPLICATION) {
419  size_t bytes_to_process = (std::min)(m_bytes_needed,len-p);
420 
421  if (bytes_to_process > 0) {
422  p += this->process_payload_bytes(buf+p,bytes_to_process,ec);
423 
424  if (ec) {break;}
425  }
426 
427  if (m_bytes_needed > 0) {
428  continue;
429  }
430 
431  // If this was the last frame in the message set the ready flag.
432  // Otherwise, reset processor state to read additional frames.
433  if (frame::get_fin(m_basic_header)) {
434  // ensure that text messages end on a valid UTF8 code point
435  if (frame::get_opcode(m_basic_header) == frame::opcode::TEXT) {
436  if (!m_current_msg->validator.complete()) {
437  ec = make_error_code(error::invalid_utf8);
438  break;
439  }
440  }
441 
442  m_state = READY;
443  } else {
444  this->reset_headers();
445  }
446  } else {
447  // shouldn't be here
448  ec = make_error_code(error::general);
449  return 0;
450  }
451  }
452 
453  return p;
454  }
455 
456  void reset_headers() {
457  m_state = HEADER_BASIC;
458  m_bytes_needed = frame::BASIC_HEADER_LENGTH;
459 
460  m_basic_header.b0 = 0x00;
461  m_basic_header.b1 = 0x00;
462 
463  std::fill_n(
464  m_extended_header.bytes,
466  0x00
467  );
468  }
469 
471  bool ready() const {
472  return (m_state == READY);
473  }
474 
475  message_ptr get_message() {
476  if (!ready()) {
477  return message_ptr();
478  }
479  message_ptr ret = m_current_msg->msg_ptr;
480  m_current_msg->msg_ptr.reset();
481 
482  if (frame::opcode::is_control(ret->get_opcode())) {
483  m_control_msg.msg_ptr.reset();
484  } else {
485  m_data_msg.msg_ptr.reset();
486  }
487 
488  this->reset_headers();
489 
490  return ret;
491  }
492 
494  bool get_error() const {
495  return m_state == FATAL_ERROR;
496  }
497 
498  size_t get_bytes_needed() const {
499  return m_bytes_needed;
500  }
501 
503 
526  virtual lib::error_code prepare_data_frame(message_ptr in, message_ptr out)
527  {
528  if (!in || !out) {
529  return make_error_code(error::invalid_arguments);
530  }
531 
532  frame::opcode::value op = in->get_opcode();
533 
534  // validate opcode: only regular data frames
535  if (frame::opcode::is_control(op)) {
536  return make_error_code(error::invalid_opcode);
537  }
538 
539  std::string& i = in->get_raw_payload();
540  std::string& o = out->get_raw_payload();
541 
542  // validate payload utf8
543  if (op == frame::opcode::TEXT && !utf8_validator::validate(i)) {
544  return make_error_code(error::invalid_payload);
545  }
546 
548  bool masked = !base::m_server;
549  bool compressed = m_permessage_deflate.is_enabled()
550  && in->get_compressed();
551  bool fin = in->get_fin();
552 
553  // generate header
554  frame::basic_header h(op,i.size(),fin,masked,compressed);
555 
556  if (masked) {
557  // Generate masking key.
558  key.i = m_rng();
559 
560  frame::extended_header e(i.size(),key.i);
561  out->set_header(frame::prepare_header(h,e));
562  } else {
563  frame::extended_header e(i.size());
564  out->set_header(frame::prepare_header(h,e));
565  }
566 
567  // prepare payload
568  if (compressed) {
569  // compress and store in o after header.
570  m_permessage_deflate.compress(i,o);
571 
572  // mask in place if necessary
573  if (masked) {
574  this->masked_copy(o,o,key);
575  }
576  } else {
577  // no compression, just copy data into the output buffer
578  o.resize(i.size());
579 
580  // if we are masked, have the masking function write to the output
581  // buffer directly to avoid another copy. If not masked, copy
582  // directly without masking.
583  if (masked) {
584  this->masked_copy(i,o,key);
585  } else {
586  std::copy(i.begin(),i.end(),o.begin());
587  }
588  }
589 
590  out->set_prepared(true);
591 
592  return lib::error_code();
593  }
594 
596  lib::error_code prepare_ping(std::string const & in, message_ptr out) const {
597  return this->prepare_control(frame::opcode::PING,in,out);
598  }
599 
600  lib::error_code prepare_pong(std::string const & in, message_ptr out) const {
601  return this->prepare_control(frame::opcode::PONG,in,out);
602  }
603 
604  virtual lib::error_code prepare_close(close::status::value code,
605  std::string const & reason, message_ptr out) const
606  {
607  if (close::status::reserved(code)) {
608  return make_error_code(error::reserved_close_code);
609  }
610 
611  if (close::status::invalid(code) && code != close::status::no_status) {
612  return make_error_code(error::invalid_close_code);
613  }
614 
615  if (code == close::status::no_status && reason.size() > 0) {
616  return make_error_code(error::reason_requires_code);
617  }
618 
619  if (reason.size() > frame:: limits::payload_size_basic-2) {
620  return make_error_code(error::control_too_big);
621  }
622 
623  std::string payload;
624 
625  if (code != close::status::no_status) {
626  close::code_converter val;
627  val.i = htons(code);
628 
629  payload.resize(reason.size()+2);
630 
631  payload[0] = val.c[0];
632  payload[1] = val.c[1];
633 
634  std::copy(reason.begin(),reason.end(),payload.begin()+2);
635  }
636 
637  return this->prepare_control(frame::opcode::CLOSE,payload,out);
638  }
639 protected:
641  lib::error_code process_handshake_key(std::string & key) const {
642  key.append(constants::handshake_guid);
643 
644  unsigned char message_digest[20];
645  sha1::calc(key.c_str(),key.length(),message_digest);
646  key = base64_encode(message_digest,20);
647 
648  return lib::error_code();
649  }
650 
652  size_t copy_basic_header_bytes(uint8_t const * buf, size_t len) {
653  if (len == 0 || m_bytes_needed == 0) {
654  return 0;
655  }
656 
657  if (len > 1) {
658  // have at least two bytes
659  if (m_bytes_needed == 2) {
660  m_basic_header.b0 = buf[0];
661  m_basic_header.b1 = buf[1];
662  m_bytes_needed -= 2;
663  return 2;
664  } else {
665  m_basic_header.b1 = buf[0];
666  m_bytes_needed--;
667  return 1;
668  }
669  } else {
670  // have exactly one byte
671  if (m_bytes_needed == 2) {
672  m_basic_header.b0 = buf[0];
673  m_bytes_needed--;
674  return 1;
675  } else {
676  m_basic_header.b1 = buf[0];
677  m_bytes_needed--;
678  return 1;
679  }
680  }
681  }
682 
684  size_t copy_extended_header_bytes(uint8_t const * buf, size_t len) {
685  size_t bytes_to_read = (std::min)(m_bytes_needed,len);
686 
687  std::copy(buf,buf+bytes_to_read,m_extended_header.bytes+m_cursor);
688  m_cursor += bytes_to_read;
689  m_bytes_needed -= bytes_to_read;
690 
691  return bytes_to_read;
692  }
693 
695 
707  size_t process_payload_bytes(uint8_t * buf, size_t len, lib::error_code& ec)
708  {
709  // unmask if masked
710  if (frame::get_masked(m_basic_header)) {
711  #ifdef WEBSOCKETPP_STRICT_MASKING
712  m_current_msg->prepared_key = frame::byte_mask_circ(
713  buf,
714  len,
715  m_current_msg->prepared_key
716  );
717  #else
718  m_current_msg->prepared_key = frame::word_mask_circ(
719  buf,
720  len,
721  m_current_msg->prepared_key
722  );
723  #endif
724  }
725 
726  std::string & out = m_current_msg->msg_ptr->get_raw_payload();
727  size_t offset = out.size();
728 
729  // decompress message if needed.
730  if (m_permessage_deflate.is_enabled()
731  && frame::get_rsv1(m_basic_header))
732  {
733  // Decompress current buffer into the message buffer
734  m_permessage_deflate.decompress(buf,len,out);
735 
736  // get the length of the newly uncompressed output
737  offset = out.size() - offset;
738  } else {
739  // No compression, straight copy
740  out.append(reinterpret_cast<char *>(buf),len);
741  }
742 
743  // validate unmasked, decompressed values
744  if (m_current_msg->msg_ptr->get_opcode() == frame::opcode::TEXT) {
745  if (!m_current_msg->validator.decode(out.begin()+offset,out.end())) {
746  ec = make_error_code(error::invalid_utf8);
747  return 0;
748  }
749  }
750 
751  m_bytes_needed -= len;
752 
753  return len;
754  }
755 
757 
767  bool is_server, bool new_msg) const
768  {
769  frame::opcode::value op = frame::get_opcode(h);
770 
771  // Check control frame size limit
772  if (frame::opcode::is_control(op) &&
774  {
775  return make_error_code(error::control_too_big);
776  }
777 
778  // Check that RSV bits are clear
779  // The only RSV bits allowed are rsv1 if the permessage_compress
780  // extension is enabled for this connection and the message is not
781  // a control message.
782  //
783  // TODO: unit tests for this
784  if (frame::get_rsv1(h) && (!m_permessage_deflate.is_enabled()
786  {
787  return make_error_code(error::invalid_rsv_bit);
788  }
789 
790  if (frame::get_rsv2(h) || frame::get_rsv3(h)) {
791  return make_error_code(error::invalid_rsv_bit);
792  }
793 
794  // Check for reserved opcodes
795  if (frame::opcode::reserved(op)) {
796  return make_error_code(error::invalid_opcode);
797  }
798 
799  // Check for invalid opcodes
800  // TODO: unit tests for this?
801  if (frame::opcode::invalid(op)) {
802  return make_error_code(error::invalid_opcode);
803  }
804 
805  // Check for fragmented control message
806  if (frame::opcode::is_control(op) && !frame::get_fin(h)) {
807  return make_error_code(error::fragmented_control);
808  }
809 
810  // Check for continuation without an active message
811  if (new_msg && op == frame::opcode::CONTINUATION) {
812  return make_error_code(error::invalid_continuation);
813  }
814 
815  // Check for new data frame when expecting continuation
816  if (!new_msg && !frame::opcode::is_control(op) &&
817  op != frame::opcode::CONTINUATION)
818  {
819  return make_error_code(error::invalid_continuation);
820  }
821 
822  // Servers should reject any unmasked frames from clients.
823  // Clients should reject any masked frames from servers.
824  if (is_server && !frame::get_masked(h)) {
825  return make_error_code(error::masking_required);
826  } else if (!is_server && frame::get_masked(h)) {
827  return make_error_code(error::masking_forbidden);
828  }
829 
830  return lib::error_code();
831  }
832 
834 
845  frame::extended_header e) const
846  {
847  uint8_t basic_size = frame::get_basic_size(h);
848  uint64_t payload_size = frame::get_payload_size(h,e);
849 
850  // Check for non-minimally encoded payloads
851  if (basic_size == frame::payload_size_code_16bit &&
852  payload_size <= frame::limits::payload_size_basic)
853  {
854  return make_error_code(error::non_minimal_encoding);
855  }
856 
857  if (basic_size == frame::payload_size_code_64bit &&
858  payload_size <= frame::limits::payload_size_extended)
859  {
860  return make_error_code(error::non_minimal_encoding);
861  }
862 
863  // Check for >32bit frames on 32 bit systems
864  if (sizeof(size_t) == 4 && (payload_size >> 32)) {
865  return make_error_code(error::requires_64bit);
866  }
867 
868  return lib::error_code();
869  }
870 
872 
879  void masked_copy (std::string const & i, std::string & o,
880  frame::masking_key_type key) const
881  {
882  #ifdef WEBSOCKETPP_STRICT_MASKING
883  frame::byte_mask(i.begin(),i.end(),o.begin(),key);
884  #else
886  reinterpret_cast<uint8_t *>(const_cast<char *>(i.data())),
887  reinterpret_cast<uint8_t *>(const_cast<char *>(o.data())),
888  i.size(),
889  key
890  );
891  #endif
892  }
893 
895 
903  lib::error_code prepare_control(frame::opcode::value op,
904  std::string const & payload, message_ptr out) const
905  {
906  if (!out) {
907  return make_error_code(error::invalid_arguments);
908  }
909 
910  if (!frame::opcode::is_control(op)) {
911  return make_error_code(error::invalid_opcode);
912  }
913 
914  if (payload.size() > frame::limits::payload_size_basic) {
915  return make_error_code(error::control_too_big);
916  }
917 
919  bool masked = !base::m_server;
920 
921  frame::basic_header h(op,payload.size(),true,masked);
922 
923  std::string & o = out->get_raw_payload();
924  o.resize(payload.size());
925 
926  if (masked) {
927  // Generate masking key.
928  key.i = m_rng();
929 
930  frame::extended_header e(payload.size(),key.i);
931  out->set_header(frame::prepare_header(h,e));
932  this->masked_copy(payload,o,key);
933  } else {
934  frame::extended_header e(payload.size());
935  out->set_header(frame::prepare_header(h,e));
936  std::copy(payload.begin(),payload.end(),o.begin());
937  }
938 
939  out->set_prepared(true);
940 
941  return lib::error_code();
942  }
943 
944  enum state {
945  HEADER_BASIC = 0,
946  HEADER_EXTENDED = 1,
947  EXTENSION = 2,
948  APPLICATION = 3,
949  READY = 4,
950  FATAL_ERROR = 5
951  };
952 
956  struct msg_metadata {
957  msg_metadata() {}
958  msg_metadata(message_ptr m, size_t p) : msg_ptr(m),prepared_key(p) {}
959  msg_metadata(message_ptr m, frame::masking_key_type p)
960  : msg_ptr(m)
961  , prepared_key(prepare_masking_key(p)) {}
962 
963  message_ptr msg_ptr; // pointer to the message data buffer
964  size_t prepared_key; // prepared masking key
965  utf8_validator::validator validator; // utf8 validation state
966  };
967 
968  // Basic header of the frame being read
969  frame::basic_header m_basic_header;
970 
971  // Pointer to a manager that can create message buffers for us.
972  msg_manager_ptr m_msg_manager;
973 
974  // Number of bytes needed to complete the current operation
975  size_t m_bytes_needed;
976 
977  // Number of extended header bytes read
978  size_t m_cursor;
979 
980  // Metadata for the current data msg
981  msg_metadata m_data_msg;
982  // Metadata for the current control msg
983  msg_metadata m_control_msg;
984 
985  // Pointer to the metadata associated with the frame being read
986  msg_metadata * m_current_msg;
987 
988  // Extended header of current frame
989  frame::extended_header m_extended_header;
990 
991  rng_type & m_rng;
992 
993  // Overall state of the processor
994  state m_state;
995 
996  // Extensions
997  permessage_deflate_type m_permessage_deflate;
998 };
999 
1000 } // namespace processor
1001 } // namespace websocketpp
1002 
1003 #endif //WEBSOCKETPP_PROCESSOR_HYBI13_HPP
bool is_control(value v)
Check if an opcode is for a control frame.
Definition: frame.hpp:138
bool invalid(value v)
Check if an opcode is invalid.
Definition: frame.hpp:129
virtual lib::error_code prepare_data_frame(message_ptr in, message_ptr out)
Prepare a user data message for writing.
Definition: hybi13.hpp:526
bool get_rsv1(basic_header const &h)
check whether the frame's RSV1 bit is set
Definition: frame.hpp:338
uint16_t value
The type of a close code value.
Definition: close.hpp:49
uri_ptr get_uri_from_host(request_type &request, std::string scheme)
Extract a URI ptr from the host header of the request.
Definition: processor.hpp:130
bool get_rsv3(basic_header const &h)
check whether the frame's RSV3 bit is set
Definition: frame.hpp:374
bool ready() const
Test whether or not the processor has a message ready.
Definition: hybi13.hpp:471
bool decode(iterator_type begin, iterator_type end)
Advance validator state with input from an iterator pair.
Clients may not send unmasked frames.
Definition: base.hpp:103
lib::error_code validate_handshake(request_type const &r) const
validate a WebSocket handshake request for this version
Definition: hybi13.hpp:139
bool get_masked(basic_header const &h)
check whether the frame is masked
Definition: frame.hpp:401
void masked_copy(std::string const &i, std::string &o, frame::masking_key_type key) const
Copy and mask/unmask in one operation.
Definition: hybi13.hpp:879
WebSocket protocol processor abstract base class.
Definition: processor.hpp:154
size_t copy_extended_header_bytes(uint8_t const *buf, size_t len)
Reads bytes from buf into m_extended_header.
Definition: hybi13.hpp:684
bool get_rsv2(basic_header const &h)
check whether the frame's RSV2 bit is set
Definition: frame.hpp:356
Using a reason requires a close code.
Definition: base.hpp:145
Illegal use of reserved bit.
Definition: base.hpp:94
Provides streaming UTF8 validation functionality.
opcode::value get_opcode(basic_header const &h)
Extract opcode from basic header.
Definition: frame.hpp:392
bool reserved(value code)
Test whether a close code is in a reserved range.
Definition: close.hpp:164
size_t process_payload_bytes(uint8_t *buf, size_t len, lib::error_code &ec)
Reads bytes from buf into message payload.
Definition: hybi13.hpp:707
static uint8_t const payload_size_basic
Maximum size of a basic WebSocket payload.
Definition: frame.hpp:155
std::vector< std::pair< std::string, attribute_list > > parameter_list
The type of an HTTP parameter list.
Definition: constants.hpp:51
lib::error_code prepare_control(frame::opcode::value op, std::string const &payload, message_ptr out) const
Generic prepare control frame with opcode and payload.
Definition: hybi13.hpp:903
lib::error_code process_handshake(request_type const &request, const std::string &subprotocol, response_type &response) const
Calculate the appropriate response for this websocket request.
Definition: hybi13.hpp:163
masking_key_type get_masking_key(basic_header const &, extended_header const &)
Extract the masking key from a frame header.
Definition: frame.hpp:515
bool get_error() const
Test whether or not the processor is in a fatal error state.
Definition: hybi13.hpp:494
bool invalid(value code)
Test whether a close code is invalid on the wire.
Definition: close.hpp:179
Four byte conversion union.
Definition: frame.hpp:60
Processor encountered invalid payload data.
Definition: base.hpp:82
void byte_mask(input_iter b, input_iter e, output_iter o, masking_key_type const &key, size_t key_offset=0)
Byte by byte mask/unmask.
Definition: frame.hpp:641
std::string base64_encode(unsigned char const *input, size_t len)
Encode a char buffer into a base64 string.
Definition: base64.hpp:66
std::string const & get_origin(request_type const &r) const
Return the value of the header containing the CORS origin.
Definition: hybi13.hpp:273
size_t get_header_len(basic_header const &)
Calculates the full length of the header based on the first bytes.
Definition: frame.hpp:444
std::string get_raw(response_type const &res) const
Given a completed response, get the raw bytes to put on the wire.
Definition: hybi13.hpp:269
Continuation without message.
Definition: base.hpp:100
size_t word_mask_circ(uint8_t *input, uint8_t *output, size_t length, size_t prepared_key)
Circular word aligned mask/unmask.
Definition: frame.hpp:764
lib::error_code extract_subprotocols(request_type const &req, std::vector< std::string > &subprotocol_list)
Extracts requested subprotocols from a handshake request.
Definition: hybi13.hpp:277
The constant size component of a WebSocket frame header.
Definition: frame.hpp:188
Not supported on 32 bit systems.
Definition: base.hpp:112
Extension related operation was ignored because extensions are disabled.
Definition: base.hpp:154
message_ptr get_message()
Retrieves the most recently processed message.
Definition: hybi13.hpp:475
void word_mask_exact(uint8_t *input, uint8_t *output, size_t length, masking_key_type const &key)
Exact word aligned mask/unmask.
Definition: frame.hpp:698
lib::error_code make_error_code(error::processor_errors e)
Create an error code with the given value and the processor category.
Definition: base.hpp:239
uint8_t get_basic_size(basic_header const &)
Extracts the raw payload length specified in the basic header.
Definition: frame.hpp:430
Namespace for the WebSocket++ project.
Definition: base64.hpp:41
uint64_t get_payload_size(basic_header const &, extended_header const &)
Extract the full payload size field from a WebSocket header.
Definition: frame.hpp:572
static unsigned int const MAX_EXTENDED_HEADER_LENGTH
Maximum length of the variable portion of the WebSocket header.
Definition: frame.hpp:51
lib::error_code process_handshake_key(std::string &key) const
Convert a client handshake key into a server response key in place.
Definition: hybi13.hpp:641
lib::error_code prepare_ping(std::string const &in, message_ptr out) const
Get URI.
Definition: hybi13.hpp:596
lib::shared_ptr< uri > uri_ptr
Pointer to a URI.
Definition: uri.hpp:350
The variable size component of a WebSocket frame header.
Definition: frame.hpp:234
static value const no_status
A dummy value to indicate that no status code was received.
Definition: close.hpp:97
Servers may not send masked frames.
Definition: base.hpp:106
Fragmented control message.
Definition: base.hpp:97
Processor encountered a message that was too large.
Definition: base.hpp:79
int get_version() const
Get the protocol version of this processor.
Definition: hybi13.hpp:79
size_t copy_basic_header_bytes(uint8_t const *buf, size_t len)
Reads bytes from buf into m_basic_header.
Definition: hybi13.hpp:652
lib::error_code validate_incoming_extended_header(frame::basic_header h, frame::extended_header e) const
Validate an incoming extended header.
Definition: hybi13.hpp:844
size_t consume(uint8_t *buf, size_t len, lib::error_code &ec)
Process new websocket connection bytes.
Definition: hybi13.hpp:327
lib::error_code client_handshake_request(request_type &req, uri_ptr uri, std::vector< std::string > const &subprotocols) const
Fill in a set of request headers for a client connection request.
Definition: hybi13.hpp:191
std::string prepare_header(const basic_header &h, const extended_header &e)
Generate a properly sized contiguous string that encodes a full frame header.
Definition: frame.hpp:488
static uint16_t const payload_size_extended
Maximum size of an extended WebSocket payload (basic payload = 126)
Definition: frame.hpp:158
size_t byte_mask_circ(uint8_t *input, uint8_t *output, size_t length, size_t prepared_key)
Circular byte aligned mask/unmask.
Definition: frame.hpp:826
Opcode was invalid for requested operation.
Definition: base.hpp:88
lib::error_code validate_incoming_basic_header(frame::basic_header const &h, bool is_server, bool new_msg) const
Validate an incoming basic header.
Definition: hybi13.hpp:766
bool reserved(value v)
Check if an opcode is reserved.
Definition: frame.hpp:117
bool get_fin(basic_header const &h)
Check whether the frame's FIN bit is set.
Definition: frame.hpp:320
uri_ptr get_uri(request_type const &request) const
Extracts client uri from a handshake request.
Definition: hybi13.hpp:296
size_t get_bytes_needed() const
Definition: hybi13.hpp:498
Processor for Hybi version 13 (RFC6455)
Definition: hybi13.hpp:53
lib::error_code validate_server_handshake_response(request_type const &req, response_type &res) const
Validate the server's response to an outgoing handshake request.
Definition: hybi13.hpp:234
static unsigned int const BASIC_HEADER_LENGTH
Minimum length of a WebSocket frame header.
Definition: frame.hpp:47
T::const_iterator ci_find_substr(T const &haystack, T const &needle, std::locale const &loc=std::locale())
Find substring (case insensitive)
Definition: utilities.hpp:103
The processor method was called with invalid arguments.
Definition: base.hpp:85
Payload length not minimally encoded.
Definition: base.hpp:109
bool complete()
Return whether the input sequence ended on a valid utf8 codepoint.
err_str_pair negotiate_extensions(request_type const &req)
Initializes extensions based on the Sec-WebSocket-Extensions header.
Definition: hybi13.hpp:87