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.
 
 
 
 
 
 

1002 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, aptAuthConfMethod *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. Owner->MaybeAddAuthTo(Proxy);
  309. if (Proxy.User.empty() == false || Proxy.Password.empty() == false)
  310. Req << "Proxy-Authorization: Basic "
  311. << Base64Encode(Proxy.User + ":" + Proxy.Password) << "\r\n";
  312. Req << "User-Agent: " << Owner->ConfigFind("User-Agent", "Debian APT-HTTP/1.3 (" PACKAGE_VERSION ")") << "\r\n";
  313. Req << "\r\n";
  314. CircleBuf In(dynamic_cast<HttpMethod *>(Owner), 4096);
  315. CircleBuf Out(dynamic_cast<HttpMethod *>(Owner), 4096);
  316. std::string Headers;
  317. if (Owner->DebugEnabled() == true)
  318. cerr << Req.str() << endl;
  319. Out.Read(Req.str());
  320. // Writing from proxy
  321. while (Out.WriteSpace() > 0)
  322. {
  323. if (WaitFd(Fd->Fd(), true, Timeout) == false)
  324. return _error->Errno("select", "Writing to proxy failed");
  325. if (Out.Write(Fd) == false)
  326. return _error->Errno("write", "Writing to proxy failed");
  327. }
  328. while (In.ReadSpace() > 0)
  329. {
  330. if (WaitFd(Fd->Fd(), false, Timeout) == false)
  331. return _error->Errno("select", "Reading from proxy failed");
  332. if (In.Read(Fd) == false)
  333. return _error->Errno("read", "Reading from proxy failed");
  334. if (In.WriteTillEl(Headers))
  335. break;
  336. }
  337. if (Owner->DebugEnabled() == true)
  338. cerr << Headers << endl;
  339. if (!(APT::String::Startswith(Headers, "HTTP/1.0 200") || APT::String::Startswith(Headers, "HTTP/1.1 200")))
  340. return _error->Error("Invalid response from proxy: %s", Headers.c_str());
  341. if (In.WriteSpace() > 0)
  342. {
  343. // Maybe there is actual data already read, if so we need to buffer it
  344. std::unique_ptr<HttpConnectFd> NewFd(new HttpConnectFd());
  345. In.Write(NewFd->Buffer);
  346. NewFd->UnderlyingFd = std::move(Fd);
  347. Fd = std::move(NewFd);
  348. }
  349. return true;
  350. }
  351. /*}}}*/
  352. // HttpServerState::HttpServerState - Constructor /*{{{*/
  353. HttpServerState::HttpServerState(URI Srv,HttpMethod *Owner) : ServerState(Srv, Owner), In(Owner, 64*1024), Out(Owner, 4*1024)
  354. {
  355. TimeOut = Owner->ConfigFindI("Timeout", TimeOut);
  356. ServerFd = MethodFd::FromFd(-1);
  357. Reset();
  358. }
  359. /*}}}*/
  360. // HttpServerState::Open - Open a connection to the server /*{{{*/
  361. // ---------------------------------------------------------------------
  362. /* This opens a connection to the server. */
  363. bool HttpServerState::Open()
  364. {
  365. // Use the already open connection if possible.
  366. if (ServerFd->Fd() != -1)
  367. return true;
  368. Close();
  369. In.Reset();
  370. Out.Reset();
  371. Persistent = true;
  372. // Determine the proxy setting
  373. // Used to run AutoDetectProxy(ServerName) here, but we now send a Proxy
  374. // header in the URI Acquire request and set "Acquire::"+uri.Access+"::proxy::"+uri.Host
  375. // to it in BaseHttpMethod::Loop()
  376. string SpecificProxy = Owner->ConfigFind("Proxy::" + ServerName.Host, "");
  377. if (!SpecificProxy.empty())
  378. {
  379. if (SpecificProxy == "DIRECT")
  380. Proxy = "";
  381. else
  382. Proxy = SpecificProxy;
  383. }
  384. else
  385. {
  386. string DefProxy = Owner->ConfigFind("Proxy", "");
  387. if (!DefProxy.empty())
  388. {
  389. Proxy = DefProxy;
  390. }
  391. else
  392. {
  393. char* result = getenv("http_proxy");
  394. Proxy = result ? result : "";
  395. }
  396. }
  397. // Parse no_proxy, a , separated list of domains
  398. if (getenv("no_proxy") != 0)
  399. {
  400. if (CheckDomainList(ServerName.Host,getenv("no_proxy")) == true)
  401. Proxy = "";
  402. }
  403. if (Proxy.empty() == false)
  404. Owner->AddProxyAuth(Proxy, ServerName);
  405. bool tls = (ServerName.Access == "https" || APT::String::Endswith(ServerName.Access, "+https"));
  406. auto const DefaultService = tls ? "https" : "http";
  407. auto const DefaultPort = tls ? 443 : 80;
  408. if (Proxy.Access == "socks5h")
  409. {
  410. if (Connect(Proxy.Host, Proxy.Port, "socks", 1080, ServerFd, TimeOut, Owner) == false)
  411. return false;
  412. if (UnwrapSocks(ServerName.Host, ServerName.Port == 0 ? DefaultPort : ServerName.Port,
  413. Proxy, ServerFd, Owner->ConfigFindI("TimeOut", 120), Owner) == false)
  414. return false;
  415. }
  416. else
  417. {
  418. // Determine what host and port to use based on the proxy settings
  419. int Port = 0;
  420. string Host;
  421. if (Proxy.empty() == true || Proxy.Host.empty() == true)
  422. {
  423. if (ServerName.Port != 0)
  424. Port = ServerName.Port;
  425. Host = ServerName.Host;
  426. }
  427. else if (Proxy.Access != "http" && Proxy.Access != "https")
  428. return _error->Error("Unsupported proxy configured: %s", URI::SiteOnly(Proxy).c_str());
  429. else
  430. {
  431. if (Proxy.Port != 0)
  432. Port = Proxy.Port;
  433. Host = Proxy.Host;
  434. if (Proxy.Access == "https" && Port == 0)
  435. Port = 443;
  436. }
  437. if (!Connect(Host, Port, DefaultService, DefaultPort, ServerFd, TimeOut, Owner))
  438. return false;
  439. if (Host == Proxy.Host && Proxy.Access == "https" && UnwrapTLS(Proxy.Host, ServerFd, TimeOut, Owner) == false)
  440. return false;
  441. if (Host == Proxy.Host && tls && UnwrapHTTPConnect(ServerName.Host, ServerName.Port == 0 ? DefaultPort : ServerName.Port, Proxy, ServerFd, Owner->ConfigFindI("TimeOut", 120), Owner) == false)
  442. return false;
  443. }
  444. if (tls && UnwrapTLS(ServerName.Host, ServerFd, TimeOut, Owner) == false)
  445. return false;
  446. return true;
  447. }
  448. /*}}}*/
  449. // HttpServerState::Close - Close a connection to the server /*{{{*/
  450. // ---------------------------------------------------------------------
  451. /* */
  452. bool HttpServerState::Close()
  453. {
  454. ServerFd->Close();
  455. return true;
  456. }
  457. /*}}}*/
  458. // HttpServerState::RunData - Transfer the data from the socket /*{{{*/
  459. bool HttpServerState::RunData(RequestState &Req)
  460. {
  461. Req.State = RequestState::Data;
  462. // Chunked transfer encoding is fun..
  463. if (Req.Encoding == RequestState::Chunked)
  464. {
  465. while (1)
  466. {
  467. // Grab the block size
  468. bool Last = true;
  469. string Data;
  470. In.Limit(-1);
  471. do
  472. {
  473. if (In.WriteTillEl(Data,true) == true)
  474. break;
  475. }
  476. while ((Last = Go(false, Req)) == true);
  477. if (Last == false)
  478. return false;
  479. // See if we are done
  480. unsigned long long Len = strtoull(Data.c_str(),0,16);
  481. if (Len == 0)
  482. {
  483. In.Limit(-1);
  484. // We have to remove the entity trailer
  485. Last = true;
  486. do
  487. {
  488. if (In.WriteTillEl(Data,true) == true && Data.length() <= 2)
  489. break;
  490. }
  491. while ((Last = Go(false, Req)) == true);
  492. if (Last == false)
  493. return false;
  494. return !_error->PendingError();
  495. }
  496. // Transfer the block
  497. In.Limit(Len);
  498. while (Go(true, Req) == true)
  499. if (In.IsLimit() == true)
  500. break;
  501. // Error
  502. if (In.IsLimit() == false)
  503. return false;
  504. // The server sends an extra new line before the next block specifier..
  505. In.Limit(-1);
  506. Last = true;
  507. do
  508. {
  509. if (In.WriteTillEl(Data,true) == true)
  510. break;
  511. }
  512. while ((Last = Go(false, Req)) == true);
  513. if (Last == false)
  514. return false;
  515. }
  516. }
  517. else
  518. {
  519. /* Closes encoding is used when the server did not specify a size, the
  520. loss of the connection means we are done */
  521. if (Req.JunkSize != 0)
  522. In.Limit(Req.JunkSize);
  523. else if (Req.DownloadSize != 0)
  524. {
  525. if (Req.MaximumSize != 0 && Req.DownloadSize > Req.MaximumSize)
  526. {
  527. Owner->SetFailReason("MaximumSizeExceeded");
  528. return _error->Error(_("File has unexpected size (%llu != %llu). Mirror sync in progress?"),
  529. Req.DownloadSize, Req.MaximumSize);
  530. }
  531. In.Limit(Req.DownloadSize);
  532. }
  533. else if (Persistent == false)
  534. In.Limit(-1);
  535. // Just transfer the whole block.
  536. do
  537. {
  538. if (In.IsLimit() == false)
  539. continue;
  540. In.Limit(-1);
  541. return !_error->PendingError();
  542. }
  543. while (Go(true, Req) == true);
  544. }
  545. return Flush(&Req.File) && !_error->PendingError();
  546. }
  547. /*}}}*/
  548. bool HttpServerState::RunDataToDevNull(RequestState &Req) /*{{{*/
  549. {
  550. // no need to clean up if we discard the connection anyhow
  551. if (Persistent == false)
  552. return true;
  553. Req.File.Open("/dev/null", FileFd::WriteOnly);
  554. return RunData(Req);
  555. }
  556. /*}}}*/
  557. bool HttpServerState::ReadHeaderLines(std::string &Data) /*{{{*/
  558. {
  559. return In.WriteTillEl(Data);
  560. }
  561. /*}}}*/
  562. bool HttpServerState::LoadNextResponse(bool const ToFile, RequestState &Req)/*{{{*/
  563. {
  564. return Go(ToFile, Req);
  565. }
  566. /*}}}*/
  567. bool HttpServerState::WriteResponse(const std::string &Data) /*{{{*/
  568. {
  569. return Out.Read(Data);
  570. }
  571. /*}}}*/
  572. APT_PURE bool HttpServerState::IsOpen() /*{{{*/
  573. {
  574. return (ServerFd->Fd() != -1);
  575. }
  576. /*}}}*/
  577. bool HttpServerState::InitHashes(HashStringList const &ExpectedHashes) /*{{{*/
  578. {
  579. delete In.Hash;
  580. In.Hash = new Hashes(ExpectedHashes);
  581. return true;
  582. }
  583. /*}}}*/
  584. void HttpServerState::Reset() /*{{{*/
  585. {
  586. ServerState::Reset();
  587. ServerFd->Close();
  588. }
  589. /*}}}*/
  590. APT_PURE Hashes * HttpServerState::GetHashes() /*{{{*/
  591. {
  592. return In.Hash;
  593. }
  594. /*}}}*/
  595. // HttpServerState::Die - The server has closed the connection. /*{{{*/
  596. bool HttpServerState::Die(RequestState &Req)
  597. {
  598. unsigned int LErrno = errno;
  599. // Dump the buffer to the file
  600. if (Req.State == RequestState::Data)
  601. {
  602. if (Req.File.IsOpen() == false)
  603. return true;
  604. // on GNU/kFreeBSD, apt dies on /dev/null because non-blocking
  605. // can't be set
  606. if (Req.File.Name() != "/dev/null")
  607. SetNonBlock(Req.File.Fd(),false);
  608. while (In.WriteSpace() == true)
  609. {
  610. if (In.Write(MethodFd::FromFd(Req.File.Fd())) == false)
  611. return _error->Errno("write",_("Error writing to the file"));
  612. // Done
  613. if (In.IsLimit() == true)
  614. return true;
  615. }
  616. }
  617. // See if this is because the server finished the data stream
  618. if (In.IsLimit() == false && Req.State != RequestState::Header &&
  619. Persistent == true)
  620. {
  621. Close();
  622. if (LErrno == 0)
  623. return _error->Error(_("Error reading from server. Remote end closed connection"));
  624. errno = LErrno;
  625. return _error->Errno("read",_("Error reading from server"));
  626. }
  627. else
  628. {
  629. In.Limit(-1);
  630. // Nothing left in the buffer
  631. if (In.WriteSpace() == false)
  632. return false;
  633. // We may have got multiple responses back in one packet..
  634. Close();
  635. return true;
  636. }
  637. return false;
  638. }
  639. /*}}}*/
  640. // HttpServerState::Flush - Dump the buffer into the file /*{{{*/
  641. // ---------------------------------------------------------------------
  642. /* This takes the current input buffer from the Server FD and writes it
  643. into the file */
  644. bool HttpServerState::Flush(FileFd * const File)
  645. {
  646. if (File != nullptr)
  647. {
  648. // on GNU/kFreeBSD, apt dies on /dev/null because non-blocking
  649. // can't be set
  650. if (File->Name() != "/dev/null")
  651. SetNonBlock(File->Fd(),false);
  652. if (In.WriteSpace() == false)
  653. return true;
  654. while (In.WriteSpace() == true)
  655. {
  656. if (In.Write(MethodFd::FromFd(File->Fd())) == false)
  657. return _error->Errno("write",_("Error writing to file"));
  658. if (In.IsLimit() == true)
  659. return true;
  660. }
  661. if (In.IsLimit() == true || Persistent == false)
  662. return true;
  663. }
  664. return false;
  665. }
  666. /*}}}*/
  667. // HttpServerState::Go - Run a single loop /*{{{*/
  668. // ---------------------------------------------------------------------
  669. /* This runs the select loop over the server FDs, Output file FDs and
  670. stdin. */
  671. bool HttpServerState::Go(bool ToFile, RequestState &Req)
  672. {
  673. // Server has closed the connection
  674. if (ServerFd->Fd() == -1 && (In.WriteSpace() == false ||
  675. ToFile == false))
  676. return false;
  677. // Handle server IO
  678. if (ServerFd->HasPending() && In.ReadSpace() == true)
  679. {
  680. errno = 0;
  681. if (In.Read(ServerFd) == false)
  682. return Die(Req);
  683. }
  684. fd_set rfds,wfds;
  685. FD_ZERO(&rfds);
  686. FD_ZERO(&wfds);
  687. /* Add the server. We only send more requests if the connection will
  688. be persisting */
  689. if (Out.WriteSpace() == true && ServerFd->Fd() != -1 && Persistent == true)
  690. FD_SET(ServerFd->Fd(), &wfds);
  691. if (In.ReadSpace() == true && ServerFd->Fd() != -1)
  692. FD_SET(ServerFd->Fd(), &rfds);
  693. // Add the file
  694. auto FileFD = MethodFd::FromFd(-1);
  695. if (Req.File.IsOpen())
  696. FileFD = MethodFd::FromFd(Req.File.Fd());
  697. if (In.WriteSpace() == true && ToFile == true && FileFD->Fd() != -1)
  698. FD_SET(FileFD->Fd(), &wfds);
  699. // Add stdin
  700. if (Owner->ConfigFindB("DependOnSTDIN", true) == true)
  701. FD_SET(STDIN_FILENO,&rfds);
  702. // Figure out the max fd
  703. int MaxFd = FileFD->Fd();
  704. if (MaxFd < ServerFd->Fd())
  705. MaxFd = ServerFd->Fd();
  706. // Select
  707. struct timeval tv;
  708. tv.tv_sec = TimeOut;
  709. tv.tv_usec = 0;
  710. int Res = 0;
  711. if ((Res = select(MaxFd+1,&rfds,&wfds,0,&tv)) < 0)
  712. {
  713. if (errno == EINTR)
  714. return true;
  715. return _error->Errno("select",_("Select failed"));
  716. }
  717. if (Res == 0)
  718. {
  719. _error->Error(_("Connection timed out"));
  720. return Die(Req);
  721. }
  722. // Handle server IO
  723. if (ServerFd->Fd() != -1 && FD_ISSET(ServerFd->Fd(), &rfds))
  724. {
  725. errno = 0;
  726. if (In.Read(ServerFd) == false)
  727. return Die(Req);
  728. }
  729. if (ServerFd->Fd() != -1 && FD_ISSET(ServerFd->Fd(), &wfds))
  730. {
  731. errno = 0;
  732. if (Out.Write(ServerFd) == false)
  733. return Die(Req);
  734. }
  735. // Send data to the file
  736. if (FileFD->Fd() != -1 && FD_ISSET(FileFD->Fd(), &wfds))
  737. {
  738. if (In.Write(FileFD) == false)
  739. return _error->Errno("write",_("Error writing to output file"));
  740. }
  741. if (Req.MaximumSize > 0 && Req.File.IsOpen() && Req.File.Failed() == false && Req.File.Tell() > Req.MaximumSize)
  742. {
  743. Owner->SetFailReason("MaximumSizeExceeded");
  744. return _error->Error(_("File has unexpected size (%llu != %llu). Mirror sync in progress?"),
  745. Req.File.Tell(), Req.MaximumSize);
  746. }
  747. // Handle commands from APT
  748. if (FD_ISSET(STDIN_FILENO,&rfds))
  749. {
  750. if (Owner->Run(true) != -1)
  751. exit(100);
  752. }
  753. return true;
  754. }
  755. /*}}}*/
  756. // HttpMethod::SendReq - Send the HTTP request /*{{{*/
  757. // ---------------------------------------------------------------------
  758. /* This places the http request in the outbound buffer */
  759. void HttpMethod::SendReq(FetchItem *Itm)
  760. {
  761. URI Uri = Itm->Uri;
  762. {
  763. auto const plus = Binary.find('+');
  764. if (plus != std::string::npos)
  765. Uri.Access = Binary.substr(plus + 1);
  766. }
  767. // The HTTP server expects a hostname with a trailing :port
  768. std::stringstream Req;
  769. string ProperHost;
  770. if (Uri.Host.find(':') != string::npos)
  771. ProperHost = '[' + Uri.Host + ']';
  772. else
  773. ProperHost = Uri.Host;
  774. /* RFC 2616 ยง5.1.2 requires absolute URIs for requests to proxies,
  775. but while its a must for all servers to accept absolute URIs,
  776. it is assumed clients will sent an absolute path for non-proxies */
  777. std::string requesturi;
  778. if ((Server->Proxy.Access != "http" && Server->Proxy.Access != "https") || APT::String::Endswith(Uri.Access, "https") || Server->Proxy.empty() == true || Server->Proxy.Host.empty())
  779. requesturi = Uri.Path;
  780. else
  781. requesturi = Uri;
  782. // The "+" is encoded as a workaround for a amazon S3 bug
  783. // see LP bugs #1003633 and #1086997.
  784. requesturi = QuoteString(requesturi, "+~ ");
  785. /* Build the request. No keep-alive is included as it is the default
  786. in 1.1, can cause problems with proxies, and we are an HTTP/1.1
  787. client anyway.
  788. C.f. https://tools.ietf.org/wg/httpbis/trac/ticket/158 */
  789. Req << "GET " << requesturi << " HTTP/1.1\r\n";
  790. if (Uri.Port != 0)
  791. Req << "Host: " << ProperHost << ":" << std::to_string(Uri.Port) << "\r\n";
  792. else
  793. Req << "Host: " << ProperHost << "\r\n";
  794. // generate a cache control header (if needed)
  795. if (ConfigFindB("No-Cache",false) == true)
  796. Req << "Cache-Control: no-cache\r\n"
  797. << "Pragma: no-cache\r\n";
  798. else if (Itm->IndexFile == true)
  799. Req << "Cache-Control: max-age=" << std::to_string(ConfigFindI("Max-Age", 0)) << "\r\n";
  800. else if (ConfigFindB("No-Store", false) == true)
  801. Req << "Cache-Control: no-store\r\n";
  802. // If we ask for uncompressed files servers might respond with content-
  803. // negotiation which lets us end up with compressed files we do not support,
  804. // see 657029, 657560 and co, so if we have no extension on the request
  805. // ask for text only. As a sidenote: If there is nothing to negotate servers
  806. // seem to be nice and ignore it.
  807. if (ConfigFindB("SendAccept", true) == true)
  808. {
  809. size_t const filepos = Itm->Uri.find_last_of('/');
  810. string const file = Itm->Uri.substr(filepos + 1);
  811. if (flExtension(file) == file)
  812. Req << "Accept: text/*\r\n";
  813. }
  814. // Check for a partial file and send if-queries accordingly
  815. struct stat SBuf;
  816. if (Server->RangesAllowed && stat(Itm->DestFile.c_str(),&SBuf) >= 0 && SBuf.st_size > 0)
  817. Req << "Range: bytes=" << std::to_string(SBuf.st_size) << "-\r\n"
  818. << "If-Range: " << TimeRFC1123(SBuf.st_mtime, false) << "\r\n";
  819. else if (Itm->LastModified != 0)
  820. Req << "If-Modified-Since: " << TimeRFC1123(Itm->LastModified, false).c_str() << "\r\n";
  821. if ((Server->Proxy.Access == "http" || Server->Proxy.Access == "https") &&
  822. (Server->Proxy.User.empty() == false || Server->Proxy.Password.empty() == false))
  823. Req << "Proxy-Authorization: Basic "
  824. << Base64Encode(Server->Proxy.User + ":" + Server->Proxy.Password) << "\r\n";
  825. MaybeAddAuthTo(Uri);
  826. if (Uri.User.empty() == false || Uri.Password.empty() == false)
  827. Req << "Authorization: Basic "
  828. << Base64Encode(Uri.User + ":" + Uri.Password) << "\r\n";
  829. Req << "User-Agent: " << ConfigFind("User-Agent",
  830. "Debian APT-HTTP/1.3 (" PACKAGE_VERSION ")") << "\r\n";
  831. Req << "\r\n";
  832. if (Debug == true)
  833. cerr << Req.str() << endl;
  834. Server->WriteResponse(Req.str());
  835. }
  836. /*}}}*/
  837. std::unique_ptr<ServerState> HttpMethod::CreateServerState(URI const &uri)/*{{{*/
  838. {
  839. return std::unique_ptr<ServerState>(new HttpServerState(uri, this));
  840. }
  841. /*}}}*/
  842. void HttpMethod::RotateDNS() /*{{{*/
  843. {
  844. ::RotateDNS();
  845. }
  846. /*}}}*/
  847. BaseHttpMethod::DealWithHeadersResult HttpMethod::DealWithHeaders(FetchResult &Res, RequestState &Req)/*{{{*/
  848. {
  849. auto ret = BaseHttpMethod::DealWithHeaders(Res, Req);
  850. if (ret != BaseHttpMethod::FILE_IS_OPEN)
  851. return ret;
  852. if (Req.File.Open(Queue->DestFile, FileFd::WriteAny) == false)
  853. return ERROR_NOT_FROM_SERVER;
  854. FailFile = Queue->DestFile;
  855. FailFile.c_str(); // Make sure we don't do a malloc in the signal handler
  856. FailFd = Req.File.Fd();
  857. FailTime = Req.Date;
  858. if (Server->InitHashes(Queue->ExpectedHashes) == false || Req.AddPartialFileToHashes(Req.File) == false)
  859. {
  860. _error->Errno("read",_("Problem hashing file"));
  861. return ERROR_NOT_FROM_SERVER;
  862. }
  863. if (Req.StartPos > 0)
  864. Res.ResumePoint = Req.StartPos;
  865. SetNonBlock(Req.File.Fd(),true);
  866. return FILE_IS_OPEN;
  867. }
  868. /*}}}*/
  869. HttpMethod::HttpMethod(std::string &&pProg) : BaseHttpMethod(pProg.c_str(), "1.2", Pipeline | SendConfig)/*{{{*/
  870. {
  871. SeccompFlags = aptMethod::BASE | aptMethod::NETWORK;
  872. auto addName = std::inserter(methodNames, methodNames.begin());
  873. if (Binary != "http")
  874. addName = "http";
  875. auto const plus = Binary.find('+');
  876. if (plus != std::string::npos)
  877. {
  878. auto name2 = Binary.substr(plus + 1);
  879. if (std::find(methodNames.begin(), methodNames.end(), name2) == methodNames.end())
  880. addName = std::move(name2);
  881. addName = Binary.substr(0, plus);
  882. }
  883. }
  884. /*}}}*/