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