]> git.saurik.com Git - apt.git/commitdiff
Merge remote-tracking branch 'upstream/debian/jessie' into debian/sid
authorMichael Vogt <mvo@ubuntu.com>
Fri, 22 May 2015 14:17:08 +0000 (16:17 +0200)
committerMichael Vogt <mvo@ubuntu.com>
Fri, 22 May 2015 14:17:08 +0000 (16:17 +0200)
Conflicts:
apt-pkg/deb/dpkgpm.cc

apt-pkg/contrib/fileutl.cc
apt-pkg/deb/deblistparser.cc
methods/http.cc
methods/https.cc
methods/server.cc
methods/server.h
test/integration/test-apt-download-progress
test/integration/test-bug-lp1445239-download-loop [new file with mode: 0755]
test/interactive-helper/aptwebserver.cc

index 1ba4674e583194155be2477097188fff8775e19f..1e6d96fe91e0904b75a4fac6b5eb9a307cf14e8f 100644 (file)
@@ -778,8 +778,9 @@ pid_t ExecFork(std::set<int> KeepFDs)
       signal(SIGCONT,SIG_DFL);
       signal(SIGTSTP,SIG_DFL);
 
+      long ScOpenMax = sysconf(_SC_OPEN_MAX);
       // Close all of our FDs - just in case
