]> git.saurik.com Git - apt.git/blobdiff - methods/http.cc
fix off-by-one error in HttpMethod::​AutoDetectProxy()
[apt.git] / methods / http.cc
index b8ed43cd256cb99d07827adb0bff7dc761c553b8..ec5b1ff52ff2bd01fd699af754be2194d243bae8 100644 (file)
@@ -42,6 +42,7 @@
 #include <stdio.h>
 #include <errno.h>
 #include <string.h>
 #include <stdio.h>
 #include <errno.h>
 #include <string.h>
+#include <climits>
 #include <iostream>
 #include <map>
 
 #include <iostream>
 #include <map>
 
@@ -60,7 +61,7 @@ using namespace std;
 string HttpMethod::FailFile;
 int HttpMethod::FailFd = -1;
 time_t HttpMethod::FailTime = 0;
 string HttpMethod::FailFile;
 int HttpMethod::FailFd = -1;
 time_t HttpMethod::FailTime = 0;
-unsigned long PipelineDepth = 10;
+unsigned long PipelineDepth = 0;
 unsigned long TimeOut = 120;
 bool AllowRedirect = false;
 bool Debug = false;
 unsigned long TimeOut = 120;
 bool AllowRedirect = false;
 bool Debug = false;
@@ -534,10 +535,6 @@ bool ServerState::HeaderLine(string Line)
    if (Line.empty() == true)
       return true;
 
    if (Line.empty() == true)
       return true;
 
