4e659ccd625b929de6cc7ba3e78cce7a7439d235
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: http.cc,v 1.33 1999/05/28 07:04:45 jgg Exp $
4 /* ######################################################################
6 HTTP Aquire Method - This is the HTTP aquire method for APT.
8 It uses HTTP/1.1 and many of the fancy options there-in, such as
9 pipelining, range, if-range and so on. It accepts on the command line
10 a list of url destination pairs and writes to stdout the status of the
11 operation as defined in the APT method spec.
13 It is based on a doubly buffered select loop. All the requests are
14 fed into a single output buffer that is constantly fed out the
15 socket. This provides ideal pipelining as in many cases all of the
16 requests will fit into a single packet. The input socket is buffered
17 the same way and fed into the fd for the file.
19 This double buffering provides fairly substantial transfer rates,
20 compared to wget the http method is about 4% faster. Most importantly,
21 when HTTP is compared with FTP as a protocol the speed difference is
22 huge. In tests over the internet from two sites to llug (via ATM) this
23 program got 230k/s sustained http transfer rates. FTP on the other
24 hand topped out at 170k/s. That combined with the time to setup the
25 FTP connection makes HTTP a vastly superior protocol.
27 ##################################################################### */
29 // Include Files /*{{{*/
30 #include <apt-pkg/fileutl.h>
31 #include <apt-pkg/acquire-method.h>
32 #include <apt-pkg/error.h>
33 #include <apt-pkg/md5.h>
44 /*#include <netinet/in.h>
45 #include <sys/socket.h>
46 #include <arpa/inet.h>
49 #include "rfc2553emu.h"
54 string
HttpMethod::FailFile
;
55 int HttpMethod::FailFd
= -1;
56 time_t HttpMethod::FailTime
= 0;
57 unsigned long PipelineDepth
= 10;
58 unsigned long TimeOut
= 120;
60 // CircleBuf::CircleBuf - Circular input buffer /*{{{*/
61 // ---------------------------------------------------------------------
63 CircleBuf::CircleBuf(unsigned long Size
) : Size(Size
), MD5(0)
65 Buf
= new unsigned char[Size
];
69 // CircleBuf::Reset - Reset to the default state /*{{{*/
70 // ---------------------------------------------------------------------
72 void CircleBuf::Reset()
77 MaxGet
= (unsigned int)-1;
82 MD5
= new MD5Summation
;
86 // CircleBuf::Read - Read from a FD into the circular buffer /*{{{*/
87 // ---------------------------------------------------------------------
88 /* This fills up the buffer with as much data as is in the FD, assuming it
90 bool CircleBuf::Read(int Fd
)
94 // Woops, buffer is full
95 if (InP
- OutP
== Size
)
98 // Write the buffer segment
100 Res
= read(Fd
,Buf
+ (InP
%Size
),LeftRead());
112 gettimeofday(&Start
,0);
117 // CircleBuf::Read - Put the string into the buffer /*{{{*/
118 // ---------------------------------------------------------------------
119 /* This will hold the string in and fill the buffer with it as it empties */
120 bool CircleBuf::Read(string Data
)
127 // CircleBuf::FillOut - Fill the buffer from the output queue /*{{{*/
128 // ---------------------------------------------------------------------
130 void CircleBuf::FillOut()
132 if (OutQueue
.empty() == true)
136 // Woops, buffer is full
137 if (InP
- OutP
== Size
)
140 // Write the buffer segment
141 unsigned long Sz
= LeftRead();
142 if (OutQueue
.length() - StrPos
< Sz
)
143 Sz
= OutQueue
.length() - StrPos
;
144 memcpy(Buf
+ (InP
%Size
),OutQueue
.begin() + StrPos
,Sz
);
149 if (OutQueue
.length() == StrPos
)
158 // CircleBuf::Write - Write from the buffer into a FD /*{{{*/
159 // ---------------------------------------------------------------------
160 /* This empties the buffer into the FD. */
161 bool CircleBuf::Write(int Fd
)
167 // Woops, buffer is empty
174 // Write the buffer segment
176 Res
= write(Fd
,Buf
+ (OutP
%Size
),LeftWrite());
189 MD5
->Add(Buf
+ (OutP
%Size
),Res
);
195 // CircleBuf::WriteTillEl - Write from the buffer to a string /*{{{*/
196 // ---------------------------------------------------------------------
197 /* This copies till the first empty line */
198 bool CircleBuf::WriteTillEl(string
&Data
,bool Single
)
200 // We cheat and assume it is unneeded to have more than one buffer load
201 for (unsigned long I
= OutP
; I
< InP
; I
++)
203 if (Buf
[I
%Size
] != '\n')
205 for (I
++; I
< InP
&& Buf
[I
%Size
] == '\r'; I
++);
209 if (Buf
[I
%Size
] != '\n')
211 for (I
++; I
< InP
&& Buf
[I
%Size
] == '\r'; I
++);
220 unsigned long Sz
= LeftWrite();
223 if (I
- OutP
< LeftWrite())
225 Data
+= string((char *)(Buf
+ (OutP
%Size
)),Sz
);
233 // CircleBuf::Stats - Print out stats information /*{{{*/
234 // ---------------------------------------------------------------------
236 void CircleBuf::Stats()
242 gettimeofday(&Stop
,0);
243 /* float Diff = Stop.tv_sec - Start.tv_sec +
244 (float)(Stop.tv_usec - Start.tv_usec)/1000000;
245 clog << "Got " << InP << " in " << Diff << " at " << InP/Diff << endl;*/
249 // ServerState::ServerState - Constructor /*{{{*/
250 // ---------------------------------------------------------------------
252 ServerState::ServerState(URI Srv
,HttpMethod
*Owner
) : Owner(Owner
),
253 In(64*1024), Out(4*1024),
259 // ServerState::Open - Open a connection to the server /*{{{*/
260 // ---------------------------------------------------------------------
261 /* This opens a connection to the server. */
264 struct addrinfo
*LastHostAddr
= 0;
265 bool ServerState::Open()
267 // Use the already open connection if possible.
275 // Determine the proxy setting
276 if (getenv("http_proxy") == 0)
278 string DefProxy
= _config
->Find("Acquire::http::Proxy");
279 string SpecificProxy
= _config
->Find("Acquire::http::Proxy::" + ServerName
.Host
);
280 if (SpecificProxy
.empty() == false)
282 if (SpecificProxy
== "DIRECT")
285 Proxy
= SpecificProxy
;
291 Proxy
= getenv("http_proxy");
293 // Determine what host and port to use based on the proxy settings
296 if (Proxy
.empty() == true)
298 if (ServerName
.Port
!= 0)
299 Port
= ServerName
.Port
;
300 Host
= ServerName
.Host
;
309 /* We used a cached address record.. Yes this is against the spec but
310 the way we have setup our rotating dns suggests that this is more
312 if (LastHost
!= Host
|| LastPort
!= Port
)
314 Owner
->Status("Connecting to %s",Host
.c_str());
319 snprintf(S
,sizeof(S
),"%u",Port
);
321 // Free the old address structure
322 if (LastHostAddr
!= 0)
324 freeaddrinfo(LastHostAddr
);
328 // We only understand SOCK_STREAM sockets.
329 struct addrinfo Hints
;
330 memset(&Hints
,0,sizeof(Hints
));
331 Hints
.ai_socktype
= SOCK_STREAM
;
333 // Resolve both the host and service simultaneously
334 if (getaddrinfo(Host
.c_str(),S
,&Hints
,&LastHostAddr
) != 0 ||
336 return _error
->Error("Could not resolve '%s'",Host
.c_str());
342 // Get the printable IP address
343 char Name
[NI_MAXHOST
];
345 getnameinfo(LastHostAddr
->ai_addr
,LastHostAddr
->ai_addrlen
,
346 Name
,sizeof(Name
),0,0,NI_NUMERICHOST
);
347 Owner
->Status("Connecting to %s (%s)",Host
.c_str(),Name
);
350 if ((ServerFd
= socket(LastHostAddr
->ai_family
,LastHostAddr
->ai_socktype
,
351 LastHostAddr
->ai_protocol
)) < 0)
352 return _error
->Errno("socket","Could not create a socket");
353 SetNonBlock(ServerFd
,true);
354 if (connect(ServerFd
,LastHostAddr
->ai_addr
,LastHostAddr
->ai_addrlen
) < 0 &&
355 errno
!= EINPROGRESS
)
356 return _error
->Errno("connect","Cannot initiate the connection "
357 "to %s (%s).",Host
.c_str(),Name
);
359 /* This implements a timeout for connect by opening the connection
361 if (WaitFd(ServerFd
,true,TimeOut
) == false)
362 return _error
->Error("Could not connect to %s (%s), "
363 "connection timed out",Host
.c_str(),Name
);
365 unsigned int Len
= sizeof(Err
);
366 if (getsockopt(ServerFd
,SOL_SOCKET
,SO_ERROR
,&Err
,&Len
) != 0)
367 return _error
->Errno("getsockopt","Failed");
369 return _error
->Error("Could not connect to %s (%s).",Host
.c_str(),Name
);
374 // ServerState::Close - Close a connection to the server /*{{{*/
375 // ---------------------------------------------------------------------
377 bool ServerState::Close()
384 // ServerState::RunHeaders - Get the headers before the data /*{{{*/
385 // ---------------------------------------------------------------------
386 /* Returns 0 if things are OK, 1 if an IO error occursed and 2 if a header
387 parse error occured */
388 int ServerState::RunHeaders()
392 Owner
->Status("Waiting for file");
406 if (In
.WriteTillEl(Data
) == false)
409 for (string::const_iterator I
= Data
.begin(); I
< Data
.end(); I
++)
411 string::const_iterator J
= I
;
412 for (; J
!= Data
.end() && *J
!= '\n' && *J
!= '\r';J
++);
413 if (HeaderLine(string(I
,J
-I
)) == false)
419 while (Owner
->Go(false,this) == true);
424 // ServerState::RunData - Transfer the data from the socket /*{{{*/
425 // ---------------------------------------------------------------------
427 bool ServerState::RunData()
431 // Chunked transfer encoding is fun..
432 if (Encoding
== Chunked
)
436 // Grab the block size
442 if (In
.WriteTillEl(Data
,true) == true)
445 while ((Last
= Owner
->Go(false,this)) == true);
450 // See if we are done
451 unsigned long Len
= strtol(Data
.c_str(),0,16);
456 // We have to remove the entity trailer
460 if (In
.WriteTillEl(Data
,true) == true && Data
.length() <= 2)
463 while ((Last
= Owner
->Go(false,this)) == true);
466 return !_error
->PendingError();
469 // Transfer the block
471 while (Owner
->Go(true,this) == true)
472 if (In
.IsLimit() == true)
476 if (In
.IsLimit() == false)
479 // The server sends an extra new line before the next block specifier..
484 if (In
.WriteTillEl(Data
,true) == true)
487 while ((Last
= Owner
->Go(false,this)) == true);
494 /* Closes encoding is used when the server did not specify a size, the
495 loss of the connection means we are done */
496 if (Encoding
== Closes
)
499 In
.Limit(Size
- StartPos
);
501 // Just transfer the whole block.
504 if (In
.IsLimit() == false)
508 return !_error
->PendingError();
510 while (Owner
->Go(true,this) == true);
513 return Owner
->Flush(this) && !_error
->PendingError();
516 // ServerState::HeaderLine - Process a header line /*{{{*/
517 // ---------------------------------------------------------------------
519 bool ServerState::HeaderLine(string Line
)
521 if (Line
.empty() == true)
524 // The http server might be trying to do something evil.
525 if (Line
.length() >= MAXLEN
)
526 return _error
->Error("Got a single header line over %u chars",MAXLEN
);
528 string::size_type Pos
= Line
.find(' ');
529 if (Pos
== string::npos
|| Pos
+1 > Line
.length())
531 // Blah, some servers use "connection:closes", evil.
532 Pos
= Line
.find(':');
533 if (Pos
== string::npos
|| Pos
+ 2 > Line
.length())
534 return _error
->Error("Bad header line");
538 // Parse off any trailing spaces between the : and the next word.
539 string::size_type Pos2
= Pos
;
540 while (Pos2
< Line
.length() && isspace(Line
[Pos2
]) != 0)
543 string Tag
= string(Line
,0,Pos
);
544 string Val
= string(Line
,Pos2
);
546 if (stringcasecmp(Tag
.begin(),Tag
.begin()+4,"HTTP") == 0)
548 // Evil servers return no version
551 if (sscanf(Line
.c_str(),"HTTP/%u.%u %u %[^\n]",&Major
,&Minor
,
553 return _error
->Error("The http server sent an invalid reply header");
559 if (sscanf(Line
.c_str(),"HTTP %u %[^\n]",&Result
,Code
) != 2)
560 return _error
->Error("The http server sent an invalid reply header");
566 if (stringcasecmp(Tag
,"Content-Length:") == 0)
568 if (Encoding
== Closes
)
572 // The length is already set from the Content-Range header
576 if (sscanf(Val
.c_str(),"%lu",&Size
) != 1)
577 return _error
->Error("The http server sent an invalid Content-Length header");
581 if (stringcasecmp(Tag
,"Content-Type:") == 0)
587 if (stringcasecmp(Tag
,"Content-Range:") == 0)
591 if (sscanf(Val
.c_str(),"bytes %lu-%*u/%lu",&StartPos
,&Size
) != 2)
592 return _error
->Error("The http server sent an invalid Content-Range header");
593 if ((unsigned)StartPos
> Size
)
594 return _error
->Error("This http server has broken range support");
598 if (stringcasecmp(Tag
,"Transfer-Encoding:") == 0)
601 if (stringcasecmp(Val
,"chunked") == 0)
607 if (stringcasecmp(Tag
,"Last-Modified:") == 0)
609 if (StrToTime(Val
,Date
) == false)
610 return _error
->Error("Unknown date format");
618 // HttpMethod::SendReq - Send the HTTP request /*{{{*/
619 // ---------------------------------------------------------------------
620 /* This places the http request in the outbound buffer */
621 void HttpMethod::SendReq(FetchItem
*Itm
,CircleBuf
&Out
)
625 // The HTTP server expects a hostname with a trailing :port
627 string ProperHost
= Uri
.Host
;
630 sprintf(Buf
,":%u",Uri
.Port
);
635 if (Itm
->Uri
.length() >= sizeof(Buf
))
638 /* Build the request. We include a keep-alive header only for non-proxy
639 requests. This is to tweak old http/1.0 servers that do support keep-alive
640 but not HTTP/1.1 automatic keep-alive. Doing this with a proxy server
641 will glitch HTTP/1.0 proxies because they do not filter it out and
642 pass it on, HTTP/1.1 says the connection should default to keep alive
643 and we expect the proxy to do this */
644 if (Proxy
.empty() == true)
645 sprintf(Buf
,"GET %s HTTP/1.1\r\nHost: %s\r\nConnection: keep-alive\r\n",
646 QuoteString(Uri
.Path
,"~").c_str(),ProperHost
.c_str());
649 /* Generate a cache control header if necessary. We place a max
650 cache age on index files, optionally set a no-cache directive
651 and a no-store directive for archives. */
652 sprintf(Buf
,"GET %s HTTP/1.1\r\nHost: %s\r\n",
653 Itm
->Uri
.c_str(),ProperHost
.c_str());
654 if (_config
->FindB("Acquire::http::No-Cache",false) == true)
655 strcat(Buf
,"Cache-Control: no-cache\r\nPragma: no-cache\r\n");
658 if (Itm
->IndexFile
== true)
659 sprintf(Buf
+strlen(Buf
),"Cache-Control: max-age=%u\r\n",
660 _config
->FindI("Acquire::http::Max-Age",60*60*24));
663 if (_config
->FindB("Acquire::http::No-Store",false) == true)
664 strcat(Buf
,"Cache-Control: no-store\r\n");
671 // Check for a partial file
673 if (stat(Itm
->DestFile
.c_str(),&SBuf
) >= 0 && SBuf
.st_size
> 0)
675 // In this case we send an if-range query with a range header
676 sprintf(Buf
,"Range: bytes=%li-\r\nIf-Range: %s\r\n",SBuf
.st_size
- 1,
677 TimeRFC1123(SBuf
.st_mtime
).c_str());
682 if (Itm
->LastModified
!= 0)
684 sprintf(Buf
,"If-Modified-Since: %s\r\n",TimeRFC1123(Itm
->LastModified
).c_str());
689 if (Proxy
.User
.empty() == false || Proxy
.Password
.empty() == false)
690 Req
+= string("Proxy-Authorization: Basic ") +
691 Base64Encode(Proxy
.User
+ ":" + Proxy
.Password
) + "\r\n";
693 Req
+= "User-Agent: Debian APT-HTTP/1.2\r\n\r\n";
694 // cerr << Req << endl;
699 // HttpMethod::Go - Run a single loop /*{{{*/
700 // ---------------------------------------------------------------------
701 /* This runs the select loop over the server FDs, Output file FDs and
703 bool HttpMethod::Go(bool ToFile
,ServerState
*Srv
)
705 // Server has closed the connection
706 if (Srv
->ServerFd
== -1 && Srv
->In
.WriteSpace() == false)
709 fd_set rfds
,wfds
,efds
;
715 if (Srv
->Out
.WriteSpace() == true && Srv
->ServerFd
!= -1)
716 FD_SET(Srv
->ServerFd
,&wfds
);
717 if (Srv
->In
.ReadSpace() == true && Srv
->ServerFd
!= -1)
718 FD_SET(Srv
->ServerFd
,&rfds
);
725 if (Srv
->In
.WriteSpace() == true && ToFile
== true && FileFD
!= -1)
726 FD_SET(FileFD
,&wfds
);
729 FD_SET(STDIN_FILENO
,&rfds
);
733 FD_SET(FileFD
,&efds
);
734 if (Srv
->ServerFd
!= -1)
735 FD_SET(Srv
->ServerFd
,&efds
);
737 // Figure out the max fd
739 if (MaxFd
< Srv
->ServerFd
)
740 MaxFd
= Srv
->ServerFd
;
747 if ((Res
= select(MaxFd
+1,&rfds
,&wfds
,&efds
,&tv
)) < 0)
748 return _error
->Errno("select","Select failed");
752 _error
->Error("Connection timed out");
753 return ServerDie(Srv
);
756 // Some kind of exception (error) on the sockets, die
757 if ((FileFD
!= -1 && FD_ISSET(FileFD
,&efds
)) ||
758 (Srv
->ServerFd
!= -1 && FD_ISSET(Srv
->ServerFd
,&efds
)))
759 return _error
->Error("Socket Exception");
762 if (Srv
->ServerFd
!= -1 && FD_ISSET(Srv
->ServerFd
,&rfds
))
765 if (Srv
->In
.Read(Srv
->ServerFd
) == false)
766 return ServerDie(Srv
);
769 if (Srv
->ServerFd
!= -1 && FD_ISSET(Srv
->ServerFd
,&wfds
))
772 if (Srv
->Out
.Write(Srv
->ServerFd
) == false)
773 return ServerDie(Srv
);
776 // Send data to the file
777 if (FileFD
!= -1 && FD_ISSET(FileFD
,&wfds
))
779 if (Srv
->In
.Write(FileFD
) == false)
780 return _error
->Errno("write","Error writing to output file");
783 // Handle commands from APT
784 if (FD_ISSET(STDIN_FILENO
,&rfds
))
793 // HttpMethod::Flush - Dump the buffer into the file /*{{{*/
794 // ---------------------------------------------------------------------
795 /* This takes the current input buffer from the Server FD and writes it
797 bool HttpMethod::Flush(ServerState
*Srv
)
801 SetNonBlock(File
->Fd(),false);
802 if (Srv
->In
.WriteSpace() == false)
805 while (Srv
->In
.WriteSpace() == true)
807 if (Srv
->In
.Write(File
->Fd()) == false)
808 return _error
->Errno("write","Error writing to file");
809 if (Srv
->In
.IsLimit() == true)
813 if (Srv
->In
.IsLimit() == true || Srv
->Encoding
== ServerState::Closes
)
819 // HttpMethod::ServerDie - The server has closed the connection. /*{{{*/
820 // ---------------------------------------------------------------------
822 bool HttpMethod::ServerDie(ServerState
*Srv
)
824 unsigned int LErrno
= errno
;
826 // Dump the buffer to the file
827 if (Srv
->State
== ServerState::Data
)
829 SetNonBlock(File
->Fd(),false);
830 while (Srv
->In
.WriteSpace() == true)
832 if (Srv
->In
.Write(File
->Fd()) == false)
833 return _error
->Errno("write","Error writing to the file");
836 if (Srv
->In
.IsLimit() == true)
841 // See if this is because the server finished the data stream
842 if (Srv
->In
.IsLimit() == false && Srv
->State
!= ServerState::Header
&&
843 Srv
->Encoding
!= ServerState::Closes
)
847 return _error
->Error("Error reading from server Remote end closed connection");
849 return _error
->Errno("read","Error reading from server");
855 // Nothing left in the buffer
856 if (Srv
->In
.WriteSpace() == false)
859 // We may have got multiple responses back in one packet..
867 // HttpMethod::DealWithHeaders - Handle the retrieved header data /*{{{*/
868 // ---------------------------------------------------------------------
869 /* We look at the header data we got back from the server and decide what
873 3 - Unrecoverable error
874 4 - Error with error content page
875 5 - Unrecoverable non-server error (close the connection) */
876 int HttpMethod::DealWithHeaders(FetchResult
&Res
,ServerState
*Srv
)
879 if (Srv
->Result
== 304)
881 unlink(Queue
->DestFile
.c_str());
883 Res
.LastModified
= Queue
->LastModified
;
887 /* We have a reply we dont handle. This should indicate a perm server
889 if (Srv
->Result
< 200 || Srv
->Result
>= 300)
891 _error
->Error("%u %s",Srv
->Result
,Srv
->Code
);
892 if (Srv
->HaveContent
== true)
897 // This is some sort of 2xx 'data follows' reply
898 Res
.LastModified
= Srv
->Date
;
899 Res
.Size
= Srv
->Size
;
903 File
= new FileFd(Queue
->DestFile
,FileFd::WriteAny
);
904 if (_error
->PendingError() == true)
907 FailFile
= Queue
->DestFile
;
908 FailFile
.c_str(); // Make sure we dont do a malloc in the signal handler
910 FailTime
= Srv
->Date
;
912 // Set the expected size
913 if (Srv
->StartPos
>= 0)
915 Res
.ResumePoint
= Srv
->StartPos
;
916 ftruncate(File
->Fd(),Srv
->StartPos
);
919 // Set the start point
920 lseek(File
->Fd(),0,SEEK_END
);
923 Srv
->In
.MD5
= new MD5Summation
;
925 // Fill the MD5 Hash if the file is non-empty (resume)
926 if (Srv
->StartPos
> 0)
928 lseek(File
->Fd(),0,SEEK_SET
);
929 if (Srv
->In
.MD5
->AddFD(File
->Fd(),Srv
->StartPos
) == false)
931 _error
->Errno("read","Problem hashing file");
934 lseek(File
->Fd(),0,SEEK_END
);
937 SetNonBlock(File
->Fd(),true);
941 // HttpMethod::SigTerm - Handle a fatal signal /*{{{*/
942 // ---------------------------------------------------------------------
943 /* This closes and timestamps the open file. This is neccessary to get
944 resume behavoir on user abort */
945 void HttpMethod::SigTerm(int)
953 UBuf
.actime
= FailTime
;
954 UBuf
.modtime
= FailTime
;
955 utime(FailFile
.c_str(),&UBuf
);
960 // HttpMethod::Fetch - Fetch an item /*{{{*/
961 // ---------------------------------------------------------------------
962 /* This adds an item to the pipeline. We keep the pipeline at a fixed
964 bool HttpMethod::Fetch(FetchItem
*)
969 // Queue the requests
972 for (FetchItem
*I
= Queue
; I
!= 0 && Depth
< (signed)PipelineDepth
; I
= I
->Next
, Depth
++)
974 // Make sure we stick with the same server
975 if (Server
->Comp(I
->Uri
) == false)
982 SendReq(I
,Server
->Out
);
990 // HttpMethod::Configuration - Handle a configuration message /*{{{*/
991 // ---------------------------------------------------------------------
992 /* We stash the desired pipeline depth */
993 bool HttpMethod::Configuration(string Message
)
995 if (pkgAcqMethod::Configuration(Message
) == false)
998 TimeOut
= _config
->FindI("Acquire::http::Timeout",TimeOut
);
999 PipelineDepth
= _config
->FindI("Acquire::http::Pipeline-Depth",
1005 // HttpMethod::Loop - Main loop /*{{{*/
1006 // ---------------------------------------------------------------------
1008 int HttpMethod::Loop()
1010 signal(SIGTERM
,SigTerm
);
1011 signal(SIGINT
,SigTerm
);
1015 int FailCounter
= 0;
1018 // We have no commands, wait for some to arrive
1021 if (WaitFd(STDIN_FILENO
) == false)
1032 // Connect to the server
1033 if (Server
== 0 || Server
->Comp(Queue
->Uri
) == false)
1036 Server
= new ServerState(Queue
->Uri
,this);
1039 // Reset the pipeline
1040 if (Server
->ServerFd
== -1)
1043 // Connnect to the host
1044 if (Server
->Open() == false)
1052 // Fill the pipeline.
1055 // Fetch the next URL header data from the server.
1056 switch (Server
->RunHeaders())
1061 // The header data is bad
1064 _error
->Error("Bad header Data");
1069 // The server closed a connection during the header get..
1077 if (FailCounter
>= 2)
1079 Fail("Connection timed out",true);
1087 // Decide what to do.
1089 Res
.Filename
= Queue
->DestFile
;
1090 switch (DealWithHeaders(Res
,Server
))
1092 // Ok, the file is Open
1098 bool Result
= Server
->RunData();
1100 // Close the file, destroy the FD object and timestamp it
1106 struct utimbuf UBuf
;
1108 UBuf
.actime
= Server
->Date
;
1109 UBuf
.modtime
= Server
->Date
;
1110 utime(Queue
->DestFile
.c_str(),&UBuf
);
1112 // Send status to APT
1115 Res
.MD5Sum
= Server
->In
.MD5
->Result();
1131 // Hard server error, not found or something
1138 // Hard internal error, kill the connection and fail
1146 // We need to flush the data, the header is like a 404 w/ error text
1151 // Send to content to dev/null
1152 File
= new FileFd("/dev/null",FileFd::WriteExists
);
1160 Fail("Internal error");