]> git.saurik.com Git - apt.git/blobdiff - methods/https.cc
do not crash on SIGPIPE in pkgDPkgPM::RunScriptsWithPkgs()
[apt.git] / methods / https.cc
index 4f00842ba8c1f67a1d4592885a39d64734bdb0c3..c4aff8f38f09fd9f0557498d81f85b3ea956a5cd 100644 (file)
@@ -3,7 +3,7 @@
 // $Id: http.cc,v 1.59 2004/05/08 19:42:35 mdz Exp $
 /* ######################################################################
 
-   HTTPS Acquire Method - This is the HTTPS aquire method for APT.
+   HTTPS Acquire Method - This is the HTTPS acquire method for APT.
    
    It uses libcurl
 
 #include <apt-pkg/hashes.h>
 #include <apt-pkg/netrc.h>
 #include <apt-pkg/configuration.h>
+#include <apt-pkg/macros.h>
+#include <apt-pkg/strutl.h>
 
 #include <sys/stat.h>
 #include <sys/time.h>
-#include <utime.h>
 #include <unistd.h>
-#include <signal.h>
 #include <stdio.h>
-#include <errno.h>
-#include <string.h>
 #include <iostream>
 #include <sstream>
+#include <ctype.h>
+#include <stdlib.h>
 
-#include "config.h"
 #include "https.h"
+
 #include <apti18n.h>
                                                                        /*}}}*/
 using namespace std;
 
+size_t
+HttpsMethod::parse_header(void *buffer, size_t size, size_t nmemb, void *userp)
+{
+   size_t len = size * nmemb;
+   HttpsMethod *me = (HttpsMethod *)userp;
+   std::string line((char*) buffer, len);
+   for (--len; len > 0; --len)
+      if (isspace(line[len]) == 0)
+      {
+        ++len;
+        break;
+      }
+   line.erase(len);
+
+   if (line.empty() == true)
+   {
+      if (me->Server->Result != 416 && me->Server->StartPos != 0)
+        ;
+      else if (me->Server->Result == 416 && me->Server->Size == me->File->FileSize())
+      {
+         me->Server->Result = 200;
+        me->Server->StartPos = me->Server->Size;
+      }
+      else
+        me->Server->StartPos = 0;
+
+      me->File->Truncate(me->Server->StartPos);
+      me->File->Seek(me->Server->StartPos);
+   }
+   else if (me->Server->HeaderLine(line) == false)
+      return 0;
+
+   return size*nmemb;
+}
+
 size_t 
 HttpsMethod::write_data(void *buffer, size_t size, size_t nmemb, void *userp)
 {
    HttpsMethod *me = (HttpsMethod *)userp;
 
+   if (me->Res.Size == 0)
+      me->URIStart(me->Res);
    if(me->File->Write(buffer, size*nmemb) != true)
       return false;
 
    return size*nmemb;
 }
 
-int 
-HttpsMethod::progress_callback(void *clientp, double dltotal, double dlnow, 
-                             double ultotal, double ulnow)
+int
+HttpsMethod::progress_callback(void *clientp, double dltotal, double /*dlnow*/,
+                             double /*ultotal*/, double /*ulnow*/)
 {
    HttpsMethod *me = (HttpsMethod *)clientp;
    if(dltotal > 0 && me->Res.Size == 0) {
       me->Res.Size = (unsigned long long)dltotal;
-      me->URIStart(me->Res);
    }
    return 0;
 }
 
+// HttpsServerState::HttpsServerState - Constructor                    /*{{{*/
+HttpsServerState::HttpsServerState(URI Srv,HttpsMethod * /*Owner*/) : ServerState(Srv, NULL)
+{
+   TimeOut = _config->FindI("Acquire::https::Timeout",TimeOut);
+   Reset();
+}
+                                                                       /*}}}*/
+
 void HttpsMethod::SetupProxy()                                         /*{{{*/
 {
    URI ServerName = Queue->Uri;
@@ -136,12 +180,18 @@ bool HttpsMethod::Fetch(FetchItem *Itm)
 
    // callbacks
    curl_easy_setopt(curl, CURLOPT_URL, static_cast<string>(Uri).c_str());
+   curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, parse_header);
+   curl_easy_setopt(curl, CURLOPT_WRITEHEADER, this);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, this);
    curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progress_callback);
    curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, this);
