]> git.saurik.com Git - apt.git/blobdiff - methods/http.cc
* Remove extraneous '\' characters from <command> tags in
[apt.git] / methods / http.cc
index f52459377fc5700765d6ed0071626c98a238e65e..3bb29cde07d7c42d1658a01c2fe66d4d28617125 100644 (file)
@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description                                                         /*{{{*/
-// $Id: http.cc,v 1.46 2000/05/28 04:33:59 jgg 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.
@@ -28,7 +28,7 @@
 #include <apt-pkg/fileutl.h>
 #include <apt-pkg/acquire-method.h>
 #include <apt-pkg/error.h>
-#include <apt-pkg/md5.h>
+#include <apt-pkg/hashes.h>
 
 #include <sys/stat.h>
 #include <sys/time.h>
@@ -37,6 +37,9 @@
 #include <signal.h>
 #include <stdio.h>
 #include <errno.h>
+#include <string.h>
+#include <iostream>
+#include <apti18n.h>
 
 // Internet stuff
 #include <netdb.h>
@@ -46,6 +49,7 @@
 #include "http.h"
 
                                                                        /*}}}*/
+using namespace std;
 
 string HttpMethod::FailFile;
 int HttpMethod::FailFd = -1;
@@ -57,7 +61,7 @@ bool Debug = false;
 // CircleBuf::CircleBuf - Circular input buffer                                /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-CircleBuf::CircleBuf(unsigned long Size) : Size(Size), MD5(0)
+CircleBuf::CircleBuf(unsigned long Size) : Size(Size), Hash(0)
 {
    Buf = new unsigned char[Size];
    Reset();
@@ -73,10 +77,10 @@ void CircleBuf::Reset()
    StrPos = 0;
    MaxGet = (unsigned int)-1;
    OutQueue = string();
-   if (MD5 != 0)
+   if (Hash != 0)
    {
-      delete MD5;
-      MD5 = new MD5Summation;
+      delete Hash;
+      Hash = new Hashes;
    }   
 };
                                                                        /*}}}*/
@@ -138,7 +142,7 @@ void CircleBuf::FillOut()
       unsigned long Sz = LeftRead();
       if (OutQueue.length() - StrPos < Sz)
         Sz = OutQueue.length() - StrPos;
-      memcpy(Buf + (InP%Size),OutQueue.begin() + StrPos,Sz);
+      memcpy(Buf + (InP%Size),OutQueue.c_str() + StrPos,Sz);
       
       // Advance
       StrPos += Sz;
@@ -182,8 +186,8 @@ bool CircleBuf::Write(int Fd)
         return false;
       }
       
-      if (MD5 != 0)
-        MD5->Add(Buf + (OutP%Size),Res);
+      if (Hash != 0)
+        Hash->Add(Buf + (OutP%Size),Res);
       
       OutP += Res;
    }
@@ -199,13 +203,17 @@ bool CircleBuf::WriteTillEl(string &Data,bool Single)
    {      
       if (Buf[I%Size] != '\n')
         continue;
-      for (I++; I < InP && Buf[I%Size] == '\r'; I++);
+      ++I;
+      if (I < InP  && Buf[I%Size] == '\r')
+         ++I;
       
       if (Single == false)
       {
         if (Buf[I%Size] != '\n')
            continue;
-        for (I++; I < InP && Buf[I%Size] == '\r'; I++);
+         ++I;
+         if (I < InP  && Buf[I%Size] == '\r')
+            ++I;
       }
       
       if (I > InP)
@@ -285,27 +293,13 @@ bool ServerState::Open()
    else
       Proxy = getenv("http_proxy");
    
-   // Parse no_proxy, a , seperated list of hosts
+   // Parse no_proxy, a , separated list of domains
    if (getenv("no_proxy") != 0)
    {
-      const char *Start = getenv("no_proxy");
-      for (const char *Cur = Start; true ; Cur++)
-      {
-        if (*Cur != ',' && *Cur != 0)
-           continue;
-        if (stringcasecmp(ServerName.Host.begin(),ServerName.Host.end(),
-                          Start,Cur) == 0)
-        {
-           Proxy = "";
-           break;
-        }
-        
-        Start = Cur + 1;
-        if (*Cur == 0)
-           break;
-      }         
-   }      
-
+      if (CheckDomainList(ServerName.Host,getenv("no_proxy")) == true)
+        Proxy = "";
+   }
+   
    // Determine what host and port to use based on the proxy settings
    int Port = 0;
    string Host;   
