]> git.saurik.com Git - apt.git/blobdiff - methods/server.cc
report apt-key errors via status-fd messages
[apt.git] / methods / server.cc
index 66551b8931c33eaf3dab77973fe5a88dee9eb928..0408dddfd3f8dfbb8ef395f1b3d8935e8cac712e 100644 (file)
@@ -46,20 +46,9 @@ time_t ServerMethod::FailTime = 0;
 ServerState::RunHeadersResult ServerState::RunHeaders(FileFd * const File,
                                                       const std::string &Uri)
 {
-   State = Header;
-   
+   Reset(false);
    Owner->Status(_("Waiting for headers"));
 
-   Major = 0; 
-   Minor = 0; 
-   Result = 0; 
-   TotalFileSize = 0;
-   JunkSize = 0;
-   StartPos = 0;
-   Encoding = Closes;
-   HaveContent = false;
-   time(&Date);
-
    do
    {
       string Data;
@@ -101,25 +90,7 @@ bool ServerState::HeaderLine(string Line)
    if (Line.empty() == true)
       return true;
 
-   string::size_type Pos = Line.find(' ');
-   if (Pos == string::npos || Pos+1 > Line.length())
-   {
-      // Blah, some servers use "connection:closes", evil.
-      Pos = Line.find(':');
-      if (Pos == string::npos || Pos + 2 > Line.length())
-        return _error->Error(_("Bad header line"));
-      Pos++;
-   }
-
-   // Parse off any trailing spaces between the : and the next word.
-   string::size_type Pos2 = Pos;
-   while (Pos2 < Line.length() && isspace_ascii(Line[Pos2]) != 0)
-      Pos2++;
-
-   string Tag = string(Line,0,Pos);
-   string Val = string(Line,Pos2);
-
-   if (stringcasecmp(Tag.c_str(),Tag.c_str()+4,"HTTP") == 0)
+   if (Line.size() > 4 && stringcasecmp(Line.data(), Line.data()+4, "HTTP") == 0)
    {
       // Evil servers return no version
       if (Line[4] == '/')
@@ -163,6 +134,21 @@ bool ServerState::HeaderLine(string Line)
       return true;
    }
 
+   // Blah, some servers use "connection:closes", evil.
+   // and some even send empty header fields…
+   string::size_type Pos = Line.find(':');
+   if (Pos == string::npos)
+      return _error->Error(_("Bad header line"));
+   ++Pos;
+
+   // Parse off any trailing spaces between the : and the next word.
+   string::size_type Pos2 = Pos;
+   while (Pos2 < Line.length() && isspace_ascii(Line[Pos2]) != 0)
+      Pos2++;
+
+   string const Tag(Line,0,Pos);
+   string const Val(Line,Pos2);
+
    if (stringcasecmp(Tag,"Content-Length:") == 0)
    {
       if (Encoding == Closes)
@@ -222,8 +208,16 @@ bool ServerState::HeaderLine(string Line)
    if (stringcasecmp(Tag,"Connection:") == 0)
    {
       if (stringcasecmp(Val,"close") == 0)
+      {
         Persistent = false;
-      if (stringcasecmp(Val,"keep-alive") == 0)
+        Pipeline = false;
+        /* Some servers send error pages (as they are dynamically generated)
+           for simplicity via a connection close instead of e.g. chunked,
+           so assuming an always closing server only if we get a file + close */
+        if (Result >= 200 && Result < 300)
+           PipelineAllowed = false;
+      }
+      else if (stringcasecmp(Val,"keep-alive") == 0)
         Persistent = true;
       return true;
    }
@@ -241,6 +235,15 @@ bool ServerState::HeaderLine(string Line)
       return true;
    }
 
+   if (stringcasecmp(Tag, "Accept-Ranges:") == 0)
+   {
+      std::string ranges = ',' + Val + ',';
+      ranges.erase(std::remove(ranges.begin(), ranges.end(), ' '), ranges.end());
+      if (ranges.find(",bytes,") == std::string::npos)
+        RangesAllowed = false;
+      return true;
+   }
+
    return true;
 }
                                                                        /*}}}*/
@@ -257,6 +260,19 @@ bool ServerState::AddPartialFileToHashes(FileFd &File)                     /*{{{*/
    return GetHashes()->AddFD(File, StartPos);
 }
                                                                        /*}}}*/
+void ServerState::Reset(bool const Everything)                         /*{{{*/
+{
+   Major = 0; Minor = 0; Result = 0; Code[0] = '\0';
+   TotalFileSize = 0; JunkSize = 0; StartPos = 0;
+   Encoding = Closes; time(&Date); HaveContent = false;
+   State = Header; MaximumSize = 0;
+   if (Everything)
+   {
+      Persistent = false; Pipeline = false; PipelineAllowed = true;
+      RangesAllowed = true;
+   }
+}
+                                                                       /*}}}*/
 
 // ServerMethod::DealWithHeaders - Handle the retrieved header data    /*{{{*/
 // ---------------------------------------------------------------------
