Line data Source code
1 : /* Copyright (c) 2013-2014, ahmet.bilgili@epfl.ch
2 : * 2014, Stefan.Eilemann@epfl.ch
3 : *
4 : * This file is part of Servus <https://github.com/HBPVIS/Servus>
5 : *
6 : * This library is free software; you can redistribute it and/or modify it under
7 : * the terms of the GNU Lesser General Public License version 3.0 as published
8 : * by the Free Software Foundation.
9 : *
10 : * This library is distributed in the hope that it will be useful, but WITHOUT
11 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
13 : * details.
14 : *
15 : * You should have received a copy of the GNU Lesser General Public License
16 : * along with this library; if not, write to the Free Software Foundation, Inc.,
17 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 : */
19 :
20 : #ifndef SERVUS_URI_H
21 : #define SERVUS_URI_H
22 :
23 : #include <servus/api.h>
24 : #include <servus/types.h>
25 :
26 : #include <map>
27 : #include <sstream>
28 :
29 : namespace servus
30 : {
31 : namespace detail
32 : {
33 : class URI;
34 : }
35 :
36 : /**
37 : * The URI class parses the given uri using the generic syntax from RFC3986 and
38 : * RFC6570
39 : * @verbatim
40 : * http://bob@www.example.com:8080/path/?key=value&foo=bar#fragment
41 : * ^ ^ ^ ^ ^ ^ ^ ^
42 : * a b c d e f g h
43 : *
44 : * URI part Range String
45 : * scheme [a, b) "http"
46 : * userinfo [c, d) bob
47 : * host [d, e) "www.example.com"
48 : * port (e, f) 8080
49 : * path [f, g) "/path/"
50 : * query (g, h) "key=value&foo=bar"
51 : * fragment (h,-) "fragment"
52 : * @endverbatim
53 : *
54 : * Queries are parsed into key-value pairs and can be accessed using
55 : * findQuery(), queryBegin() and queryEnd().
56 : *
57 : * We enforce schemas to have the separator "://", not only ":" which is enough
58 : * for the RFC specification.
59 : *
60 : * Example: @include tests/uri.cpp
61 : */
62 : class URI
63 : {
64 : public:
65 : typedef std::map<std::string, std::string> KVMap;
66 : typedef KVMap::const_iterator ConstKVIter;
67 :
68 : /** Construct an empty URI. */
69 : SERVUS_API URI();
70 :
71 : /**
72 : * @param uri URI string to parse.
73 : * @throw std::exception for incomplete URIs, and std::invalid_argument
74 : * if the port is not a number.
75 : */
76 : SERVUS_API explicit URI(const std::string& uri);
77 :
78 : /** @overload URI::URI( const std::string& ) */
79 : SERVUS_API explicit URI(const char* uri);
80 :
81 : /** Copy-construct an URI. */
82 : SERVUS_API URI(const URI& from);
83 :
84 : SERVUS_API ~URI();
85 :
86 : /** Assign the data from another URI. */
87 : SERVUS_API URI& operator=(const URI& rhs);
88 :
89 : /** Equals operator */
90 : SERVUS_API bool operator==(const URI& rhs) const;
91 :
92 : /** Not equals operator */
93 : SERVUS_API bool operator!=(const URI& rhs) const;
94 :
95 : /** @name Getters for uri data */
96 : //@{
97 : SERVUS_API const std::string& getScheme() const;
98 : SERVUS_API const std::string& getUserinfo() const;
99 : SERVUS_API uint16_t getPort() const;
100 : SERVUS_API const std::string& getHost() const;
101 : /** Return the compound authority part of the URI.
102 :
103 : User info added only if not empty, port number added only if it's
104 : different from 0. */
105 : SERVUS_API std::string getAuthority() const;
106 : SERVUS_API const std::string& getPath() const;
107 : SERVUS_API const std::string& getQuery() const;
108 : SERVUS_API const std::string& getFragment() const;
109 : //@}
110 :
111 : /** @name Setters for uri data. */
112 : //@{
113 : SERVUS_API void setScheme(const std::string& scheme);
114 : SERVUS_API void setUserInfo(const std::string& userinfo);
115 : SERVUS_API void setHost(const std::string& host);
116 : SERVUS_API void setPort(uint16_t port);
117 : SERVUS_API void setPath(const std::string& path);
118 : SERVUS_API void setQuery(const std::string& query);
119 : SERVUS_API void setFragment(const std::string& fragment);
120 : //@}
121 :
122 : /** @name Access to key-value data in query. */
123 : //@{
124 : /**
125 : * @return a const iterator to the beginning of the query map.
126 : */
127 : SERVUS_API ConstKVIter queryBegin() const;
128 :
129 : /**
130 : * @return a const iterator to end beginning of the query map.
131 : */
132 : SERVUS_API ConstKVIter queryEnd() const;
133 :
134 : /**
135 : * @return a const iterator to the given key, or queryEnd().
136 : */
137 : SERVUS_API ConstKVIter findQuery(const std::string& key) const;
138 :
139 : /** Add a key-value pair to the query. */
140 : SERVUS_API void addQuery(const std::string& key, const std::string& value);
141 : //@}
142 :
143 : private:
144 : detail::URI* const _impl;
145 : };
146 :
147 13 : inline std::ostream& operator<<(std::ostream& os, const URI& uri)
148 : {
149 13 : if (!uri.getScheme().empty())
150 7 : os << uri.getScheme() << "://";
151 : // A valid URI can't contain the user info or port number alone, so if
152 : // the host name is empty the other two field are simply ignored.
153 13 : if (!uri.getHost().empty())
154 : {
155 7 : if (!uri.getUserinfo().empty())
156 6 : os << uri.getUserinfo() << "@";
157 7 : os << uri.getHost();
158 7 : if (uri.getPort())
159 6 : os << ':' << uri.getPort();
160 : }
161 13 : os << uri.getPath();
162 13 : if (!uri.getQuery().empty())
163 3 : os << '?' << uri.getQuery();
164 13 : if (!uri.getFragment().empty())
165 3 : os << '#' << uri.getFragment();
166 13 : return os;
167 : }
168 : }
169 :
170 : namespace std
171 : {
172 10 : inline std::string to_string(const servus::URI& uri)
173 : {
174 20 : ostringstream os;
175 10 : os << uri;
176 20 : return os.str();
177 : }
178 : }
179 : #endif // SERVUS_URI_H
|