From 3eb74629cbd0f01113bc581d486a8ec95633b4ad Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sun, 20 Apr 2008 06:30:44 +0000 Subject: [PATCH] 2008-04-20 Tatsuhiro Tsujikawa Added --header option. You can specify any number of additional HTTP headers like: aria2 --header="X-A: 300" --header="X-B: 900" http://host/file Unlike other commad-line option, you can use --header option multiple times. * src/HelpItemFactory.cc * src/HttpRequest.{cc, h} * src/HttpRequestCommand.cc * src/OptionHandlerFactory.cc * src/OptionHandlerImpl.h * src/option_processing.cc * src/prefs.h * src/usage_text.h * test/HttpRequestTest.cc (testUserHeaders) --- ChangeLog | 16 ++++++++++++++++ src/HelpItemFactory.cc | 5 +++++ src/HttpRequest.cc | 14 ++++++++++++++ src/HttpRequest.h | 4 ++++ src/HttpRequestCommand.cc | 1 + src/OptionHandlerFactory.cc | 2 +- src/OptionHandlerImpl.h | 19 +++++++++++++++++++ src/option_processing.cc | 4 ++++ src/prefs.h | 2 ++ src/usage_text.h | 6 ++++++ test/HttpRequestTest.cc | 26 ++++++++++++++++++++++++++ 11 files changed, 98 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 38d5a0ad3..7da797fcd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2008-04-20 Tatsuhiro Tsujikawa + + Added --header option. You can specify any number of additional HTTP headers + like: + aria2 --header="X-A: 300" --header="X-B: 900" http://host/file + Unlike other commad-line option, you can use --header option multiple times. + * src/HelpItemFactory.cc + * src/HttpRequest.{cc, h} + * src/HttpRequestCommand.cc + * src/OptionHandlerFactory.cc + * src/OptionHandlerImpl.h + * src/option_processing.cc + * src/prefs.h + * src/usage_text.h + * test/HttpRequestTest.cc (testUserHeaders) + 2008-04-20 Tatsuhiro Tsujikawa Eliminates the time lag between sequential downloads and commands in diff --git a/src/HelpItemFactory.cc b/src/HelpItemFactory.cc index 5025883f1..e4011e06a 100644 --- a/src/HelpItemFactory.cc +++ b/src/HelpItemFactory.cc @@ -432,6 +432,11 @@ TagContainerHandle HelpItemFactory::createHelpItems() item->addTag(TAG_ADVANCED); tc->addItem(item); } + { + HelpItemHandle item(new HelpItem(PREF_HEADER, TEXT_HEADER)); + item->addTag(TAG_ADVANCED); + tc->addItem(item); + } { HelpItemHandle item(new HelpItem("help", TEXT_HELP, TAG_BASIC)); char buf[64]; diff --git a/src/HttpRequest.cc b/src/HttpRequest.cc index 9d43902da..da2db3861 100644 --- a/src/HttpRequest.cc +++ b/src/HttpRequest.cc @@ -44,6 +44,7 @@ #include "prefs.h" #include "AuthConfigFactory.h" #include "AuthConfig.h" +#include namespace aria2 { @@ -190,6 +191,12 @@ std::string HttpRequest::createRequest() const if(cookiesValue.size()) { requestLine += std::string("Cookie: ")+cookiesValue+"\r\n"; } + // append additional headers given by user. + for(std::deque::const_iterator i = _userHeaders.begin(); + i != _userHeaders.end(); ++i) { + requestLine += (*i)+"\r\n"; + } + requestLine += "\r\n"; return requestLine; } @@ -218,6 +225,13 @@ std::string HttpRequest::getProxyAuthString() const { Base64::encode(AuthConfigFactorySingleton::instance()->createAuthConfigForHttpProxy(request)->getAuthText())+"\r\n"; } +void HttpRequest::setUserHeaders(const std::string& userHeadersString) +{ + std::deque headers; + Util::slice(headers, userHeadersString, '\n', true); + _userHeaders = headers; +} + void HttpRequest::configure(const Option* option) { authEnabled = option->get(PREF_HTTP_AUTH_ENABLED) == V_TRUE; diff --git a/src/HttpRequest.h b/src/HttpRequest.h index a47b10a39..ae39bb47b 100644 --- a/src/HttpRequest.h +++ b/src/HttpRequest.h @@ -66,6 +66,8 @@ private: std::string userAgent; + std::deque _userHeaders; + std::string getHostText(const std::string& host, uint16_t port) const; std::string getProxyAuthString() const; @@ -164,6 +166,8 @@ public: { this->userAgent = userAgent; } + + void setUserHeaders(const std::string& userHeaders); }; typedef SharedHandle HttpRequestHandle; diff --git a/src/HttpRequestCommand.cc b/src/HttpRequestCommand.cc index c691c4b38..7f94c34e4 100644 --- a/src/HttpRequestCommand.cc +++ b/src/HttpRequestCommand.cc @@ -84,6 +84,7 @@ bool HttpRequestCommand::executeInternal() { httpRequest->setUserAgent(e->option->get(PREF_USER_AGENT)); httpRequest->setRequest(req); httpRequest->setEntityLength(_requestGroup->getTotalLength()); + httpRequest->setUserHeaders(e->option->get(PREF_HEADER)); httpRequest->configure(e->option); _httpConnection->sendRequest(httpRequest); diff --git a/src/OptionHandlerFactory.cc b/src/OptionHandlerFactory.cc index 9dafed579..a8e0ce3e7 100644 --- a/src/OptionHandlerFactory.cc +++ b/src/OptionHandlerFactory.cc @@ -126,7 +126,7 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers() handlers.push_back(SH(new NumberOptionHandler(PREF_STOP, 0, INT32_MAX))); handlers.push_back(SH(new ParameterOptionHandler(PREF_BT_MIN_CRYPTO_LEVEL, V_PLAIN, V_ARC4))); handlers.push_back(SH(new BooleanOptionHandler(PREF_BT_REQUIRE_CRYPTO))); - + handlers.push_back(SH(new CumulativeOptionHandler(PREF_HEADER, "\n"))); return handlers; } diff --git a/src/OptionHandlerImpl.h b/src/OptionHandlerImpl.h index 5925e3b4c..1d6e81a98 100644 --- a/src/OptionHandlerImpl.h +++ b/src/OptionHandlerImpl.h @@ -192,6 +192,25 @@ public: } }; +class CumulativeOptionHandler : public NameMatchOptionHandler { +private: + std::string _delim; +public: + CumulativeOptionHandler(const std::string& optName, + const std::string& delim): + NameMatchOptionHandler(optName), + _delim(delim) {} + + virtual ~CumulativeOptionHandler() {} + + virtual void parseArg(Option* option, const std::string& optarg) + { + std::string value = option->get(_optName); + value += optarg+_delim; + option->put(_optName, value); + } +}; + class ParameterOptionHandler : public NameMatchOptionHandler { private: std::deque _validParamValues; diff --git a/src/option_processing.cc b/src/option_processing.cc index 6c11cac13..74cb00445 100644 --- a/src/option_processing.cc +++ b/src/option_processing.cc @@ -204,6 +204,7 @@ Option* option_processing(int argc, char* const argv[]) { PREF_NO_CONF, no_argument, &lopt, 212 }, { PREF_CONF_PATH, required_argument, &lopt, 213 }, { PREF_STOP, required_argument, &lopt, 214 }, + { PREF_HEADER, required_argument, &lopt, 215 }, #if defined ENABLE_BITTORRENT || ENABLE_METALINK { PREF_SHOW_FILES, no_argument, NULL, 'S' }, { PREF_SELECT_FILE, required_argument, &lopt, 21 }, @@ -402,6 +403,9 @@ Option* option_processing(int argc, char* const argv[]) case 214: cmdstream << PREF_STOP << "=" << optarg << "\n"; break; + case 215: + cmdstream << PREF_HEADER << "=" << optarg << "\n"; + break; } break; } diff --git a/src/prefs.h b/src/prefs.h index 88c4fe0f0..96c5e3510 100644 --- a/src/prefs.h +++ b/src/prefs.h @@ -163,6 +163,8 @@ #define PREF_ENABLE_HTTP_PIPELINING "enable-http-pipelining" // value: 1*digit #define PREF_MAX_HTTP_PIPELINING "max-http-pipelining" +// value: string +#define PREF_HEADER "header" /** * HTTP proxy related preferences diff --git a/src/usage_text.h b/src/usage_text.h index 774a23177..af3b1d204 100644 --- a/src/usage_text.h +++ b/src/usage_text.h @@ -330,3 +330,9 @@ _(" --conf-path=PATH Change the configuration file path to PATH.") #define TEXT_STOP \ _(" --stop=SEC Stop application after SEC seconds has passed.\n" \ " If 0 is given, this feature is disabled.") +#define TEXT_HEADER \ +_(" --header=HEADER Append HEADER to HTTP request header. You can use\n"\ + " this option repeatedly to specify more than one\n"\ + " header:\n"\ + " aria2c --header=\"X-A: b78\" --header=\"X-B: 9J1\"\n"\ + " http://host/file") diff --git a/test/HttpRequestTest.cc b/test/HttpRequestTest.cc index a06109d50..a2ffb5581 100644 --- a/test/HttpRequestTest.cc +++ b/test/HttpRequestTest.cc @@ -22,6 +22,7 @@ class HttpRequestTest : public CppUnit::TestFixture { CPPUNIT_TEST(testCreateProxyRequest); CPPUNIT_TEST(testIsRangeSatisfied); CPPUNIT_TEST(testUserAgent); + CPPUNIT_TEST(testUserHeaders); CPPUNIT_TEST_SUITE_END(); private: @@ -36,6 +37,7 @@ public: void testCreateProxyRequest(); void testIsRangeSatisfied(); void testUserAgent(); + void testUserHeaders(); }; @@ -557,4 +559,28 @@ void HttpRequestTest::testUserAgent() CPPUNIT_ASSERT_EQUAL(expectedTextForProxy, httpRequest.createProxyRequest()); } +void HttpRequestTest::testUserHeaders() +{ + SharedHandle request(new Request()); + request->setUrl("http://localhost/archives/aria2-1.0.0.tar.bz2"); + + HttpRequest httpRequest; + httpRequest.setRequest(request); + httpRequest.setUserHeaders("X-ARIA2: v0.13\nX-ARIA2-DISTRIBUTE: enabled\n"); + + std::string expectedText = "GET /archives/aria2-1.0.0.tar.bz2 HTTP/1.1\r\n" + "User-Agent: aria2\r\n" + "Accept: */*\r\n" + "Host: localhost\r\n" + "Pragma: no-cache\r\n" + "Cache-Control: no-cache\r\n" + "Connection: close\r\n" + "X-ARIA2: v0.13\r\n" + "X-ARIA2-DISTRIBUTE: enabled\r\n" + "\r\n"; + + CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createRequest()); +} + + } // namespace aria2