22 using std::ostringstream;
57 if (!dirname.empty() && dirname[dirname.size() - 1] ==
'/') {
60 dirname.resize(dirname.size() - 1);
115 hash =
int_hash::add_hash(hash, _flags & (F_has_scheme | F_has_username | F_has_server));
137 return _url.substr(0, _scheme_end);
173 if (scheme ==
"http" || scheme.empty()) {
176 }
else if (scheme ==
"https") {
179 }
else if (scheme ==
"socks") {
196 if (server.find(
':') != string::npos) {
198 strm <<
'[' << server <<
']';
218 return _url.substr(_path_start, _path_end - _path_start);
230 return _url.substr(_path_start);
247 lc_scheme.reserve(scheme.length());
248 for (string::const_iterator si = scheme.begin(); si != scheme.end(); ++si) {
249 lc_scheme += tolower(*si);
252 if (lc_scheme.empty()) {
259 length_adjust = -(int)_scheme_end;
260 _url = _url.substr(_scheme_end);
261 _flags &= ~F_has_scheme;
266 if (lc_scheme[lc_scheme.length() - 1] ==
':') {
267 length_adjust = lc_scheme.length();
268 _url = lc_scheme + _url;
271 length_adjust = lc_scheme.length() + 1;
272 _url = lc_scheme +
":" + _url;
278 _flags |= F_has_scheme;
284 if (lc_scheme[lc_scheme.length() - 1] ==
':') {
285 lc_scheme = lc_scheme.substr(0, lc_scheme.length() - 1);
288 int old_length = (int)_scheme_end;
289 length_adjust = scheme.length() - old_length;
290 _url = lc_scheme + _url.substr(_scheme_end);
293 _scheme_end += length_adjust;
294 _username_start += length_adjust;
295 _username_end += length_adjust;
296 _server_start += length_adjust;
297 _server_end += length_adjust;
298 _port_start += length_adjust;
299 _port_end += length_adjust;
300 _path_start += length_adjust;
301 _path_end += length_adjust;
302 _query_start += length_adjust;
312 int extra_slash_adjust = 0;
314 if (authority.empty()) {
319 _username_start -= 2;
320 length_adjust = -((int)_port_end - (
int)_username_start);
321 _url = _url.substr(0, _username_start) + _url.substr(_port_end);
322 _flags &= ~(F_has_authority | F_has_username | F_has_server | F_has_port);
324 _username_end = _username_start;
325 _server_start = _username_start;
326 _server_end = _username_start;
327 _port_start = _username_start;
331 length_adjust = authority.length() + 2;
334 if (
has_path() && _url[_path_start] !=
'/') {
337 extra_slash_adjust = 1;
339 _url = _url.substr(0, _username_start) +
"//" + authority + extra_slash + _url.substr(_port_end);
340 _flags |= F_has_authority;
341 _username_start += 2;
345 int old_length = (int)_port_end - (
int)_username_start;
346 length_adjust = authority.length() - old_length;
347 _url = _url.substr(0, _username_start) + authority + _url.substr(_port_end);
350 _port_end += length_adjust;
351 _path_start += length_adjust;
352 _path_end += length_adjust + extra_slash_adjust;
353 _query_start += length_adjust + extra_slash_adjust;
368 if (!username.empty()) {
369 authority = username +
"@";
373 if (server.find(
':') != string::npos) {
375 authority +=
"[" + server +
"]";
404 if (server.find(
':') != string::npos) {
406 authority +=
"[" + server +
"]";
434 if (server.find(
':') != string::npos) {
436 authority +=
"[" + server +
"]";
474 authority += server_and_port;
490 length_adjust = -((int)_path_end - (
int)_path_start);
491 _url = _url.substr(0, _path_start) + _url.substr(_path_end);
492 _flags &= ~F_has_path;
497 if (cpath[0] !=
'/') {
501 length_adjust = cpath.length();
503 _url = _url.substr(0, _path_start) + cpath + _url.substr(_path_end);
504 _flags |= F_has_path;
509 if (cpath[0] !=
'/') {
513 int old_length = (int)_path_end - (
int)_path_start;
514 length_adjust = cpath.length() - old_length;
515 _url = _url.substr(0, _path_start) + cpath + _url.substr(_path_end);
518 _path_end += length_adjust;
519 _query_start += length_adjust;
533 _url = _url.substr(0, _query_start);
534 _flags &= ~F_has_query;
538 _url = _url.substr(0, _query_start) +
"?" + query;
539 _flags |= F_has_query;
544 _url = _url.substr(0, _query_start) + query;
554 set_url(
const string &url,
bool server_name_expected) {
559 while (p < url.length() && isspace(url[p])) {
563 while (q > p && isspace(url[q - 1])) {
567 _url = url.substr(p, q - p);
572 server_name_expected =
false;
579 for (p = 0; p < _url.length() && _url[p] !=
'?'; p++) {
580 if (_url[p] ==
'\\') {
586 for (p = 0; p + 2 < _url.length();) {
587 if (_url[p++] ==
'%') {
588 if (_url[p] !=
'%') {
589 _url[p] = toupper(_url[p]);
591 _url[p] = toupper(_url[p]);
605 size_t next = _url.find_first_of(
":/", start);
606 if (next < _url.length() - 1 && _url.substr(next, 2) ==
":/") {
608 _flags |= F_has_scheme;
612 for (
size_t p = 0; p < _scheme_end; ++p) {
613 _url[p] = tolower(_url[p]);
621 _username_start = start;
622 _username_end = start;
623 _server_start = start;
636 bool leading_slashes =
637 (start < _url.length() - 1 && _url.substr(start, 2) ==
"//");
638 if (leading_slashes) {
645 if (!leading_slashes) {
646 if (start < _url.length() && _url[start] ==
'/') {
648 _url = _url.substr(0, start + 1) + _url.substr(start);
651 _url = _url.substr(0, start) +
"//" + _url.substr(start);
657 _flags |= F_has_authority;
658 _username_start = start;
659 _port_end = _url.find_first_of(
"/?", start);
660 if (_port_end == string::npos) {
661 _port_end = _url.length();
670 if (start < _url.length() && url[start] !=
'?') {
672 _flags |= F_has_path;
674 _path_end = _url.find(
"?", _path_start);
675 if (_path_end == string::npos) {
676 _path_end = _url.length();
682 _query_start = start;
683 if (start < _url.length()) {
684 nassertv(_url[start] ==
'?');
685 _flags |= F_has_query;
708 output(ostream &out)
const {
719 quote(
const string &source,
const string &safe) {
720 ostringstream result;
721 result << std::hex << setfill(
'0');
723 for (string::const_iterator si = source.begin(); si != source.end(); ++si) {
739 }
else if (safe.find(ch) != string::npos) {
745 result <<
'%' << setw(2) << (int)ch;
759 ostringstream result;
760 result << std::hex << setfill(
'0');
762 for (string::const_iterator si = source.begin(); si != source.end(); ++si) {
782 }
else if (safe.find(ch) != string::npos) {
788 result <<
'%' << setw(2) << (int)ch;
805 while (p < source.length()) {
806 if (source[p] ==
'%' && p + 2 < source.length()) {
809 for (
int i = 0; i < 2; i++) {
811 char ch = source[p + i];
815 value = tolower(ch) -
'a' + 10;
817 hex = (hex << 4) | value;
841 while (p < source.length()) {
842 if (source[p] ==
'%' && p + 2 < source.length()) {
845 for (
int i = 0; i < 2; i++) {
847 char ch = source[p + i];
851 value = tolower(ch) -
'a' + 10;
853 hex = (hex << 4) | value;
858 }
else if (source[p] ==
'+') {
878 _flags &= ~(F_has_username | F_has_server | F_has_port);
885 _username_end = _username_start;
886 _port_start = _port_end;
889 _flags |= F_has_server;
890 _server_start = _username_start;
891 _server_end = _port_end;
894 size_t at_sign = _url.find(
'@', _username_start);
895 if (at_sign < _port_end) {
897 _flags |= F_has_username;
898 _username_end = at_sign;
899 _server_start = at_sign + 1;
903 size_t bracket = _url.find(
'[', _server_start);
904 if (bracket < _port_end) {
908 bracket = _url.find(
']');
909 if (bracket < _server_end) {
910 _server_end = bracket;
913 size_t colon = _url.find(
':', _server_end);
914 if (colon < _port_end) {
915 _port_start = colon + 1;
920 size_t colon = _url.find(
':', _server_start);
921 if (colon < _port_end) {
924 _port_start = colon + 1;
928 if (_port_start < _port_end) {
929 _flags |= F_has_port;
933 string port_str = _url.substr(_port_start, _port_end - _port_start);
934 _port = (uint16_t)atoi(port_str.c_str());
938 for (
size_t si = _server_start; si != _server_end; ++si) {
939 _url[si] = tolower(_url[si]);
944 if (_server_end > _server_start && _url[_server_end - 1] ==
'.') {
945 _url = _url.substr(0, _server_end - 1) + _url.substr(_server_end);