2009-08-31 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>

Added support for IPv6 literal address in URI. Now aria2 can
	handle URI such as http://[::1]/
	* src/HttpRequest.cc
	* src/HttpRequest.h
	* src/Request.cc
	* src/Request.h
	* test/HttpRequestTest.cc
	* test/OptionHandlerTest.cc
	* test/RequestTest.cc
pull/1/head
Tatsuhiro Tsujikawa 2009-08-30 15:05:30 +00:00
parent 19ae8f9d07
commit ce25b54cfe
8 changed files with 117 additions and 24 deletions

View File

@ -1,3 +1,15 @@
2009-08-31 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
Added support for IPv6 literal address in URI. Now aria2 can
handle URI such as http://[::1]/
* src/HttpRequest.cc
* src/HttpRequest.h
* src/Request.cc
* src/Request.h
* test/HttpRequestTest.cc
* test/OptionHandlerTest.cc
* test/RequestTest.cc
2009-08-30 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net> 2009-08-30 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
Fixed the bug that HTTP request header for XML-RPC request is not Fixed the bug that HTTP request header for XML-RPC request is not

View File

@ -117,7 +117,7 @@ bool HttpRequest::isRangeSatisfied(const RangeHandle& range) const
} }
} }
std::string HttpRequest::getHostText(const std::string& host, uint16_t port) const static std::string getHostText(const std::string& host, uint16_t port)
{ {
std::string hosttext = host; std::string hosttext = host;
if(!(port == 80 || port == 443)) { if(!(port == 80 || port == 443)) {
@ -172,7 +172,7 @@ std::string HttpRequest::createRequest()
} }
} }
strappend(requestLine, "Host: ", getHostText(getHost(), getPort()), "\r\n"); strappend(requestLine, "Host: ", getHostText(getURIHost(), getPort()), "\r\n");
requestLine += "Pragma: no-cache\r\n"; requestLine += "Pragma: no-cache\r\n";
requestLine += "Cache-Control: no-cache\r\n"; requestLine += "Cache-Control: no-cache\r\n";
@ -235,7 +235,7 @@ std::string HttpRequest::createRequest()
std::string HttpRequest::createProxyRequest() const std::string HttpRequest::createProxyRequest() const
{ {
assert(!_proxyRequest.isNull()); assert(!_proxyRequest.isNull());
std::string hostport = getHost(); std::string hostport = getURIHost();
strappend(hostport, ":", Util::uitos(getPort())); strappend(hostport, ":", Util::uitos(getPort()));
std::string requestLine = "CONNECT "; std::string requestLine = "CONNECT ";

View File

@ -83,8 +83,6 @@ private:
SharedHandle<Request> _proxyRequest; SharedHandle<Request> _proxyRequest;
std::string getHostText(const std::string& host, uint16_t port) const;
std::string getProxyAuthString() const; std::string getProxyAuthString() const;
public: public:
HttpRequest(); HttpRequest();
@ -149,6 +147,11 @@ public:
return request->getPreviousUrl(); return request->getPreviousUrl();
} }
std::string getURIHost() const
{
return request->getURIHost();
}
SharedHandle<Range> getRange() const; SharedHandle<Range> getRange() const;
/** /**

View File

@ -71,7 +71,8 @@ Request::Request():
_keepAliveHint(false), _keepAliveHint(false),
_pipeliningHint(false), _pipeliningHint(false),
_maxPipelinedRequest(1), _maxPipelinedRequest(1),
method(METHOD_GET) method(METHOD_GET),
_ipv6LiteralAddress(false)
{} {}
static std::string removeFragment(const std::string url) static std::string removeFragment(const std::string url)
@ -160,6 +161,7 @@ bool Request::parseUrl(const std::string& url) {
_query = A2STR::NIL; _query = A2STR::NIL;
_username = A2STR::NIL; _username = A2STR::NIL;
_password = A2STR::NIL; _password = A2STR::NIL;
_ipv6LiteralAddress = false;
// find query part // find query part
std::string queryTemp; std::string queryTemp;
std::string::size_type startQueryIndex = tempUrl.find("?"); std::string::size_type startQueryIndex = tempUrl.find("?");
@ -193,22 +195,40 @@ bool Request::parseUrl(const std::string& url) {
_password = Util::urldecode(userPass.second); _password = Util::urldecode(userPass.second);
hostPart.erase(0, atmarkp+1); hostPart.erase(0, atmarkp+1);
} }
std::pair<std::string, std::string> hostAndPort; {
Util::split(hostAndPort, hostPart, ':'); std::string::size_type colonpos;
host = hostAndPort.first; // Detect IPv6 literal address in square brackets
if(hostAndPort.second != A2STR::NIL) { if(Util::startsWith(hostPart, "[")) {
try { std::string::size_type rbracketpos = hostPart.find("]");
unsigned int tempPort = Util::parseUInt(hostAndPort.second); if(rbracketpos == std::string::npos) {
if(65535 < tempPort) {
return false; return false;
} }
port = tempPort; _ipv6LiteralAddress = true;
} catch(RecoverableException& e) { colonpos = hostPart.find(":", rbracketpos+1);
return false; } else {
colonpos = hostPart.find_last_of(":");
}
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) {
return false;
}
}
if(_ipv6LiteralAddress) {
host = hostPart.substr(1, colonpos-2);
} else {
host = hostPart.substr(0, colonpos);
} }
} else {
// If port is not specified, then we set it to default port of its protocol..
port = defPort;
} }
// find directory and file part // find directory and file part
std::string::size_type direp = tempUrl.find_last_of("/"); std::string::size_type direp = tempUrl.find_last_of("/");

View File

@ -41,6 +41,7 @@
#include "SharedHandle.h" #include "SharedHandle.h"
#include "PeerStat.h" #include "PeerStat.h"
#include "a2functional.h"
namespace aria2 { namespace aria2 {
@ -82,6 +83,8 @@ private:
std::string _password; std::string _password;
bool _ipv6LiteralAddress;
SharedHandle<PeerStat> _peerStat; SharedHandle<PeerStat> _peerStat;
bool parseUrl(const std::string& url); bool parseUrl(const std::string& url);
@ -116,10 +119,21 @@ public:
void setReferer(const std::string& url); void setReferer(const std::string& url);
const std::string& getProtocol() const { return protocol; } const std::string& getProtocol() const { return protocol; }
const std::string& getHost() const { return host; } const std::string& getHost() const { return host; }
// Same as getHost(), but for IPv6 literal addresses, enclose them
// with square brackets and return.
std::string getURIHost() const
{
if(isIPv6LiteralAddress()) {
return strconcat("[", getHost(), "]");
} else {
return getHost();
}
}
uint16_t getPort() const { return port; } uint16_t getPort() const { return port; }
const std::string& getDir() const { return dir; } const std::string& getDir() const { return dir; }
const std::string& getFile() const { return file;} const std::string& getFile() const { return file;}
const std::string& getQuery() const { return _query; } const std::string& getQuery() const { return _query; }
bool isIPv6LiteralAddress() const { return _ipv6LiteralAddress; }
void supportsPersistentConnection(bool f) void supportsPersistentConnection(bool f)
{ {

View File

@ -28,6 +28,7 @@ class HttpRequestTest : public CppUnit::TestFixture {
CPPUNIT_TEST(testCreateRequest_with_cookie); CPPUNIT_TEST(testCreateRequest_with_cookie);
CPPUNIT_TEST(testCreateRequest_query); CPPUNIT_TEST(testCreateRequest_query);
CPPUNIT_TEST(testCreateRequest_head); CPPUNIT_TEST(testCreateRequest_head);
CPPUNIT_TEST(testCreateRequest_ipv6LiteralAddr);
CPPUNIT_TEST(testCreateProxyRequest); CPPUNIT_TEST(testCreateProxyRequest);
CPPUNIT_TEST(testIsRangeSatisfied); CPPUNIT_TEST(testIsRangeSatisfied);
CPPUNIT_TEST(testUserAgent); CPPUNIT_TEST(testUserAgent);
@ -53,6 +54,7 @@ public:
void testCreateRequest_with_cookie(); void testCreateRequest_with_cookie();
void testCreateRequest_query(); void testCreateRequest_query();
void testCreateRequest_head(); void testCreateRequest_head();
void testCreateRequest_ipv6LiteralAddr();
void testCreateProxyRequest(); void testCreateProxyRequest();
void testIsRangeSatisfied(); void testIsRangeSatisfied();
void testUserAgent(); void testUserAgent();
@ -735,4 +737,23 @@ void HttpRequestTest::testEnableAcceptEncoding()
CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createRequest()); CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createRequest());
} }
void HttpRequestTest::testCreateRequest_ipv6LiteralAddr()
{
SharedHandle<Request> request(new Request());
request->setUrl("http://[::1]/path");
HttpRequest httpRequest;
httpRequest.disableContentEncoding();
httpRequest.setRequest(request);
httpRequest.setAuthConfigFactory(_authConfigFactory, _option.get());
CPPUNIT_ASSERT(httpRequest.createRequest().find("Host: [::1]") != std::string::npos);
SharedHandle<Request> proxy(new Request());
proxy->setUrl("http://proxy");
httpRequest.setProxyRequest(proxy);
std::string proxyRequest = httpRequest.createProxyRequest();
CPPUNIT_ASSERT(proxyRequest.find("Host: [::1]:80") != std::string::npos);
CPPUNIT_ASSERT(proxyRequest.find("CONNECT [::1]:80 ") != std::string::npos);
}
} // namespace aria2 } // namespace aria2

View File

@ -311,11 +311,7 @@ void OptionHandlerTest::testHttpProxyOptionHandler()
handler.parse(option, "http://proxy:8080"); handler.parse(option, "http://proxy:8080");
CPPUNIT_ASSERT_EQUAL(std::string("http://proxy:8080"), CPPUNIT_ASSERT_EQUAL(std::string("http://proxy:8080"),
option.get(PREF_HTTP_PROXY)); option.get(PREF_HTTP_PROXY));
handler.parse(option, "ftp://proxy:8080");
CPPUNIT_ASSERT_EQUAL(std::string("http://ftp://proxy:8080"),
option.get(PREF_HTTP_PROXY));
try { try {
handler.parse(option, "http://bar:65536"); handler.parse(option, "http://bar:65536");

View File

@ -32,6 +32,7 @@ class RequestTest:public CppUnit::TestFixture {
CPPUNIT_TEST(testSetUrl_usernamePassword); CPPUNIT_TEST(testSetUrl_usernamePassword);
CPPUNIT_TEST(testSetUrl_zeroUsername); CPPUNIT_TEST(testSetUrl_zeroUsername);
CPPUNIT_TEST(testSetUrl_supportsPersistentConnection); CPPUNIT_TEST(testSetUrl_supportsPersistentConnection);
CPPUNIT_TEST(testSetUrl_ipv6);
CPPUNIT_TEST(testRedirectUrl); CPPUNIT_TEST(testRedirectUrl);
CPPUNIT_TEST(testRedirectUrl2); CPPUNIT_TEST(testRedirectUrl2);
CPPUNIT_TEST(testRedirectUrl_supportsPersistentConnection); CPPUNIT_TEST(testRedirectUrl_supportsPersistentConnection);
@ -39,6 +40,7 @@ class RequestTest:public CppUnit::TestFixture {
CPPUNIT_TEST(testResetUrl_supportsPersistentConnection); CPPUNIT_TEST(testResetUrl_supportsPersistentConnection);
CPPUNIT_TEST(testInnerLink); CPPUNIT_TEST(testInnerLink);
CPPUNIT_TEST(testInnerLinkInReferer); CPPUNIT_TEST(testInnerLinkInReferer);
CPPUNIT_TEST(testGetURIHost);
CPPUNIT_TEST_SUITE_END(); CPPUNIT_TEST_SUITE_END();
public: public:
@ -63,6 +65,7 @@ public:
void testSetUrl_usernamePassword(); void testSetUrl_usernamePassword();
void testSetUrl_zeroUsername(); void testSetUrl_zeroUsername();
void testSetUrl_supportsPersistentConnection(); void testSetUrl_supportsPersistentConnection();
void testSetUrl_ipv6();
void testRedirectUrl(); void testRedirectUrl();
void testRedirectUrl2(); void testRedirectUrl2();
void testRedirectUrl_supportsPersistentConnection(); void testRedirectUrl_supportsPersistentConnection();
@ -70,6 +73,7 @@ public:
void testResetUrl_supportsPersistentConnection(); void testResetUrl_supportsPersistentConnection();
void testInnerLink(); void testInnerLink();
void testInnerLinkInReferer(); void testInnerLinkInReferer();
void testGetURIHost();
}; };
@ -91,6 +95,7 @@ void RequestTest::testSetUrl1() {
CPPUNIT_ASSERT_EQUAL(std::string(""), req.getQuery()); CPPUNIT_ASSERT_EQUAL(std::string(""), req.getQuery());
CPPUNIT_ASSERT_EQUAL(std::string(""), req.getUsername()); CPPUNIT_ASSERT_EQUAL(std::string(""), req.getUsername());
CPPUNIT_ASSERT_EQUAL(std::string(""), req.getPassword()); CPPUNIT_ASSERT_EQUAL(std::string(""), req.getPassword());
CPPUNIT_ASSERT(!req.isIPv6LiteralAddress());
} }
void RequestTest::testSetUrl2() { void RequestTest::testSetUrl2() {
@ -483,4 +488,26 @@ void RequestTest::testRedirectUrl_supportsPersistentConnection()
CPPUNIT_ASSERT(req.supportsPersistentConnection()); CPPUNIT_ASSERT(req.supportsPersistentConnection());
} }
void RequestTest::testSetUrl_ipv6()
{
Request req;
CPPUNIT_ASSERT(!req.setUrl("http://[::1"));
CPPUNIT_ASSERT(req.setUrl("http://[::1]"));
CPPUNIT_ASSERT_EQUAL(std::string("::1"), req.getHost());
CPPUNIT_ASSERT(req.setUrl("http://[::1]:8000/dir/file"));
CPPUNIT_ASSERT_EQUAL(std::string("::1"), req.getHost());
CPPUNIT_ASSERT_EQUAL((uint16_t)8000, req.getPort());
CPPUNIT_ASSERT_EQUAL(std::string("/dir"), req.getDir());
CPPUNIT_ASSERT_EQUAL(std::string("file"), req.getFile());
CPPUNIT_ASSERT(req.isIPv6LiteralAddress());
}
void RequestTest::testGetURIHost()
{
Request req;
CPPUNIT_ASSERT(req.setUrl("http://[::1]"));
CPPUNIT_ASSERT_EQUAL(std::string("[::1]"), req.getURIHost());
}
} // namespace aria2 } // namespace aria2