WebSocket++  0.8.0-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 
35 #include <algorithm>
36 #include <sstream>
37 #include <string>
38 
39 namespace websocketpp {
40 
41 // TODO: figure out why this fixes horrible linking errors.
42 
43 /// Default port for ws://
44 static uint16_t const uri_default_port = 80;
45 /// Default port for wss://
46 static uint16_t const uri_default_secure_port = 443;
47 
48 class uri {
49 public:
50  explicit uri(std::string const & uri_string) : m_valid(false) {
51  std::string::const_iterator it;
52  std::string::const_iterator temp;
53 
54  int state = 0;
55 
56  it = uri_string.begin();
57  size_t uri_len = uri_string.length();
58 
59  if (uri_len >= 7 && std::equal(it,it+6,"wss://")) {
60  m_secure = true;
61  m_scheme = "wss";
62  it += 6;
63  } else if (uri_len >= 6 && std::equal(it,it+5,"ws://")) {
64  m_secure = false;
65  m_scheme = "ws";
66  it += 5;
67  } else if (uri_len >= 8 && std::equal(it,it+7,"http://")) {
68  m_secure = false;
69  m_scheme = "http";
70  it += 7;
71  } else if (uri_len >= 9 && std::equal(it,it+8,"https://")) {
72  m_secure = true;
73  m_scheme = "https";
74  it += 8;
75  } else {
76  return;
77  }
78 
79  // extract host.
80  // either a host string
81  // an IPv4 address
82  // or an IPv6 address
83  if (*it == '[') {
84  ++it;
85  // IPv6 literal
86  // extract IPv6 digits until ]
87 
88  // TODO: this doesn't work on g++... not sure why
89  //temp = std::find(it,it2,']');
90 
91  temp = it;
92  while (temp != uri_string.end()) {
93  if (*temp == ']') {
94  break;
95  }
96  ++temp;
97  }
98 
99  if (temp == uri_string.end()) {
100  return;
101  } else {
102  // validate IPv6 literal parts
103  // can contain numbers, a-f and A-F
104  m_host.append(it,temp);
105  }
106  it = temp+1;
107  if (it == uri_string.end()) {
108  state = 2;
109  } else if (*it == '/') {
110  state = 2;
111  ++it;
112  } else if (*it == ':') {
113  state = 1;
114  ++it;
115  } else {
116  // problem
117  return;
118  }
119  } else {
120  // IPv4 or hostname
121  // extract until : or /
122  while (state == 0) {
123  if (it == uri_string.end()) {
124  state = 2;
125  break;
126  } else if (*it == '/') {
127  state = 2;
128  } else if (*it == ':') {
129  // end hostname start port
130  state = 1;
131  } else {
132  m_host += *it;
133  }
134  ++it;
135  }
136  }
137 
138  // parse port
139  std::string port;
140  while (state == 1) {
141  if (it == uri_string.end()) {
142  // state is not used after this point presently.
143  // this should be re-enabled if it ever is needed in a future
144  // refactoring
145  //state = 3;
146  break;
147  } else if (*it == '/') {
148  state = 3;
149  } else {
150  port += *it;
151  }
152  ++it;
153  }
154 
155  lib::error_code ec;
156  m_port = get_port_from_string(port, ec);
157 
158  if (ec) {
159  return;
160  }
161 
162  m_resource = "/";
163  m_resource.append(it,uri_string.end());
164 
165 
166  m_valid = true;
167  }
168 
169  uri(bool secure, std::string const & host, uint16_t port,
170  std::string const & resource)
171  : m_scheme(secure ? "wss" : "ws")
172  , m_host(host)
173  , m_resource(resource.empty() ? "/" : resource)
174  , m_port(port)
175  , m_secure(secure)
176  , m_valid(true) {}
177 
178  uri(bool secure, std::string const & host, std::string const & resource)
179  : m_scheme(secure ? "wss" : "ws")
180  , m_host(host)
181  , m_resource(resource.empty() ? "/" : resource)
182  , m_port(secure ? uri_default_secure_port : uri_default_port)
183  , m_secure(secure)
184  , m_valid(true) {}
185 
186  uri(bool secure, std::string const & host, std::string const & port,
187  std::string const & resource)
188  : m_scheme(secure ? "wss" : "ws")
189  , m_host(host)
190  , m_resource(resource.empty() ? "/" : resource)
191  , m_secure(secure)
192  {
193  lib::error_code ec;
194  m_port = get_port_from_string(port,ec);
195  m_valid = !ec;
196  }
197 
198  uri(std::string const & scheme, std::string const & host, uint16_t port,
199  std::string const & resource)
200  : m_scheme(scheme)
201  , m_host(host)
202  , m_resource(resource.empty() ? "/" : resource)
203  , m_port(port)
204  , m_secure(scheme == "wss" || scheme == "https")
205  , m_valid(true) {}
206 
207  uri(std::string scheme, std::string const & host, std::string const & resource)
208  : m_scheme(scheme)
209  , m_host(host)
210  , m_resource(resource.empty() ? "/" : resource)
211  , m_port((scheme == "wss" || scheme == "https") ? uri_default_secure_port : uri_default_port)
212  , m_secure(scheme == "wss" || scheme == "https")
213  , m_valid(true) {}
214 
215  uri(std::string const & scheme, std::string const & host,
216  std::string const & port, std::string const & resource)
217  : m_scheme(scheme)
218  , m_host(host)
219  , m_resource(resource.empty() ? "/" : resource)
220  , m_secure(scheme == "wss" || scheme == "https")
221  {
222  lib::error_code ec;
223  m_port = get_port_from_string(port,ec);
224  m_valid = !ec;
225  }
226 
227  bool get_valid() const {
228  return m_valid;
229  }
230 
231  bool get_secure() const {
232  return m_secure;
233  }
234 
235  std::string const & get_scheme() const {
236  return m_scheme;
237  }
238 
239  std::string const & get_host() const {
240  return m_host;
241  }
242 
243  std::string get_host_port() const {
244  if (m_port == (m_secure ? uri_default_secure_port : uri_default_port)) {
245  return m_host;
246  } else {
247  std::stringstream p;
248  p << m_host << ":" << m_port;
249  return p.str();
250  }
251  }
252 
253  std::string get_authority() const {
254  std::stringstream p;
255  p << m_host << ":" << m_port;
256  return p.str();
257  }
258 
259  uint16_t get_port() const {
260  return m_port;
261  }
262 
263  std::string get_port_str() const {
264  std::stringstream p;
265  p << m_port;
266  return p.str();
267  }
268 
269  std::string const & get_resource() const {
270  return m_resource;
271  }
272 
273  std::string str() const {
274  std::stringstream s;
275 
276  s << m_scheme << "://" << m_host;
277 
278  if (m_port != (m_secure ? uri_default_secure_port : uri_default_port)) {
279  s << ":" << m_port;
280  }
281 
282  s << m_resource;
283  return s.str();
284  }
285 
286  /// Return the query portion
287  /**
288  * Returns the query portion (after the ?) of the URI or an empty string if
289  * there is none.
290  *
291  * @return query portion of the URI.
292  */
293  std::string get_query() const {
294  std::size_t found = m_resource.find('?');
295  if (found != std::string::npos) {
296  return m_resource.substr(found + 1);
297  } else {
298  return "";
299  }
300  }
301 
302  // get fragment
303 
304  // hi <3
305 
306  // get the string representation of this URI
307 
308  //std::string base() const; // is this still needed?
309 
310  // setter methods set some or all (in the case of parse) based on the input.
311  // These functions throw a uri_exception on failure.
312  /*void set_uri(const std::string& uri);
313 
314  void set_secure(bool secure);
315  void set_host(const std::string& host);
316  void set_port(uint16_t port);
317  void set_port(const std::string& port);
318  void set_resource(const std::string& resource);*/
319 private:
320  uint16_t get_port_from_string(std::string const & port, lib::error_code &
321  ec) const
322  {
323  ec = lib::error_code();
324 
325  if (port.empty()) {
326  return (m_secure ? uri_default_secure_port : uri_default_port);
327  }
328 
329  unsigned int t_port = static_cast<unsigned int>(atoi(port.c_str()));
330 
331  if (t_port > 65535) {
332  ec = error::make_error_code(error::invalid_port);
333  }
334 
335  if (t_port == 0) {
336  ec = error::make_error_code(error::invalid_port);
337  }
338 
339  return static_cast<uint16_t>(t_port);
340  }
341 
342  std::string m_scheme;
343  std::string m_host;
344  std::string m_resource;
345  uint16_t m_port;
346  bool m_secure;
347  bool m_valid;
348 };
349 
350 /// Pointer to a URI
352 
353 } // namespace websocketpp
354 
355 #endif // WEBSOCKETPP_URI_HPP
std::string get_query() const
Return the query portion.
Definition: uri.hpp:293
void handle_accept(connection_ptr con, lib::error_code const &ec)
Handler callback for start_accept.
static uint16_t const uri_default_port
Default port for ws://.
Definition: uri.hpp:44
static uint16_t const uri_default_secure_port
Default port for wss://.
Definition: uri.hpp:46