2008-04-26 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>

Added build-in "Accept-Feature" support. For now only "metalink" is
	used in this header field.
	This "metalink" value is removed from the list when connecting URLs
	fed by metalink file to avoid loop in "transparent" metlaink.
	* src/HttpRequest.cc
	* src/HttpRequest.h: Renamed _userHeaders as _headers. Accept-Feature
	header is also held in this variable. Also renamed setUserHeaders as
	addHeader and it was rewritten to add header not just to clear the old
	value.
	* src/HttpRequestCommand.cc
	* src/Metalink2RequestGroup.cc: Added the code to remove "metalink"
	from "Accept-Feature" list.
	* src/RequestGroup.cc: Added "metalink" to "Accept-Feature" by default.
	* src/RequestGroup.h
	* src/TaggedItem.cc: Moved Concat class to a2functional.h.
	* src/a2functional.h: Included <string> because Concat class depends on
	it.
	* test/HttpRequestTest.cc
pull/1/head
Tatsuhiro Tsujikawa 2008-04-25 17:44:03 +00:00
parent 8ea2f386cb
commit 2a81fd466d
10 changed files with 112 additions and 29 deletions

View File

@ -1,3 +1,24 @@
2008-04-26 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
Added build-in "Accept-Feature" support. For now only "metalink" is
used in this header field.
This "metalink" value is removed from the list when connecting URLs
fed by metalink file to avoid loop in "transparent" metlaink.
* src/HttpRequest.cc
* src/HttpRequest.h: Renamed _userHeaders as _headers. Accept-Feature
header is also held in this variable. Also renamed setUserHeaders as
addHeader and it was rewritten to add header not just to clear the old
value.
* src/HttpRequestCommand.cc
* src/Metalink2RequestGroup.cc: Added the code to remove "metalink"
from "Accept-Feature" list.
* src/RequestGroup.cc: Added "metalink" to "Accept-Feature" by default.
* src/RequestGroup.h
* src/TaggedItem.cc: Moved Concat class to a2functional.h.
* src/a2functional.h: Included <string> because Concat class depends on
it.
* test/HttpRequestTest.cc
2008-04-26 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com> 2008-04-26 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
Added comment Added comment

View File

@ -192,8 +192,8 @@ std::string HttpRequest::createRequest() const
requestLine += std::string("Cookie: ")+cookiesValue+"\r\n"; requestLine += std::string("Cookie: ")+cookiesValue+"\r\n";
} }
// append additional headers given by user. // append additional headers given by user.
for(std::deque<std::string>::const_iterator i = _userHeaders.begin(); for(std::deque<std::string>::const_iterator i = _headers.begin();
i != _userHeaders.end(); ++i) { i != _headers.end(); ++i) {
requestLine += (*i)+"\r\n"; requestLine += (*i)+"\r\n";
} }
@ -225,11 +225,11 @@ std::string HttpRequest::getProxyAuthString() const {
Base64::encode(AuthConfigFactorySingleton::instance()->createAuthConfigForHttpProxy(request)->getAuthText())+"\r\n"; Base64::encode(AuthConfigFactorySingleton::instance()->createAuthConfigForHttpProxy(request)->getAuthText())+"\r\n";
} }
void HttpRequest::setUserHeaders(const std::string& userHeadersString) void HttpRequest::addHeader(const std::string& headersString)
{ {
std::deque<std::string> headers; std::deque<std::string> headers;
Util::slice(headers, userHeadersString, '\n', true); Util::slice(headers, headersString, '\n', true);
_userHeaders = headers; _headers.insert(_headers.end(), headers.begin(), headers.end());
} }
void HttpRequest::configure(const Option* option) void HttpRequest::configure(const Option* option)

View File

