]>
git.saurik.com Git - apt.git/blob - methods/http.cc
067d805643d7e34fcab47bfcd0b6214d79314c7e
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: http.cc,v 1.32 1999/05/26 04:08:39 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","Connect initiate the connection");
358 /* This implements a timeout for connect by opening the connection
360 if (WaitFd(ServerFd
,true,TimeOut
) == false)
361 return _error
->Error("Could not connect, connection timed out");
363 unsigned int Len
= sizeof(Err
);
364 if (getsockopt(ServerFd
,SOL_SOCKET
,SO_ERROR
,&Err
,&Len
) != 0)
365 return _error
->Errno("getsockopt","Failed");
367 return _error
->Error("Could not connect.");
372 // ServerState::Close - Close a connection to the server /*{{{*/
373 // ---------------------------------------------------------------------
375 bool ServerState::Close()
382 // ServerState::RunHeaders - Get the headers before the data /*{{{*/
383 // ---------------------------------------------------------------------
384 /* Returns 0 if things are OK, 1 if an IO error occursed and 2 if a header
385 parse error occured */
386 int ServerState::RunHeaders()
390 Owner
->Status("Waiting for file");
404 if (In
.WriteTillEl(Data
) == false)
407 for (string::const_iterator I
= Data
.begin(); I
< Data
.end(); I
++)
409 string::const_iterator J
= I
;
410 for (; J
!= Data
.end() && *J
!= '\n' && *J
!= '\r';J
++);
411 if (HeaderLine(string(I
,J
-I
)) == false)
417 while (Owner
->Go(false,this) == true);
422 // ServerState::RunData - Transfer the data from the socket /*{{{*/
423 // ---------------------------------------------------------------------
425 bool ServerState::RunData()
429 // Chunked transfer encoding is fun..
430 if (Encoding
== Chunked
)
434 // Grab the block size
440 if (In
.WriteTillEl(Data
,true) == true)
443 while ((Last
= Owner
->Go(false,this)) == true);
448 // See if we are done
449 unsigned long Len
= strtol(Data
.c_str(),0,16);
454 // We have to remove the entity trailer
458 if (In
.WriteTillEl(Data
,true) == true && Data
.length() <= 2)
461 while ((Last
= Owner
->Go(false,this)) == true);
464 return !_error
->PendingError();
467 // Transfer the block
469 while (Owner
->Go(true,this) == true)
470 if (In
.IsLimit() == true)
474 if (In
.IsLimit() == false)
477 // The server sends an extra new line before the next block specifier..
482 if (In
.WriteTillEl(Data
,true) == true)
485 while ((Last
= Owner
->Go(false,this)) == true);
492 /* Closes encoding is used when the server did not specify a size, the
493 loss of the connection means we are done */
494 if (Encoding
== Closes
)
497 In
.Limit(Size
- StartPos
);
499 // Just transfer the whole block.
502 if (In
.IsLimit() == false)
506 return !_error
->PendingError();
508 while (Owner
->Go(true,this) == true);
511 return Owner
->Flush(this) && !_error
->PendingError();
514 // ServerState::HeaderLine - Process a header line /*{{{*/
515 // ---------------------------------------------------------------------
517 bool ServerState::HeaderLine(string Line
)
519 if (Line
.empty() == true)
522 // The http server might be trying to do something evil.
523 if (Line
.length() >= MAXLEN
)
524 return _error
->Error("Got a single header line over %u chars",MAXLEN
);
526 string::size_type Pos
= Line
.find(' ');
527 if (Pos
== string::npos
|| Pos
+1 > Line
.length())
529 // Blah, some servers use "connection:closes", evil.
530 Pos
= Line
.find(':');
531 if (Pos
== string::npos
|| Pos
+ 2 > Line
.length())
532 return _error
->Error("Bad header line");
536 // Parse off any trailing spaces between the : and the next word.
537 string::size_type Pos2
= Pos
;
538 while (Pos2
< Line
.length() && isspace(Line
[Pos2
]) != 0)
541 string Tag
= string(Line
,0,Pos
);
542 string Val
= string(Line
,Pos2
);
544 if (stringcasecmp(Tag
.begin(),Tag
.begin()+4,"HTTP") == 0)
546 // Evil servers return no version
549 if (sscanf(Line
.c_str(),"HTTP/%u.%u %u %[^\n]",&Major
,&Minor
,
551 return _error
->Error("The http server sent an invalid reply header");
557 if (sscanf(Line
.c_str(),"HTTP %u %[^\n]",&Result
,Code
) != 2)
558 return _error
->Error("The http server sent an invalid reply header");
564 if (stringcasecmp(Tag
,"Content-Length:") == 0)
566 if (Encoding
== Closes
)
570 // The length is already set from the Content-Range header
574 if (sscanf(Val
.c_str(),"%lu",&Size
) != 1)
575 return _error
->Error("The http server sent an invalid Content-Length header");
579 if (stringcasecmp(Tag
,"Content-Type:") == 0)
585 if (stringcasecmp(Tag
,"Content-Range:") == 0)
589 if (sscanf(Val
.c_str(),"bytes %lu-%*u/%lu",&StartPos
,&Size
) != 2)
590 return _error
->Error("The http server sent an invalid Content-Range header");
591 if ((unsigned)StartPos
> Size
)
592 return _error
->Error("This http server has broken range support");
596 if (stringcasecmp(Tag
,"Transfer-Encoding:") == 0)
599 if (stringcasecmp(Val
,"chunked") == 0)
605 if (stringcasecmp(Tag
,"Last-Modified:") == 0)
607 if (StrToTime(Val
,Date
) == false)
608 return _error
->Error("Unknown date format");
616 // HttpMethod::SendReq - Send the HTTP request /*{{{*/
617 // ---------------------------------------------------------------------
618 /* This places the http request in the outbound buffer */
619 void HttpMethod::SendReq(FetchItem
*Itm
,CircleBuf
&Out
)
623 // The HTTP server expects a hostname with a trailing :port
625 string ProperHost
= Uri
.Host
;
628 sprintf(Buf
,":%u",Uri
.Port
);
633 if (Itm
->Uri
.length() >= sizeof(Buf
))
636 /* Build the request. We include a keep-alive header only for non-proxy
637 requests. This is to tweak old http/1.0 servers that do support keep-alive
638 but not HTTP/1.1 automatic keep-alive. Doing this with a proxy server
639 will glitch HTTP/1.0 proxies because they do not filter it out and
640 pass it on, HTTP/1.1 says the connection should default to keep alive
641 and we expect the proxy to do this */
642 if (Proxy
.empty() == true)
643 sprintf(Buf
,"GET %s HTTP/1.1\r\nHost: %s\r\nConnection: keep-alive\r\n",
644 QuoteString(Uri
.Path
,"~").c_str(),ProperHost
.c_str());
647 /* Generate a cache control header if necessary. We place a max
648 cache age on index files, optionally set a no-cache directive
649 and a no-store directive for archives. */
650 sprintf(Buf
,"GET %s HTTP/1.1\r\nHost: %s\r\n",
651 Itm
->Uri
.c_str(),ProperHost
.c_str());
652 if (_config
->FindB("Acquire::http::No-Cache",false) == true)
653 strcat(Buf
,"Cache-Control: no-cache\r\nPragma: no-cache\r\n");
656 if (Itm
->IndexFile
== true)
657 sprintf(Buf
+strlen(Buf
),"Cache-Control: max-age=%u\r\n",
658 _config
->FindI("Acquire::http::Max-Age",60*60*24));
661 if (_config
->FindB("Acquire::http::No-Store",false) == true)
662 strcat(Buf
,"Cache-Control: no-store\r\n");
669 // Check for a partial file
671 if (stat(Itm
->DestFile
.c_str(),&SBuf
) >= 0 && SBuf
.st_size
> 0)
673 // In this case we send an if-range query with a range header
674 sprintf(Buf
,"Range: bytes=%li-\r\nIf-Range: %s\r\n",SBuf
.st_size
- 1,
675 TimeRFC1123(SBuf
.st_mtime
).c_str());
680 if (Itm
->LastModified
!= 0)
682 sprintf(Buf
,"If-Modified-Since: %s\r\n",TimeRFC1123(Itm
->LastModified
).c_str());
687 if (Proxy
.User
.empty() == false || Proxy
.Password
.empty() == false)
688 Req
+= string("Proxy-Authorization: Basic ") +
689 Base64Encode(Proxy
.User
+ ":" + Proxy
.Password
) + "\r\n";
691 Req
+= "User-Agent: Debian APT-HTTP/1.2\r\n\r\n";
692 // cerr << Req << endl;
697 // HttpMethod::Go - Run a single loop /*{{{*/
698 // ---------------------------------------------------------------------
699 /* This runs the select loop over the server FDs, Output file FDs and
701 bool HttpMethod::Go(bool ToFile
,ServerState
*Srv
)
703 // Server has closed the connection
704 if (Srv
->ServerFd
== -1 && Srv
->In
.WriteSpace() == false)
707 fd_set rfds
,wfds
,efds
;
713 if (Srv
->Out
.WriteSpace() == true && Srv
->ServerFd
!= -1)
714 FD_SET(Srv
->ServerFd
,&wfds
);
715 if (Srv
->In
.ReadSpace() == true && Srv
->ServerFd
!= -1)
716 FD_SET(Srv
->ServerFd
,&rfds
);
723 if (Srv
->In
.WriteSpace() == true && ToFile
== true && FileFD
!= -1)
724 FD_SET(FileFD
,&wfds
);
727 FD_SET(STDIN_FILENO
,&rfds
);
731 FD_SET(FileFD
,&efds
);
732 if (Srv
->ServerFd
!= -1)
733 FD_SET(Srv
->ServerFd
,&efds
);
735 // Figure out the max fd
737 if (MaxFd
< Srv
->ServerFd
)
738 MaxFd
= Srv
->ServerFd
;
745 if ((Res
= select(MaxFd
+1,&rfds
,&wfds
,&efds
,&tv
)) < 0)
746 return _error
->Errno("select","Select failed");
750 _error
->Error("Connection timed out");
751 return ServerDie(Srv
);
754 // Some kind of exception (error) on the sockets, die
755 if ((FileFD
!= -1 && FD_ISSET(FileFD
,&efds
)) ||
756 (Srv
->ServerFd
!= -1 && FD_ISSET(Srv
->ServerFd
,&efds
)))
757 return _error
->Error("Socket Exception");
760 if (Srv
->ServerFd
!= -1 && FD_ISSET(Srv
->ServerFd
,&rfds
))
763 if (Srv
->In
.Read(Srv
->ServerFd
) == false)
764 return ServerDie(Srv
);
767 if (Srv
->ServerFd
!= -1 && FD_ISSET(Srv
->ServerFd
,&wfds
))
770 if (Srv
->Out
.Write(Srv
->ServerFd
) == false)
771 return ServerDie(Srv
);
774 // Send data to the file
775 if (FileFD
!= -1 && FD_ISSET(FileFD
,&wfds
))
777 if (Srv
->In
.Write(FileFD
) == false)
778 return _error
->Errno("write","Error writing to output file");
781 // Handle commands from APT
782 if (FD_ISSET(STDIN_FILENO
,&rfds
))
791 // HttpMethod::Flush - Dump the buffer into the file /*{{{*/
792 // ---------------------------------------------------------------------
793 /* This takes the current input buffer from the Server FD and writes it
795 bool HttpMethod::Flush(ServerState
*Srv
)
799 SetNonBlock(File
->Fd(),false);
800 if (Srv
->In
.WriteSpace() == false)
803 while (Srv
->In
.WriteSpace() == true)
805 if (Srv
->In
.Write(File
->Fd()) == false)
806 return _error
->Errno("write","Error writing to file");
807 if (Srv
->In
.IsLimit() == true)
811 if (Srv
->In
.IsLimit() == true || Srv
->Encoding
== ServerState::Closes
)
817 // HttpMethod::ServerDie - The server has closed the connection. /*{{{*/
818 // ---------------------------------------------------------------------
820 bool HttpMethod::ServerDie(ServerState
*Srv
)
822 unsigned int LErrno
= errno
;
824 // Dump the buffer to the file
825 if (Srv
->State
== ServerState::Data
)
827 SetNonBlock(File
->Fd(),false);
828 while (Srv
->In
.WriteSpace() == true)
830 if (Srv
->In
.Write(File
->Fd()) == false)
831 return _error
->Errno("write","Error writing to the file");
834 if (Srv
->In
.IsLimit() == true)
839 // See if this is because the server finished the data stream
840 if (Srv
->In
.IsLimit() == false && Srv
->State
!= ServerState::Header
&&
841 Srv
->Encoding
!= ServerState::Closes
)
845 return _error
->Error("Error reading from server Remote end closed connection");
847 return _error
->Errno("read","Error reading from server");
853 // Nothing left in the buffer
854 if (Srv
->In
.WriteSpace() == false)
857 // We may have got multiple responses back in one packet..
865 // HttpMethod::DealWithHeaders - Handle the retrieved header data /*{{{*/
866 // ---------------------------------------------------------------------
867 /* We look at the header data we got back from the server and decide what
871 3 - Unrecoverable error
872 4 - Error with error content page
873 5 - Unrecoverable non-server error (close the connection) */
874 int HttpMethod::DealWithHeaders(FetchResult
&Res
,ServerState
*Srv
)
877 if (Srv
->Result
== 304)
879 unlink(Queue
->DestFile
.c_str());
881 Res
.LastModified
= Queue
->LastModified
;
885 /* We have a reply we dont handle. This should indicate a perm server
887 if (Srv
->Result
< 200 || Srv
->Result
>= 300)
889 _error
->Error("%u %s",Srv
->Result
,Srv
->Code
);
890 if (Srv
->HaveContent
== true)
895 // This is some sort of 2xx 'data follows' reply
896 Res
.LastModified
= Srv
->Date
;
897 Res
.Size
= Srv
->Size
;
901 File
= new FileFd(Queue
->DestFile
,FileFd::WriteAny
);
902 if (_error
->PendingError() == true)
905 FailFile
= Queue
->DestFile
;
906 FailFile
.c_str(); // Make sure we dont do a malloc in the signal handler
908 FailTime
= Srv
->Date
;
910 // Set the expected size
911 if (Srv
->StartPos
>= 0)
913 Res
.ResumePoint
= Srv
->StartPos
;
914 ftruncate(File
->Fd(),Srv
->StartPos
);
917 // Set the start point
918 lseek(File
->Fd(),0,SEEK_END
);
921 Srv
->In
.MD5
= new MD5Summation
;
923 // Fill the MD5 Hash if the file is non-empty (resume)
924 if (Srv
->StartPos
> 0)
926 lseek(File
->Fd(),0,SEEK_SET
);
927 if (Srv
->In
.MD5
->AddFD(File
->Fd(),Srv
->StartPos
) == false)
929 _error
->Errno("read","Problem hashing file");
932 lseek(File
->Fd(),0,SEEK_END
);
935 SetNonBlock(File
->Fd(),true);
939 // HttpMethod::SigTerm - Handle a fatal signal /*{{{*/
940 // ---------------------------------------------------------------------
941 /* This closes and timestamps the open file. This is neccessary to get
942 resume behavoir on user abort */
943 void HttpMethod::SigTerm(int)
951 UBuf
.actime
= FailTime
;
952 UBuf
.modtime
= FailTime
;
953 utime(FailFile
.c_str(),&UBuf
);
958 // HttpMethod::Fetch - Fetch an item /*{{{*/
959 // ---------------------------------------------------------------------
960 /* This adds an item to the pipeline. We keep the pipeline at a fixed
962 bool HttpMethod::Fetch(FetchItem
*)
967 // Queue the requests
970 for (FetchItem
*I
= Queue
; I
!= 0 && Depth
< (signed)PipelineDepth
; I
= I
->Next
, Depth
++)
972 // Make sure we stick with the same server
973 if (Server
->Comp(I
->Uri
) == false)
980 SendReq(I
,Server
->Out
);
988 // HttpMethod::Configuration - Handle a configuration message /*{{{*/
989 // ---------------------------------------------------------------------
990 /* We stash the desired pipeline depth */
991 bool HttpMethod::Configuration(string Message
)
993 if (pkgAcqMethod::Configuration(Message
) == false)
996 TimeOut
= _config
->FindI("Acquire::http::Timeout",TimeOut
);
997 PipelineDepth
= _config
->FindI("Acquire::http::Pipeline-Depth",
1003 // HttpMethod::Loop - Main loop /*{{{*/
1004 // ---------------------------------------------------------------------
1006 int HttpMethod::Loop()
1008 signal(SIGTERM
,SigTerm
);
1009 signal(SIGINT
,SigTerm
);
1013 int FailCounter
= 0;
1016 // We have no commands, wait for some to arrive
1019 if (WaitFd(STDIN_FILENO
) == false)
1030 // Connect to the server
1031 if (Server
== 0 || Server
->Comp(Queue
->Uri
) == false)
1034 Server
= new ServerState(Queue
->Uri
,this);
1037 // Reset the pipeline
1038 if (Server
->ServerFd
== -1)
1041 // Connnect to the host
1042 if (Server
->Open() == false)
1050 // Fill the pipeline.
1053 // Fetch the next URL header data from the server.
1054 switch (Server
->RunHeaders())
1059 // The header data is bad
1062 _error
->Error("Bad header Data");
1067 // The server closed a connection during the header get..
1075 if (FailCounter
>= 2)
1077 Fail("Connection timed out",true);
1085 // Decide what to do.
1087 Res
.Filename
= Queue
->DestFile
;
1088 switch (DealWithHeaders(Res
,Server
))
1090 // Ok, the file is Open
1096 bool Result
= Server
->RunData();
1098 // Close the file, destroy the FD object and timestamp it
1104 struct utimbuf UBuf
;
1106 UBuf
.actime
= Server
->Date
;
1107 UBuf
.modtime
= Server
->Date
;
1108 utime(Queue
->DestFile
.c_str(),&UBuf
);
1110 // Send status to APT
1113 Res
.MD5Sum
= Server
->In
.MD5
->Result();
1129 // Hard server error, not found or something
1136 // Hard internal error, kill the connection and fail
1144 // We need to flush the data, the header is like a 404 w/ error text
1149 // Send to content to dev/null
1150 File
= new FileFd("/dev/null",FileFd::WriteExists
);
1158 Fail("Internal error");