@@ -313,10 +329,30 @@ ServerMethod::DealWithHeaders(FetchResult &Res)
       {
         NextURI = DeQuoteString(Server->Location);
         URI tmpURI = NextURI;
-        if (tmpURI.Access == "http" && Binary == "https+http")
+        if (tmpURI.Access.find('+') != std::string::npos)
         {
-           tmpURI.Access = "https+http";
-           NextURI = tmpURI;
+           _error->Error("Server tried to trick us into using a specific implementation: %s", tmpURI.Access.c_str());
+           if (Server->HaveContent == true)
+              return ERROR_WITH_CONTENT_PAGE;
+           return ERROR_UNRECOVERABLE;
+        }
+        URI Uri = Queue->Uri;
+        if (Binary.find('+') != std::string::npos)
+        {
+           auto base = Binary.substr(0, Binary.find('+'));
+           if (base != tmpURI.Access)
+           {
+              tmpURI.Access = base + '+' + tmpURI.Access;
+              if (tmpURI.Access == Binary)
+              {
+                 std::string tmpAccess = Uri.Access;
+                 std::swap(tmpURI.Access, Uri.Access);
+                 NextURI = tmpURI;
+                 std::swap(tmpURI.Access, Uri.Access);
+              }
+              else
+                 NextURI = tmpURI;
+           }
         }
         if (Queue->Uri == NextURI)
         {
@@ -326,7 +362,7 @@ ServerMethod::DealWithHeaders(FetchResult &Res)
               return ERROR_WITH_CONTENT_PAGE;
            return ERROR_UNRECOVERABLE;
         }
-        URI Uri = Queue->Uri;
+        Uri.Access = Binary;
         // same protocol redirects are okay
         if (tmpURI.Access == Uri.Access)
            return TRY_AGAIN_OR_REDIRECT;
@@ -334,7 +370,22 @@ ServerMethod::DealWithHeaders(FetchResult &Res)
         else if ((Uri.Access == "http" || Uri.Access == "https+http") && tmpURI.Access == "https")
            return TRY_AGAIN_OR_REDIRECT;
         else
-           _error->Error("Redirection from %s to '%s' is forbidden", Uri.Access.c_str(), NextURI.c_str());
+        {
+           auto const tmpplus = tmpURI.Access.find('+');
+           if (tmpplus != std::string::npos && tmpURI.Access.substr(tmpplus + 1) == "https")
+           {
+              auto const uriplus = Uri.Access.find('+');
+              if (uriplus == std::string::npos)
+              {
+                 if (Uri.Access == tmpURI.Access.substr(0, tmpplus)) // foo -> foo+https
+                    return TRY_AGAIN_OR_REDIRECT;
+              }
+              else if (Uri.Access.substr(uriplus + 1) == "http" &&
+                    Uri.Access.substr(0, uriplus) == tmpURI.Access.substr(0, tmpplus)) // foo+http -> foo+https
+                 return TRY_AGAIN_OR_REDIRECT;
+           }
+        }
+        _error->Error("Redirection from %s to '%s' is forbidden", Uri.Access.c_str(), NextURI.c_str());
       }
       /* else pass through for error message */
    }
@@ -513,7 +564,7 @@ int ServerMethod::Loop()
       if (Result != -1 && (Result != 0 || Queue == 0))
       {
         if(FailReason.empty() == false ||
-           _config->FindB("Acquire::http::DependOnSTDIN", true) == true)
+           ConfigFindB("DependOnSTDIN", true) == true)
            return 100;
         else
            return 0;
@@ -524,7 +575,13 @@ int ServerMethod::Loop()
       
       // Connect to the server
       if (Server == 0 || Server->Comp(Queue->Uri) == false)
+      {
         Server = CreateServerState(Queue->Uri);
+        setPostfixForMethodNames(::URI(Queue->Uri).Host.c_str());
+        AllowRedirect = ConfigFindB("AllowRedirect", true);
+        PipelineDepth = ConfigFindI("Pipeline-Depth", 10);
+        Debug = DebugEnabled();
+      }
 
       /* If the server has explicitly said this is the last connection
          then we pre-emptively shut down the pipeline and tear down 
@@ -713,8 +770,8 @@ int ServerMethod::Loop()
         // We need to flush the data, the header is like a 404 w/ error text
         case ERROR_WITH_CONTENT_PAGE:
         {
-           Fail();
            Server->RunDataToDevNull();
+           Fail();
            break;
         }
 
@@ -747,9 +804,35 @@ unsigned long long ServerMethod::FindMaximumObjectSizeInQueue() const      /*{{{*/
    return MaxSizeInQueue;
 }
                                                                        /*}}}*/
-ServerMethod::ServerMethod(char const * const Binary, char const * const Ver,unsigned long const Flags) :/*{{{*/
-   aptMethod(Binary, Ver, Flags), Server(nullptr), File(NULL), PipelineDepth(10),
+ServerMethod::ServerMethod(std::string &&Binary, char const * const Ver,unsigned long const Flags) :/*{{{*/
+   aptMethod(std::move(Binary), Ver, Flags), Server(nullptr), File(NULL), PipelineDepth(10),
    AllowRedirect(false), Debug(false)
 {
 }
                                                                        /*}}}*/
+bool ServerMethod::Configuration(std::string Message)                  /*{{{*/
+{
+   if (aptMethod::Configuration(Message) == false)
+      return false;
+
+   _config->CndSet("Acquire::tor::Proxy",
+        "socks5h://apt-transport-tor@localhost:9050");
+   return true;
+}
+                                                                       /*}}}*/
+bool ServerMethod::AddProxyAuth(URI &Proxy, URI const &Server) const   /*{{{*/
+{
+   if (std::find(methodNames.begin(), methodNames.end(), "tor") != methodNames.end() &&
+        Proxy.User == "apt-transport-tor" && Proxy.Password.empty())
+   {
+      std::string pass = Server.Host;
+      pass.erase(std::remove_if(pass.begin(), pass.end(), [](char const c) { return std::isalnum(c) == 0; }), pass.end());
+      if (pass.length() > 255)
+        Proxy.Password = pass.substr(0, 255);
+      else
+        Proxy.Password = std::move(pass);
+   }
+   // FIXME: should we support auth.conf for proxies?
+   return true;
+}
+                                                                       /*}}}*/