2008-07-19 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>

Supported absolute/relative path in Location header field.
	* src/AbstractCommand.cc: Call resetUrl() when DlRetryEx is 
caught.
	* src/HttpHeader.cc
	* src/HttpHeader.h
	* src/HttpResponse.cc
	* src/HttpSkipResponseCommand.cc
	* src/Request.cc
	* test/HttpHeaderTest.cc
	* test/HttpResponseTest.cc
	* test/RequestTest.cc
This commit is contained in:
Tatsuhiro Tsujikawa 2008-07-18 15:20:52 +00:00
parent 5122ae031d
commit 5d2651c5ed
10 changed files with 114 additions and 6 deletions

View File

@ -1,3 +1,16 @@
2008-07-19 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
Supported absolute/relative path in Location header field.
* src/AbstractCommand.cc: Call resetUrl() when DlRetryEx is caught.
* src/HttpHeader.cc
* src/HttpHeader.h
* src/HttpResponse.cc
* src/HttpSkipResponseCommand.cc
* src/Request.cc
* test/HttpHeaderTest.cc
* test/HttpResponseTest.cc
* test/RequestTest.cc
2008-07-16 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
Changed help text for --load-cookie option.

View File

@ -156,6 +156,8 @@ bool AbstractCommand::execute() {
if(isAbort) {
onAbort();
}
// In case where Request::getCurrentUrl() is not a valid URI.
req->resetUrl();
if(isAbort) {
logger->info(MSG_MAX_TRY, cuid, req->getTryCount());
logger->error(MSG_DOWNLOAD_ABORTED, err, cuid, req->getUrl().c_str());

View File

@ -205,4 +205,9 @@ void HttpHeader::fill(std::istream& in)
}
}
void HttpHeader::clearField()
{
table.clear();
}
} // namespace aria2

View File

@ -79,6 +79,9 @@ public:
void fill(std::istream& in);
// Clears table. _responseStatus and _version are unchanged.
void clearField();
static const std::string LOCATION;
static const std::string TRANSFER_ENCODING;

View File

@ -44,6 +44,7 @@
#include "Util.h"
#include "message.h"
#include "DlAbortEx.h"
#include "DlRetryEx.h"
#include "StringFormat.h"
#include "A2STR.h"
#include "Decoder.h"
@ -123,8 +124,16 @@ bool HttpResponse::isRedirect() const
void HttpResponse::processRedirect()
{
httpRequest->getRequest()->redirectUrl(getRedirectURI());
if(httpRequest->getRequest()->redirectUrl(getRedirectURI())) {
logger->info(MSG_REDIRECT, cuid,
httpRequest->getRequest()->getCurrentUrl().c_str());
} else {
throw DlRetryEx
(StringFormat("CUID#%d - Redirect to %s failed. It may not be a valid"
" URI.", cuid,
httpRequest->getRequest()->getCurrentUrl().c_str()).str());
}
}
std::string HttpResponse::getRedirectURI() const

View File

@ -134,7 +134,6 @@ bool HttpSkipResponseCommand::processResponse()
throw DlAbortEx(StringFormat("Too many redirects: count=%u", rnum).str());
}
_httpResponse->processRedirect();
logger->info(MSG_REDIRECT, cuid, _httpResponse->getRedirectURI().c_str());
return prepareForRetry(0);
} else if(_httpResponse->hasRetryAfter()) {
return prepareForRetry(_httpResponse->getRetryAfter());

View File

@ -80,7 +80,19 @@ bool Request::redirectUrl(const std::string& url) {
previousUrl = A2STR::NIL;
_supportsPersistentConnection = true;
++_redirectCount;
return parseUrl(url);
if(url.find("://") == std::string::npos) {
// rfc2616 requires absolute URI should be provided by Location header
// field, but some servers don't obey this rule.
if(Util::startsWith(url, "/")) {
// abosulute path
return parseUrl(protocol+"://"+host+url);
} else {
// relative path
return parseUrl(protocol+"://"+host+dir+"/"+url);
}
} else {
return parseUrl(url);
}
}
bool Request::parseUrl(const std::string& url) {

View File

@ -9,11 +9,13 @@ class HttpHeaderTest:public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(HttpHeaderTest);
CPPUNIT_TEST(testGetRange);
CPPUNIT_TEST(testGet);
CPPUNIT_TEST(testClearField);
CPPUNIT_TEST_SUITE_END();
public:
void testGetRange();
void testGet();
void testClearField();
};
@ -58,4 +60,20 @@ void HttpHeaderTest::testGet()
CPPUNIT_ASSERT_EQUAL(std::string("101"), r[1]);
}
void HttpHeaderTest::testClearField()
{
HttpHeader h;
h.setResponseStatus(HttpHeader::S200);
h.setVersion(HttpHeader::HTTP_1_1);
h.put("Foo", "Bar");
CPPUNIT_ASSERT_EQUAL(std::string("Bar"), h.getFirst("Foo"));
h.clearField();
CPPUNIT_ASSERT_EQUAL(std::string(""), h.getFirst("Foo"));
CPPUNIT_ASSERT_EQUAL(HttpHeader::S200, h.getResponseStatus());
CPPUNIT_ASSERT_EQUAL(HttpHeader::HTTP_1_1, h.getVersion());
}
} // namespace aria2