@@ -347,7 +341,7 @@ int ServerState::RunHeaders()
 {
    State = Header;
    
-   Owner->Status("Waiting for file");
+   Owner->Status(_("Waiting for headers"));
 
    Major = 0; 
    Minor = 0; 
@@ -371,11 +365,15 @@ int ServerState::RunHeaders()
       {
         string::const_iterator J = I;
         for (; J != Data.end() && *J != '\n' && *J != '\r';J++);
-        if (HeaderLine(string(I,J-I)) == false)
+        if (HeaderLine(string(I,J)) == false)
            return 2;
         I = J;
       }
 
+      // 100 Continue is a Nop...
+      if (Result == 100)
+        continue;
+      
       // Tidy up the connection persistance state.
       if (Encoding == Closes && HaveContent == true)
         Persistent = false;
@@ -489,7 +487,7 @@ bool ServerState::HeaderLine(string Line)
 
    // 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);
+      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())
@@ -497,7 +495,7 @@ bool ServerState::HeaderLine(string Line)
       // Blah, some servers use "connection:closes", evil.
       Pos = Line.find(':');
       if (Pos == string::npos || Pos + 2 > Line.length())
-        return _error->Error("Bad header line");
+        return _error->Error(_("Bad header line"));
       Pos++;
    }
 
@@ -509,21 +507,21 @@ bool ServerState::HeaderLine(string Line)
    string Tag = string(Line,0,Pos);
    string Val = string(Line,Pos2);
    
-   if (stringcasecmp(Tag.begin(),Tag.begin()+4,"HTTP") == 0)
+   if (stringcasecmp(Tag.c_str(),Tag.c_str()+4,"HTTP") == 0)
    {
       // Evil servers return no version
       if (Line[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)
-           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
@@ -537,7 +535,7 @@ bool ServerState::HeaderLine(string Line)
         else
            Persistent = true;
       }
-      
+
       return true;
    }      
       
@@ -552,7 +550,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;
    }
 
@@ -567,9 +565,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;
    }
    
@@ -593,7 +591,7 @@ bool ServerState::HeaderLine(string Line)
    if (stringcasecmp(Tag,"Last-Modified:") == 0)
    {
       if (StrToTime(Val,Date) == false)
-        return _error->Error("Unknown date format");
+        return _error->Error(_("Unknown date format"));
       return true;
    }
 
@@ -643,7 +641,7 @@ void HttpMethod::SendReq(FetchItem *Itm,CircleBuf &Out)
       {
         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)
@@ -676,7 +674,11 @@ void HttpMethod::SendReq(FetchItem *Itm,CircleBuf &Out)
       Req += string("Proxy-Authorization: Basic ") + 
           Base64Encode(Proxy.User + ":" + Proxy.Password) + "\r\n";
 
-   Req += "User-Agent: Debian APT-HTTP/1.2\r\n\r\n";
+   if (Uri.User.empty() == false || Uri.Password.empty() == false)
+      Req += string("Authorization: Basic ") + 
+          Base64Encode(Uri.User + ":" + Uri.Password) + "\r\n";
+   
+   Req += "User-Agent: Debian APT-HTTP/1.3\r\n\r\n";
    
    if (Debug == true)
       cerr << Req << endl;
@@ -729,11 +731,15 @@ bool HttpMethod::Go(bool ToFile,ServerState *Srv)
    tv.tv_usec = 0;
    int Res = 0;
    if ((Res = select(MaxFd+1,&rfds,&wfds,0,&tv)) < 0)
-      return _error->Errno("select","Select failed");
+   {
+      if (errno == EINTR)
+        return true;
+      return _error->Errno("select",_("Select failed"));
+   }
    
    if (Res == 0)
    {
-      _error->Error("Connection timed out");
+      _error->Error(_("Connection timed out"));
       return ServerDie(Srv);
    }
    
