| // Copyright 2025 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "content/public/browser/keep_alive_request_tracker.h" |
| |
| #include "base/no_destructor.h" |
| |
| namespace content { |
| |
| KeepAliveRequestTracker::KeepAliveRequestTracker(RequestType request_type) |
| : request_type_(request_type), |
| current_stage_({RequestStageType::kLoaderCreated, std::nullopt}) {} |
| KeepAliveRequestTracker::~KeepAliveRequestTracker() = default; |
| |
| KeepAliveRequestTracker::RequestStage::RequestStage( |
| const RequestStageType& other_type, |
| std::optional<network::URLLoaderCompletionStatus> other_status) |
| : type(other_type), status(other_status) {} |
| KeepAliveRequestTracker::RequestStage::RequestStage( |
| const RequestStageType& other_type) |
| : RequestStage(other_type, std::nullopt) {} |
| KeepAliveRequestTracker::RequestStage::~RequestStage() = default; |
| |
| KeepAliveRequestTracker::RequestStage::RequestStage(const RequestStage& other) = |
| default; |
| KeepAliveRequestTracker::RequestStage& |
| KeepAliveRequestTracker::RequestStage::operator=(const RequestStage&) = default; |
| |
| std::ostream& operator<<( |
| std::ostream& os, |
| const KeepAliveRequestTracker::RequestStageType& stage_type) { |
| switch (stage_type) { |
| case KeepAliveRequestTracker::RequestStageType::kLoaderCreated: |
| os << "Loader Created"; |
| break; |
| case KeepAliveRequestTracker::RequestStageType::kRequestStarted: |
| os << "Request Started"; |
| break; |
| case KeepAliveRequestTracker::RequestStageType::kFirstRedirectReceived: |
| os << "First Redirect Received"; |
| break; |
| case KeepAliveRequestTracker::RequestStageType::kSecondRedirectReceived: |
| os << "Second Redirect Received"; |
| break; |
| case KeepAliveRequestTracker::RequestStageType:: |
| kThirdOrLaterRedirectReceived: |
| os << "Third or Later Redirect Received"; |
| break; |
| case KeepAliveRequestTracker::RequestStageType::kResponseReceived: |
| os << "Response Received"; |
| break; |
| case KeepAliveRequestTracker::RequestStageType::kRequestFailed: |
| os << "Request Failed"; |
| break; |
| case KeepAliveRequestTracker::RequestStageType:: |
| kLoaderDisconnectedFromRenderer: |
| os << "Loader Disconnected from Renderer"; |
| break; |
| case KeepAliveRequestTracker::RequestStageType::kRequestCancelledByRenderer: |
| os << "Request Cancelled by Renderer"; |
| break; |
| case KeepAliveRequestTracker::RequestStageType:: |
| kRequestCancelledAfterTimeLimit: |
| os << "Request Cancelled after Time Limit"; |
| break; |
| case KeepAliveRequestTracker::RequestStageType::kBrowserShutdown: |
| os << "Browser Shutdown"; |
| break; |
| case KeepAliveRequestTracker::RequestStageType::kLoaderCompleted: |
| os << "Loader Completed"; |
| break; |
| default: |
| os << "<invalid value: " << static_cast<int>(stage_type) << ">"; |
| } |
| return os; |
| } |
| |
| void KeepAliveRequestTracker::AdvanceToNextStage( |
| const RequestStageType& next_stage_type, |
| std::optional<network::URLLoaderCompletionStatus> next_stage_status) { |
| RequestStage next_stage(next_stage_type, next_stage_status); |
| // kLoaderCreated is the initial stage set in ctor. |
| CHECK_NE(next_stage.type, RequestStageType::kLoaderCreated); |
| |
| switch (next_stage.type) { |
| case RequestStageType::kLoaderCreated: |
| // kLoaderCreated is the initial stage set in ctor. |
| NOTREACHED(); |
| case RequestStageType::kRequestStarted: |
| CHECK(!next_stage.status.has_value()); |
| break; |
| case RequestStageType::kFirstRedirectReceived: |
| CHECK(!next_stage.status.has_value()); |
| break; |
| case RequestStageType::kSecondRedirectReceived: |
| CHECK(!next_stage.status.has_value()); |
| break; |
| case RequestStageType::kThirdOrLaterRedirectReceived: |
| CHECK(!next_stage.status.has_value()); |
| break; |
| case RequestStageType::kResponseReceived: |
| CHECK(!next_stage.status.has_value()); |
| break; |
| case RequestStageType::kRequestFailed: |
| CHECK(next_stage.status.has_value()); |
| break; |
| case RequestStageType::kLoaderDisconnectedFromRenderer: |
| CHECK(!next_stage.status.has_value()); |
| break; |
| case RequestStageType::kRequestCancelledByRenderer: |
| CHECK(!next_stage.status.has_value()); |
| break; |
| case RequestStageType::kRequestCancelledAfterTimeLimit: |
| CHECK(!next_stage.status.has_value()); |
| break; |
| case RequestStageType::kBrowserShutdown: |
| CHECK(!next_stage.status.has_value()); |
| break; |
| case RequestStageType::kLoaderCompleted: |
| CHECK(next_stage.status.has_value()); |
| break; |
| case RequestStageType::kRequestRetried: |
| CHECK(next_stage.status.has_value()); |
| break; |
| } |
| |
| AddStageMetrics(next_stage); |
| |
| previous_stage_ = current_stage_; |
| current_stage_ = next_stage; |
| } |
| |
| const KeepAliveRequestTracker::RequestStage& |
| KeepAliveRequestTracker::GetCurrentStage() const { |
| return current_stage_; |
| } |
| |
| const std::optional<KeepAliveRequestTracker::RequestStage>& |
| KeepAliveRequestTracker::GetPreviousStage() const { |
| return previous_stage_; |
| } |
| |
| KeepAliveRequestTracker::RequestStageType |
| KeepAliveRequestTracker::GetNextRedirectStageType() const { |
| switch (num_redirects_) { |
| case 0: |
| return KeepAliveRequestTracker::RequestStageType::kFirstRedirectReceived; |
| case 1: |
| return KeepAliveRequestTracker::RequestStageType::kSecondRedirectReceived; |
| case 2: |
| return KeepAliveRequestTracker::RequestStageType:: |
| kThirdOrLaterRedirectReceived; |
| default: |
| return KeepAliveRequestTracker::RequestStageType:: |
| kThirdOrLaterRedirectReceived; |
| } |
| } |
| |
| uint32_t KeepAliveRequestTracker::GetNumRedirects() const { |
| return num_redirects_; |
| } |
| |
| void KeepAliveRequestTracker::IncreaseNumRedirects() { |
| ++num_redirects_; |
| } |
| |
| uint32_t KeepAliveRequestTracker::GetNumRetries() const { |
| return num_retries_; |
| } |
| |
| void KeepAliveRequestTracker::IncreaseNumRetries() { |
| ++num_retries_; |
| } |
| |
| } // namespace content |