View File

@ -8,6 +8,7 @@
#include "Exception.h"
#include "A2STR.h"
#include "Decoder.h"
#include "DlRetryEx.h"
#include <iostream>
#include <cppunit/extensions/HelperMacros.h>
@ -38,6 +39,7 @@ class HttpResponseTest : public CppUnit::TestFixture {
CPPUNIT_TEST(testValidateResponse_bad_range);
CPPUNIT_TEST(testValidateResponse_chunked);
CPPUNIT_TEST(testHasRetryAfter);
CPPUNIT_TEST(testProcessRedirect);
CPPUNIT_TEST_SUITE_END();
private:
@ -66,6 +68,7 @@ public:
void testValidateResponse_bad_range();
void testValidateResponse_chunked();
void testHasRetryAfter();
void testProcessRedirect();
};
@ -422,4 +425,33 @@ void HttpResponseTest::testHasRetryAfter()
CPPUNIT_ASSERT_EQUAL((time_t)60, httpResponse.getRetryAfter());
}
void HttpResponseTest::testProcessRedirect()
{
HttpResponse httpResponse;
SharedHandle<HttpHeader> httpHeader(new HttpHeader());
httpResponse.setHttpHeader(httpHeader);
SharedHandle<HttpRequest> httpRequest(new HttpRequest());
SharedHandle<Request> request(new Request());
request->setUrl("http://localhost/archives/aria2-1.0.0.tar.bz2");
httpRequest->setRequest(request);
httpResponse.setHttpRequest(httpRequest);
httpHeader->put("Location", "http://mirror/aria2-1.0.0.tar.bz2");
httpResponse.processRedirect();
httpHeader->clearField();
// Give unsupported scheme
httpHeader->put("Location", "unsupported://mirror/aria2-1.0.0.tar.bz2");
try {
httpResponse.processRedirect();
CPPUNIT_FAIL("DlRetryEx exception must be thrown.");
} catch(DlRetryEx& e) {
// Success
} catch(...) {
CPPUNIT_FAIL("DlRetryEx exception must be thrown.");
}
}
} // namespace aria2

View File

@ -279,10 +279,12 @@ void RequestTest::testRedirectUrl() {
// persistent connection flag is set to be true after redirection
CPPUNIT_ASSERT(req.supportsPersistentConnection());
// url must be the same
CPPUNIT_ASSERT_EQUAL(std::string("http://aria.rednoah.com:8080/aria2/index.html"),
CPPUNIT_ASSERT_EQUAL(std::string("http://aria.rednoah.com:8080/aria2/"
"index.html"),
req.getUrl());
// currentUrl must be updated
CPPUNIT_ASSERT_EQUAL(std::string("http://aria.rednoah.co.jp/"), req.getCurrentUrl());
CPPUNIT_ASSERT_EQUAL(std::string("http://aria.rednoah.co.jp/"),
req.getCurrentUrl());
// previousUrl must be "" when redirection
CPPUNIT_ASSERT_EQUAL(std::string(""), req.getPreviousUrl());
CPPUNIT_ASSERT_EQUAL(std::string("http"), req.getProtocol());
@ -293,6 +295,19 @@ void RequestTest::testRedirectUrl() {
CPPUNIT_ASSERT_EQUAL(std::string(""), req.getQuery());
// See redirect count is incremented.
CPPUNIT_ASSERT_EQUAL((unsigned int)1, req.getRedirectCount());
// Give abosulute path
CPPUNIT_ASSERT(req.redirectUrl("/abspath/to/file"));
CPPUNIT_ASSERT_EQUAL(std::string("http://aria.rednoah.co.jp/abspath/to/file"),
req.getCurrentUrl());
CPPUNIT_ASSERT_EQUAL((unsigned int)2, req.getRedirectCount());
// Give relative path
CPPUNIT_ASSERT(req.redirectUrl("relativepath/to/file"));
CPPUNIT_ASSERT_EQUAL(std::string("http://aria.rednoah.co.jp/abspath/to/"
"relativepath/to/file"),
req.getCurrentUrl());
CPPUNIT_ASSERT_EQUAL((unsigned int)3, req.getRedirectCount());
}
void RequestTest::testRedirectUrl2() {