ソースを参照

detect Releasefile IMS hits even if the server doesn't

Not all servers we are talking to support If-Modified-Since and some are
not even sending Last-Modified for us, so in an effort to detect such
hits we run a hashsum check on the 'old' compared to the 'new' file, we
got the hashes for the 'new' already for "free" from the methods anyway
and hence just need to calculated the old ones.

This allows us to detect hits even with unsupported servers, which in
turn means we benefit from all the new hit behavior also here.
David Kalnischkies 11 年 前
コミット
8eafc75954

+ 23 - 8
apt-pkg/acquire-item.cc

@@ -253,7 +253,10 @@ bool pkgAcquire::Item::Rename(string From,string To)
    strprintf(S, _("rename failed, %s (%s -> %s)."), strerror(errno),
    strprintf(S, _("rename failed, %s (%s -> %s)."), strerror(errno),
 	 From.c_str(),To.c_str());
 	 From.c_str(),To.c_str());
    Status = StatError;
    Status = StatError;
-   ErrorText += S;
+   if (ErrorText.empty())
+      ErrorText = S;
+   else
+      ErrorText = ErrorText + ": " + S;
    return false;
    return false;
 }
 }
 									/*}}}*/
 									/*}}}*/
@@ -1794,7 +1797,7 @@ void pkgAcqMetaSig::Done(string Message,unsigned long long Size,
 
 
    if(AuthPass == false)
    if(AuthPass == false)
    {
    {
-      if(CheckDownloadDone(Message) == true)
+      if(CheckDownloadDone(Message, Hashes) == true)
       {
       {
          // destfile will be modified to point to MetaIndexFile for the
          // destfile will be modified to point to MetaIndexFile for the
          // gpgv method, so we need to save it here
          // gpgv method, so we need to save it here
@@ -1837,7 +1840,8 @@ void pkgAcqMetaSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf)/*{{{*/
          Status = StatDone;
          Status = StatDone;
       } else {
       } else {
          _error->Error("%s", downgrade_msg.c_str());
          _error->Error("%s", downgrade_msg.c_str());
-         Rename(MetaIndexFile, MetaIndexFile+".FAILED");
+	 if (TransactionManager->IMSHit == false)
+	    Rename(MetaIndexFile, MetaIndexFile+".FAILED");
 	 Item::Failed("Message: " + downgrade_msg, Cnf);
 	 Item::Failed("Message: " + downgrade_msg, Cnf);
          TransactionManager->AbortTransaction();
          TransactionManager->AbortTransaction();
          return;
          return;
@@ -1922,12 +1926,12 @@ void pkgAcqMetaIndex::Done(string Message,unsigned long long Size,	/*{{{*/
 {
 {
    Item::Done(Message,Size,Hashes,Cfg);
    Item::Done(Message,Size,Hashes,Cfg);
 
 
-   if(CheckDownloadDone(Message))
+   if(CheckDownloadDone(Message, Hashes))
    {
    {
       // we have a Release file, now download the Signature, all further
       // we have a Release file, now download the Signature, all further
       // verify/queue for additional downloads will be done in the
       // verify/queue for additional downloads will be done in the
       // pkgAcqMetaSig::Done() code
       // pkgAcqMetaSig::Done() code
-      std::string MetaIndexFile = DestFile;
+      std::string const MetaIndexFile = DestFile;
       new pkgAcqMetaSig(Owner, TransactionManager, 
       new pkgAcqMetaSig(Owner, TransactionManager, 
                         MetaIndexSigURI, MetaIndexSigURIDesc,
                         MetaIndexSigURI, MetaIndexSigURIDesc,
                         MetaIndexSigShortDesc, MetaIndexFile, IndexTargets, 
                         MetaIndexSigShortDesc, MetaIndexFile, IndexTargets, 
@@ -2008,7 +2012,7 @@ void pkgAcqMetaBase::QueueForSignatureVerify(const std::string &MetaIndexFile,
 }
 }
 									/*}}}*/
 									/*}}}*/
 // pkgAcqMetaBase::CheckDownloadDone					/*{{{*/
 // pkgAcqMetaBase::CheckDownloadDone					/*{{{*/
-bool pkgAcqMetaBase::CheckDownloadDone(const std::string &Message)
+bool pkgAcqMetaBase::CheckDownloadDone(const std::string &Message, HashStringList const &Hashes)
 {
 {
    // We have just finished downloading a Release file (it is not
    // We have just finished downloading a Release file (it is not
    // verified yet)
    // verified yet)
@@ -2031,7 +2035,18 @@ bool pkgAcqMetaBase::CheckDownloadDone(const std::string &Message)
 
 
    // make sure to verify against the right file on I-M-S hit
    // make sure to verify against the right file on I-M-S hit
    IMSHit = StringToBool(LookupTag(Message,"IMS-Hit"),false);
    IMSHit = StringToBool(LookupTag(Message,"IMS-Hit"),false);
-   if(IMSHit)
+   if (IMSHit == false)
+   {
+      // detect IMS-Hits servers haven't detected by Hash comparison
+      std::string FinalFile = GetFinalFilename();
+      if (RealFileExists(FinalFile) && Hashes.VerifyFile(FinalFile) == true)
+      {
+	 IMSHit = true;
+	 unlink(DestFile.c_str());
+      }
+   }
+
+   if(IMSHit == true)
    {
    {
       // for simplicity, the transaction manager is always InRelease
       // for simplicity, the transaction manager is always InRelease
       // even if it doesn't exist.
       // even if it doesn't exist.
@@ -2273,7 +2288,7 @@ void pkgAcqMetaClearSig::Done(std::string Message,unsigned long long Size,
 
 
    if(AuthPass == false)
    if(AuthPass == false)
    {
    {
-      if(CheckDownloadDone(Message) == true)
+      if(CheckDownloadDone(Message, Hashes) == true)
          QueueForSignatureVerify(DestFile, DestFile);
          QueueForSignatureVerify(DestFile, DestFile);
       return;
       return;
    }
    }

+ 1 - 1
apt-pkg/acquire-item.h

@@ -429,7 +429,7 @@ class pkgAcqMetaBase  : public pkgAcquire::Item				/*{{{*/
     *  \param Message The message block received from the fetch
     *  \param Message The message block received from the fetch
     *  subprocess.
     *  subprocess.
     */
     */
-   bool CheckDownloadDone(const std::string &Message);
+   bool CheckDownloadDone(const std::string &Message, HashStringList const &Hashes);
 
 
    /** \brief Queue the downloaded Signature for verification */
    /** \brief Queue the downloaded Signature for verification */
    void QueueForSignatureVerify(const std::string &MetaIndexFile,
    void QueueForSignatureVerify(const std::string &MetaIndexFile,

+ 4 - 4
apt-pkg/acquire-worker.cc

@@ -333,13 +333,12 @@ bool pkgAcquire::Worker::RunMessages()
 
 
 	    // see if there is a hash to verify
 	    // see if there is a hash to verify
 	    HashStringList ReceivedHashes;
 	    HashStringList ReceivedHashes;
-	    HashStringList expectedHashes = Owner->HashSums();
-	    for (HashStringList::const_iterator hs = expectedHashes.begin(); hs != expectedHashes.end(); ++hs)
+	    for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
 	    {
 	    {
-	       std::string const tagname = hs->HashType() + "-Hash";
+	       std::string const tagname = std::string(*type) + "-Hash";
 	       std::string const hashsum = LookupTag(Message, tagname.c_str());
 	       std::string const hashsum = LookupTag(Message, tagname.c_str());
 	       if (hashsum.empty() == false)
 	       if (hashsum.empty() == false)
-		  ReceivedHashes.push_back(HashString(hs->HashType(), hashsum));
+		  ReceivedHashes.push_back(HashString(*type, hashsum));
 	    }
 	    }
 
 
 	    if(_config->FindB("Debug::pkgAcquire::Auth", false) == true)
 	    if(_config->FindB("Debug::pkgAcquire::Auth", false) == true)
@@ -349,6 +348,7 @@ bool pkgAcquire::Worker::RunMessages()
 	       for (HashStringList::const_iterator hs = ReceivedHashes.begin(); hs != ReceivedHashes.end(); ++hs)
 	       for (HashStringList::const_iterator hs = ReceivedHashes.begin(); hs != ReceivedHashes.end(); ++hs)
 		  std::clog <<  "\t- " << hs->toStr() << std::endl;
 		  std::clog <<  "\t- " << hs->toStr() << std::endl;
 	       std::clog << "ExpectedHash:" << endl;
 	       std::clog << "ExpectedHash:" << endl;
+	       HashStringList expectedHashes = Owner->HashSums();
 	       for (HashStringList::const_iterator hs = expectedHashes.begin(); hs != expectedHashes.end(); ++hs)
 	       for (HashStringList::const_iterator hs = expectedHashes.begin(); hs != expectedHashes.end(); ++hs)
 		  std::clog <<  "\t- " << hs->toStr() << std::endl;
 		  std::clog <<  "\t- " << hs->toStr() << std::endl;
 	       std::clog << endl;
 	       std::clog << endl;

+ 1 - 1
methods/https.cc

@@ -444,7 +444,7 @@ bool HttpsMethod::Fetch(FetchItem *Itm)
       char err[255];
       char err[255];
       snprintf(err, sizeof(err) - 1, "HttpError%i", Server->Result);
       snprintf(err, sizeof(err) - 1, "HttpError%i", Server->Result);
       SetFailReason(err);
       SetFailReason(err);
-      _error->Error("%s", err);
+      _error->Error("%i %s", Server->Result, Server->Code);
       // unlink, no need keep 401/404 page content in partial/
       // unlink, no need keep 401/404 page content in partial/
       unlink(File->Name().c_str());
       unlink(File->Name().c_str());
       return false;
       return false;

+ 9 - 0
test/integration/framework

@@ -1005,6 +1005,15 @@ signreleasefiles() {
 	msgdone "info"
 	msgdone "info"
 }
 }
 
 
+redatereleasefiles() {
+	local DATE="$(date -d "$1" '+%a, %d %b %Y %H:%M:%S %Z')"
+	for release in $(find aptarchive/ -name 'Release'); do
+		sed -i "s/^Date: .*$/Date: ${DATE}/" $release
+		touch -d "$DATE" $release
+	done
+	signreleasefiles "${2:-Joe Sixpack}"
+}
+
 webserverconfig() {
 webserverconfig() {
 	local WEBSERVER="${3:-http://localhost:8080}"
 	local WEBSERVER="${3:-http://localhost:8080}"
 	local NOCHECK=false
 	local NOCHECK=false

+ 1 - 0
test/integration/test-apt-update-expected-size

@@ -26,6 +26,7 @@ test_inreleasetoobig() {
 }
 }
 
 
 test_packagestoobig() {
 test_packagestoobig() {
+	redatereleasefiles '+1hour'
 	# append junk at the end of the Packages.gz/Packages
 	# append junk at the end of the Packages.gz/Packages
 	SIZE="$(stat --printf=%s aptarchive/dists/unstable/main/binary-i386/Packages)"
 	SIZE="$(stat --printf=%s aptarchive/dists/unstable/main/binary-i386/Packages)"
 	find aptarchive/dists -name 'Packages*' | while read pkg; do
 	find aptarchive/dists -name 'Packages*' | while read pkg; do

+ 57 - 1
test/integration/test-apt-update-not-modified

@@ -12,7 +12,7 @@ insertpackage 'unstable' 'apt' 'all' '1.0'
 setupaptarchive --no-update
 setupaptarchive --no-update
 
 
 methodtest() {
 methodtest() {
-	msgmsg 'Test with' "$1"
+	msgmsg 'Test InRelease with' "$1"
 	rm -rf rootdir/var/lib/apt/lists
 	rm -rf rootdir/var/lib/apt/lists
 	# get our cache populated
 	# get our cache populated
 	testsuccess aptget update
 	testsuccess aptget update
@@ -36,6 +36,62 @@ Reading package lists..." aptget update
 Get:1 $1 unstable/main amd64 Packages [$(stat -c '%s' 'aptarchive/dists/unstable/main/binary-amd64/Packages.gz') B]
 Get:1 $1 unstable/main amd64 Packages [$(stat -c '%s' 'aptarchive/dists/unstable/main/binary-amd64/Packages.gz') B]
 Reading package lists..." aptget update
 Reading package lists..." aptget update
 	testfileequal 'listsdir.lst' "$(listcurrentlistsdirectory)"
 	testfileequal 'listsdir.lst' "$(listcurrentlistsdirectory)"
+
+	webserverconfig 'aptwebserver::support::modified-since' 'false'
+	webserverconfig 'aptwebserver::support::last-modified' 'false'
+	testsuccessequal "Get:1 $1 unstable InRelease [$(stat -c '%s' 'aptarchive/dists/unstable/InRelease') B]
+Reading package lists..." aptget update
+	webserverconfig 'aptwebserver::support::modified-since' 'true'
+	webserverconfig 'aptwebserver::support::last-modified' 'true'
+
+	msgmsg 'Test Release.gpg with' "$1"
+	rm -rf rootdir/var/lib/apt/lists
+	cp -a aptarchive/dists  aptarchive/dists.good
+	find aptarchive/dists -name 'InRelease' -delete
+	# get our cache populated
+	testsuccess aptget update
+	listcurrentlistsdirectory > listsdir.lst
+
+	# hit again with a good cache
+	testsuccessequal "Ign $1 unstable InRelease
+  404  Not Found
+Hit $1 unstable Release
+Hit $1 unstable Release.gpg
+Reading package lists..." aptget update
+	testfileequal 'listsdir.lst' "$(listcurrentlistsdirectory)"
+
+	# drop an architecture, which means the file should be gone now
+	configarchitecture 'i386'
+	sed '/_binary-amd64_Packages/ d' listsdir.lst > listsdir-without-amd64.lst
+	testsuccessequal "Ign $1 unstable InRelease
+  404  Not Found
+Hit $1 unstable Release
+Hit $1 unstable Release.gpg
+Reading package lists..." aptget update
+	testfileequal 'listsdir-without-amd64.lst' "$(listcurrentlistsdirectory)"
+
+	# readd arch so its downloaded again
+	configarchitecture 'amd64' 'i386'
+	testsuccessequal "Ign $1 unstable InRelease
+  404  Not Found
+Hit $1 unstable Release
+Hit $1 unstable Release.gpg
+Get:1 $1 unstable/main amd64 Packages [$(stat -c '%s' 'aptarchive/dists/unstable/main/binary-amd64/Packages.gz') B]
+Reading package lists..." aptget update
+	testfileequal 'listsdir.lst' "$(listcurrentlistsdirectory)"
+
+	webserverconfig 'aptwebserver::support::modified-since' 'false'
+	webserverconfig 'aptwebserver::support::last-modified' 'false'
+	testsuccessequal "Ign $1 unstable InRelease
+  404  Not Found
+Get:1 $1 unstable Release [$(stat -c '%s' 'aptarchive/dists/unstable/Release') B]
+Get:2 $1 unstable Release.gpg [$(stat -c '%s' 'aptarchive/dists/unstable/Release.gpg') B]
+Reading package lists..." aptget update
+	webserverconfig 'aptwebserver::support::modified-since' 'true'
+	webserverconfig 'aptwebserver::support::last-modified' 'true'
+
+	rm -rf aptarchive/dists
+	cp -a aptarchive/dists.good aptarchive/dists
 }
 }
 
 
 changetowebserver
 changetowebserver

+ 1 - 0
test/integration/test-apt-update-rollback

@@ -158,6 +158,7 @@ test_inrelease_to_broken_gzip() {
     msgmsg "Test InRelease to broken gzip"
     msgmsg "Test InRelease to broken gzip"
     start_with_good_inrelease
     start_with_good_inrelease
 
 
+    redatereleasefiles '+2hours'
     # append junk at the end of the compressed file
     # append junk at the end of the compressed file
     echo "lala" >> $APTARCHIVE/dists/unstable/main/source/Sources.gz
     echo "lala" >> $APTARCHIVE/dists/unstable/main/source/Sources.gz
     touch -d '+2min' $APTARCHIVE/dists/unstable/main/source/Sources.gz
     touch -d '+2min' $APTARCHIVE/dists/unstable/main/source/Sources.gz

+ 2 - 0
test/integration/test-apt-update-transactions

@@ -47,6 +47,7 @@ testrun() {
 
 
 testsetup() {
 testsetup() {
 	msgmsg 'Test with no initial data over' "$1"
 	msgmsg 'Test with no initial data over' "$1"
+	redatereleasefiles 'now'
 	rm -rf rootdir/var/lib/apt/lists
 	rm -rf rootdir/var/lib/apt/lists
 	mkdir -p rootdir/var/lib/apt/lists/partial
 	mkdir -p rootdir/var/lib/apt/lists/partial
 	listcurrentlistsdirectory > listsdir.lst
 	listcurrentlistsdirectory > listsdir.lst
@@ -55,6 +56,7 @@ testsetup() {
 	msgmsg 'Test with initial data over' "$1"
 	msgmsg 'Test with initial data over' "$1"
 	testsuccess aptget update
 	testsuccess aptget update
 	listcurrentlistsdirectory > listsdir.lst
 	listcurrentlistsdirectory > listsdir.lst
+	redatereleasefiles '+1hour'
 	testrun 'listsdir.lst'
 	testrun 'listsdir.lst'
 }
 }