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