Prechádzať zdrojové kódy

2009-05-22 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>

	Added --save-cookies option.
	* src/Cookie.cc
	* src/Cookie.h
	* src/CookieStorage.cc
	* src/CookieStorage.h
	* src/MultiUrlRequestInfo.cc
	* src/OptionHandlerFactory.cc
	* src/prefs.cc
	* src/prefs.h
	* src/usage_text.h
	* test/CookieStorageTest.cc
	* test/CookieTest.cc
Tatsuhiro Tsujikawa 16 rokov pred
rodič
commit
383b12d7f1

+ 15 - 0
ChangeLog

@@ -1,3 +1,18 @@
+2009-05-22  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
+
+	Added --save-cookies option.
+	* src/Cookie.cc
+	* src/Cookie.h
+	* src/CookieStorage.cc
+	* src/CookieStorage.h
+	* src/MultiUrlRequestInfo.cc
+	* src/OptionHandlerFactory.cc
+	* src/prefs.cc
+	* src/prefs.h
+	* src/usage_text.h
+	* test/CookieStorageTest.cc
+	* test/CookieTest.cc
+
 2009-05-22  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
 
 	Removed tellAll XML-RPC command because its reponse tends to be

+ 24 - 0
src/Cookie.cc

@@ -35,6 +35,7 @@
 #include "Cookie.h"
 
 #include <algorithm>
+#include <sstream>
 
 #include "Util.h"
 #include "A2STR.h"
@@ -240,4 +241,27 @@ bool Cookie::isSessionCookie() const
   return _expiry == 0;
 }
 
+std::string Cookie::toNsCookieFormat() const
+{
+  std::stringstream ss;
+  ss << _domain << "\t";
+  if(Util::startsWith(_domain, ".")) {
+    ss << "TRUE";
+  } else {
+    ss << "FALSE";
+  }
+  ss << "\t";
+  ss << _path << "\t";
+  if(_secure) {
+    ss << "TRUE";
+  } else {
+    ss << "FALSE";
+  }
+  ss << "\t";
+  ss << _expiry << "\t";
+  ss << _name << "\t";
+  ss << _value;
+  return ss.str();
+}
+
 } // namespace aria2

+ 2 - 0
src/Cookie.h

@@ -104,6 +104,8 @@ public:
   bool isSecureCookie() const;
 
   bool isSessionCookie() const;
+
+  std::string toNsCookieFormat() const;
 };
 
 typedef std::deque<Cookie> Cookies;

+ 19 - 0
src/CookieStorage.cc

@@ -34,6 +34,7 @@
 /* copyright --> */
 #include "CookieStorage.h"
 
+#include <cstring>
 #include <algorithm>
 #include <fstream>
 
@@ -171,4 +172,22 @@ void CookieStorage::load(const std::string& filename)
   }
 }
 
+void CookieStorage::saveNsFormat(const std::string& filename)
+{
+  std::ofstream o(filename.c_str(), std::ios::binary);
+  if(!o) {
+    throw DL_ABORT_EX
+      (StringFormat("Cannot create cookie file %s, cause %s",
+		    filename.c_str(), strerror(errno)).str());
+  }
+  for(std::deque<Cookie>::const_iterator i = _cookies.begin();
+      i != _cookies.end(); ++i) {
+    o << (*i).toNsCookieFormat() << "\n";
+    if(!o) {
+      throw DL_ABORT_EX
+	(StringFormat("Failed to save cookies to %s", filename.c_str()).str());
+    }
+  }
+}
+
 } // namespace aria2

+ 6 - 2
src/CookieStorage.h

@@ -36,11 +36,13 @@
 #define _D_COOKIE_STORAGE_H_
 
 #include "common.h"
+
+#include <string>
+#include <deque>
+
 #include "a2time.h"
 #include "Cookie.h"
 #include "CookieParser.h"
-#include <string>
-#include <deque>
 
 namespace aria2 {
 
@@ -75,6 +77,8 @@ public:
 				  time_t date, bool secure) const;
 
   void load(const std::string& filename);
+  
+  void saveNsFormat(const std::string& filename);
 
   size_t size() const;
   

+ 8 - 0
src/MultiUrlRequestInfo.cc

@@ -182,6 +182,14 @@ DownloadResult::RESULT MultiUrlRequestInfo::execute()
     
     e->run();
     
+    if(!_option->blank(PREF_SAVE_COOKIES)) {
+      try {
+	e->getCookieStorage()->saveNsFormat(_option->get(PREF_SAVE_COOKIES));
+      } catch(RecoverableException& e) {
+	_logger->error(EX_EXCEPTION_CAUGHT, e);
+      }
+    }
+
     std::string serverStatOf = _option->get(PREF_SERVER_STAT_OF);
     if(!serverStatOf.empty()) {
       e->_requestGroupMan->saveServerStat(serverStatOf);

+ 9 - 0
src/OptionHandlerFactory.cc

@@ -735,6 +735,15 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
     op->addTag(TAG_HTTP);
     handlers.push_back(op);
   }
