File Coverage

/root/.cpan/build/URI-XS-2.1.2-0/clib/src/panda/uri/URI.h
Criterion Covered Total %
statement 135 148 91.2
branch 56 96 58.3
condition n/a
subroutine n/a
pod n/a
total 191 244 78.2


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