-   // The http server might be trying to do something evil.
-   if (Line.length() >= MAXLEN)
-      return _error->Error(_("Got a single header line over %u chars"),MAXLEN);
-
    string::size_type Pos = Line.find(' ');
    if (Pos == string::npos || Pos+1 > Line.length())
    {
    string::size_type Pos = Line.find(' ');
    if (Pos == string::npos || Pos+1 > Line.length())
    {
@@ -561,7 +558,7 @@ bool ServerState::HeaderLine(string Line)
       // Evil servers return no version
       if (Line[4] == '/')
       {
       // Evil servers return no version
       if (Line[4] == '/')
       {
-        int const elements = sscanf(Line.c_str(),"HTTP/%u.%u %u%[^\n]",&Major,&Minor,&Result,Code);
+        int const elements = sscanf(Line.c_str(),"HTTP/%3u.%3u %3u%359[^\n]",&Major,&Minor,&Result,Code);
         if (elements == 3)
         {
            Code[0] = '\0';
         if (elements == 3)
         {
            Code[0] = '\0';
@@ -575,7 +572,7 @@ bool ServerState::HeaderLine(string Line)
       {
         Major = 0;
         Minor = 9;
       {
         Major = 0;
         Minor = 9;
-        if (sscanf(Line.c_str(),"HTTP %u%[^\n]",&Result,Code) != 2)
+        if (sscanf(Line.c_str(),"HTTP %3u%359[^\n]",&Result,Code) != 2)
            return _error->Error(_("The HTTP server sent an invalid reply header"));
       }
 
            return _error->Error(_("The HTTP server sent an invalid reply header"));
       }
 
@@ -585,7 +582,7 @@ bool ServerState::HeaderLine(string Line)
         Persistent = false;
       else
       {
         Persistent = false;
       else
       {
-        if (Major == 1 && Minor <= 0)
+        if (Major == 1 && Minor == 0)
            Persistent = false;
         else
            Persistent = true;
            Persistent = false;
         else
            Persistent = true;
@@ -603,9 +600,10 @@ bool ServerState::HeaderLine(string Line)
       // The length is already set from the Content-Range header
       if (StartPos != 0)
         return true;
       // The length is already set from the Content-Range header
       if (StartPos != 0)
         return true;
-      
-      if (sscanf(Val.c_str(),"%llu",&Size) != 1)
-        return _error->Error(_("The HTTP server sent an invalid Content-Length header"));
+
+      Size = strtoull(Val.c_str(), NULL, 10);
+      if (Size >= std::numeric_limits<unsigned long long>::max())
+        return _error->Errno("HeaderLine", _("The HTTP server sent an invalid Content-Length header"));
       return true;
    }
 
       return true;
    }
 
@@ -669,7 +667,12 @@ void HttpMethod::SendReq(FetchItem *Itm,CircleBuf &Out)
 
    // The HTTP server expects a hostname with a trailing :port
    char Buf[1000];
 
    // The HTTP server expects a hostname with a trailing :port
    char Buf[1000];
-   string ProperHost = Uri.Host;
+   string ProperHost;
+
+   if (Uri.Host.find(':') != string::npos)
+      ProperHost = '[' + Uri.Host + ']';
+   else
+      ProperHost = Uri.Host;
    if (Uri.Port != 0)
    {
       sprintf(Buf,":%u",Uri.Port);
    if (Uri.Port != 0)
    {
       sprintf(Buf,":%u",Uri.Port);
@@ -687,8 +690,12 @@ void HttpMethod::SendReq(FetchItem *Itm,CircleBuf &Out)
       pass it on, HTTP/1.1 says the connection should default to keep alive
       and we expect the proxy to do this */
    if (Proxy.empty() == true || Proxy.Host.empty())
       pass it on, HTTP/1.1 says the connection should default to keep alive
       and we expect the proxy to do this */
    if (Proxy.empty() == true || Proxy.Host.empty())
+   {
+      // see LP bugs #1003633 and #1086997. The "+" is encoded as a workaround
+      // for a amazon S3 bug
       sprintf(Buf,"GET %s HTTP/1.1\r\nHost: %s\r\nConnection: keep-alive\r\n",
       sprintf(Buf,"GET %s HTTP/1.1\r\nHost: %s\r\nConnection: keep-alive\r\n",
-             QuoteString(Uri.Path,"~").c_str(),ProperHost.c_str());
+             QuoteString(Uri.Path,"+~ ").c_str(),ProperHost.c_str());
+   }
    else
    {
       /* Generate a cache control header if necessary. We place a max
    else
    {
       /* Generate a cache control header if necessary. We place a max
@@ -716,7 +723,19 @@ void HttpMethod::SendReq(FetchItem *Itm,CircleBuf &Out)
       }
    }
 
       }
    }
 
-   
+   // If we ask for uncompressed files servers might respond with content-
+   // negotation 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.
+   if (_config->FindB("Acquire::http::SendAccept", true) == true)
+   {
+      size_t const filepos = Itm->Uri.find_last_of('/');
+      string const file = Itm->Uri.substr(filepos + 1);
+      if (flExtension(file) == file)
+        strcat(Buf,"Accept: text/*\r\n");
+   }
+
    string Req = Buf;
 
    // Check for a partial file
    string Req = Buf;
 
    // Check for a partial file
@@ -748,7 +767,7 @@ void HttpMethod::SendReq(FetchItem *Itm,CircleBuf &Out)
           Base64Encode(Uri.User + ":" + Uri.Password) + "\r\n";
    }
    Req += "User-Agent: " + _config->Find("Acquire::http::User-Agent",
           Base64Encode(Uri.User + ":" + Uri.Password) + "\r\n";
    }
    Req += "User-Agent: " + _config->Find("Acquire::http::User-Agent",
-               "Debian APT-HTTP/1.3 ("VERSION")") + "\r\n\r\n";
+               "Debian APT-HTTP/1.3 (" PACKAGE_VERSION ")") + "\r\n\r\n";
    
    if (Debug == true)
       cerr << Req << endl;
    
    if (Debug == true)
       cerr << Req << endl;
@@ -961,12 +980,7 @@ HttpMethod::DealWithHeaders(FetchResult &Res,ServerState *Srv)
       {
         URI Uri = Queue->Uri;
         if (Uri.Host.empty() == false)
       {
         URI Uri = Queue->Uri;
         if (Uri.Host.empty() == false)
-        {
-           if (Uri.Port != 0)
-              strprintf(NextURI, "http://%s:%u", Uri.Host.c_str(), Uri.Port);
-           else
-              NextURI = "http://" + Uri.Host;
-        }
+            NextURI = URI::SiteOnly(Uri);
         else
            NextURI.clear();
         NextURI.append(DeQuoteString(Srv->Location));
         else
            NextURI.clear();
         NextURI.append(DeQuoteString(Srv->Location));
@@ -975,7 +989,10 @@ HttpMethod::DealWithHeaders(FetchResult &Res,ServerState *Srv)
       else
       {
          NextURI = DeQuoteString(Srv->Location);
       else
       {
          NextURI = DeQuoteString(Srv->Location);
-         return TRY_AGAIN_OR_REDIRECT;
+         URI tmpURI = NextURI;
+         // Do not allow a redirection to switch protocol
+         if (tmpURI.Access == "http")
+            return TRY_AGAIN_OR_REDIRECT;
       }
       /* else pass through for error message */
    }
       }
       /* else pass through for error message */
    }
@@ -1317,7 +1334,7 @@ int HttpMethod::Loop()
                after the same URI is seen twice in a queue item. */
             StringVector &R = Redirected[Queue->DestFile];
             bool StopRedirects = false;
                after the same URI is seen twice in a queue item. */
             StringVector &R = Redirected[Queue->DestFile];
             bool StopRedirects = false;
-            if (R.size() == 0)
+            if (R.empty() == true)
                R.push_back(Queue->Uri);
             else if (R[0] == "STOP" || R.size() > 10)
                StopRedirects = true;
                R.push_back(Queue->Uri);
             else if (R[0] == "STOP" || R.size() > 10)
                StopRedirects = true;
@@ -1384,7 +1401,7 @@ bool HttpMethod::AutoDetectProxy()
    char buf[512];
    int InFd = Pipes[0];
    close(Pipes[1]);
    char buf[512];
    int InFd = Pipes[0];
    close(Pipes[1]);
-   int res = read(InFd, buf, sizeof(buf));
+   int res = read(InFd, buf, sizeof(buf)-1);
    ExecWait(Process, "ProxyAutoDetect", true);
 
    if (res < 0)
    ExecWait(Process, "ProxyAutoDetect", true);
 
    if (res < 0)