+  {
+    SharedHandle<OptionHandler> op(new DefaultOptionHandler
+				   (PREF_SAVE_COOKIES,
+				    TEXT_SAVE_COOKIES,
+				    NO_DEFAULT_VALUE,
+				    "/path/to/file"));
+    op->addTag(TAG_HTTP);
+    handlers.push_back(op);
+  }
   {
     SharedHandle<OptionHandler> op(new BooleanOptionHandler
 				   (PREF_USE_HEAD,

+ 2 - 0
src/prefs.cc

@@ -199,6 +199,8 @@ const std::string V_BASIC("basic");
 const std::string PREF_USER_AGENT("user-agent");
 // value: string that your file system recognizes as a file name.
 const std::string PREF_LOAD_COOKIES("load-cookies");
+// value: string that your file system recognizes as a file name.
+const std::string PREF_SAVE_COOKIES("save-cookies");
 // values: true | false
 const std::string PREF_ENABLE_HTTP_KEEP_ALIVE("enable-http-keep-alive");
 // values: true | false

+ 2 - 0
src/prefs.h

@@ -203,6 +203,8 @@ extern const std::string V_BASIC;
 extern const std::string PREF_USER_AGENT;
 // value: string that your file system recognizes as a file name.
 extern const std::string PREF_LOAD_COOKIES;
+// value: string that your file system recognizes as a file name.
+extern const std::string PREF_SAVE_COOKIES;
 // values: true | false
 extern const std::string PREF_ENABLE_HTTP_KEEP_ALIVE;
 // values: true | false

+ 5 - 0
src/usage_text.h

@@ -217,6 +217,11 @@ _(" -j, --max-concurrent-downloads=N Set maximum number of parallel downloads fo
 #define TEXT_LOAD_COOKIES \
 _(" --load-cookies=FILE          Load Cookies from FILE using the Firefox3 format\n"\
   "                              and Mozilla/Firefox(1.x/2.x)/Netscape format.")
+#define TEXT_SAVE_COOKIES \
+_(" --save-cookies=FILE          Save Cookies to FILE in Mozilla/Firefox(1.x/2.x)/\n"\
+  "                              Netscape format. If FILE already exists, it is\n"\
+  "                              overwritten. Session Cookies are also saved and\n"\
+  "                              their expiry values are treated as 0.")
 #define TEXT_SHOW_FILES \
 _(" -S, --show-files             Print file listing of .torrent or .metalink file\n"\
   "                              and exit. More detailed information will be listed\n"\

+ 37 - 0
test/CookieStorageTest.cc

@@ -22,6 +22,8 @@ class CookieStorageTest:public CppUnit::TestFixture {
   CPPUNIT_TEST(testLoad);
   CPPUNIT_TEST(testLoad_sqlite3);
   CPPUNIT_TEST(testLoad_fileNotfound);
+  CPPUNIT_TEST(testSaveNsFormat);
+  CPPUNIT_TEST(testSaveNsFormat_fail);
   CPPUNIT_TEST_SUITE_END();
 public:
   void setUp() {}
@@ -34,6 +36,8 @@ public:
   void testLoad();
   void testLoad_sqlite3();
   void testLoad_fileNotfound();
+  void testSaveNsFormat();
+  void testSaveNsFormat_fail();
 };
 
 
@@ -261,4 +265,37 @@ void CookieStorageTest::testLoad_fileNotfound()
   }
 }
 
+void CookieStorageTest::testSaveNsFormat()
+{
+  std::string filename = "/tmp/aria2_CookieStorageTest_testSaveNsFormat";
+  File(filename).remove();
+  CookieStorage st;
+  st.store(Cookie("uid","tujikawa","/",".domain.org",true));
+  st.store(Cookie("favorite","classic","/config",".domain.org",false));
+  st.saveNsFormat(filename);
+  CookieStorage loadst;
+  loadst.load(filename);
+  CPPUNIT_ASSERT_EQUAL((size_t)2, loadst.size());
+  CPPUNIT_ASSERT_EQUAL(std::string("uid"), (*loadst.begin()).getName());
+  CPPUNIT_ASSERT_EQUAL((time_t)0, (*loadst.begin()).getExpiry());
+  CPPUNIT_ASSERT((*loadst.begin()).isSessionCookie());
+  CPPUNIT_ASSERT_EQUAL(std::string("favorite"), (*(loadst.begin()+1)).getName());
+}
+
+void CookieStorageTest::testSaveNsFormat_fail()
+{
+  std::string filename = "/tmp/aria2_CookieStorageTest_testSaveNsFormat_fail";
+  File f(filename);
+  if(!f.exists()) {
+    f.mkdirs();
+  }
+  CookieStorage st;
+  try {
+    st.saveNsFormat(filename);
+    CPPUNIT_FAIL("exception should be thrown.");
+  } catch(RecoverableException& e) {
+    // OK
+  }
+}
+
 } // namespace aria2

+ 13 - 0
test/CookieTest.cc

@@ -18,6 +18,7 @@ class CookieTest:public CppUnit::TestFixture {
   CPPUNIT_TEST(testMatch);
   CPPUNIT_TEST(testIsExpired);
   CPPUNIT_TEST(testNormalizeDomain);
+  CPPUNIT_TEST(testToNsCookieFormat);
   CPPUNIT_TEST_SUITE_END();
 public:
   void setUp() {}
@@ -29,6 +30,7 @@ public:
   void testMatch();
   void testIsExpired();
   void testNormalizeDomain();
+  void testToNsCookieFormat();
 };
 
 
@@ -176,4 +178,15 @@ void CookieTest::testNormalizeDomain()
   CPPUNIT_ASSERT_EQUAL(std::string("192.168.1.1"), ip.getDomain());
 }
 
+void CookieTest::testToNsCookieFormat()
+{
+  CPPUNIT_ASSERT_EQUAL
+    (std::string(".domain.org\tTRUE\t/\tFALSE\t12345678\thello\tworld"),
+     Cookie("hello","world",12345678,"/",".domain.org",false).toNsCookieFormat());
+  // Session cookie's expiry is 0
+  CPPUNIT_ASSERT_EQUAL
+    (std::string(".domain.org\tTRUE\t/\tTRUE\t0\thello\tworld"),
+     Cookie("hello","world","/","domain.org",true).toNsCookieFormat());
+}
+
 } // namespace aria2