From ce25b54cfe3ba23408da19fcd87539bec879b943 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sun, 30 Aug 2009 15:05:30 +0000 Subject: [PATCH] 2009-08-31 Tatsuhiro Tsujikawa 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 --- ChangeLog | 12 ++++++++++ src/HttpRequest.cc | 6 ++--- src/HttpRequest.h | 7 ++++-- src/Request.cc | 48 +++++++++++++++++++++++++++------------ src/Request.h | 14 ++++++++++++ test/HttpRequestTest.cc | 21 +++++++++++++++++ test/OptionHandlerTest.cc | 6 +---- test/RequestTest.cc | 27 ++++++++++++++++++++++ 8 files changed, 117 insertions(+), 24 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4da4f9e0..a13597dc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2009-08-31 Tatsuhiro Tsujikawa + + 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 Fixed the bug that HTTP request header for XML-RPC request is not diff --git a/src/HttpRequest.cc b/src/HttpRequest.cc index 3c4e8f06..63bdc557 100644 --- a/src/HttpRequest.cc +++ b/src/HttpRequest.cc @@ -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; 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 += "Cache-Control: no-cache\r\n"; @@ -235,7 +235,7 @@ std::string HttpRequest::createRequest() std::string HttpRequest::createProxyRequest() const { assert(!_proxyRequest.isNull()); - std::string hostport = getHost(); + std::string hostport = getURIHost(); strappend(hostport, ":", Util::uitos(getPort())); std::string requestLine = "CONNECT "; diff --git a/src/HttpRequest.h b/src/HttpRequest.h index 18a0768b..b32b614b 100644 --- a/src/HttpRequest.h +++ b/src/HttpRequest.h @@ -83,8 +83,6 @@ private: SharedHandle _proxyRequest; - std::string getHostText(const std::string& host, uint16_t port) const; - std::string getProxyAuthString() const; public: HttpRequest(); @@ -149,6 +147,11 @@ public: return request->getPreviousUrl(); } + std::string getURIHost() const + { + return request->getURIHost(); + } + SharedHandle getRange() const; /** diff --git a/src/Request.cc b/src/Request.cc index ee9d7c0a..e055811f 100644 --- a/src/Request.cc +++ b/src/Request.cc @@ -71,7 +71,8 @@ Request::Request(): _keepAliveHint(false), _pipeliningHint(false), _maxPipelinedRequest(1), - method(METHOD_GET) + method(METHOD_GET), + _ipv6LiteralAddress(false) {} static std::string removeFragment(const std::string url) @@ -160,6 +161,7 @@ bool Request::parseUrl(const std::string& url) { _query = A2STR::NIL; _username = A2STR::NIL; _password = A2STR::NIL; + _ipv6LiteralAddress = false; // find query part std::string queryTemp; std::string::size_type startQueryIndex = tempUrl.find("?"); @@ -193,22 +195,40 @@ bool Request::parseUrl(const std::string& url) { _password = Util::urldecode(userPass.second); hostPart.erase(0, atmarkp+1); } - std::pair hostAndPort; - Util::split(hostAndPort, hostPart, ':'); - host = hostAndPort.first; - if(hostAndPort.second != A2STR::NIL) { - try { - unsigned int tempPort = Util::parseUInt(hostAndPort.second); - if(65535 < tempPort) { + { + std::string::size_type colonpos; + // Detect IPv6 literal address in square brackets + if(Util::startsWith(hostPart, "[")) { + std::string::size_type rbracketpos = hostPart.find("]"); + if(rbracketpos == std::string::npos) { return false; } - port = tempPort; - } catch(RecoverableException& e) { - return false; + _ipv6LiteralAddress = true; + colonpos = hostPart.find(":", rbracketpos+1); + } 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 std::string::size_type direp = tempUrl.find_last_of("/"); diff --git a/src/Request.h b/src/Request.h index cab16999..5c88cf62 100644 --- a/src/Request.h +++ b/src/Request.h @@ -41,6 +41,7 @@ #include "SharedHandle.h" #include "PeerStat.h" +#include "a2functional.h" namespace aria2 { @@ -82,6 +83,8 @@ private: std::string _password; + bool _ipv6LiteralAddress; + SharedHandle _peerStat; bool parseUrl(const std::string& url); @@ -116,10 +119,21 @@ public: void setReferer(const std::string& url); const std::string& getProtocol() const { return protocol; } 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; } const std::string& getDir() const { return dir; } const std::string& getFile() const { return file;} const std::string& getQuery() const { return _query; } + bool isIPv6LiteralAddress() const { return _ipv6LiteralAddress; } void supportsPersistentConnection(bool f) { diff --git a/test/HttpRequestTest.cc b/test/HttpRequestTest.cc index 2df09ccb..de65245c 100644 --- a/test/HttpRequestTest.cc +++ b/test/HttpRequestTest.cc @@ -28,6 +28,7 @@ class HttpRequestTest : public CppUnit::TestFixture { CPPUNIT_TEST(testCreateRequest_with_cookie); CPPUNIT_TEST(testCreateRequest_query); CPPUNIT_TEST(testCreateRequest_head); + CPPUNIT_TEST(testCreateRequest_ipv6LiteralAddr); CPPUNIT_TEST(testCreateProxyRequest); CPPUNIT_TEST(testIsRangeSatisfied); CPPUNIT_TEST(testUserAgent); @@ -53,6 +54,7 @@ public: void testCreateRequest_with_cookie(); void testCreateRequest_query(); void testCreateRequest_head(); + void testCreateRequest_ipv6LiteralAddr(); void testCreateProxyRequest(); void testIsRangeSatisfied(); void testUserAgent(); @@ -735,4 +737,23 @@ void HttpRequestTest::testEnableAcceptEncoding() CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createRequest()); } +void HttpRequestTest::testCreateRequest_ipv6LiteralAddr() +{ + SharedHandle 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 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 diff --git a/test/OptionHandlerTest.cc b/test/OptionHandlerTest.cc index b99c91d3..e033600a 100644 --- a/test/OptionHandlerTest.cc +++ b/test/OptionHandlerTest.cc @@ -311,11 +311,7 @@ void OptionHandlerTest::testHttpProxyOptionHandler() handler.parse(option, "http://proxy:8080"); CPPUNIT_ASSERT_EQUAL(std::string("http://proxy:8080"), - 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)); + option.get(PREF_HTTP_PROXY)); try { handler.parse(option, "http://bar:65536"); diff --git a/test/RequestTest.cc b/test/RequestTest.cc index cc109372..61ad9d65 100644 --- a/test/RequestTest.cc +++ b/test/RequestTest.cc @@ -32,6 +32,7 @@ class RequestTest:public CppUnit::TestFixture { CPPUNIT_TEST(testSetUrl_usernamePassword); CPPUNIT_TEST(testSetUrl_zeroUsername); CPPUNIT_TEST(testSetUrl_supportsPersistentConnection); + CPPUNIT_TEST(testSetUrl_ipv6); CPPUNIT_TEST(testRedirectUrl); CPPUNIT_TEST(testRedirectUrl2); CPPUNIT_TEST(testRedirectUrl_supportsPersistentConnection); @@ -39,6 +40,7 @@ class RequestTest:public CppUnit::TestFixture { CPPUNIT_TEST(testResetUrl_supportsPersistentConnection); CPPUNIT_TEST(testInnerLink); CPPUNIT_TEST(testInnerLinkInReferer); + CPPUNIT_TEST(testGetURIHost); CPPUNIT_TEST_SUITE_END(); public: @@ -63,6 +65,7 @@ public: void testSetUrl_usernamePassword(); void testSetUrl_zeroUsername(); void testSetUrl_supportsPersistentConnection(); + void testSetUrl_ipv6(); void testRedirectUrl(); void testRedirectUrl2(); void testRedirectUrl_supportsPersistentConnection(); @@ -70,6 +73,7 @@ public: void testResetUrl_supportsPersistentConnection(); void testInnerLink(); void testInnerLinkInReferer(); + void testGetURIHost(); }; @@ -91,6 +95,7 @@ void RequestTest::testSetUrl1() { CPPUNIT_ASSERT_EQUAL(std::string(""), req.getQuery()); CPPUNIT_ASSERT_EQUAL(std::string(""), req.getUsername()); CPPUNIT_ASSERT_EQUAL(std::string(""), req.getPassword()); + CPPUNIT_ASSERT(!req.isIPv6LiteralAddress()); } void RequestTest::testSetUrl2() { @@ -483,4 +488,26 @@ void RequestTest::testRedirectUrl_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