Przeglądaj źródła

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
Tatsuhiro Tsujikawa 16 lat temu
rodzic
commit
ce25b54cfe
8 zmienionych plików z 117 dodań i 24 usunięć
  1. 12 0
      ChangeLog
  2. 3 3
      src/HttpRequest.cc
  3. 5 2
      src/HttpRequest.h
  4. 34 14
      src/Request.cc
  5. 14 0
      src/Request.h
  6. 21 0
      test/HttpRequestTest.cc
  7. 1 5
      test/OptionHandlerTest.cc
  8. 27 0
      test/RequestTest.cc

+ 12 - 0
ChangeLog

@@ -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>
 
 	Fixed the bug that HTTP request header for XML-RPC request is not

+ 3 - 3
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 ";

+ 5 - 2
src/HttpRequest.h

@@ -83,8 +83,6 @@ private:
 
   SharedHandle<Request> _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<Range> getRange() const;
 
   /**

+ 34 - 14
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<std::string, std::string> 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("/");

+ 14 - 0
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> _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)
   {

+ 21 - 0
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> 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

+ 1 - 5
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");

+ 27 - 0
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