X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/dc738e7ae6a9c14992279dc2c52f71b14ced53aa..18a14a834e4068917d97467a3a52f17ed6055da3:/methods/http.cc

diff --git a/methods/http.cc b/methods/http.cc
index d1ff9b6b8..d4e231fbe 100644
--- a/methods/http.cc
+++ b/methods/http.cc
@@ -1,9 +1,9 @@
 // -*- mode: cpp; mode: fold -*-
 // Description								/*{{{*/
-// $Id: http.cc,v 1.55 2003/02/10 07:34:41 doogie Exp $
+// $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. 
@@ -25,7 +25,6 @@
    ##################################################################### */
 									/*}}}*/
 // Include Files							/*{{{*/
-#include <apti18n.h>
 #include <apt-pkg/fileutl.h>
 #include <apt-pkg/acquire-method.h>
 #include <apt-pkg/error.h>
@@ -40,10 +39,12 @@
 #include <errno.h>
 #include <string.h>
 #include <iostream>
+#include <apti18n.h>
 
 // Internet stuff
 #include <netdb.h>
 
+#include "config.h"
 #include "connect.h"
 #include "rfc2553emu.h"
 #include "http.h"
@@ -57,7 +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				/*{{{*/
 // ---------------------------------------------------------------------
 /* */
@@ -65,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			/*{{{*/
@@ -90,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)
@@ -203,25 +241,24 @@ bool CircleBuf::WriteTillEl(string &Data,bool Single)
    {      
       if (Buf[I%Size] != '\n')
 	 continue;
-      for (I++; I < InP && Buf[I%Size] == '\r'; I++);
+      ++I;
       
       if (Single == false)
       {
-	 if (Buf[I%Size] != '\n')
-	    continue;
-	 for (I++; I < InP && Buf[I%Size] == '\r'; 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;
@@ -337,7 +374,7 @@ int ServerState::RunHeaders()
 {
    State = Header;
    
-   Owner->Status(_("Waiting for file"));
+   Owner->Status(_("Waiting for headers"));
 
    Major = 0; 
    Minor = 0; 
@@ -510,14 +547,14 @@ bool ServerState::HeaderLine(string Line)
       {
 	 if (sscanf(Line.c_str(),"HTTP/%u.%u %u %[^\n]",&Major,&Minor,
 		    &Result,Code) != 4)
-	    return _error->Error(_("The http server sent an invalid reply header"));
+	    return _error->Error(_("The HTTP server sent an invalid reply header"));
       }
       else
       {
 	 Major = 0;
 	 Minor = 9;
 	 if (sscanf(Line.c_str(),"HTTP %u %[^\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"));
       }
 
       /* Check the HTTP response header to get the default persistance
@@ -546,7 +583,7 @@ bool ServerState::HeaderLine(string Line)
 	 return true;
       
       if (sscanf(Val.c_str(),"%lu",&Size) != 1)
-	 return _error->Error(_("The http server sent an invalid Content-Length header"));
+	 return _error->Error(_("The HTTP server sent an invalid Content-Length header"));
       return true;
    }
 
@@ -561,9 +598,9 @@ bool ServerState::HeaderLine(string Line)
       HaveContent = true;
       
       if (sscanf(Val.c_str(),"bytes %lu-%*u/%lu",&StartPos,&Size) != 2)
-	 return _error->Error(_("The http server sent an invalid Content-Range header"));
+	 return _error->Error(_("The HTTP server sent an invalid Content-Range header"));
       if ((unsigned)StartPos > Size)
-	 return _error->Error(_("This http server has broken range support"));
+	 return _error->Error(_("This HTTP server has broken range support"));
       return true;
    }
    
@@ -621,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
@@ -631,13 +668,13 @@ void HttpMethod::SendReq(FetchItem *Itm,CircleBuf &Out)
        	 and a no-store directive for archives. */
       sprintf(Buf,"GET %s HTTP/1.1\r\nHost: %s\r\n",
 	      Itm->Uri.c_str(),ProperHost.c_str());
-      if (_config->FindB("Acquire::http::No-Cache",false) == true)
-	 strcat(Buf,"Cache-Control: no-cache\r\nPragma: no-cache\r\n");
-      else
+      // only generate a cache control header if we actually want to 
+      // use a cache
+      if (_config->FindB("Acquire::http::No-Cache",false) == false)
       {
 	 if (Itm->IndexFile == true)
 	    sprintf(Buf+strlen(Buf),"Cache-Control: max-age=%u\r\n",
-		    _config->FindI("Acquire::http::Max-Age",60*60*24));
+		    _config->FindI("Acquire::http::Max-Age",0));
 	 else
 	 {
 	    if (_config->FindB("Acquire::http::No-Store",false) == true)
@@ -645,6 +682,10 @@ void HttpMethod::SendReq(FetchItem *Itm,CircleBuf &Out)
 	 }	 
       }
    }
+   // generate a no-cache header if needed
+   if (_config->FindB("Acquire::http::No-Cache",false) == true)
+      strcat(Buf,"Cache-Control: no-cache\r\nPragma: no-cache\r\n");
+
    
    string Req = Buf;
 
@@ -674,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;
@@ -779,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;
       
@@ -807,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)
@@ -825,7 +872,7 @@ bool HttpMethod::ServerDie(ServerState *Srv)
    {
       Srv->Close();
       if (LErrno == 0)
-	 return _error->Error(_("Error reading from server Remote end closed connection"));
+	 return _error->Error(_("Error reading from server. Remote end closed connection"));
       errno = LErrno;
       return _error->Errno("read",_("Error reading from server"));
    }
@@ -949,7 +996,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++)
    {
@@ -961,8 +1007,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);
@@ -1024,7 +1068,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
@@ -1058,7 +1101,7 @@ int HttpMethod::Loop()
 	 // The header data is bad
 	 case 2:
 	 {
-	    _error->Error(_("Bad header Data"));
+	    _error->Error(_("Bad header data"));
 	    Fail(true);
 	    RotateDNS();
 	    continue;
@@ -1121,8 +1164,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;
 	 }
 	 
@@ -1179,6 +1238,8 @@ int HttpMethod::Loop()
 
 int main()
 {
+   setlocale(LC_ALL, "");
+
    HttpMethod Mth;
    
    return Mth.Loop();