cert_net_fetcher_url_request.cc 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887
  1. // Copyright 2015 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. //
  5. // Overview
  6. //
  7. // The main entry point is CertNetFetcherURLRequest. This is an implementation
  8. // of CertNetFetcher that provides a service for fetching network requests.
  9. //
  10. // The interface for CertNetFetcher is synchronous, however allows
  11. // overlapping requests. When starting a request CertNetFetcherURLRequest
  12. // returns a CertNetFetcher::Request (CertNetFetcherRequestImpl) that the
  13. // caller can use to cancel the fetch, or wait for it to complete
  14. // (blocking).
  15. //
  16. // The CertNetFetcherURLRequest is shared between a network thread and a
  17. // caller thread that waits for fetches to happen on the network thread.
  18. //
  19. // The classes are mainly organized based on their thread affinity:
  20. //
  21. // ---------------
  22. // Straddles caller thread and network thread
  23. // ---------------
  24. //
  25. // CertNetFetcherURLRequest (implements CertNetFetcher)
  26. // * Main entry point. Must be created and shutdown from the network thread.
  27. // * Provides a service to start/cancel/wait for URL fetches, to be
  28. // used on the caller thread.
  29. // * Returns callers a CertNetFetcher::Request as a handle
  30. // * Requests can run in parallel, however will block the current thread when
  31. // reading results.
  32. // * Posts tasks to network thread to coordinate actual work
  33. //
  34. // RequestCore
  35. // * Reference-counted bridge between CertNetFetcherRequestImpl and the
  36. // dependencies on the network thread
  37. // * Holds the result of the request, a WaitableEvent for signaling
  38. // completion, and pointers for canceling work on network thread.
  39. //
  40. // ---------------
  41. // Lives on caller thread
  42. // ---------------
  43. //
  44. // CertNetFetcherRequestImpl (implements CertNetFetcher::Request)
  45. // * Wrapper for cancelling events, or waiting for a request to complete
  46. // * Waits on a WaitableEvent to complete requests.
  47. //
  48. // ---------------
  49. // Lives on network thread
  50. // ---------------
  51. //
  52. // AsyncCertNetFetcherURLRequest
  53. // * Asynchronous manager for outstanding requests. Handles de-duplication,
  54. // timeouts, and actual integration with network stack. This is where the
  55. // majority of the logic lives.
  56. // * Signals completion of requests through RequestCore's WaitableEvent.
  57. // * Attaches requests to Jobs for the purpose of de-duplication
  58. #include "net/cert_net/cert_net_fetcher_url_request.h"
  59. #include <memory>
  60. #include <tuple>
  61. #include <utility>
  62. #include "base/bind.h"
  63. #include "base/callback_helpers.h"
  64. #include "base/check_op.h"
  65. #include "base/memory/ptr_util.h"
  66. #include "base/memory/raw_ptr.h"
  67. #include "base/numerics/safe_math.h"
  68. #include "base/synchronization/waitable_event.h"
  69. #include "base/task/single_thread_task_runner.h"
  70. #include "base/threading/thread_task_runner_handle.h"
  71. #include "base/time/time.h"
  72. #include "base/timer/timer.h"
  73. #include "net/base/io_buffer.h"
  74. #include "net/base/isolation_info.h"
  75. #include "net/base/load_flags.h"
  76. #include "net/cert/cert_net_fetcher.h"
  77. #include "net/cookies/site_for_cookies.h"
  78. #include "net/dns/public/secure_dns_policy.h"
  79. #include "net/traffic_annotation/network_traffic_annotation.h"
  80. #include "net/url_request/redirect_info.h"
  81. #include "net/url_request/url_request_context.h"
  82. #include "url/origin.h"
  83. // TODO(eroman): Add support for POST parameters.
  84. // TODO(eroman): Add controls for bypassing the cache.
  85. // TODO(eroman): Add a maximum number of in-flight jobs/requests.
  86. // TODO(eroman): Add NetLog integration.
  87. namespace net {
  88. namespace {
  89. // The size of the buffer used for reading the response body of the URLRequest.
  90. const int kReadBufferSizeInBytes = 4096;
  91. // The maximum size in bytes for the response body when fetching a CRL.
  92. const int kMaxResponseSizeInBytesForCrl = 5 * 1024 * 1024;
  93. // The maximum size in bytes for the response body when fetching an AIA URL
  94. // (caIssuers/OCSP).
  95. const int kMaxResponseSizeInBytesForAia = 64 * 1024;
  96. // The default timeout in seconds for fetch requests.
  97. const int kTimeoutSeconds = 15;
  98. class Job;
  99. struct JobToRequestParamsComparator;
  100. struct JobComparator {
  101. bool operator()(const Job* job1, const Job* job2) const;
  102. };
  103. // Would be a set<unique_ptr> but extraction of owned objects from a set of
  104. // owned types doesn't come until C++17.
  105. using JobSet = std::map<Job*, std::unique_ptr<Job>, JobComparator>;
  106. } // namespace
  107. // AsyncCertNetFetcherURLRequest manages URLRequests in an async fashion on the
  108. // URLRequestContexts's task runner thread.
  109. //
  110. // * Schedules
  111. // * De-duplicates requests
  112. // * Handles timeouts
  113. class CertNetFetcherURLRequest::AsyncCertNetFetcherURLRequest {
  114. public:
  115. // Initializes AsyncCertNetFetcherURLRequest using the specified
  116. // URLRequestContext for issuing requests. |context| must remain valid until
  117. // Shutdown() is called or the AsyncCertNetFetcherURLRequest is destroyed.
  118. explicit AsyncCertNetFetcherURLRequest(URLRequestContext* context);
  119. AsyncCertNetFetcherURLRequest(const AsyncCertNetFetcherURLRequest&) = delete;
  120. AsyncCertNetFetcherURLRequest& operator=(
  121. const AsyncCertNetFetcherURLRequest&) = delete;
  122. // The AsyncCertNetFetcherURLRequest is expected to be kept alive until all
  123. // requests have completed or Shutdown() is called.
  124. ~AsyncCertNetFetcherURLRequest();
  125. // Starts an asynchronous request to fetch the given URL. On completion
  126. // request->OnJobCompleted() will be invoked.
  127. void Fetch(std::unique_ptr<RequestParams> request_params,
  128. scoped_refptr<RequestCore> request);
  129. // Removes |job| from the in progress jobs and transfers ownership to the
  130. // caller.
  131. std::unique_ptr<Job> RemoveJob(Job* job);
  132. // Cancels outstanding jobs, which stops network requests and signals the
  133. // corresponding RequestCores that the requests have completed.
  134. void Shutdown();
  135. private:
  136. // Finds a job with a matching RequestPararms or returns nullptr if there was
  137. // no match.
  138. Job* FindJob(const RequestParams& params);
  139. // The in-progress jobs. This set does not contain the job which is actively
  140. // invoking callbacks (OnJobCompleted).
  141. JobSet jobs_;
  142. // Not owned. |context_| must outlive the AsyncCertNetFetcherURLRequest.
  143. raw_ptr<URLRequestContext> context_ = nullptr;
  144. THREAD_CHECKER(thread_checker_);
  145. };
  146. namespace {
  147. // Policy for which URLs are allowed to be fetched. This is called both for the
  148. // initial URL and for each redirect. Returns OK on success or a net error
  149. // code on failure.
  150. Error CanFetchUrl(const GURL& url) {
  151. if (!url.SchemeIs("http"))
  152. return ERR_DISALLOWED_URL_SCHEME;
  153. return OK;
  154. }
  155. base::TimeDelta GetTimeout(int timeout_milliseconds) {
  156. if (timeout_milliseconds == CertNetFetcher::DEFAULT)
  157. return base::Seconds(kTimeoutSeconds);
  158. return base::Milliseconds(timeout_milliseconds);
  159. }
  160. size_t GetMaxResponseBytes(int max_response_bytes,
  161. size_t default_max_response_bytes) {
  162. if (max_response_bytes == CertNetFetcher::DEFAULT)
  163. return default_max_response_bytes;
  164. // Ensure that the specified limit is not negative, and cannot result in an
  165. // overflow while reading.
  166. base::CheckedNumeric<size_t> check(max_response_bytes);
  167. check += kReadBufferSizeInBytes;
  168. DCHECK(check.IsValid());
  169. return max_response_bytes;
  170. }
  171. enum HttpMethod {
  172. HTTP_METHOD_GET,
  173. HTTP_METHOD_POST,
  174. };
  175. } // namespace
  176. // RequestCore tracks an outstanding call to Fetch(). It is
  177. // reference-counted for ease of sharing between threads.
  178. class CertNetFetcherURLRequest::RequestCore
  179. : public base::RefCountedThreadSafe<RequestCore> {
  180. public:
  181. explicit RequestCore(scoped_refptr<base::SingleThreadTaskRunner> task_runner)
  182. : completion_event_(base::WaitableEvent::ResetPolicy::MANUAL,
  183. base::WaitableEvent::InitialState::NOT_SIGNALED),
  184. task_runner_(std::move(task_runner)) {}
  185. RequestCore(const RequestCore&) = delete;
  186. RequestCore& operator=(const RequestCore&) = delete;
  187. void AttachedToJob(Job* job) {
  188. DCHECK(task_runner_->RunsTasksInCurrentSequence());
  189. DCHECK(!job_);
  190. // Requests should not be attached to jobs after they have been signalled
  191. // with a cancellation error (which happens via either Cancel() or
  192. // SignalImmediateError()).
  193. DCHECK_NE(error_, ERR_ABORTED);
  194. job_ = job;
  195. }
  196. void OnJobCompleted(Job* job,
  197. Error error,
  198. const std::vector<uint8_t>& response_body) {
  199. DCHECK(task_runner_->RunsTasksInCurrentSequence());
  200. DCHECK_EQ(job_, job);
  201. job_ = nullptr;
  202. error_ = error;
  203. bytes_ = response_body;
  204. completion_event_.Signal();
  205. }
  206. // Detaches this request from its job (if it is attached to any) and
  207. // signals completion with ERR_ABORTED. Can be called from any thread.
  208. void CancelJob();
  209. // Can be used to signal that an error was encountered before the request was
  210. // attached to a job. Can be called from any thread.
  211. void SignalImmediateError();
  212. // Should only be called once.
  213. void WaitForResult(Error* error, std::vector<uint8_t>* bytes) {
  214. DCHECK(!task_runner_->RunsTasksInCurrentSequence());
  215. completion_event_.Wait();
  216. *bytes = std::move(bytes_);
  217. *error = error_;
  218. error_ = ERR_UNEXPECTED;
  219. }
  220. private:
  221. friend class base::RefCountedThreadSafe<RequestCore>;
  222. ~RequestCore() {
  223. // Requests should have been cancelled prior to destruction.
  224. DCHECK(!job_);
  225. }
  226. // A non-owned pointer to the job that is executing the request.
  227. raw_ptr<Job> job_ = nullptr;
  228. // May be written to from network thread, or from the caller thread only when
  229. // there is no work that will be done on the network thread (e.g. when the
  230. // network thread has been shutdown before the request begins). See comment in
  231. // SignalImmediateError.
  232. Error error_ = OK;
  233. std::vector<uint8_t> bytes_;
  234. // Indicates when |error_| and |bytes_| have been written to.
  235. base::WaitableEvent completion_event_;
  236. scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
  237. };
  238. struct CertNetFetcherURLRequest::RequestParams {
  239. RequestParams();
  240. RequestParams(const RequestParams&) = delete;
  241. RequestParams& operator=(const RequestParams&) = delete;
  242. bool operator<(const RequestParams& other) const;
  243. GURL url;
  244. HttpMethod http_method = HTTP_METHOD_GET;
  245. size_t max_response_bytes = 0;
  246. // If set to a value <= 0 then means "no timeout".
  247. base::TimeDelta timeout;
  248. // IMPORTANT: When adding fields to this structure, update operator<().
  249. };
  250. CertNetFetcherURLRequest::RequestParams::RequestParams() = default;
  251. bool CertNetFetcherURLRequest::RequestParams::operator<(
  252. const RequestParams& other) const {
  253. return std::tie(url, http_method, max_response_bytes, timeout) <
  254. std::tie(other.url, other.http_method, other.max_response_bytes,
  255. other.timeout);
  256. }
  257. namespace {
  258. // Job tracks an outstanding URLRequest as well as all of the pending requests
  259. // for it.
  260. class Job : public URLRequest::Delegate {
  261. public:
  262. Job(std::unique_ptr<CertNetFetcherURLRequest::RequestParams> request_params,
  263. CertNetFetcherURLRequest::AsyncCertNetFetcherURLRequest* parent);
  264. Job(const Job&) = delete;
  265. Job& operator=(const Job&) = delete;
  266. ~Job() override;
  267. const CertNetFetcherURLRequest::RequestParams& request_params() const {
  268. return *request_params_;
  269. }
  270. // Creates a request and attaches it to the job. When the job completes it
  271. // will notify the request of completion through OnJobCompleted.
  272. void AttachRequest(
  273. scoped_refptr<CertNetFetcherURLRequest::RequestCore> request);
  274. // Removes |request| from the job.
  275. void DetachRequest(CertNetFetcherURLRequest::RequestCore* request);
  276. // Creates and starts a URLRequest for the job. After the URLRequest has
  277. // completed, OnJobCompleted() will be invoked and all the registered requests
  278. // notified of completion.
  279. void StartURLRequest(URLRequestContext* context);
  280. // Cancels the request with an ERR_ABORTED error and invokes
  281. // RequestCore::OnJobCompleted() to notify the registered requests of the
  282. // cancellation. The job is *not* removed from the
  283. // AsyncCertNetFetcherURLRequest.
  284. void Cancel();
  285. private:
  286. // Implementation of URLRequest::Delegate
  287. void OnReceivedRedirect(URLRequest* request,
  288. const RedirectInfo& redirect_info,
  289. bool* defer_redirect) override;
  290. void OnResponseStarted(URLRequest* request, int net_error) override;
  291. void OnReadCompleted(URLRequest* request, int bytes_read) override;
  292. // Clears the URLRequest and timer. Helper for doing work common to
  293. // cancellation and job completion.
  294. void Stop();
  295. // Reads as much data as available from |request|.
  296. void ReadBody(URLRequest* request);
  297. // Helper to copy the partial bytes read from the read IOBuffer to an
  298. // aggregated buffer.
  299. bool ConsumeBytesRead(URLRequest* request, int num_bytes);
  300. // Called when the URLRequest has completed (either success or failure).
  301. void OnUrlRequestCompleted(int net_error);
  302. // Called when the Job has completed. The job may finish in response to a
  303. // timeout, an invalid URL, or the URLRequest completing. By the time this
  304. // method is called, the |response_body_| variable have been assigned.
  305. void OnJobCompleted(Error error);
  306. // Calls r->OnJobCompleted() for each RequestCore |r| currently attached
  307. // to this job, and then clears |requests_|.
  308. void CompleteAndClearRequests(Error error);
  309. // Cancels a request with a specified error code and calls
  310. // OnUrlRequestCompleted().
  311. void FailRequest(Error error);
  312. // The requests attached to this job.
  313. std::vector<scoped_refptr<CertNetFetcherURLRequest::RequestCore>> requests_;
  314. // The input parameters for starting a URLRequest.
  315. std::unique_ptr<CertNetFetcherURLRequest::RequestParams> request_params_;
  316. // The URLRequest response information.
  317. std::vector<uint8_t> response_body_;
  318. std::unique_ptr<URLRequest> url_request_;
  319. scoped_refptr<IOBuffer> read_buffer_;
  320. // Used to timeout the job when the URLRequest takes too long. This timer is
  321. // also used for notifying a failure to start the URLRequest.
  322. base::OneShotTimer timer_;
  323. // Non-owned pointer to the AsyncCertNetFetcherURLRequest that created this
  324. // job.
  325. raw_ptr<CertNetFetcherURLRequest::AsyncCertNetFetcherURLRequest> parent_;
  326. };
  327. } // namespace
  328. void CertNetFetcherURLRequest::RequestCore::CancelJob() {
  329. if (!task_runner_->RunsTasksInCurrentSequence()) {
  330. task_runner_->PostTask(FROM_HERE,
  331. base::BindOnce(&RequestCore::CancelJob, this));
  332. return;
  333. }
  334. if (job_) {
  335. auto* job = job_.get();
  336. job_ = nullptr;
  337. job->DetachRequest(this);
  338. }
  339. SignalImmediateError();
  340. }
  341. void CertNetFetcherURLRequest::RequestCore::SignalImmediateError() {
  342. // These data members are normally only written on the network thread, but it
  343. // is safe to write here from either thread. This is because
  344. // SignalImmediateError is only to be called before this request is attached
  345. // to a job. In particular, if called from the caller thread, no work will be
  346. // done on the network thread for this request, so these variables will only
  347. // be written and read on the caller thread. If called from the network
  348. // thread, they will only be written to on the network thread and will not be
  349. // read on the caller thread until |completion_event_| is signalled (after
  350. // which it will be not be written on the network thread again).
  351. DCHECK(!job_);
  352. error_ = ERR_ABORTED;
  353. bytes_.clear();
  354. completion_event_.Signal();
  355. }
  356. namespace {
  357. Job::Job(
  358. std::unique_ptr<CertNetFetcherURLRequest::RequestParams> request_params,
  359. CertNetFetcherURLRequest::AsyncCertNetFetcherURLRequest* parent)
  360. : request_params_(std::move(request_params)), parent_(parent) {}
  361. Job::~Job() {
  362. DCHECK(requests_.empty());
  363. Stop();
  364. }
  365. void Job::AttachRequest(
  366. scoped_refptr<CertNetFetcherURLRequest::RequestCore> request) {
  367. request->AttachedToJob(this);
  368. requests_.push_back(std::move(request));
  369. }
  370. void Job::DetachRequest(CertNetFetcherURLRequest::RequestCore* request) {
  371. std::unique_ptr<Job> delete_this;
  372. auto it = std::find(requests_.begin(), requests_.end(), request);
  373. DCHECK(it != requests_.end());
  374. requests_.erase(it);
  375. // If there are no longer any requests attached to the job then
  376. // cancel and delete it.
  377. if (requests_.empty())
  378. delete_this = parent_->RemoveJob(this);
  379. }
  380. void Job::StartURLRequest(URLRequestContext* context) {
  381. Error error = CanFetchUrl(request_params_->url);
  382. if (error != OK) {
  383. OnJobCompleted(error);
  384. return;
  385. }
  386. // Start the URLRequest.
  387. read_buffer_ = base::MakeRefCounted<IOBuffer>(kReadBufferSizeInBytes);
  388. NetworkTrafficAnnotationTag traffic_annotation =
  389. DefineNetworkTrafficAnnotation("certificate_verifier_url_request",
  390. R"(
  391. semantics {
  392. sender: "Certificate Verifier"
  393. description:
  394. "When verifying certificates, the browser may need to fetch "
  395. "additional URLs that are encoded in the server-provided "
  396. "certificate chain. This may be part of revocation checking ("
  397. "Online Certificate Status Protocol, Certificate Revocation List), "
  398. "or path building (Authority Information Access fetches). Please "
  399. "refer to the following for more on above protocols: "
  400. "https://tools.ietf.org/html/rfc6960, "
  401. "https://tools.ietf.org/html/rfc5280#section-4.2.1.13, and"
  402. "https://tools.ietf.org/html/rfc5280#section-5.2.7."
  403. "NOTE: this path is being deprecated. Please see the"
  404. "certificate_verifier_url_loader annotation for the new path."
  405. trigger:
  406. "Verifying a certificate (likely in response to navigating to an "
  407. "'https://' website)."
  408. data:
  409. "In the case of OCSP this may divulge the website being viewed. No "
  410. "user data in other cases."
  411. destination: OTHER
  412. destination_other:
  413. "The URL specified in the certificate."
  414. }
  415. policy {
  416. cookies_allowed: NO
  417. setting: "This feature cannot be disabled by settings."
  418. policy_exception_justification: "Not implemented."
  419. })");
  420. url_request_ = context->CreateRequest(request_params_->url, DEFAULT_PRIORITY,
  421. this, traffic_annotation);
  422. if (request_params_->http_method == HTTP_METHOD_POST)
  423. url_request_->set_method("POST");
  424. url_request_->set_allow_credentials(false);
  425. // Disable secure DNS for hostname lookups triggered by certificate network
  426. // fetches to prevent deadlock.
  427. url_request_->SetSecureDnsPolicy(SecureDnsPolicy::kDisable);
  428. // Create IsolationInfo based on the origin of the requested URL.
  429. // TODO(https://crbug.com/1016890): Cert validation needs to either be
  430. // double-keyed or based on a static database, to protect it from being used
  431. // as a cross-site user tracking vector. For now, just treat it as if it were
  432. // a subresource request of the origin used for the request. This allows the
  433. // result to still be cached in the HTTP cache, and lets URLRequest DCHECK
  434. // that all requests have non-empty IsolationInfos.
  435. url::Origin origin = url::Origin::Create(request_params_->url);
  436. url_request_->set_isolation_info(IsolationInfo::Create(
  437. IsolationInfo::RequestType::kOther, origin /* top_frame_origin */,
  438. origin /* frame_origin */, SiteForCookies()));
  439. url_request_->Start();
  440. // Start a timer to limit how long the job runs for.
  441. if (request_params_->timeout.is_positive()) {
  442. timer_.Start(FROM_HERE, request_params_->timeout,
  443. base::BindOnce(&Job::FailRequest, base::Unretained(this),
  444. ERR_TIMED_OUT));
  445. }
  446. }
  447. void Job::Cancel() {
  448. // Stop the timer and clear the URLRequest.
  449. Stop();
  450. // Signal attached requests that they've been completed.
  451. CompleteAndClearRequests(static_cast<Error>(ERR_ABORTED));
  452. }
  453. void Job::OnReceivedRedirect(URLRequest* request,
  454. const RedirectInfo& redirect_info,
  455. bool* defer_redirect) {
  456. DCHECK_EQ(url_request_.get(), request);
  457. // Ensure that the new URL matches the policy.
  458. Error error = CanFetchUrl(redirect_info.new_url);
  459. if (error != OK) {
  460. FailRequest(error);
  461. return;
  462. }
  463. }
  464. void Job::OnResponseStarted(URLRequest* request, int net_error) {
  465. DCHECK_EQ(url_request_.get(), request);
  466. DCHECK_NE(ERR_IO_PENDING, net_error);
  467. if (net_error != OK) {
  468. OnUrlRequestCompleted(net_error);
  469. return;
  470. }
  471. if (request->GetResponseCode() != 200) {
  472. FailRequest(ERR_HTTP_RESPONSE_CODE_FAILURE);
  473. return;
  474. }
  475. ReadBody(request);
  476. }
  477. void Job::OnReadCompleted(URLRequest* request, int bytes_read) {
  478. DCHECK_EQ(url_request_.get(), request);
  479. DCHECK_NE(ERR_IO_PENDING, bytes_read);
  480. // Keep reading the response body.
  481. if (ConsumeBytesRead(request, bytes_read))
  482. ReadBody(request);
  483. }
  484. void Job::Stop() {
  485. timer_.Stop();
  486. url_request_.reset();
  487. }
  488. void Job::ReadBody(URLRequest* request) {
  489. // Read as many bytes as are available synchronously.
  490. int num_bytes = 0;
  491. while (num_bytes >= 0) {
  492. num_bytes = request->Read(read_buffer_.get(), kReadBufferSizeInBytes);
  493. if (num_bytes == ERR_IO_PENDING)
  494. return;
  495. if (!ConsumeBytesRead(request, num_bytes))
  496. return;
  497. }
  498. OnUrlRequestCompleted(num_bytes);
  499. }
  500. bool Job::ConsumeBytesRead(URLRequest* request, int num_bytes) {
  501. DCHECK_NE(ERR_IO_PENDING, num_bytes);
  502. if (num_bytes <= 0) {
  503. // Error while reading, or EOF.
  504. OnUrlRequestCompleted(num_bytes);
  505. return false;
  506. }
  507. // Enforce maximum size bound.
  508. if (num_bytes + response_body_.size() > request_params_->max_response_bytes) {
  509. FailRequest(ERR_FILE_TOO_BIG);
  510. return false;
  511. }
  512. // Append the data to |response_body_|.
  513. response_body_.reserve(num_bytes);
  514. response_body_.insert(response_body_.end(), read_buffer_->data(),
  515. read_buffer_->data() + num_bytes);
  516. return true;
  517. }
  518. void Job::OnUrlRequestCompleted(int net_error) {
  519. DCHECK_NE(ERR_IO_PENDING, net_error);
  520. Error result = static_cast<Error>(net_error);
  521. OnJobCompleted(result);
  522. }
  523. void Job::OnJobCompleted(Error error) {
  524. DCHECK_NE(ERR_IO_PENDING, error);
  525. // Stop the timer and clear the URLRequest.
  526. Stop();
  527. std::unique_ptr<Job> delete_this = parent_->RemoveJob(this);
  528. CompleteAndClearRequests(error);
  529. }
  530. void Job::CompleteAndClearRequests(Error error) {
  531. for (const auto& request : requests_) {
  532. request->OnJobCompleted(this, error, response_body_);
  533. }
  534. requests_.clear();
  535. }
  536. void Job::FailRequest(Error error) {
  537. DCHECK_NE(ERR_IO_PENDING, error);
  538. int result = url_request_->CancelWithError(error);
  539. OnUrlRequestCompleted(result);
  540. }
  541. } // namespace
  542. CertNetFetcherURLRequest::AsyncCertNetFetcherURLRequest::
  543. AsyncCertNetFetcherURLRequest(URLRequestContext* context)
  544. : context_(context) {
  545. // Allow creation to happen from another thread.
  546. DETACH_FROM_THREAD(thread_checker_);
  547. }
  548. CertNetFetcherURLRequest::AsyncCertNetFetcherURLRequest::
  549. ~AsyncCertNetFetcherURLRequest() {
  550. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  551. jobs_.clear();
  552. }
  553. bool JobComparator::operator()(const Job* job1, const Job* job2) const {
  554. return job1->request_params() < job2->request_params();
  555. }
  556. void CertNetFetcherURLRequest::AsyncCertNetFetcherURLRequest::Fetch(
  557. std::unique_ptr<RequestParams> request_params,
  558. scoped_refptr<RequestCore> request) {
  559. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  560. // If there is an in-progress job that matches the request parameters use it.
  561. // Otherwise start a new job.
  562. Job* job = FindJob(*request_params);
  563. if (job) {
  564. job->AttachRequest(std::move(request));
  565. return;
  566. }
  567. auto new_job = std::make_unique<Job>(std::move(request_params), this);
  568. job = new_job.get();
  569. jobs_[job] = std::move(new_job);
  570. // Attach the request before calling StartURLRequest; this ensures that the
  571. // request will get signalled if StartURLRequest completes the job
  572. // synchronously.
  573. job->AttachRequest(std::move(request));
  574. job->StartURLRequest(context_);
  575. }
  576. void CertNetFetcherURLRequest::AsyncCertNetFetcherURLRequest::Shutdown() {
  577. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  578. for (const auto& job : jobs_) {
  579. job.first->Cancel();
  580. }
  581. jobs_.clear();
  582. }
  583. namespace {
  584. struct JobToRequestParamsComparator {
  585. bool operator()(const JobSet::value_type& job,
  586. const CertNetFetcherURLRequest::RequestParams& value) const {
  587. return job.first->request_params() < value;
  588. }
  589. };
  590. } // namespace
  591. Job* CertNetFetcherURLRequest::AsyncCertNetFetcherURLRequest::FindJob(
  592. const RequestParams& params) {
  593. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  594. // The JobSet is kept in sorted order so items can be found using binary
  595. // search.
  596. auto it = std::lower_bound(jobs_.begin(), jobs_.end(), params,
  597. JobToRequestParamsComparator());
  598. if (it != jobs_.end() && !(params < (*it).first->request_params()))
  599. return (*it).first;
  600. return nullptr;
  601. }
  602. std::unique_ptr<Job>
  603. CertNetFetcherURLRequest::AsyncCertNetFetcherURLRequest::RemoveJob(Job* job) {
  604. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  605. auto it = jobs_.find(job);
  606. CHECK(it != jobs_.end());
  607. std::unique_ptr<Job> owned_job = std::move(it->second);
  608. jobs_.erase(it);
  609. return owned_job;
  610. }
  611. namespace {
  612. class CertNetFetcherRequestImpl : public CertNetFetcher::Request {
  613. public:
  614. explicit CertNetFetcherRequestImpl(
  615. scoped_refptr<CertNetFetcherURLRequest::RequestCore> core)
  616. : core_(std::move(core)) {
  617. DCHECK(core_);
  618. }
  619. void WaitForResult(Error* error, std::vector<uint8_t>* bytes) override {
  620. // Should only be called a single time.
  621. DCHECK(core_);
  622. core_->WaitForResult(error, bytes);
  623. core_ = nullptr;
  624. }
  625. ~CertNetFetcherRequestImpl() override {
  626. if (core_)
  627. core_->CancelJob();
  628. }
  629. private:
  630. scoped_refptr<CertNetFetcherURLRequest::RequestCore> core_;
  631. };
  632. } // namespace
  633. CertNetFetcherURLRequest::CertNetFetcherURLRequest()
  634. : task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
  635. CertNetFetcherURLRequest::~CertNetFetcherURLRequest() {
  636. // The fetcher must be shutdown (at which point |context_| will be set to
  637. // null) before destruction.
  638. DCHECK(!context_);
  639. }
  640. void CertNetFetcherURLRequest::SetURLRequestContext(
  641. URLRequestContext* context) {
  642. DCHECK(task_runner_->RunsTasksInCurrentSequence());
  643. context_ = context;
  644. }
  645. // static
  646. base::TimeDelta CertNetFetcherURLRequest::GetDefaultTimeoutForTesting() {
  647. return GetTimeout(CertNetFetcher::DEFAULT);
  648. }
  649. void CertNetFetcherURLRequest::Shutdown() {
  650. DCHECK(task_runner_->RunsTasksInCurrentSequence());
  651. if (impl_) {
  652. impl_->Shutdown();
  653. impl_.reset();
  654. }
  655. context_ = nullptr;
  656. }
  657. std::unique_ptr<CertNetFetcher::Request>
  658. CertNetFetcherURLRequest::FetchCaIssuers(const GURL& url,
  659. int timeout_milliseconds,
  660. int max_response_bytes) {
  661. auto request_params = std::make_unique<RequestParams>();
  662. request_params->url = url;
  663. request_params->http_method = HTTP_METHOD_GET;
  664. request_params->timeout = GetTimeout(timeout_milliseconds);
  665. request_params->max_response_bytes =
  666. GetMaxResponseBytes(max_response_bytes, kMaxResponseSizeInBytesForAia);
  667. return DoFetch(std::move(request_params));
  668. }
  669. std::unique_ptr<CertNetFetcher::Request> CertNetFetcherURLRequest::FetchCrl(
  670. const GURL& url,
  671. int timeout_milliseconds,
  672. int max_response_bytes) {
  673. auto request_params = std::make_unique<RequestParams>();
  674. request_params->url = url;
  675. request_params->http_method = HTTP_METHOD_GET;
  676. request_params->timeout = GetTimeout(timeout_milliseconds);
  677. request_params->max_response_bytes =
  678. GetMaxResponseBytes(max_response_bytes, kMaxResponseSizeInBytesForCrl);
  679. return DoFetch(std::move(request_params));
  680. }
  681. std::unique_ptr<CertNetFetcher::Request> CertNetFetcherURLRequest::FetchOcsp(
  682. const GURL& url,
  683. int timeout_milliseconds,
  684. int max_response_bytes) {
  685. auto request_params = std::make_unique<RequestParams>();
  686. request_params->url = url;
  687. request_params->http_method = HTTP_METHOD_GET;
  688. request_params->timeout = GetTimeout(timeout_milliseconds);
  689. request_params->max_response_bytes =
  690. GetMaxResponseBytes(max_response_bytes, kMaxResponseSizeInBytesForAia);
  691. return DoFetch(std::move(request_params));
  692. }
  693. void CertNetFetcherURLRequest::DoFetchOnNetworkSequence(
  694. std::unique_ptr<RequestParams> request_params,
  695. scoped_refptr<RequestCore> request) {
  696. DCHECK(task_runner_->RunsTasksInCurrentSequence());
  697. if (!context_) {
  698. // The fetcher might have been shutdown between when this task was posted
  699. // and when it is running. In this case, signal the request and do not
  700. // start a network request.
  701. request->SignalImmediateError();
  702. return;
  703. }
  704. if (!impl_) {
  705. impl_ = std::make_unique<AsyncCertNetFetcherURLRequest>(context_);
  706. }
  707. impl_->Fetch(std::move(request_params), request);
  708. }
  709. std::unique_ptr<CertNetFetcherURLRequest::Request>
  710. CertNetFetcherURLRequest::DoFetch(
  711. std::unique_ptr<RequestParams> request_params) {
  712. auto request_core = base::MakeRefCounted<RequestCore>(task_runner_);
  713. // If the fetcher has already been shutdown, DoFetchOnNetworkSequence will
  714. // signal the request with an error. However, if the fetcher shuts down
  715. // before DoFetchOnNetworkSequence runs and PostTask still returns true,
  716. // then the request will hang (that is, WaitForResult will not return).
  717. if (!task_runner_->PostTask(
  718. FROM_HERE,
  719. base::BindOnce(&CertNetFetcherURLRequest::DoFetchOnNetworkSequence,
  720. this, std::move(request_params), request_core))) {
  721. request_core->SignalImmediateError();
  722. }
  723. return std::make_unique<CertNetFetcherRequestImpl>(std::move(request_core));
  724. }
  725. } // namespace net