- apply Progeny's redir and authentication patch
[apt.git] / methods / http.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description                                                          /*{{{*/
3 // $Id: http.cc,v 1.56 2003/02/12 15:33:36 doogie Exp $
4 /* ######################################################################
5
6    HTTP Aquire Method - This is the HTTP aquire method for APT.
7    
8    It uses HTTP/1.1 and many of the fancy options there-in, such as
9    pipelining, range, if-range and so on. 
10
11    It is based on a doubly buffered select loop. A groupe of requests are 
12    fed into a single output buffer that is constantly fed out the 
13    socket. This provides ideal pipelining as in many cases all of the
14    requests will fit into a single packet. The input socket is buffered 
15    the same way and fed into the fd for the file (may be a pipe in future).
16    
17    This double buffering provides fairly substantial transfer rates,
18    compared to wget the http method is about 4% faster. Most importantly,
19    when HTTP is compared with FTP as a protocol the speed difference is
20    huge. In tests over the internet from two sites to llug (via ATM) this
21    program got 230k/s sustained http transfer rates. FTP on the other 
22    hand topped out at 170k/s. That combined with the time to setup the
23    FTP connection makes HTTP a vastly superior protocol.
24       
25    ##################################################################### */
26                                                                         /*}}}*/
27 // Include Files                                                        /*{{{*/
28 #include <apt-pkg/fileutl.h>
29 #include <apt-pkg/acquire-method.h>
30 #include <apt-pkg/error.h>
31 #include <apt-pkg/hashes.h>
32
33 #include <sys/stat.h>
34 #include <sys/time.h>
35 #include <utime.h>
36 #include <unistd.h>
37 #include <signal.h>
38 #include <stdio.h>
39 #include <errno.h>
40 #include <string.h>
41 #include <iostream>
42 #include <map>
43
44 // Internet stuff
45 #include <netdb.h>
46
47 // CNC:2003-02-20 - Moved header to fix compilation error when
48 //                  --disable-nls is used.
49 #include <apti18n.h>
50
51 #include "connect.h"
52 #include "rfc2553emu.h"
53 #include "http.h"
54
55                                                                         /*}}}*/
56 using namespace std;
57
58 string HttpMethod::FailFile;
59 int HttpMethod::FailFd = -1;
60 time_t HttpMethod::FailTime = 0;
61 unsigned long PipelineDepth = 10;
62 unsigned long TimeOut = 120;
63 bool ChokePipe = true;
64 bool Debug = false;
65
66 // CircleBuf::CircleBuf - Circular input buffer                         /*{{{*/
67 // ---------------------------------------------------------------------
68 /* */
69 CircleBuf::CircleBuf(unsigned long Size) : Size(Size), Hash(0)
70 {
71    Buf = new unsigned char[Size];
72    Reset();
73 }
74                                                                         /*}}}*/
75 // CircleBuf::Reset - Reset to the default state                        /*{{{*/
76 // ---------------------------------------------------------------------
77 /* */
78 void CircleBuf::Reset()
79 {
80    InP = 0;
81    OutP = 0;
82    StrPos = 0;
83    MaxGet = (unsigned int)-1;
84    OutQueue = string();
85    if (Hash != 0)
86    {
87       delete Hash;
88       Hash = new Hashes;
89    }   
90 };
91                                                                         /*}}}*/
92 // CircleBuf::Read - Read from a FD into the circular buffer            /*{{{*/
93 // ---------------------------------------------------------------------
94 /* This fills up the buffer with as much data as is in the FD, assuming it
95    is non-blocking.. */
96 bool CircleBuf::Read(int Fd)
97 {
98    while (1)
99    {
100       // Woops, buffer is full
101       if (InP - OutP == Size)
102          return true;
103       
104       // Write the buffer segment
105       int Res;
106       Res = read(Fd,Buf + (InP%Size),LeftRead());
107       
108       if (Res == 0)
109          return false;
110       if (Res < 0)
111       {
112          if (errno == EAGAIN)
113             return true;
114          return false;
115       }
116
117       if (InP == 0)
118          gettimeofday(&Start,0);
119       InP += Res;
120    }
121 }
122                                                                         /*}}}*/
123 // CircleBuf::Read - Put the string into the buffer                     /*{{{*/
124 // ---------------------------------------------------------------------
125 /* This will hold the string in and fill the buffer with it as it empties */
126 bool CircleBuf::Read(string Data)
127 {
128    OutQueue += Data;
129    FillOut();
130    return true;
131 }
132                                                                         /*}}}*/
133 // CircleBuf::FillOut - Fill the buffer from the output queue           /*{{{*/
134 // ---------------------------------------------------------------------
135 /* */
136 void CircleBuf::FillOut()
137 {
138    if (OutQueue.empty() == true)
139       return;
140    while (1)
141    {
142       // Woops, buffer is full
143       if (InP - OutP == Size)
144          return;
145       
146       // Write the buffer segment
147       unsigned long Sz = LeftRead();
148       if (OutQueue.length() - StrPos < Sz)
149          Sz = OutQueue.length() - StrPos;
150       memcpy(Buf + (InP%Size),OutQueue.c_str() + StrPos,Sz);
151       
152       // Advance
153       StrPos += Sz;
154       InP += Sz;
155       if (OutQueue.length() == StrPos)
156       {
157          StrPos = 0;
158          OutQueue = "";
159          return;
160       }
161    }
162 }
163                                                                         /*}}}*/
164 // CircleBuf::Write - Write from the buffer into a FD                   /*{{{*/
165 // ---------------------------------------------------------------------
166 /* This empties the buffer into the FD. */
167 bool CircleBuf::Write(int Fd)
168 {
169    while (1)
170    {
171       FillOut();
172       
173       // Woops, buffer is empty
174       if (OutP == InP)
175          return true;
176       
177       if (OutP == MaxGet)
178          return true;
179       
180       // Write the buffer segment
181       int Res;
182       Res = write(Fd,Buf + (OutP%Size),LeftWrite());
183
184       if (Res == 0)
185          return false;
186       if (Res < 0)
187       {
188          if (errno == EAGAIN)
189             return true;
190          
191          return false;
192       }
193       
194       if (Hash != 0)
195          Hash->Add(Buf + (OutP%Size),Res);
196       
197       OutP += Res;
198    }
199 }
200                                                                         /*}}}*/
201 // CircleBuf::WriteTillEl - Write from the buffer to a string           /*{{{*/
202 // ---------------------------------------------------------------------
203 /* This copies till the first empty line */
204 bool CircleBuf::WriteTillEl(string &Data,bool Single)
205 {
206    // We cheat and assume it is unneeded to have more than one buffer load
207    for (unsigned long I = OutP; I < InP; I++)
208    {      
209       if (Buf[I%Size] != '\n')
210          continue;
211       for (I++; I < InP && Buf[I%Size] == '\r'; I++);
212       
213       if (Single == false)
214       {
215          if (Buf[I%Size] != '\n')
216             continue;
217          for (I++; I < InP && Buf[I%Size] == '\r'; I++);
218       }
219       
220       if (I > InP)
221          I = InP;
222       
223       Data = "";
224       while (OutP < I)
225       {
226          unsigned long Sz = LeftWrite();
227          if (Sz == 0)
228             return false;
229          if (I - OutP < LeftWrite())
230             Sz = I - OutP;
231          Data += string((char *)(Buf + (OutP%Size)),Sz);
232          OutP += Sz;
233       }
234       return true;
235    }      
236    return false;
237 }
238                                                                         /*}}}*/
239 // CircleBuf::Stats - Print out stats information                       /*{{{*/
240 // ---------------------------------------------------------------------
241 /* */
242 void CircleBuf::Stats()
243 {
244    if (InP == 0)
245       return;
246    
247    struct timeval Stop;
248    gettimeofday(&Stop,0);
249 /*   float Diff = Stop.tv_sec - Start.tv_sec + 
250              (float)(Stop.tv_usec - Start.tv_usec)/1000000;
251    clog << "Got " << InP << " in " << Diff << " at " << InP/Diff << endl;*/
252 }
253                                                                         /*}}}*/
254
255 // ServerState::ServerState - Constructor                               /*{{{*/
256 // ---------------------------------------------------------------------
257 /* */
258 ServerState::ServerState(URI Srv,HttpMethod *Owner) : Owner(Owner),
259                         In(64*1024), Out(4*1024),
260                         ServerName(Srv)
261 {
262    Reset();
263 }
264                                                                         /*}}}*/
265 // ServerState::Open - Open a connection to the server                  /*{{{*/
266 // ---------------------------------------------------------------------
267 /* This opens a connection to the server. */
268 bool ServerState::Open()
269 {
270    // Use the already open connection if possible.
271    if (ServerFd != -1)
272       return true;
273    
274    Close();
275    In.Reset();
276    Out.Reset();
277    Persistent = true;
278    
279    // Determine the proxy setting
280    if (getenv("http_proxy") == 0)
281    {
282       string DefProxy = _config->Find("Acquire::http::Proxy");
283       string SpecificProxy = _config->Find("Acquire::http::Proxy::" + ServerName.Host);
284       if (SpecificProxy.empty() == false)
285       {
286          if (SpecificProxy == "DIRECT")
287             Proxy = "";
288          else
289             Proxy = SpecificProxy;
290       }   
291       else
292          Proxy = DefProxy;
293    }
294    else
295       Proxy = getenv("http_proxy");
296    
297    // Parse no_proxy, a , separated list of domains
298    if (getenv("no_proxy") != 0)
299    {
300       if (CheckDomainList(ServerName.Host,getenv("no_proxy")) == true)
301          Proxy = "";
302    }
303    
304    // Determine what host and port to use based on the proxy settings
305    int Port = 0;
306    string Host;   
307    if (Proxy.empty() == true || Proxy.Host.empty() == true)
308    {
309       if (ServerName.Port != 0)
310          Port = ServerName.Port;
311       Host = ServerName.Host;
312    }
313    else
314    {
315       if (Proxy.Port != 0)
316          Port = Proxy.Port;
317       Host = Proxy.Host;
318    }
319    
320    // Connect to the remote server
321    if (Connect(Host,Port,"http",80,ServerFd,TimeOut,Owner) == false)
322       return false;
323    
324    return true;
325 }
326                                                                         /*}}}*/
327 // ServerState::Close - Close a connection to the server                /*{{{*/
328 // ---------------------------------------------------------------------
329 /* */
330 bool ServerState::Close()
331 {
332    close(ServerFd);
333    ServerFd = -1;
334    return true;
335 }
336                                                                         /*}}}*/
337 // ServerState::RunHeaders - Get the headers before the data            /*{{{*/
338 // ---------------------------------------------------------------------
339 /* Returns 0 if things are OK, 1 if an IO error occursed and 2 if a header
340    parse error occured */
341 int ServerState::RunHeaders()
342 {
343    State = Header;
344    
345    Owner->Status(_("Waiting for headers"));
346
347    Major = 0; 
348    Minor = 0; 
349    Result = 0; 
350    Size = 0; 
351    StartPos = 0;
352    Encoding = Closes;
353    HaveContent = false;
354    time(&Date);
355
356    do
357    {
358       string Data;
359       if (In.WriteTillEl(Data) == false)
360          continue;
361
362       if (Debug == true)
363          clog << Data;
364       
365       for (string::const_iterator I = Data.begin(); I < Data.end(); I++)
366       {
367          string::const_iterator J = I;
368          for (; J != Data.end() && *J != '\n' && *J != '\r';J++);
369          if (HeaderLine(string(I,J)) == false)
370             return 2;
371          I = J;
372       }
373
374       // 100 Continue is a Nop...
375       if (Result == 100)
376          continue;
377       
378       // Tidy up the connection persistance state.
379       if (Encoding == Closes && HaveContent == true)
380          Persistent = false;
381       
382       return 0;
383    }
384    while (Owner->Go(false,this) == true);
385    
386    return 1;
387 }
388                                                                         /*}}}*/
389 // ServerState::RunData - Transfer the data from the socket             /*{{{*/
390 // ---------------------------------------------------------------------
391 /* */
392 bool ServerState::RunData()
393 {
394    State = Data;
395    
396    // Chunked transfer encoding is fun..
397    if (Encoding == Chunked)
398    {
399       while (1)
400       {
401          // Grab the block size
402          bool Last = true;
403          string Data;
404          In.Limit(-1);
405          do
406          {
407             if (In.WriteTillEl(Data,true) == true)
408                break;
409          }
410          while ((Last = Owner->Go(false,this)) == true);
411
412          if (Last == false)
413             return false;
414                  
415          // See if we are done
416          unsigned long Len = strtol(Data.c_str(),0,16);
417          if (Len == 0)
418          {
419             In.Limit(-1);
420             
421             // We have to remove the entity trailer
422             Last = true;
423             do
424             {
425                if (In.WriteTillEl(Data,true) == true && Data.length() <= 2)
426                   break;
427             }
428             while ((Last = Owner->Go(false,this)) == true);
429             if (Last == false)
430                return false;
431             return !_error->PendingError();
432          }
433          
434          // Transfer the block
435          In.Limit(Len);
436          while (Owner->Go(true,this) == true)
437             if (In.IsLimit() == true)
438                break;
439          
440          // Error
441          if (In.IsLimit() == false)
442             return false;
443          
444          // The server sends an extra new line before the next block specifier..
445          In.Limit(-1);
446          Last = true;
447          do
448          {
449             if (In.WriteTillEl(Data,true) == true)
450                break;
451          }
452          while ((Last = Owner->Go(false,this)) == true);
453          if (Last == false)
454             return false;
455       }
456    }
457    else
458    {
459       /* Closes encoding is used when the server did not specify a size, the
460          loss of the connection means we are done */
461       if (Encoding == Closes)
462          In.Limit(-1);
463       else
464          In.Limit(Size - StartPos);
465       
466       // Just transfer the whole block.
467       do
468       {
469          if (In.IsLimit() == false)
470             continue;
471          
472          In.Limit(-1);
473          return !_error->PendingError();
474       }
475       while (Owner->Go(true,this) == true);
476    }
477
478    return Owner->Flush(this) && !_error->PendingError();
479 }
480                                                                         /*}}}*/
481 // ServerState::HeaderLine - Process a header line                      /*{{{*/
482 // ---------------------------------------------------------------------
483 /* */
484 bool ServerState::HeaderLine(string Line)
485 {
486    if (Line.empty() == true)
487       return true;
488
489    // The http server might be trying to do something evil.
490    if (Line.length() >= MAXLEN)
491       return _error->Error(_("Got a single header line over %u chars"),MAXLEN);
492
493    string::size_type Pos = Line.find(' ');
494    if (Pos == string::npos || Pos+1 > Line.length())
495    {
496       // Blah, some servers use "connection:closes", evil.
497       Pos = Line.find(':');
498       if (Pos == string::npos || Pos + 2 > Line.length())
499          return _error->Error(_("Bad header line"));
500       Pos++;
501    }
502
503    // Parse off any trailing spaces between the : and the next word.
504    string::size_type Pos2 = Pos;
505    while (Pos2 < Line.length() && isspace(Line[Pos2]) != 0)
506       Pos2++;
507       
508    string Tag = string(Line,0,Pos);
509    string Val = string(Line,Pos2);
510    
511    if (stringcasecmp(Tag.c_str(),Tag.c_str()+4,"HTTP") == 0)
512    {
513       // Evil servers return no version
514       if (Line[4] == '/')
515       {
516          if (sscanf(Line.c_str(),"HTTP/%u.%u %u %[^\n]",&Major,&Minor,
517                     &Result,Code) != 4)
518             return _error->Error(_("The http server sent an invalid reply header"));
519       }
520       else
521       {
522          Major = 0;
523          Minor = 9;
524          if (sscanf(Line.c_str(),"HTTP %u %[^\n]",&Result,Code) != 2)
525             return _error->Error(_("The http server sent an invalid reply header"));
526       }
527
528       /* Check the HTTP response header to get the default persistance
529          state. */
530       if (Major < 1)
531          Persistent = false;
532       else
533       {
534          if (Major == 1 && Minor <= 0)
535             Persistent = false;
536          else
537             Persistent = true;
538       }
539
540       return true;
541    }      
542       
543    if (stringcasecmp(Tag,"Content-Length:") == 0)
544    {
545       if (Encoding == Closes)
546          Encoding = Stream;
547       HaveContent = true;
548       
549       // The length is already set from the Content-Range header
550       if (StartPos != 0)
551          return true;
552       
553       if (sscanf(Val.c_str(),"%lu",&Size) != 1)
554          return _error->Error(_("The http server sent an invalid Content-Length header"));
555       return true;
556    }
557
558    if (stringcasecmp(Tag,"Content-Type:") == 0)
559    {
560       HaveContent = true;
561       return true;
562    }
563    
564    if (stringcasecmp(Tag,"Content-Range:") == 0)
565    {
566       HaveContent = true;
567       
568       if (sscanf(Val.c_str(),"bytes %lu-%*u/%lu",&StartPos,&Size) != 2)
569          return _error->Error(_("The http server sent an invalid Content-Range header"));
570       if ((unsigned)StartPos > Size)
571          return _error->Error(_("This http server has broken range support"));
572       return true;
573    }
574    
575    if (stringcasecmp(Tag,"Transfer-Encoding:") == 0)
576    {
577       HaveContent = true;
578       if (stringcasecmp(Val,"chunked") == 0)
579          Encoding = Chunked;      
580       return true;
581    }
582
583    if (stringcasecmp(Tag,"Connection:") == 0)
584    {
585       if (stringcasecmp(Val,"close") == 0)
586          Persistent = false;
587       if (stringcasecmp(Val,"keep-alive") == 0)
588          Persistent = true;
589       return true;
590    }
591    
592    if (stringcasecmp(Tag,"Last-Modified:") == 0)
593    {
594       if (StrToTime(Val,Date) == false)
595          return _error->Error(_("Unknown date format"));
596       return true;
597    }
598
599    if (stringcasecmp(Tag,"Location:") == 0)
600    {
601       Location = Val;
602       return true;
603    }
604
605    if (stringcasecmp(Tag,"WWW-Authenticate:") == 0 ||
606        stringcasecmp(Tag,"Proxy-Authenticate:") == 0)
607    {
608       string::size_type SplitPoint = Val.find(' ');
609       string AuthType = Val.substr(0, SplitPoint);
610       string RealmStr = Val.substr(SplitPoint + 1, 
611                                    Val.length() - SplitPoint - 1);
612       SplitPoint = RealmStr.find('=');
613       string FoundRealm = RealmStr.substr(SplitPoint, 
614                                           RealmStr.length() - SplitPoint);
615
616       if (stringcasecmp(Tag,"WWW-Authenticate:") == 0)
617          Realm = FoundRealm;
618       else
619          ProxyRealm = FoundRealm;
620
621       return true;
622    }
623
624    return true;
625 }
626                                                                         /*}}}*/
627
628 // HttpMethod::SendReq - Send the HTTP request                          /*{{{*/
629 // ---------------------------------------------------------------------
630 /* This places the http request in the outbound buffer */
631 void HttpMethod::SendReq(FetchItem *Itm,CircleBuf &Out)
632 {
633    URI Uri = Itm->Uri;
634
635    // The HTTP server expects a hostname with a trailing :port
636    char Buf[1000];
637    string ProperHost = Uri.Host;
638    if (Uri.Port != 0)
639    {
640       sprintf(Buf,":%u",Uri.Port);
641       ProperHost += Buf;
642    }   
643       
644    // Just in case.
645    if (Itm->Uri.length() >= sizeof(Buf))
646        abort();
647        
648    /* Build the request. We include a keep-alive header only for non-proxy
649       requests. This is to tweak old http/1.0 servers that do support keep-alive
650       but not HTTP/1.1 automatic keep-alive. Doing this with a proxy server 
651       will glitch HTTP/1.0 proxies because they do not filter it out and 
652       pass it on, HTTP/1.1 says the connection should default to keep alive
653       and we expect the proxy to do this */
654    if (Proxy.empty() == true)
655       sprintf(Buf,"GET %s HTTP/1.1\r\nHost: %s\r\nConnection: keep-alive\r\n",
656               QuoteString(Uri.Path,"~").c_str(),ProperHost.c_str());
657    else
658    {
659       /* Generate a cache control header if necessary. We place a max
660          cache age on index files, optionally set a no-cache directive
661          and a no-store directive for archives. */
662       sprintf(Buf,"GET %s HTTP/1.1\r\nHost: %s\r\n",
663               Itm->Uri.c_str(),ProperHost.c_str());
664       if (_config->FindB("Acquire::http::No-Cache",false) == true)
665          strcat(Buf,"Cache-Control: no-cache\r\nPragma: no-cache\r\n");
666       else
667       {
668          if (Itm->IndexFile == true)
669             sprintf(Buf+strlen(Buf),"Cache-Control: max-age=%u\r\n",
670                     _config->FindI("Acquire::http::Max-Age",60*60*24));
671          else
672          {
673             if (_config->FindB("Acquire::http::No-Store",false) == true)
674                strcat(Buf,"Cache-Control: no-store\r\n");
675          }       
676       }
677    }
678    
679    string Req = Buf;
680
681    // Check for a partial file
682    struct stat SBuf;
683    if (stat(Itm->DestFile.c_str(),&SBuf) >= 0 && SBuf.st_size > 0)
684    {
685       // In this case we send an if-range query with a range header
686       sprintf(Buf,"Range: bytes=%li-\r\nIf-Range: %s\r\n",(long)SBuf.st_size - 1,
687               TimeRFC1123(SBuf.st_mtime).c_str());
688       Req += Buf;
689    }
690    else
691    {
692       if (Itm->LastModified != 0)
693       {
694          sprintf(Buf,"If-Modified-Since: %s\r\n",TimeRFC1123(Itm->LastModified).c_str());
695          Req += Buf;
696       }
697    }
698
699    if (Proxy.User.empty() == false || Proxy.Password.empty() == false)
700       Req += string("Proxy-Authorization: Basic ") + 
701           Base64Encode(Proxy.User + ":" + Proxy.Password) + "\r\n";
702
703    if (Uri.User.empty() == false || Uri.Password.empty() == false)
704       Req += string("Authorization: Basic ") + 
705           Base64Encode(Uri.User + ":" + Uri.Password) + "\r\n";
706
707    // CNC:2003-01-29
708    string UserAgent = _config->Find("Acquire::http::User-Agent");
709    if (UserAgent.empty() == true) 
710           UserAgent = "RPM APT-HTTP/1.3";
711    Req += string("User-Agent: ") + UserAgent + "\r\n\r\n";
712    
713    if (Debug == true)
714       cerr << Req << endl;
715
716    Out.Read(Req);
717 }
718                                                                         /*}}}*/
719 // HttpMethod::Go - Run a single loop                                   /*{{{*/
720 // ---------------------------------------------------------------------
721 /* This runs the select loop over the server FDs, Output file FDs and
722    stdin. */
723 bool HttpMethod::Go(bool ToFile,ServerState *Srv)
724 {
725    // Server has closed the connection
726    if (Srv->ServerFd == -1 && (Srv->In.WriteSpace() == false || 
727                                ToFile == false))
728       return false;
729    
730    fd_set rfds,wfds;
731    FD_ZERO(&rfds);
732    FD_ZERO(&wfds);
733    
734    /* Add the server. We only send more requests if the connection will 
735       be persisting */
736    if (Srv->Out.WriteSpace() == true && Srv->ServerFd != -1 
737        && Srv->Persistent == true)
738       FD_SET(Srv->ServerFd,&wfds);
739    if (Srv->In.ReadSpace() == true && Srv->ServerFd != -1)
740       FD_SET(Srv->ServerFd,&rfds);
741    
742    // Add the file
743    int FileFD = -1;
744    if (File != 0)
745       FileFD = File->Fd();
746    
747    if (Srv->In.WriteSpace() == true && ToFile == true && FileFD != -1)
748       FD_SET(FileFD,&wfds);
749    
750    // Add stdin
751    FD_SET(STDIN_FILENO,&rfds);
752           
753    // Figure out the max fd
754    int MaxFd = FileFD;
755    if (MaxFd < Srv->ServerFd)
756       MaxFd = Srv->ServerFd;
757
758    // Select
759    struct timeval tv;
760    tv.tv_sec = TimeOut;
761    tv.tv_usec = 0;
762    int Res = 0;
763    if ((Res = select(MaxFd+1,&rfds,&wfds,0,&tv)) < 0)
764    {
765       if (errno == EINTR)
766          return true;
767       return _error->Errno("select",_("Select failed"));
768    }
769    
770    if (Res == 0)
771    {
772       _error->Error(_("Connection timed out"));
773       return ServerDie(Srv);
774    }
775    
776    // Handle server IO
777    if (Srv->ServerFd != -1 && FD_ISSET(Srv->ServerFd,&rfds))
778    {
779       errno = 0;
780       if (Srv->In.Read(Srv->ServerFd) == false)
781          return ServerDie(Srv);
782    }
783          
784    if (Srv->ServerFd != -1 && FD_ISSET(Srv->ServerFd,&wfds))
785    {
786       errno = 0;
787       if (Srv->Out.Write(Srv->ServerFd) == false)
788          return ServerDie(Srv);
789    }
790
791    // Send data to the file
792    if (FileFD != -1 && FD_ISSET(FileFD,&wfds))
793    {
794       if (Srv->In.Write(FileFD) == false)
795          return _error->Errno("write",_("Error writing to output file"));
796    }
797
798    // Handle commands from APT
799    if (FD_ISSET(STDIN_FILENO,&rfds))
800    {
801       if (Run(true) != -1)
802          exit(100);
803    }   
804        
805    return true;
806 }
807                                                                         /*}}}*/
808 // HttpMethod::Flush - Dump the buffer into the file                    /*{{{*/
809 // ---------------------------------------------------------------------
810 /* This takes the current input buffer from the Server FD and writes it
811    into the file */
812 bool HttpMethod::Flush(ServerState *Srv)
813 {
814    if (File != 0)
815    {
816       SetNonBlock(File->Fd(),false);
817       if (Srv->In.WriteSpace() == false)
818          return true;
819       
820       while (Srv->In.WriteSpace() == true)
821       {
822          if (Srv->In.Write(File->Fd()) == false)
823             return _error->Errno("write",_("Error writing to file"));
824          if (Srv->In.IsLimit() == true)
825             return true;
826       }
827
828       if (Srv->In.IsLimit() == true || Srv->Encoding == ServerState::Closes)
829          return true;
830    }
831    return false;
832 }
833                                                                         /*}}}*/
834 // HttpMethod::ServerDie - The server has closed the connection.        /*{{{*/
835 // ---------------------------------------------------------------------
836 /* */
837 bool HttpMethod::ServerDie(ServerState *Srv)
838 {
839    unsigned int LErrno = errno;
840    
841    // Dump the buffer to the file
842    if (Srv->State == ServerState::Data)
843    {
844       SetNonBlock(File->Fd(),false);
845       while (Srv->In.WriteSpace() == true)
846       {
847          if (Srv->In.Write(File->Fd()) == false)
848             return _error->Errno("write",_("Error writing to the file"));
849
850          // Done
851          if (Srv->In.IsLimit() == true)
852             return true;
853       }
854    }
855    
856    // See if this is because the server finished the data stream
857    if (Srv->In.IsLimit() == false && Srv->State != ServerState::Header && 
858        Srv->Encoding != ServerState::Closes)
859    {
860       Srv->Close();
861       if (LErrno == 0)
862          return _error->Error(_("Error reading from server Remote end closed connection"));
863       errno = LErrno;
864       return _error->Errno("read",_("Error reading from server"));
865    }
866    else
867    {
868       Srv->In.Limit(-1);
869
870       // Nothing left in the buffer
871       if (Srv->In.WriteSpace() == false)
872          return false;
873       
874       // We may have got multiple responses back in one packet..
875       Srv->Close();
876       return true;
877    }
878    
879    return false;
880 }
881                                                                         /*}}}*/
882 // HttpMethod::DealWithHeaders - Handle the retrieved header data       /*{{{*/
883 // ---------------------------------------------------------------------
884 /* We look at the header data we got back from the server and decide what
885    to do. Returns 
886      0 - File is open,
887      1 - IMS hit
888      3 - Unrecoverable error 
889      4 - Error with error content page
890      5 - Unrecoverable non-server error (close the connection)
891      6 - Try again with a new or changed URI  */
892 int HttpMethod::DealWithHeaders(FetchResult &Res,ServerState *Srv)
893 {
894    // Not Modified
895    if (Srv->Result == 304)
896    {
897       unlink(Queue->DestFile.c_str());
898       Res.IMSHit = true;
899       Res.LastModified = Queue->LastModified;
900       return 1;
901    }
902
903    /* Redirect
904     *
905     * Note that it is only OK for us to treat all redirection the same
906     * because we *always* use GET, not other HTTP methods.  There are
907     * three redirection codes for which it is not appropriate that we
908     * redirect.  Pass on those codes so the error handling kicks in.
909     */
910    if ((Srv->Result > 300 && Srv->Result < 400)
911        && (Srv->Result != 300       // Multiple Choices
912            && Srv->Result != 304    // Not Modified
913            && Srv->Result != 306))  // (Not part of HTTP/1.1, reserved)
914    {
915       if (!Srv->Location.empty())
916       {
917          NextURI = Srv->Location;
918          return 6;
919       }
920       else
921          return 3;
922    }
923
924    // Authentication
925    if (Srv->Result == 401)
926    {
927       string Description;
928       string AuthUser, AuthPass;
929       vector<AuthRec>::iterator CurrentAuth;
930       URI ParsedURI(Queue->Uri);
931
932       // Have we had to log in to this site before?
933       if (ParsedURI.User.empty())
934       {
935          for (CurrentAuth = AuthList.begin(); CurrentAuth != AuthList.end();
936               CurrentAuth++)
937             if (CurrentAuth->Host == Srv->ServerName.Host &&
938                 CurrentAuth->Realm == Srv->Realm)
939             {
940                AuthUser = CurrentAuth->User;
941                AuthPass = CurrentAuth->Password;
942                break;
943             }
944       }
945       else
946          CurrentAuth = AuthList.end();
947
948       // Nope - get username and password
949       if (CurrentAuth == AuthList.end())
950       {
951          Description = ParsedURI.Host + ":" + Srv->Realm;
952
953 #ifdef WITH_SSL
954          if (ParsedURI.Access == "https")
955             Description += string(" (secure)");
956 #endif
957
958          if (NeedAuth(Description, AuthUser, AuthPass) == true)
959          {
960             // Got new credentials; save them
961             AuthRec NewAuthInfo;
962
963             NewAuthInfo.Host = Srv->ServerName.Host;
964             NewAuthInfo.Realm = Srv->Realm;
965             NewAuthInfo.User = AuthUser;
966             NewAuthInfo.Password = AuthPass;
967
968             for (CurrentAuth = AuthList.begin(); CurrentAuth != AuthList.end();
969                  CurrentAuth++)
970                if (CurrentAuth->Host == Srv->ServerName.Host &&
971                    CurrentAuth->Realm == Srv->Realm)
972                {
973                   *CurrentAuth = NewAuthInfo;
974                   break;
975                }
976             
977             if (CurrentAuth == AuthList.end())
978                AuthList.push_back(NewAuthInfo);
979          }
980          else
981             // Interactive auth failed
982             return 4;
983       }
984
985       // Try the same URI again, with credentials this time
986       ParsedURI.User = AuthUser;
987       ParsedURI.Password = AuthPass;
988       NextURI = ParsedURI;
989       return 6;
990    }
991
992    /* We have a reply we dont handle. This should indicate a perm server
993       failure */
994    if (Srv->Result < 200 || Srv->Result >= 300)
995    {
996       _error->Error("%u %s",Srv->Result,Srv->Code);
997       if (Srv->HaveContent == true)
998          return 4;
999       return 3;
1000    }
1001
1002    // This is some sort of 2xx 'data follows' reply
1003    Res.LastModified = Srv->Date;
1004    Res.Size = Srv->Size;
1005    
1006    // Open the file
1007    delete File;
1008    File = new FileFd(Queue->DestFile,FileFd::WriteAny);
1009    if (_error->PendingError() == true)
1010       return 5;
1011
1012    FailFile = Queue->DestFile;
1013    FailFile.c_str();   // Make sure we dont do a malloc in the signal handler
1014    FailFd = File->Fd();
1015    FailTime = Srv->Date;
1016       
1017    // Set the expected size
1018    if (Srv->StartPos >= 0)
1019    {
1020       Res.ResumePoint = Srv->StartPos;
1021       ftruncate(File->Fd(),Srv->StartPos);
1022    }
1023       
1024    // Set the start point
1025    lseek(File->Fd(),0,SEEK_END);
1026
1027    delete Srv->In.Hash;
1028    Srv->In.Hash = new Hashes;
1029    
1030    // Fill the Hash if the file is non-empty (resume)
1031    if (Srv->StartPos > 0)
1032    {
1033       lseek(File->Fd(),0,SEEK_SET);
1034       if (Srv->In.Hash->AddFD(File->Fd(),Srv->StartPos) == false)
1035       {
1036          _error->Errno("read",_("Problem hashing file"));
1037          return 5;
1038       }
1039       lseek(File->Fd(),0,SEEK_END);
1040    }
1041    
1042    SetNonBlock(File->Fd(),true);
1043    return 0;
1044 }
1045                                                                         /*}}}*/
1046 // HttpMethod::SigTerm - Handle a fatal signal                          /*{{{*/
1047 // ---------------------------------------------------------------------
1048 /* This closes and timestamps the open file. This is neccessary to get 
1049    resume behavoir on user abort */
1050 void HttpMethod::SigTerm(int)
1051 {
1052    if (FailFd == -1)
1053       _exit(100);
1054    close(FailFd);
1055    
1056    // Timestamp
1057    struct utimbuf UBuf;
1058    UBuf.actime = FailTime;
1059    UBuf.modtime = FailTime;
1060    utime(FailFile.c_str(),&UBuf);
1061    
1062    _exit(100);
1063 }
1064                                                                         /*}}}*/
1065 // HttpMethod::Fetch - Fetch an item                                    /*{{{*/
1066 // ---------------------------------------------------------------------
1067 /* This adds an item to the pipeline. We keep the pipeline at a fixed
1068    depth. */
1069 bool HttpMethod::Fetch(FetchItem *)
1070 {
1071    if (Server == 0)
1072       return true;
1073
1074    // Queue the requests
1075    int Depth = -1;
1076    bool Tail = false;
1077    for (FetchItem *I = Queue; I != 0 && Depth < (signed)PipelineDepth; 
1078         I = I->Next, Depth++)
1079    {
1080       // If pipelining is disabled, we only queue 1 request
1081       if (Server->Pipeline == false && Depth >= 0)
1082          break;
1083
1084       // If we're choking the pipeline, we only queue 1 request
1085       if (ChokePipe == true && Depth >= 0)
1086       {
1087          ChokePipe = false;
1088          break;
1089       }
1090       
1091       // Make sure we stick with the same server
1092       if (Server->Comp(I->Uri) == false)
1093       {
1094          ChokePipe = true;
1095          break;
1096       }
1097
1098       if (QueueBack == I)
1099          Tail = true;
1100       if (Tail == true)
1101       {
1102          QueueBack = I->Next;
1103          SendReq(I,Server->Out);
1104          continue;
1105       }
1106    }
1107    
1108    return true;
1109 };
1110                                                                         /*}}}*/
1111 // HttpMethod::Configuration - Handle a configuration message           /*{{{*/
1112 // ---------------------------------------------------------------------
1113 /* We stash the desired pipeline depth */
1114 bool HttpMethod::Configuration(string Message)
1115 {
1116    if (pkgAcqMethod::Configuration(Message) == false)
1117       return false;
1118    
1119    TimeOut = _config->FindI("Acquire::http::Timeout",TimeOut);
1120    PipelineDepth = _config->FindI("Acquire::http::Pipeline-Depth",
1121                                   PipelineDepth);
1122    Debug = _config->FindB("Debug::Acquire::http",false);
1123    
1124    return true;
1125 }
1126                                                                         /*}}}*/
1127 // HttpMethod::Loop - Main loop                                         /*{{{*/
1128 // ---------------------------------------------------------------------
1129 /* */
1130 int HttpMethod::Loop()
1131 {
1132    typedef vector<string> StringVector;
1133    typedef vector<string>::iterator StringVectorIterator;
1134    map<string, StringVector> Redirected;
1135
1136    signal(SIGTERM,SigTerm);
1137    signal(SIGINT,SigTerm);
1138    
1139    Server = 0;
1140    
1141    int FailCounter = 0;
1142
1143    while (1)
1144    {      
1145       // We have no commands, wait for some to arrive
1146       if (Queue == 0)
1147       {
1148          if (WaitFd(STDIN_FILENO) == false)
1149             return 0;
1150       }
1151       
1152       /* Run messages, we can accept 0 (no message) if we didn't
1153          do a WaitFd above.. Otherwise the FD is closed. */
1154       int Result = Run(true);
1155       if (Result != -1 && (Result != 0 || Queue == 0))
1156          return 100;
1157
1158       if (Queue == 0)
1159          continue;
1160       
1161       // Connect to the server
1162       if (Server == 0 || Server->Comp(Queue->Uri) == false)
1163       {
1164          delete Server;
1165          Server = new ServerState(Queue->Uri,this);
1166       }
1167       
1168       /* If the server has explicitly said this is the last connection
1169          then we pre-emptively shut down the pipeline and tear down 
1170          the connection. This will speed up HTTP/1.0 servers a tad
1171          since we don't have to wait for the close sequence to
1172          complete */
1173       if (Server->Persistent == false)
1174          Server->Close();
1175       
1176       // Reset the pipeline
1177       if (Server->ServerFd == -1)
1178          QueueBack = Queue;      
1179          
1180       // Connnect to the host
1181       if (Server->Open() == false)
1182       {
1183          Fail(true);
1184          delete Server;
1185          Server = 0;
1186          continue;
1187       }
1188
1189       // Fill the pipeline.
1190       Fetch(0);
1191       
1192       // Fetch the next URL header data from the server.
1193       switch (Server->RunHeaders())
1194       {
1195          case 0:
1196          break;
1197          
1198          // The header data is bad
1199          case 2:
1200          {
1201             _error->Error(_("Bad header Data"));
1202             Fail(true);
1203             RotateDNS();
1204             continue;
1205          }
1206          
1207          // The server closed a connection during the header get..
1208          default:
1209          case 1:
1210          {
1211             FailCounter++;
1212             _error->Discard();
1213             Server->Close();
1214             Server->Pipeline = false;
1215             
1216             if (FailCounter >= 2)
1217             {
1218                Fail(_("Connection failed"),true);
1219                FailCounter = 0;
1220             }
1221             
1222             RotateDNS();
1223             continue;
1224          }
1225       };
1226
1227       // Decide what to do.
1228       FetchResult Res;
1229       Res.Filename = Queue->DestFile;
1230       switch (DealWithHeaders(Res,Server))
1231       {
1232          // Ok, the file is Open
1233          case 0:
1234          {
1235             URIStart(Res);
1236
1237             // Run the data
1238             bool Result =  Server->RunData();
1239
1240             /* If the server is sending back sizeless responses then fill in
1241                the size now */
1242             if (Res.Size == 0)
1243                Res.Size = File->Size();
1244             
1245             // Close the file, destroy the FD object and timestamp it
1246             FailFd = -1;
1247             delete File;
1248             File = 0;
1249             
1250             // Timestamp
1251             struct utimbuf UBuf;
1252             time(&UBuf.actime);
1253             UBuf.actime = Server->Date;
1254             UBuf.modtime = Server->Date;
1255             utime(Queue->DestFile.c_str(),&UBuf);
1256
1257             // Send status to APT
1258             if (Result == true)
1259             {
1260                Res.TakeHashes(*Server->In.Hash);
1261                URIDone(Res);
1262             }
1263             else
1264                Fail(true);
1265             
1266             break;
1267          }
1268          
1269          // IMS hit
1270          case 1:
1271          {
1272             URIDone(Res);
1273             break;
1274          }
1275          
1276          // Hard server error, not found or something
1277          case 3:
1278          {
1279             Fail();
1280             break;
1281          }
1282           
1283          // Hard internal error, kill the connection and fail
1284          case 5:
1285          {
1286             delete File;
1287             File = 0;
1288
1289             Fail();
1290             RotateDNS();
1291             Server->Close();
1292             break;
1293          }
1294
1295          // We need to flush the data, the header is like a 404 w/ error text
1296          case 4:
1297          {
1298             Fail();
1299             
1300             // Send to content to dev/null
1301             File = new FileFd("/dev/null",FileFd::WriteExists);
1302             Server->RunData();
1303             delete File;
1304             File = 0;
1305             break;
1306          }
1307
1308          // Try again with a new URL
1309          case 6:
1310          {
1311             // Clear rest of response if there is content
1312             if (Server->HaveContent)
1313             {
1314                File = new FileFd("/dev/null",FileFd::WriteExists);
1315                Server->RunData();
1316                delete File;
1317                File = 0;
1318             }
1319
1320             /* Detect redirect loops.  No more redirects are allowed
1321                after the same URI is seen twice in a queue item. */
1322             StringVector &R = Redirected[Queue->DestFile];
1323             bool StopRedirects = false;
1324             if (R.size() == 0)
1325                R.push_back(Queue->Uri);
1326             else if (R[0] == "STOP")
1327                StopRedirects = true;
1328             else
1329             {
1330                for (StringVectorIterator I = R.begin(); I != R.end(); I++)
1331                   if (Queue->Uri == *I)
1332                   {
1333                      R[0] = "STOP";
1334                      break;
1335                   }
1336
1337                R.push_back(Queue->Uri);
1338             }
1339
1340             if (StopRedirects == false)
1341                Redirect(NextURI);
1342             else
1343                Fail();
1344
1345             break;
1346          }
1347          
1348          default:
1349          Fail(_("Internal error"));
1350          break;
1351       }
1352       
1353       FailCounter = 0;
1354    }
1355    
1356    return 0;
1357 }
1358                                                                         /*}}}*/
1359
1360 int main()
1361 {
1362    HttpMethod Mth;
1363    
1364    return Mth.Loop();
1365 }
1366
1367