-      for (int K = 3; K != sysconf(_SC_OPEN_MAX); K++)
+      for (int K = 3; K != ScOpenMax; K++)
       {
         if(KeepFDs.find(K) == KeepFDs.end())
            fcntl(K,F_SETFD,FD_CLOEXEC);
index 213235c2b16b217b1ca31fea7bb23d77fe10ac89..e87e7b5e49daa6dbf4e045d2966855edfd288c64 100644 (file)
@@ -817,10 +817,16 @@ bool debListParser::ParseProvides(pkgCache::VerIterator &Ver)
       while (1)
       {
         Start = ParseDepends(Start,Stop,Package,Version,Op);
+        const size_t archfound = Package.rfind(':');
         if (Start == 0)
            return _error->Error("Problem parsing Provides line");
         if (Op != pkgCache::Dep::NoOp && Op != pkgCache::Dep::Equals) {
            _error->Warning("Ignoring Provides line with non-equal DepCompareOp for package %s", Package.c_str());
+        } else if (archfound != string::npos) {
+           string OtherArch = Package.substr(archfound+1, string::npos);
+           Package = Package.substr(0, archfound);
+           if (NewProvides(Ver, Package, OtherArch, Version) == false)
+              return false;
         } else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign) {
            if (NewProvidesAllArch(Ver, Package, Version) == false)
               return false;
index 1b996db9816bab01f688a645a0f855b90a0c138f..ad90c98912f32de585a263c00e8b7a18b854bf7f 100644 (file)
@@ -443,7 +443,7 @@ bool HttpServerState::RunData(FileFd * const File)
       else if (JunkSize != 0)
         In.Limit(JunkSize);
       else
-        In.Limit(Size - StartPos);
+        In.Limit(DownloadSize);
       
       // Just transfer the whole block.
       do
index cb11159bc56cb5e7768ef3b41ee4c9b64bcd3280..81060122cd2d486171e4700b27bd9f47b9304e51 100644 (file)
@@ -55,10 +55,10 @@ HttpsMethod::parse_header(void *buffer, size_t size, size_t nmemb, void *userp)
    {
       if (me->Server->Result != 416 && me->Server->StartPos != 0)
         ;
-      else if (me->Server->Result == 416 && me->Server->Size == me->File->FileSize())
+      else if (me->Server->Result == 416 && me->Server->TotalFileSize == me->File->FileSize())
       {
          me->Server->Result = 200;
-        me->Server->StartPos = me->Server->Size;
+        me->Server->StartPos = me->Server->TotalFileSize;
         // the actual size is not important for https as curl will deal with it
         // by itself and e.g. doesn't bother us with transport-encoding…
         me->Server->JunkSize = std::numeric_limits<unsigned long long>::max();
index e321e0230362a363702214d383edde2bbbf59301..6c05700a57ecc20ccc9840b541c778c5cb8732bd 100644 (file)
@@ -54,7 +54,7 @@ ServerState::RunHeadersResult ServerState::RunHeaders(FileFd * const File,
    Major = 0; 
    Minor = 0; 
    Result = 0; 
-   Size = 0; 
+   TotalFileSize = 0;
    JunkSize = 0;
    StartPos = 0;
    Encoding = Closes;
@@ -164,15 +164,22 @@ bool ServerState::HeaderLine(string Line)
         Encoding = Stream;
       HaveContent = true;
 
-      unsigned long long * SizePtr = &Size;
+      unsigned long long * DownloadSizePtr = &DownloadSize;
       if (Result == 416)
-        SizePtr = &JunkSize;
+        DownloadSizePtr = &JunkSize;
 
-      *SizePtr = strtoull(Val.c_str(), NULL, 10);
-      if (*SizePtr >= std::numeric_limits<unsigned long long>::max())
+      *DownloadSizePtr = strtoull(Val.c_str(), NULL, 10);
+      if (*DownloadSizePtr >= std::numeric_limits<unsigned long long>::max())
         return _error->Errno("HeaderLine", _("The HTTP server sent an invalid Content-Length header"));
-      else if (*SizePtr == 0)
+      else if (*DownloadSizePtr == 0)
         HaveContent = false;
+
+      // On partial content (206) the Content-Length less than the real
+      // size, so do not set it here but leave that to the Content-Range
+      // header instead
+      if(Result != 206 && TotalFileSize == 0)
+         TotalFileSize = DownloadSize;
+
       return true;
    }
 
@@ -187,12 +194,15 @@ bool ServerState::HeaderLine(string Line)
       HaveContent = true;
 
       // Â§14.16 says 'byte-range-resp-spec' should be a '*' in case of 416
-      if (Result == 416 && sscanf(Val.c_str(), "bytes */%llu",&Size) == 1)
+      if (Result == 416 && sscanf(Val.c_str(), "bytes */%llu",&TotalFileSize) == 1)
         ; // we got the expected filesize which is all we wanted
-      else if (sscanf(Val.c_str(),"bytes %llu-%*u/%llu",&StartPos,&Size) != 2)
+      else if (sscanf(Val.c_str(),"bytes %llu-%*u/%llu",&StartPos,&TotalFileSize) != 2)
         return _error->Error(_("The HTTP server sent an invalid Content-Range header"));
-      if ((unsigned long long)StartPos > Size)
+      if ((unsigned long long)StartPos > TotalFileSize)
         return _error->Error(_("This HTTP server has broken range support"));
+
+      // figure out what we will download
+      DownloadSize = TotalFileSize - StartPos;
       return true;
    }
 
@@ -303,7 +313,7 @@ ServerMethod::DealWithHeaders(FetchResult &Res)
       struct stat SBuf;
       if (stat(Queue->DestFile.c_str(),&SBuf) >= 0 && SBuf.st_size > 0)
       {
-        if ((unsigned long long)SBuf.st_size == Server->Size)
+        if ((unsigned long long)SBuf.st_size == Server->TotalFileSize)
         {
            // the file is completely downloaded, but was not moved
            if (Server->HaveContent == true)
@@ -313,7 +323,7 @@ ServerMethod::DealWithHeaders(FetchResult &Res)
               Server->RunData(&DevNull);
            }
            Server->HaveContent = false;
-           Server->StartPos = Server->Size;
+           Server->StartPos = Server->TotalFileSize;
            Server->Result = 200;
         }
         else if (unlink(Queue->DestFile.c_str()) == 0)
@@ -339,7 +349,7 @@ ServerMethod::DealWithHeaders(FetchResult &Res)
 
    // This is some sort of 2xx 'data follows' reply
    Res.LastModified = Server->Date;
-   Res.Size = Server->Size;
+   Res.Size = Server->TotalFileSize;
    
    // Open the file
    delete File;
index 1b81e3549b5d05370700f1985aa532d2e3fff2aa..8c14282b6d77254b160ee3c5571175cb28c9aa64 100644 (file)
@@ -34,9 +34,16 @@ struct ServerState
    char Code[360];
 
    // These are some statistics from the last parsed header lines
-   unsigned long long Size; // size of the usable content (aka: the file)
-   unsigned long long JunkSize; // size of junk content (aka: server error pages)
+
+   // total size of the usable content (aka: the file)
+   unsigned long long TotalFileSize;
+   // size we actually download (can be smaller than Size if we have partial content)
+   unsigned long long DownloadSize;
+   // size of junk content (aka: server error pages)
+   unsigned long long JunkSize;
+   // The start of the data (for partial content)
    unsigned long long StartPos;
+
    time_t Date;
    bool HaveContent;
    enum {Chunked,Stream,Closes} Encoding;
@@ -72,7 +79,7 @@ struct ServerState
    RunHeadersResult RunHeaders(FileFd * const File, const std::string &Uri);
 
    bool Comp(URI Other) const {return Other.Host == ServerName.Host && Other.Port == ServerName.Port;};
-   virtual void Reset() {Major = 0; Minor = 0; Result = 0; Code[0] = '\0'; Size = 0; JunkSize = 0;
+   virtual void Reset() {Major = 0; Minor = 0; Result = 0; Code[0] = '\0'; TotalFileSize = 0; JunkSize = 0;
                 StartPos = 0; Encoding = Closes; time(&Date); HaveContent = false;
                 State = Header; Persistent = false; Pipeline = true;};
    virtual bool WriteResponse(std::string const &Data) = 0;
index 0a9020bece02556d8f32f66ae1e733353f124d3f..7092e163e6fe35e439bbf5be32537cb93498f13d 100755 (executable)
@@ -30,13 +30,13 @@ testsuccess dd if=/dev/zero of=./aptarchive/$TESTFILE bs=800k count=1
 msgtest 'download progress works via' 'http'
 printf '\n'
 exec 3> apt-progress.log
-testsuccess apthelper download-file "http://localhost:8080/$TESTFILE" http-$TESTFILE -o APT::Status-Fd=3 -o Acquire::http::Dl-Limit=800
+testsuccess apthelper download-file "http://localhost:8080/$TESTFILE" http-$TESTFILE -o APT::Status-Fd=3 -o Acquire::http::Dl-Limit=600
 assertprogress apt-progress.log
 
 msgtest 'download progress works via' 'https'
 printf '\n'
 exec 3> apt-progress.log
-testsuccess apthelper download-file "https://localhost:4433/$TESTFILE" https-$TESTFILE -o APT::Status-Fd=3 -o Acquire::https::Dl-Limit=800
+testsuccess apthelper download-file "https://localhost:4433/$TESTFILE" https-$TESTFILE -o APT::Status-Fd=3 -o Acquire::https::Dl-Limit=600
 assertprogress apt-progress.log
 
 # cleanup
diff --git a/test/integration/test-bug-lp1445239-download-loop b/test/integration/test-bug-lp1445239-download-loop
new file mode 100755 (executable)
index 0000000..342e3c6
--- /dev/null
@@ -0,0 +1,29 @@
+#!/bin/sh
+#
+# this is a regression test for LP: #1445239 where a partial download can
+# trigger an endless hang of the download method
+#
+
+set -e
+
+TESTDIR=$(readlink -f $(dirname $0))
+. $TESTDIR/framework
+setupenvironment
+configarchitecture 'amd64'
+
+changetowebserver
+webserverconfig 'aptwebserver::support::range' 'true'
+
+TESTFILE='aptarchive/testfile'
+dd if=/dev/zero of=$TESTFILE bs=100k count=1 2>/dev/null
+
+DOWNLOADLOG='rootdir/tmp/testdownloadfile.log'
+
+TARGET=testfile-downloaded
+dd if=/dev/zero of=$TARGET bs=99k count=1 2>/dev/null
+if ! downloadfile http://localhost:8080/testfile "$TARGET" > "$DOWNLOADLOG"; then
+    cat >&2 "$DOWNLOADLOG"
+    msgfail
+else
+    msgpass
+fi
index cd52da692a8339cffdbab68ff61b039ea72275a8..e02caa2b3516df0a248cb482256795b648b9ff6a 100644 (file)
@@ -654,13 +654,15 @@ static void * handleClient(void * voidclient)                             /*{{{*/
                     if (filesize > filestart)
                     {
                        data.Skip(filestart);
-                       std::ostringstream contentlength;
-                       contentlength << "Content-Length: " << (filesize - filestart);
-                       headers.push_back(contentlength.str());
+                        // make sure to send content-range before conent-length
+                        // as regression test for LP: #1445239
                        std::ostringstream contentrange;
                        contentrange << "Content-Range: bytes " << filestart << "-"
                           << filesize - 1 << "/" << filesize;
                        headers.push_back(contentrange.str());
+                       std::ostringstream contentlength;
+                       contentlength << "Content-Length: " << (filesize - filestart);
+                       headers.push_back(contentlength.str());
                        sendHead(client, 206, headers);
                        if (sendContent == true)
                           sendFile(client, headers, data);