47 operator = (
const URLSpec ©) {
51 _scheme_end = copy._scheme_end;
52 _username_start = copy._username_start;
53 _username_end = copy._username_end;
54 _server_start = copy._server_start;
55 _server_end = copy._server_end;
56 _port_start = copy._port_start;
57 _port_end = copy._port_end;
58 _path_start = copy._path_start;
59 _path_end = copy._path_end;
60 _query_start = copy._query_start;
72 return _url.substr(0, _scheme_end);
115 if (scheme ==
"http" || scheme.empty()) {
118 }
else if (scheme ==
"https") {
121 }
else if (scheme ==
"socks") {
139 return _url.substr(_server_start, _port_end - _server_start);
155 return _url.substr(_path_start, _path_end - _path_start);
169 return _url.substr(_path_start);
188 lc_scheme.reserve(scheme.length());
189 for (string::const_iterator si = scheme.begin(); si != scheme.end(); ++si) {
190 lc_scheme += tolower(*si);
193 if (lc_scheme.empty()) {
200 length_adjust = -(int)_scheme_end;
201 _url = _url.substr(_scheme_end);
202 _flags &= ~F_has_scheme;
207 if (lc_scheme[lc_scheme.length() - 1] ==
':') {
208 length_adjust = lc_scheme.length();
209 _url = lc_scheme + _url;
212 length_adjust = lc_scheme.length() + 1;
213 _url = lc_scheme +
":" + _url;
220 _flags |= F_has_scheme;
226 if (lc_scheme[lc_scheme.length() - 1] ==
':') {
227 lc_scheme = lc_scheme.substr(0, lc_scheme.length() - 1);
230 int old_length = (int)_scheme_end;
231 length_adjust = scheme.length() - old_length;
232 _url = lc_scheme + _url.substr(_scheme_end);
235 _scheme_end += length_adjust;
236 _username_start += length_adjust;
237 _username_end += length_adjust;
238 _server_start += length_adjust;
239 _server_end += length_adjust;
240 _port_start += length_adjust;
241 _port_end += length_adjust;
242 _path_start += length_adjust;
243 _path_end += length_adjust;
244 _query_start += length_adjust;
256 int extra_slash_adjust = 0;
258 if (authority.empty()) {
263 _username_start -= 2;
264 length_adjust = -((int)_port_end - (
int)_username_start);
265 _url = _url.substr(0, _username_start) + _url.substr(_port_end);
266 _flags &= ~(F_has_authority | F_has_username | F_has_server | F_has_port);
268 _username_end = _username_start;
269 _server_start = _username_start;
270 _server_end = _username_start;
271 _port_start = _username_start;
275 length_adjust = authority.length() + 2;
278 if (
has_path() && _url[_path_start] !=
'/') {
281 extra_slash_adjust = 1;
283 _url = _url.substr(0, _username_start) +
"//" + authority + extra_slash + _url.substr(_port_end);
284 _flags |= F_has_authority;
285 _username_start += 2;
289 int old_length = (int)_port_end - (
int)_username_start;
290 length_adjust = authority.length() - old_length;
291 _url = _url.substr(0, _username_start) + authority + _url.substr(_port_end);
294 _port_end += length_adjust;
295 _path_start += length_adjust;
296 _path_end += length_adjust + extra_slash_adjust;
297 _query_start += length_adjust + extra_slash_adjust;
314 if (!username.empty()) {
315 authority = username +
"@";
406 authority += server_and_port;
424 length_adjust = -((int)_path_end - (
int)_path_start);
425 _url = _url.substr(0, _path_start) + _url.substr(_path_end);
426 _flags &= ~F_has_path;
431 if (cpath[0] !=
'/') {
435 length_adjust = cpath.length();
437 _url = _url.substr(0, _path_start) + cpath + _url.substr(_path_end);
438 _flags |= F_has_path;
443 if (cpath[0] !=
'/') {
447 int old_length = (int)_path_end - (
int)_path_start;
448 length_adjust = cpath.length() - old_length;
449 _url = _url.substr(0, _path_start) + cpath + _url.substr(_path_end);
452 _path_end += length_adjust;
453 _query_start += length_adjust;
469 _url = _url.substr(0, _query_start);
470 _flags &= ~F_has_query;
474 _url = _url.substr(0, _query_start) +
"?" + query;
475 _flags |= F_has_query;
480 _url = _url.substr(0, _query_start) + query;
493 set_url(
const string &url,
bool server_name_expected) {
498 while (p < url.length() && isspace(url[p])) {
502 while (q > p && isspace(url[q - 1])) {
506 _url = url.substr(p, q - p);
511 server_name_expected =
false;
518 for (p = 0; p < _url.length() && _url[p] !=
'?'; p++) {
519 if (_url[p] ==
'\\') {
532 size_t next = _url.find_first_of(
":/", start);
533 if (next < _url.length() - 1 && _url.substr(next, 2) ==
":/") {
535 _flags |= F_has_scheme;
539 for (
size_t p = 0; p < _scheme_end; ++p) {
540 _url[p] = tolower(_url[p]);
548 _username_start = start;
549 _username_end = start;
550 _server_start = start;
563 bool leading_slashes =
564 (start < _url.length() - 1 && _url.substr(start, 2) ==
"//");
565 if (leading_slashes) {
566 has_authority =
true;
573 if (!leading_slashes) {
574 if (start < _url.length() && _url[start] ==
'/') {
576 _url = _url.substr(0, start + 1) + _url.substr(start);
579 _url = _url.substr(0, start) +
"//" + _url.substr(start);
585 _flags |= F_has_authority;
586 _username_start = start;
587 _port_end = _url.find_first_of(
"/?", start);
588 if (_port_end == string::npos) {
589 _port_end = _url.length();
598 if (start < _url.length() && url[start] !=
'?') {
600 _flags |= F_has_path;
602 _path_end = _url.find(
"?", _path_start);
603 if (_path_end == string::npos) {
604 _path_end = _url.length();
610 _query_start = start;
611 if (start < _url.length()) {
612 nassertv(_url[start] ==
'?');
613 _flags |= F_has_query;
640 output(ostream &out)
const {
656 quote(
const string &source,
const string &safe) {
658 result << hex << setfill(
'0');
660 for (string::const_iterator si = source.begin(); si != source.end(); ++si) {
676 }
else if (safe.find(ch) != string::npos) {
682 result <<
'%' << setw(2) << (int)ch;
699 result << hex << setfill(
'0');
701 for (string::const_iterator si = source.begin(); si != source.end(); ++si) {
721 }
else if (safe.find(ch) != string::npos) {
727 result <<
'%' << setw(2) << (int)ch;
747 while (p < source.length()) {
748 if (source[p] ==
'%' && p + 2 < source.length()) {
751 for (
int i = 0; i < 2; i++) {
753 char ch = source[p + i];
757 value = tolower(ch) -
'a' + 10;
759 hex = (hex << 4) | value;
785 while (p < source.length()) {
786 if (source[p] ==
'%' && p + 2 < source.length()) {
789 for (
int i = 0; i < 2; i++) {
791 char ch = source[p + i];
795 value = tolower(ch) -
'a' + 10;
797 hex = (hex << 4) | value;
802 }
else if (source[p] ==
'+') {
826 _flags &= ~(F_has_username | F_has_server | F_has_port);
833 _username_end = _username_start;
834 _port_start = _port_end;
837 _flags |= F_has_server;
838 _server_start = _username_start;
839 _server_end = _port_end;
842 size_t at_sign = _url.find(
'@', _username_start);
843 if (at_sign < _port_end) {
845 _flags |= F_has_username;
846 _username_end = at_sign;
847 _server_start = at_sign + 1;
851 size_t colon = _url.find(
':', _server_start);
852 if (colon < _port_end) {
854 _flags |= F_has_port;
856 _port_start = colon + 1;
860 string port_str = _url.substr(_port_start, _port_end - _port_start);
861 _port = atoi(port_str.c_str());
865 for (
size_t si = _server_start; si != _server_end; ++si) {
866 _url[si] = tolower(_url[si]);
871 if (_server_end > _server_start && _url[_server_end - 1] ==
'.') {
872 _url = _url.substr(0, _server_end - 1) + _url.substr(_server_end);
string get_server_and_port() const
Returns a string consisting of the server name, followed by a colon, followed by the port number...
A container for a URL, e.g.
string get_username() const
Returns the username specified by the URL, if any.
static string quote(const string &source, const string &safe="/")
Returns the source string with all "unsafe" characters quoted, making a string suitable for placing i...
string get_server() const
Returns the server name specified by the URL, if any.
bool has_username() const
Returns true if the URL specifies a username (and/or password), false otherwise.
bool has_authority() const
Returns true if the URL specifies an authority (this includes username, server, and/or port)...
bool has_path() const
Returns true if the URL includes a path specification (that is, the particular filename on the server...
bool is_default_port() const
Returns true if the port number encoded in this URL is the default port number for the scheme (or if ...
int get_port() const
Returns the port number specified by the URL, or the default port if not specified.
static int get_default_port_for_scheme(const string &scheme)
Returns the default port number for the indicated scheme, or 0 if there is no known default...
string get_path_and_query() const
Returns the path (or "/" if no path is specified), followed by the query if it is specified...
bool has_scheme() const
Returns true if the URL specifies a scheme (e.g.
bool has_port() const
Returns true if the URL specifies a port number, false otherwise.
string get_path() const
Returns the path specified by the URL, or "/" if no path is specified.
static string unquote_plus(const string &source)
Reverses the operation of quote_plus(): converts escaped characters of the form "%xx" to their ascii ...
static string unquote(const string &source)
Reverses the operation of quote(): converts escaped characters of the form "%xx" to their ascii equiv...
string get_query() const
Returns the query specified by the URL, or empty string if no query is specified. ...
void set_server(const string &server)
Replaces the server part of the URL specification.
static string quote_plus(const string &source, const string &safe="/")
Behaves like quote() with the additional behavior of replacing spaces with plus signs.
bool has_query() const
Returns true if the URL includes a query specification, false otherwise.
void set_scheme(const string &scheme)
Replaces the scheme part of the URL specification.
const string & get_url() const
Returns the complete URL specification.
string get_scheme() const
Returns the scheme specified by the URL, or empty string if no scheme is specified.
void set_query(const string &query)
Replaces the query part of the URL specification.
void set_authority(const string &authority)
Replaces the authority part of the URL specification.
void set_path(const string &path)
Replaces the path part of the URL specification.
void set_url(const string &url, bool server_name_expected=false)
Completely replaces the URL with the indicated string.
void set_server_and_port(const string &server_and_port)
Replaces the server and port parts of the URL specification simultaneously.
void set_port(const string &port)
Replaces the port part of the URL specification.
void set_username(const string &username)
Replaces the username part of the URL specification.
string get_port_str() const
Returns the port specified by the URL as a string, or the empty string if no port is specified...