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.
 
 
 
 
 
 

831 lines
23 KiB

  1. // -*- mode: cpp; mode: fold -*-
  2. // Description /*{{{*/
  3. /* ######################################################################
  4. HTTP and HTTPS share a lot of common code and these classes are
  5. exactly the dumping ground for this common code
  6. ##################################################################### */
  7. /*}}}*/
  8. // Include Files /*{{{*/
  9. #include <config.h>
  10. #include <apt-pkg/configuration.h>
  11. #include <apt-pkg/error.h>
  12. #include <apt-pkg/fileutl.h>
  13. #include <apt-pkg/strutl.h>
  14. #include <ctype.h>
  15. #include <signal.h>
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <sys/stat.h>
  19. #include <sys/time.h>
  20. #include <time.h>
  21. #include <unistd.h>
  22. #include <iostream>
  23. #include <limits>
  24. #include <map>
  25. #include <string>
  26. #include <vector>
  27. #include "server.h"
  28. #include <apti18n.h>
  29. /*}}}*/
  30. using namespace std;
  31. string ServerMethod::FailFile;
  32. int ServerMethod::FailFd = -1;
  33. time_t ServerMethod::FailTime = 0;
  34. // ServerState::RunHeaders - Get the headers before the data /*{{{*/
  35. // ---------------------------------------------------------------------
  36. /* Returns 0 if things are OK, 1 if an IO error occurred and 2 if a header
  37. parse error occurred */
  38. ServerState::RunHeadersResult ServerState::RunHeaders(FileFd * const File,
  39. const std::string &Uri)
  40. {
  41. Reset(false);
  42. Owner->Status(_("Waiting for headers"));
  43. do
  44. {
  45. string Data;
  46. if (ReadHeaderLines(Data) == false)
  47. continue;
  48. if (Owner->Debug == true)
  49. clog << "Answer for: " << Uri << endl << Data;
  50. for (string::const_iterator I = Data.begin(); I < Data.end(); ++I)
  51. {
  52. string::const_iterator J = I;
  53. for (; J != Data.end() && *J != '\n' && *J != '\r'; ++J);
  54. if (HeaderLine(string(I,J)) == false)
  55. return RUN_HEADERS_PARSE_ERROR;
  56. I = J;
  57. }
  58. // 100 Continue is a Nop...
  59. if (Result == 100)
  60. continue;
  61. // Tidy up the connection persistence state.
  62. if (Encoding == Closes && HaveContent == true)
  63. Persistent = false;
  64. return RUN_HEADERS_OK;
  65. }
  66. while (LoadNextResponse(false, File) == true);
  67. return RUN_HEADERS_IO_ERROR;
  68. }
  69. /*}}}*/
  70. // ServerState::HeaderLine - Process a header line /*{{{*/
  71. // ---------------------------------------------------------------------
  72. /* */
  73. bool ServerState::HeaderLine(string Line)
  74. {
  75. if (Line.empty() == true)
  76. return true;
  77. if (Line.size() > 4 && stringcasecmp(Line.data(), Line.data()+4, "HTTP") == 0)
  78. {
  79. // Evil servers return no version
  80. if (Line[4] == '/')
  81. {
  82. int const elements = sscanf(Line.c_str(),"HTTP/%3u.%3u %3u%359[^\n]",&Major,&Minor,&Result,Code);
  83. if (elements == 3)
  84. {
  85. Code[0] = '\0';
  86. if (Owner != NULL && Owner->Debug == true)
  87. clog << "HTTP server doesn't give Reason-Phrase for " << std::to_string(Result) << std::endl;
  88. }
  89. else if (elements != 4)
  90. return _error->Error(_("The HTTP server sent an invalid reply header"));
  91. }
  92. else
  93. {
  94. Major = 0;
  95. Minor = 9;
  96. if (sscanf(Line.c_str(),"HTTP %3u%359[^\n]",&Result,Code) != 2)
  97. return _error->Error(_("The HTTP server sent an invalid reply header"));
  98. }
  99. /* Check the HTTP response header to get the default persistence
  100. state. */
  101. if (Major < 1)
  102. Persistent = false;
  103. else
  104. {
  105. if (Major == 1 && Minor == 0)
  106. {
  107. Persistent = false;
  108. }
  109. else
  110. {
  111. Persistent = true;
  112. if (PipelineAllowed)
  113. Pipeline = true;
  114. }
  115. }
  116. return true;
  117. }
  118. // Blah, some servers use "connection:closes", evil.
  119. // and some even send empty header fields…
  120. string::size_type Pos = Line.find(':');
  121. if (Pos == string::npos)
  122. return _error->Error(_("Bad header line"));
  123. ++Pos;
  124. // Parse off any trailing spaces between the : and the next word.
  125. string::size_type Pos2 = Pos;
  126. while (Pos2 < Line.length() && isspace_ascii(Line[Pos2]) != 0)
  127. Pos2++;
  128. string const Tag(Line,0,Pos);
  129. string const Val(Line,Pos2);
  130. if (stringcasecmp(Tag,"Content-Length:") == 0)
  131. {
  132. if (Encoding == Closes)
  133. Encoding = Stream;
  134. HaveContent = true;
  135. unsigned long long * DownloadSizePtr = &DownloadSize;
  136. if (Result == 416 || (Result >= 300 && Result < 400))
  137. DownloadSizePtr = &JunkSize;
  138. *DownloadSizePtr = strtoull(Val.c_str(), NULL, 10);
  139. if (*DownloadSizePtr >= std::numeric_limits<unsigned long long>::max())
  140. return _error->Errno("HeaderLine", _("The HTTP server sent an invalid Content-Length header"));
  141. else if (*DownloadSizePtr == 0)
  142. HaveContent = false;
  143. // On partial content (206) the Content-Length less than the real
  144. // size, so do not set it here but leave that to the Content-Range
  145. // header instead
  146. if(Result != 206 && TotalFileSize == 0)
  147. TotalFileSize = DownloadSize;
  148. return true;
  149. }
  150. if (stringcasecmp(Tag,"Content-Type:") == 0)
  151. {
  152. HaveContent = true;
  153. return true;
  154. }
  155. if (stringcasecmp(Tag,"Content-Range:") == 0)
  156. {
  157. HaveContent = true;
  158. // §14.16 says 'byte-range-resp-spec' should be a '*' in case of 416
  159. if (Result == 416 && sscanf(Val.c_str(), "bytes */%llu",&TotalFileSize) == 1)
  160. ; // we got the expected filesize which is all we wanted
  161. else if (sscanf(Val.c_str(),"bytes %llu-%*u/%llu",&StartPos,&TotalFileSize) != 2)
  162. return _error->Error(_("The HTTP server sent an invalid Content-Range header"));
  163. if ((unsigned long long)StartPos > TotalFileSize)
  164. return _error->Error(_("This HTTP server has broken range support"));
  165. // figure out what we will download
  166. DownloadSize = TotalFileSize - StartPos;
  167. return true;
  168. }
  169. if (stringcasecmp(Tag,"Transfer-Encoding:") == 0)
  170. {
  171. HaveContent = true;
  172. if (stringcasecmp(Val,"chunked") == 0)
  173. Encoding = Chunked;
  174. return true;
  175. }
  176. if (stringcasecmp(Tag,"Connection:") == 0)
  177. {
  178. if (stringcasecmp(Val,"close") == 0)
  179. Persistent = false;
  180. if (stringcasecmp(Val,"keep-alive") == 0)
  181. Persistent = true;
  182. return true;
  183. }
  184. if (stringcasecmp(Tag,"Last-Modified:") == 0)
  185. {
  186. if (RFC1123StrToTime(Val.c_str(), Date) == false)
  187. return _error->Error(_("Unknown date format"));
  188. return true;
  189. }
  190. if (stringcasecmp(Tag,"Location:") == 0)
  191. {
  192. Location = Val;
  193. return true;
  194. }
  195. if (stringcasecmp(Tag, "Accept-Ranges:") == 0)
  196. {
  197. std::string ranges = ',' + Val + ',';
  198. ranges.erase(std::remove(ranges.begin(), ranges.end(), ' '), ranges.end());
  199. if (ranges.find(",bytes,") == std::string::npos)
  200. RangesAllowed = false;
  201. return true;
  202. }
  203. return true;
  204. }
  205. /*}}}*/
  206. // ServerState::ServerState - Constructor /*{{{*/
  207. ServerState::ServerState(URI Srv, ServerMethod *Owner) :
  208. DownloadSize(0), ServerName(Srv), TimeOut(120), Owner(Owner)
  209. {
  210. Reset();
  211. }
  212. /*}}}*/
  213. bool ServerState::AddPartialFileToHashes(FileFd &File) /*{{{*/
  214. {
  215. File.Truncate(StartPos);
  216. return GetHashes()->AddFD(File, StartPos);
  217. }
  218. /*}}}*/
  219. void ServerState::Reset(bool const Everything) /*{{{*/
  220. {
  221. Major = 0; Minor = 0; Result = 0; Code[0] = '\0';
  222. TotalFileSize = 0; JunkSize = 0; StartPos = 0;
  223. Encoding = Closes; time(&Date); HaveContent = false;
  224. State = Header; MaximumSize = 0;
  225. if (Everything)
  226. {
  227. Persistent = false; Pipeline = false; PipelineAllowed = true;
  228. RangesAllowed = true;
  229. }
  230. }
  231. /*}}}*/
  232. // ServerMethod::DealWithHeaders - Handle the retrieved header data /*{{{*/
  233. // ---------------------------------------------------------------------
  234. /* We look at the header data we got back from the server and decide what
  235. to do. Returns DealWithHeadersResult (see http.h for details).
  236. */
  237. ServerMethod::DealWithHeadersResult
  238. ServerMethod::DealWithHeaders(FetchResult &Res)
  239. {
  240. // Not Modified
  241. if (Server->Result == 304)
  242. {
  243. RemoveFile("server", Queue->DestFile);
  244. Res.IMSHit = true;
  245. Res.LastModified = Queue->LastModified;
  246. Res.Size = 0;
  247. return IMS_HIT;
  248. }
  249. /* Redirect
  250. *
  251. * Note that it is only OK for us to treat all redirection the same
  252. * because we *always* use GET, not other HTTP methods. There are
  253. * three redirection codes for which it is not appropriate that we
  254. * redirect. Pass on those codes so the error handling kicks in.
  255. */
  256. if (AllowRedirect
  257. && (Server->Result > 300 && Server->Result < 400)
  258. && (Server->Result != 300 // Multiple Choices
  259. && Server->Result != 304 // Not Modified
  260. && Server->Result != 306)) // (Not part of HTTP/1.1, reserved)
  261. {
  262. if (Server->Location.empty() == true)
  263. ;
  264. else if (Server->Location[0] == '/' && Queue->Uri.empty() == false)
  265. {
  266. URI Uri = Queue->Uri;
  267. if (Uri.Host.empty() == false)
  268. NextURI = URI::SiteOnly(Uri);
  269. else
  270. NextURI.clear();
  271. NextURI.append(DeQuoteString(Server->Location));
  272. if (Queue->Uri == NextURI)
  273. {
  274. SetFailReason("RedirectionLoop");
  275. _error->Error("Redirection loop encountered");
  276. if (Server->HaveContent == true)
  277. return ERROR_WITH_CONTENT_PAGE;
  278. return ERROR_UNRECOVERABLE;
  279. }
  280. return TRY_AGAIN_OR_REDIRECT;
  281. }
  282. else
  283. {
  284. NextURI = DeQuoteString(Server->Location);
  285. URI tmpURI = NextURI;
  286. if (tmpURI.Access.find('+') != std::string::npos)
  287. {
  288. _error->Error("Server tried to trick us into using a specific implementation: %s", tmpURI.Access.c_str());
  289. if (Server->HaveContent == true)
  290. return ERROR_WITH_CONTENT_PAGE;
  291. return ERROR_UNRECOVERABLE;
  292. }
  293. URI Uri = Queue->Uri;
  294. if (Binary.find('+') != std::string::npos)
  295. {
  296. auto base = Binary.substr(0, Binary.find('+'));
  297. if (base != tmpURI.Access)
  298. {
  299. tmpURI.Access = base + '+' + tmpURI.Access;
  300. if (tmpURI.Access == Binary)
  301. {
  302. std::string tmpAccess = Uri.Access;
  303. std::swap(tmpURI.Access, Uri.Access);
  304. NextURI = tmpURI;
  305. std::swap(tmpURI.Access, Uri.Access);
  306. }
  307. else
  308. NextURI = tmpURI;
  309. }
  310. }
  311. if (Queue->Uri == NextURI)
  312. {
  313. SetFailReason("RedirectionLoop");
  314. _error->Error("Redirection loop encountered");
  315. if (Server->HaveContent == true)
  316. return ERROR_WITH_CONTENT_PAGE;
  317. return ERROR_UNRECOVERABLE;
  318. }
  319. Uri.Access = Binary;
  320. // same protocol redirects are okay
  321. if (tmpURI.Access == Uri.Access)
  322. return TRY_AGAIN_OR_REDIRECT;
  323. // as well as http to https
  324. else if ((Uri.Access == "http" || Uri.Access == "https+http") && tmpURI.Access == "https")
  325. return TRY_AGAIN_OR_REDIRECT;
  326. else
  327. {
  328. auto const tmpplus = tmpURI.Access.find('+');
  329. if (tmpplus != std::string::npos && tmpURI.Access.substr(tmpplus + 1) == "https")
  330. {
  331. auto const uriplus = Uri.Access.find('+');
  332. if (uriplus == std::string::npos)
  333. {
  334. if (Uri.Access == tmpURI.Access.substr(0, tmpplus)) // foo -> foo+https
  335. return TRY_AGAIN_OR_REDIRECT;
  336. }
  337. else if (Uri.Access.substr(uriplus + 1) == "http" &&
  338. Uri.Access.substr(0, uriplus) == tmpURI.Access.substr(0, tmpplus)) // foo+http -> foo+https
  339. return TRY_AGAIN_OR_REDIRECT;
  340. }
  341. }
  342. _error->Error("Redirection from %s to '%s' is forbidden", Uri.Access.c_str(), NextURI.c_str());
  343. }
  344. /* else pass through for error message */
  345. }
  346. // retry after an invalid range response without partial data
  347. else if (Server->Result == 416)
  348. {
  349. struct stat SBuf;
  350. if (stat(Queue->DestFile.c_str(),&SBuf) >= 0 && SBuf.st_size > 0)
  351. {
  352. bool partialHit = false;
  353. if (Queue->ExpectedHashes.usable() == true)
  354. {
  355. Hashes resultHashes(Queue->ExpectedHashes);
  356. FileFd file(Queue->DestFile, FileFd::ReadOnly);
  357. Server->TotalFileSize = file.FileSize();
  358. Server->Date = file.ModificationTime();
  359. resultHashes.AddFD(file);
  360. HashStringList const hashList = resultHashes.GetHashStringList();
  361. partialHit = (Queue->ExpectedHashes == hashList);
  362. }
  363. else if ((unsigned long long)SBuf.st_size == Server->TotalFileSize)
  364. partialHit = true;
  365. if (partialHit == true)
  366. {
  367. // the file is completely downloaded, but was not moved
  368. if (Server->HaveContent == true)
  369. {
  370. // nuke the sent error page
  371. Server->RunDataToDevNull();
  372. Server->HaveContent = false;
  373. }
  374. Server->StartPos = Server->TotalFileSize;
  375. Server->Result = 200;
  376. }
  377. else if (RemoveFile("server", Queue->DestFile))
  378. {
  379. NextURI = Queue->Uri;
  380. return TRY_AGAIN_OR_REDIRECT;
  381. }
  382. }
  383. }
  384. /* We have a reply we don't handle. This should indicate a perm server
  385. failure */
  386. if (Server->Result < 200 || Server->Result >= 300)
  387. {
  388. if (_error->PendingError() == false)
  389. {
  390. std::string err;
  391. strprintf(err, "HttpError%u", Server->Result);
  392. SetFailReason(err);
  393. _error->Error("%u %s", Server->Result, Server->Code);
  394. }
  395. if (Server->HaveContent == true)
  396. return ERROR_WITH_CONTENT_PAGE;
  397. return ERROR_UNRECOVERABLE;
  398. }
  399. // This is some sort of 2xx 'data follows' reply
  400. Res.LastModified = Server->Date;
  401. Res.Size = Server->TotalFileSize;
  402. return FILE_IS_OPEN;
  403. }
  404. /*}}}*/
  405. // ServerMethod::SigTerm - Handle a fatal signal /*{{{*/
  406. // ---------------------------------------------------------------------
  407. /* This closes and timestamps the open file. This is necessary to get
  408. resume behavoir on user abort */
  409. void ServerMethod::SigTerm(int)
  410. {
  411. if (FailFd == -1)
  412. _exit(100);
  413. struct timeval times[2];
  414. times[0].tv_sec = FailTime;
  415. times[1].tv_sec = FailTime;
  416. times[0].tv_usec = times[1].tv_usec = 0;
  417. utimes(FailFile.c_str(), times);
  418. close(FailFd);
  419. _exit(100);
  420. }
  421. /*}}}*/
  422. // ServerMethod::Fetch - Fetch an item /*{{{*/
  423. // ---------------------------------------------------------------------
  424. /* This adds an item to the pipeline. We keep the pipeline at a fixed
  425. depth. */
  426. bool ServerMethod::Fetch(FetchItem *)
  427. {
  428. if (Server == nullptr || QueueBack == nullptr)
  429. return true;
  430. // If pipelining is disabled, we only queue 1 request
  431. auto const AllowedDepth = Server->Pipeline ? PipelineDepth : 0;
  432. // how deep is our pipeline currently?
  433. decltype(PipelineDepth) CurrentDepth = 0;
  434. for (FetchItem const *I = Queue; I != QueueBack; I = I->Next)
  435. ++CurrentDepth;
  436. if (CurrentDepth > AllowedDepth)
  437. return true;
  438. do {
  439. // Make sure we stick with the same server
  440. if (Server->Comp(QueueBack->Uri) == false)
  441. break;
  442. bool const UsableHashes = QueueBack->ExpectedHashes.usable();
  443. // if we have no hashes, do at most one such request
  444. // as we can't fixup pipeling misbehaviors otherwise
  445. if (CurrentDepth != 0 && UsableHashes == false)
  446. break;
  447. if (UsableHashes && FileExists(QueueBack->DestFile))
  448. {
  449. FileFd partial(QueueBack->DestFile, FileFd::ReadOnly);
  450. Hashes wehave(QueueBack->ExpectedHashes);
  451. if (QueueBack->ExpectedHashes.FileSize() == partial.FileSize())
  452. {
  453. if (wehave.AddFD(partial) &&
  454. wehave.GetHashStringList() == QueueBack->ExpectedHashes)
  455. {
  456. FetchResult Res;
  457. Res.Filename = QueueBack->DestFile;
  458. Res.ResumePoint = QueueBack->ExpectedHashes.FileSize();
  459. URIStart(Res);
  460. // move item to the start of the queue as URIDone will
  461. // always dequeued the first item in the queue
  462. if (Queue != QueueBack)
  463. {
  464. FetchItem *Prev = Queue;
  465. for (; Prev->Next != QueueBack; Prev = Prev->Next)
  466. /* look for the previous queue item */;
  467. Prev->Next = QueueBack->Next;
  468. QueueBack->Next = Queue;
  469. Queue = QueueBack;
  470. QueueBack = Prev->Next;
  471. }
  472. Res.TakeHashes(wehave);
  473. URIDone(Res);
  474. continue;
  475. }
  476. else
  477. RemoveFile("Fetch-Partial", QueueBack->DestFile);
  478. }
  479. }
  480. auto const Tmp = QueueBack;
  481. QueueBack = QueueBack->Next;
  482. SendReq(Tmp);
  483. ++CurrentDepth;
  484. } while (CurrentDepth <= AllowedDepth && QueueBack != nullptr);
  485. return true;
  486. }
  487. /*}}}*/
  488. // ServerMethod::Loop - Main loop /*{{{*/
  489. int ServerMethod::Loop()
  490. {
  491. signal(SIGTERM,SigTerm);
  492. signal(SIGINT,SigTerm);
  493. Server = 0;
  494. int FailCounter = 0;
  495. while (1)
  496. {
  497. // We have no commands, wait for some to arrive
  498. if (Queue == 0)
  499. {
  500. if (WaitFd(STDIN_FILENO) == false)
  501. return 0;
  502. }
  503. /* Run messages, we can accept 0 (no message) if we didn't
  504. do a WaitFd above.. Otherwise the FD is closed. */
  505. int Result = Run(true);
  506. if (Result != -1 && (Result != 0 || Queue == 0))
  507. {
  508. if(FailReason.empty() == false ||
  509. ConfigFindB("DependOnSTDIN", true) == true)
  510. return 100;
  511. else
  512. return 0;
  513. }
  514. if (Queue == 0)
  515. continue;
  516. // Connect to the server
  517. if (Server == 0 || Server->Comp(Queue->Uri) == false)
  518. {
  519. Server = CreateServerState(Queue->Uri);
  520. setPostfixForMethodNames(::URI(Queue->Uri).Host.c_str());
  521. AllowRedirect = ConfigFindB("AllowRedirect", true);
  522. PipelineDepth = ConfigFindI("Pipeline-Depth", 10);
  523. Debug = DebugEnabled();
  524. }
  525. /* If the server has explicitly said this is the last connection
  526. then we pre-emptively shut down the pipeline and tear down
  527. the connection. This will speed up HTTP/1.0 servers a tad
  528. since we don't have to wait for the close sequence to
  529. complete */
  530. if (Server->Persistent == false)
  531. Server->Close();
  532. // Reset the pipeline
  533. if (Server->IsOpen() == false)
  534. QueueBack = Queue;
  535. // Connnect to the host
  536. if (Server->Open() == false)
  537. {
  538. Fail(true);
  539. Server = nullptr;
  540. continue;
  541. }
  542. // Fill the pipeline.
  543. Fetch(0);
  544. // Fetch the next URL header data from the server.
  545. switch (Server->RunHeaders(File, Queue->Uri))
  546. {
  547. case ServerState::RUN_HEADERS_OK:
  548. break;
  549. // The header data is bad
  550. case ServerState::RUN_HEADERS_PARSE_ERROR:
  551. {
  552. _error->Error(_("Bad header data"));
  553. Fail(true);
  554. Server->Close();
  555. RotateDNS();
  556. continue;
  557. }
  558. // The server closed a connection during the header get..
  559. default:
  560. case ServerState::RUN_HEADERS_IO_ERROR:
  561. {
  562. FailCounter++;
  563. _error->Discard();
  564. Server->Close();
  565. Server->Pipeline = false;
  566. Server->PipelineAllowed = false;
  567. if (FailCounter >= 2)
  568. {
  569. Fail(_("Connection failed"),true);
  570. FailCounter = 0;
  571. }
  572. RotateDNS();
  573. continue;
  574. }
  575. };
  576. // Decide what to do.
  577. FetchResult Res;
  578. Res.Filename = Queue->DestFile;
  579. switch (DealWithHeaders(Res))
  580. {
  581. // Ok, the file is Open
  582. case FILE_IS_OPEN:
  583. {
  584. URIStart(Res);
  585. // Run the data
  586. bool Result = true;
  587. // ensure we don't fetch too much
  588. // we could do "Server->MaximumSize = Queue->MaximumSize" here
  589. // but that would break the clever pipeline messup detection
  590. // so instead we use the size of the biggest item in the queue
  591. Server->MaximumSize = FindMaximumObjectSizeInQueue();
  592. if (Server->HaveContent)
  593. Result = Server->RunData(File);
  594. /* If the server is sending back sizeless responses then fill in
  595. the size now */
  596. if (Res.Size == 0)
  597. Res.Size = File->Size();
  598. // Close the file, destroy the FD object and timestamp it
  599. FailFd = -1;
  600. delete File;
  601. File = 0;
  602. // Timestamp
  603. struct timeval times[2];
  604. times[0].tv_sec = times[1].tv_sec = Server->Date;
  605. times[0].tv_usec = times[1].tv_usec = 0;
  606. utimes(Queue->DestFile.c_str(), times);
  607. // Send status to APT
  608. if (Result == true)
  609. {
  610. Hashes * const resultHashes = Server->GetHashes();
  611. HashStringList const hashList = resultHashes->GetHashStringList();
  612. if (PipelineDepth != 0 && Queue->ExpectedHashes.usable() == true && Queue->ExpectedHashes != hashList)
  613. {
  614. // we did not get the expected hash… mhhh:
  615. // could it be that server/proxy messed up pipelining?
  616. FetchItem * BeforeI = Queue;
  617. for (FetchItem *I = Queue->Next; I != 0 && I != QueueBack; I = I->Next)
  618. {
  619. if (I->ExpectedHashes.usable() == true && I->ExpectedHashes == hashList)
  620. {
  621. // yes, he did! Disable pipelining and rewrite queue
  622. if (Server->Pipeline == true)
  623. {
  624. Warning(_("Automatically disabled %s due to incorrect response from server/proxy. (man 5 apt.conf)"), "Acquire::http::Pipeline-Depth");
  625. Server->Pipeline = false;
  626. Server->PipelineAllowed = false;
  627. // we keep the PipelineDepth value so that the rest of the queue can be fixed up as well
  628. }
  629. Rename(Res.Filename, I->DestFile);
  630. Res.Filename = I->DestFile;
  631. BeforeI->Next = I->Next;
  632. I->Next = Queue;
  633. Queue = I;
  634. break;
  635. }
  636. BeforeI = I;
  637. }
  638. }
  639. Res.TakeHashes(*resultHashes);
  640. URIDone(Res);
  641. }
  642. else
  643. {
  644. if (Server->IsOpen() == false)
  645. {
  646. FailCounter++;
  647. _error->Discard();
  648. Server->Close();
  649. if (FailCounter >= 2)
  650. {
  651. Fail(_("Connection failed"),true);
  652. FailCounter = 0;
  653. }
  654. QueueBack = Queue;
  655. }
  656. else
  657. {
  658. Server->Close();
  659. Fail(true);
  660. }
  661. }
  662. break;
  663. }
  664. // IMS hit
  665. case IMS_HIT:
  666. {
  667. URIDone(Res);
  668. break;
  669. }
  670. // Hard server error, not found or something
  671. case ERROR_UNRECOVERABLE:
  672. {
  673. Fail();
  674. break;
  675. }
  676. // Hard internal error, kill the connection and fail
  677. case ERROR_NOT_FROM_SERVER:
  678. {
  679. delete File;
  680. File = 0;
  681. Fail();
  682. RotateDNS();
  683. Server->Close();
  684. break;
  685. }
  686. // We need to flush the data, the header is like a 404 w/ error text
  687. case ERROR_WITH_CONTENT_PAGE:
  688. {
  689. Fail();
  690. Server->RunDataToDevNull();
  691. break;
  692. }
  693. // Try again with a new URL
  694. case TRY_AGAIN_OR_REDIRECT:
  695. {
  696. // Clear rest of response if there is content
  697. if (Server->HaveContent)
  698. Server->RunDataToDevNull();
  699. Redirect(NextURI);
  700. break;
  701. }
  702. default:
  703. Fail(_("Internal error"));
  704. break;
  705. }
  706. FailCounter = 0;
  707. }
  708. return 0;
  709. }
  710. /*}}}*/
  711. unsigned long long ServerMethod::FindMaximumObjectSizeInQueue() const /*{{{*/
  712. {
  713. unsigned long long MaxSizeInQueue = 0;
  714. for (FetchItem *I = Queue; I != 0 && I != QueueBack; I = I->Next)
  715. MaxSizeInQueue = std::max(MaxSizeInQueue, I->MaximumSize);
  716. return MaxSizeInQueue;
  717. }
  718. /*}}}*/
  719. ServerMethod::ServerMethod(std::string &&Binary, char const * const Ver,unsigned long const Flags) :/*{{{*/
  720. aptMethod(std::move(Binary), Ver, Flags), Server(nullptr), File(NULL), PipelineDepth(10),
  721. AllowRedirect(false), Debug(false)
  722. {
  723. }
  724. /*}}}*/
  725. bool ServerMethod::Configuration(std::string Message) /*{{{*/
  726. {
  727. if (aptMethod::Configuration(Message) == false)
  728. return false;
  729. _config->CndSet("Acquire::tor::Proxy",
  730. "socks5h://apt-transport-tor@localhost:9050");
  731. return true;
  732. }
  733. /*}}}*/
  734. bool ServerMethod::AddProxyAuth(URI &Proxy, URI const &Server) const /*{{{*/
  735. {
  736. if (std::find(methodNames.begin(), methodNames.end(), "tor") != methodNames.end() &&
  737. Proxy.User == "apt-transport-tor" && Proxy.Password.empty())
  738. {
  739. std::string pass = Server.Host;
  740. pass.erase(std::remove_if(pass.begin(), pass.end(), [](char const c) { return std::isalnum(c) == 0; }), pass.end());
  741. if (pass.length() > 255)
  742. Proxy.Password = pass.substr(0, 255);
  743. else
  744. Proxy.Password = std::move(pass);
  745. }
  746. // FIXME: should we support auth.conf for proxies?
  747. return true;
  748. }
  749. /*}}}*/