]> git.saurik.com Git - apt.git/blobdiff - methods/http.cc
* apt-pkg/acquire-item.cc:
[apt.git] / methods / http.cc
index a5af2891763d6181fe10ce90bafe73d2a78c44ac..ecfb80bd2e3a451d3264b061e4c1fdf86f32e775 100644 (file)
@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description                                                         /*{{{*/
 // -*- mode: cpp; mode: fold -*-
 // Description                                                         /*{{{*/
-// $Id: http.cc,v 1.57 2004/01/07 20:39:38 mdz 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 Aquire Method - This is the HTTP aquire method for APT.
 #include <stdio.h>
 #include <errno.h>
 #include <string.h>
 #include <stdio.h>
 #include <errno.h>
 #include <string.h>
-#include <iostream>
 #include <apti18n.h>
 
 // Internet stuff
 #include <netdb.h>
 
 #include <apti18n.h>
 
 // Internet stuff
 #include <netdb.h>
 
+#include "config.h"
 #include "connect.h"
 #include "rfc2553emu.h"
 #include "http.h"
 #include "connect.h"
 #include "rfc2553emu.h"
 #include "http.h"
@@ -57,7 +57,13 @@ time_t HttpMethod::FailTime = 0;
 unsigned long PipelineDepth = 10;
 unsigned long TimeOut = 120;
 bool Debug = false;
 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                                /*{{{*/
 // ---------------------------------------------------------------------
 /* */
 // CircleBuf::CircleBuf - Circular input buffer                                /*{{{*/
 // ---------------------------------------------------------------------
 /* */
@@ -65,6 +71,8 @@ CircleBuf::CircleBuf(unsigned long Size) : Size(Size), Hash(0)
 {
    Buf = new unsigned char[Size];
    Reset();
 {
    Buf = new unsigned char[Size];
    Reset();
+
+   CircleBuf::BwReadLimit = _config->FindI("Acquire::http::Dl-Limit",0)*1024;
 }
                                                                        /*}}}*/
 // CircleBuf::Reset - Reset to the default state                       /*{{{*/
 }
                                                                        /*}}}*/
 // CircleBuf::Reset - Reset to the default state                       /*{{{*/
@@ -90,16 +98,45 @@ void CircleBuf::Reset()
    is non-blocking.. */
 bool CircleBuf::Read(int Fd)
 {
    is non-blocking.. */
 bool CircleBuf::Read(int Fd)
 {
+   unsigned long BwReadMax;
+
    while (1)
    {
       // Woops, buffer is full
       if (InP - OutP == Size)
         return true;
    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;
       // 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)
       if (Res == 0)
         return false;
       if (Res < 0)
@@ -203,25 +240,24 @@ bool CircleBuf::WriteTillEl(string &Data,bool Single)
    {      
       if (Buf[I%Size] != '\n')
         continue;
    {      
       if (Buf[I%Size] != '\n')
         continue;
-      for (I++; I < InP && Buf[I%Size] == '\r'; I++);
+      ++I;
       
       if (Single == false)
       {
       
       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;
       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;
            Sz = I - OutP;
         Data += string((char *)(Buf + (OutP%Size)),Sz);
         OutP += Sz;
@@ -510,14 +546,14 @@ bool ServerState::HeaderLine(string Line)
       {
         if (sscanf(Line.c_str(),"HTTP/%u.%u %u %[^\n]",&Major,&Minor,
                    &Result,Code) != 4)
       {
         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)
       }
       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
       }
 
       /* Check the HTTP response header to get the default persistance
@@ -546,7 +582,7 @@ bool ServerState::HeaderLine(string Line)
         return true;
       
       if (sscanf(Val.c_str(),"%lu",&Size) != 1)
         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;
    }
 
       return true;
    }
 
@@ -561,9 +597,9 @@ bool ServerState::HeaderLine(string Line)
       HaveContent = true;
       
       if (sscanf(Val.c_str(),"bytes %lu-%*u/%lu",&StartPos,&Size) != 2)
       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)
       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;
    }
    
       return true;
    }
    
@@ -621,7 +657,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 */
       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
       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 +667,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());
                 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",
       {
         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)
         else
         {
            if (_config->FindB("Acquire::http::No-Store",false) == true)
@@ -645,6 +681,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;
 
    
    string Req = Buf;
 
@@ -674,7 +714,7 @@ void HttpMethod::SendReq(FetchItem *Itm,CircleBuf &Out)
       Req += string("Authorization: Basic ") + 
           Base64Encode(Uri.User + ":" + Uri.Password) + "\r\n";
    
       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: Ubuntu APT-HTTP/1.3 ("VERSION")\r\n\r\n";
    
    if (Debug == true)
       cerr << Req << endl;
    
    if (Debug == true)
       cerr << Req << endl;
@@ -779,7 +819,10 @@ bool HttpMethod::Flush(ServerState *Srv)
 {
    if (File != 0)
    {
 {
    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;
       
       if (Srv->In.WriteSpace() == false)
         return true;
       
@@ -807,7 +850,10 @@ bool HttpMethod::ServerDie(ServerState *Srv)
    // Dump the buffer to the file
    if (Srv->State == ServerState::Data)
    {
    // 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)
       while (Srv->In.WriteSpace() == true)
       {
         if (Srv->In.Write(File->Fd()) == false)
@@ -825,7 +871,7 @@ bool HttpMethod::ServerDie(ServerState *Srv)
    {
       Srv->Close();
       if (LErrno == 0)
    {
       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"));
    }
       errno = LErrno;
       return _error->Errno("read",_("Error reading from server"));
    }
@@ -869,6 +915,9 @@ int HttpMethod::DealWithHeaders(FetchResult &Res,ServerState *Srv)
       failure */
    if (Srv->Result < 200 || Srv->Result >= 300)
    {
       failure */
    if (Srv->Result < 200 || Srv->Result >= 300)
    {
+      char err[255];
+      snprintf(err,sizeof(err)-1,"HttpError%i",Srv->Result);
+      SetFailReason(err);
       _error->Error("%u %s",Srv->Result,Srv->Code);
       if (Srv->HaveContent == true)
         return 4;
       _error->Error("%u %s",Srv->Result,Srv->Code);
       if (Srv->HaveContent == true)
         return 4;
@@ -944,7 +993,7 @@ void HttpMethod::SigTerm(int)
    depth. */
 bool HttpMethod::Fetch(FetchItem *)
 {
    depth. */
 bool HttpMethod::Fetch(FetchItem *)
 {
-   if (Server == 0)
+   if (Server == 0) 
       return true;
 
    // Queue the requests
       return true;
 
    // Queue the requests
@@ -1058,7 +1107,7 @@ int HttpMethod::Loop()
         // The header data is bad
         case 2:
         {
         // The header data is bad
         case 2:
         {
-           _error->Error(_("Bad header Data"));
+           _error->Error(_("Bad header data"));
            Fail(true);
            RotateDNS();
            continue;
            Fail(true);
            RotateDNS();
            continue;
@@ -1177,11 +1226,5 @@ int HttpMethod::Loop()
 }
                                                                        /*}}}*/
 
 }
                                                                        /*}}}*/
 
-int main()
-{
-   HttpMethod Mth;
-   
-   return Mth.Loop();
-}