diff --git a/panda/src/downloader/Sources.pp b/panda/src/downloader/Sources.pp index d410d68507..7e0e393bc5 100644 --- a/panda/src/downloader/Sources.pp +++ b/panda/src/downloader/Sources.pp @@ -14,6 +14,7 @@ config_downloader.h asyncUtility.I asyncUtility.h \ extractor.h multiplexStream.I multiplexStream.h \ multiplexStreamBuf.I multiplexStreamBuf.h \ + urlSpec.I urlSpec.h \ $[if $[HAVE_NET], downloadDb.I downloadDb.h downloader.I downloader.h] \ $[if $[HAVE_ZLIB], decompressor.h zcompressor.I zcompressor.h download_utils.h] \ $[if $[HAVE_CRYPTO], patcher.cxx patcher.h patcher.I] @@ -21,6 +22,7 @@ #define INCLUDED_SOURCES \ config_downloader.cxx asyncUtility.cxx \ extractor.cxx multiplexStream.cxx multiplexStreamBuf.cxx \ + urlSpec.cxx \ $[if $[HAVE_NET], downloadDb.cxx downloader.cxx] \ $[if $[HAVE_ZLIB], decompressor.cxx zcompressor.cxx download_utils.cxx] @@ -34,8 +36,17 @@ multiplexStream.I multiplexStream.h \ multiplexStreamBuf.I multiplexStreamBuf.I \ patcher.h patcher.I \ + urlSpec.h urlSpec.I \ zcompressor.I zcompressor.h #define IGATESCAN all #end lib_target + +#begin test_bin_target + #define TARGET test_proxy + + #define SOURCES test_proxy.cxx + #define LOCAL_LIBS $[LOCAL_LIBS] putil net + #define OTHER_LIBS $[OTHER_LIBS] pystub +#end test_bin_target diff --git a/panda/src/downloader/downloader_composite1.cxx b/panda/src/downloader/downloader_composite1.cxx index 8625c82ea1..feef27e5fd 100644 --- a/panda/src/downloader/downloader_composite1.cxx +++ b/panda/src/downloader/downloader_composite1.cxx @@ -3,4 +3,5 @@ #include "extractor.cxx" #include "multiplexStream.cxx" #include "multiplexStreamBuf.cxx" +#include "urlSpec.cxx" diff --git a/panda/src/downloader/urlSpec.I b/panda/src/downloader/urlSpec.I new file mode 100644 index 0000000000..d59da05430 --- /dev/null +++ b/panda/src/downloader/urlSpec.I @@ -0,0 +1,204 @@ +// Filename: urlSpec.I +// Created by: drose (24Sep02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: URLSpec::Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE URLSpec:: +URLSpec(const string &url) { + (*this) = url; +} + +//////////////////////////////////////////////////////////////////// +// Function: URLSpec::Copy Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE URLSpec:: +URLSpec(const URLSpec ©) { + (*this) = copy; +} + +//////////////////////////////////////////////////////////////////// +// Function: URLSpec::Assignment Operator +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void URLSpec:: +operator = (const string &url) { + set_url(url); +} + +//////////////////////////////////////////////////////////////////// +// Function: URLSpec::has_scheme +// Access: Published +// Description: Returns true if the URL specifies a scheme +// (e.g. "http:"), false otherwise. +//////////////////////////////////////////////////////////////////// +INLINE bool URLSpec:: +has_scheme() const { + return (_flags & F_has_scheme) != 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: URLSpec::has_authority +// Access: Published +// Description: Returns true if the URL specifies an authority +// (this includes username, server, and/or port), false +// otherwise. +//////////////////////////////////////////////////////////////////// +INLINE bool URLSpec:: +has_authority() const { + return (_flags & F_has_authority) != 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: URLSpec::has_username +// Access: Published +// Description: Returns true if the URL specifies a username +// (and/or password), false otherwise. +//////////////////////////////////////////////////////////////////// +INLINE bool URLSpec:: +has_username() const { + return (_flags & F_has_username) != 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: URLSpec::has_server +// Access: Published +// Description: Returns true if the URL specifies a server name, +// false otherwise. +//////////////////////////////////////////////////////////////////// +INLINE bool URLSpec:: +has_server() const { + return (_flags & F_has_server) != 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: URLSpec::has_port +// Access: Published +// Description: Returns true if the URL specifies a port number, +// false otherwise. +//////////////////////////////////////////////////////////////////// +INLINE bool URLSpec:: +has_port() const { + return (_flags & F_has_port) != 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: URLSpec::has_path +// Access: Published +// Description: Returns true if the URL includes a path specification +// (that is, the particular filename on the server to +// retrieve), false otherwise. +//////////////////////////////////////////////////////////////////// +INLINE bool URLSpec:: +has_path() const { + return (_flags & F_has_path) != 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: URLSpec::has_query +// Access: Published +// Description: Returns true if the URL includes a query +// specification, false otherwise. +//////////////////////////////////////////////////////////////////// +INLINE bool URLSpec:: +has_query() const { + return (_flags & F_has_query) != 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: URLSpec::get_authority +// Access: Published +// Description: Returns the authority specified by the URL (this +// includes username, server, and/or port), or empty +// string if no authority is specified. +//////////////////////////////////////////////////////////////////// +INLINE string URLSpec:: +get_authority() const { + return _url.substr(_username_start, _port_end - _username_start); +} + +//////////////////////////////////////////////////////////////////// +// Function: URLSpec::get_username +// Access: Published +// Description: Returns the username specified by the URL, if any. +// This might also include a password, +// e.g. "username:password", although putting a password +// on the URL is probably a bad idea. +//////////////////////////////////////////////////////////////////// +INLINE string URLSpec:: +get_username() const { + return _url.substr(_username_start, _username_end - _username_start); +} + +//////////////////////////////////////////////////////////////////// +// Function: URLSpec::get_server +// Access: Published +// Description: Returns the server name specified by the URL, if any. +//////////////////////////////////////////////////////////////////// +INLINE string URLSpec:: +get_server() const { + return _url.substr(_server_start, _server_end - _server_start); +} + +//////////////////////////////////////////////////////////////////// +// Function: URLSpec::get_port_str +// Access: Published +// Description: Returns the port specified by the URL as a string, or +// the empty string if no port is specified. Compare +// this with get_port(), which returns a default port +// number if no port is specified. +//////////////////////////////////////////////////////////////////// +INLINE string URLSpec:: +get_port_str() const { + return _url.substr(_port_start, _port_end - _port_start); +} + +//////////////////////////////////////////////////////////////////// +// Function: URLSpec::get_query +// Access: Published +// Description: Returns the query specified by the URL, or empty +// string if no query is specified. +//////////////////////////////////////////////////////////////////// +INLINE string URLSpec:: +get_query() const { + return _url.substr(_query_start); +} + +//////////////////////////////////////////////////////////////////// +// Function: URLSpec::get_url +// Access: Published +// Description: Returns the complete URL specification. +//////////////////////////////////////////////////////////////////// +INLINE const string &URLSpec:: +get_url() const { + return _url; +} + +INLINE ostream & +operator << (ostream &out, const URLSpec &url) { + url.output(out); + return out; +} + + diff --git a/panda/src/downloader/urlSpec.cxx b/panda/src/downloader/urlSpec.cxx new file mode 100644 index 0000000000..0ee77bd189 --- /dev/null +++ b/panda/src/downloader/urlSpec.cxx @@ -0,0 +1,676 @@ +// Filename: urlSpec.cxx +// Created by: drose (24Sep02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "urlSpec.h" + +#include + + +//////////////////////////////////////////////////////////////////// +// Function: URLSpec::Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +URLSpec:: +URLSpec() { + _port = 0; + _flags = 0; + _scheme_end = 0; + _username_start = 0; + _username_end = 0; + _server_start = 0; + _server_end = 0; + _port_start = 0; + _port_end = 0; + _path_start = 0; + _path_end = 0; + _query_start = 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: URLSpec::Copy Assignment Operator +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +void URLSpec:: +operator = (const URLSpec ©) { + _url = copy._url; + _port = copy._port; + _flags = copy._flags; + _scheme_end = copy._scheme_end; + _username_start = copy._username_start; + _username_end = copy._username_end; + _server_start = copy._server_start; + _server_end = copy._server_end; + _port_start = copy._port_start; + _port_end = copy._port_end; + _path_start = copy._path_start; + _path_end = copy._path_end; + _query_start = copy._query_start; +} + +//////////////////////////////////////////////////////////////////// +// Function: URLSpec::get_scheme +// Access: Published +// Description: Returns the scheme specified by the URL, or "http" +// if no scheme is specified. +//////////////////////////////////////////////////////////////////// +string URLSpec:: +get_scheme() const { + if (has_scheme()) { + return _url.substr(0, _scheme_end); + } + return "http"; +} + +//////////////////////////////////////////////////////////////////// +// Function: URLSpec::get_port +// Access: Published +// Description: Returns the port number specified by the URL, or the +// default port if not specified. +//////////////////////////////////////////////////////////////////// +int URLSpec:: +get_port() const { + if (has_port()) { + return _port; + } + string scheme = get_scheme(); + if (scheme == "https") { + return 443; + + } else { // == "http" + return 80; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: URLSpec::get_path +// Access: Published +// Description: Returns the path specified by the URL, or "/" if no +// path is specified. +//////////////////////////////////////////////////////////////////// +string URLSpec:: +get_path() const { + if (has_path()) { + return _url.substr(_path_start, _path_end - _path_start); + } + return "/"; +} + +//////////////////////////////////////////////////////////////////// +// Function: URLSpec::set_scheme +// Access: Published +// Description: Replaces the scheme part of the URL specification. +//////////////////////////////////////////////////////////////////// +void URLSpec:: +set_scheme(const string &scheme) { + int length_adjust; + + // The scheme is always converted to lowercase. + string lc_scheme; + lc_scheme.reserve(scheme.length()); + for (string::const_iterator si = scheme.begin(); si != scheme.end(); ++si) { + lc_scheme += tolower(*si); + } + + if (lc_scheme.empty()) { + // Remove the scheme specification. + if (!has_scheme()) { + return; + } + _scheme_end++; + length_adjust = -(int)_scheme_end; + _url = _url.substr(_scheme_end); + _flags &= ~F_has_scheme; + + } else if (!has_scheme()) { + // Insert a new scheme specification. + length_adjust = lc_scheme.length() + 1; + + _url = lc_scheme + ":" + _url; + _flags |= F_has_scheme; + + } else { + int old_length = (int)_scheme_end; + length_adjust = scheme.length() - old_length; + _url = lc_scheme + _url.substr(_scheme_end); + } + + _scheme_end += length_adjust; + _username_start += length_adjust; + _username_end += length_adjust; + _server_start += length_adjust; + _server_end += length_adjust; + _port_start += length_adjust; + _port_end += length_adjust; + _path_start += length_adjust; + _path_end += length_adjust; + _query_start += length_adjust; +} + +//////////////////////////////////////////////////////////////////// +// Function: URLSpec::set_authority +// Access: Published +// Description: Replaces the authority part of the URL specification. +// This includes the username, server, and port. +//////////////////////////////////////////////////////////////////// +void URLSpec:: +set_authority(const string &authority) { + int length_adjust; + + if (authority.empty()) { + // Remove the authority specification. + if (!has_authority()) { + return; + } + _username_start -= 2; + length_adjust = -((int)_port_end - (int)_username_start); + _url = _url.substr(0, _username_start) + _url.substr(_port_end); + _flags &= ~(F_has_authority | F_has_username | F_has_server | F_has_port); + + _username_end = _username_start; + _server_start = _username_start; + _server_end = _username_start; + _port_start = _username_start; + + } else if (!has_authority()) { + // Insert a new authority specification. + length_adjust = authority.length() + 2; + + _url = _url.substr(0, _username_start) + "//" + authority + _url.substr(_port_end); + _flags |= F_has_authority; + _username_start += 2; + + } else { + // Replace an existing authority specification. + int old_length = (int)_port_end - (int)_username_start; + length_adjust = authority.length() - old_length; + _url = _url.substr(0, _username_start) + authority + _url.substr(_port_end); + } + + _port_end += length_adjust; + _path_start += length_adjust; + _path_end += length_adjust; + _query_start += length_adjust; + + parse_authority(); +} + +//////////////////////////////////////////////////////////////////// +// Function: URLSpec::set_username +// Access: Published +// Description: Replaces the username part of the URL specification. +//////////////////////////////////////////////////////////////////// +void URLSpec:: +set_username(const string &username) { + if (username.empty() && !has_authority()) { + return; + } + string authority; + + if (!username.empty()) { + authority = username + "@"; + } + authority += get_server(); + if (has_port()) { + authority += ":"; + authority += get_port_str(); + } + + set_authority(authority); +} + +//////////////////////////////////////////////////////////////////// +// Function: URLSpec::set_server +// Access: Published +// Description: Replaces the server part of the URL specification. +//////////////////////////////////////////////////////////////////// +void URLSpec:: +set_server(const string &server) { + if (server.empty() && !has_authority()) { + return; + } + string authority; + + if (has_username()) { + authority = get_username() + "@"; + } + authority += server; + if (has_port()) { + authority += ":"; + authority += get_port_str(); + } + + set_authority(authority); +} + +//////////////////////////////////////////////////////////////////// +// Function: URLSpec::set_port +// Access: Published +// Description: Replaces the port part of the URL specification. +//////////////////////////////////////////////////////////////////// +void URLSpec:: +set_port(const string &port) { + if (port.empty() && !has_authority()) { + return; + } + string authority; + + if (has_username()) { + authority = get_username() + "@"; + } + authority += get_server(); + + if (!port.empty()) { + authority += ":"; + authority += port; + } + + set_authority(authority); +} + +//////////////////////////////////////////////////////////////////// +// Function: URLSpec::set_port +// Access: Published +// Description: Replaces the port part of the URL specification, +// given a numeric port number. +//////////////////////////////////////////////////////////////////// +void URLSpec:: +set_port(int port) { + ostringstream str; + str << port; + set_port(str.str()); +} + +//////////////////////////////////////////////////////////////////// +// Function: URLSpec::set_path +// Access: Published +// Description: Replaces the path part of the URL specification. +//////////////////////////////////////////////////////////////////// +void URLSpec:: +set_path(const string &path) { + int length_adjust; + + if (path.empty()) { + // Remove the path specification. + if (!has_path()) { + return; + } + length_adjust = -((int)_path_end - (int)_path_start); + _url = _url.substr(0, _path_start) + _url.substr(_path_end); + _flags &= ~F_has_path; + + } else if (!has_path()) { + // Insert a new path specification. + length_adjust = path.length(); + + _url = _url.substr(0, _path_start) + path + _url.substr(_path_end); + _flags |= F_has_path; + + } else { + // Replace an existing path specification. + int old_length = (int)_path_end - (int)_path_start; + length_adjust = path.length() - old_length; + _url = _url.substr(0, _path_start) + path + _url.substr(_path_end); + } + + _path_end += length_adjust; + _query_start += length_adjust; +} + +//////////////////////////////////////////////////////////////////// +// Function: URLSpec::set_query +// Access: Published +// Description: Replaces the query part of the URL specification. +//////////////////////////////////////////////////////////////////// +void URLSpec:: +set_query(const string &query) { + if (query.empty()) { + // Remove the query specification. + if (!has_query()) { + return; + } + _query_start--; + _url = _url.substr(0, _query_start); + _flags &= ~F_has_query; + + } else if (!has_query()) { + // Insert a new query specification. + _url = _url.substr(0, _query_start) + "?" + query; + _flags |= F_has_query; + _query_start++; + + } else { + // Replace an existing query specification. + _url = _url.substr(0, _query_start) + query; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: URLSpec::set_url +// Access: Published +// Description: Completely replaces the URL with the indicated +// string. +//////////////////////////////////////////////////////////////////// +void URLSpec:: +set_url(const string &url) { + _url = url; + _flags = 0; + + // First, replace backslashes with forward slashes, since this is a + // common mistake among Windows users. + size_t p; + for (p = 0; p < _url.length(); p++) { + if (_url[p] == '\\') { + _url[p] = '/'; + } + } + + // What have we got? + _flags = 0; + _port = 0; + + // Look for the scheme specification. + size_t start = 0; + + _scheme_end = start; + size_t next = _url.find_first_of(":/", start); + if (next != string::npos && _url[next] == ':') { + // We have a scheme. + _flags |= F_has_scheme; + _scheme_end = next; + + // Ensure the scheme is lowercase. + for (size_t p = 0; p < _scheme_end; ++p) { + _url[p] = tolower(_url[p]); + } + + start = next + 1; + } + + // Look for the authority specification, which may include any of + // username, server, and/or port. + _username_start = start; + _username_end = start; + _server_start = start; + _server_end = start; + _port_start = start; + _port_end = start; + if (start + 1 < _url.length() && _url.substr(start, 2) == "//") { + // We have an authority specification. + start += 2; + _flags |= F_has_authority; + _username_start = start; + _port_end = _url.find_first_of("/?", start); + if (_port_end == string::npos) { + _port_end = _url.length(); + } + parse_authority(); + start = _port_end; + } + + // Everything up to the ?, if any, is the path. + _path_start = start; + _path_end = start; + if (start < _url.length() && url[start] != '?') { + // We have a path. + _flags |= F_has_path; + _path_start = start; + _path_end = _url.find("?", _path_start); + if (_path_end == string::npos) { + _path_end = _url.length(); + } + start = _path_end; + } + + // Everything after the ? is the query. + _query_start = start; + if (start < _url.length()) { + nassertv(_url[start] == '?'); + _flags |= F_has_query; + _query_start++; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: URLSpec::output +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +void URLSpec:: +output(ostream &out) const { + out << get_url(); +} + +//////////////////////////////////////////////////////////////////// +// Function: URLSpec::quote +// Access: Published, Static +// Description: Returns the source string with all "unsafe" +// characters quoted, making a string suitable for +// placing in a URL. Letters, digits, and the +// underscore, comma, period, and hyphen characters, as +// well as any included in the safe string, are left +// alone; all others are converted to hex +// representation. +//////////////////////////////////////////////////////////////////// +string URLSpec:: +quote(const string &source, const string &safe) { + ostringstream result; + result << hex << setw(2) << setfill('0'); + + for (string::const_iterator si = source.begin(); si != source.end(); ++si) { + char ch = (*si); + switch (ch) { + case '_': + case ',': + case '.': + case '-': + // Safe character. + result << ch; + break; + + default: + if (isalnum(ch)) { + // Letters and digits are safe. + result << ch; + + } else if (safe.find(ch) != string::npos) { + // If it's listed in "safe", it's safe. + result << ch; + + } else { + // Otherwise, escape it. + result << "0x" << ch; + } + } + } + + return result.str(); +} + +//////////////////////////////////////////////////////////////////// +// Function: URLSpec::quote_plus +// Access: Published, Static +// Description: Behaves like quote() with the additional behavior of +// replacing spaces with plus signs. +//////////////////////////////////////////////////////////////////// +string URLSpec:: +quote_plus(const string &source, const string &safe) { + ostringstream result; + result << hex << setw(2) << setfill('0'); + + for (string::const_iterator si = source.begin(); si != source.end(); ++si) { + char ch = (*si); + switch (ch) { + case '_': + case ',': + case '.': + case '-': + // Safe character. + result << ch; + break; + + case ' ': + result << '+'; + break; + + default: + if (isalnum(ch)) { + // Letters and digits are safe. + result << ch; + + } else if (safe.find(ch) != string::npos) { + // If it's listed in "safe", it's safe. + result << ch; + + } else { + // Otherwise, escape it. + result << "0x" << ch; + } + } + } + + return result.str(); +} + +//////////////////////////////////////////////////////////////////// +// Function: URLSpec::unquote +// Access: Published, Static +// Description: Reverses the operation of quote(): converts escaped +// characters of the form "%xx" to their ascii +// equivalent. +//////////////////////////////////////////////////////////////////// +string URLSpec:: +unquote(const string &source) { + string result; + + string::const_iterator si = source.begin(); + while (si != source.end()) { + if ((*si) == '%') { + ++si; + int hex = 0; + while (si != source.end() && isxdigit(*si)) { + int value; + char ch = *si; + if (isdigit(ch)) { + value = ch - '0'; + } else { + value = tolower(ch) - 'a'; + } + hex = (hex << 8) | value; + ++si; + } + result += (char)hex; + + } else { + result += (*si); + ++si; + } + } + + return result; +} + +//////////////////////////////////////////////////////////////////// +// Function: URLSpec::unquote_plus +// Access: Published, Static +// Description: Reverses the operation of quote_plus(): converts escaped +// characters of the form "%xx" to their ascii +// equivalent, and also converts plus signs to spaces. +//////////////////////////////////////////////////////////////////// +string URLSpec:: +unquote_plus(const string &source) { + string result; + + string::const_iterator si = source.begin(); + while (si != source.end()) { + if ((*si) == '%') { + ++si; + int hex = 0; + while (si != source.end() && isxdigit(*si)) { + int value; + char ch = *si; + if (isdigit(ch)) { + value = ch - '0'; + } else { + value = tolower(ch) - 'a'; + } + hex = (hex << 8) | value; + ++si; + } + result += (char)hex; + + } else if ((*si) == '+') { + result += ' '; + + } else { + result += (*si); + ++si; + } + } + + return result; +} + +//////////////////////////////////////////////////////////////////// +// Function: URLSpec::parse_authority +// Access: Private +// Description: Assumes _url[_username_start .. _port_end - 1] is +// the authority component if the URL, consisting of +// [username@]server[:port]. Parses out the three +// pieces and updates the various _start and _end +// parameters accordingly. +//////////////////////////////////////////////////////////////////// +void URLSpec:: +parse_authority() { + if (!has_authority()) { + return; + } + + // Assume we don't have a username or port unless we find them. + _username_end = _username_start; + _port_start = _port_end; + + // We assume we have a server, even if it becomes the empty string. + _flags |= F_has_server; + _server_start = _username_start; + _server_end = _port_end; + + // Is there a username? + size_t at_sign = _url.find('@', _username_start); + if (at_sign < _port_end) { + // We have a username. + _flags |= F_has_username; + _username_end = at_sign; + _server_start = at_sign + 1; + } + + // Is there a port? + size_t colon = _url.find(':', _server_start); + if (colon < _port_end) { + // Yep. + _flags |= F_has_port; + _server_end = colon; + _port_start = colon + 1; + + // Decode the port into an integer. Don't bother to error + // check if it's not really an integer. + string port_str = _url.substr(_port_start, _port_end - _port_start); + _port = atoi(port_str.c_str()); + } +} diff --git a/panda/src/downloader/urlSpec.h b/panda/src/downloader/urlSpec.h new file mode 100644 index 0000000000..c9ff365f30 --- /dev/null +++ b/panda/src/downloader/urlSpec.h @@ -0,0 +1,111 @@ +// Filename: urlSpec.h +// Created by: drose (24Sep02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef URLSPEC_H +#define URLSPEC_H + +#include "pandabase.h" + +//////////////////////////////////////////////////////////////////// +// Class : URLSpec +// Description : A container for a URL, e.g. "http://server:port/path". +// +// The URLSpec object is similar to a Filename in that +// it contains logic to identify the various parts of a +// URL and return (or modify) them separately. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDAEXPRESS URLSpec { +PUBLISHED: + URLSpec(); + INLINE URLSpec(const string &url); + INLINE URLSpec(const URLSpec ©); + INLINE void operator = (const string &url); + void operator = (const URLSpec ©); + + INLINE bool has_scheme() const; + INLINE bool has_authority() const; + INLINE bool has_username() const; + INLINE bool has_server() const; + INLINE bool has_port() const; + INLINE bool has_path() const; + INLINE bool has_query() const; + + string get_scheme() const; + INLINE string get_authority() const; + INLINE string get_username() const; + INLINE string get_server() const; + INLINE string get_port_str() const; + int get_port() const; + string get_path() const; + INLINE string get_query() const; + + INLINE const string &get_url() const; + + void set_scheme(const string &scheme); + void set_authority(const string &authority); + void set_username(const string &username); + void set_server(const string &server); + void set_port(const string &port); + void set_port(int port); + void set_path(const string &path); + void set_query(const string &query); + + void set_url(const string &url); + + void output(ostream &out) const; + + static string quote(const string &source, const string &safe = "/"); + static string quote_plus(const string &source, const string &safe = "/"); + static string unquote(const string &source); + static string unquote_plus(const string &source); + +private: + void parse_authority(); + + enum Flags { + F_has_scheme = 0x0001, + F_has_authority = 0x0002, + F_has_username = 0x0004, + F_has_server = 0x0008, + F_has_port = 0x0010, + F_has_path = 0x0020, + F_has_query = 0x0040, + }; + + string _url; + int _port; + int _flags; + + size_t _scheme_end; + size_t _username_start; + size_t _username_end; + size_t _server_start; + size_t _server_end; + size_t _port_start; + size_t _port_end; + size_t _path_start; + size_t _path_end; + size_t _query_start; +}; + +INLINE ostream &operator << (ostream &out, const URLSpec &url); + +#include "urlSpec.I" + +#endif +