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());
}
void HttpRequest::clearHeader()
{
headers_.clear();
}
void HttpRequest::addAcceptType(const std::string& type)
{
acceptTypes_.push_back(type);
@ -431,4 +436,20 @@ void HttpRequest::setIfModifiedSinceHeader(const std::string& 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

View File

@ -168,6 +168,8 @@ public:
// accepts multiline headers, delimited by LF
void addHeader(const std::string& headers);
void clearHeader();
void addAcceptType(const std::string& type);
template<typename InputIterator>
@ -249,6 +251,11 @@ public:
{
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

View File

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

View File

@ -174,26 +174,22 @@ bool HttpResponseCommand::executeInternal()
}
int statusCode = httpResponse->getStatusCode();
if(!httpResponse->getHttpRequest()->getIfModifiedSinceHeader().empty()) {
if(statusCode == 304) {
uint64_t totalLength = httpResponse->getEntityLength();
getFileEntry()->setLength(totalLength);
getRequestGroup()->initPieceStorage();
getPieceStorage()->markAllPiecesDone();
// Just set checksum verification done.
getDownloadContext()->setChecksumVerified(true);
A2_LOG_NOTICE(fmt(MSG_DOWNLOAD_ALREADY_COMPLETED,
util::itos(getRequestGroup()->getGID()).c_str(),
getRequestGroup()->getFirstFilePath().c_str()));
poolConnection();
getFileEntry()->poolRequest(getRequest());
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) {
uint64_t totalLength = httpResponse->getEntityLength();
getFileEntry()->setLength(totalLength);
getRequestGroup()->initPieceStorage();
getPieceStorage()->markAllPiecesDone();
// Just set checksum verification done.
getDownloadContext()->setChecksumVerified(true);
A2_LOG_NOTICE(fmt(MSG_DOWNLOAD_ALREADY_COMPLETED,
util::itos(getRequestGroup()->getGID()).c_str(),
getRequestGroup()->getFirstFilePath().c_str()));
poolConnection();
getFileEntry()->poolRequest(getRequest());
return true;
}
if(statusCode != 304 && statusCode >= 300) {
if(statusCode >= 300) {
if(statusCode == 404) {
getRequestGroup()->increaseAndValidateFileNotFoundCount();
}

View File

@ -37,6 +37,7 @@ class HttpRequestTest : public CppUnit::TestFixture {
CPPUNIT_TEST(testAddHeader);
CPPUNIT_TEST(testAddAcceptType);
CPPUNIT_TEST(testEnableAcceptEncoding);
CPPUNIT_TEST(testConditionalRequest);
CPPUNIT_TEST_SUITE_END();
private:
SharedHandle<Option> option_;
@ -64,6 +65,7 @@ public:
void testAddHeader();
void testAddAcceptType();
void testEnableAcceptEncoding();
void testConditionalRequest();
};
@ -843,4 +845,19 @@ void HttpRequestTest::testCreateRequest_ipv6LiteralAddr()
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