Accept HTTP 304 reply as success when If-None-Match request-header

field is specified using --header option.

When --conditional-get is used, --allow-overwrite is now required to
overwrite existing file.
pull/1/head
Tatsuhiro Tsujikawa 2011-01-29 23:19:10 +09:00
parent 7a6ec762ef
commit 1b9329c67c
5 changed files with 62 additions and 21 deletions

View File

@ -322,6 +322,11 @@ void HttpRequest::addHeader(const std::string& headersString)
headers_.insert(headers_.end(), headers.begin(), headers.end()); headers_.insert(headers_.end(), headers.begin(), headers.end());
} }
void HttpRequest::clearHeader()
{
headers_.clear();
}
void HttpRequest::addAcceptType(const std::string& type) void HttpRequest::addAcceptType(const std::string& type)
{ {
acceptTypes_.push_back(type); acceptTypes_.push_back(type);
@ -431,4 +436,20 @@ void HttpRequest::setIfModifiedSinceHeader(const std::string& hd)
ifModSinceHeader_ = hd; ifModSinceHeader_ = hd;
} }
bool HttpRequest::conditionalRequest() const
{
if(!ifModSinceHeader_.empty()) {
return true;
}
for(std::vector<std::string>::const_iterator i = headers_.begin(),
eoi = headers_.end(); i != eoi; ++i) {
std::string hd = util::toLower(*i);
if(util::startsWith(hd, "if-modified-since") ||
util::startsWith(hd, "if-none-match")) {
return true;
}
}
return false;
}
} // namespace aria2 } // namespace aria2

View File

@ -168,6 +168,8 @@ public:
// accepts multiline headers, delimited by LF // accepts multiline headers, delimited by LF
void addHeader(const std::string& headers); void addHeader(const std::string& headers);
void clearHeader();
void addAcceptType(const std::string& type); void addAcceptType(const std::string& type);
template<typename InputIterator> template<typename InputIterator>
@ -249,6 +251,11 @@ public:
{ {
return ifModSinceHeader_; return ifModSinceHeader_;
} }
// Returns true if request is conditional:more specifically, the
// request is considered to be conditional if the client sent
// "If-Modified-Since" or "If-None-Match" request-header field.
bool conditionalRequest() const;
}; };
} // namespace aria2 } // namespace aria2

View File

@ -70,8 +70,8 @@ void HttpResponse::validateResponse() const
return; return;
} }
if(statusCode == 304) { if(statusCode == 304) {
if(httpRequest_->getIfModifiedSinceHeader().empty()) { if(!httpRequest_->conditionalRequest()) {
throw DL_ABORT_EX2("Got 304 without If-Modified-Since", throw DL_ABORT_EX2("Got 304 without If-Modified-Since or If-None-Match",
error_code::HTTP_PROTOCOL_ERROR); error_code::HTTP_PROTOCOL_ERROR);
} }
} else if(statusCode == 301 || } else if(statusCode == 301 ||

View File

@ -174,26 +174,22 @@ bool HttpResponseCommand::executeInternal()
} }
int statusCode = httpResponse->getStatusCode(); int statusCode = httpResponse->getStatusCode();
if(!httpResponse->getHttpRequest()->getIfModifiedSinceHeader().empty()) {
if(statusCode == 304) { if(statusCode == 304) {
uint64_t totalLength = httpResponse->getEntityLength(); uint64_t totalLength = httpResponse->getEntityLength();
getFileEntry()->setLength(totalLength); getFileEntry()->setLength(totalLength);
getRequestGroup()->initPieceStorage(); getRequestGroup()->initPieceStorage();
getPieceStorage()->markAllPiecesDone(); getPieceStorage()->markAllPiecesDone();
// Just set checksum verification done. // Just set checksum verification done.
getDownloadContext()->setChecksumVerified(true); getDownloadContext()->setChecksumVerified(true);
A2_LOG_NOTICE(fmt(MSG_DOWNLOAD_ALREADY_COMPLETED, A2_LOG_NOTICE(fmt(MSG_DOWNLOAD_ALREADY_COMPLETED,
util::itos(getRequestGroup()->getGID()).c_str(), util::itos(getRequestGroup()->getGID()).c_str(),
getRequestGroup()->getFirstFilePath().c_str())); getRequestGroup()->getFirstFilePath().c_str()));
poolConnection(); poolConnection();
getFileEntry()->poolRequest(getRequest()); getFileEntry()->poolRequest(getRequest());
return true; return true;
} else if(statusCode == 200 || statusCode == 206) {
// Remote file is newer than local file. We allow overwrite.
getOption()->put(PREF_ALLOW_OVERWRITE, A2_V_TRUE);
}
} }
if(statusCode != 304 && statusCode >= 300) { if(statusCode >= 300) {
if(statusCode == 404) { if(statusCode == 404) {
getRequestGroup()->increaseAndValidateFileNotFoundCount(); getRequestGroup()->increaseAndValidateFileNotFoundCount();
} }

View File

@ -37,6 +37,7 @@ class HttpRequestTest : public CppUnit::TestFixture {
CPPUNIT_TEST(testAddHeader); CPPUNIT_TEST(testAddHeader);
CPPUNIT_TEST(testAddAcceptType); CPPUNIT_TEST(testAddAcceptType);
CPPUNIT_TEST(testEnableAcceptEncoding); CPPUNIT_TEST(testEnableAcceptEncoding);
CPPUNIT_TEST(testConditionalRequest);
CPPUNIT_TEST_SUITE_END(); CPPUNIT_TEST_SUITE_END();
private: private:
SharedHandle<Option> option_; SharedHandle<Option> option_;
@ -64,6 +65,7 @@ public:
void testAddHeader(); void testAddHeader();
void testAddAcceptType(); void testAddAcceptType();
void testEnableAcceptEncoding(); void testEnableAcceptEncoding();
void testConditionalRequest();
}; };
@ -843,4 +845,19 @@ void HttpRequestTest::testCreateRequest_ipv6LiteralAddr()
CPPUNIT_ASSERT(proxyRequest.find("CONNECT [::1]:80 ") != std::string::npos); CPPUNIT_ASSERT(proxyRequest.find("CONNECT [::1]:80 ") != std::string::npos);
} }
void HttpRequestTest::testConditionalRequest()
{
HttpRequest httpRequest;
CPPUNIT_ASSERT(!httpRequest.conditionalRequest());
httpRequest.setIfModifiedSinceHeader("dummy");
CPPUNIT_ASSERT(httpRequest.conditionalRequest());
httpRequest.setIfModifiedSinceHeader("");
CPPUNIT_ASSERT(!httpRequest.conditionalRequest());
httpRequest.addHeader("If-None-Match: *");
CPPUNIT_ASSERT(httpRequest.conditionalRequest());
httpRequest.clearHeader();
httpRequest.addHeader("If-Modified-Since: dummy");
CPPUNIT_ASSERT(httpRequest.conditionalRequest());
}
} // namespace aria2 } // namespace aria2