2009-11-12 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>

Rewritten Request::parseUrl()
	* src/Request.cc
	* test/RequestTest.cc
pull/1/head
Tatsuhiro Tsujikawa 2009-11-12 14:50:23 +00:00
parent 37a50cf468
commit 7a94ae6af2
3 changed files with 151 additions and 75 deletions

View File

@ -1,3 +1,9 @@
2009-11-12 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
Rewritten Request::parseUrl()
* src/Request.cc
* test/RequestTest.cc
2009-11-11 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net> 2009-11-11 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
Removed unused macro SAFE_CHARS Removed unused macro SAFE_CHARS

View File

@ -145,7 +145,6 @@ bool Request::redirectUrl(const std::string& url) {
bool Request::parseUrl(const std::string& url) { bool Request::parseUrl(const std::string& url) {
currentUrl = url; currentUrl = url;
std::string tempUrl = url;
host = A2STR::NIL; host = A2STR::NIL;
port = 0; port = 0;
dir = A2STR::NIL; dir = A2STR::NIL;
@ -155,98 +154,150 @@ bool Request::parseUrl(const std::string& url) {
_password = A2STR::NIL; _password = A2STR::NIL;
_hasPassword = false; _hasPassword = false;
_ipv6LiteralAddress = false; _ipv6LiteralAddress = false;
// http://user:password@aria2.sourceforge.net:80/dir/file?query
// | || || | | |
// | || hostLast| | | |
// | || portFirst| | |
// authorityFirst || authorityLast | |
// || | | |
// userInfoLast | | |
// | | | |
// hostPortFirst | | |
// | | |
// dirFirst dirLast|
// |
// queryFirst
// find query part // find query part
std::string queryTemp; std::string::const_iterator queryFirst = url.begin();
std::string::size_type startQueryIndex = tempUrl.find("?"); for(; queryFirst != url.end(); ++queryFirst) {
if(startQueryIndex != std::string::npos) { if(*queryFirst == '?') break;
queryTemp = tempUrl.substr(startQueryIndex);
tempUrl.erase(startQueryIndex);
} }
_query = std::string(queryFirst, url.end());
// find protocol // find protocol
std::string::size_type hp = tempUrl.find("://"); std::string::size_type protocolOffset = url.find("://");
if(hp == std::string::npos) return false; if(protocolOffset == std::string::npos) return false;
protocol = tempUrl.substr(0, hp); protocol = std::string(url.begin(), url.begin()+protocolOffset);
uint16_t defPort; uint16_t defPort;
if((defPort = FeatureConfig::getInstance()->getDefaultPort(protocol)) == 0) { if((defPort = FeatureConfig::getInstance()->getDefaultPort(protocol)) == 0) {
return false; return false;
} }
hp += 3; // find authority
// find host part std::string::const_iterator authorityFirst = url.begin()+protocolOffset+3;
if(tempUrl.size() <= hp) return false; std::string::const_iterator authorityLast = authorityFirst;
std::string::size_type hep = tempUrl.find("/", hp); for(; authorityLast != queryFirst; ++authorityLast) {
if(hep == std::string::npos) { if(*authorityLast == '/') break;
hep = tempUrl.size();
} }
std::string hostPart = tempUrl.substr(hp, hep-hp); if(authorityFirst == authorityLast) {
// find username and password in host part if they exist // No authority found
std::string::size_type atmarkp = hostPart.find_last_of("@"); return false;
if(atmarkp != std::string::npos) {
std::string authPart = hostPart.substr(0, atmarkp);
std::pair<std::string, std::string> userPass =
util::split(authPart, A2STR::COLON_C);
_username = util::urldecode(userPass.first);
_password = util::urldecode(userPass.second);
if(authPart.find(A2STR::COLON_C) != std::string::npos) {
_hasPassword = true;
}
hostPart.erase(0, atmarkp+1);
} }
{ // find userinfo(username and password) in authority if they exist
std::string::size_type colonpos; std::string::const_iterator userInfoLast = authorityFirst;
// Detect IPv6 literal address in square brackets std::string::const_iterator hostPortFirst = authorityFirst;
if(util::startsWith(hostPart, "[")) { for(; userInfoLast != authorityLast; ++userInfoLast) {
std::string::size_type rbracketpos = hostPart.find("]"); if(*userInfoLast == '@') {
if(rbracketpos == std::string::npos) { hostPortFirst = userInfoLast;
return false; ++hostPortFirst;
} std::string::const_iterator userLast = authorityFirst;
_ipv6LiteralAddress = true; for(; userLast != userInfoLast; ++userLast) {
colonpos = hostPart.find(":", rbracketpos+1); if(*userLast == ':') {
} else { _password = util::urldecode(std::string(userLast+1, userInfoLast));
colonpos = hostPart.find_last_of(":"); _hasPassword = true;
} break;
if(colonpos == std::string::npos) {
colonpos = hostPart.size();
// If port is not specified, then we set it to default port of
// its protocol..
port = defPort;
} else {
try {
unsigned int tempPort = util::parseUInt(hostPart.substr(colonpos+1));
if(65535 < tempPort) {
return false;
} }
port = tempPort; }
} catch(RecoverableException& e) { _username = util::urldecode(std::string(authorityFirst, userLast));
return false; break;
}
}
std::string::const_iterator hostLast = hostPortFirst;
std::string::const_iterator portFirst = authorityLast;
if(*hostPortFirst == '[') {
// Detected IPv6 literal address in square brackets
for(; hostLast != authorityLast; ++hostLast) {
if(*hostLast == ']') {
++hostLast;
if(hostLast == authorityLast) {
_ipv6LiteralAddress = true;
} else {
if(*hostLast == ':') {
portFirst = hostLast;
++portFirst;
_ipv6LiteralAddress = true;
}
}
break;
} }
} }
if(_ipv6LiteralAddress) { if(!_ipv6LiteralAddress) {
host = hostPart.substr(1, colonpos-2); return false;
} else {
host = hostPart.substr(0, colonpos);
} }
} else {
for(; hostLast != authorityLast; ++hostLast) {
if(*hostLast == ':') {
portFirst = hostLast;
++portFirst;
break;
}
}
}
if(hostPortFirst == hostLast) {
// No host
return false;
}
if(portFirst == authorityLast) {
// If port is not specified, then we set it to default port of
// its protocol..
port = defPort;
} else {
try {
unsigned int tempPort =
util::parseUInt(std::string(portFirst, authorityLast));
if(65535 < tempPort) {
return false;
}
port = tempPort;
} catch(RecoverableException& e) {
return false;
}
}
if(_ipv6LiteralAddress) {
host = std::string(hostPortFirst+1, hostLast-1);
} else {
host = std::string(hostPortFirst, hostLast);
} }
// find directory and file part // find directory and file part
std::string::size_type direp = tempUrl.find_last_of("/"); std::string::const_iterator dirLast = authorityLast;
if(direp == std::string::npos || direp <= hep) { for(std::string::const_iterator i = authorityLast;
i != queryFirst; ++i) {
if(*i == '/') {
dirLast = i;
}
}
if(dirLast != queryFirst) {
file = std::string(dirLast+1, queryFirst);
}
// Erase duplicated slashes.
std::string::const_iterator dirFirst = authorityLast;
for(; dirFirst != dirLast; ++dirFirst) {
if(*dirFirst != '/') {
--dirFirst;
break;
}
}
for(; dirLast != dirFirst; --dirLast) {
if(*dirLast != '/') {
++dirLast;
break;
}
}
if(dirFirst == dirLast) {
dir = A2STR::SLASH_C; dir = A2STR::SLASH_C;
direp = hep;
} else { } else {
std::string rawDir = tempUrl.substr(hep, direp-hep); dir = std::string(dirFirst, dirLast);
std::string::size_type p = rawDir.find_first_not_of("/");
if(p != std::string::npos) {
rawDir.erase(0, p-1);
}
p = rawDir.find_last_not_of("/");
if(p != std::string::npos) {
rawDir.erase(p+1);
}
dir = rawDir;
} }
if(tempUrl.size() > direp+1) {
file = tempUrl.substr(direp+1);
}
_query = queryTemp;
return true; return true;
} }

View File

@ -28,6 +28,8 @@ class RequestTest:public CppUnit::TestFixture {
CPPUNIT_TEST(testSetUrl15); CPPUNIT_TEST(testSetUrl15);
CPPUNIT_TEST(testSetUrl16); CPPUNIT_TEST(testSetUrl16);
CPPUNIT_TEST(testSetUrl17); CPPUNIT_TEST(testSetUrl17);
CPPUNIT_TEST(testSetUrl18);
CPPUNIT_TEST(testSetUrl19);
CPPUNIT_TEST(testSetUrl_username); CPPUNIT_TEST(testSetUrl_username);
CPPUNIT_TEST(testSetUrl_usernamePassword); CPPUNIT_TEST(testSetUrl_usernamePassword);
CPPUNIT_TEST(testSetUrl_zeroUsername); CPPUNIT_TEST(testSetUrl_zeroUsername);
@ -61,6 +63,8 @@ public:
void testSetUrl15(); void testSetUrl15();
void testSetUrl16(); void testSetUrl16();
void testSetUrl17(); void testSetUrl17();
void testSetUrl18();
void testSetUrl19();
void testSetUrl_username(); void testSetUrl_username();
void testSetUrl_usernamePassword(); void testSetUrl_usernamePassword();
void testSetUrl_zeroUsername(); void testSetUrl_zeroUsername();
@ -290,6 +294,21 @@ void RequestTest::testSetUrl17()
req.getUrl()); req.getUrl());
} }
void RequestTest::testSetUrl18() {
Request req;
bool v = req.setUrl("http://1/");
CPPUNIT_ASSERT(v);
}
void RequestTest::testSetUrl19() {
Request req;
// No host
bool v = req.setUrl("http://user@");
CPPUNIT_ASSERT(!v);
}
void RequestTest::testRedirectUrl() { void RequestTest::testRedirectUrl() {
Request req; Request req;
req.supportsPersistentConnection(false); req.supportsPersistentConnection(false);