WebSocket++  0.8.3-dev
C++ websocket client/server library
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
uri.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_URI_HPP
29 #define WEBSOCKETPP_URI_HPP
30 
31 #include <websocketpp/error.hpp>
32 
33 #include <websocketpp/common/memory.hpp>
34 #include <websocketpp/common/stdint.hpp>
35 
36 #include <algorithm>
37 #include <sstream>
38 #include <string>
39 
40 namespace websocketpp {
41 
42 // TODO: figure out why this fixes horrible linking errors.
43 
44 /// Default port for ws://
45 static uint16_t const uri_default_port = 80;
46 /// Default port for wss://
47 static uint16_t const uri_default_secure_port = 443;
48 
49 
50 
51 /// A group of helper methods for parsing and validating URIs against RFC 3986
52 namespace uri_helper {
53 
54 /// RFC3986 unreserved character test
55 /**
56  * @since 0.8.3
57  *
58  * @param c the char to test
59  * @return True if the character is considered `unreserved`
60  */
61 inline bool unreserved(char c) {
62  if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
63  return true;
64  } else if (c >= '0' && c <= '9') {
65  return true;
66  } else if (c == '-' || c == '.' || c == '_' || c == '~') {
67  return true;
68  } else {
69  return false;
70  }
71 }
72 
73 /// RFC3986 generic delimiter character test
74 /**
75  * @param c the char to test
76  * @return True if the character is considered a generic delimiter
77  */
78 inline bool gen_delim(char c) {
79  switch(c) {
80  case ':':
81  case '/':
82  case '?':
83  case '#':
84  case '[':
85  case ']':
86  case '@':
87  return true;
88  default:
89  return false;
90  }
91 }
92 
93 /// RFC3986 subcomponent delimiter character test
94 /**
95  * @since 0.8.3
96  *
97  * @param c the char to test
98  * @return True if the character is considered a subcomponent delimiter
99  */
100 inline bool sub_delim(char c) {
101  switch(c) {
102  case '!':
103  case '$':
104  case '&':
105  case '\'':
106  case '(':
107  case ')':
108  case '*':
109  case '+':
110  case ',':
111  case ';':
112  case '=':
113  return true;
114  default:
115  return false;
116  }
117 }
118 
119 /// RFC3986 hex digit character test
120 /**
121  * Case insensitive
122  *
123  * @since 0.8.3
124  *
125  * @param c the char to test
126  * @return True if the character is considered a hexadecimal digit
127  */
128 inline bool hexdigit(char c) {
129  switch(c) {
130  case '0':
131  case '1':
132  case '2':
133  case '3':
134  case '4':
135  case '5':
136  case '6':
137  case '7':
138  case '8':
139  case '9':
140  case 'A':
141  case 'B':
142  case 'C':
143  case 'D':
144  case 'E':
145  case 'F':
146  case 'a':
147  case 'b':
148  case 'c':
149  case 'd':
150  case 'e':
151  case 'f':
152  return true;
153  default:
154  return false;
155  }
156 }
157 
158 /// RFC3986 scheme character test
159 /**
160  * @since 0.8.3
161  *
162  * @param c the char to test
163  * @return True if the character is considered a valid character for a uri scheme
164  */
165 inline bool scheme(char c) {
166  if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
167  return true;
168  } else if (c >= '0' && c <= '9') {
169  return true;
170  } else if (c == '+' || c == '-' || c == '.') {
171  return true;
172  } else {
173  return false;
174  }
175 }
176 
177 /// RFC3986 digit character test
178 /**
179  * @since 0.8.3
180  *
181  * @param c the char to test
182  * @return True if the character is considered a digit (0-9)
183  */
184 inline bool digit(char c) {
185  return c >= '0' && c <= '9';
186 }
187 
188 /// RFC3986 digit character test (iterator version)
189 /**
190  * @since 0.8.3
191  *
192  * @param c the char to test
193  * @return True if the character is considered a digit (0-9)
194  */
195 inline bool digit(std::string::const_iterator it) {
196  return digit(*it);
197 }
198 
199 
200 /// RFC3986 per cent encoded character test
201 /**
202  * caller must range check (only caller knows the actual range)
203  * caller must check for leading %
204  *
205  * @since 0.8.3
206  *
207  * @param it An iterator to the first character after the % sign
208  * @return True if both the character pointed at by the iterator and
209  * the next one represent a valid RFC3986 percent encoding
210  */
211 inline bool pct_encoded(std::string::const_iterator it) {
212  return hexdigit(*it) && hexdigit(*(it + 1));
213 }
214 
215 /// Tests a range for a valid IPv4 decimal octet
216 /**
217  * @since 0.8.3
218  *
219  * @param start An iterator to the first character of the range to check (inclusive)
220  * @param start An iterator to the last character of the range to check (exclusive)
221  * @return True if the range represents a valid IPv4 decimal octet (0-255)
222  */
223 inline bool dec_octet(std::string::const_iterator start, std::string::const_iterator end) {
224  if (end-start == 1) {
225  return digit(start);
226  } else if (end-start == 2) {
227  return ((*start >= '1' && *start <= '9') && digit(start+1));
228  } else if (end-start == 3) {
229  if (*start == '1') {
230  return digit(start+1) && digit(start+2);
231  } else if (*start == '2') {
232  if (*(start+1) >= '0' && *(start+1) <= '4') {
233  return digit(start+2);
234  } else if (*(start+1) == '5') {
235  return *(start+2) >= '0' && *(start+2) <= '5';
236  }
237  }
238  }
239  return false;
240 }
241 
242 /// Tests a range for a valid IPv4 literal
243 /**
244  * @since 0.8.3
245  *
246  * @param start An iterator to the first character of the range to check (inclusive)
247  * @param start An iterator to the last character of the range to check (exclusive)
248  * @return True if the range represents a valid IPv4 literal address
249  */
250 inline bool ipv4_literal(std::string::const_iterator start, std::string::const_iterator end) {
251  std::string::const_iterator cursor = start;
252  size_t counter = 0;
253  for (std::string::const_iterator it = start; it != end; ++it) {
254  if (*it == '.') {
255  if (dec_octet(cursor,it)) {
256  cursor = it+1;
257  counter++;
258  if (counter > 3) {
259  return false;
260  }
261  } else {
262  return false;
263  }
264  }
265  }
266 
267  // check final octet
268  return (counter == 3 && dec_octet(cursor,end));
269 }
270 
271 /// Tests a range for a valid IPv6 hex quad
272 /**
273  * @since 0.8.3
274  *
275  * @param start An iterator to the first character of the range to check (inclusive)
276  * @param start An iterator to the last character of the range to check (exclusive)
277  * @return True if the range represents a valid IPv6 hex quad
278  */
279 inline bool hex4(std::string::const_iterator start, std::string::const_iterator end) {
280  if (end-start == 0 || end-start >4) {
281  return false;
282  }
283  for (std::string::const_iterator it = start; it != end; ++it) {
284  if (!hexdigit(*it)) {
285  return false;
286  }
287  }
288  return true;
289 }
290 
291 /// Tests a range for a valid IPv6 literal
292 /**
293  * @since 0.8.3
294  *
295  * @param start An iterator to the first character of the range to check (inclusive)
296  * @param start An iterator to the last character of the range to check (exclusive)
297  * @return True if the range represents a valid IPv6 literal
298  */
299 inline bool ipv6_literal(std::string::const_iterator start, std::string::const_iterator end) {
300  // initial range check
301  if (end-start > 45 && end-start >= 2) {
302  return false;
303  }
304 
305  // peal off and count hex4s until we run out of colons,
306  // note the abbreviation marker if we see one.
307  std::string::const_iterator cursor = start;
308  std::string::const_iterator it = start;
309  size_t count = 0;
310  size_t abbr = 0;
311  while (it != end) {
312  if (*it == ':') {
313  if (it == start) {
314  // if a : happens at the beginning, don't check for a hex quad, just advance
315  // the cursor. The abbreviation marker will be counted on the next pass
316  cursor++;
317  } else if (it-cursor == 0) {
318  // this is a double colon abbreviation marker
319  cursor++;
320  abbr++;
321  } else if (hex4(cursor,it)) {
322  cursor = it+1;
323  count++;
324  } else {
325  return false;
326  }
327  }
328  it++;
329  }
330 
331  // final bit either needs to be a hex4 or an IPv4 literal
332  if (cursor == end) {
333  // fine
334  } else if (hex4(cursor,end)) {
335  count++;
336  } else if (ipv4_literal(cursor, end)) {
337  count += 2;
338  } else {
339  return false;
340  }
341 
342  if ((abbr == 0 && count != 8) || (abbr == 1 && count > 7) || abbr > 1) {
343  return false;
344  }
345 
346  return true;
347 }
348 
349 /// Tests a character for validity for a registry name
350 /**
351  * will fail on %, which is valid, but only when used as a part of a multiple
352  * character escape sequence. Since this test checks a single character it
353  * can't tell whether a % character is valid so it returns false. The caller
354  * needs to catch and handle %s in another way.
355  *
356  * @since 0.8.3
357  *
358  * @param c The character to test
359  * @return True if the range represents a valid IPv6 literal
360  */
361 inline bool reg_name(char c) {
362  return unreserved(c) || sub_delim(c);
363 }
364 
365 /// Tests a range for validity for a registry name
366 /**
367  * @since 0.8.3
368  *
369  * @param start An iterator to the first character of the range to check (inclusive)
370  * @param start An iterator to the last character of the range to check (exclusive)
371  * @return True if the range represents a valid registry name
372  */
373 inline bool reg_name(std::string::const_iterator start, std::string::const_iterator end) {
374  std::string::const_iterator it = start;
375  while (it != end) {
376  if (*it == '%') {
377  // check for valid % encoded char
378  if (it+2 < end && uri_helper::pct_encoded(it+1)) {
379  it += 3;
380  continue;
381  } else {
382  return false;
383  }
384  } else if (!uri_helper::reg_name(*it)) {
385  return false;
386  }
387  ++it;
388  }
389  return true;
390 }
391 
392 } // end namespace uri_helper
393 
394 
395 
396 
397 class uri {
398 public:
399  explicit uri(std::string const & uri_string) : m_valid(false), m_ipv6_literal(false) {
400  std::string::const_iterator it;
401  std::string::const_iterator temp;
402 
403  int state = 0;
404 
405  it = uri_string.begin();
406  size_t uri_len = uri_string.length();
407 
408  // extract scheme. We only consider Websocket and HTTP URI schemes as valid
409  if (uri_len >= 7 && std::equal(it,it+6,"wss://")) {
410  m_secure = true;
411  m_scheme = "wss";
412  it += 6;
413  } else if (uri_len >= 6 && std::equal(it,it+5,"ws://")) {
414  m_secure = false;
415  m_scheme = "ws";
416  it += 5;
417  } else if (uri_len >= 8 && std::equal(it,it+7,"http://")) {
418  m_secure = false;
419  m_scheme = "http";
420  it += 7;
421  } else if (uri_len >= 9 && std::equal(it,it+8,"https://")) {
422  m_secure = true;
423  m_scheme = "https";
424  it += 8;
425  } else {
426  return;
427  }
428 
429  // extract host.
430  // either a host string
431  // an IPv4 address
432  // or an IPv6 address
433  if (*it == '[') {
434  ++it;
435  // IPv6 literal
436  // extract IPv6 digits until ]
437 
438  // TODO: this doesn't work on g++... not sure why
439  //temp = std::find(it,it2,']');
440 
441  temp = it;
442  while (temp != uri_string.end()) {
443  if (*temp == ']') {
444  break;
445  }
446  ++temp;
447  }
448 
449  if (temp == uri_string.end()) {
450  return;
451  } else {
452  // validate IPv6 literal parts
453  if (!uri_helper::ipv6_literal(it,temp)) {
454  return;
455  } else {
456  m_ipv6_literal = true;
457  }
458  m_host.append(it,temp);
459  }
460  it = temp+1;
461  if (it == uri_string.end()) {
462  state = 2;
463  } else if (*it == '/' || *it == '?' || *it == '#') {
464  // todo: better path parsing
465  state = 2;
466 
467  // we don't increment the iterator here because we want the
468  // delimiter to be read again as a part of the path
469  } else if (*it == ':') {
470  state = 1;
471 
472  // start reading port after the delimiter
473  ++it;
474  } else {
475  // problem
476  return;
477  }
478  } else {
479  // IPv4 or hostname
480  // extract until : or first path component
481  while (state == 0) {
482  if (it == uri_string.end()) {
483  state = 2;
484  break;
485  } else if (*it == '%') {
486  // check for valid % encoded char
487  if (it+2 < uri_string.end() && uri_helper::pct_encoded(it+1)) {
488  m_host.append(it,it+2);
489  it += 3;
490  }
491  } else if (!uri_helper::reg_name(*it)) {
492  // we hit one of the general delimiters
493  if (*it == ':') {
494  // got host vs port delimiter
495  // end hostname start port
496  state = 1;
497 
498  // start reading port after the delimiter
499  ++it;
500  } else if (*it == '/' || *it == '#' || *it == '?') {
501  // one of the normal authority vs path delimiters
502  // end hostname and start parsing path
503  state = 2;
504 
505  // we don't increment the iterator here because we want the
506  // delimiter to be read again as a part of the path
507  } else {
508  // either @, [, or ]
509  // @ = userinfo fragment
510  // [ and ] = illegal, basically
511  return;
512  }
513  } else {
514  m_host += *it;
515  ++it;
516  }
517 
518  }
519  }
520 
521  // parse port
522  std::string port;
523  while (state == 1) {
524  if (it == uri_string.end()) {
525  // if we stop parsing the port and there wasn't actually a port
526  // we have an invalid URI
527  if (port.empty()) {
528  return;
529  }
530  state = 3;
531  } else if (uri_helper::digit(it)) {
532  port += *it;
533  ++it;
534  } else {
535  // if we stop parsing the port and there wasn't actually a port
536  // we have an invalid URI
537  if (port.empty()) {
538  return;
539  }
540  state = 3;
541 
542  // we don't increment the iterator here because we want the
543  // delimiter to be read again as a part of the path
544  }
545 
546  }
547 
548  lib::error_code ec;
549  m_port = get_port_from_string(port, ec);
550 
551  if (ec) {
552  return;
553  }
554 
555  // step back one so the first char of the path delimiter doesn't get eaten
556  m_resource.append(it,uri_string.end());
557 
558  if (m_resource.empty()) {
559  m_resource = "/";
560  }
561 
562  // todo: validate path component
563 
564 
565  m_valid = true;
566  }
567 
568  uri(bool secure, std::string const & host, uint16_t port,
569  std::string const & resource)
570  : m_scheme(secure ? "wss" : "ws")
571  , m_host(host)
572  , m_resource(resource.empty() ? "/" : resource)
573  , m_port(port)
574  , m_secure(secure)
575  {
576  m_ipv6_literal = uri_helper::ipv6_literal(host.begin(), host.end());
577  m_valid = m_ipv6_literal || uri_helper::reg_name(host.begin(), host.end());
578  }
579 
580  uri(bool secure, std::string const & host, std::string const & resource)
581  : m_scheme(secure ? "wss" : "ws")
582  , m_host(host)
583  , m_resource(resource.empty() ? "/" : resource)
584  , m_port(secure ? uri_default_secure_port : uri_default_port)
585  , m_secure(secure)
586  {
587  m_ipv6_literal = uri_helper::ipv6_literal(host.begin(), host.end());
588  m_valid = m_ipv6_literal || uri_helper::reg_name(host.begin(), host.end());
589  }
590 
591  uri(bool secure, std::string const & host, std::string const & port,
592  std::string const & resource)
593  : m_scheme(secure ? "wss" : "ws")
594  , m_host(host)
595  , m_resource(resource.empty() ? "/" : resource)
596  , m_secure(secure)
597  {
598  lib::error_code ec;
599  m_port = get_port_from_string(port,ec);
600  m_ipv6_literal = uri_helper::ipv6_literal(host.begin(), host.end());
601 
602  m_valid = !ec && (m_ipv6_literal || uri_helper::reg_name(host.begin(), host.end()));
603  }
604 
605  uri(std::string const & scheme, std::string const & host, uint16_t port,
606  std::string const & resource)
607  : m_scheme(scheme)
608  , m_host(host)
609  , m_resource(resource.empty() ? "/" : resource)
610  , m_port(port)
611  , m_secure(scheme == "wss" || scheme == "https")
612  {
613  m_ipv6_literal = uri_helper::ipv6_literal(host.begin(), host.end());
614  m_valid = m_ipv6_literal || uri_helper::reg_name(host.begin(), host.end());
615  }
616 
617  uri(std::string scheme, std::string const & host, std::string const & resource)
618  : m_scheme(scheme)
619  , m_host(host)
620  , m_resource(resource.empty() ? "/" : resource)
621  , m_port((scheme == "wss" || scheme == "https") ? uri_default_secure_port : uri_default_port)
622  , m_secure(scheme == "wss" || scheme == "https")
623  {
624  m_ipv6_literal = uri_helper::ipv6_literal(host.begin(), host.end());
625  m_valid = m_ipv6_literal || uri_helper::reg_name(host.begin(), host.end());
626  }
627 
628  uri(std::string const & scheme, std::string const & host,
629  std::string const & port, std::string const & resource)
630  : m_scheme(scheme)
631  , m_host(host)
632  , m_resource(resource.empty() ? "/" : resource)
633  , m_secure(scheme == "wss" || scheme == "https")
634  {
635  lib::error_code ec;
636  m_port = get_port_from_string(port,ec);
637  m_ipv6_literal = uri_helper::ipv6_literal(host.begin(), host.end());
638 
639  m_valid = !ec && (m_ipv6_literal || uri_helper::reg_name(host.begin(), host.end()));
640  }
641 
642  bool get_valid() const {
643  return m_valid;
644  }
645 
646  // Check whether the host of this URI is an IPv6 literal address
647  /**
648  * @since 0.8.3
649  * @return True if the host of this URI is an IPv6 literal address
650  */
651  bool is_ipv6_literal() const {
652  return m_ipv6_literal;
653  }
654 
655  bool get_secure() const {
656  return m_secure;
657  }
658 
659  std::string const & get_scheme() const {
660  return m_scheme;
661  }
662 
663  std::string const & get_host() const {
664  return m_host;
665  }
666 
667  std::string get_host_port() const {
668  if (m_port == (m_secure ? uri_default_secure_port : uri_default_port)) {
669  // todo: should this have brackets for v6?
670  return m_host;
671  } else {
672  std::stringstream p;
673  if (m_ipv6_literal) {
674  p << "[" << m_host << "]:" << m_port;
675  } else {
676  p << m_host << ":" << m_port;
677  }
678 
679  return p.str();
680  }
681  }
682 
683  std::string get_authority() const {
684  std::stringstream p;
685  if (m_ipv6_literal) {
686  p << "[" << m_host << "]:" << m_port;
687  } else {
688  p << m_host << ":" << m_port;
689  }
690  return p.str();
691  }
692 
693  uint16_t get_port() const {
694  return m_port;
695  }
696 
697  std::string get_port_str() const {
698  std::stringstream p;
699  p << m_port;
700  return p.str();
701  }
702 
703  std::string const & get_resource() const {
704  return m_resource;
705  }
706 
707  std::string str() const {
708  std::stringstream s;
709 
710  s << m_scheme << "://";
711  if (m_ipv6_literal) {
712  s << "[" << m_host << "]";
713  } else {
714  s << m_host;
715  }
716 
717  if (m_port != (m_secure ? uri_default_secure_port : uri_default_port)) {
718  s << ":" << m_port;
719  }
720 
721  s << m_resource;
722  return s.str();
723  }
724 
725  /// Return the query portion
726  /**
727  * Returns the query portion (after the ?) of the URI or an empty string if
728  * there is none.
729  *
730  * @return query portion of the URI.
731  */
732  std::string get_query() const {
733  std::size_t found = m_resource.find('?');
734  if (found != std::string::npos) {
735  return m_resource.substr(found + 1);
736  } else {
737  return "";
738  }
739  }
740 
741  // get fragment
742 
743  // hi <3
744 
745  // get the string representation of this URI
746 
747  //std::string base() const; // is this still needed?
748 
749  // setter methods set some or all (in the case of parse) based on the input.
750  // These functions throw a uri_exception on failure.
751  /*void set_uri(const std::string& uri);
752 
753  void set_secure(bool secure);
754  void set_host(const std::string& host);
755  void set_port(uint16_t port);
756  void set_port(const std::string& port);
757  void set_resource(const std::string& resource);*/
758 private:
759  uint16_t get_port_from_string(std::string const & port, lib::error_code &
760  ec) const
761  {
762  ec = lib::error_code();
763 
764  if (port.empty()) {
765  return (m_secure ? uri_default_secure_port : uri_default_port);
766  }
767 
768  unsigned int t_port = static_cast<unsigned int>(atoi(port.c_str()));
769 
770  if (t_port > 65535) {
771  ec = error::make_error_code(error::invalid_port);
772  }
773 
774  if (t_port == 0) {
775  ec = error::make_error_code(error::invalid_port);
776  }
777 
778  return static_cast<uint16_t>(t_port);
779  }
780 
781  std::string m_scheme;
782  std::string m_host;
783  std::string m_resource;
784  uint16_t m_port;
785  bool m_secure;
786  bool m_valid;
787  bool m_ipv6_literal;
788 };
789 
790 /// Pointer to a URI
792 
793 } // namespace websocketpp
794 
795 #endif // WEBSOCKETPP_URI_HPP
websocketpp::uri_helper::gen_delim
bool gen_delim(char c)
RFC3986 generic delimiter character test.
Definition: uri.hpp:78
websocketpp::uri_helper::scheme
bool scheme(char c)
RFC3986 scheme character test.
Definition: uri.hpp:165
websocketpp::uri_helper::ipv4_literal
bool ipv4_literal(std::string::const_iterator start, std::string::const_iterator end)
Tests a range for a valid IPv4 literal.
Definition: uri.hpp:250
websocketpp::uri_helper::ipv6_literal
bool ipv6_literal(std::string::const_iterator start, std::string::const_iterator end)
Tests a range for a valid IPv6 literal.
Definition: uri.hpp:299
websocketpp::uri::is_ipv6_literal
bool is_ipv6_literal() const
Definition: uri.hpp:651
websocketpp::uri_helper
A group of helper methods for parsing and validating URIs against RFC 3986.
Definition: uri.hpp:52
websocketpp::uri
Definition: uri.hpp:397
websocketpp::versions_supported
static std::vector< int > const versions_supported(helper, helper+4)
Container that stores the list of protocol versions supported.
websocketpp::uri::get_query
std::string get_query() const
Return the query portion.
Definition: uri.hpp:732
websocketpp::uri_helper::digit
bool digit(char c)
RFC3986 digit character test.
Definition: uri.hpp:184
websocketpp::uri_helper::digit
bool digit(std::string::const_iterator it)
RFC3986 digit character test (iterator version)
Definition: uri.hpp:195
websocketpp::uri_helper::dec_octet
bool dec_octet(std::string::const_iterator start, std::string::const_iterator end)
Tests a range for a valid IPv4 decimal octet.
Definition: uri.hpp:223
websocketpp::uri_helper::pct_encoded
bool pct_encoded(std::string::const_iterator it)
RFC3986 per cent encoded character test.
Definition: uri.hpp:211
websocketpp::uri_helper::sub_delim
bool sub_delim(char c)
RFC3986 subcomponent delimiter character test.
Definition: uri.hpp:100
websocketpp::uri_helper::unreserved
bool unreserved(char c)
RFC3986 unreserved character test.
Definition: uri.hpp:61
websocketpp::uri_helper::reg_name
bool reg_name(std::string::const_iterator start, std::string::const_iterator end)
Tests a range for validity for a registry name.
Definition: uri.hpp:373
websocketpp::uri_helper::hexdigit
bool hexdigit(char c)
RFC3986 hex digit character test.
Definition: uri.hpp:128
websocketpp::uri_helper::reg_name
bool reg_name(char c)
Tests a character for validity for a registry name.
Definition: uri.hpp:361
websocketpp::uri_default_secure_port
static uint16_t const uri_default_secure_port
Default port for wss://.
Definition: uri.hpp:47
websocketpp::uri_default_port
static uint16_t const uri_default_port
Default port for ws://.
Definition: uri.hpp:45
websocketpp::uri_helper::hex4
bool hex4(std::string::const_iterator start, std::string::const_iterator end)
Tests a range for a valid IPv6 hex quad.
Definition: uri.hpp:279