Parcourir la source

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.

Tatsuhiro Tsujikawa il y a 14 ans
Parent
commit
1b9329c67c
5 fichiers modifiés avec 62 ajouts et 21 suppressions
  1. 21 0
      src/HttpRequest.cc
  2. 7 0
      src/HttpRequest.h
  3. 2 2
      src/HttpResponse.cc
  4. 15 19
      src/HttpResponseCommand.cc
  5. 17 0
      test/HttpRequestTest.cc

+ 21 - 0
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<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

+ 7 - 0
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<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

+ 2 - 2
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 ||

+ 15 - 19
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();
     }

+ 17 - 0
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<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