+   // options
    curl_easy_setopt(curl, CURLOPT_NOPROGRESS, false);
    curl_easy_setopt(curl, CURLOPT_FILETIME, true);
+   // only allow curl to handle https, not the other stuff it supports
+   curl_easy_setopt(curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS);
+   curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS);
 
    // SSL parameters are set by default to the common (non mirror-specific) value
    // if available (or a default one) and gets overload by mirror-specific ones.
@@ -260,7 +310,7 @@ bool HttpsMethod::Fetch(FetchItem *Itm)
    curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_errorstr);
 
    // If we ask for uncompressed files servers might respond with content-
-   // negotation which lets us end up with compressed files we do not support,
+   // negotiation which lets us end up with compressed files we do not support,
    // see 657029, 657560 and co, so if we have no extension on the request
    // ask for text only. As a sidenote: If there is nothing to negotate servers
    // seem to be nice and ignore it.
@@ -289,16 +339,13 @@ 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());
+   Server = new HttpsServerState(Itm->Uri, this);
 
    // 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);
 
    // If the server returns 200 OK but the If-Modified-Since condition is not
    // met, CURLINFO_CONDITION_UNMET will be set to 1
@@ -317,7 +364,7 @@ bool HttpsMethod::Fetch(FetchItem *Itm)
    }
 
    // server says file not modified
-   if (curl_responsecode == 304 || curl_condition_unmet == 1)
+   if (Server->Result == 304 || curl_condition_unmet == 1)
    {
       unlink(File->Name().c_str());
       Res.IMSHit = true;
@@ -326,13 +373,14 @@ bool HttpsMethod::Fetch(FetchItem *Itm)
       URIDone(Res);
       return true;
    }
+   Res.IMSHit = false;
 
-   if (curl_responsecode != 200 && // OK
-        curl_responsecode != 206 && // Partial
-        curl_responsecode != 416) // invalid Range
+   if (Server->Result != 200 && // OK
+        Server->Result != 206 && // Partial
+        Server->Result != 416) // invalid Range
    {
       char err[255];
-      snprintf(err, sizeof(err) - 1, "HttpError%ld", curl_responsecode);
+      snprintf(err, sizeof(err) - 1, "HttpError%i", Server->Result);
       SetFailReason(err);
       _error->Error("%s", err);
       // unlink, no need keep 401/404 page content in partial/
@@ -349,7 +397,7 @@ bool HttpsMethod::Fetch(FetchItem *Itm)
    Res.Size = resultStat.st_size;
 
    // invalid range-request
-   if (curl_responsecode == 416)
+   if (Server->Result == 416)
    {
       unlink(File->Name().c_str());
       Res.Size = 0;
@@ -358,26 +406,15 @@ bool HttpsMethod::Fetch(FetchItem *Itm)
       return true;
    }
 
-   // check the downloaded result
-   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.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);
+      struct timeval times[2];
+      times[0].tv_sec = Res.LastModified;
+      times[1].tv_sec = Res.LastModified;
+      times[0].tv_usec = times[1].tv_usec = 0;
+      utimes(File->Name().c_str(), times);
    }
    else
       Res.LastModified = resultStat.st_mtime;
@@ -396,7 +433,7 @@ bool HttpsMethod::Fetch(FetchItem *Itm)
    delete File;
 
    return true;
-};
+}
 
 int main()
 {
@@ -408,4 +445,3 @@ int main()
    return Mth.Run();
 }
 
-