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
|
|
|
|
|
|
|
}} |