@ -66,7 +66,7 @@ private:
std::string userAgent; std::string userAgent;
std::deque<std::string> _userHeaders; std::deque<std::string> _headers;
std::string getHostText(const std::string& host, uint16_t port) const; std::string getHostText(const std::string& host, uint16_t port) const;
@ -167,7 +167,8 @@ public:
this->userAgent = userAgent; this->userAgent = userAgent;
} }
void setUserHeaders(const std::string& userHeaders); // accepts multiline headers, deliminated by LF
void addHeader(const std::string& headers);
}; };
typedef SharedHandle<HttpRequest> HttpRequestHandle; typedef SharedHandle<HttpRequest> HttpRequestHandle;

View File

@ -44,6 +44,9 @@
#include "Option.h" #include "Option.h"
#include "Socket.h" #include "Socket.h"
#include "prefs.h" #include "prefs.h"
#include "a2functional.h"
#include "Util.h"
#include <numeric>
namespace aria2 { namespace aria2 {
@ -67,14 +70,24 @@ static SharedHandle<HttpRequest>
createHttpRequest(const SharedHandle<Request>& req, createHttpRequest(const SharedHandle<Request>& req,
const SharedHandle<Segment>& segment, const SharedHandle<Segment>& segment,
uint64_t totalLength, uint64_t totalLength,
const Option* option) const Option* option,
const std::deque<std::string>& acceptFeatures)
{ {
HttpRequestHandle httpRequest(new HttpRequest()); HttpRequestHandle httpRequest(new HttpRequest());
httpRequest->setUserAgent(option->get(PREF_USER_AGENT)); httpRequest->setUserAgent(option->get(PREF_USER_AGENT));
httpRequest->setRequest(req); httpRequest->setRequest(req);
httpRequest->setSegment(segment); httpRequest->setSegment(segment);
httpRequest->setEntityLength(totalLength); httpRequest->setEntityLength(totalLength);
httpRequest->setUserHeaders(option->get(PREF_HEADER)); httpRequest->addHeader(option->get(PREF_HEADER));
if(acceptFeatures.size()) {
std::string acceptFeaturesHeader = "Accept-Features: "+
Util::trim
(std::accumulate(acceptFeatures.begin()+1, acceptFeatures.end(),
*acceptFeatures.begin(),
Concat(",")),
",");
httpRequest->addHeader(acceptFeaturesHeader);
}
httpRequest->configure(option); httpRequest->configure(option);
return httpRequest; return httpRequest;
@ -89,7 +102,8 @@ bool HttpRequestCommand::executeInternal() {
if(_segments.empty()) { if(_segments.empty()) {
HttpRequestHandle httpRequest HttpRequestHandle httpRequest
(createHttpRequest(req, SharedHandle<Segment>(), (createHttpRequest(req, SharedHandle<Segment>(),
_requestGroup->getTotalLength(), e->option)); _requestGroup->getTotalLength(), e->option,
_requestGroup->getAcceptFeatures()));
_httpConnection->sendRequest(httpRequest); _httpConnection->sendRequest(httpRequest);
} else { } else {
for(Segments::iterator itr = _segments.begin(); itr != _segments.end(); ++itr) { for(Segments::iterator itr = _segments.begin(); itr != _segments.end(); ++itr) {
@ -97,7 +111,8 @@ bool HttpRequestCommand::executeInternal() {
if(!_httpConnection->isIssued(segment)) { if(!_httpConnection->isIssued(segment)) {
HttpRequestHandle httpRequest HttpRequestHandle httpRequest
(createHttpRequest(req, segment, (createHttpRequest(req, segment,
_requestGroup->getTotalLength(), e->option)); _requestGroup->getTotalLength(), e->option,
_requestGroup->getAcceptFeatures()));
_httpConnection->sendRequest(httpRequest); _httpConnection->sendRequest(httpRequest);
} }
} }

View File

@ -169,6 +169,9 @@ Metalink2RequestGroup::createRequestGroup(std::deque<SharedHandle<MetalinkEntry>
torrentRg->setDownloadContext(dctx); torrentRg->setDownloadContext(dctx);
torrentRg->clearPreDowloadHandler(); torrentRg->clearPreDowloadHandler();
torrentRg->clearPostDowloadHandler(); torrentRg->clearPostDowloadHandler();
// remove "metalink" from Accept-Feature list to avoid loop in tranparent
// metalink
torrentRg->removeAcceptFeatureHeader(RequestGroup::FEATURE_METALINK);
// make it in-memory download // make it in-memory download
SharedHandle<PreDownloadHandler> preh(new MemoryBufferPreDownloadHandler()); SharedHandle<PreDownloadHandler> preh(new MemoryBufferPreDownloadHandler());
{ {
@ -219,6 +222,9 @@ Metalink2RequestGroup::createRequestGroup(std::deque<SharedHandle<MetalinkEntry>
std::min(_option->getAsInt(PREF_METALINK_SERVERS), entry->maxConnections)); std::min(_option->getAsInt(PREF_METALINK_SERVERS), entry->maxConnections));
// In metalink, multi connection to a single host is not allowed by default. // In metalink, multi connection to a single host is not allowed by default.
rg->setSingleHostMultiConnectionEnabled(!_option->getAsBool(PREF_METALINK_ENABLE_UNIQUE_PROTOCOL)); rg->setSingleHostMultiConnectionEnabled(!_option->getAsBool(PREF_METALINK_ENABLE_UNIQUE_PROTOCOL));
// remove "metalink" from Accept-Feature list to avoid loop in tranparent
// metalink
rg->removeAcceptFeatureHeader(RequestGroup::FEATURE_METALINK);
#ifdef ENABLE_BITTORRENT #ifdef ENABLE_BITTORRENT
// Inject depenency between rg and torrentRg here if torrentRg.isNull() == false // Inject depenency between rg and torrentRg here if torrentRg.isNull() == false

View File

@ -103,6 +103,8 @@ namespace aria2 {
int32_t RequestGroup::_gidCounter = 0; int32_t RequestGroup::_gidCounter = 0;
const std::string RequestGroup::FEATURE_METALINK = "metalink";
RequestGroup::RequestGroup(const Option* option, RequestGroup::RequestGroup(const Option* option,
const std::deque<std::string>& uris): const std::deque<std::string>& uris):
_gid(++_gidCounter), _gid(++_gidCounter),
@ -124,6 +126,12 @@ RequestGroup::RequestGroup(const Option* option,
} else { } else {
_fileAllocationEnabled = false; _fileAllocationEnabled = false;
} }
// For now, only supported 'Accept-Features' is "metalink" used for
// transparent metalink.
// It would be good to put this value in Option so that user can tweak
// and add this list.
_acceptFeatures.push_back(FEATURE_METALINK);
initializePreDownloadHandler(); initializePreDownloadHandler();
initializePostDownloadHandler(); initializePostDownloadHandler();
} }
@ -933,4 +941,24 @@ void RequestGroup::reportDownloadFinished()
#endif // ENABLE_BITTORRENT #endif // ENABLE_BITTORRENT
} }
const std::deque<std::string>& RequestGroup::getAcceptFeatures() const
{
return _acceptFeatures;
}
void RequestGroup::addAcceptFeatureHeader(const std::string& feature)
{
if(std::find(_acceptFeatures.begin(), _acceptFeatures.end(), feature) == _acceptFeatures.end()) {
_acceptFeatures.push_back(feature);
}
}
void RequestGroup::removeAcceptFeatureHeader(const std::string& feature)
{
std::deque<std::string>::iterator i = std::find(_acceptFeatures.begin(), _acceptFeatures.end(), feature);
if(i != _acceptFeatures.end()) {
_acceptFeatures.erase(i);
}
}
} // namespace aria2 } // namespace aria2

View File

@ -108,6 +108,8 @@ private:
std::deque<SharedHandle<PostDownloadHandler> > _postDownloadHandlers; std::deque<SharedHandle<PostDownloadHandler> > _postDownloadHandlers;
std::deque<std::string> _acceptFeatures;
const Option* _option; const Option* _option;
const Logger* _logger; const Logger* _logger;
@ -334,6 +336,14 @@ public:
void removeURIWhoseHostnameIs(const std::string& hostname); void removeURIWhoseHostnameIs(const std::string& hostname);
void reportDownloadFinished(); void reportDownloadFinished();
const std::deque<std::string>& getAcceptFeatures() const;
void addAcceptFeatureHeader(const std::string& feature);
void removeAcceptFeatureHeader(const std::string& feature);
static const std::string FEATURE_METALINK;
}; };
typedef SharedHandle<RequestGroup> RequestGroupHandle; typedef SharedHandle<RequestGroup> RequestGroupHandle;

View File

@ -33,23 +33,12 @@
*/ */
/* copyright --> */ /* copyright --> */
#include "TaggedItem.h" #include "TaggedItem.h"
#include "a2functional.h"
#include <numeric> #include <numeric>
#include <algorithm> #include <algorithm>
namespace aria2 { namespace aria2 {
class Concat {
private:
std::string _delim;
public:
Concat(const std::string& delim = ""):_delim(delim) {}
std::string operator()(const std::string& s1, const std::string& s2) const
{
return s1+_delim+s2;
}
};
std::string TaggedItem::toTagString() const std::string TaggedItem::toTagString() const
{ {
if(_tags.size()) { if(_tags.size()) {

View File

@ -37,6 +37,7 @@
#include <functional> #include <functional>
#include "SharedHandle.h" #include "SharedHandle.h"
#include <string>
namespace aria2 { namespace aria2 {
@ -138,6 +139,18 @@ public:
} }
}; };
class Concat {
private:
std::string _delim;
public:
Concat(const std::string& delim = ""):_delim(delim) {}
std::string operator()(const std::string& s1, const std::string& s2) const
{
return s1+_delim+s2;
}
};
} // namespace aria2 } // namespace aria2
#endif // _D_A2_FUNCTIONAL_H_ #endif // _D_A2_FUNCTIONAL_H_

View File

@ -22,7 +22,7 @@ class HttpRequestTest : public CppUnit::TestFixture {
CPPUNIT_TEST(testCreateProxyRequest); CPPUNIT_TEST(testCreateProxyRequest);
CPPUNIT_TEST(testIsRangeSatisfied); CPPUNIT_TEST(testIsRangeSatisfied);
CPPUNIT_TEST(testUserAgent); CPPUNIT_TEST(testUserAgent);
CPPUNIT_TEST(testUserHeaders); CPPUNIT_TEST(testAddHeader);
CPPUNIT_TEST_SUITE_END(); CPPUNIT_TEST_SUITE_END();
private: private:
@ -37,7 +37,7 @@ public:
void testCreateProxyRequest(); void testCreateProxyRequest();
void testIsRangeSatisfied(); void testIsRangeSatisfied();
void testUserAgent(); void testUserAgent();
void testUserHeaders(); void testAddHeader();
}; };
@ -596,14 +596,14 @@ void HttpRequestTest::testUserAgent()
CPPUNIT_ASSERT_EQUAL(expectedTextForProxy, httpRequest.createProxyRequest()); CPPUNIT_ASSERT_EQUAL(expectedTextForProxy, httpRequest.createProxyRequest());
} }
void HttpRequestTest::testUserHeaders() void HttpRequestTest::testAddHeader()
{ {
SharedHandle<Request> request(new Request()); SharedHandle<Request> request(new Request());
request->setUrl("http://localhost/archives/aria2-1.0.0.tar.bz2"); request->setUrl("http://localhost/archives/aria2-1.0.0.tar.bz2");
HttpRequest httpRequest; HttpRequest httpRequest;
httpRequest.setRequest(request); httpRequest.setRequest(request);
httpRequest.setUserHeaders("X-ARIA2: v0.13\nX-ARIA2-DISTRIBUTE: enabled\n"); httpRequest.addHeader("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" std::string expectedText = "GET /archives/aria2-1.0.0.tar.bz2 HTTP/1.1\r\n"
"User-Agent: aria2\r\n" "User-Agent: aria2\r\n"