add urlSpec

This commit is contained in:
David Rose 2002-09-25 00:23:35 +00:00
parent 875e6a4f76
commit ffc858f09e
5 changed files with 1003 additions and 0 deletions

View File

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

View File

@ -3,4 +3,5 @@
#include "extractor.cxx"
#include "multiplexStream.cxx"
#include "multiplexStreamBuf.cxx"
#include "urlSpec.cxx"

View File

@ -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 &copy) {
(*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;
}

View File

@ -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 <ctype.h>
////////////////////////////////////////////////////////////////////
// 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 &copy) {
_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());
}
}

View File

@ -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 &copy);
INLINE void operator = (const string &url);
void operator = (const URLSpec &copy);
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