summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Vogt <mvo@ubuntu.com>2015-05-22 15:28:53 +0200
committerMichael Vogt <mvo@ubuntu.com>2015-05-22 15:28:53 +0200
commitceafe8a6edc815df2923ba892894617829e9d3c2 (patch)
tree82f8e819f161b7f79d510d51b51b191f12840c8e
parent68be2fbb252a71303046e2ca7866cd659a91b585 (diff)
downloadapt-ceafe8a6edc815df2923ba892894617829e9d3c2.tar.gz
Fix endless loop in apt-get update that can cause disk fillup
The apt http code parses Content-Length and Content-Range. For both requests the variable "Size" is used and the semantic for this Size is the total file size. However Content-Length is not the entire file size for partital file requests. For servers that send the Content-Range header first and then the Content-Length header this can lead to globbing of Size so that its less than the real file size. This may lead to a subsequent passing of a negative number into the CircleBuf which leads to a endless loop that writes data. Thanks to Anton Blanchard for the analysis and initial patch. LP: #1445239
-rw-r--r--methods/http.cc2
-rw-r--r--methods/server.cc20
-rw-r--r--methods/server.h3
-rw-r--r--test/interactive-helper/aptwebserver.cc6
4 files changed, 21 insertions, 10 deletions
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/server.cc b/methods/server.cc
index e321e0230..ba0a8864b 100644
--- a/methods/server.cc
+++ b/methods/server.cc
@@ -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 && Size == 0)
+ Size = DownloadSize;
+
return true;
}
@@ -193,6 +200,9 @@ bool ServerState::HeaderLine(string Line)
return _error->Error(_("The HTTP server sent an invalid Content-Range header"));
if ((unsigned long long)StartPos > Size)
return _error->Error(_("This HTTP server has broken range support"));
+
+ // figure out what we will download
+ DownloadSize = Size - StartPos;
return true;
}
diff --git a/methods/server.h b/methods/server.h
index 1b81e3549..ed3cb456a 100644
--- a/methods/server.h
+++ b/methods/server.h
@@ -34,7 +34,8 @@ 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 Size; // total size of the usable content (aka: the file)
+ unsigned long long DownloadSize; // size we actually download (can be smaller than Size if we have partial content)
unsigned long long JunkSize; // size of junk content (aka: server error pages)
unsigned long long StartPos;
time_t Date;
diff --git a/test/interactive-helper/aptwebserver.cc b/test/interactive-helper/aptwebserver.cc
index cd52da692..9c67b67e4 100644
--- a/test/interactive-helper/aptwebserver.cc
+++ b/test/interactive-helper/aptwebserver.cc
@@ -654,13 +654,13 @@ static void * handleClient(void * voidclient) /*{{{*/
if (filesize > filestart)
{
data.Skip(filestart);
- std::ostringstream contentlength;
- contentlength << "Content-Length: " << (filesize - filestart);
- headers.push_back(contentlength.str());
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);