2004-10-05 10:28:21 +00:00
|
|
|
//
|
2005-03-18 21:33:11 +00:00
|
|
|
// VMime library (http://www.vmime.org)
|
2006-02-05 10:22:59 +00:00
|
|
|
// Copyright (C) 2002-2006 Vincent Richard <vincent@vincent-richard.net>
|
2004-10-05 10:28:21 +00:00
|
|
|
//
|
|
|
|
// This program is free software; you can redistribute it and/or
|
|
|
|
// modify it under the terms of the GNU General Public License as
|
|
|
|
// published by the Free Software Foundation; either version 2 of
|
|
|
|
// the License, or (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
// General Public License for more details.
|
|
|
|
//
|
2005-09-17 10:10:29 +00:00
|
|
|
// You should have received a copy of the GNU General Public License along along
|
|
|
|
// with this program; if not, write to the Free Software Foundation, Inc., Foundation, Inc.,
|
|
|
|
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA..
|
2004-10-05 10:28:21 +00:00
|
|
|
//
|
|
|
|
|
2005-04-14 11:27:49 +00:00
|
|
|
#include "vmime/utility/url.hpp"
|
2004-10-05 10:28:21 +00:00
|
|
|
|
2004-12-26 20:23:29 +00:00
|
|
|
#include "vmime/parserHelpers.hpp"
|
2005-04-14 11:27:49 +00:00
|
|
|
#include "vmime/utility/urlUtils.hpp"
|
2004-12-26 20:23:29 +00:00
|
|
|
#include "vmime/exception.hpp"
|
2004-10-05 10:28:21 +00:00
|
|
|
|
|
|
|
#include <sstream>
|
|
|
|
|
|
|
|
|
|
|
|
namespace vmime {
|
2005-04-14 11:27:49 +00:00
|
|
|
namespace utility {
|
2004-10-05 10:28:21 +00:00
|
|
|
|
|
|
|
|
2005-08-25 21:15:17 +00:00
|
|
|
// Unspecified port
|
|
|
|
const port_t url::UNSPECIFIED_PORT = static_cast <port_t>(-1);
|
|
|
|
|
2004-10-05 10:28:21 +00:00
|
|
|
// Known protocols
|
|
|
|
const string url::PROTOCOL_FILE = "file";
|
|
|
|
const string url::PROTOCOL_HTTP = "http";
|
|
|
|
const string url::PROTOCOL_FTP = "ftp";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
url::url(const string& s)
|
|
|
|
{
|
|
|
|
parse(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
url::url(const url& u)
|
|
|
|
{
|
|
|
|
operator=(u);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
url::url(const string& protocol, const string& host, const port_t port,
|
|
|
|
const string& path, const string& username, const string& password)
|
|
|
|
: m_protocol(protocol), m_username(username), m_password(password),
|
|
|
|
m_host(host), m_port(port), m_path(path)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
url& url::operator=(const url& u)
|
|
|
|
{
|
|
|
|
m_protocol = u.m_protocol;
|
|
|
|
|
|
|
|
m_username = u.m_username;
|
|
|
|
m_password = u.m_password;
|
|
|
|
|
|
|
|
m_host = u.m_host;
|
|
|
|
m_port = u.m_port;
|
|
|
|
|
|
|
|
m_path = u.m_path;
|
|
|
|
|
2005-04-28 16:35:37 +00:00
|
|
|
m_params = u.m_params;
|
|
|
|
|
2004-10-05 10:28:21 +00:00
|
|
|
return (*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
url& url::operator=(const string& s)
|
|
|
|
{
|
|
|
|
parse(s);
|
|
|
|
|
|
|
|
return (*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
url::operator string() const
|
|
|
|
{
|
|
|
|
return build();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const string url::build() const
|
|
|
|
{
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
|
|
|
oss << m_protocol << "://";
|
|
|
|
|
|
|
|
if (!m_username.empty())
|
|
|
|
{
|
|
|
|
oss << urlUtils::encode(m_username);
|
|
|
|
|
|
|
|
if (!m_password.empty())
|
|
|
|
{
|
|
|
|
oss << ":";
|
|
|
|
oss << urlUtils::encode(m_password);
|
|
|
|
}
|
|
|
|
|
|
|
|
oss << "@";
|
|
|
|
}
|
|
|
|
|
|
|
|
oss << urlUtils::encode(m_host);
|
|
|
|
|
|
|
|
if (m_port != UNSPECIFIED_PORT)
|
|
|
|
{
|
|
|
|
oss << ":";
|
|
|
|
oss << m_port;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!m_path.empty())
|
|
|
|
{
|
|
|
|
oss << "/";
|
|
|
|
oss << urlUtils::encode(m_path);
|
|
|
|
}
|
|
|
|
|
2005-07-12 22:28:02 +00:00
|
|
|
const std::vector <ref <const propertySet::property> > params
|
2005-04-28 16:35:37 +00:00
|
|
|
= m_params.getPropertyList();
|
|
|
|
|
|
|
|
if (!params.empty())
|
|
|
|
{
|
|
|
|
if (m_path.empty())
|
|
|
|
oss << "/";
|
|
|
|
|
|
|
|
oss << "?";
|
|
|
|
|
|
|
|
for (unsigned int i = 0 ; i < params.size() ; ++i)
|
|
|
|
{
|
2005-07-12 22:28:02 +00:00
|
|
|
const ref <const propertySet::property> prop = params[i];
|
2005-04-28 16:35:37 +00:00
|
|
|
|
|
|
|
if (i != 0)
|
|
|
|
oss << "&";
|
|
|
|
|
|
|
|
oss << urlUtils::encode(prop->getName());
|
|
|
|
oss << "=";
|
|
|
|
oss << urlUtils::encode(prop->getValue());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-10-05 10:28:21 +00:00
|
|
|
return (oss.str());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void url::parse(const string& str)
|
|
|
|
{
|
|
|
|
// Protocol
|
|
|
|
const string::size_type protoEnd = str.find("://");
|
|
|
|
if (protoEnd == string::npos) throw exceptions::malformed_url("No protocol separator");
|
|
|
|
|
|
|
|
const string proto =
|
2005-01-02 17:17:12 +00:00
|
|
|
utility::stringUtils::toLower(string(str.begin(), str.begin() + protoEnd));
|
2004-10-05 10:28:21 +00:00
|
|
|
|
|
|
|
// Username/password
|
|
|
|
string::size_type slashPos = str.find('/', protoEnd + 3);
|
|
|
|
if (slashPos == string::npos) slashPos = str.length();
|
|
|
|
|
2006-01-09 18:02:25 +00:00
|
|
|
string::size_type atPos = str.rfind('@', slashPos);
|
2004-10-05 10:28:21 +00:00
|
|
|
string hostPart;
|
|
|
|
|
|
|
|
string username;
|
|
|
|
string password;
|
|
|
|
|
2004-12-26 16:42:30 +00:00
|
|
|
if (proto == PROTOCOL_FILE)
|
2004-10-05 10:28:21 +00:00
|
|
|
{
|
2004-12-26 16:42:30 +00:00
|
|
|
// No user name, password and host part.
|
|
|
|
slashPos = protoEnd + 3;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (atPos != string::npos && atPos < slashPos)
|
2004-10-05 10:28:21 +00:00
|
|
|
{
|
2004-12-26 16:42:30 +00:00
|
|
|
const string userPart(str.begin() + protoEnd + 3, str.begin() + atPos);
|
|
|
|
const string::size_type colonPos = userPart.find(':');
|
|
|
|
|
|
|
|
if (colonPos == string::npos)
|
|
|
|
{
|
|
|
|
username = userPart;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
username = string(userPart.begin(), userPart.begin() + colonPos);
|
|
|
|
password = string(userPart.begin() + colonPos + 1, userPart.end());
|
|
|
|
}
|
|
|
|
|
|
|
|
hostPart = string(str.begin() + atPos + 1, str.begin() + slashPos);
|
2004-10-05 10:28:21 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-12-26 16:42:30 +00:00
|
|
|
hostPart = string(str.begin() + protoEnd + 3, str.begin() + slashPos);
|
2004-10-05 10:28:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Host/port
|
|
|
|
const string::size_type colonPos = hostPart.find(':');
|
|
|
|
|
|
|
|
string host;
|
|
|
|
string port;
|
|
|
|
|
|
|
|
if (colonPos == string::npos)
|
|
|
|
{
|
2005-04-18 19:55:58 +00:00
|
|
|
host = utility::stringUtils::trim(hostPart);
|
2004-10-05 10:28:21 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-04-18 19:55:58 +00:00
|
|
|
host = utility::stringUtils::trim(string(hostPart.begin(), hostPart.begin() + colonPos));
|
|
|
|
port = utility::stringUtils::trim(string(hostPart.begin() + colonPos + 1, hostPart.end()));
|
2004-10-05 10:28:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Path
|
2005-01-02 17:17:12 +00:00
|
|
|
string path = utility::stringUtils::trim(string(str.begin() + slashPos, str.end()));
|
2005-04-28 16:35:37 +00:00
|
|
|
string params;
|
|
|
|
|
|
|
|
string::size_type paramSep = path.find_first_of('?');
|
|
|
|
|
|
|
|
if (paramSep != string::npos)
|
|
|
|
{
|
|
|
|
params = string(path.begin() + paramSep + 1, path.end());
|
|
|
|
path.erase(path.begin() + paramSep, path.end());
|
|
|
|
}
|
2004-10-05 10:28:21 +00:00
|
|
|
|
|
|
|
if (path == "/")
|
|
|
|
path.clear();
|
|
|
|
|
|
|
|
// Some sanity check
|
|
|
|
if (proto.empty())
|
|
|
|
throw exceptions::malformed_url("No protocol specified");
|
2005-04-18 19:55:58 +00:00
|
|
|
else if (host.empty())
|
|
|
|
{
|
|
|
|
// Accept empty host (eg. "file:///home/vincent/mydoc")
|
|
|
|
if (proto != PROTOCOL_FILE)
|
|
|
|
throw exceptions::malformed_url("No host specified");
|
|
|
|
}
|
2004-10-05 10:28:21 +00:00
|
|
|
|
|
|
|
bool onlyDigit = true;
|
|
|
|
|
|
|
|
for (string::const_iterator it = port.begin() ;
|
|
|
|
onlyDigit && it != port.end() ; ++it)
|
|
|
|
{
|
2005-03-16 17:13:08 +00:00
|
|
|
onlyDigit = parserHelpers::isDigit(*it);
|
2004-10-05 10:28:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!onlyDigit)
|
|
|
|
throw exceptions::malformed_url("Port can only contain digits");
|
|
|
|
|
|
|
|
std::istringstream iss(port);
|
|
|
|
port_t portNum = 0;
|
|
|
|
|
|
|
|
iss >> portNum;
|
|
|
|
|
2005-04-18 19:55:58 +00:00
|
|
|
if (portNum == 0)
|
|
|
|
portNum = UNSPECIFIED_PORT;
|
|
|
|
|
2005-04-28 16:35:37 +00:00
|
|
|
// Extract parameters
|
|
|
|
m_params.removeAllProperties();
|
|
|
|
|
|
|
|
if (!params.empty())
|
|
|
|
{
|
|
|
|
string::size_type pos = 0;
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
const string::size_type start = pos;
|
|
|
|
|
|
|
|
pos = params.find_first_of('&', pos);
|
|
|
|
|
|
|
|
const string::size_type equal = params.find_first_of('=', start);
|
|
|
|
const string::size_type end =
|
|
|
|
(pos == string::npos ? params.length() : pos);
|
|
|
|
|
|
|
|
string name;
|
|
|
|
string value;
|
|
|
|
|
|
|
|
if (equal == string::npos || equal > pos) // no value
|
|
|
|
{
|
|
|
|
name = string(params.begin() + start, params.begin() + end);
|
|
|
|
value = name;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
name = string(params.begin() + start, params.begin() + equal);
|
|
|
|
value = string(params.begin() + equal + 1, params.begin() + end);
|
|
|
|
}
|
|
|
|
|
|
|
|
name = urlUtils::decode(name);
|
|
|
|
value = urlUtils::decode(value);
|
|
|
|
|
|
|
|
m_params.setProperty(name, value);
|
|
|
|
|
|
|
|
if (pos != string::npos)
|
|
|
|
++pos;
|
|
|
|
}
|
|
|
|
while (pos != string::npos);
|
|
|
|
}
|
|
|
|
|
2004-10-05 10:28:21 +00:00
|
|
|
// Now, save URL parts
|
|
|
|
m_protocol = proto;
|
|
|
|
|
|
|
|
m_username = urlUtils::decode(username);
|
|
|
|
m_password = urlUtils::decode(password);
|
|
|
|
|
|
|
|
m_host = urlUtils::decode(host);
|
|
|
|
m_port = portNum;
|
|
|
|
|
|
|
|
m_path = urlUtils::decode(path);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-10-21 15:05:47 +00:00
|
|
|
const string& url::getProtocol() const
|
|
|
|
{
|
|
|
|
return (m_protocol);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void url::setProtocol(const string& protocol)
|
|
|
|
{
|
|
|
|
m_protocol = protocol;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const string& url::getUsername() const
|
|
|
|
{
|
|
|
|
return (m_username);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void url::setUsername(const string& username)
|
|
|
|
{
|
|
|
|
m_username = username;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const string& url::getPassword() const
|
|
|
|
{
|
|
|
|
return (m_password);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void url::setPassword(const string& password)
|
|
|
|
{
|
|
|
|
m_password = password;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const string& url::getHost() const
|
|
|
|
{
|
|
|
|
return (m_host);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void url::setHost(const string& host)
|
|
|
|
{
|
|
|
|
m_host = host;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const port_t url::getPort() const
|
|
|
|
{
|
|
|
|
return (m_port);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void url::setPort(const port_t port)
|
|
|
|
{
|
|
|
|
m_port = port;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const string& url::getPath() const
|
|
|
|
{
|
|
|
|
return (m_path);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void url::setPath(const string& path)
|
|
|
|
{
|
|
|
|
m_path = path;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-04-28 16:35:37 +00:00
|
|
|
const propertySet& url::getParams() const
|
|
|
|
{
|
|
|
|
return (m_params);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
propertySet& url::getParams()
|
|
|
|
{
|
|
|
|
return (m_params);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-04-14 11:27:49 +00:00
|
|
|
} // utility
|
2004-10-05 10:28:21 +00:00
|
|
|
} // vmime
|