You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

999 lines
28 KiB

  1. // -*- mode: cpp; mode: fold -*-
  2. // Description /*{{{*/
  3. // $Id: http.cc,v 1.59 2004/05/08 19:42:35 mdz Exp $
  4. /* ######################################################################
  5. HTTP Acquire Method - This is the HTTP acquire 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.
  8. It is based on a doubly buffered select loop. A groupe of requests are
  9. fed into a single output buffer that is constantly fed out the
  10. socket. This provides ideal pipelining as in many cases all of the
  11. requests will fit into a single packet. The input socket is buffered
  12. the same way and fed into the fd for the file (may be a pipe in future).
  13. ##################################################################### */
  14. /*}}}*/
  15. // Include Files /*{{{*/
  16. #include <config.h>
  17. #include <apt-pkg/configuration.h>
  18. #include <apt-pkg/error.h>
  19. #include <apt-pkg/fileutl.h>
  20. #include <apt-pkg/hashes.h>
  21. #include <apt-pkg/proxy.h>
  22. #include <apt-pkg/strutl.h>
  23. #include <cstring>
  24. #include <iostream>
  25. #include <sstream>
  26. #include <arpa/inet.h>
  27. #include <errno.h>
  28. #include <stddef.h>
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <sys/select.h>
  32. #include <sys/stat.h>
  33. #include <sys/time.h>
  34. #include <unistd.h>
  35. #include "config.h"
  36. #include "connect.h"
  37. #include "http.h"
  38. #include <apti18n.h>
  39. /*}}}*/
  40. using namespace std;
  41. unsigned long long CircleBuf::BwReadLimit=0;
  42. unsigned long long CircleBuf::BwTickReadData=0;
  43. struct timeval CircleBuf::BwReadTick={0,0};
  44. const unsigned int CircleBuf::BW_HZ=10;
  45. // CircleBuf::CircleBuf - Circular input buffer /*{{{*/
  46. // ---------------------------------------------------------------------
  47. /* */
  48. CircleBuf::CircleBuf(HttpMethod const * const Owner, unsigned long long Size)
  49. : Size(Size), Hash(NULL), TotalWriten(0)
  50. {
  51. Buf = new unsigned char[Size];
  52. Reset();
  53. CircleBuf::BwReadLimit = Owner->ConfigFindI("Dl-Limit", 0) * 1024;
  54. }
  55. /*}}}*/
  56. // CircleBuf::Reset - Reset to the default state /*{{{*/
  57. // ---------------------------------------------------------------------
  58. /* */
  59. void CircleBuf::Reset()
  60. {
  61. InP = 0;
  62. OutP = 0;
  63. StrPos = 0;
  64. TotalWriten = 0;
  65. MaxGet = (unsigned long long)-1;
  66. OutQueue = string();
  67. if (Hash != NULL)
  68. {
  69. delete Hash;
  70. Hash = NULL;
  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(std::unique_ptr<MethodFd> const &Fd)
  79. {
  80. while (1)
  81. {
  82. // Woops, buffer is full
  83. if (InP - OutP == Size)
  84. return true;
  85. // what's left to read in this tick
  86. unsigned long long const BwReadMax = CircleBuf::BwReadLimit/BW_HZ;
  87. if(CircleBuf::BwReadLimit) {
  88. struct timeval now;
  89. gettimeofday(&now,0);
  90. unsigned long long d = (now.tv_sec-CircleBuf::BwReadTick.tv_sec)*1000000 +
  91. now.tv_usec-CircleBuf::BwReadTick.tv_usec;
  92. if(d > 1000000/BW_HZ) {
  93. CircleBuf::BwReadTick = now;
  94. CircleBuf::BwTickReadData = 0;
  95. }
  96. if(CircleBuf::BwTickReadData >= BwReadMax) {
  97. usleep(1000000/BW_HZ);
  98. return true;
  99. }
  100. }
  101. // Write the buffer segment
  102. ssize_t Res;
  103. if(CircleBuf::BwReadLimit) {
  104. Res = Fd->Read(Buf + (InP % Size),
  105. BwReadMax > LeftRead() ? LeftRead() : BwReadMax);
  106. } else
  107. Res = Fd->Read(Buf + (InP % Size), LeftRead());
  108. if(Res > 0 && BwReadLimit > 0)
  109. CircleBuf::BwTickReadData += Res;
  110. if (Res == 0)
  111. return false;
  112. if (Res < 0)
  113. {
  114. if (errno == EAGAIN)
  115. return true;
  116. return false;
  117. }
  118. if (InP == 0)
  119. gettimeofday(&Start,0);
  120. InP += Res;
  121. }
  122. }
  123. /*}}}*/
  124. // CircleBuf::Read - Put the string into the buffer /*{{{*/
  125. // ---------------------------------------------------------------------
  126. /* This will hold the string in and fill the buffer with it as it empties */
  127. bool CircleBuf::Read(string const &Data)
  128. {
  129. OutQueue.append(Data);
  130. FillOut();
  131. return true;
  132. }
  133. /*}}}*/
  134. // CircleBuf::FillOut - Fill the buffer from the output queue /*{{{*/
  135. // ---------------------------------------------------------------------
  136. /* */
  137. void CircleBuf::FillOut()
  138. {
  139. if (OutQueue.empty() == true)
  140. return;
  141. while (1)
  142. {
  143. // Woops, buffer is full
  144. if (InP - OutP == Size)
  145. return;
  146. // Write the buffer segment
  147. unsigned long 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. // Advance
  152. StrPos += Sz;
  153. InP += Sz;
  154. if (OutQueue.length() == StrPos)
  155. {
  156. StrPos = 0;
  157. OutQueue = "";
  158. return;
  159. }
  160. }
  161. }
  162. /*}}}*/
  163. // CircleBuf::Write - Write from the buffer into a FD /*{{{*/
  164. // ---------------------------------------------------------------------
  165. /* This empties the buffer into the FD. */
  166. bool CircleBuf::Write(std::unique_ptr<MethodFd> const &Fd)
  167. {
  168. while (1)
  169. {
  170. FillOut();
  171. // Woops, buffer is empty
  172. if (OutP == InP)
  173. return true;
  174. if (OutP == MaxGet)
  175. return true;
  176. // Write the buffer segment
  177. ssize_t Res;
  178. Res = Fd->Write(Buf + (OutP % Size), LeftWrite());
  179. if (Res == 0)
  180. return false;
  181. if (Res < 0)
  182. {
  183. if (errno == EAGAIN)
  184. return true;
  185. return false;
  186. }
  187. TotalWriten += Res;
  188. if (Hash != NULL)
  189. Hash->Add(Buf + (OutP%Size),Res);
  190. OutP += Res;
  191. }
  192. }
  193. /*}}}*/
  194. // CircleBuf::WriteTillEl - Write from the buffer to a string /*{{{*/
  195. // ---------------------------------------------------------------------
  196. /* This copies till the first empty line */
  197. bool CircleBuf::WriteTillEl(string &Data,bool Single)
  198. {
  199. // We cheat and assume it is unneeded to have more than one buffer load
  200. for (unsigned long long I = OutP; I < InP; I++)
  201. {
  202. if (Buf[I%Size] != '\n')
  203. continue;
  204. ++I;
  205. if (Single == false)
  206. {
  207. if (I < InP && Buf[I%Size] == '\r')
  208. ++I;
  209. if (I >= InP || Buf[I%Size] != '\n')
  210. continue;
  211. ++I;
  212. }
  213. Data = "";
  214. while (OutP < I)
  215. {
  216. unsigned long long Sz = LeftWrite();
  217. if (Sz == 0)
  218. return false;
  219. if (I - OutP < Sz)
  220. Sz = I - OutP;
  221. Data += string((char *)(Buf + (OutP%Size)),Sz);
  222. OutP += Sz;
  223. }
  224. return true;
  225. }
  226. return false;
  227. }
  228. /*}}}*/
  229. // CircleBuf::Write - Write from the buffer to a string /*{{{*/
  230. // ---------------------------------------------------------------------
  231. /* This copies everything */
  232. bool CircleBuf::Write(string &Data)
  233. {
  234. Data = std::string((char *)Buf + (OutP % Size), LeftWrite());
  235. OutP += LeftWrite();
  236. return true;
  237. }
  238. /*}}}*/
  239. // CircleBuf::Stats - Print out stats information /*{{{*/
  240. // ---------------------------------------------------------------------
  241. /* */
  242. void CircleBuf::Stats()
  243. {
  244. if (InP == 0)
  245. return;
  246. struct timeval Stop;
  247. gettimeofday(&Stop,0);
  248. /* float Diff = Stop.tv_sec - Start.tv_sec +
  249. (float)(Stop.tv_usec - Start.tv_usec)/1000000;
  250. clog << "Got " << InP << " in " << Diff << " at " << InP/Diff << endl;*/
  251. }
  252. /*}}}*/
  253. CircleBuf::~CircleBuf() /*{{{*/
  254. {
  255. delete [] Buf;
  256. delete Hash;
  257. }
  258. /*}}}*/
  259. // UnwrapHTTPConnect - Does the HTTP CONNECT handshake /*{{{*/
  260. // ---------------------------------------------------------------------
  261. /* Performs a TLS handshake on the socket */
  262. struct HttpConnectFd : public MethodFd
  263. {
  264. std::unique_ptr<MethodFd> UnderlyingFd;
  265. std::string Buffer;
  266. int Fd() APT_OVERRIDE { return UnderlyingFd->Fd(); }
  267. ssize_t Read(void *buf, size_t count) APT_OVERRIDE
  268. {
  269. if (!Buffer.empty())
  270. {
  271. auto read = count < Buffer.size() ? count : Buffer.size();
  272. memcpy(buf, Buffer.data(), read);
  273. Buffer.erase(Buffer.begin(), Buffer.begin() + read);
  274. return read;
  275. }
  276. return UnderlyingFd->Read(buf, count);
  277. }
  278. ssize_t Write(void *buf, size_t count) APT_OVERRIDE
  279. {
  280. return UnderlyingFd->Write(buf, count);
  281. }
  282. int Close() APT_OVERRIDE
  283. {
  284. return UnderlyingFd->Close();
  285. }
  286. bool HasPending() APT_OVERRIDE
  287. {
  288. return !Buffer.empty();
  289. }
  290. };
  291. bool UnwrapHTTPConnect(std::string Host, int Port, URI Proxy, std::unique_ptr<MethodFd> &Fd,
  292. unsigned long Timeout, aptMethod *Owner)
  293. {
  294. Owner->Status(_("Connecting to %s (%s)"), "HTTP proxy", URI::SiteOnly(Proxy).c_str());
  295. // The HTTP server expects a hostname with a trailing :port
  296. std::stringstream Req;
  297. std::string ProperHost;
  298. if (Host.find(':') != std::string::npos)
  299. ProperHost = '[' + Proxy.Host + ']';
  300. else
  301. ProperHost = Proxy.Host;
  302. // Build the connect
  303. Req << "CONNECT " << Host << ":" << std::to_string(Port) << " HTTP/1.1\r\n";
  304. if (Proxy.Port != 0)
  305. Req << "Host: " << ProperHost << ":" << std::to_string(Proxy.Port) << "\r\n";
  306. else
  307. Req << "Host: " << ProperHost << "\r\n";
  308. ;
  309. Owner->MaybeAddAuthTo(Proxy);
  310. if (Proxy.User.empty() == false || Proxy.Password.empty() == false)
  311. Req << "Proxy-Authorization: Basic "
  312. << Base64Encode(Proxy.User + ":" + Proxy.Password) << "\r\n";
  313. Req << "User-Agent: " << Owner->ConfigFind("User-Agent", "Debian APT-HTTP/1.3 (" PACKAGE_VERSION ")") << "\r\n";
  314. Req << "\r\n";
  315. CircleBuf In(dynamic_cast<HttpMethod *>(Owner), 4096);
  316. CircleBuf Out(dynamic_cast<HttpMethod *>(Owner), 4096);
  317. std::string Headers;
  318. if (Owner->DebugEnabled() == true)
  319. cerr << Req.str() << endl;
  320. Out.Read(Req.str());
  321. // Writing from proxy
  322. while (Out.WriteSpace() > 0)
  323. {
  324. if (WaitFd(Fd->Fd(), true, Timeout) == false)
  325. return _error->Errno("select", "Writing to proxy failed");
  326. if (Out.Write(Fd) == false)
  327. return _error->Errno("write", "Writing to proxy failed");
  328. }
  329. while (In.ReadSpace() > 0)
  330. {
  331. if (WaitFd(Fd->Fd(), false, Timeout) == false)
  332. return _error->Errno("select", "Reading from proxy failed");
  333. if (In.Read(Fd) == false)
  334. return _error->Errno("read", "Reading from proxy failed");
  335. if (In.WriteTillEl(Headers))
  336. break;
  337. }
  338. if (Owner->DebugEnabled() == true)
  339. cerr << Headers << endl;
  340. if (!(APT::String::Startswith(Headers, "HTTP/1.0 200") || APT::String::Startswith(Headers, "HTTP/1.1 200")))
  341. return _error->Error("Invalid response from proxy: %s", Headers.c_str());
  342. if (In.WriteSpace() > 0)
  343. {
  344. // Maybe there is actual data already read, if so we need to buffer it
  345. std::unique_ptr<HttpConnectFd> NewFd(new HttpConnectFd());
  346. In.Write(NewFd->Buffer);
  347. NewFd->UnderlyingFd = std::move(Fd);
  348. Fd = std::move(NewFd);
  349. }
  350. return true;
  351. }
  352. /*}}}*/
  353. // HttpServerState::HttpServerState - Constructor /*{{{*/
  354. HttpServerState::HttpServerState(URI Srv,HttpMethod *Owner) : ServerState(Srv, Owner), In(Owner, 64*1024), Out(Owner, 4*1024)
  355. {
  356. TimeOut = Owner->ConfigFindI("Timeout", TimeOut);
  357. ServerFd = MethodFd::FromFd(-1);
  358. Reset();
  359. }
  360. /*}}}*/
  361. // HttpServerState::Open - Open a connection to the server /*{{{*/
  362. // ---------------------------------------------------------------------
  363. /* This opens a connection to the server. */
  364. bool HttpServerState::Open()
  365. {
  366. // Use the already open connection if possible.
  367. if (ServerFd->Fd() != -1)
  368. return true;
  369. Close();
  370. In.Reset();
  371. Out.Reset();
  372. Persistent = true;
  373. // Determine the proxy setting
  374. AutoDetectProxy(ServerName);
  375. string SpecificProxy = Owner->ConfigFind("Proxy::" + ServerName.Host, "");
  376. if (!SpecificProxy.empty())
  377. {
  378. if (SpecificProxy == "DIRECT")
  379. Proxy = "";
  380. else
  381. Proxy = SpecificProxy;
  382. }
  383. else
  384. {
  385. string DefProxy = Owner->ConfigFind("Proxy", "");
  386. if (!DefProxy.empty())
  387. {
  388. Proxy = DefProxy;
  389. }
  390. else
  391. {
  392. char* result = getenv("http_proxy");
  393. Proxy = result ? result : "";
  394. }
  395. }
  396. // Parse no_proxy, a , separated list of domains
  397. if (getenv("no_proxy") != 0)
  398. {
  399. if (CheckDomainList(ServerName.Host,getenv("no_proxy")) == true)
  400. Proxy = "";
  401. }
  402. if (Proxy.empty() == false)
  403. Owner->AddProxyAuth(Proxy, ServerName);
  404. bool tls = (ServerName.Access == "https" || APT::String::Endswith(ServerName.Access, "+https"));
  405. auto const DefaultService = tls ? "https" : "http";
  406. auto const DefaultPort = tls ? 443 : 80;
  407. if (Proxy.Access == "socks5h")
  408. {
  409. if (Connect(Proxy.Host, Proxy.Port, "socks", 1080, ServerFd, TimeOut, Owner) == false)
  410. return false;
  411. if (UnwrapSocks(ServerName.Host, ServerName.Port == 0 ? DefaultPort : ServerName.Port,
  412. Proxy, ServerFd, Owner->ConfigFindI("TimeOut", 120), Owner) == false)
  413. return false;
  414. }
  415. else
  416. {
  417. // Determine what host and port to use based on the proxy settings
  418. int Port = 0;
  419. string Host;
  420. if (Proxy.empty() == true || Proxy.Host.empty() == true)
  421. {
  422. if (ServerName.Port != 0)
  423. Port = ServerName.Port;
  424. Host = ServerName.Host;
  425. }
  426. else if (Proxy.Access != "http" && Proxy.Access != "https")
  427. return _error->Error("Unsupported proxy configured: %s", URI::SiteOnly(Proxy).c_str());
  428. else
  429. {
  430. if (Proxy.Port != 0)
  431. Port = Proxy.Port;
  432. Host = Proxy.Host;
  433. if (Proxy.Access == "https" && Port == 0)
  434. Port = 443;
  435. }
  436. if (!Connect(Host, Port, DefaultService, DefaultPort, ServerFd, TimeOut, Owner))
  437. return false;
  438. if (Host == Proxy.Host && Proxy.Access == "https" && UnwrapTLS(Proxy.Host, ServerFd, TimeOut, Owner) == false)
  439. return false;
  440. if (Host == Proxy.Host && tls && UnwrapHTTPConnect(ServerName.Host, ServerName.Port == 0 ? DefaultPort : ServerName.Port, Proxy, ServerFd, Owner->ConfigFindI("TimeOut", 120), Owner) == false)
  441. return false;
  442. }
  443. if (tls && UnwrapTLS(ServerName.Host, ServerFd, TimeOut, Owner) == false)
  444. return false;
  445. return true;
  446. }
  447. /*}}}*/
  448. // HttpServerState::Close - Close a connection to the server /*{{{*/
  449. // ---------------------------------------------------------------------
  450. /* */
  451. bool HttpServerState::Close()
  452. {
  453. ServerFd->Close();
  454. return true;
  455. }
  456. /*}}}*/
  457. // HttpServerState::RunData - Transfer the data from the socket /*{{{*/
  458. bool HttpServerState::RunData(RequestState &Req)
  459. {
  460. Req.State = RequestState::Data;
  461. // Chunked transfer encoding is fun..
  462. if (Req.Encoding == RequestState::Chunked)
  463. {
  464. while (1)
  465. {
  466. // Grab the block size
  467. bool Last = true;
  468. string Data;
  469. In.Limit(-1);
  470. do
  471. {
  472. if (In.WriteTillEl(Data,true) == true)
  473. break;
  474. }
  475. while ((Last = Go(false, Req)) == true);
  476. if (Last == false)
  477. return false;
  478. // See if we are done
  479. unsigned long long Len = strtoull(Data.c_str(),0,16);
  480. if (Len == 0)
  481. {
  482. In.Limit(-1);
  483. // We have to remove the entity trailer
  484. Last = true;
  485. do
  486. {
  487. if (In.WriteTillEl(Data,true) == true && Data.length() <= 2)
  488. break;
  489. }
  490. while ((Last = Go(false, Req)) == true);
  491. if (Last == false)
  492. return false;
  493. return !_error->PendingError();
  494. }
  495. // Transfer the block
  496. In.Limit(Len);
  497. while (Go(true, Req) == true)
  498. if (In.IsLimit() == true)
  499. break;
  500. // Error
  501. if (In.IsLimit() == false)
  502. return false;
  503. // The server sends an extra new line before the next block specifier..
  504. In.Limit(-1);
  505. Last = true;
  506. do
  507. {
  508. if (In.WriteTillEl(Data,true) == true)
  509. break;
  510. }
  511. while ((Last = Go(false, Req)) == true);
  512. if (Last == false)
  513. return false;
  514. }
  515. }
  516. else
  517. {
  518. /* Closes encoding is used when the server did not specify a size, the
  519. loss of the connection means we are done */
  520. if (Req.JunkSize != 0)
  521. In.Limit(Req.JunkSize);
  522. else if (Req.DownloadSize != 0)
  523. {
  524. if (Req.MaximumSize != 0 && Req.DownloadSize > Req.MaximumSize)
  525. {
  526. Owner->SetFailReason("MaximumSizeExceeded");
  527. return _error->Error(_("File has unexpected size (%llu != %llu). Mirror sync in progress?"),
  528. Req.DownloadSize, Req.MaximumSize);
  529. }
  530. In.Limit(Req.DownloadSize);
  531. }
  532. else if (Persistent == false)
  533. In.Limit(-1);
  534. // Just transfer the whole block.
  535. do
  536. {
  537. if (In.IsLimit() == false)
  538. continue;
  539. In.Limit(-1);
  540. return !_error->PendingError();
  541. }
  542. while (Go(true, Req) == true);
  543. }
  544. return Flush(&Req.File) && !_error->PendingError();
  545. }
  546. /*}}}*/
  547. bool HttpServerState::RunDataToDevNull(RequestState &Req) /*{{{*/
  548. {
  549. // no need to clean up if we discard the connection anyhow
  550. if (Persistent == false)
  551. return true;
  552. Req.File.Open("/dev/null", FileFd::WriteOnly);
  553. return RunData(Req);
  554. }
  555. /*}}}*/
  556. bool HttpServerState::ReadHeaderLines(std::string &Data) /*{{{*/
  557. {
  558. return In.WriteTillEl(Data);
  559. }
  560. /*}}}*/
  561. bool HttpServerState::LoadNextResponse(bool const ToFile, RequestState &Req)/*{{{*/
  562. {
  563. return Go(ToFile, Req);
  564. }
  565. /*}}}*/
  566. bool HttpServerState::WriteResponse(const std::string &Data) /*{{{*/
  567. {
  568. return Out.Read(Data);
  569. }
  570. /*}}}*/
  571. APT_PURE bool HttpServerState::IsOpen() /*{{{*/
  572. {
  573. return (ServerFd->Fd() != -1);
  574. }
  575. /*}}}*/
  576. bool HttpServerState::InitHashes(HashStringList const &ExpectedHashes) /*{{{*/
  577. {
  578. delete In.Hash;
  579. In.Hash = new Hashes(ExpectedHashes);
  580. return true;
  581. }
  582. /*}}}*/
  583. void HttpServerState::Reset() /*{{{*/
  584. {
  585. ServerState::Reset();
  586. ServerFd->Close();
  587. }
  588. /*}}}*/
  589. APT_PURE Hashes * HttpServerState::GetHashes() /*{{{*/
  590. {
  591. return In.Hash;
  592. }
  593. /*}}}*/
  594. // HttpServerState::Die - The server has closed the connection. /*{{{*/
  595. bool HttpServerState::Die(RequestState &Req)
  596. {
  597. unsigned int LErrno = errno;
  598. // Dump the buffer to the file
  599. if (Req.State == RequestState::Data)
  600. {
  601. if (Req.File.IsOpen() == false)
  602. return true;
  603. // on GNU/kFreeBSD, apt dies on /dev/null because non-blocking
  604. // can't be set
  605. if (Req.File.Name() != "/dev/null")
  606. SetNonBlock(Req.File.Fd(),false);
  607. while (In.WriteSpace() == true)
  608. {
  609. if (In.Write(MethodFd::FromFd(Req.File.Fd())) == false)
  610. return _error->Errno("write",_("Error writing to the file"));
  611. // Done
  612. if (In.IsLimit() == true)
  613. return true;
  614. }
  615. }
  616. // See if this is because the server finished the data stream
  617. if (In.IsLimit() == false && Req.State != RequestState::Header &&
  618. Persistent == true)
  619. {
  620. Close();
  621. if (LErrno == 0)
  622. return _error->Error(_("Error reading from server. Remote end closed connection"));
  623. errno = LErrno;
  624. return _error->Errno("read",_("Error reading from server"));
  625. }
  626. else
  627. {
  628. In.Limit(-1);
  629. // Nothing left in the buffer
  630. if (In.WriteSpace() == false)
  631. return false;
  632. // We may have got multiple responses back in one packet..
  633. Close();
  634. return true;
  635. }
  636. return false;
  637. }
  638. /*}}}*/
  639. // HttpServerState::Flush - Dump the buffer into the file /*{{{*/
  640. // ---------------------------------------------------------------------
  641. /* This takes the current input buffer from the Server FD and writes it
  642. into the file */
  643. bool HttpServerState::Flush(FileFd * const File)
  644. {
  645. if (File != nullptr)
  646. {
  647. // on GNU/kFreeBSD, apt dies on /dev/null because non-blocking
  648. // can't be set
  649. if (File->Name() != "/dev/null")
  650. SetNonBlock(File->Fd(),false);
  651. if (In.WriteSpace() == false)
  652. return true;
  653. while (In.WriteSpace() == true)
  654. {
  655. if (In.Write(MethodFd::FromFd(File->Fd())) == false)
  656. return _error->Errno("write",_("Error writing to file"));
  657. if (In.IsLimit() == true)
  658. return true;
  659. }
  660. if (In.IsLimit() == true || Persistent == false)
  661. return true;
  662. }
  663. return false;
  664. }
  665. /*}}}*/
  666. // HttpServerState::Go - Run a single loop /*{{{*/
  667. // ---------------------------------------------------------------------
  668. /* This runs the select loop over the server FDs, Output file FDs and
  669. stdin. */
  670. bool HttpServerState::Go(bool ToFile, RequestState &Req)
  671. {
  672. // Server has closed the connection
  673. if (ServerFd->Fd() == -1 && (In.WriteSpace() == false ||
  674. ToFile == false))
  675. return false;
  676. // Handle server IO
  677. if (ServerFd->HasPending() && In.ReadSpace() == true)
  678. {
  679. errno = 0;
  680. if (In.Read(ServerFd) == false)
  681. return Die(Req);
  682. }
  683. fd_set rfds,wfds;
  684. FD_ZERO(&rfds);
  685. FD_ZERO(&wfds);
  686. /* Add the server. We only send more requests if the connection will
  687. be persisting */
  688. if (Out.WriteSpace() == true && ServerFd->Fd() != -1 && Persistent == true)
  689. FD_SET(ServerFd->Fd(), &wfds);
  690. if (In.ReadSpace() == true && ServerFd->Fd() != -1)
  691. FD_SET(ServerFd->Fd(), &rfds);
  692. // Add the file
  693. auto FileFD = MethodFd::FromFd(-1);
  694. if (Req.File.IsOpen())
  695. FileFD = MethodFd::FromFd(Req.File.Fd());
  696. if (In.WriteSpace() == true && ToFile == true && FileFD->Fd() != -1)
  697. FD_SET(FileFD->Fd(), &wfds);
  698. // Add stdin
  699. if (Owner->ConfigFindB("DependOnSTDIN", true) == true)
  700. FD_SET(STDIN_FILENO,&rfds);
  701. // Figure out the max fd
  702. int MaxFd = FileFD->Fd();
  703. if (MaxFd < ServerFd->Fd())
  704. MaxFd = ServerFd->Fd();
  705. // Select
  706. struct timeval tv;
  707. tv.tv_sec = TimeOut;
  708. tv.tv_usec = 0;
  709. int Res = 0;
  710. if ((Res = select(MaxFd+1,&rfds,&wfds,0,&tv)) < 0)
  711. {
  712. if (errno == EINTR)
  713. return true;
  714. return _error->Errno("select",_("Select failed"));
  715. }
  716. if (Res == 0)
  717. {
  718. _error->Error(_("Connection timed out"));
  719. return Die(Req);
  720. }
  721. // Handle server IO
  722. if (ServerFd->Fd() != -1 && FD_ISSET(ServerFd->Fd(), &rfds))
  723. {
  724. errno = 0;
  725. if (In.Read(ServerFd) == false)
  726. return Die(Req);
  727. }
  728. if (ServerFd->Fd() != -1 && FD_ISSET(ServerFd->Fd(), &wfds))
  729. {
  730. errno = 0;
  731. if (Out.Write(ServerFd) == false)
  732. return Die(Req);
  733. }
  734. // Send data to the file
  735. if (FileFD->Fd() != -1 && FD_ISSET(FileFD->Fd(), &wfds))
  736. {
  737. if (In.Write(FileFD) == false)
  738. return _error->Errno("write",_("Error writing to output file"));
  739. }
  740. if (Req.MaximumSize > 0 && Req.File.IsOpen() && Req.File.Failed() == false && Req.File.Tell() > Req.MaximumSize)
  741. {
  742. Owner->SetFailReason("MaximumSizeExceeded");
  743. return _error->Error(_("File has unexpected size (%llu != %llu). Mirror sync in progress?"),
  744. Req.File.Tell(), Req.MaximumSize);
  745. }
  746. // Handle commands from APT
  747. if (FD_ISSET(STDIN_FILENO,&rfds))
  748. {
  749. if (Owner->Run(true) != -1)
  750. exit(100);
  751. }
  752. return true;
  753. }
  754. /*}}}*/
  755. // HttpMethod::SendReq - Send the HTTP request /*{{{*/
  756. // ---------------------------------------------------------------------
  757. /* This places the http request in the outbound buffer */
  758. void HttpMethod::SendReq(FetchItem *Itm)
  759. {
  760. URI Uri = Itm->Uri;
  761. {
  762. auto const plus = Binary.find('+');
  763. if (plus != std::string::npos)
  764. Uri.Access = Binary.substr(plus + 1);
  765. }
  766. // The HTTP server expects a hostname with a trailing :port
  767. std::stringstream Req;
  768. string ProperHost;
  769. if (Uri.Host.find(':') != string::npos)
  770. ProperHost = '[' + Uri.Host + ']';
  771. else
  772. ProperHost = Uri.Host;
  773. /* RFC 2616 ยง5.1.2 requires absolute URIs for requests to proxies,
  774. but while its a must for all servers to accept absolute URIs,
  775. it is assumed clients will sent an absolute path for non-proxies */
  776. std::string requesturi;
  777. if ((Server->Proxy.Access != "http" && Server->Proxy.Access != "https") || APT::String::Endswith(Uri.Access, "https") || Server->Proxy.empty() == true || Server->Proxy.Host.empty())
  778. requesturi = Uri.Path;
  779. else
  780. requesturi = Uri;
  781. // The "+" is encoded as a workaround for a amazon S3 bug
  782. // see LP bugs #1003633 and #1086997.
  783. requesturi = QuoteString(requesturi, "+~ ");
  784. /* Build the request. No keep-alive is included as it is the default
  785. in 1.1, can cause problems with proxies, and we are an HTTP/1.1
  786. client anyway.
  787. C.f. https://tools.ietf.org/wg/httpbis/trac/ticket/158 */
  788. Req << "GET " << requesturi << " HTTP/1.1\r\n";
  789. if (Uri.Port != 0)
  790. Req << "Host: " << ProperHost << ":" << std::to_string(Uri.Port) << "\r\n";
  791. else
  792. Req << "Host: " << ProperHost << "\r\n";
  793. // generate a cache control header (if needed)
  794. if (ConfigFindB("No-Cache",false) == true)
  795. Req << "Cache-Control: no-cache\r\n"
  796. << "Pragma: no-cache\r\n";
  797. else if (Itm->IndexFile == true)
  798. Req << "Cache-Control: max-age=" << std::to_string(ConfigFindI("Max-Age", 0)) << "\r\n";
  799. else if (ConfigFindB("No-Store", false) == true)
  800. Req << "Cache-Control: no-store\r\n";
  801. // If we ask for uncompressed files servers might respond with content-
  802. // negotiation which lets us end up with compressed files we do not support,
  803. // see 657029, 657560 and co, so if we have no extension on the request
  804. // ask for text only. As a sidenote: If there is nothing to negotate servers
  805. // seem to be nice and ignore it.
  806. if (ConfigFindB("SendAccept", true) == true)
  807. {
  808. size_t const filepos = Itm->Uri.find_last_of('/');
  809. string const file = Itm->Uri.substr(filepos + 1);
  810. if (flExtension(file) == file)
  811. Req << "Accept: text/*\r\n";
  812. }
  813. // Check for a partial file and send if-queries accordingly
  814. struct stat SBuf;
  815. if (Server->RangesAllowed && stat(Itm->DestFile.c_str(),&SBuf) >= 0 && SBuf.st_size > 0)
  816. Req << "Range: bytes=" << std::to_string(SBuf.st_size) << "-\r\n"
  817. << "If-Range: " << TimeRFC1123(SBuf.st_mtime, false) << "\r\n";
  818. else if (Itm->LastModified != 0)
  819. Req << "If-Modified-Since: " << TimeRFC1123(Itm->LastModified, false).c_str() << "\r\n";
  820. if ((Server->Proxy.Access == "http" || Server->Proxy.Access == "https") &&
  821. (Server->Proxy.User.empty() == false || Server->Proxy.Password.empty() == false))
  822. Req << "Proxy-Authorization: Basic "
  823. << Base64Encode(Server->Proxy.User + ":" + Server->Proxy.Password) << "\r\n";
  824. MaybeAddAuthTo(Uri);
  825. if (Uri.User.empty() == false || Uri.Password.empty() == false)
  826. Req << "Authorization: Basic "
  827. << Base64Encode(Uri.User + ":" + Uri.Password) << "\r\n";
  828. Req << "User-Agent: " << ConfigFind("User-Agent",
  829. "Debian APT-HTTP/1.3 (" PACKAGE_VERSION ")") << "\r\n";
  830. Req << "\r\n";
  831. if (Debug == true)
  832. cerr << Req.str() << endl;
  833. Server->WriteResponse(Req.str());
  834. }
  835. /*}}}*/
  836. std::unique_ptr<ServerState> HttpMethod::CreateServerState(URI const &uri)/*{{{*/
  837. {
  838. return std::unique_ptr<ServerState>(new HttpServerState(uri, this));
  839. }
  840. /*}}}*/
  841. void HttpMethod::RotateDNS() /*{{{*/
  842. {
  843. ::RotateDNS();
  844. }
  845. /*}}}*/
  846. BaseHttpMethod::DealWithHeadersResult HttpMethod::DealWithHeaders(FetchResult &Res, RequestState &Req)/*{{{*/
  847. {
  848. auto ret = BaseHttpMethod::DealWithHeaders(Res, Req);
  849. if (ret != BaseHttpMethod::FILE_IS_OPEN)
  850. return ret;
  851. if (Req.File.Open(Queue->DestFile, FileFd::WriteAny) == false)
  852. return ERROR_NOT_FROM_SERVER;
  853. FailFile = Queue->DestFile;
  854. FailFile.c_str(); // Make sure we don't do a malloc in the signal handler
  855. FailFd = Req.File.Fd();
  856. FailTime = Req.Date;
  857. if (Server->InitHashes(Queue->ExpectedHashes) == false || Req.AddPartialFileToHashes(Req.File) == false)
  858. {
  859. _error->Errno("read",_("Problem hashing file"));
  860. return ERROR_NOT_FROM_SERVER;
  861. }
  862. if (Req.StartPos > 0)
  863. Res.ResumePoint = Req.StartPos;
  864. SetNonBlock(Req.File.Fd(),true);
  865. return FILE_IS_OPEN;
  866. }
  867. /*}}}*/
  868. HttpMethod::HttpMethod(std::string &&pProg) : BaseHttpMethod(pProg.c_str(), "1.2", Pipeline | SendConfig)/*{{{*/
  869. {
  870. auto addName = std::inserter(methodNames, methodNames.begin());
  871. if (Binary != "http")
  872. addName = "http";
  873. auto const plus = Binary.find('+');
  874. if (plus != std::string::npos)
  875. {
  876. auto name2 = Binary.substr(plus + 1);
  877. if (std::find(methodNames.begin(), methodNames.end(), name2) == methodNames.end())
  878. addName = std::move(name2);
  879. addName = Binary.substr(0, plus);
  880. }
  881. }
  882. /*}}}*/