diff --git a/src/HttpRequest.cc b/src/HttpRequest.cc index 6f9b155f..2c0839cd 100644 --- a/src/HttpRequest.cc +++ b/src/HttpRequest.cc @@ -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::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 diff --git a/src/HttpRequest.h b/src/HttpRequest.h index f9a08b17..11d6642b 100644 --- a/src/HttpRequest.h +++ b/src/HttpRequest.h @@ -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 @@ -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 diff --git a/src/HttpResponse.cc b/src/HttpResponse.cc index 8ec7d257..61f8e878 100644 --- a/src/HttpResponse.cc +++ b/src/HttpResponse.cc @@ -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 || diff --git a/src/HttpResponseCommand.cc b/src/HttpResponseCommand.cc index bb03659d..aa7afd42 100644 --- a/src/HttpResponseCommand.cc +++ b/src/HttpResponseCommand.cc @@ -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(); } diff --git a/test/HttpRequestTest.cc b/test/HttpRequestTest.cc index 00251a1b..590072de 100644 --- a/test/HttpRequestTest.cc +++ b/test/HttpRequestTest.cc @@ -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