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