summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apt-pkg/contrib/fileutl.cc3
-rw-r--r--apt-pkg/deb/deblistparser.cc6
-rw-r--r--debian/changelog20
-rw-r--r--methods/http.cc2
-rw-r--r--methods/https.cc6
-rw-r--r--methods/server.cc34
-rw-r--r--methods/server.h13
-rwxr-xr-xtest/integration/test-bug-lp1445239-download-loop29
-rw-r--r--test/interactive-helper/aptwebserver.cc8
9 files changed, 98 insertions, 23 deletions
diff --git a/apt-pkg/contrib/fileutl.cc b/apt-pkg/contrib/fileutl.cc
index 1ba4674e5..1e6d96fe9 100644
--- a/apt-pkg/contrib/fileutl.cc
+++ b/apt-pkg/contrib/fileutl.cc
@@ -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);
diff --git a/apt-pkg/deb/deblistparser.cc b/apt-pkg/deb/deblistparser.cc
index 213235c2b..e87e7b5e4 100644
--- a/apt-pkg/deb/deblistparser.cc
+++ b/apt-pkg/deb/deblistparser.cc
@@ -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;
diff --git a/debian/changelog b/debian/changelog
index 769610e52..3f0d78b3c 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,23 @@
+apt (1.0.9.10ubuntu1) unstable; urgency=low
+
+ * merged from debian/sid
+
+ -- Michael Vogt <michael.vogt@ubuntu.com> Fri, 22 May 2015 18:08:10 +0200
+
+apt (1.0.9.10) unstable; urgency=medium
+
+ [ Michael Vogt ]
+ * Fix crash in pkgDPkgPM::WriteApportReport(() (LP: #1436626)
+ * Move sysconf(_SC_OPEN_MAX); out of the for() loop to avoid unneeded
+ syscalls
+ * Fix endless loop in apt-get update that can cause disk fillup
+ (LP: #1445239)
+
+ [ Helmut Grohne ]
+ * parse arch-qualified Provides correctly (Closes: 777071)
+
+ -- Michael Vogt <mvo@debian.org> Fri, 22 May 2015 17:38:31 +0200
+
apt (1.0.9.9ubuntu1) wily; urgency=low
* merged from debian/sid
diff --git a/methods/http.cc b/methods/http.cc
index 1b996db98..ad90c9891 100644
--- a/methods/http.cc
+++ b/methods/http.cc
@@ -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
diff --git a/methods/https.cc b/methods/https.cc
index cb11159bc..c97367323 100644
--- a/methods/https.cc
+++ b/methods/https.cc
@@ -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();
@@ -69,7 +69,7 @@ HttpsMethod::parse_header(void *buffer, size_t size, size_t nmemb, void *userp)
me->File->Truncate(me->Server->StartPos);
me->File->Seek(me->Server->StartPos);
- me->Res.Size = me->Server->Size;
+ me->Res.Size = me->Server->TotalFileSize;
}
else if (me->Server->HeaderLine(line) == false)
return 0;
diff --git a/methods/server.cc b/methods/server.cc
index e321e0230..6c05700a5 100644
--- a/methods/server.cc
+++ b/methods/server.cc
@@ -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;
diff --git a/methods/server.h b/methods/server.h
index 1b81e3549..8c14282b6 100644
--- a/methods/server.h
+++ b/methods/server.h
@@ -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;
diff --git a/test/integration/test-bug-lp1445239-download-loop b/test/integration/test-bug-lp1445239-download-loop
new file mode 100755
index 000000000..342e3c61e
--- /dev/null
+++ b/test/integration/test-bug-lp1445239-download-loop
@@ -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
diff --git a/test/interactive-helper/aptwebserver.cc b/test/interactive-helper/aptwebserver.cc
index cd52da692..e02caa2b3 100644
--- a/test/interactive-helper/aptwebserver.cc
+++ b/test/interactive-helper/aptwebserver.cc
@@ -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);