• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "net/url_request/url_request_job.h"
6 
7 #include <utility>
8 
9 #include "base/compiler_specific.h"
10 #include "base/functional/bind.h"
11 #include "base/functional/callback_helpers.h"
12 #include "base/location.h"
13 #include "base/memory/raw_ptr.h"
14 #include "base/metrics/histogram_macros.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/task/single_thread_task_runner.h"
17 #include "base/values.h"
18 #include "net/base/auth.h"
19 #include "net/base/features.h"
20 #include "net/base/io_buffer.h"
21 #include "net/base/load_flags.h"
22 #include "net/base/load_states.h"
23 #include "net/base/net_errors.h"
24 #include "net/base/network_delegate.h"
25 #include "net/base/proxy_server.h"
26 #include "net/base/schemeful_site.h"
27 #include "net/cert/x509_certificate.h"
28 #include "net/cookies/cookie_setting_override.h"
29 #include "net/log/net_log.h"
30 #include "net/log/net_log_capture_mode.h"
31 #include "net/log/net_log_event_type.h"
32 #include "net/log/net_log_with_source.h"
33 #include "net/nqe/network_quality_estimator.h"
34 #include "net/ssl/ssl_private_key.h"
35 #include "net/url_request/redirect_util.h"
36 #include "net/url_request/url_request_context.h"
37 
38 namespace net {
39 
40 namespace {
41 
42 // Callback for TYPE_URL_REQUEST_FILTERS_SET net-internals event.
SourceStreamSetParams(SourceStream * source_stream)43 base::Value::Dict SourceStreamSetParams(SourceStream* source_stream) {
44   base::Value::Dict event_params;
45   event_params.Set("filters", source_stream->Description());
46   return event_params;
47 }
48 
49 }  // namespace
50 
51 // Each SourceStreams own the previous SourceStream in the chain, but the
52 // ultimate source is URLRequestJob, which has other ownership semantics, so
53 // this class is a proxy for URLRequestJob that is owned by the first stream
54 // (in dataflow order).
55 class URLRequestJob::URLRequestJobSourceStream : public SourceStream {
56  public:
URLRequestJobSourceStream(URLRequestJob * job)57   explicit URLRequestJobSourceStream(URLRequestJob* job)
58       : SourceStream(SourceStream::TYPE_NONE), job_(job) {
59     DCHECK(job_);
60   }
61 
62   URLRequestJobSourceStream(const URLRequestJobSourceStream&) = delete;
63   URLRequestJobSourceStream& operator=(const URLRequestJobSourceStream&) =
64       delete;
65 
66   ~URLRequestJobSourceStream() override = default;
67 
68   // SourceStream implementation:
Read(IOBuffer * dest_buffer,int buffer_size,CompletionOnceCallback callback)69   int Read(IOBuffer* dest_buffer,
70            int buffer_size,
71            CompletionOnceCallback callback) override {
72     DCHECK(job_);
73     return job_->ReadRawDataHelper(dest_buffer, buffer_size,
74                                    std::move(callback));
75   }
76 
Description() const77   std::string Description() const override { return std::string(); }
78 
MayHaveMoreBytes() const79   bool MayHaveMoreBytes() const override { return true; }
80 
81  private:
82   // It is safe to keep a raw pointer because |job_| owns the last stream which
83   // indirectly owns |this|. Therefore, |job_| will not be destroyed when |this|
84   // is alive.
85   const raw_ptr<URLRequestJob> job_;
86 };
87 
URLRequestJob(URLRequest * request)88 URLRequestJob::URLRequestJob(URLRequest* request)
89     : request_(request),
90       request_initiator_site_(request->initiator().has_value()
91                                   ? absl::make_optional(net::SchemefulSite(
92                                         request->initiator().value()))
93                                   : absl::nullopt) {}
94 
95 URLRequestJob::~URLRequestJob() = default;
96 
SetUpload(UploadDataStream * upload)97 void URLRequestJob::SetUpload(UploadDataStream* upload) {
98 }
99 
SetExtraRequestHeaders(const HttpRequestHeaders & headers)100 void URLRequestJob::SetExtraRequestHeaders(const HttpRequestHeaders& headers) {
101 }
102 
SetPriority(RequestPriority priority)103 void URLRequestJob::SetPriority(RequestPriority priority) {
104 }
105 
Kill()106 void URLRequestJob::Kill() {
107   weak_factory_.InvalidateWeakPtrs();
108   // Make sure the URLRequest is notified that the job is done.  This assumes
109   // that the URLRequest took care of setting its error status before calling
110   // Kill().
111   // TODO(mmenke):  The URLRequest is currently deleted before this method
112   // invokes its async callback whenever this is called by the URLRequest.
113   // Try to simplify how cancellation works.
114   NotifyCanceled();
115 }
116 
117 // This method passes reads down the filter chain, where they eventually end up
118 // at URLRequestJobSourceStream::Read, which calls back into
119 // URLRequestJob::ReadRawData.
Read(IOBuffer * buf,int buf_size)120 int URLRequestJob::Read(IOBuffer* buf, int buf_size) {
121   DCHECK(buf);
122 
123   pending_read_buffer_ = buf;
124   int result = source_stream_->Read(
125       buf, buf_size,
126       base::BindOnce(&URLRequestJob::SourceStreamReadComplete,
127                      weak_factory_.GetWeakPtr(), false));
128   if (result == ERR_IO_PENDING)
129     return ERR_IO_PENDING;
130 
131   SourceStreamReadComplete(true, result);
132   return result;
133 }
134 
GetTotalReceivedBytes() const135 int64_t URLRequestJob::GetTotalReceivedBytes() const {
136   return 0;
137 }
138 
GetTotalSentBytes() const139 int64_t URLRequestJob::GetTotalSentBytes() const {
140   return 0;
141 }
142 
GetLoadState() const143 LoadState URLRequestJob::GetLoadState() const {
144   return LOAD_STATE_IDLE;
145 }
146 
GetCharset(std::string * charset)147 bool URLRequestJob::GetCharset(std::string* charset) {
148   return false;
149 }
150 
GetResponseInfo(HttpResponseInfo * info)151 void URLRequestJob::GetResponseInfo(HttpResponseInfo* info) {
152 }
153 
GetLoadTimingInfo(LoadTimingInfo * load_timing_info) const154 void URLRequestJob::GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const {
155   // Only certain request types return more than just request start times.
156 }
157 
GetTransactionRemoteEndpoint(IPEndPoint * endpoint) const158 bool URLRequestJob::GetTransactionRemoteEndpoint(IPEndPoint* endpoint) const {
159   return false;
160 }
161 
PopulateNetErrorDetails(NetErrorDetails * details) const162 void URLRequestJob::PopulateNetErrorDetails(NetErrorDetails* details) const {
163   return;
164 }
165 
IsRedirectResponse(GURL * location,int * http_status_code,bool * insecure_scheme_was_upgraded)166 bool URLRequestJob::IsRedirectResponse(GURL* location,
167                                        int* http_status_code,
168                                        bool* insecure_scheme_was_upgraded) {
169   // For non-HTTP jobs, headers will be null.
170   HttpResponseHeaders* headers = request_->response_headers();
171   if (!headers)
172     return false;
173 
174   std::string value;
175   if (!headers->IsRedirect(&value))
176     return false;
177   *insecure_scheme_was_upgraded = false;
178   *location = request_->url().Resolve(value);
179   // If this a redirect to HTTP of a request that had the
180   // 'upgrade-insecure-requests' policy set, upgrade it to HTTPS.
181   if (request_->upgrade_if_insecure()) {
182     if (location->SchemeIs("http")) {
183       *insecure_scheme_was_upgraded = true;
184       GURL::Replacements replacements;
185       replacements.SetSchemeStr("https");
186       *location = location->ReplaceComponents(replacements);
187     }
188   }
189   *http_status_code = headers->response_code();
190   return true;
191 }
192 
CopyFragmentOnRedirect(const GURL & location) const193 bool URLRequestJob::CopyFragmentOnRedirect(const GURL& location) const {
194   return true;
195 }
196 
IsSafeRedirect(const GURL & location)197 bool URLRequestJob::IsSafeRedirect(const GURL& location) {
198   return true;
199 }
200 
NeedsAuth()201 bool URLRequestJob::NeedsAuth() {
202   return false;
203 }
204 
GetAuthChallengeInfo()205 std::unique_ptr<AuthChallengeInfo> URLRequestJob::GetAuthChallengeInfo() {
206   // This will only be called if NeedsAuth() returns true, in which
207   // case the derived class should implement this!
208   NOTREACHED();
209   return nullptr;
210 }
211 
SetAuth(const AuthCredentials & credentials)212 void URLRequestJob::SetAuth(const AuthCredentials& credentials) {
213   // This will only be called if NeedsAuth() returns true, in which
214   // case the derived class should implement this!
215   NOTREACHED();
216 }
217 
CancelAuth()218 void URLRequestJob::CancelAuth() {
219   // This will only be called if NeedsAuth() returns true, in which
220   // case the derived class should implement this!
221   NOTREACHED();
222 }
223 
ContinueWithCertificate(scoped_refptr<X509Certificate> client_cert,scoped_refptr<SSLPrivateKey> client_private_key)224 void URLRequestJob::ContinueWithCertificate(
225     scoped_refptr<X509Certificate> client_cert,
226     scoped_refptr<SSLPrivateKey> client_private_key) {
227   // The derived class should implement this!
228   NOTREACHED();
229 }
230 
ContinueDespiteLastError()231 void URLRequestJob::ContinueDespiteLastError() {
232   // Implementations should know how to recover from errors they generate.
233   // If this code was reached, we are trying to recover from an error that
234   // we don't know how to recover from.
235   NOTREACHED();
236 }
237 
FollowDeferredRedirect(const absl::optional<std::vector<std::string>> & removed_headers,const absl::optional<net::HttpRequestHeaders> & modified_headers)238 void URLRequestJob::FollowDeferredRedirect(
239     const absl::optional<std::vector<std::string>>& removed_headers,
240     const absl::optional<net::HttpRequestHeaders>& modified_headers) {
241   // OnReceivedRedirect must have been called.
242   DCHECK(deferred_redirect_info_);
243 
244   // It is possible that FollowRedirect will delete |this|, so it is not safe to
245   // pass along a reference to |deferred_redirect_info_|.
246   absl::optional<RedirectInfo> redirect_info =
247       std::move(deferred_redirect_info_);
248   FollowRedirect(*redirect_info, removed_headers, modified_headers);
249 }
250 
prefilter_bytes_read() const251 int64_t URLRequestJob::prefilter_bytes_read() const {
252   return prefilter_bytes_read_;
253 }
254 
GetMimeType(std::string * mime_type) const255 bool URLRequestJob::GetMimeType(std::string* mime_type) const {
256   return false;
257 }
258 
GetResponseCode() const259 int URLRequestJob::GetResponseCode() const {
260   HttpResponseHeaders* headers = request_->response_headers();
261   if (!headers)
262     return -1;
263   return headers->response_code();
264 }
265 
GetResponseRemoteEndpoint() const266 IPEndPoint URLRequestJob::GetResponseRemoteEndpoint() const {
267   return IPEndPoint();
268 }
269 
NotifyURLRequestDestroyed()270 void URLRequestJob::NotifyURLRequestDestroyed() {
271 }
272 
GetConnectionAttempts() const273 ConnectionAttempts URLRequestJob::GetConnectionAttempts() const {
274   return {};
275 }
276 
CloseConnectionOnDestruction()277 void URLRequestJob::CloseConnectionOnDestruction() {}
278 
279 namespace {
280 
281 // Assuming |url| has already been stripped for use as a referrer, if
282 // |should_strip_to_origin| is true, this method returns the output of the
283 // "Strip `url` for use as a referrer" algorithm from the Referrer Policy spec
284 // with its "origin-only" flag set to true:
285 // https://w3c.github.io/webappsec-referrer-policy/#strip-url
MaybeStripToOrigin(GURL url,bool should_strip_to_origin)286 GURL MaybeStripToOrigin(GURL url, bool should_strip_to_origin) {
287   if (!should_strip_to_origin)
288     return url;
289 
290   return url.DeprecatedGetOriginAsURL();
291 }
292 
293 }  // namespace
294 
295 // static
ComputeReferrerForPolicy(ReferrerPolicy policy,const GURL & original_referrer,const GURL & destination,bool * same_origin_out_for_metrics)296 GURL URLRequestJob::ComputeReferrerForPolicy(
297     ReferrerPolicy policy,
298     const GURL& original_referrer,
299     const GURL& destination,
300     bool* same_origin_out_for_metrics) {
301   // Here and below, numbered lines are from the Referrer Policy spec's
302   // "Determine request's referrer" algorithm:
303   // https://w3c.github.io/webappsec-referrer-policy/#determine-requests-referrer
304   //
305   // 4. Let referrerURL be the result of stripping referrerSource for use as a
306   // referrer.
307   GURL stripped_referrer = original_referrer.GetAsReferrer();
308 
309   // 5. Let referrerOrigin be the result of stripping referrerSource for use as
310   // a referrer, with the origin-only flag set to true.
311   //
312   // (We use a boolean instead of computing the URL right away in order to avoid
313   // constructing a new GURL when it's not necessary.)
314   bool should_strip_to_origin = false;
315 
316   // 6. If the result of serializing referrerURL is a string whose length is
317   // greater than 4096, set referrerURL to referrerOrigin.
318   if (stripped_referrer.spec().size() > 4096)
319     should_strip_to_origin = true;
320 
321   bool same_origin = url::IsSameOriginWith(original_referrer, destination);
322 
323   if (same_origin_out_for_metrics)
324     *same_origin_out_for_metrics = same_origin;
325 
326   // 7. The user agent MAY alter referrerURL or referrerOrigin at this point to
327   // enforce arbitrary policy considerations in the interests of minimizing data
328   // leakage. For example, the user agent could strip the URL down to an origin,
329   // modify its host, replace it with an empty string, etc.
330   if (base::FeatureList::IsEnabled(
331           features::kCapReferrerToOriginOnCrossOrigin) &&
332       !same_origin) {
333     should_strip_to_origin = true;
334   }
335 
336   bool secure_referrer_but_insecure_destination =
337       original_referrer.SchemeIsCryptographic() &&
338       !destination.SchemeIsCryptographic();
339 
340   switch (policy) {
341     case ReferrerPolicy::CLEAR_ON_TRANSITION_FROM_SECURE_TO_INSECURE:
342       if (secure_referrer_but_insecure_destination)
343         return GURL();
344       return MaybeStripToOrigin(std::move(stripped_referrer),
345                                 should_strip_to_origin);
346 
347     case ReferrerPolicy::REDUCE_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN:
348       if (secure_referrer_but_insecure_destination)
349         return GURL();
350       if (!same_origin)
351         should_strip_to_origin = true;
352       return MaybeStripToOrigin(std::move(stripped_referrer),
353                                 should_strip_to_origin);
354 
355     case ReferrerPolicy::ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN:
356       if (!same_origin)
357         should_strip_to_origin = true;
358       return MaybeStripToOrigin(std::move(stripped_referrer),
359                                 should_strip_to_origin);
360 
361     case ReferrerPolicy::NEVER_CLEAR:
362       return MaybeStripToOrigin(std::move(stripped_referrer),
363                                 should_strip_to_origin);
364 
365     case ReferrerPolicy::ORIGIN:
366       should_strip_to_origin = true;
367       return MaybeStripToOrigin(std::move(stripped_referrer),
368                                 should_strip_to_origin);
369 
370     case ReferrerPolicy::CLEAR_ON_TRANSITION_CROSS_ORIGIN:
371       if (!same_origin)
372         return GURL();
373       return MaybeStripToOrigin(std::move(stripped_referrer),
374                                 should_strip_to_origin);
375 
376     case ReferrerPolicy::ORIGIN_CLEAR_ON_TRANSITION_FROM_SECURE_TO_INSECURE:
377       if (secure_referrer_but_insecure_destination)
378         return GURL();
379       should_strip_to_origin = true;
380       return MaybeStripToOrigin(std::move(stripped_referrer),
381                                 should_strip_to_origin);
382 
383     case ReferrerPolicy::NO_REFERRER:
384       return GURL();
385   }
386 
387   NOTREACHED();
388   return GURL();
389 }
390 
NotifyConnected(const TransportInfo & info,CompletionOnceCallback callback)391 int URLRequestJob::NotifyConnected(const TransportInfo& info,
392                                    CompletionOnceCallback callback) {
393   return request_->NotifyConnected(info, std::move(callback));
394 }
395 
NotifyCertificateRequested(SSLCertRequestInfo * cert_request_info)396 void URLRequestJob::NotifyCertificateRequested(
397     SSLCertRequestInfo* cert_request_info) {
398   request_->NotifyCertificateRequested(cert_request_info);
399 }
400 
NotifySSLCertificateError(int net_error,const SSLInfo & ssl_info,bool fatal)401 void URLRequestJob::NotifySSLCertificateError(int net_error,
402                                               const SSLInfo& ssl_info,
403                                               bool fatal) {
404   request_->NotifySSLCertificateError(net_error, ssl_info, fatal);
405 }
406 
CanSetCookie(const net::CanonicalCookie & cookie,CookieOptions * options) const407 bool URLRequestJob::CanSetCookie(const net::CanonicalCookie& cookie,
408                                  CookieOptions* options) const {
409   return request_->CanSetCookie(cookie, options);
410 }
411 
NotifyHeadersComplete()412 void URLRequestJob::NotifyHeadersComplete() {
413   if (has_handled_response_)
414     return;
415 
416   // Initialize to the current time, and let the subclass optionally override
417   // the time stamps if it has that information.  The default request_time is
418   // set by URLRequest before it calls our Start method.
419   request_->response_info_.response_time = base::Time::Now();
420   GetResponseInfo(&request_->response_info_);
421 
422   request_->OnHeadersComplete();
423 
424   GURL new_location;
425   int http_status_code;
426   bool insecure_scheme_was_upgraded;
427 
428   if (IsRedirectResponse(&new_location, &http_status_code,
429                          &insecure_scheme_was_upgraded)) {
430     // Redirect response bodies are not read. Notify the transaction
431     // so it does not treat being stopped as an error.
432     DoneReadingRedirectResponse();
433 
434     // Invalid redirect targets are failed early before
435     // NotifyReceivedRedirect. This means the delegate can assume that, if it
436     // accepts the redirect, future calls to OnResponseStarted correspond to
437     // |redirect_info.new_url|.
438     int redirect_check_result = CanFollowRedirect(new_location);
439     if (redirect_check_result != OK) {
440       OnDone(redirect_check_result, true /* notify_done */);
441       return;
442     }
443 
444     // When notifying the URLRequest::Delegate, it can destroy the request,
445     // which will destroy |this|.  After calling to the URLRequest::Delegate,
446     // pointer must be checked to see if |this| still exists, and if not, the
447     // code must return immediately.
448     base::WeakPtr<URLRequestJob> weak_this(weak_factory_.GetWeakPtr());
449 
450     RedirectInfo redirect_info = RedirectInfo::ComputeRedirectInfo(
451         request_->method(), request_->url(), request_->site_for_cookies(),
452         request_->first_party_url_policy(), request_->referrer_policy(),
453         request_->referrer(), http_status_code, new_location,
454         net::RedirectUtil::GetReferrerPolicyHeader(
455             request_->response_headers()),
456         insecure_scheme_was_upgraded, CopyFragmentOnRedirect(new_location));
457     bool defer_redirect = false;
458     request_->NotifyReceivedRedirect(redirect_info, &defer_redirect);
459 
460     // Ensure that the request wasn't detached, destroyed, or canceled in
461     // NotifyReceivedRedirect.
462     if (!weak_this || request_->failed())
463       return;
464 
465     if (defer_redirect) {
466       deferred_redirect_info_ = std::move(redirect_info);
467     } else {
468       FollowRedirect(redirect_info, absl::nullopt, /*  removed_headers */
469                      absl::nullopt /* modified_headers */);
470     }
471     return;
472   }
473 
474   if (NeedsAuth()) {
475     std::unique_ptr<AuthChallengeInfo> auth_info = GetAuthChallengeInfo();
476     // Need to check for a NULL auth_info because the server may have failed
477     // to send a challenge with the 401 response.
478     if (auth_info) {
479       request_->NotifyAuthRequired(std::move(auth_info));
480       // Wait for SetAuth or CancelAuth to be called.
481       return;
482     }
483   }
484 
485   NotifyFinalHeadersReceived();
486   // |this| may be destroyed at this point.
487 }
488 
NotifyFinalHeadersReceived()489 void URLRequestJob::NotifyFinalHeadersReceived() {
490   DCHECK(!NeedsAuth() || !GetAuthChallengeInfo());
491 
492   if (has_handled_response_)
493     return;
494 
495   // While the request's status is normally updated in NotifyHeadersComplete(),
496   // URLRequestHttpJob::CancelAuth() posts a task to invoke this method
497   // directly, which bypasses that logic.
498   if (request_->status() == ERR_IO_PENDING)
499     request_->set_status(OK);
500 
501   has_handled_response_ = true;
502   if (request_->status() == OK) {
503     DCHECK(!source_stream_);
504     source_stream_ = SetUpSourceStream();
505 
506     if (!source_stream_) {
507       OnDone(ERR_CONTENT_DECODING_INIT_FAILED, true /* notify_done */);
508       return;
509     }
510     if (source_stream_->type() == SourceStream::TYPE_NONE) {
511       // If the subclass didn't set |expected_content_size|, and there are
512       // headers, and the response body is not compressed, try to get the
513       // expected content size from the headers.
514       if (expected_content_size_ == -1 && request_->response_headers()) {
515         // This sets |expected_content_size_| to its previous value of -1 if
516         // there's no Content-Length header.
517         expected_content_size_ =
518             request_->response_headers()->GetContentLength();
519       }
520     } else {
521       request_->net_log().AddEvent(
522           NetLogEventType::URL_REQUEST_FILTERS_SET,
523           [&] { return SourceStreamSetParams(source_stream_.get()); });
524     }
525   }
526 
527   request_->NotifyResponseStarted(OK);
528   // |this| may be destroyed at this point.
529 }
530 
ConvertResultToError(int result,Error * error,int * count)531 void URLRequestJob::ConvertResultToError(int result, Error* error, int* count) {
532   if (result >= 0) {
533     *error = OK;
534     *count = result;
535   } else {
536     *error = static_cast<Error>(result);
537     *count = 0;
538   }
539 }
540 
ReadRawDataComplete(int result)541 void URLRequestJob::ReadRawDataComplete(int result) {
542   DCHECK_EQ(ERR_IO_PENDING, request_->status());
543   DCHECK_NE(ERR_IO_PENDING, result);
544 
545   // The headers should be complete before reads complete
546   DCHECK(has_handled_response_);
547 
548   GatherRawReadStats(result);
549 
550   // Notify SourceStream.
551   DCHECK(!read_raw_callback_.is_null());
552 
553   std::move(read_raw_callback_).Run(result);
554   // |this| may be destroyed at this point.
555 }
556 
NotifyStartError(int net_error)557 void URLRequestJob::NotifyStartError(int net_error) {
558   DCHECK(!has_handled_response_);
559   DCHECK_EQ(ERR_IO_PENDING, request_->status());
560 
561   has_handled_response_ = true;
562   // There may be relevant information in the response info even in the
563   // error case.
564   GetResponseInfo(&request_->response_info_);
565 
566   request_->NotifyResponseStarted(net_error);
567   // |this| may have been deleted here.
568 }
569 
OnDone(int net_error,bool notify_done)570 void URLRequestJob::OnDone(int net_error, bool notify_done) {
571   DCHECK_NE(ERR_IO_PENDING, net_error);
572   DCHECK(!done_) << "Job sending done notification twice";
573   if (done_)
574     return;
575   done_ = true;
576 
577   // Unless there was an error, we should have at least tried to handle
578   // the response before getting here.
579   DCHECK(has_handled_response_ || net_error != OK);
580 
581   request_->set_is_pending(false);
582   // With async IO, it's quite possible to have a few outstanding
583   // requests.  We could receive a request to Cancel, followed shortly
584   // by a successful IO.  For tracking the status(), once there is
585   // an error, we do not change the status back to success.  To
586   // enforce this, only set the status if the job is so far
587   // successful.
588   if (!request_->failed()) {
589     if (net_error != net::OK && net_error != ERR_ABORTED) {
590       request_->net_log().AddEventWithNetErrorCode(NetLogEventType::FAILED,
591                                                    net_error);
592     }
593     request_->set_status(net_error);
594   }
595 
596   if (notify_done) {
597     // Complete this notification later.  This prevents us from re-entering the
598     // delegate if we're done because of a synchronous call.
599     base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
600         FROM_HERE,
601         base::BindOnce(&URLRequestJob::NotifyDone, weak_factory_.GetWeakPtr()));
602   }
603 }
604 
NotifyDone()605 void URLRequestJob::NotifyDone() {
606   // Check if we should notify the URLRequest that we're done because of an
607   // error.
608   if (request_->failed()) {
609     // We report the error differently depending on whether we've called
610     // OnResponseStarted yet.
611     if (has_handled_response_) {
612       // We signal the error by calling OnReadComplete with a bytes_read of -1.
613       request_->NotifyReadCompleted(-1);
614     } else {
615       has_handled_response_ = true;
616       // Error code doesn't actually matter here, since the status has already
617       // been updated.
618       request_->NotifyResponseStarted(request_->status());
619     }
620   }
621 }
622 
NotifyCanceled()623 void URLRequestJob::NotifyCanceled() {
624   if (!done_)
625     OnDone(ERR_ABORTED, true /* notify_done */);
626 }
627 
OnCallToDelegate(NetLogEventType type)628 void URLRequestJob::OnCallToDelegate(NetLogEventType type) {
629   request_->OnCallToDelegate(type);
630 }
631 
OnCallToDelegateComplete()632 void URLRequestJob::OnCallToDelegateComplete() {
633   request_->OnCallToDelegateComplete();
634 }
635 
ReadRawData(IOBuffer * buf,int buf_size)636 int URLRequestJob::ReadRawData(IOBuffer* buf, int buf_size) {
637   return 0;
638 }
639 
DoneReading()640 void URLRequestJob::DoneReading() {
641   // Do nothing.
642 }
643 
DoneReadingRedirectResponse()644 void URLRequestJob::DoneReadingRedirectResponse() {
645 }
646 
SetUpSourceStream()647 std::unique_ptr<SourceStream> URLRequestJob::SetUpSourceStream() {
648   return std::make_unique<URLRequestJobSourceStream>(this);
649 }
650 
SetProxyServer(const ProxyServer & proxy_server)651 void URLRequestJob::SetProxyServer(const ProxyServer& proxy_server) {
652   request_->proxy_server_ = proxy_server;
653 }
654 
SourceStreamReadComplete(bool synchronous,int result)655 void URLRequestJob::SourceStreamReadComplete(bool synchronous, int result) {
656   DCHECK_NE(ERR_IO_PENDING, result);
657 
658   if (result > 0 && request()->net_log().IsCapturing()) {
659     request()->net_log().AddByteTransferEvent(
660         NetLogEventType::URL_REQUEST_JOB_FILTERED_BYTES_READ, result,
661         pending_read_buffer_->data());
662   }
663   pending_read_buffer_ = nullptr;
664 
665   if (result < 0) {
666     OnDone(result, !synchronous /* notify_done */);
667     return;
668   }
669 
670   if (result > 0) {
671     postfilter_bytes_read_ += result;
672   } else {
673     DCHECK_EQ(0, result);
674     DoneReading();
675     // In the synchronous case, the caller will notify the URLRequest of
676     // completion. In the async case, the NotifyReadCompleted call will.
677     // TODO(mmenke): Can this be combined with the error case?
678     OnDone(OK, false /* notify_done */);
679   }
680 
681   if (!synchronous)
682     request_->NotifyReadCompleted(result);
683 }
684 
ReadRawDataHelper(IOBuffer * buf,int buf_size,CompletionOnceCallback callback)685 int URLRequestJob::ReadRawDataHelper(IOBuffer* buf,
686                                      int buf_size,
687                                      CompletionOnceCallback callback) {
688   DCHECK(!raw_read_buffer_);
689 
690   // Keep a pointer to the read buffer, so URLRequestJob::GatherRawReadStats()
691   // has access to it to log stats.
692   raw_read_buffer_ = buf;
693 
694   // TODO(xunjieli): Make ReadRawData take in a callback rather than requiring
695   // subclass to call ReadRawDataComplete upon asynchronous completion.
696   int result = ReadRawData(buf, buf_size);
697 
698   if (result != ERR_IO_PENDING) {
699     // If the read completes synchronously, either success or failure, invoke
700     // GatherRawReadStats so we can account for the completed read.
701     GatherRawReadStats(result);
702   } else {
703     read_raw_callback_ = std::move(callback);
704   }
705   return result;
706 }
707 
CanFollowRedirect(const GURL & new_url)708 int URLRequestJob::CanFollowRedirect(const GURL& new_url) {
709   if (request_->redirect_limit_ <= 0) {
710     DVLOG(1) << "disallowing redirect: exceeds limit";
711     return ERR_TOO_MANY_REDIRECTS;
712   }
713 
714   if (!new_url.is_valid())
715     return ERR_INVALID_REDIRECT;
716 
717   if (!IsSafeRedirect(new_url)) {
718     DVLOG(1) << "disallowing redirect: unsafe protocol";
719     return ERR_UNSAFE_REDIRECT;
720   }
721 
722   return OK;
723 }
724 
FollowRedirect(const RedirectInfo & redirect_info,const absl::optional<std::vector<std::string>> & removed_headers,const absl::optional<net::HttpRequestHeaders> & modified_headers)725 void URLRequestJob::FollowRedirect(
726     const RedirectInfo& redirect_info,
727     const absl::optional<std::vector<std::string>>& removed_headers,
728     const absl::optional<net::HttpRequestHeaders>& modified_headers) {
729   request_->Redirect(redirect_info, removed_headers, modified_headers);
730 }
731 
GatherRawReadStats(int bytes_read)732 void URLRequestJob::GatherRawReadStats(int bytes_read) {
733   DCHECK(raw_read_buffer_ || bytes_read == 0);
734   DCHECK_NE(ERR_IO_PENDING, bytes_read);
735 
736   if (bytes_read > 0) {
737     // If there is a filter, bytes will be logged after the filter is applied.
738     if (source_stream_->type() != SourceStream::TYPE_NONE &&
739         request()->net_log().IsCapturing()) {
740       request()->net_log().AddByteTransferEvent(
741           NetLogEventType::URL_REQUEST_JOB_BYTES_READ, bytes_read,
742           raw_read_buffer_->data());
743     }
744     RecordBytesRead(bytes_read);
745   }
746   raw_read_buffer_ = nullptr;
747 }
748 
RecordBytesRead(int bytes_read)749 void URLRequestJob::RecordBytesRead(int bytes_read) {
750   DCHECK_GT(bytes_read, 0);
751   prefilter_bytes_read_ += base::checked_cast<size_t>(bytes_read);
752 
753   // On first read, notify NetworkQualityEstimator that response headers have
754   // been received.
755   // TODO(tbansal): Move this to url_request_http_job.cc. This may catch
756   // Service Worker jobs twice.
757   // If prefilter_bytes_read_ is equal to bytes_read, it indicates this is the
758   // first raw read of the response body. This is used as the signal that
759   // response headers have been received.
760   if (request_->context()->network_quality_estimator()) {
761     if (prefilter_bytes_read() == bytes_read) {
762       request_->context()->network_quality_estimator()->NotifyHeadersReceived(
763           *request_, prefilter_bytes_read());
764     } else {
765       request_->context()->network_quality_estimator()->NotifyBytesRead(
766           *request_, prefilter_bytes_read());
767     }
768   }
769 
770   DVLOG(2) << __FUNCTION__ << "() "
771            << "\"" << request_->url().spec() << "\""
772            << " pre bytes read = " << bytes_read
773            << " pre total = " << prefilter_bytes_read()
774            << " post total = " << postfilter_bytes_read();
775 }
776 
777 }  // namespace net
778