From 383b12d7f19c037a771e5d85931a62eebeb403f7 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Fri, 22 May 2009 14:51:57 +0000 Subject: [PATCH] 2009-05-22 Tatsuhiro Tsujikawa 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 --- ChangeLog | 15 +++++++++++++++ src/Cookie.cc | 24 ++++++++++++++++++++++++ src/Cookie.h | 2 ++ src/CookieStorage.cc | 19 +++++++++++++++++++ src/CookieStorage.h | 8 ++++++-- src/MultiUrlRequestInfo.cc | 8 ++++++++ src/OptionHandlerFactory.cc | 9 +++++++++ src/prefs.cc | 2 ++ src/prefs.h | 2 ++ src/usage_text.h | 5 +++++ test/CookieStorageTest.cc | 37 +++++++++++++++++++++++++++++++++++++ test/CookieTest.cc | 13 +++++++++++++ 12 files changed, 142 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index f770bfbb..73372ef4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2009-05-22 Tatsuhiro Tsujikawa + + 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 Removed tellAll XML-RPC command because its reponse tends to be diff --git a/src/Cookie.cc b/src/Cookie.cc index bdbfaad8..284d6aa1 100644 --- a/src/Cookie.cc +++ b/src/Cookie.cc @@ -35,6 +35,7 @@ #include "Cookie.h" #include +#include #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 diff --git a/src/Cookie.h b/src/Cookie.h index b1b98573..83150dbd 100644 --- a/src/Cookie.h +++ b/src/Cookie.h @@ -104,6 +104,8 @@ public: bool isSecureCookie() const; bool isSessionCookie() const; + + std::string toNsCookieFormat() const; }; typedef std::deque Cookies; diff --git a/src/CookieStorage.cc b/src/CookieStorage.cc index 0f817097..044353bf 100644 --- a/src/CookieStorage.cc +++ b/src/CookieStorage.cc @@ -34,6 +34,7 @@ /* copyright --> */ #include "CookieStorage.h" +#include #include #include @@ -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::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 diff --git a/src/CookieStorage.h b/src/CookieStorage.h index d8ea6149..32a12809 100644 --- a/src/CookieStorage.h +++ b/src/CookieStorage.h @@ -36,11 +36,13 @@ #define _D_COOKIE_STORAGE_H_ #include "common.h" + +#include +#include + #include "a2time.h" #include "Cookie.h" #include "CookieParser.h" -#include -#include 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; diff --git a/src/MultiUrlRequestInfo.cc b/src/MultiUrlRequestInfo.cc index d0ffe5ed..82a45083 100644 --- a/src/MultiUrlRequestInfo.cc +++ b/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); diff --git a/src/OptionHandlerFactory.cc b/src/OptionHandlerFactory.cc index d59a6b1d..8179ec41 100644 --- a/src/OptionHandlerFactory.cc +++ b/src/OptionHandlerFactory.cc @@ -735,6 +735,15 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers() op->addTag(TAG_HTTP); handlers.push_back(op); } + { + SharedHandle op(new DefaultOptionHandler + (PREF_SAVE_COOKIES, + TEXT_SAVE_COOKIES, + NO_DEFAULT_VALUE, + "/path/to/file")); + op->addTag(TAG_HTTP); + handlers.push_back(op); + } { SharedHandle op(new BooleanOptionHandler (PREF_USE_HEAD, diff --git a/src/prefs.cc b/src/prefs.cc index 3ea9763b..a184bc03 100644 --- a/src/prefs.cc +++ b/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 diff --git a/src/prefs.h b/src/prefs.h index 79b7bf84..efee24f9 100644 --- a/src/prefs.h +++ b/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 diff --git a/src/usage_text.h b/src/usage_text.h index ec4e5b70..69695ca5 100644 --- a/src/usage_text.h +++ b/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"\ diff --git a/test/CookieStorageTest.cc b/test/CookieStorageTest.cc index 77b791d6..ad223847 100644 --- a/test/CookieStorageTest.cc +++ b/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 diff --git a/test/CookieTest.cc b/test/CookieTest.cc index cc1c67d4..0ec0727e 100644 --- a/test/CookieTest.cc +++ b/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