File Coverage

src/panda/uri/URI.h
Criterion Covered Total %
statement 16 36 44.4
branch 11 16 68.7
condition n/a
subroutine n/a
pod n/a
total 27 52 51.9


line stmt bran cond sub pod time code
1             #pragma once
2             #include
3             #include
4             #include
5             #include
6             #include
7             #include
8             #include
9             #include
10             #include
11             #include
12             #include
13             #include
14              
15             namespace panda { namespace uri {
16              
17 16 50         struct URIError : std::logic_error {
18 16           explicit URIError (const std::string& what_arg) : logic_error(what_arg) {}
19             };
20              
21 16 50         struct WrongScheme : URIError {
22 16           explicit WrongScheme (const std::string& what_arg) : URIError(what_arg) {}
23             };
24              
25             struct URI : Refcnt {
26             struct Flags {
27             static constexpr const int allow_suffix_reference = 1; // https://tools.ietf.org/html/rfc3986#section-4.5 uri may omit leading "SCHEME://"
28             static constexpr const int query_param_semicolon = 2; // query params are delimited by ';' instead of '&'
29             };
30              
31             template struct Strict;
32             struct http; struct https; struct ftp; struct socks; struct ws; struct wss; struct ssh; struct telnet; struct sftp;
33              
34             using uricreator = URI*(*)(const URI& uri);
35              
36 468           struct SchemeInfo {
37             int index;
38             string scheme;
39             uricreator creator;
40             uint16_t default_port;
41             bool secure;
42             const std::type_info* type_info;
43             };
44              
45             static void register_scheme (const string& scheme, uint16_t default_port, bool secure = false);
46             static void register_scheme (const string& scheme, const std::type_info*, uricreator, uint16_t default_port, bool secure = false);
47              
48             static URI* create (const string& source, int flags = 0) {
49             URI temp(source, flags);
50             if (temp.scheme_info) return temp.scheme_info->creator(temp);
51             else return new URI(temp);
52             }
53              
54             static URI* create (const URI& source) {
55             if (source.scheme_info) return source.scheme_info->creator(source);
56             else return new URI(source);
57             }
58              
59             URI () : scheme_info(NULL), _port(0), _qrev(1), _flags(0) {}
60             URI (const string& s, int flags = 0) : scheme_info(NULL), _port(0), _qrev(1), _flags(flags) { parse(s); }
61             URI (const string& s, const Query& q, int flags = 0) : URI(s, flags) { add_query(q); }
62 23 50         URI (const URI& s) { assign(s); }
63              
64             URI& operator= (const URI& source) { if (this != &source) assign(source); return *this; }
65             URI& operator= (const string& source) { assign(source); return *this; }
66              
67             const string& scheme () const { return _scheme; }
68             const string& user_info () const { return _user_info; }
69             const string& host () const { return _host; }
70             const string& path () const { return _path; }
71             const string& fragment () const { return _fragment; }
72             uint16_t explicit_port () const { return _port; }
73             uint16_t default_port () const { return scheme_info ? scheme_info->default_port : 0; }
74             uint16_t port () const { return _port ? _port : default_port(); }
75             bool secure () const { return scheme_info ? scheme_info->secure : false; }
76              
77 0           virtual void assign (const URI& source) {
78 0           _scheme = source._scheme;
79 0           scheme_info = source.scheme_info;
80 0           _user_info = source._user_info;
81 0           _host = source._host;
82 0           _path = source._path;
83 0           _qstr = source._qstr;
84 0           _query = source._query;
85 0           _query.rev = source._query.rev;
86 0           _qrev = source._qrev;
87 0           _fragment = source._fragment;
88 0           _port = source._port;
89 0           _flags = source._flags;
90 0           }
91              
92             void assign (const string& s, int flags = 0) {
93             clear();
94             _flags = flags;
95             parse(s);
96             }
97              
98             const string& query_string () const {
99             sync_query_string();
100             return _qstr;
101             }
102              
103             const string raw_query () const {
104             sync_query_string();
105             return decode_uri_component(_qstr);
106             }
107              
108             Query& query () {
109             sync_query();
110             return _query;
111             }
112              
113             const Query& query () const {
114             sync_query();
115             return _query;
116             }
117              
118 0           virtual void scheme (const string& scheme) {
119 0           _scheme = scheme;
120 0           sync_scheme_info();
121 0           }
122              
123             void user_info (const string& user_info) { _user_info = user_info; }
124             void host (const string& host) { _host = host; }
125             void fragment (const string& fragment) { _fragment = fragment; }
126             void port (uint16_t port) { _port = port; }
127              
128             void path (const string& path) {
129             if (path && path.front() != '/') {
130             _path = '/';
131             _path += path;
132             }
133             else _path = path;
134             }
135              
136             void query_string (const string& qstr) {
137             _qstr = qstr;
138             ok_qstr();
139             }
140              
141             void raw_query (const string& rq) {
142             _qstr.clear();
143             encode_uri_component(rq, _qstr, URIComponent::query);
144             ok_qstr();
145             }
146              
147             void query (const string& qstr) { query_string(qstr); }
148             void query (const Query& query) {
149             _query = query;
150             ok_query();
151             }
152              
153             void add_query (const string& addstr) {
154             if (!addstr) return;
155             sync_query_string();
156             ok_qstr();
157             if (_qstr) {
158             _qstr.reserve(_qstr.length() + addstr.length() + 1);
159             _qstr += '&';
160             _qstr += addstr;
161             }
162             else _qstr = addstr;
163             }
164              
165             void add_query (const Query& addquery);
166              
167             const string& param (const string_view& key) const {
168             sync_query();
169             const auto& cq = _query;
170             auto it = cq.find(key);
171             return it == cq.cend() ? _empty : it->second;
172             }
173              
174             void param (const string& key, const string& val) {
175             sync_query();
176             auto it = _query.find(key);
177             if (it != _query.cend()) it->second.assign(val);
178             else _query.emplace(key, val);
179             }
180              
181             string explicit_location () const {
182             if (!_port) return _host;
183             return location();
184             }
185              
186             string location () const {
187             string ret(_host.length() + 6); // port is 5 chars max
188             if (_host) ret += _host;
189             ret += ':';
190             char* buf = ret.buf(); // has exactly 5 bytes left
191             auto len = ret.length();
192             auto ptr_start = buf + len;
193             auto res = to_chars(ptr_start, buf + ret.capacity(), port());
194             assert(!res.ec); // because buf is always enough
195             ret.length(len + (res.ptr - ptr_start));
196             return ret;
197             }
198              
199             void location (const string& newloc) {
200             if (!newloc) {
201             _host.clear();
202             _port = 0;
203             return;
204             }
205              
206             size_t delim = newloc.rfind(':');
207             if (delim == string::npos) _host.assign(newloc);
208             else {
209             size_t ipv6end = newloc.rfind(']');
210             if (ipv6end != string::npos && ipv6end > delim) _host.assign(newloc);
211             else {
212             _host.assign(newloc, 0, delim);
213             _port = 0;
214             from_chars(newloc.data() + delim + 1, newloc.data() + newloc.length(), _port);
215             }
216             }
217             }
218              
219             const std::vector path_segments () const;
220              
221             template
222             void path_segments (It begin, It end) {
223             _path.clear();
224             for (auto it = begin; it != end; ++it) {
225             if (!it->length()) continue;
226             _path += '/';
227             _encode_uri_component_append(*it, _path, URIComponent::path_segment);
228             }
229             }
230              
231             string to_string (bool relative = false) const;
232             string relative () const { return to_string(true); }
233              
234             bool equals (const URI& uri) const {
235             if (_path != uri._path || _host != uri._host || _user_info != uri._user_info || _fragment != uri._fragment || _scheme != uri._scheme) return false;
236             if (_port != uri._port && port() != uri.port()) return false;
237             sync_query_string();
238             uri.sync_query_string();
239             return _qstr == uri._qstr;
240             }
241              
242             void swap (URI& uri);
243              
244             string user () const;
245             void user (const string& user);
246              
247             string password () const;
248             void password (const string& password);
249              
250 0 0         virtual ~URI () {}
251              
252             protected:
253             SchemeInfo* scheme_info;
254              
255             virtual void parse (const string& uristr);
256              
257             static SchemeInfo* get_scheme_info (const std::type_info*);
258              
259             private:
260             string _scheme;
261             string _user_info;
262             string _host;
263             string _path;
264             string _fragment;
265             uint16_t _port;
266             mutable string _qstr;
267             mutable Query _query;
268             mutable uint32_t _qrev; // last query rev we've synced query string with (0 if query itself isn't synced with string)
269             int _flags;
270              
271             static const string _empty;
272              
273             void ok_qstr () const { _qrev = 0; }
274 2           void ok_query () const { _qrev = _query.rev - 1; }
275 0           void ok_qboth () const { _qrev = _query.rev; }
276 834 100         bool has_ok_qstr () const { return !_qrev || _qrev == _query.rev; }
    100          
277 102           bool has_ok_query () const { return _qrev != 0; }
278              
279             void clear () {
280             _port = 0;
281             _scheme.clear();
282             scheme_info = NULL;
283             _user_info.clear();
284             _host.clear();
285             _path.clear();
286             _qstr.clear();
287             _query.clear();
288             _fragment.clear();
289             ok_qboth();
290             _flags = 0;
291             }
292              
293             void guess_suffix_reference ();
294              
295             void compile_query () const;
296             void parse_query () const;
297              
298 834 100         void sync_query_string () const { if (!has_ok_qstr()) compile_query(); }
299 102 100         void sync_query () const { if (!has_ok_query()) parse_query(); }
300              
301             void sync_scheme_info ();
302              
303 265           static inline void _encode_uri_component_append (const string_view& src, string& dest, const char* unsafe) {
304 265           char* buf = dest.reserve(dest.length() + src.length()*3) + dest.length();
305 265           size_t final_size = encode_uri_component(src, buf, unsafe);
306 265           dest.length(dest.length() + final_size);
307 265           }
308             };
309              
310             using URISP = iptr;
311              
312             std::ostream& operator<< (std::ostream& os, const URI& uri);
313              
314             inline bool operator== (const URI& lhs, const URI& rhs) { return lhs.equals(rhs); }
315             inline bool operator!= (const URI& lhs, const URI& rhs) { return !lhs.equals(rhs); }
316             inline void swap (URI& l, URI& r) { l.swap(r); }
317              
318             }}