@@ -756,7 +762,7 @@ bool HttpMethod::Go(bool ToFile,ServerState *Srv)
    if (FileFD != -1 && FD_ISSET(FileFD,&wfds))
    {
       if (Srv->In.Write(FileFD) == false)
-        return _error->Errno("write","Error writing to output file");
+        return _error->Errno("write",_("Error writing to output file"));
    }
 
    // Handle commands from APT
@@ -784,7 +790,7 @@ bool HttpMethod::Flush(ServerState *Srv)
       while (Srv->In.WriteSpace() == true)
       {
         if (Srv->In.Write(File->Fd()) == false)
-           return _error->Errno("write","Error writing to file");
+           return _error->Errno("write",_("Error writing to file"));
         if (Srv->In.IsLimit() == true)
            return true;
       }
@@ -809,7 +815,7 @@ bool HttpMethod::ServerDie(ServerState *Srv)
       while (Srv->In.WriteSpace() == true)
       {
         if (Srv->In.Write(File->Fd()) == false)
-           return _error->Errno("write","Error writing to the file");
+           return _error->Errno("write",_("Error writing to the file"));
 
         // Done
         if (Srv->In.IsLimit() == true)
@@ -823,9 +829,9 @@ 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");
+      return _error->Errno("read",_("Error reading from server"));
    }
    else
    {
@@ -898,16 +904,16 @@ int HttpMethod::DealWithHeaders(FetchResult &Res,ServerState *Srv)
    // Set the start point
    lseek(File->Fd(),0,SEEK_END);
 
-   delete Srv->In.MD5;
-   Srv->In.MD5 = new MD5Summation;
+   delete Srv->In.Hash;
+   Srv->In.Hash = new Hashes;
    
-   // Fill the MD5 Hash if the file is non-empty (resume)
+   // Fill the Hash if the file is non-empty (resume)
    if (Srv->StartPos > 0)
    {
       lseek(File->Fd(),0,SEEK_SET);
-      if (Srv->In.MD5->AddFD(File->Fd(),Srv->StartPos) == false)
+      if (Srv->In.Hash->AddFD(File->Fd(),Srv->StartPos) == false)
       {
-        _error->Errno("read","Problem hashing file");
+        _error->Errno("read",_("Problem hashing file"));
         return 5;
       }
       lseek(File->Fd(),0,SEEK_END);
@@ -1056,8 +1062,9 @@ int HttpMethod::Loop()
         // The header data is bad
         case 2:
         {
-           _error->Error("Bad header Data");
+           _error->Error(_("Bad header Data"));
            Fail(true);
+           RotateDNS();
            continue;
         }
         
@@ -1072,10 +1079,11 @@ int HttpMethod::Loop()
            
            if (FailCounter >= 2)
            {
-              Fail("Connection failed",true);
+              Fail(_("Connection failed"),true);
               FailCounter = 0;
            }
            
+           RotateDNS();
            continue;
         }
       };
@@ -1093,6 +1101,11 @@ int HttpMethod::Loop()
            // Run the data
            bool Result =  Server->RunData();
 
+           /* If the server is sending back sizeless responses then fill in
+              the size now */
+           if (Res.Size == 0)
+              Res.Size = File->Size();
+           
            // Close the file, destroy the FD object and timestamp it
            FailFd = -1;
            delete File;
@@ -1108,7 +1121,7 @@ int HttpMethod::Loop()
            // Send status to APT
            if (Result == true)
            {
-              Res.MD5Sum = Server->In.MD5->Result();
+              Res.TakeHashes(*Server->In.Hash);
               URIDone(Res);
            }
            else
@@ -1134,7 +1147,11 @@ int HttpMethod::Loop()
         // Hard internal error, kill the connection and fail
         case 5:
         {
+           delete File;
+           File = 0;
+
            Fail();
+           RotateDNS();
            Server->Close();
            break;
         }
@@ -1153,7 +1170,7 @@ int HttpMethod::Loop()
         }
         
         default:
-        Fail("Internal error");
+        Fail(_("Internal error"));
         break;
       }
       
@@ -1170,3 +1187,5 @@ int main()
    
    return Mth.Loop();
 }
+
+