mirror of
https://github.com/ukui/apt.git
synced 2026-03-09 09:35:45 -07:00
fix partial (206 and 416) support in https
As lengthy discussed in lp:1157943 partial https support was utterly broken as a 206 response was handled as an (unhandled) error. This is the first part of fixing it by supporting a 206 response and starting to deal with 416.
This commit is contained in:
+67
-33
@@ -121,7 +121,6 @@ bool HttpsMethod::Fetch(FetchItem *Itm)
|
||||
struct stat SBuf;
|
||||
struct curl_slist *headers=NULL;
|
||||
char curl_errorstr[CURL_ERROR_SIZE];
|
||||
long curl_responsecode;
|
||||
URI Uri = Itm->Uri;
|
||||
string remotehost = Uri.Host;
|
||||
|
||||
@@ -277,7 +276,7 @@ bool HttpsMethod::Fetch(FetchItem *Itm)
|
||||
if (stat(Itm->DestFile.c_str(),&SBuf) >= 0 && SBuf.st_size > 0)
|
||||
{
|
||||
char Buf[1000];
|
||||
sprintf(Buf, "Range: bytes=%li-", (long) SBuf.st_size - 1);
|
||||
sprintf(Buf, "Range: bytes=%li-", (long) SBuf.st_size);
|
||||
headers = curl_slist_append(headers, Buf);
|
||||
sprintf(Buf, "If-Range: %s", TimeRFC1123(SBuf.st_mtime).c_str());
|
||||
headers = curl_slist_append(headers, Buf);
|
||||
@@ -291,75 +290,110 @@ bool HttpsMethod::Fetch(FetchItem *Itm)
|
||||
// go for it - if the file exists, append on it
|
||||
File = new FileFd(Itm->DestFile, FileFd::WriteAny);
|
||||
if (File->Size() > 0)
|
||||
File->Seek(File->Size() - 1);
|
||||
|
||||
File->Seek(File->Size());
|
||||
|
||||
// keep apt updated
|
||||
Res.Filename = Itm->DestFile;
|
||||
|
||||
// get it!
|
||||
CURLcode success = curl_easy_perform(curl);
|
||||
long curl_responsecode;
|
||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &curl_responsecode);
|
||||
|
||||
long curl_servdate;
|
||||
curl_easy_getinfo(curl, CURLINFO_FILETIME, &curl_servdate);
|
||||
|
||||
// If the server returns 200 OK but the If-Modified-Since condition is not
|
||||
// met, CURLINFO_CONDITION_UNMET will be set to 1
|
||||
long curl_condition_unmet = 0;
|
||||
curl_easy_getinfo(curl, CURLINFO_CONDITION_UNMET, &curl_condition_unmet);
|
||||
|
||||
File->Close();
|
||||
curl_slist_free_all(headers);
|
||||
|
||||
// cleanup
|
||||
if(success != 0 || (curl_responsecode != 200 && curl_responsecode != 304))
|
||||
if (success != 0)
|
||||
{
|
||||
_error->Error("%s", curl_errorstr);
|
||||
// unlink, no need keep 401/404 page content in partial/
|
||||
unlink(File->Name().c_str());
|
||||
Fail();
|
||||
return false;
|
||||
}
|
||||
|
||||
// server says file not modified
|
||||
if (curl_responsecode == 304 || curl_condition_unmet == 1)
|
||||
{
|
||||
unlink(File->Name().c_str());
|
||||
Res.IMSHit = true;
|
||||
Res.LastModified = Itm->LastModified;
|
||||
Res.Size = 0;
|
||||
URIDone(Res);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Timestamp
|
||||
struct utimbuf UBuf;
|
||||
if (curl_servdate != -1) {
|
||||
UBuf.actime = curl_servdate;
|
||||
UBuf.modtime = curl_servdate;
|
||||
utime(File->Name().c_str(),&UBuf);
|
||||
if (curl_responsecode != 200 && // OK
|
||||
curl_responsecode != 206 && // Partial
|
||||
curl_responsecode != 416) // invalid Range
|
||||
{
|
||||
char err[255];
|
||||
snprintf(err, sizeof(err) - 1, "HttpError%ld", curl_responsecode);
|
||||
SetFailReason(err);
|
||||
_error->Error("%s", err);
|
||||
// unlink, no need keep 401/404 page content in partial/
|
||||
unlink(File->Name().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
struct stat resultStat;
|
||||
if (unlikely(stat(File->Name().c_str(), &resultStat) != 0))
|
||||
{
|
||||
_error->Errno("stat", "Unable to access file %s", File->Name().c_str());
|
||||
return false;
|
||||
}
|
||||
Res.Size = resultStat.st_size;
|
||||
|
||||
// invalid range-request
|
||||
if (curl_responsecode == 416)
|
||||
{
|
||||
unlink(File->Name().c_str());
|
||||
Res.Size = 0;
|
||||
delete File;
|
||||
Redirect(Itm->Uri);
|
||||
return true;
|
||||
}
|
||||
|
||||
// check the downloaded result
|
||||
struct stat Buf;
|
||||
if (stat(File->Name().c_str(),&Buf) == 0)
|
||||
if (curl_responsecode == 304 || curl_condition_unmet)
|
||||
{
|
||||
Res.Filename = File->Name();
|
||||
Res.LastModified = Buf.st_mtime;
|
||||
Res.IMSHit = false;
|
||||
if (curl_responsecode == 304 || curl_condition_unmet)
|
||||
{
|
||||
unlink(File->Name().c_str());
|
||||
Res.IMSHit = true;
|
||||
Res.LastModified = Itm->LastModified;
|
||||
Res.Size = 0;
|
||||
URIDone(Res);
|
||||
return true;
|
||||
}
|
||||
Res.Size = Buf.st_size;
|
||||
unlink(File->Name().c_str());
|
||||
Res.IMSHit = true;
|
||||
Res.LastModified = Itm->LastModified;
|
||||
Res.Size = 0;
|
||||
URIDone(Res);
|
||||
return true;
|
||||
}
|
||||
Res.IMSHit = false;
|
||||
|
||||
// Timestamp
|
||||
curl_easy_getinfo(curl, CURLINFO_FILETIME, &Res.LastModified);
|
||||
if (Res.LastModified != -1)
|
||||
{
|
||||
struct utimbuf UBuf;
|
||||
UBuf.actime = Res.LastModified;
|
||||
UBuf.modtime = Res.LastModified;
|
||||
utime(File->Name().c_str(),&UBuf);
|
||||
}
|
||||
else
|
||||
Res.LastModified = resultStat.st_mtime;
|
||||
|
||||
// take hashes
|
||||
Hashes Hash;
|
||||
FileFd Fd(Res.Filename, FileFd::ReadOnly);
|
||||
Hash.AddFD(Fd);
|
||||
Res.TakeHashes(Hash);
|
||||
|
||||
|
||||
// keep apt updated
|
||||
URIDone(Res);
|
||||
|
||||
// cleanup
|
||||
Res.Size = 0;
|
||||
delete File;
|
||||
curl_slist_free_all(headers);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user