http.cc 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142
  1. // -*- mode: cpp; mode: fold -*-
  2. // Description /*{{{*/
  3. // $Id: http.cc,v 1.44 2000/01/30 08:16:43 jgg Exp $
  4. /* ######################################################################
  5. HTTP Aquire Method - This is the HTTP aquire method for APT.
  6. It uses HTTP/1.1 and many of the fancy options there-in, such as
  7. pipelining, range, if-range and so on. It accepts on the command line
  8. a list of url destination pairs and writes to stdout the status of the
  9. operation as defined in the APT method spec.
  10. It is based on a doubly buffered select loop. All the requests are
  11. fed into a single output buffer that is constantly fed out the
  12. socket. This provides ideal pipelining as in many cases all of the
  13. requests will fit into a single packet. The input socket is buffered
  14. the same way and fed into the fd for the file.
  15. This double buffering provides fairly substantial transfer rates,
  16. compared to wget the http method is about 4% faster. Most importantly,
  17. when HTTP is compared with FTP as a protocol the speed difference is
  18. huge. In tests over the internet from two sites to llug (via ATM) this
  19. program got 230k/s sustained http transfer rates. FTP on the other
  20. hand topped out at 170k/s. That combined with the time to setup the
  21. FTP connection makes HTTP a vastly superior protocol.
  22. ##################################################################### */
  23. /*}}}*/
  24. // Include Files /*{{{*/
  25. #include <apt-pkg/fileutl.h>
  26. #include <apt-pkg/acquire-method.h>
  27. #include <apt-pkg/error.h>
  28. #include <apt-pkg/md5.h>
  29. #include <sys/stat.h>
  30. #include <sys/time.h>
  31. #include <utime.h>
  32. #include <unistd.h>
  33. #include <signal.h>
  34. #include <stdio.h>
  35. #include <errno.h>
  36. // Internet stuff
  37. #include <netdb.h>
  38. #include "connect.h"
  39. #include "rfc2553emu.h"
  40. #include "http.h"
  41. /*}}}*/
  42. string HttpMethod::FailFile;
  43. int HttpMethod::FailFd = -1;
  44. time_t HttpMethod::FailTime = 0;
  45. unsigned long PipelineDepth = 10;
  46. unsigned long TimeOut = 120;
  47. bool Debug = false;
  48. // CircleBuf::CircleBuf - Circular input buffer /*{{{*/
  49. // ---------------------------------------------------------------------
  50. /* */
  51. CircleBuf::CircleBuf(unsigned long Size) : Size(Size), MD5(0)
  52. {
  53. Buf = new unsigned char[Size];
  54. Reset();
  55. }
  56. /*}}}*/
  57. // CircleBuf::Reset - Reset to the default state /*{{{*/
  58. // ---------------------------------------------------------------------
  59. /* */
  60. void CircleBuf::Reset()
  61. {
  62. InP = 0;
  63. OutP = 0;
  64. StrPos = 0;
  65. MaxGet = (unsigned int)-1;
  66. OutQueue = string();
  67. if (MD5 != 0)
  68. {
  69. delete MD5;
  70. MD5 = new MD5Summation;
  71. }
  72. };
  73. /*}}}*/
  74. // CircleBuf::Read - Read from a FD into the circular buffer /*{{{*/
  75. // ---------------------------------------------------------------------
  76. /* This fills up the buffer with as much data as is in the FD, assuming it
  77. is non-blocking.. */
  78. bool CircleBuf::Read(int Fd)
  79. {
  80. while (1)
  81. {
  82. // Woops, buffer is full
  83. if (InP - OutP == Size)
  84. return true;
  85. // Write the buffer segment
  86. int Res;
  87. Res = read(Fd,Buf + (InP%Size),LeftRead());
  88. if (Res == 0)
  89. return false;
  90. if (Res < 0)
  91. {
  92. if (errno == EAGAIN)
  93. return true;
  94. return false;
  95. }
  96. if (InP == 0)
  97. gettimeofday(&Start,0);
  98. InP += Res;
  99. }
  100. }
  101. /*}}}*/
  102. // CircleBuf::Read - Put the string into the buffer /*{{{*/
  103. // ---------------------------------------------------------------------
  104. /* This will hold the string in and fill the buffer with it as it empties */
  105. bool CircleBuf::Read(string Data)
  106. {
  107. OutQueue += Data;
  108. FillOut();
  109. return true;
  110. }
  111. /*}}}*/
  112. // CircleBuf::FillOut - Fill the buffer from the output queue /*{{{*/
  113. // ---------------------------------------------------------------------
  114. /* */
  115. void CircleBuf::FillOut()
  116. {
  117. if (OutQueue.empty() == true)
  118. return;
  119. while (1)
  120. {
  121. // Woops, buffer is full
  122. if (InP - OutP == Size)
  123. return;
  124. // Write the buffer segment
  125. unsigned long Sz = LeftRead();
  126. if (OutQueue.length() - StrPos < Sz)
  127. Sz = OutQueue.length() - StrPos;
  128. memcpy(Buf + (InP%Size),OutQueue.begin() + StrPos,Sz);
  129. // Advance
  130. StrPos += Sz;
  131. InP += Sz;
  132. if (OutQueue.length() == StrPos)
  133. {
  134. StrPos = 0;
  135. OutQueue = "";
  136. return;
  137. }
  138. }
  139. }
  140. /*}}}*/
  141. // CircleBuf::Write - Write from the buffer into a FD /*{{{*/
  142. // ---------------------------------------------------------------------
  143. /* This empties the buffer into the FD. */
  144. bool CircleBuf::Write(int Fd)
  145. {
  146. while (1)
  147. {
  148. FillOut();
  149. // Woops, buffer is empty
  150. if (OutP == InP)
  151. return true;
  152. if (OutP == MaxGet)
  153. return true;
  154. // Write the buffer segment
  155. int Res;
  156. Res = write(Fd,Buf + (OutP%Size),LeftWrite());
  157. if (Res == 0)
  158. return false;
  159. if (Res < 0)
  160. {
  161. if (errno == EAGAIN)
  162. return true;
  163. return false;
  164. }
  165. if (MD5 != 0)
  166. MD5->Add(Buf + (OutP%Size),Res);
  167. OutP += Res;
  168. }
  169. }
  170. /*}}}*/
  171. // CircleBuf::WriteTillEl - Write from the buffer to a string /*{{{*/
  172. // ---------------------------------------------------------------------
  173. /* This copies till the first empty line */
  174. bool CircleBuf::WriteTillEl(string &Data,bool Single)
  175. {
  176. // We cheat and assume it is unneeded to have more than one buffer load
  177. for (unsigned long I = OutP; I < InP; I++)
  178. {
  179. if (Buf[I%Size] != '\n')
  180. continue;
  181. for (I++; I < InP && Buf[I%Size] == '\r'; I++);
  182. if (Single == false)
  183. {
  184. if (Buf[I%Size] != '\n')
  185. continue;
  186. for (I++; I < InP && Buf[I%Size] == '\r'; I++);
  187. }
  188. if (I > InP)
  189. I = InP;
  190. Data = "";
  191. while (OutP < I)
  192. {
  193. unsigned long Sz = LeftWrite();
  194. if (Sz == 0)
  195. return false;
  196. if (I - OutP < LeftWrite())
  197. Sz = I - OutP;
  198. Data += string((char *)(Buf + (OutP%Size)),Sz);
  199. OutP += Sz;
  200. }
  201. return true;
  202. }
  203. return false;
  204. }
  205. /*}}}*/
  206. // CircleBuf::Stats - Print out stats information /*{{{*/
  207. // ---------------------------------------------------------------------
  208. /* */
  209. void CircleBuf::Stats()
  210. {
  211. if (InP == 0)
  212. return;
  213. struct timeval Stop;
  214. gettimeofday(&Stop,0);
  215. /* float Diff = Stop.tv_sec - Start.tv_sec +
  216. (float)(Stop.tv_usec - Start.tv_usec)/1000000;
  217. clog << "Got " << InP << " in " << Diff << " at " << InP/Diff << endl;*/
  218. }
  219. /*}}}*/
  220. // ServerState::ServerState - Constructor /*{{{*/
  221. // ---------------------------------------------------------------------
  222. /* */
  223. ServerState::ServerState(URI Srv,HttpMethod *Owner) : Owner(Owner),
  224. In(64*1024), Out(4*1024),
  225. ServerName(Srv)
  226. {
  227. Reset();
  228. }
  229. /*}}}*/
  230. // ServerState::Open - Open a connection to the server /*{{{*/
  231. // ---------------------------------------------------------------------
  232. /* This opens a connection to the server. */
  233. string LastHost;
  234. int LastPort = 0;
  235. struct addrinfo *LastHostAddr = 0;
  236. bool ServerState::Open()
  237. {
  238. // Use the already open connection if possible.
  239. if (ServerFd != -1)
  240. return true;
  241. Close();
  242. In.Reset();
  243. Out.Reset();
  244. // Determine the proxy setting
  245. if (getenv("http_proxy") == 0)
  246. {
  247. string DefProxy = _config->Find("Acquire::http::Proxy");
  248. string SpecificProxy = _config->Find("Acquire::http::Proxy::" + ServerName.Host);
  249. if (SpecificProxy.empty() == false)
  250. {
  251. if (SpecificProxy == "DIRECT")
  252. Proxy = "";
  253. else
  254. Proxy = SpecificProxy;
  255. }
  256. else
  257. Proxy = DefProxy;
  258. }
  259. else
  260. Proxy = getenv("http_proxy");
  261. // Parse no_proxy, a , seperated list of hosts
  262. if (getenv("no_proxy") != 0)
  263. {
  264. const char *Start = getenv("no_proxy");
  265. for (const char *Cur = Start; true ; Cur++)
  266. {
  267. if (*Cur != ',' && *Cur != 0)
  268. continue;
  269. if (stringcasecmp(ServerName.Host.begin(),ServerName.Host.end(),
  270. Start,Cur) == 0)
  271. {
  272. Proxy = "";
  273. break;
  274. }
  275. Start = Cur + 1;
  276. if (*Cur == 0)
  277. break;
  278. }
  279. }
  280. // Determine what host and port to use based on the proxy settings
  281. int Port = 0;
  282. string Host;
  283. if (Proxy.empty() == true)
  284. {
  285. if (ServerName.Port != 0)
  286. Port = ServerName.Port;
  287. Host = ServerName.Host;
  288. }
  289. else
  290. {
  291. if (Proxy.Port != 0)
  292. Port = Proxy.Port;
  293. Host = Proxy.Host;
  294. }
  295. // Connect to the remote server
  296. if (Connect(Host,Port,"http",80,ServerFd,TimeOut,Owner) == false)
  297. return false;
  298. return true;
  299. }
  300. /*}}}*/
  301. // ServerState::Close - Close a connection to the server /*{{{*/
  302. // ---------------------------------------------------------------------
  303. /* */
  304. bool ServerState::Close()
  305. {
  306. close(ServerFd);
  307. ServerFd = -1;
  308. return true;
  309. }
  310. /*}}}*/
  311. // ServerState::RunHeaders - Get the headers before the data /*{{{*/
  312. // ---------------------------------------------------------------------
  313. /* Returns 0 if things are OK, 1 if an IO error occursed and 2 if a header
  314. parse error occured */
  315. int ServerState::RunHeaders()
  316. {
  317. State = Header;
  318. Owner->Status("Waiting for file");
  319. Major = 0;
  320. Minor = 0;
  321. Result = 0;
  322. Size = 0;
  323. StartPos = 0;
  324. Encoding = Closes;
  325. HaveContent = false;
  326. time(&Date);
  327. do
  328. {
  329. string Data;
  330. if (In.WriteTillEl(Data) == false)
  331. continue;
  332. if (Debug == true)
  333. clog << Data;
  334. for (string::const_iterator I = Data.begin(); I < Data.end(); I++)
  335. {
  336. string::const_iterator J = I;
  337. for (; J != Data.end() && *J != '\n' && *J != '\r';J++);
  338. if (HeaderLine(string(I,J-I)) == false)
  339. return 2;
  340. I = J;
  341. }
  342. return 0;
  343. }
  344. while (Owner->Go(false,this) == true);
  345. return 1;
  346. }
  347. /*}}}*/
  348. // ServerState::RunData - Transfer the data from the socket /*{{{*/
  349. // ---------------------------------------------------------------------
  350. /* */
  351. bool ServerState::RunData()
  352. {
  353. State = Data;
  354. // Chunked transfer encoding is fun..
  355. if (Encoding == Chunked)
  356. {
  357. while (1)
  358. {
  359. // Grab the block size
  360. bool Last = true;
  361. string Data;
  362. In.Limit(-1);
  363. do
  364. {
  365. if (In.WriteTillEl(Data,true) == true)
  366. break;
  367. }
  368. while ((Last = Owner->Go(false,this)) == true);
  369. if (Last == false)
  370. return false;
  371. // See if we are done
  372. unsigned long Len = strtol(Data.c_str(),0,16);
  373. if (Len == 0)
  374. {
  375. In.Limit(-1);
  376. // We have to remove the entity trailer
  377. Last = true;
  378. do
  379. {
  380. if (In.WriteTillEl(Data,true) == true && Data.length() <= 2)
  381. break;
  382. }
  383. while ((Last = Owner->Go(false,this)) == true);
  384. if (Last == false)
  385. return false;
  386. return !_error->PendingError();
  387. }
  388. // Transfer the block
  389. In.Limit(Len);
  390. while (Owner->Go(true,this) == true)
  391. if (In.IsLimit() == true)
  392. break;
  393. // Error
  394. if (In.IsLimit() == false)
  395. return false;
  396. // The server sends an extra new line before the next block specifier..
  397. In.Limit(-1);
  398. Last = true;
  399. do
  400. {
  401. if (In.WriteTillEl(Data,true) == true)
  402. break;
  403. }
  404. while ((Last = Owner->Go(false,this)) == true);
  405. if (Last == false)
  406. return false;
  407. }
  408. }
  409. else
  410. {
  411. /* Closes encoding is used when the server did not specify a size, the
  412. loss of the connection means we are done */
  413. if (Encoding == Closes)
  414. In.Limit(-1);
  415. else
  416. In.Limit(Size - StartPos);
  417. // Just transfer the whole block.
  418. do
  419. {
  420. if (In.IsLimit() == false)
  421. continue;
  422. In.Limit(-1);
  423. return !_error->PendingError();
  424. }
  425. while (Owner->Go(true,this) == true);
  426. }
  427. return Owner->Flush(this) && !_error->PendingError();
  428. }
  429. /*}}}*/
  430. // ServerState::HeaderLine - Process a header line /*{{{*/
  431. // ---------------------------------------------------------------------
  432. /* */
  433. bool ServerState::HeaderLine(string Line)
  434. {
  435. if (Line.empty() == true)
  436. return true;
  437. // The http server might be trying to do something evil.
  438. if (Line.length() >= MAXLEN)
  439. return _error->Error("Got a single header line over %u chars",MAXLEN);
  440. string::size_type Pos = Line.find(' ');
  441. if (Pos == string::npos || Pos+1 > Line.length())
  442. {
  443. // Blah, some servers use "connection:closes", evil.
  444. Pos = Line.find(':');
  445. if (Pos == string::npos || Pos + 2 > Line.length())
  446. return _error->Error("Bad header line");
  447. Pos++;
  448. }
  449. // Parse off any trailing spaces between the : and the next word.
  450. string::size_type Pos2 = Pos;
  451. while (Pos2 < Line.length() && isspace(Line[Pos2]) != 0)
  452. Pos2++;
  453. string Tag = string(Line,0,Pos);
  454. string Val = string(Line,Pos2);
  455. if (stringcasecmp(Tag.begin(),Tag.begin()+4,"HTTP") == 0)
  456. {
  457. // Evil servers return no version
  458. if (Line[4] == '/')
  459. {
  460. if (sscanf(Line.c_str(),"HTTP/%u.%u %u %[^\n]",&Major,&Minor,
  461. &Result,Code) != 4)
  462. return _error->Error("The http server sent an invalid reply header");
  463. }
  464. else
  465. {
  466. Major = 0;
  467. Minor = 9;
  468. if (sscanf(Line.c_str(),"HTTP %u %[^\n]",&Result,Code) != 2)
  469. return _error->Error("The http server sent an invalid reply header");
  470. }
  471. return true;
  472. }
  473. if (stringcasecmp(Tag,"Content-Length:") == 0)
  474. {
  475. if (Encoding == Closes)
  476. Encoding = Stream;
  477. HaveContent = true;
  478. // The length is already set from the Content-Range header
  479. if (StartPos != 0)
  480. return true;
  481. if (sscanf(Val.c_str(),"%lu",&Size) != 1)
  482. return _error->Error("The http server sent an invalid Content-Length header");
  483. return true;
  484. }
  485. if (stringcasecmp(Tag,"Content-Type:") == 0)
  486. {
  487. HaveContent = true;
  488. return true;
  489. }
  490. if (stringcasecmp(Tag,"Content-Range:") == 0)
  491. {
  492. HaveContent = true;
  493. if (sscanf(Val.c_str(),"bytes %lu-%*u/%lu",&StartPos,&Size) != 2)
  494. return _error->Error("The http server sent an invalid Content-Range header");
  495. if ((unsigned)StartPos > Size)
  496. return _error->Error("This http server has broken range support");
  497. return true;
  498. }
  499. if (stringcasecmp(Tag,"Transfer-Encoding:") == 0)
  500. {
  501. HaveContent = true;
  502. if (stringcasecmp(Val,"chunked") == 0)
  503. Encoding = Chunked;
  504. return true;
  505. }
  506. if (stringcasecmp(Tag,"Last-Modified:") == 0)
  507. {
  508. if (StrToTime(Val,Date) == false)
  509. return _error->Error("Unknown date format");
  510. return true;
  511. }
  512. return true;
  513. }
  514. /*}}}*/
  515. // HttpMethod::SendReq - Send the HTTP request /*{{{*/
  516. // ---------------------------------------------------------------------
  517. /* This places the http request in the outbound buffer */
  518. void HttpMethod::SendReq(FetchItem *Itm,CircleBuf &Out)
  519. {
  520. URI Uri = Itm->Uri;
  521. // The HTTP server expects a hostname with a trailing :port
  522. char Buf[1000];
  523. string ProperHost = Uri.Host;
  524. if (Uri.Port != 0)
  525. {
  526. sprintf(Buf,":%u",Uri.Port);
  527. ProperHost += Buf;
  528. }
  529. // Just in case.
  530. if (Itm->Uri.length() >= sizeof(Buf))
  531. abort();
  532. /* Build the request. We include a keep-alive header only for non-proxy
  533. requests. This is to tweak old http/1.0 servers that do support keep-alive
  534. but not HTTP/1.1 automatic keep-alive. Doing this with a proxy server
  535. will glitch HTTP/1.0 proxies because they do not filter it out and
  536. pass it on, HTTP/1.1 says the connection should default to keep alive
  537. and we expect the proxy to do this */
  538. if (Proxy.empty() == true)
  539. sprintf(Buf,"GET %s HTTP/1.1\r\nHost: %s\r\nConnection: keep-alive\r\n",
  540. QuoteString(Uri.Path,"~").c_str(),ProperHost.c_str());
  541. else
  542. {
  543. /* Generate a cache control header if necessary. We place a max
  544. cache age on index files, optionally set a no-cache directive
  545. and a no-store directive for archives. */
  546. sprintf(Buf,"GET %s HTTP/1.1\r\nHost: %s\r\n",
  547. Itm->Uri.c_str(),ProperHost.c_str());
  548. if (_config->FindB("Acquire::http::No-Cache",false) == true)
  549. strcat(Buf,"Cache-Control: no-cache\r\nPragma: no-cache\r\n");
  550. else
  551. {
  552. if (Itm->IndexFile == true)
  553. sprintf(Buf+strlen(Buf),"Cache-Control: max-age=%u\r\n",
  554. _config->FindI("Acquire::http::Max-Age",60*60*24));
  555. else
  556. {
  557. if (_config->FindB("Acquire::http::No-Store",false) == true)
  558. strcat(Buf,"Cache-Control: no-store\r\n");
  559. }
  560. }
  561. }
  562. string Req = Buf;
  563. // Check for a partial file
  564. struct stat SBuf;
  565. if (stat(Itm->DestFile.c_str(),&SBuf) >= 0 && SBuf.st_size > 0)
  566. {
  567. // In this case we send an if-range query with a range header
  568. sprintf(Buf,"Range: bytes=%li-\r\nIf-Range: %s\r\n",(long)SBuf.st_size - 1,
  569. TimeRFC1123(SBuf.st_mtime).c_str());
  570. Req += Buf;
  571. }
  572. else
  573. {
  574. if (Itm->LastModified != 0)
  575. {
  576. sprintf(Buf,"If-Modified-Since: %s\r\n",TimeRFC1123(Itm->LastModified).c_str());
  577. Req += Buf;
  578. }
  579. }
  580. if (Proxy.User.empty() == false || Proxy.Password.empty() == false)
  581. Req += string("Proxy-Authorization: Basic ") +
  582. Base64Encode(Proxy.User + ":" + Proxy.Password) + "\r\n";
  583. Req += "User-Agent: Debian APT-HTTP/1.2\r\n\r\n";
  584. if (Debug == true)
  585. cerr << Req << endl;
  586. Out.Read(Req);
  587. }
  588. /*}}}*/
  589. // HttpMethod::Go - Run a single loop /*{{{*/
  590. // ---------------------------------------------------------------------
  591. /* This runs the select loop over the server FDs, Output file FDs and
  592. stdin. */
  593. bool HttpMethod::Go(bool ToFile,ServerState *Srv)
  594. {
  595. // Server has closed the connection
  596. if (Srv->ServerFd == -1 && (Srv->In.WriteSpace() == false ||
  597. ToFile == false))
  598. return false;
  599. fd_set rfds,wfds;
  600. FD_ZERO(&rfds);
  601. FD_ZERO(&wfds);
  602. // Add the server
  603. if (Srv->Out.WriteSpace() == true && Srv->ServerFd != -1)
  604. FD_SET(Srv->ServerFd,&wfds);
  605. if (Srv->In.ReadSpace() == true && Srv->ServerFd != -1)
  606. FD_SET(Srv->ServerFd,&rfds);
  607. // Add the file
  608. int FileFD = -1;
  609. if (File != 0)
  610. FileFD = File->Fd();
  611. if (Srv->In.WriteSpace() == true && ToFile == true && FileFD != -1)
  612. FD_SET(FileFD,&wfds);
  613. // Add stdin
  614. FD_SET(STDIN_FILENO,&rfds);
  615. // Figure out the max fd
  616. int MaxFd = FileFD;
  617. if (MaxFd < Srv->ServerFd)
  618. MaxFd = Srv->ServerFd;
  619. // Select
  620. struct timeval tv;
  621. tv.tv_sec = TimeOut;
  622. tv.tv_usec = 0;
  623. int Res = 0;
  624. if ((Res = select(MaxFd+1,&rfds,&wfds,0,&tv)) < 0)
  625. return _error->Errno("select","Select failed");
  626. if (Res == 0)
  627. {
  628. _error->Error("Connection timed out");
  629. return ServerDie(Srv);
  630. }
  631. // Handle server IO
  632. if (Srv->ServerFd != -1 && FD_ISSET(Srv->ServerFd,&rfds))
  633. {
  634. errno = 0;
  635. if (Srv->In.Read(Srv->ServerFd) == false)
  636. return ServerDie(Srv);
  637. }
  638. if (Srv->ServerFd != -1 && FD_ISSET(Srv->ServerFd,&wfds))
  639. {
  640. errno = 0;
  641. if (Srv->Out.Write(Srv->ServerFd) == false)
  642. return ServerDie(Srv);
  643. }
  644. // Send data to the file
  645. if (FileFD != -1 && FD_ISSET(FileFD,&wfds))
  646. {
  647. if (Srv->In.Write(FileFD) == false)
  648. return _error->Errno("write","Error writing to output file");
  649. }
  650. // Handle commands from APT
  651. if (FD_ISSET(STDIN_FILENO,&rfds))
  652. {
  653. if (Run(true) != -1)
  654. exit(100);
  655. }
  656. return true;
  657. }
  658. /*}}}*/
  659. // HttpMethod::Flush - Dump the buffer into the file /*{{{*/
  660. // ---------------------------------------------------------------------
  661. /* This takes the current input buffer from the Server FD and writes it
  662. into the file */
  663. bool HttpMethod::Flush(ServerState *Srv)
  664. {
  665. if (File != 0)
  666. {
  667. SetNonBlock(File->Fd(),false);
  668. if (Srv->In.WriteSpace() == false)
  669. return true;
  670. while (Srv->In.WriteSpace() == true)
  671. {
  672. if (Srv->In.Write(File->Fd()) == false)
  673. return _error->Errno("write","Error writing to file");
  674. if (Srv->In.IsLimit() == true)
  675. return true;
  676. }
  677. if (Srv->In.IsLimit() == true || Srv->Encoding == ServerState::Closes)
  678. return true;
  679. }
  680. return false;
  681. }
  682. /*}}}*/
  683. // HttpMethod::ServerDie - The server has closed the connection. /*{{{*/
  684. // ---------------------------------------------------------------------
  685. /* */
  686. bool HttpMethod::ServerDie(ServerState *Srv)
  687. {
  688. unsigned int LErrno = errno;
  689. // Dump the buffer to the file
  690. if (Srv->State == ServerState::Data)
  691. {
  692. SetNonBlock(File->Fd(),false);
  693. while (Srv->In.WriteSpace() == true)
  694. {
  695. if (Srv->In.Write(File->Fd()) == false)
  696. return _error->Errno("write","Error writing to the file");
  697. // Done
  698. if (Srv->In.IsLimit() == true)
  699. return true;
  700. }
  701. }
  702. // See if this is because the server finished the data stream
  703. if (Srv->In.IsLimit() == false && Srv->State != ServerState::Header &&
  704. Srv->Encoding != ServerState::Closes)
  705. {
  706. Srv->Close();
  707. if (LErrno == 0)
  708. return _error->Error("Error reading from server Remote end closed connection");
  709. errno = LErrno;
  710. return _error->Errno("read","Error reading from server");
  711. }
  712. else
  713. {
  714. Srv->In.Limit(-1);
  715. // Nothing left in the buffer
  716. if (Srv->In.WriteSpace() == false)
  717. return false;
  718. // We may have got multiple responses back in one packet..
  719. Srv->Close();
  720. return true;
  721. }
  722. return false;
  723. }
  724. /*}}}*/
  725. // HttpMethod::DealWithHeaders - Handle the retrieved header data /*{{{*/
  726. // ---------------------------------------------------------------------
  727. /* We look at the header data we got back from the server and decide what
  728. to do. Returns
  729. 0 - File is open,
  730. 1 - IMS hit
  731. 3 - Unrecoverable error
  732. 4 - Error with error content page
  733. 5 - Unrecoverable non-server error (close the connection) */
  734. int HttpMethod::DealWithHeaders(FetchResult &Res,ServerState *Srv)
  735. {
  736. // Not Modified
  737. if (Srv->Result == 304)
  738. {
  739. unlink(Queue->DestFile.c_str());
  740. Res.IMSHit = true;
  741. Res.LastModified = Queue->LastModified;
  742. return 1;
  743. }
  744. /* We have a reply we dont handle. This should indicate a perm server
  745. failure */
  746. if (Srv->Result < 200 || Srv->Result >= 300)
  747. {
  748. _error->Error("%u %s",Srv->Result,Srv->Code);
  749. if (Srv->HaveContent == true)
  750. return 4;
  751. return 3;
  752. }
  753. // This is some sort of 2xx 'data follows' reply
  754. Res.LastModified = Srv->Date;
  755. Res.Size = Srv->Size;
  756. // Open the file
  757. delete File;
  758. File = new FileFd(Queue->DestFile,FileFd::WriteAny);
  759. if (_error->PendingError() == true)
  760. return 5;
  761. FailFile = Queue->DestFile;
  762. FailFile.c_str(); // Make sure we dont do a malloc in the signal handler
  763. FailFd = File->Fd();
  764. FailTime = Srv->Date;
  765. // Set the expected size
  766. if (Srv->StartPos >= 0)
  767. {
  768. Res.ResumePoint = Srv->StartPos;
  769. ftruncate(File->Fd(),Srv->StartPos);
  770. }
  771. // Set the start point
  772. lseek(File->Fd(),0,SEEK_END);
  773. delete Srv->In.MD5;
  774. Srv->In.MD5 = new MD5Summation;
  775. // Fill the MD5 Hash if the file is non-empty (resume)
  776. if (Srv->StartPos > 0)
  777. {
  778. lseek(File->Fd(),0,SEEK_SET);
  779. if (Srv->In.MD5->AddFD(File->Fd(),Srv->StartPos) == false)
  780. {
  781. _error->Errno("read","Problem hashing file");
  782. return 5;
  783. }
  784. lseek(File->Fd(),0,SEEK_END);
  785. }
  786. SetNonBlock(File->Fd(),true);
  787. return 0;
  788. }
  789. /*}}}*/
  790. // HttpMethod::SigTerm - Handle a fatal signal /*{{{*/
  791. // ---------------------------------------------------------------------
  792. /* This closes and timestamps the open file. This is neccessary to get
  793. resume behavoir on user abort */
  794. void HttpMethod::SigTerm(int)
  795. {
  796. if (FailFd == -1)
  797. _exit(100);
  798. close(FailFd);
  799. // Timestamp
  800. struct utimbuf UBuf;
  801. UBuf.actime = FailTime;
  802. UBuf.modtime = FailTime;
  803. utime(FailFile.c_str(),&UBuf);
  804. _exit(100);
  805. }
  806. /*}}}*/
  807. // HttpMethod::Fetch - Fetch an item /*{{{*/
  808. // ---------------------------------------------------------------------
  809. /* This adds an item to the pipeline. We keep the pipeline at a fixed
  810. depth. */
  811. bool HttpMethod::Fetch(FetchItem *)
  812. {
  813. if (Server == 0)
  814. return true;
  815. // Queue the requests
  816. int Depth = -1;
  817. bool Tail = false;
  818. for (FetchItem *I = Queue; I != 0 && Depth < (signed)PipelineDepth;
  819. I = I->Next, Depth++)
  820. {
  821. // If pipelining is disabled, we only queue 1 request
  822. if (Server->Pipeline == false && Depth >= 0)
  823. break;
  824. // Make sure we stick with the same server
  825. if (Server->Comp(I->Uri) == false)
  826. break;
  827. if (QueueBack == I)
  828. Tail = true;
  829. if (Tail == true)
  830. {
  831. QueueBack = I->Next;
  832. SendReq(I,Server->Out);
  833. continue;
  834. }
  835. }
  836. return true;
  837. };
  838. /*}}}*/
  839. // HttpMethod::Configuration - Handle a configuration message /*{{{*/
  840. // ---------------------------------------------------------------------
  841. /* We stash the desired pipeline depth */
  842. bool HttpMethod::Configuration(string Message)
  843. {
  844. if (pkgAcqMethod::Configuration(Message) == false)
  845. return false;
  846. TimeOut = _config->FindI("Acquire::http::Timeout",TimeOut);
  847. PipelineDepth = _config->FindI("Acquire::http::Pipeline-Depth",
  848. PipelineDepth);
  849. Debug = _config->FindB("Debug::Acquire::http",false);
  850. return true;
  851. }
  852. /*}}}*/
  853. // HttpMethod::Loop - Main loop /*{{{*/
  854. // ---------------------------------------------------------------------
  855. /* */
  856. int HttpMethod::Loop()
  857. {
  858. signal(SIGTERM,SigTerm);
  859. signal(SIGINT,SigTerm);
  860. Server = 0;
  861. int FailCounter = 0;
  862. while (1)
  863. {
  864. // We have no commands, wait for some to arrive
  865. if (Queue == 0)
  866. {
  867. if (WaitFd(STDIN_FILENO) == false)
  868. return 0;
  869. }
  870. /* Run messages, we can accept 0 (no message) if we didn't
  871. do a WaitFd above.. Otherwise the FD is closed. */
  872. int Result = Run(true);
  873. if (Result != -1 && (Result != 0 || Queue == 0))
  874. return 100;
  875. if (Queue == 0)
  876. continue;
  877. // Connect to the server
  878. if (Server == 0 || Server->Comp(Queue->Uri) == false)
  879. {
  880. delete Server;
  881. Server = new ServerState(Queue->Uri,this);
  882. }
  883. // Reset the pipeline
  884. if (Server->ServerFd == -1)
  885. QueueBack = Queue;
  886. // Connnect to the host
  887. if (Server->Open() == false)
  888. {
  889. Fail(true);
  890. delete Server;
  891. Server = 0;
  892. continue;
  893. }
  894. // Fill the pipeline.
  895. Fetch(0);
  896. // Fetch the next URL header data from the server.
  897. switch (Server->RunHeaders())
  898. {
  899. case 0:
  900. break;
  901. // The header data is bad
  902. case 2:
  903. {
  904. _error->Error("Bad header Data");
  905. Fail(true);
  906. continue;
  907. }
  908. // The server closed a connection during the header get..
  909. default:
  910. case 1:
  911. {
  912. FailCounter++;
  913. _error->Discard();
  914. Server->Close();
  915. Server->Pipeline = false;
  916. if (FailCounter >= 2)
  917. {
  918. Fail("Connection failed",true);
  919. FailCounter = 0;
  920. }
  921. continue;
  922. }
  923. };
  924. // Decide what to do.
  925. FetchResult Res;
  926. Res.Filename = Queue->DestFile;
  927. switch (DealWithHeaders(Res,Server))
  928. {
  929. // Ok, the file is Open
  930. case 0:
  931. {
  932. URIStart(Res);
  933. // Run the data
  934. bool Result = Server->RunData();
  935. // Close the file, destroy the FD object and timestamp it
  936. FailFd = -1;
  937. delete File;
  938. File = 0;
  939. // Timestamp
  940. struct utimbuf UBuf;
  941. time(&UBuf.actime);
  942. UBuf.actime = Server->Date;
  943. UBuf.modtime = Server->Date;
  944. utime(Queue->DestFile.c_str(),&UBuf);
  945. // Send status to APT
  946. if (Result == true)
  947. {
  948. Res.MD5Sum = Server->In.MD5->Result();
  949. URIDone(Res);
  950. }
  951. else
  952. Fail(true);
  953. break;
  954. }
  955. // IMS hit
  956. case 1:
  957. {
  958. URIDone(Res);
  959. break;
  960. }
  961. // Hard server error, not found or something
  962. case 3:
  963. {
  964. Fail();
  965. break;
  966. }
  967. // Hard internal error, kill the connection and fail
  968. case 5:
  969. {
  970. Fail();
  971. Server->Close();
  972. break;
  973. }
  974. // We need to flush the data, the header is like a 404 w/ error text
  975. case 4:
  976. {
  977. Fail();
  978. // Send to content to dev/null
  979. File = new FileFd("/dev/null",FileFd::WriteExists);
  980. Server->RunData();
  981. delete File;
  982. File = 0;
  983. break;
  984. }
  985. default:
  986. Fail("Internal error");
  987. break;
  988. }
  989. FailCounter = 0;
  990. }
  991. return 0;
  992. }
  993. /*}}}*/
  994. int main()
  995. {
  996. HttpMethod Mth;
  997. return Mth.Loop();
  998. }