]> git.saurik.com Git - apt.git/blobdiff - methods/http.cc
- fix "apt-get source pkg=ver" if binary name != source name
[apt.git] / methods / http.cc
index e2337a9ba3459d1110a15e98a5f5c4591fa1c8fc..b3c791fa0a0e2fd555e81b4361dd7076b08e88bf 100644 (file)
@@ -3,7 +3,7 @@
 // $Id: http.cc,v 1.59 2004/05/08 19:42:35 mdz Exp $
 /* ######################################################################
 
-   HTTP Aquire Method - This is the HTTP aquire method for APT.
+   HTTP Acquire Method - This is the HTTP aquire method for APT.
    
    It uses HTTP/1.1 and many of the fancy options there-in, such as
    pipelining, range, if-range and so on. 
@@ -44,6 +44,7 @@
 // Internet stuff
 #include <netdb.h>
 
+#include "config.h"
 #include "connect.h"
 #include "rfc2553emu.h"
 #include "http.h"
@@ -57,8 +58,13 @@ time_t HttpMethod::FailTime = 0;
 unsigned long PipelineDepth = 10;
 unsigned long TimeOut = 120;
 bool Debug = false;
+URI Proxy;
 
-
+unsigned long CircleBuf::BwReadLimit=0;
+unsigned long CircleBuf::BwTickReadData=0;
+struct timeval CircleBuf::BwReadTick={0,0};
+const unsigned int CircleBuf::BW_HZ=10;
+  
 // CircleBuf::CircleBuf - Circular input buffer                                /*{{{*/
 // ---------------------------------------------------------------------
 /* */
@@ -66,6 +72,8 @@ CircleBuf::CircleBuf(unsigned long Size) : Size(Size), Hash(0)
 {
    Buf = new unsigned char[Size];
    Reset();
+
+   CircleBuf::BwReadLimit = _config->FindI("Acquire::http::Dl-Limit",0)*1024;
 }
                                                                        /*}}}*/
 // CircleBuf::Reset - Reset to the default state                       /*{{{*/
