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_http_job.h"
6
7 #include <algorithm>
8 #include <iterator>
9 #include <memory>
10 #include <utility>
11 #include <vector>
12
13 #include "base/base_switches.h"
14 #include "base/check_op.h"
15 #include "base/command_line.h"
16 #include "base/compiler_specific.h"
17 #include "base/containers/adapters.h"
18 #include "base/file_version_info.h"
19 #include "base/functional/bind.h"
20 #include "base/functional/callback_helpers.h"
21 #include "base/location.h"
22 #include "base/memory/ptr_util.h"
23 #include "base/metrics/field_trial.h"
24 #include "base/metrics/histogram_functions.h"
25 #include "base/metrics/histogram_macros.h"
26 #include "base/numerics/safe_conversions.h"
27 #include "base/rand_util.h"
28 #include "base/strings/string_util.h"
29 #include "base/strings/stringprintf.h"
30 #include "base/task/single_thread_task_runner.h"
31 #include "base/time/time.h"
32 #include "base/types/optional_util.h"
33 #include "base/values.h"
34 #include "build/build_config.h"
35 #include "net/base/features.h"
36 #include "net/base/host_port_pair.h"
37 #include "net/base/http_user_agent_settings.h"
38 #include "net/base/load_flags.h"
39 #include "net/base/net_errors.h"
40 #include "net/base/network_anonymization_key.h"
41 #include "net/base/network_delegate.h"
42 #include "net/base/network_isolation_key.h"
43 #include "net/base/privacy_mode.h"
44 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
45 #include "net/base/trace_constants.h"
46 #include "net/base/tracing.h"
47 #include "net/base/url_util.h"
48 #include "net/cert/cert_status_flags.h"
49 #include "net/cert/ct_policy_status.h"
50 #include "net/cert/known_roots.h"
51 #include "net/cookies/canonical_cookie.h"
52 #include "net/cookies/cookie_access_delegate.h"
53 #include "net/cookies/cookie_constants.h"
54 #include "net/cookies/cookie_store.h"
55 #include "net/cookies/cookie_util.h"
56 #include "net/cookies/parsed_cookie.h"
57 #include "net/filter/brotli_source_stream.h"
58 #include "net/filter/filter_source_stream.h"
59 #include "net/filter/gzip_source_stream.h"
60 #include "net/filter/source_stream.h"
61 #include "net/first_party_sets/first_party_set_metadata.h"
62 #include "net/first_party_sets/same_party_context.h"
63 #include "net/http/http_content_disposition.h"
64 #include "net/http/http_log_util.h"
65 #include "net/http/http_network_session.h"
66 #include "net/http/http_request_headers.h"
67 #include "net/http/http_response_headers.h"
68 #include "net/http/http_response_info.h"
69 #include "net/http/http_status_code.h"
70 #include "net/http/http_transaction.h"
71 #include "net/http/http_transaction_factory.h"
72 #include "net/http/http_util.h"
73 #include "net/http/transport_security_state.h"
74 #include "net/log/net_log.h"
75 #include "net/log/net_log_event_type.h"
76 #include "net/log/net_log_values.h"
77 #include "net/log/net_log_with_source.h"
78 #include "net/nqe/network_quality_estimator.h"
79 #include "net/proxy_resolution/proxy_info.h"
80 #include "net/proxy_resolution/proxy_resolution_service.h"
81 #include "net/proxy_resolution/proxy_retry_info.h"
82 #include "net/ssl/ssl_cert_request_info.h"
83 #include "net/ssl/ssl_config_service.h"
84 #include "net/ssl/ssl_connection_status_flags.h"
85 #include "net/url_request/redirect_util.h"
86 #include "net/url_request/url_request.h"
87 #include "net/url_request/url_request_context.h"
88 #include "net/url_request/url_request_error_job.h"
89 #include "net/url_request/url_request_job_factory.h"
90 #include "net/url_request/url_request_redirect_job.h"
91 #include "net/url_request/url_request_throttler_manager.h"
92 #include "net/url_request/websocket_handshake_userdata_key.h"
93 #include "third_party/abseil-cpp/absl/types/optional.h"
94 #include "url/gurl.h"
95 #include "url/origin.h"
96 #include "url/url_constants.h"
97
98 #if BUILDFLAG(IS_ANDROID)
99 #include "net/android/network_library.h"
100 #endif
101
102 namespace {
103
CookieInclusionStatusNetLogParams(const std::string & operation,const std::string & cookie_name,const std::string & cookie_domain,const std::string & cookie_path,const net::CookieInclusionStatus & status,net::NetLogCaptureMode capture_mode)104 base::Value::Dict CookieInclusionStatusNetLogParams(
105 const std::string& operation,
106 const std::string& cookie_name,
107 const std::string& cookie_domain,
108 const std::string& cookie_path,
109 const net::CookieInclusionStatus& status,
110 net::NetLogCaptureMode capture_mode) {
111 base::Value::Dict dict;
112 dict.Set("operation", operation);
113 dict.Set("status", status.GetDebugString());
114 if (net::NetLogCaptureIncludesSensitive(capture_mode)) {
115 if (!cookie_name.empty())
116 dict.Set("name", cookie_name);
117 if (!cookie_domain.empty())
118 dict.Set("domain", cookie_domain);
119 if (!cookie_path.empty())
120 dict.Set("path", cookie_path);
121 }
122 return dict;
123 }
124
125 // Records details about the most-specific trust anchor in |spki_hashes|,
126 // which is expected to be ordered with the leaf cert first and the root cert
127 // last. This complements the per-verification histogram
128 // Net.Certificate.TrustAnchor.Verify
LogTrustAnchor(const net::HashValueVector & spki_hashes)129 void LogTrustAnchor(const net::HashValueVector& spki_hashes) {
130 // Don't record metrics if there are no hashes; this is true if the HTTP
131 // load did not come from an active network connection, such as the disk
132 // cache or a synthesized response.
133 if (spki_hashes.empty())
134 return;
135
136 int32_t id = 0;
137 for (const auto& hash : spki_hashes) {
138 id = net::GetNetTrustAnchorHistogramIdForSPKI(hash);
139 if (id != 0)
140 break;
141 }
142 base::UmaHistogramSparse("Net.Certificate.TrustAnchor.Request", id);
143 }
144
CreateCookieOptions(net::CookieOptions::SameSiteCookieContext same_site_context,const net::SamePartyContext & same_party_context,const net::IsolationInfo & isolation_info,bool is_in_nontrivial_first_party_set)145 net::CookieOptions CreateCookieOptions(
146 net::CookieOptions::SameSiteCookieContext same_site_context,
147 const net::SamePartyContext& same_party_context,
148 const net::IsolationInfo& isolation_info,
149 bool is_in_nontrivial_first_party_set) {
150 net::CookieOptions options;
151 options.set_return_excluded_cookies();
152 options.set_include_httponly();
153 options.set_same_site_cookie_context(same_site_context);
154 options.set_same_party_context(same_party_context);
155 if (isolation_info.party_context().has_value()) {
156 // Count the top-frame site since it's not in the party_context.
157 options.set_full_party_context_size(isolation_info.party_context()->size() +
158 1);
159 }
160 options.set_is_in_nontrivial_first_party_set(
161 is_in_nontrivial_first_party_set);
162 return options;
163 }
164
IsTLS13OverTCP(const net::HttpResponseInfo & response_info)165 bool IsTLS13OverTCP(const net::HttpResponseInfo& response_info) {
166 // Although IETF QUIC also uses TLS 1.3, our QUIC connections report
167 // SSL_CONNECTION_VERSION_QUIC.
168 return net::SSLConnectionStatusToVersion(
169 response_info.ssl_info.connection_status) ==
170 net::SSL_CONNECTION_VERSION_TLS1_3;
171 }
172
UpgradeSchemeToCryptographic(const GURL & insecure_url)173 GURL UpgradeSchemeToCryptographic(const GURL& insecure_url) {
174 DCHECK(!insecure_url.SchemeIsCryptographic());
175 DCHECK(insecure_url.SchemeIs(url::kHttpScheme) ||
176 insecure_url.SchemeIs(url::kWsScheme));
177
178 GURL::Replacements replacements;
179 replacements.SetSchemeStr(insecure_url.SchemeIs(url::kHttpScheme)
180 ? url::kHttpsScheme
181 : url::kWssScheme);
182
183 GURL secure_url = insecure_url.ReplaceComponents(replacements);
184 DCHECK(secure_url.SchemeIsCryptographic());
185
186 return secure_url;
187 }
188
189 } // namespace
190
191 namespace net {
192
Create(URLRequest * request)193 std::unique_ptr<URLRequestJob> URLRequestHttpJob::Create(URLRequest* request) {
194 const GURL& url = request->url();
195
196 // URLRequestContext must have been initialized.
197 DCHECK(request->context()->http_transaction_factory());
198 DCHECK(url.SchemeIsHTTPOrHTTPS() || url.SchemeIsWSOrWSS());
199
200 // Check for reasons not to return a URLRequestHttpJob. These don't apply to
201 // https and wss requests.
202 if (!url.SchemeIsCryptographic()) {
203 // Check for HSTS upgrade.
204 TransportSecurityState* hsts =
205 request->context()->transport_security_state();
206 if (hsts && hsts->ShouldUpgradeToSSL(url.host(), request->net_log())) {
207 return std::make_unique<URLRequestRedirectJob>(
208 request, UpgradeSchemeToCryptographic(url),
209 // Use status code 307 to preserve the method, so POST requests work.
210 RedirectUtil::ResponseCode::REDIRECT_307_TEMPORARY_REDIRECT, "HSTS");
211 }
212
213 #if BUILDFLAG(IS_ANDROID)
214 // Check whether the app allows cleartext traffic to this host, and return
215 // ERR_CLEARTEXT_NOT_PERMITTED if not.
216 if (request->context()->check_cleartext_permitted() &&
217 !android::IsCleartextPermitted(url.host())) {
218 return std::make_unique<URLRequestErrorJob>(request,
219 ERR_CLEARTEXT_NOT_PERMITTED);
220 }
221 #endif
222 }
223
224 return base::WrapUnique<URLRequestJob>(new URLRequestHttpJob(
225 request, request->context()->http_user_agent_settings()));
226 }
227
URLRequestHttpJob(URLRequest * request,const HttpUserAgentSettings * http_user_agent_settings)228 URLRequestHttpJob::URLRequestHttpJob(
229 URLRequest* request,
230 const HttpUserAgentSettings* http_user_agent_settings)
231 : URLRequestJob(request),
232 http_user_agent_settings_(http_user_agent_settings) {
233 URLRequestThrottlerManager* manager = request->context()->throttler_manager();
234 if (manager)
235 throttling_entry_ = manager->RegisterRequestUrl(request->url());
236
237 ResetTimer();
238 }
239
~URLRequestHttpJob()240 URLRequestHttpJob::~URLRequestHttpJob() {
241 CHECK(!awaiting_callback_);
242
243 DoneWithRequest(ABORTED);
244 }
245
SetPriority(RequestPriority priority)246 void URLRequestHttpJob::SetPriority(RequestPriority priority) {
247 priority_ = priority;
248 if (transaction_)
249 transaction_->SetPriority(priority_);
250 }
251
Start()252 void URLRequestHttpJob::Start() {
253 DCHECK(!transaction_.get());
254
255 request_info_.url = request_->url();
256 request_info_.method = request_->method();
257
258 request_info_.network_isolation_key =
259 request_->isolation_info().network_isolation_key();
260 request_info_.network_anonymization_key =
261 request_->isolation_info().network_anonymization_key();
262 request_info_.possibly_top_frame_origin =
263 request_->isolation_info().top_frame_origin();
264 request_info_.is_subframe_document_resource =
265 request_->isolation_info().request_type() ==
266 net::IsolationInfo::RequestType::kSubFrame;
267 request_info_.load_flags = request_->load_flags();
268 request_info_.priority_incremental = request_->priority_incremental();
269 request_info_.secure_dns_policy = request_->secure_dns_policy();
270 request_info_.traffic_annotation =
271 net::MutableNetworkTrafficAnnotationTag(request_->traffic_annotation());
272 request_info_.socket_tag = request_->socket_tag();
273 request_info_.idempotency = request_->GetIdempotency();
274 request_info_.pervasive_payloads_index_for_logging =
275 request_->pervasive_payloads_index_for_logging();
276 request_info_.checksum = request_->expected_response_checksum();
277 #if BUILDFLAG(ENABLE_REPORTING)
278 request_info_.reporting_upload_depth = request_->reporting_upload_depth();
279 #endif
280
281 // Add/remove the Storage Access override enum based on whether the request's
282 // url and initiator are same-site, to prevent cross-site sibling iframes
283 // benefit from each other's storage access API grants.
284 request()->cookie_setting_overrides().PutOrRemove(
285 net::CookieSettingOverride::kStorageAccessGrantEligible,
286 request()->has_storage_access() && request_initiator_site().has_value() &&
287 request_initiator_site().value() ==
288 net::SchemefulSite(request()->url()));
289
290 bool should_add_cookie_header = ShouldAddCookieHeader();
291 UMA_HISTOGRAM_BOOLEAN("Net.HttpJob.CanIncludeCookies",
292 should_add_cookie_header);
293
294 if (!should_add_cookie_header) {
295 OnGotFirstPartySetMetadata(FirstPartySetMetadata());
296 return;
297 }
298 absl::optional<FirstPartySetMetadata> metadata =
299 cookie_util::ComputeFirstPartySetMetadataMaybeAsync(
300 SchemefulSite(request()->url()), request()->isolation_info(),
301 request()->context()->cookie_store()->cookie_access_delegate(),
302 request()->force_ignore_top_frame_party_for_cookies(),
303 base::BindOnce(&URLRequestHttpJob::OnGotFirstPartySetMetadata,
304 weak_factory_.GetWeakPtr()));
305
306 if (metadata.has_value())
307 OnGotFirstPartySetMetadata(std::move(metadata.value()));
308 }
309
OnGotFirstPartySetMetadata(FirstPartySetMetadata first_party_set_metadata)310 void URLRequestHttpJob::OnGotFirstPartySetMetadata(
311 FirstPartySetMetadata first_party_set_metadata) {
312 first_party_set_metadata_ = std::move(first_party_set_metadata);
313
314 if (!request()->network_delegate()) {
315 OnGotFirstPartySetCacheFilterMatchInfo(
316 net::FirstPartySetsCacheFilter::MatchInfo());
317 return;
318 }
319 absl::optional<FirstPartySetsCacheFilter::MatchInfo> match_info =
320 request()
321 ->network_delegate()
322 ->GetFirstPartySetsCacheFilterMatchInfoMaybeAsync(
323 SchemefulSite(request()->url()),
324 base::BindOnce(
325 &URLRequestHttpJob::OnGotFirstPartySetCacheFilterMatchInfo,
326 weak_factory_.GetWeakPtr()));
327
328 if (match_info.has_value())
329 OnGotFirstPartySetCacheFilterMatchInfo(std::move(match_info.value()));
330 }
331
OnGotFirstPartySetCacheFilterMatchInfo(FirstPartySetsCacheFilter::MatchInfo match_info)332 void URLRequestHttpJob::OnGotFirstPartySetCacheFilterMatchInfo(
333 FirstPartySetsCacheFilter::MatchInfo match_info) {
334 request_info_.fps_cache_filter = match_info.clear_at_run_id;
335 request_info_.browser_run_id = match_info.browser_run_id;
336
337 // Privacy mode could still be disabled in SetCookieHeaderAndStart if we are
338 // going to send previously saved cookies.
339 request_info_.privacy_mode = DeterminePrivacyMode();
340 request()->net_log().AddEventWithStringParams(
341 NetLogEventType::COMPUTED_PRIVACY_MODE, "privacy_mode",
342 PrivacyModeToDebugString(request_info_.privacy_mode));
343
344 // Strip Referer from request_info_.extra_headers to prevent, e.g., plugins
345 // from overriding headers that are controlled using other means. Otherwise a
346 // plugin could set a referrer although sending the referrer is inhibited.
347 request_info_.extra_headers.RemoveHeader(HttpRequestHeaders::kReferer);
348
349 // URLRequest::SetReferrer ensures that we do not send username and password
350 // fields in the referrer.
351 GURL referrer(request_->referrer());
352
353 // Our consumer should have made sure that this is a safe referrer (e.g. via
354 // URLRequestJob::ComputeReferrerForPolicy).
355 if (referrer.is_valid()) {
356 std::string referer_value = referrer.spec();
357 request_info_.extra_headers.SetHeader(HttpRequestHeaders::kReferer,
358 referer_value);
359 }
360
361 request_info_.extra_headers.SetHeaderIfMissing(
362 HttpRequestHeaders::kUserAgent,
363 http_user_agent_settings_ ?
364 http_user_agent_settings_->GetUserAgent() : std::string());
365
366 AddExtraHeaders();
367
368 if (ShouldAddCookieHeader()) {
369 // We shouldn't overwrite this if we've already computed the key.
370 DCHECK(!cookie_partition_key_.has_value());
371
372 cookie_partition_key_ = CookiePartitionKey::FromNetworkIsolationKey(
373 request_->isolation_info().network_isolation_key());
374 AddCookieHeaderAndStart();
375 } else {
376 StartTransaction();
377 }
378 }
379
Kill()380 void URLRequestHttpJob::Kill() {
381 weak_factory_.InvalidateWeakPtrs();
382 if (transaction_)
383 DestroyTransaction();
384 URLRequestJob::Kill();
385 }
386
GetConnectionAttempts() const387 ConnectionAttempts URLRequestHttpJob::GetConnectionAttempts() const {
388 if (transaction_)
389 return transaction_->GetConnectionAttempts();
390 return {};
391 }
392
CloseConnectionOnDestruction()393 void URLRequestHttpJob::CloseConnectionOnDestruction() {
394 DCHECK(transaction_);
395 transaction_->CloseConnectionOnDestruction();
396 }
397
NotifyConnectedCallback(const TransportInfo & info,CompletionOnceCallback callback)398 int URLRequestHttpJob::NotifyConnectedCallback(
399 const TransportInfo& info,
400 CompletionOnceCallback callback) {
401 return URLRequestJob::NotifyConnected(info, std::move(callback));
402 }
403
DeterminePrivacyMode() const404 PrivacyMode URLRequestHttpJob::DeterminePrivacyMode() const {
405 if (!request()->allow_credentials()) {
406 // |allow_credentials_| implies LOAD_DO_NOT_SAVE_COOKIES.
407 DCHECK(request_->load_flags() & LOAD_DO_NOT_SAVE_COOKIES);
408
409 // TODO(https://crbug.com/775438): Client certs should always be
410 // affirmatively omitted for these requests.
411 return request()->send_client_certs()
412 ? PRIVACY_MODE_ENABLED
413 : PRIVACY_MODE_ENABLED_WITHOUT_CLIENT_CERTS;
414 }
415
416 // Otherwise, check with the delegate if present, or base it off of
417 // |URLRequest::DefaultCanUseCookies()| if not.
418 // TODO(mmenke): Looks like |URLRequest::DefaultCanUseCookies()| is not too
419 // useful, with the network service - remove it.
420 NetworkDelegate::PrivacySetting privacy_setting =
421 URLRequest::DefaultCanUseCookies()
422 ? NetworkDelegate::PrivacySetting::kStateAllowed
423 : NetworkDelegate::PrivacySetting::kStateDisallowed;
424 if (request_->network_delegate()) {
425 privacy_setting =
426 request()->network_delegate()->ForcePrivacyMode(*request());
427 }
428 switch (privacy_setting) {
429 case NetworkDelegate::PrivacySetting::kStateAllowed:
430 return PRIVACY_MODE_DISABLED;
431 case NetworkDelegate::PrivacySetting::kPartitionedStateAllowedOnly:
432 return PRIVACY_MODE_ENABLED_PARTITIONED_STATE_ALLOWED;
433 case NetworkDelegate::PrivacySetting::kStateDisallowed:
434 return PRIVACY_MODE_ENABLED;
435 }
436 NOTREACHED();
437 return PRIVACY_MODE_ENABLED;
438 }
439
NotifyHeadersComplete()440 void URLRequestHttpJob::NotifyHeadersComplete() {
441 DCHECK(!response_info_);
442 DCHECK_EQ(0, num_cookie_lines_left_);
443 DCHECK(request_->maybe_stored_cookies().empty());
444
445 if (override_response_info_) {
446 DCHECK(!transaction_);
447 response_info_ = override_response_info_.get();
448 } else {
449 response_info_ = transaction_->GetResponseInfo();
450 }
451
452 if (!response_info_->was_cached && throttling_entry_.get())
453 throttling_entry_->UpdateWithResponse(GetResponseCode());
454
455 ProcessStrictTransportSecurityHeader();
456
457 // Clear |set_cookie_access_result_list_| after any processing in case
458 // SaveCookiesAndNotifyHeadersComplete is called again.
459 request_->set_maybe_stored_cookies(std::move(set_cookie_access_result_list_));
460
461 // The HTTP transaction may be restarted several times for the purposes
462 // of sending authorization information. Each time it restarts, we get
463 // notified of the headers completion so that we can update the cookie store.
464 if (transaction_ && transaction_->IsReadyToRestartForAuth()) {
465 // TODO(battre): This breaks the webrequest API for
466 // URLRequestTestHTTP.BasicAuthWithCookies
467 // where OnBeforeStartTransaction -> OnStartTransaction ->
468 // OnBeforeStartTransaction occurs.
469 RestartTransactionWithAuth(AuthCredentials());
470 return;
471 }
472
473 URLRequestJob::NotifyHeadersComplete();
474 }
475
DestroyTransaction()476 void URLRequestHttpJob::DestroyTransaction() {
477 DCHECK(transaction_.get());
478
479 DoneWithRequest(ABORTED);
480
481 total_received_bytes_from_previous_transactions_ +=
482 transaction_->GetTotalReceivedBytes();
483 total_sent_bytes_from_previous_transactions_ +=
484 transaction_->GetTotalSentBytes();
485 response_info_ = nullptr;
486 transaction_.reset();
487 override_response_headers_ = nullptr;
488 receive_headers_end_ = base::TimeTicks();
489 }
490
StartTransaction()491 void URLRequestHttpJob::StartTransaction() {
492 DCHECK(!override_response_info_);
493
494 NetworkDelegate* network_delegate = request()->network_delegate();
495 if (network_delegate) {
496 OnCallToDelegate(
497 NetLogEventType::NETWORK_DELEGATE_BEFORE_START_TRANSACTION);
498 int rv = network_delegate->NotifyBeforeStartTransaction(
499 request_, request_info_.extra_headers,
500 base::BindOnce(&URLRequestHttpJob::NotifyBeforeStartTransactionCallback,
501 weak_factory_.GetWeakPtr()));
502 // If an extension blocks the request, we rely on the callback to
503 // MaybeStartTransactionInternal().
504 if (rv == ERR_IO_PENDING)
505 return;
506 MaybeStartTransactionInternal(rv);
507 return;
508 }
509 StartTransactionInternal();
510 }
511
NotifyBeforeStartTransactionCallback(int result,const absl::optional<HttpRequestHeaders> & headers)512 void URLRequestHttpJob::NotifyBeforeStartTransactionCallback(
513 int result,
514 const absl::optional<HttpRequestHeaders>& headers) {
515 // The request should not have been cancelled or have already completed.
516 DCHECK(!is_done());
517
518 if (headers)
519 request_info_.extra_headers = headers.value();
520 MaybeStartTransactionInternal(result);
521 }
522
MaybeStartTransactionInternal(int result)523 void URLRequestHttpJob::MaybeStartTransactionInternal(int result) {
524 OnCallToDelegateComplete();
525 if (result == OK) {
526 StartTransactionInternal();
527 } else {
528 request_->net_log().AddEventWithStringParams(NetLogEventType::CANCELLED,
529 "source", "delegate");
530 // Don't call back synchronously to the delegate.
531 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
532 FROM_HERE, base::BindOnce(&URLRequestHttpJob::NotifyStartError,
533 weak_factory_.GetWeakPtr(), result));
534 }
535 }
536
StartTransactionInternal()537 void URLRequestHttpJob::StartTransactionInternal() {
538 DCHECK(!override_response_headers_);
539
540 // NOTE: This method assumes that request_info_ is already setup properly.
541
542 // If we already have a transaction, then we should restart the transaction
543 // with auth provided by auth_credentials_.
544
545 int rv;
546
547 // Notify NetworkQualityEstimator.
548 NetworkQualityEstimator* network_quality_estimator =
549 request()->context()->network_quality_estimator();
550 if (network_quality_estimator)
551 network_quality_estimator->NotifyStartTransaction(*request_);
552
553 if (transaction_.get()) {
554 rv = transaction_->RestartWithAuth(
555 auth_credentials_, base::BindOnce(&URLRequestHttpJob::OnStartCompleted,
556 base::Unretained(this)));
557 auth_credentials_ = AuthCredentials();
558 } else {
559 DCHECK(request_->context()->http_transaction_factory());
560
561 rv = request_->context()->http_transaction_factory()->CreateTransaction(
562 priority_, &transaction_);
563
564 if (rv == OK && request_info_.url.SchemeIsWSOrWSS()) {
565 base::SupportsUserData::Data* data =
566 request_->GetUserData(kWebSocketHandshakeUserDataKey);
567 if (data) {
568 transaction_->SetWebSocketHandshakeStreamCreateHelper(
569 static_cast<WebSocketHandshakeStreamBase::CreateHelper*>(data));
570 } else {
571 rv = ERR_DISALLOWED_URL_SCHEME;
572 }
573 }
574
575 if (rv == OK && request_info_.method == "CONNECT") {
576 // CONNECT has different kinds of targets than other methods (RFC 9110,
577 // section 9.3.6), which are incompatible with URLRequest.
578 rv = ERR_METHOD_NOT_SUPPORTED;
579 }
580
581 if (rv == OK) {
582 transaction_->SetConnectedCallback(base::BindRepeating(
583 &URLRequestHttpJob::NotifyConnectedCallback, base::Unretained(this)));
584 transaction_->SetRequestHeadersCallback(request_headers_callback_);
585 transaction_->SetEarlyResponseHeadersCallback(
586 early_response_headers_callback_);
587 transaction_->SetResponseHeadersCallback(response_headers_callback_);
588
589 if (!throttling_entry_.get() ||
590 !throttling_entry_->ShouldRejectRequest(*request_)) {
591 rv = transaction_->Start(
592 &request_info_,
593 base::BindOnce(&URLRequestHttpJob::OnStartCompleted,
594 base::Unretained(this)),
595 request_->net_log());
596 start_time_ = base::TimeTicks::Now();
597 } else {
598 // Special error code for the exponential back-off module.
599 rv = ERR_TEMPORARILY_THROTTLED;
600 }
601 }
602 }
603
604 if (rv == ERR_IO_PENDING)
605 return;
606
607 // The transaction started synchronously, but we need to notify the
608 // URLRequest delegate via the message loop.
609 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
610 FROM_HERE, base::BindOnce(&URLRequestHttpJob::OnStartCompleted,
611 weak_factory_.GetWeakPtr(), rv));
612 }
613
AddExtraHeaders()614 void URLRequestHttpJob::AddExtraHeaders() {
615 request_info_.extra_headers.SetAcceptEncodingIfMissing(
616 request()->url(), request()->accepted_stream_types(),
617 request()->context()->enable_brotli());
618
619 if (http_user_agent_settings_) {
620 // Only add default Accept-Language if the request didn't have it
621 // specified.
622 std::string accept_language =
623 http_user_agent_settings_->GetAcceptLanguage();
624 if (!accept_language.empty()) {
625 request_info_.extra_headers.SetHeaderIfMissing(
626 HttpRequestHeaders::kAcceptLanguage,
627 accept_language);
628 }
629 }
630 }
631
AddCookieHeaderAndStart()632 void URLRequestHttpJob::AddCookieHeaderAndStart() {
633 CookieStore* cookie_store = request_->context()->cookie_store();
634 DCHECK(cookie_store);
635 DCHECK(ShouldAddCookieHeader());
636 bool force_ignore_site_for_cookies =
637 request_->force_ignore_site_for_cookies();
638 if (cookie_store->cookie_access_delegate() &&
639 cookie_store->cookie_access_delegate()->ShouldIgnoreSameSiteRestrictions(
640 request_->url(), request_->site_for_cookies())) {
641 force_ignore_site_for_cookies = true;
642 }
643 bool is_main_frame_navigation =
644 IsolationInfo::RequestType::kMainFrame ==
645 request_->isolation_info().request_type() ||
646 request_->force_main_frame_for_same_site_cookies();
647 CookieOptions::SameSiteCookieContext same_site_context =
648 net::cookie_util::ComputeSameSiteContextForRequest(
649 request_->method(), request_->url_chain(),
650 request_->site_for_cookies(), request_->initiator(),
651 is_main_frame_navigation, force_ignore_site_for_cookies);
652
653 bool is_in_nontrivial_first_party_set =
654 first_party_set_metadata_.frame_entry().has_value();
655 CookieOptions options = CreateCookieOptions(
656 same_site_context, first_party_set_metadata_.context(),
657 request_->isolation_info(), is_in_nontrivial_first_party_set);
658
659 cookie_store->GetCookieListWithOptionsAsync(
660 request_->url(), options,
661 CookiePartitionKeyCollection::FromOptional(cookie_partition_key_.value()),
662 base::BindOnce(&URLRequestHttpJob::SetCookieHeaderAndStart,
663 weak_factory_.GetWeakPtr(), options));
664 }
665
666 namespace {
667
ShouldBlockAllCookies(const PrivacyMode & privacy_mode)668 bool ShouldBlockAllCookies(const PrivacyMode& privacy_mode) {
669 return privacy_mode == PRIVACY_MODE_ENABLED ||
670 privacy_mode == PRIVACY_MODE_ENABLED_WITHOUT_CLIENT_CERTS;
671 }
672
ShouldBlockUnpartitionedCookiesOnly(const PrivacyMode & privacy_mode)673 bool ShouldBlockUnpartitionedCookiesOnly(const PrivacyMode& privacy_mode) {
674 return privacy_mode == PRIVACY_MODE_ENABLED_PARTITIONED_STATE_ALLOWED;
675 }
676
677 } // namespace
678
SetCookieHeaderAndStart(const CookieOptions & options,const CookieAccessResultList & cookies_with_access_result_list,const CookieAccessResultList & excluded_list)679 void URLRequestHttpJob::SetCookieHeaderAndStart(
680 const CookieOptions& options,
681 const CookieAccessResultList& cookies_with_access_result_list,
682 const CookieAccessResultList& excluded_list) {
683 DCHECK(request_->maybe_sent_cookies().empty());
684
685 CookieAccessResultList maybe_included_cookies =
686 cookies_with_access_result_list;
687 CookieAccessResultList excluded_cookies = excluded_list;
688
689 if (ShouldBlockAllCookies(request_info_.privacy_mode)) {
690 // If cookies are blocked (without our needing to consult the delegate),
691 // we move them to `excluded_cookies` and ensure that they have the
692 // correct exclusion reason.
693 excluded_cookies.insert(
694 excluded_cookies.end(),
695 std::make_move_iterator(maybe_included_cookies.begin()),
696 std::make_move_iterator(maybe_included_cookies.end()));
697 maybe_included_cookies.clear();
698 for (auto& cookie : excluded_cookies) {
699 cookie.access_result.status.AddExclusionReason(
700 CookieInclusionStatus::EXCLUDE_USER_PREFERENCES);
701 }
702 }
703 if (ShouldBlockUnpartitionedCookiesOnly(request_info_.privacy_mode)) {
704 auto partition_it = base::ranges::stable_partition(
705 maybe_included_cookies, [](const CookieWithAccessResult& el) {
706 return el.cookie.IsPartitioned();
707 });
708 for (auto it = partition_it; it < maybe_included_cookies.end(); ++it) {
709 it->access_result.status.AddExclusionReason(
710 CookieInclusionStatus::EXCLUDE_USER_PREFERENCES);
711 if (first_party_set_metadata_.AreSitesInSameFirstPartySet()) {
712 it->access_result.status.AddExclusionReason(
713 CookieInclusionStatus::
714 EXCLUDE_THIRD_PARTY_BLOCKED_WITHIN_FIRST_PARTY_SET);
715 }
716 }
717 excluded_cookies.insert(
718 excluded_cookies.end(), std::make_move_iterator(partition_it),
719 std::make_move_iterator(maybe_included_cookies.end()));
720 maybe_included_cookies.erase(partition_it, maybe_included_cookies.end());
721 }
722 if (request_info_.privacy_mode == PRIVACY_MODE_DISABLED ||
723 !maybe_included_cookies.empty()) {
724 AnnotateAndMoveUserBlockedCookies(maybe_included_cookies, excluded_cookies);
725 if (!maybe_included_cookies.empty()) {
726 std::string cookie_line =
727 CanonicalCookie::BuildCookieLine(maybe_included_cookies);
728 request_info_.extra_headers.SetHeader(HttpRequestHeaders::kCookie,
729 cookie_line);
730
731 size_t n_partitioned_cookies = 0;
732
733 // TODO(crbug.com/1031664): Reduce the number of times the cookie list
734 // is iterated over. Get metrics for every cookie which is included.
735 for (const auto& c : maybe_included_cookies) {
736 bool request_is_secure = request_->url().SchemeIsCryptographic();
737 net::CookieSourceScheme cookie_scheme = c.cookie.SourceScheme();
738 CookieRequestScheme cookie_request_schemes;
739
740 switch (cookie_scheme) {
741 case net::CookieSourceScheme::kSecure:
742 cookie_request_schemes =
743 request_is_secure
744 ? CookieRequestScheme::kSecureSetSecureRequest
745 : CookieRequestScheme::kSecureSetNonsecureRequest;
746 break;
747
748 case net::CookieSourceScheme::kNonSecure:
749 cookie_request_schemes =
750 request_is_secure
751 ? CookieRequestScheme::kNonsecureSetSecureRequest
752 : CookieRequestScheme::kNonsecureSetNonsecureRequest;
753 break;
754
755 case net::CookieSourceScheme::kUnset:
756 cookie_request_schemes = CookieRequestScheme::kUnsetCookieScheme;
757 break;
758 }
759
760 UMA_HISTOGRAM_ENUMERATION("Cookie.CookieSchemeRequestScheme",
761 cookie_request_schemes);
762 if (c.cookie.IsPartitioned()) {
763 ++n_partitioned_cookies;
764 }
765 }
766
767 if (IsPartitionedCookiesEnabled()) {
768 base::UmaHistogramCounts100("Cookie.PartitionedCookiesInRequest",
769 n_partitioned_cookies);
770 }
771 }
772 }
773
774 CookieAccessResultList maybe_sent_cookies = std::move(excluded_cookies);
775 maybe_sent_cookies.insert(
776 maybe_sent_cookies.end(),
777 std::make_move_iterator(maybe_included_cookies.begin()),
778 std::make_move_iterator(maybe_included_cookies.end()));
779 maybe_included_cookies.clear();
780
781 if (request_->net_log().IsCapturing()) {
782 for (const auto& cookie_with_access_result : maybe_sent_cookies) {
783 request_->net_log().AddEvent(
784 NetLogEventType::COOKIE_INCLUSION_STATUS,
785 [&](NetLogCaptureMode capture_mode) {
786 return CookieInclusionStatusNetLogParams(
787 "send", cookie_with_access_result.cookie.Name(),
788 cookie_with_access_result.cookie.Domain(),
789 cookie_with_access_result.cookie.Path(),
790 cookie_with_access_result.access_result.status, capture_mode);
791 });
792 }
793 }
794
795 request_->set_maybe_sent_cookies(std::move(maybe_sent_cookies));
796
797 StartTransaction();
798 }
799
AnnotateAndMoveUserBlockedCookies(CookieAccessResultList & maybe_included_cookies,CookieAccessResultList & excluded_cookies) const800 void URLRequestHttpJob::AnnotateAndMoveUserBlockedCookies(
801 CookieAccessResultList& maybe_included_cookies,
802 CookieAccessResultList& excluded_cookies) const {
803 DCHECK(request_info_.privacy_mode == PrivacyMode::PRIVACY_MODE_DISABLED ||
804 (request_info_.privacy_mode ==
805 PrivacyMode::PRIVACY_MODE_ENABLED_PARTITIONED_STATE_ALLOWED &&
806 base::ranges::all_of(maybe_included_cookies,
807 [](const CookieWithAccessResult& el) {
808 return el.cookie.IsPartitioned();
809 })))
810 << request_info_.privacy_mode;
811
812 bool can_get_cookies = URLRequest::DefaultCanUseCookies();
813 if (request()->network_delegate()) {
814 can_get_cookies =
815 request()->network_delegate()->AnnotateAndMoveUserBlockedCookies(
816 *request(), first_party_set_metadata_, maybe_included_cookies,
817 excluded_cookies);
818 }
819
820 if (!can_get_cookies) {
821 request()->net_log().AddEvent(
822 NetLogEventType::COOKIE_GET_BLOCKED_BY_NETWORK_DELEGATE);
823 }
824 }
825
SaveCookiesAndNotifyHeadersComplete(int result)826 void URLRequestHttpJob::SaveCookiesAndNotifyHeadersComplete(int result) {
827 DCHECK(set_cookie_access_result_list_.empty());
828 // TODO(crbug.com/1186863): Turn this CHECK into DCHECK once the investigation
829 // is done.
830 CHECK_EQ(0, num_cookie_lines_left_);
831
832 // End of the call started in OnStartCompleted.
833 OnCallToDelegateComplete();
834
835 if (result != OK) {
836 request_->net_log().AddEventWithStringParams(NetLogEventType::CANCELLED,
837 "source", "delegate");
838 NotifyStartError(result);
839 return;
840 }
841
842 CookieStore* cookie_store = request_->context()->cookie_store();
843
844 if ((request_info_.load_flags & LOAD_DO_NOT_SAVE_COOKIES) || !cookie_store) {
845 NotifyHeadersComplete();
846 return;
847 }
848
849 base::Time response_date;
850 absl::optional<base::Time> server_time = absl::nullopt;
851 if (GetResponseHeaders()->GetDateValue(&response_date))
852 server_time = absl::make_optional(response_date);
853
854 bool force_ignore_site_for_cookies =
855 request_->force_ignore_site_for_cookies();
856 if (cookie_store->cookie_access_delegate() &&
857 cookie_store->cookie_access_delegate()->ShouldIgnoreSameSiteRestrictions(
858 request_->url(), request_->site_for_cookies())) {
859 force_ignore_site_for_cookies = true;
860 }
861 bool is_main_frame_navigation =
862 IsolationInfo::RequestType::kMainFrame ==
863 request_->isolation_info().request_type() ||
864 request_->force_main_frame_for_same_site_cookies();
865 CookieOptions::SameSiteCookieContext same_site_context =
866 net::cookie_util::ComputeSameSiteContextForResponse(
867 request_->url_chain(), request_->site_for_cookies(),
868 request_->initiator(), is_main_frame_navigation,
869 force_ignore_site_for_cookies);
870
871 bool is_in_nontrivial_first_party_set =
872 first_party_set_metadata_.frame_entry().has_value();
873 CookieOptions options = CreateCookieOptions(
874 same_site_context, first_party_set_metadata_.context(),
875 request_->isolation_info(), is_in_nontrivial_first_party_set);
876
877 // Set all cookies, without waiting for them to be set. Any subsequent
878 // read will see the combined result of all cookie operation.
879 const base::StringPiece name("Set-Cookie");
880 std::string cookie_string;
881 size_t iter = 0;
882 HttpResponseHeaders* headers = GetResponseHeaders();
883
884 // NotifyHeadersComplete needs to be called once and only once after the
885 // list has been fully processed, and it can either be called in the
886 // callback or after the loop is called, depending on how the last element
887 // was handled. |num_cookie_lines_left_| keeps track of how many async
888 // callbacks are currently out (starting from 1 to make sure the loop runs
889 // all the way through before trying to exit). If there are any callbacks
890 // still waiting when the loop ends, then NotifyHeadersComplete will be
891 // called when it reaches 0 in the callback itself.
892 num_cookie_lines_left_ = 1;
893 while (headers->EnumerateHeader(&iter, name, &cookie_string)) {
894 CookieInclusionStatus returned_status;
895
896 num_cookie_lines_left_++;
897
898 std::unique_ptr<CanonicalCookie> cookie = net::CanonicalCookie::Create(
899 request_->url(), cookie_string, base::Time::Now(), server_time,
900 cookie_partition_key_.value(), &returned_status);
901
902 absl::optional<CanonicalCookie> cookie_to_return = absl::nullopt;
903 if (returned_status.IsInclude()) {
904 DCHECK(cookie);
905 // Make a copy of the cookie if we successfully made one.
906 cookie_to_return = *cookie;
907 }
908 if (cookie && !CanSetCookie(*cookie, &options)) {
909 returned_status.AddExclusionReason(
910 CookieInclusionStatus::EXCLUDE_USER_PREFERENCES);
911 }
912 if (!returned_status.IsInclude()) {
913 OnSetCookieResult(options, cookie_to_return, std::move(cookie_string),
914 CookieAccessResult(returned_status));
915 continue;
916 }
917 CookieAccessResult cookie_access_result(returned_status);
918 cookie_store->SetCanonicalCookieAsync(
919 std::move(cookie), request_->url(), options,
920 base::BindOnce(&URLRequestHttpJob::OnSetCookieResult,
921 weak_factory_.GetWeakPtr(), options, cookie_to_return,
922 cookie_string),
923 std::move(cookie_access_result));
924 }
925 // Removing the 1 that |num_cookie_lines_left| started with, signifing that
926 // loop has been exited.
927 num_cookie_lines_left_--;
928
929 if (num_cookie_lines_left_ == 0)
930 NotifyHeadersComplete();
931 }
932
OnSetCookieResult(const CookieOptions & options,absl::optional<CanonicalCookie> cookie,std::string cookie_string,CookieAccessResult access_result)933 void URLRequestHttpJob::OnSetCookieResult(
934 const CookieOptions& options,
935 absl::optional<CanonicalCookie> cookie,
936 std::string cookie_string,
937 CookieAccessResult access_result) {
938 if (request_->net_log().IsCapturing()) {
939 request_->net_log().AddEvent(NetLogEventType::COOKIE_INCLUSION_STATUS,
940 [&](NetLogCaptureMode capture_mode) {
941 return CookieInclusionStatusNetLogParams(
942 "store",
943 cookie ? cookie.value().Name() : "",
944 cookie ? cookie.value().Domain() : "",
945 cookie ? cookie.value().Path() : "",
946 access_result.status, capture_mode);
947 });
948 }
949
950 set_cookie_access_result_list_.emplace_back(
951 std::move(cookie), std::move(cookie_string), access_result);
952
953 num_cookie_lines_left_--;
954
955 // If all the cookie lines have been handled, |set_cookie_access_result_list_|
956 // now reflects the result of all Set-Cookie lines, and the request can be
957 // continued.
958 if (num_cookie_lines_left_ == 0)
959 NotifyHeadersComplete();
960 }
961
ProcessStrictTransportSecurityHeader()962 void URLRequestHttpJob::ProcessStrictTransportSecurityHeader() {
963 DCHECK(response_info_);
964 TransportSecurityState* security_state =
965 request_->context()->transport_security_state();
966 const SSLInfo& ssl_info = response_info_->ssl_info;
967
968 // Only accept HSTS headers on HTTPS connections that have no
969 // certificate errors.
970 if (!ssl_info.is_valid() || IsCertStatusError(ssl_info.cert_status) ||
971 !security_state) {
972 return;
973 }
974
975 // Don't accept HSTS headers when the hostname is an IP address.
976 if (request_info_.url.HostIsIPAddress())
977 return;
978
979 // http://tools.ietf.org/html/draft-ietf-websec-strict-transport-sec:
980 //
981 // If a UA receives more than one STS header field in a HTTP response
982 // message over secure transport, then the UA MUST process only the
983 // first such header field.
984 HttpResponseHeaders* headers = GetResponseHeaders();
985 std::string value;
986 if (headers->EnumerateHeader(nullptr, "Strict-Transport-Security", &value))
987 security_state->AddHSTSHeader(request_info_.url.host(), value);
988 }
989
OnStartCompleted(int result)990 void URLRequestHttpJob::OnStartCompleted(int result) {
991 TRACE_EVENT0(NetTracingCategory(), "URLRequestHttpJob::OnStartCompleted");
992 RecordTimer();
993
994 // If the job is done (due to cancellation), can just ignore this
995 // notification.
996 if (done_)
997 return;
998
999 receive_headers_end_ = base::TimeTicks::Now();
1000
1001 const URLRequestContext* context = request_->context();
1002
1003 if (transaction_ && transaction_->GetResponseInfo()) {
1004 const SSLInfo& ssl_info = transaction_->GetResponseInfo()->ssl_info;
1005 if (!IsCertificateError(result)) {
1006 LogTrustAnchor(ssl_info.public_key_hashes);
1007 }
1008 }
1009
1010 if (transaction_ && transaction_->GetResponseInfo()) {
1011 SetProxyServer(transaction_->GetResponseInfo()->proxy_server);
1012 }
1013
1014 if (result == OK) {
1015 scoped_refptr<HttpResponseHeaders> headers = GetResponseHeaders();
1016
1017 NetworkDelegate* network_delegate = request()->network_delegate();
1018 if (network_delegate) {
1019 // Note that |this| may not be deleted until
1020 // |URLRequestHttpJob::OnHeadersReceivedCallback()| or
1021 // |NetworkDelegate::URLRequestDestroyed()| has been called.
1022 OnCallToDelegate(NetLogEventType::NETWORK_DELEGATE_HEADERS_RECEIVED);
1023 preserve_fragment_on_redirect_url_ = absl::nullopt;
1024 IPEndPoint endpoint;
1025 if (transaction_)
1026 transaction_->GetRemoteEndpoint(&endpoint);
1027 // The NetworkDelegate must watch for OnRequestDestroyed and not modify
1028 // any of the arguments after it's called.
1029 // TODO(mattm): change the API to remove the out-params and take the
1030 // results as params of the callback.
1031 int error = network_delegate->NotifyHeadersReceived(
1032 request_,
1033 base::BindOnce(&URLRequestHttpJob::OnHeadersReceivedCallback,
1034 weak_factory_.GetWeakPtr()),
1035 headers.get(), &override_response_headers_, endpoint,
1036 &preserve_fragment_on_redirect_url_);
1037 if (error != OK) {
1038 if (error == ERR_IO_PENDING) {
1039 awaiting_callback_ = true;
1040 } else {
1041 request_->net_log().AddEventWithStringParams(
1042 NetLogEventType::CANCELLED, "source", "delegate");
1043 OnCallToDelegateComplete();
1044 NotifyStartError(error);
1045 }
1046 return;
1047 }
1048 }
1049
1050 SaveCookiesAndNotifyHeadersComplete(OK);
1051 } else if (IsCertificateError(result)) {
1052 // We encountered an SSL certificate error.
1053 // Maybe overridable, maybe not. Ask the delegate to decide.
1054 TransportSecurityState* state = context->transport_security_state();
1055 NotifySSLCertificateError(
1056 result, transaction_->GetResponseInfo()->ssl_info,
1057 state->ShouldSSLErrorsBeFatal(request_info_.url.host()) &&
1058 result != ERR_CERT_KNOWN_INTERCEPTION_BLOCKED);
1059 } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
1060 NotifyCertificateRequested(
1061 transaction_->GetResponseInfo()->cert_request_info.get());
1062 } else if (result == ERR_DNS_NAME_HTTPS_ONLY) {
1063 // If DNS indicated the name is HTTPS-only, synthesize a redirect to either
1064 // HTTPS or WSS.
1065 DCHECK(!request_->url().SchemeIsCryptographic());
1066
1067 base::Time request_time =
1068 transaction_ && transaction_->GetResponseInfo()
1069 ? transaction_->GetResponseInfo()->request_time
1070 : base::Time::Now();
1071 DestroyTransaction();
1072 override_response_info_ = std::make_unique<HttpResponseInfo>();
1073 override_response_info_->request_time = request_time;
1074
1075 override_response_info_->headers = RedirectUtil::SynthesizeRedirectHeaders(
1076 UpgradeSchemeToCryptographic(request_->url()),
1077 RedirectUtil::ResponseCode::REDIRECT_307_TEMPORARY_REDIRECT, "DNS",
1078 request_->extra_request_headers());
1079 NetLogResponseHeaders(
1080 request_->net_log(),
1081 NetLogEventType::URL_REQUEST_FAKE_RESPONSE_HEADERS_CREATED,
1082 override_response_info_->headers.get());
1083
1084 NotifyHeadersComplete();
1085 } else {
1086 // Even on an error, there may be useful information in the response
1087 // info (e.g. whether there's a cached copy).
1088 if (transaction_.get())
1089 response_info_ = transaction_->GetResponseInfo();
1090 NotifyStartError(result);
1091 }
1092 }
1093
OnHeadersReceivedCallback(int result)1094 void URLRequestHttpJob::OnHeadersReceivedCallback(int result) {
1095 // The request should not have been cancelled or have already completed.
1096 DCHECK(!is_done());
1097
1098 awaiting_callback_ = false;
1099
1100 SaveCookiesAndNotifyHeadersComplete(result);
1101 }
1102
OnReadCompleted(int result)1103 void URLRequestHttpJob::OnReadCompleted(int result) {
1104 TRACE_EVENT0(NetTracingCategory(), "URLRequestHttpJob::OnReadCompleted");
1105 read_in_progress_ = false;
1106
1107 DCHECK_NE(ERR_IO_PENDING, result);
1108
1109 if (ShouldFixMismatchedContentLength(result))
1110 result = OK;
1111
1112 // EOF or error, done with this job.
1113 if (result <= 0)
1114 DoneWithRequest(FINISHED);
1115
1116 ReadRawDataComplete(result);
1117 }
1118
RestartTransactionWithAuth(const AuthCredentials & credentials)1119 void URLRequestHttpJob::RestartTransactionWithAuth(
1120 const AuthCredentials& credentials) {
1121 DCHECK(!override_response_info_);
1122
1123 auth_credentials_ = credentials;
1124
1125 // These will be reset in OnStartCompleted.
1126 response_info_ = nullptr;
1127 override_response_headers_ = nullptr; // See https://crbug.com/801237.
1128 receive_headers_end_ = base::TimeTicks();
1129
1130 ResetTimer();
1131
1132 // Update the cookies, since the cookie store may have been updated from the
1133 // headers in the 401/407. Since cookies were already appended to
1134 // extra_headers, we need to strip them out before adding them again.
1135 request_info_.extra_headers.RemoveHeader(HttpRequestHeaders::kCookie);
1136
1137 // TODO(https://crbug.com/968327/): This is weird, as all other clearing is at
1138 // the URLRequest layer. Should this call into URLRequest so it can share
1139 // logic at that layer with SetAuth()?
1140 request_->set_maybe_sent_cookies({});
1141 request_->set_maybe_stored_cookies({});
1142
1143 if (ShouldAddCookieHeader()) {
1144 // Since `request_->isolation_info()` hasn't changed, we don't need to
1145 // recompute the cookie partition key.
1146 AddCookieHeaderAndStart();
1147 } else {
1148 StartTransaction();
1149 }
1150 }
1151
SetUpload(UploadDataStream * upload)1152 void URLRequestHttpJob::SetUpload(UploadDataStream* upload) {
1153 DCHECK(!transaction_.get() && !override_response_info_)
1154 << "cannot change once started";
1155 request_info_.upload_data_stream = upload;
1156 }
1157
SetExtraRequestHeaders(const HttpRequestHeaders & headers)1158 void URLRequestHttpJob::SetExtraRequestHeaders(
1159 const HttpRequestHeaders& headers) {
1160 DCHECK(!transaction_.get() && !override_response_info_)
1161 << "cannot change once started";
1162 request_info_.extra_headers.CopyFrom(headers);
1163 }
1164
GetLoadState() const1165 LoadState URLRequestHttpJob::GetLoadState() const {
1166 return transaction_.get() ?
1167 transaction_->GetLoadState() : LOAD_STATE_IDLE;
1168 }
1169
GetMimeType(std::string * mime_type) const1170 bool URLRequestHttpJob::GetMimeType(std::string* mime_type) const {
1171 DCHECK(transaction_.get() || override_response_info_);
1172
1173 if (!response_info_)
1174 return false;
1175
1176 HttpResponseHeaders* headers = GetResponseHeaders();
1177 if (!headers)
1178 return false;
1179 return headers->GetMimeType(mime_type);
1180 }
1181
GetCharset(std::string * charset)1182 bool URLRequestHttpJob::GetCharset(std::string* charset) {
1183 DCHECK(transaction_.get() || override_response_info_);
1184
1185 if (!response_info_)
1186 return false;
1187
1188 return GetResponseHeaders()->GetCharset(charset);
1189 }
1190
GetResponseInfo(HttpResponseInfo * info)1191 void URLRequestHttpJob::GetResponseInfo(HttpResponseInfo* info) {
1192 if (override_response_info_) {
1193 DCHECK(!transaction_.get());
1194 *info = *override_response_info_;
1195 return;
1196 }
1197
1198 if (response_info_) {
1199 DCHECK(transaction_.get());
1200
1201 *info = *response_info_;
1202 if (override_response_headers_.get())
1203 info->headers = override_response_headers_;
1204 }
1205 }
1206
GetLoadTimingInfo(LoadTimingInfo * load_timing_info) const1207 void URLRequestHttpJob::GetLoadTimingInfo(
1208 LoadTimingInfo* load_timing_info) const {
1209 // If haven't made it far enough to receive any headers, don't return
1210 // anything. This makes for more consistent behavior in the case of errors.
1211 if (!transaction_ || receive_headers_end_.is_null())
1212 return;
1213 if (transaction_->GetLoadTimingInfo(load_timing_info))
1214 load_timing_info->receive_headers_end = receive_headers_end_;
1215 }
1216
GetTransactionRemoteEndpoint(IPEndPoint * endpoint) const1217 bool URLRequestHttpJob::GetTransactionRemoteEndpoint(
1218 IPEndPoint* endpoint) const {
1219 if (!transaction_)
1220 return false;
1221
1222 return transaction_->GetRemoteEndpoint(endpoint);
1223 }
1224
GetResponseCode() const1225 int URLRequestHttpJob::GetResponseCode() const {
1226 DCHECK(transaction_.get());
1227
1228 if (!response_info_)
1229 return -1;
1230
1231 return GetResponseHeaders()->response_code();
1232 }
1233
PopulateNetErrorDetails(NetErrorDetails * details) const1234 void URLRequestHttpJob::PopulateNetErrorDetails(
1235 NetErrorDetails* details) const {
1236 if (!transaction_)
1237 return;
1238 return transaction_->PopulateNetErrorDetails(details);
1239 }
1240
SetUpSourceStream()1241 std::unique_ptr<SourceStream> URLRequestHttpJob::SetUpSourceStream() {
1242 DCHECK(transaction_.get());
1243 if (!response_info_)
1244 return nullptr;
1245
1246 std::unique_ptr<SourceStream> upstream = URLRequestJob::SetUpSourceStream();
1247 HttpResponseHeaders* headers = GetResponseHeaders();
1248 std::vector<SourceStream::SourceType> types;
1249 size_t iter = 0;
1250 for (std::string type;
1251 headers->EnumerateHeader(&iter, "Content-Encoding", &type);) {
1252 SourceStream::SourceType source_type =
1253 FilterSourceStream::ParseEncodingType(type);
1254 switch (source_type) {
1255 case SourceStream::TYPE_BROTLI:
1256 case SourceStream::TYPE_DEFLATE:
1257 case SourceStream::TYPE_GZIP:
1258 if (request_->accepted_stream_types() &&
1259 !request_->accepted_stream_types()->contains(source_type)) {
1260 // If the source type is disabled, we treat it
1261 // in the same way as SourceStream::TYPE_UNKNOWN.
1262 return upstream;
1263 }
1264 types.push_back(source_type);
1265 break;
1266 case SourceStream::TYPE_NONE:
1267 // Identity encoding type. Pass through raw response body.
1268 return upstream;
1269 case SourceStream::TYPE_UNKNOWN:
1270 // Unknown encoding type. Pass through raw response body.
1271 // Request will not be canceled; though
1272 // it is expected that user will see malformed / garbage response.
1273 return upstream;
1274 }
1275 }
1276
1277 for (const auto& type : base::Reversed(types)) {
1278 std::unique_ptr<FilterSourceStream> downstream;
1279 switch (type) {
1280 case SourceStream::TYPE_BROTLI:
1281 downstream = CreateBrotliSourceStream(std::move(upstream));
1282 break;
1283 case SourceStream::TYPE_GZIP:
1284 case SourceStream::TYPE_DEFLATE:
1285 downstream = GzipSourceStream::Create(std::move(upstream), type);
1286 break;
1287 case SourceStream::TYPE_NONE:
1288 case SourceStream::TYPE_UNKNOWN:
1289 NOTREACHED();
1290 return nullptr;
1291 }
1292 if (downstream == nullptr)
1293 return nullptr;
1294 upstream = std::move(downstream);
1295 }
1296
1297 return upstream;
1298 }
1299
CopyFragmentOnRedirect(const GURL & location) const1300 bool URLRequestHttpJob::CopyFragmentOnRedirect(const GURL& location) const {
1301 // Allow modification of reference fragments by default, unless
1302 // |preserve_fragment_on_redirect_url_| is set and equal to the redirect URL.
1303 return !preserve_fragment_on_redirect_url_.has_value() ||
1304 preserve_fragment_on_redirect_url_ != location;
1305 }
1306
IsSafeRedirect(const GURL & location)1307 bool URLRequestHttpJob::IsSafeRedirect(const GURL& location) {
1308 // HTTP is always safe.
1309 // TODO(pauljensen): Remove once crbug.com/146591 is fixed.
1310 if (location.is_valid() &&
1311 (location.scheme() == "http" || location.scheme() == "https")) {
1312 return true;
1313 }
1314 // Query URLRequestJobFactory as to whether |location| would be safe to
1315 // redirect to.
1316 return request_->context()->job_factory() &&
1317 request_->context()->job_factory()->IsSafeRedirectTarget(location);
1318 }
1319
NeedsAuth()1320 bool URLRequestHttpJob::NeedsAuth() {
1321 int code = GetResponseCode();
1322 if (code == -1)
1323 return false;
1324
1325 // Check if we need either Proxy or WWW Authentication. This could happen
1326 // because we either provided no auth info, or provided incorrect info.
1327 switch (code) {
1328 case 407:
1329 if (proxy_auth_state_ == AUTH_STATE_CANCELED)
1330 return false;
1331 proxy_auth_state_ = AUTH_STATE_NEED_AUTH;
1332 return true;
1333 case 401:
1334 if (server_auth_state_ == AUTH_STATE_CANCELED)
1335 return false;
1336 server_auth_state_ = AUTH_STATE_NEED_AUTH;
1337 return true;
1338 }
1339 return false;
1340 }
1341
GetAuthChallengeInfo()1342 std::unique_ptr<AuthChallengeInfo> URLRequestHttpJob::GetAuthChallengeInfo() {
1343 DCHECK(transaction_.get());
1344 DCHECK(response_info_);
1345
1346 // sanity checks:
1347 DCHECK(proxy_auth_state_ == AUTH_STATE_NEED_AUTH ||
1348 server_auth_state_ == AUTH_STATE_NEED_AUTH);
1349 DCHECK((GetResponseHeaders()->response_code() == HTTP_UNAUTHORIZED) ||
1350 (GetResponseHeaders()->response_code() ==
1351 HTTP_PROXY_AUTHENTICATION_REQUIRED));
1352
1353 if (!response_info_->auth_challenge.has_value())
1354 return nullptr;
1355 return std::make_unique<AuthChallengeInfo>(
1356 response_info_->auth_challenge.value());
1357 }
1358
SetAuth(const AuthCredentials & credentials)1359 void URLRequestHttpJob::SetAuth(const AuthCredentials& credentials) {
1360 DCHECK(transaction_.get());
1361
1362 // Proxy gets set first, then WWW.
1363 if (proxy_auth_state_ == AUTH_STATE_NEED_AUTH) {
1364 proxy_auth_state_ = AUTH_STATE_HAVE_AUTH;
1365 } else {
1366 DCHECK_EQ(server_auth_state_, AUTH_STATE_NEED_AUTH);
1367 server_auth_state_ = AUTH_STATE_HAVE_AUTH;
1368 }
1369
1370 RestartTransactionWithAuth(credentials);
1371 }
1372
CancelAuth()1373 void URLRequestHttpJob::CancelAuth() {
1374 if (proxy_auth_state_ == AUTH_STATE_NEED_AUTH) {
1375 proxy_auth_state_ = AUTH_STATE_CANCELED;
1376 } else {
1377 DCHECK_EQ(server_auth_state_, AUTH_STATE_NEED_AUTH);
1378 server_auth_state_ = AUTH_STATE_CANCELED;
1379 }
1380
1381 // The above lines should ensure this is the case.
1382 DCHECK(!NeedsAuth());
1383
1384 // Let the consumer read the HTTP error page. NeedsAuth() should now return
1385 // false, so NotifyHeadersComplete() should not request auth from the client
1386 // again.
1387 //
1388 // Have to do this via PostTask to avoid re-entrantly calling into the
1389 // consumer.
1390 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1391 FROM_HERE, base::BindOnce(&URLRequestHttpJob::NotifyFinalHeadersReceived,
1392 weak_factory_.GetWeakPtr()));
1393 }
1394
ContinueWithCertificate(scoped_refptr<X509Certificate> client_cert,scoped_refptr<SSLPrivateKey> client_private_key)1395 void URLRequestHttpJob::ContinueWithCertificate(
1396 scoped_refptr<X509Certificate> client_cert,
1397 scoped_refptr<SSLPrivateKey> client_private_key) {
1398 DCHECK(transaction_);
1399
1400 DCHECK(!response_info_) << "should not have a response yet";
1401 DCHECK(!override_response_headers_);
1402 receive_headers_end_ = base::TimeTicks();
1403
1404 ResetTimer();
1405
1406 int rv = transaction_->RestartWithCertificate(
1407 std::move(client_cert), std::move(client_private_key),
1408 base::BindOnce(&URLRequestHttpJob::OnStartCompleted,
1409 base::Unretained(this)));
1410 if (rv == ERR_IO_PENDING)
1411 return;
1412
1413 // The transaction started synchronously, but we need to notify the
1414 // URLRequest delegate via the message loop.
1415 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1416 FROM_HERE, base::BindOnce(&URLRequestHttpJob::OnStartCompleted,
1417 weak_factory_.GetWeakPtr(), rv));
1418 }
1419
ContinueDespiteLastError()1420 void URLRequestHttpJob::ContinueDespiteLastError() {
1421 // If the transaction was destroyed, then the job was cancelled.
1422 if (!transaction_.get())
1423 return;
1424
1425 DCHECK(!response_info_) << "should not have a response yet";
1426 DCHECK(!override_response_headers_);
1427 receive_headers_end_ = base::TimeTicks();
1428
1429 ResetTimer();
1430
1431 int rv = transaction_->RestartIgnoringLastError(base::BindOnce(
1432 &URLRequestHttpJob::OnStartCompleted, base::Unretained(this)));
1433 if (rv == ERR_IO_PENDING)
1434 return;
1435
1436 // The transaction started synchronously, but we need to notify the
1437 // URLRequest delegate via the message loop.
1438 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1439 FROM_HERE, base::BindOnce(&URLRequestHttpJob::OnStartCompleted,
1440 weak_factory_.GetWeakPtr(), rv));
1441 }
1442
ShouldFixMismatchedContentLength(int rv) const1443 bool URLRequestHttpJob::ShouldFixMismatchedContentLength(int rv) const {
1444 // Some servers send the body compressed, but specify the content length as
1445 // the uncompressed size. Although this violates the HTTP spec we want to
1446 // support it (as IE and FireFox do), but *only* for an exact match.
1447 // See http://crbug.com/79694.
1448 if (rv == ERR_CONTENT_LENGTH_MISMATCH ||
1449 rv == ERR_INCOMPLETE_CHUNKED_ENCODING) {
1450 if (request_->response_headers()) {
1451 int64_t expected_length =
1452 request_->response_headers()->GetContentLength();
1453 VLOG(1) << __func__ << "() \"" << request_->url().spec() << "\""
1454 << " content-length = " << expected_length
1455 << " pre total = " << prefilter_bytes_read()
1456 << " post total = " << postfilter_bytes_read();
1457 if (postfilter_bytes_read() == expected_length) {
1458 // Clear the error.
1459 return true;
1460 }
1461 }
1462 }
1463 return false;
1464 }
1465
ReadRawData(IOBuffer * buf,int buf_size)1466 int URLRequestHttpJob::ReadRawData(IOBuffer* buf, int buf_size) {
1467 DCHECK_NE(buf_size, 0);
1468 DCHECK(!read_in_progress_);
1469
1470 int rv =
1471 transaction_->Read(buf, buf_size,
1472 base::BindOnce(&URLRequestHttpJob::OnReadCompleted,
1473 base::Unretained(this)));
1474
1475 if (ShouldFixMismatchedContentLength(rv))
1476 rv = OK;
1477
1478 if (rv == 0 || (rv < 0 && rv != ERR_IO_PENDING))
1479 DoneWithRequest(FINISHED);
1480
1481 if (rv == ERR_IO_PENDING)
1482 read_in_progress_ = true;
1483
1484 return rv;
1485 }
1486
GetTotalReceivedBytes() const1487 int64_t URLRequestHttpJob::GetTotalReceivedBytes() const {
1488 int64_t total_received_bytes =
1489 total_received_bytes_from_previous_transactions_;
1490 if (transaction_)
1491 total_received_bytes += transaction_->GetTotalReceivedBytes();
1492 return total_received_bytes;
1493 }
1494
GetTotalSentBytes() const1495 int64_t URLRequestHttpJob::GetTotalSentBytes() const {
1496 int64_t total_sent_bytes = total_sent_bytes_from_previous_transactions_;
1497 if (transaction_)
1498 total_sent_bytes += transaction_->GetTotalSentBytes();
1499 return total_sent_bytes;
1500 }
1501
DoneReading()1502 void URLRequestHttpJob::DoneReading() {
1503 if (transaction_) {
1504 transaction_->DoneReading();
1505 }
1506 DoneWithRequest(FINISHED);
1507 }
1508
DoneReadingRedirectResponse()1509 void URLRequestHttpJob::DoneReadingRedirectResponse() {
1510 if (transaction_) {
1511 DCHECK(!override_response_info_);
1512 if (transaction_->GetResponseInfo()->headers->IsRedirect(nullptr)) {
1513 // If the original headers indicate a redirect, go ahead and cache the
1514 // response, even if the |override_response_headers_| are a redirect to
1515 // another location.
1516 transaction_->DoneReading();
1517 } else {
1518 // Otherwise, |override_response_headers_| must be non-NULL and contain
1519 // bogus headers indicating a redirect.
1520 DCHECK(override_response_headers_.get());
1521 DCHECK(override_response_headers_->IsRedirect(nullptr));
1522 transaction_->StopCaching();
1523 }
1524 }
1525 DoneWithRequest(FINISHED);
1526 }
1527
GetResponseRemoteEndpoint() const1528 IPEndPoint URLRequestHttpJob::GetResponseRemoteEndpoint() const {
1529 return response_info_ ? response_info_->remote_endpoint : IPEndPoint();
1530 }
1531
RecordTimer()1532 void URLRequestHttpJob::RecordTimer() {
1533 if (request_creation_time_.is_null()) {
1534 NOTREACHED()
1535 << "The same transaction shouldn't start twice without new timing.";
1536 return;
1537 }
1538
1539 base::TimeDelta to_start = base::Time::Now() - request_creation_time_;
1540 request_creation_time_ = base::Time();
1541
1542 UMA_HISTOGRAM_MEDIUM_TIMES("Net.HttpTimeToFirstByte", to_start);
1543
1544 // Record additional metrics for TLS 1.3 servers. This is to help measure the
1545 // impact of enabling 0-RTT. The effects of 0-RTT will be muted because not
1546 // all TLS 1.3 servers enable 0-RTT, and only the first round-trip on a
1547 // connection makes use of 0-RTT. However, 0-RTT can affect how requests are
1548 // bound to connections and which connections offer resumption. We look at all
1549 // TLS 1.3 responses for an apples-to-apples comparison.
1550 //
1551 // Additionally record metrics for Google hosts. Most Google hosts are known
1552 // to implement 0-RTT, so this gives more targeted metrics as we initially
1553 // roll out client support.
1554 //
1555 // TODO(https://crbug.com/641225): Remove these metrics after launching 0-RTT.
1556 if (transaction_ && transaction_->GetResponseInfo() &&
1557 IsTLS13OverTCP(*transaction_->GetResponseInfo())) {
1558 base::UmaHistogramMediumTimes("Net.HttpTimeToFirstByte.TLS13", to_start);
1559 if (HasGoogleHost(request()->url())) {
1560 base::UmaHistogramMediumTimes("Net.HttpTimeToFirstByte.TLS13.Google",
1561 to_start);
1562 }
1563 }
1564 }
1565
ResetTimer()1566 void URLRequestHttpJob::ResetTimer() {
1567 if (!request_creation_time_.is_null()) {
1568 NOTREACHED()
1569 << "The timer was reset before it was recorded.";
1570 return;
1571 }
1572 request_creation_time_ = base::Time::Now();
1573 }
1574
SetRequestHeadersCallback(RequestHeadersCallback callback)1575 void URLRequestHttpJob::SetRequestHeadersCallback(
1576 RequestHeadersCallback callback) {
1577 DCHECK(!transaction_);
1578 DCHECK(!request_headers_callback_);
1579 request_headers_callback_ = std::move(callback);
1580 }
1581
SetEarlyResponseHeadersCallback(ResponseHeadersCallback callback)1582 void URLRequestHttpJob::SetEarlyResponseHeadersCallback(
1583 ResponseHeadersCallback callback) {
1584 DCHECK(!transaction_);
1585 DCHECK(!early_response_headers_callback_);
1586 early_response_headers_callback_ = std::move(callback);
1587 }
1588
SetResponseHeadersCallback(ResponseHeadersCallback callback)1589 void URLRequestHttpJob::SetResponseHeadersCallback(
1590 ResponseHeadersCallback callback) {
1591 DCHECK(!transaction_);
1592 DCHECK(!response_headers_callback_);
1593 response_headers_callback_ = std::move(callback);
1594 }
1595
RecordCompletionHistograms(CompletionCause reason)1596 void URLRequestHttpJob::RecordCompletionHistograms(CompletionCause reason) {
1597 if (start_time_.is_null())
1598 return;
1599
1600 base::TimeDelta total_time = base::TimeTicks::Now() - start_time_;
1601 UMA_HISTOGRAM_TIMES("Net.HttpJob.TotalTime", total_time);
1602
1603 if (reason == FINISHED) {
1604 UmaHistogramTimes(
1605 base::StringPrintf("Net.HttpJob.TotalTimeSuccess.Priority%d",
1606 request()->priority()),
1607 total_time);
1608 UMA_HISTOGRAM_TIMES("Net.HttpJob.TotalTimeSuccess", total_time);
1609 } else {
1610 UMA_HISTOGRAM_TIMES("Net.HttpJob.TotalTimeCancel", total_time);
1611 }
1612
1613 if (response_info_) {
1614 // QUIC (by default) supports https scheme only, thus track https URLs only
1615 // for QUIC.
1616 bool is_https_google = request() && request()->url().SchemeIs("https") &&
1617 HasGoogleHost(request()->url());
1618 bool used_quic = response_info_->DidUseQuic();
1619 if (is_https_google) {
1620 if (used_quic) {
1621 UMA_HISTOGRAM_MEDIUM_TIMES("Net.HttpJob.TotalTime.Secure.Quic",
1622 total_time);
1623 }
1624 }
1625
1626 // Record metrics for TLS 1.3 to measure the impact of 0-RTT. See comment in
1627 // RecordTimer().
1628 //
1629 // TODO(https://crbug.com/641225): Remove these metrics after launching
1630 // 0-RTT.
1631 if (IsTLS13OverTCP(*response_info_)) {
1632 base::UmaHistogramTimes("Net.HttpJob.TotalTime.TLS13", total_time);
1633 if (is_https_google) {
1634 base::UmaHistogramTimes("Net.HttpJob.TotalTime.TLS13.Google",
1635 total_time);
1636 }
1637 }
1638
1639 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.HttpJob.PrefilterBytesRead",
1640 prefilter_bytes_read(), 1, 50000000, 50);
1641 if (response_info_->was_cached) {
1642 UMA_HISTOGRAM_TIMES("Net.HttpJob.TotalTimeCached", total_time);
1643 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.HttpJob.PrefilterBytesRead.Cache",
1644 prefilter_bytes_read(), 1, 50000000, 50);
1645
1646 if (response_info_->unused_since_prefetch)
1647 UMA_HISTOGRAM_COUNTS_1M("Net.Prefetch.HitBytes",
1648 prefilter_bytes_read());
1649 } else {
1650 UMA_HISTOGRAM_TIMES("Net.HttpJob.TotalTimeNotCached", total_time);
1651 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.HttpJob.PrefilterBytesRead.Net",
1652 prefilter_bytes_read(), 1, 50000000, 50);
1653
1654 if (request_info_.load_flags & LOAD_PREFETCH) {
1655 UMA_HISTOGRAM_COUNTS_1M("Net.Prefetch.PrefilterBytesReadFromNetwork",
1656 prefilter_bytes_read());
1657 }
1658 if (is_https_google && used_quic) {
1659 UMA_HISTOGRAM_MEDIUM_TIMES("Net.HttpJob.TotalTimeNotCached.Secure.Quic",
1660 total_time);
1661 }
1662 }
1663 }
1664
1665 start_time_ = base::TimeTicks();
1666 }
1667
DoneWithRequest(CompletionCause reason)1668 void URLRequestHttpJob::DoneWithRequest(CompletionCause reason) {
1669 if (done_)
1670 return;
1671 done_ = true;
1672
1673 // Notify NetworkQualityEstimator.
1674 NetworkQualityEstimator* network_quality_estimator =
1675 request()->context()->network_quality_estimator();
1676 if (network_quality_estimator) {
1677 network_quality_estimator->NotifyRequestCompleted(*request());
1678 }
1679
1680 RecordCompletionHistograms(reason);
1681 request()->set_received_response_content_length(prefilter_bytes_read());
1682 }
1683
GetResponseHeaders() const1684 HttpResponseHeaders* URLRequestHttpJob::GetResponseHeaders() const {
1685 if (override_response_info_) {
1686 DCHECK(!transaction_.get());
1687 return override_response_info_->headers.get();
1688 }
1689
1690 DCHECK(transaction_.get());
1691 DCHECK(transaction_->GetResponseInfo());
1692
1693 return override_response_headers_.get() ?
1694 override_response_headers_.get() :
1695 transaction_->GetResponseInfo()->headers.get();
1696 }
1697
NotifyURLRequestDestroyed()1698 void URLRequestHttpJob::NotifyURLRequestDestroyed() {
1699 awaiting_callback_ = false;
1700
1701 // Notify NetworkQualityEstimator.
1702 NetworkQualityEstimator* network_quality_estimator =
1703 request()->context()->network_quality_estimator();
1704 if (network_quality_estimator)
1705 network_quality_estimator->NotifyURLRequestDestroyed(*request());
1706 }
1707
ShouldAddCookieHeader() const1708 bool URLRequestHttpJob::ShouldAddCookieHeader() const {
1709 // Read cookies whenever allow_credentials() is true, even if the PrivacyMode
1710 // is being overridden by NetworkDelegate and will eventually block them, as
1711 // blocked cookies still need to be logged in that case.
1712 return request_->context()->cookie_store() && request_->allow_credentials();
1713 }
1714
IsPartitionedCookiesEnabled() const1715 bool URLRequestHttpJob::IsPartitionedCookiesEnabled() const {
1716 // Only valid to call this after we've computed the key.
1717 DCHECK(cookie_partition_key_.has_value());
1718 return cookie_partition_key_.value().has_value();
1719 }
1720
1721 } // namespace net
1722