@@ -91,16 +99,45 @@ void CircleBuf::Reset()
    is non-blocking.. */
 bool CircleBuf::Read(int Fd)
 {
+   unsigned long BwReadMax;
+
    while (1)
    {
       // Woops, buffer is full
       if (InP - OutP == Size)
         return true;
 
+      // what's left to read in this tick
+      BwReadMax = CircleBuf::BwReadLimit/BW_HZ;
+
+      if(CircleBuf::BwReadLimit) {
+        struct timeval now;
+        gettimeofday(&now,0);
+
+        unsigned long d = (now.tv_sec-CircleBuf::BwReadTick.tv_sec)*1000000 +
+           now.tv_usec-CircleBuf::BwReadTick.tv_usec;
+        if(d > 1000000/BW_HZ) {
+           CircleBuf::BwReadTick = now;
+           CircleBuf::BwTickReadData = 0;
+        } 
+        
+        if(CircleBuf::BwTickReadData >= BwReadMax) {
+           usleep(1000000/BW_HZ);
+           return true;
+        }
+      }
+
       // Write the buffer segment
       int Res;
-      Res = read(Fd,Buf + (InP%Size),LeftRead());
+      if(CircleBuf::BwReadLimit) {
+        Res = read(Fd,Buf + (InP%Size), 
+                   BwReadMax > LeftRead() ? LeftRead() : BwReadMax);
+      } else
+        Res = read(Fd,Buf + (InP%Size),LeftRead());
       
+      if(Res > 0 && BwReadLimit > 0) 
+        CircleBuf::BwTickReadData += Res;
+    
       if (Res == 0)
         return false;
       if (Res < 0)
@@ -205,28 +242,23 @@ bool CircleBuf::WriteTillEl(string &Data,bool Single)
       if (Buf[I%Size] != '\n')
         continue;
       ++I;
-      if (I < InP  && Buf[I%Size] == '\r')
-         ++I;
       
       if (Single == false)
       {
-        if (Buf[I%Size] != '\n')
-           continue;
-         ++I;
          if (I < InP  && Buf[I%Size] == '\r')
             ++I;
+         if (I >= InP || Buf[I%Size] != '\n')
+            continue;
+         ++I;
       }
       
-      if (I > InP)
-        I = InP;
-      
       Data = "";
       while (OutP < I)
       {
         unsigned long Sz = LeftWrite();
         if (Sz == 0)
            return false;
-        if (I - OutP < LeftWrite())
+        if (I - OutP < Sz)
            Sz = I - OutP;
         Data += string((char *)(Buf + (OutP%Size)),Sz);
         OutP += Sz;
@@ -336,8 +368,8 @@ bool ServerState::Close()
                                                                        /*}}}*/
 // ServerState::RunHeaders - Get the headers before the data           /*{{{*/
 // ---------------------------------------------------------------------
-/* Returns 0 if things are OK, 1 if an IO error occursed and 2 if a header
-   parse error occured */
+/* Returns 0 if things are OK, 1 if an IO error occurred and 2 if a header
+   parse error occurred */
 int ServerState::RunHeaders()
 {
    State = Header;
@@ -626,7 +658,7 @@ void HttpMethod::SendReq(FetchItem *Itm,CircleBuf &Out)
       will glitch HTTP/1.0 proxies because they do not filter it out and 
       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)
+   if (Proxy.empty() == true || Proxy.Host.empty())
       sprintf(Buf,"GET %s HTTP/1.1\r\nHost: %s\r\nConnection: keep-alive\r\n",
              QuoteString(Uri.Path,"~").c_str(),ProperHost.c_str());
    else
@@ -683,7 +715,7 @@ void HttpMethod::SendReq(FetchItem *Itm,CircleBuf &Out)
       Req += string("Authorization: Basic ") + 
           Base64Encode(Uri.User + ":" + Uri.Password) + "\r\n";
    
-   Req += "User-Agent: Debian APT-HTTP/1.3\r\n\r\n";
+   Req += "User-Agent: Debian APT-HTTP/1.3 ("VERSION")\r\n\r\n";
    
    if (Debug == true)
       cerr << Req << endl;
@@ -788,7 +820,10 @@ bool HttpMethod::Flush(ServerState *Srv)
 {
    if (File != 0)
    {
-      SetNonBlock(File->Fd(),false);
+      // on GNU/kFreeBSD, apt dies on /dev/null because non-blocking
+      // can't be set
+      if (File->Name() != "/dev/null")
+        SetNonBlock(File->Fd(),false);
       if (Srv->In.WriteSpace() == false)
         return true;
       
@@ -816,7 +851,10 @@ bool HttpMethod::ServerDie(ServerState *Srv)
    // Dump the buffer to the file
    if (Srv->State == ServerState::Data)
    {
-      SetNonBlock(File->Fd(),false);
+      // on GNU/kFreeBSD, apt dies on /dev/null because non-blocking
+      // can't be set
+      if (File->Name() != "/dev/null")
+        SetNonBlock(File->Fd(),false);
       while (Srv->In.WriteSpace() == true)
       {
         if (Srv->In.Write(File->Fd()) == false)
@@ -903,7 +941,8 @@ int HttpMethod::DealWithHeaders(FetchResult &Res,ServerState *Srv)
    if (Srv->StartPos >= 0)
    {
       Res.ResumePoint = Srv->StartPos;
-      ftruncate(File->Fd(),Srv->StartPos);
+      if (ftruncate(File->Fd(),Srv->StartPos) < 0)
+        _error->Errno("ftruncate", _("Failed to truncate file"));
    }
       
    // Set the start point
@@ -958,7 +997,6 @@ bool HttpMethod::Fetch(FetchItem *)
 
    // Queue the requests
    int Depth = -1;
-   bool Tail = false;
    for (FetchItem *I = Queue; I != 0 && Depth < (signed)PipelineDepth; 
        I = I->Next, Depth++)
    {
@@ -970,8 +1008,6 @@ bool HttpMethod::Fetch(FetchItem *)
       if (Server->Comp(I->Uri) == false)
         break;
       if (QueueBack == I)
-        Tail = true;
-      if (Tail == true)
       {
         QueueBack = I->Next;
         SendReq(I,Server->Out);
@@ -1033,7 +1069,6 @@ int HttpMethod::Loop()
         delete Server;
         Server = new ServerState(Queue->Uri,this);
       }
-      
       /* If the server has explicitly said this is the last connection
          then we pre-emptively shut down the pipeline and tear down 
         the connection. This will speed up HTTP/1.0 servers a tad
@@ -1130,8 +1165,24 @@ int HttpMethod::Loop()
               URIDone(Res);
            }
            else
-              Fail(true);
-           
+           {
+              if (Server->ServerFd == -1)
+              {
+                 FailCounter++;
+                 _error->Discard();
+                 Server->Close();
+                 
+                 if (FailCounter >= 2)
+                 {
+                    Fail(_("Connection failed"),true);
+                    FailCounter = 0;
+                 }
+                 
+                 QueueBack = Queue;
+              }
+              else
+                 Fail(true);
+           }
            break;
         }