Commit 49464f56 authored by Robin Lewis's avatar Robin Lewis Committed by Commit Bot

[GCPW] Add retry mechanism for WinHttpUrlFetcher

Failed HTTP calls in BuildRequestAndFetchResultFromHttpService are re-tried specified number of times before failing.

Bug: 1064502
Change-Id: Id7f89ea42ee8f6076052b9a9f3bd2d84f9ca57e1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2119668Reviewed-by: default avatarRakesh Soma <rakeshsoma@google.com>
Reviewed-by: default avatarTien Mai <tienmai@chromium.org>
Reviewed-by: default avatarYusuf Sengul <yusufsn@google.com>
Commit-Queue: Robin Lewis <wrlewis@google.com>
Cr-Commit-Position: refs/heads/master@{#753757}
parent 442661c8
...@@ -56,6 +56,9 @@ constexpr int kDefaultNumberOfEventsToRead = 10; ...@@ -56,6 +56,9 @@ constexpr int kDefaultNumberOfEventsToRead = 10;
// Maximum number of upload requests to make per upload invocation. // Maximum number of upload requests to make per upload invocation.
constexpr int kMaxAllowedNumberOfUploadRequests = 5; constexpr int kMaxAllowedNumberOfUploadRequests = 5;
// Maximum number of retries if a HTTP call to the backend fails.
constexpr unsigned int kMaxNumHttpRetries = 3;
// Maximum size of the log entries payload in bytes per HTTP request. // Maximum size of the log entries payload in bytes per HTTP request.
// TODO (crbug.com/1043195): Change this to use an experiment flag once an // TODO (crbug.com/1043195): Change this to use an experiment flag once an
// experiment framework for GCPW is available. // experiment framework for GCPW is available.
...@@ -498,7 +501,7 @@ HRESULT EventLogsUploadManager::MakeUploadLogChunkRequest( ...@@ -498,7 +501,7 @@ HRESULT EventLogsUploadManager::MakeUploadLogChunkRequest(
hr = WinHttpUrlFetcher::BuildRequestAndFetchResultFromHttpService( hr = WinHttpUrlFetcher::BuildRequestAndFetchResultFromHttpService(
EventLogsUploadManager::Get()->GetGcpwServiceUploadEventViewerLogsUrl(), EventLogsUploadManager::Get()->GetGcpwServiceUploadEventViewerLogsUrl(),
access_token, {}, request_dict, kDefaultUploadLogsRequestTimeout, access_token, {}, request_dict, kDefaultUploadLogsRequestTimeout,
&request_result); kMaxNumHttpRetries, &request_result);
if (FAILED(hr)) { if (FAILED(hr)) {
LOGFN(ERROR) << "BuildRequestAndFetchResultFromHttpService hr=" LOGFN(ERROR) << "BuildRequestAndFetchResultFromHttpService hr="
...@@ -506,13 +509,6 @@ HRESULT EventLogsUploadManager::MakeUploadLogChunkRequest( ...@@ -506,13 +509,6 @@ HRESULT EventLogsUploadManager::MakeUploadLogChunkRequest(
return hr; return hr;
} }
if (!request_result.has_value() ||
request_result->FindDictKey(kErrorKeyInRequestResult)) {
LOGFN(ERROR) << "error="
<< *request_result->FindDictKey(kErrorKeyInRequestResult);
return E_FAIL;
}
// Store the chunk id which is the last uploaded event log id // Store the chunk id which is the last uploaded event log id
// in registry so we know where to start next time. // in registry so we know where to start next time.
SetGlobalFlag(kEventLogUploadLastUploadedIdRegKey, chunk_id); SetGlobalFlag(kEventLogUploadLastUploadedIdRegKey, chunk_id);
......
...@@ -49,6 +49,9 @@ const char kIsAdJoinedUserParameterName[] = "is_ad_joined_user"; ...@@ -49,6 +49,9 @@ const char kIsAdJoinedUserParameterName[] = "is_ad_joined_user";
const char kMacAddressParameterName[] = "wlan_mac_addr"; const char kMacAddressParameterName[] = "wlan_mac_addr";
const char kUploadDeviceDetailsResponseDeviceResourceIdParameterName[] = const char kUploadDeviceDetailsResponseDeviceResourceIdParameterName[] =
"deviceResourceId"; "deviceResourceId";
// Maximum number of retries if a HTTP call to the backend fails.
constexpr unsigned int kMaxNumHttpRetries = 3;
} // namespace } // namespace
// static // static
...@@ -127,7 +130,7 @@ HRESULT GemDeviceDetailsManager::UploadDeviceDetails( ...@@ -127,7 +130,7 @@ HRESULT GemDeviceDetailsManager::UploadDeviceDetails(
hr = WinHttpUrlFetcher::BuildRequestAndFetchResultFromHttpService( hr = WinHttpUrlFetcher::BuildRequestAndFetchResultFromHttpService(
GemDeviceDetailsManager::Get()->GetGemServiceUploadDeviceDetailsUrl(), GemDeviceDetailsManager::Get()->GetGemServiceUploadDeviceDetailsUrl(),
access_token, {}, *request_dict_, upload_device_details_request_timeout_, access_token, {}, *request_dict_, upload_device_details_request_timeout_,
&request_result); kMaxNumHttpRetries, &request_result);
if (FAILED(hr)) { if (FAILED(hr)) {
LOGFN(ERROR) << "BuildRequestAndFetchResultFromHttpService hr=" LOGFN(ERROR) << "BuildRequestAndFetchResultFromHttpService hr="
...@@ -135,13 +138,6 @@ HRESULT GemDeviceDetailsManager::UploadDeviceDetails( ...@@ -135,13 +138,6 @@ HRESULT GemDeviceDetailsManager::UploadDeviceDetails(
return E_FAIL; return E_FAIL;
} }
base::Value* error_detail =
request_result->FindDictKey(kErrorKeyInRequestResult);
if (error_detail) {
LOGFN(ERROR) << "error=" << *error_detail;
hr = E_FAIL;
}
std::string* resource_id = request_result->FindStringKey( std::string* resource_id = request_result->FindStringKey(
kUploadDeviceDetailsResponseDeviceResourceIdParameterName); kUploadDeviceDetailsResponseDeviceResourceIdParameterName);
if (resource_id) { if (resource_id) {
......
...@@ -80,6 +80,9 @@ constexpr size_t kNonceLength = 12; ...@@ -80,6 +80,9 @@ constexpr size_t kNonceLength = 12;
constexpr size_t kSessionKeyLength = 32; constexpr size_t kSessionKeyLength = 32;
// Maximum number of retries if a HTTP call to the backend fails.
constexpr unsigned int kMaxNumHttpRetries = 3;
bool Base64DecodeCryptographicKey(const std::string& cryptographic_key, bool Base64DecodeCryptographicKey(const std::string& cryptographic_key,
std::string* out) { std::string* out) {
std::string cryptographic_key_copy; std::string cryptographic_key_copy;
...@@ -275,7 +278,8 @@ HRESULT EncryptUserPasswordUsingEscrowService( ...@@ -275,7 +278,8 @@ HRESULT EncryptUserPasswordUsingEscrowService(
// |public_key| to be used for encryption. // |public_key| to be used for encryption.
HRESULT hr = WinHttpUrlFetcher::BuildRequestAndFetchResultFromHttpService( HRESULT hr = WinHttpUrlFetcher::BuildRequestAndFetchResultFromHttpService(
PasswordRecoveryManager::Get()->GetEscrowServiceGenerateKeyPairUrl(), PasswordRecoveryManager::Get()->GetEscrowServiceGenerateKeyPairUrl(),
access_token, {}, request_dict, request_timeout, &request_result); access_token, {}, request_dict, request_timeout, kMaxNumHttpRetries,
&request_result);
if (FAILED(hr)) { if (FAILED(hr)) {
LOGFN(ERROR) << "BuildRequestAndFetchResultFromHttpService hr=" LOGFN(ERROR) << "BuildRequestAndFetchResultFromHttpService hr="
...@@ -363,7 +367,8 @@ HRESULT DecryptUserPasswordUsingEscrowService( ...@@ -363,7 +367,8 @@ HRESULT DecryptUserPasswordUsingEscrowService(
HRESULT hr = WinHttpUrlFetcher::BuildRequestAndFetchResultFromHttpService( HRESULT hr = WinHttpUrlFetcher::BuildRequestAndFetchResultFromHttpService(
PasswordRecoveryManager::Get()->GetEscrowServiceGetPrivateKeyUrl( PasswordRecoveryManager::Get()->GetEscrowServiceGetPrivateKeyUrl(
*resource_id), *resource_id),
access_token, {}, {}, request_timeout, &request_result); access_token, {}, {}, request_timeout, kMaxNumHttpRetries,
&request_result);
if (FAILED(hr)) { if (FAILED(hr)) {
LOGFN(ERROR) << "BuildRequestAndFetchResultFromHttpService hr=" LOGFN(ERROR) << "BuildRequestAndFetchResultFromHttpService hr="
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
#include <atlconv.h> #include <atlconv.h>
#include <process.h> #include <process.h>
#include <set>
#include "base/base64.h" #include "base/base64.h"
#include "base/containers/span.h" #include "base/containers/span.h"
#include "base/json/json_reader.h" #include "base/json/json_reader.h"
...@@ -20,6 +22,18 @@ ...@@ -20,6 +22,18 @@
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "chrome/credential_provider/gaiacp/logging.h" #include "chrome/credential_provider/gaiacp/logging.h"
#include "chrome/credential_provider/gaiacp/mdm_utils.h"
namespace {
// Key name containing the HTTP error code within the dictionary returned by the
// server in case of errors.
constexpr char kHttpErrorCodeKeyNameInResponse[] = "code";
// The HTTP response codes for which the request is re-tried on failure.
const std::set<int> kRetryableHttpErrorCodes = {
503, // Service Unavailable
504 // Gateway Timeout
};
// Self deleting http service requester. This class will try to make a query // Self deleting http service requester. This class will try to make a query
// using the given url fetcher. It will delete itself when the request is // using the given url fetcher. It will delete itself when the request is
...@@ -41,11 +55,12 @@ ...@@ -41,11 +55,12 @@
// thread can self delete. // thread can self delete.
class HttpServiceRequest { class HttpServiceRequest {
public: public:
explicit HttpServiceRequest( static HttpServiceRequest* Create(
std::unique_ptr<credential_provider::WinHttpUrlFetcher> fetcher) const GURL& request_url,
: fetcher_(std::move(fetcher)) { const std::string& access_token,
DCHECK(fetcher_); const std::vector<std::pair<std::string, std::string>>& headers,
} const std::string& request_body,
const base::TimeDelta& request_timeout);
// Tries to fetch the request stored in |fetcher_| in a background thread // Tries to fetch the request stored in |fetcher_| in a background thread
// within the given |request_timeout|. If the background thread returns before // within the given |request_timeout|. If the background thread returns before
...@@ -103,6 +118,12 @@ class HttpServiceRequest { ...@@ -103,6 +118,12 @@ class HttpServiceRequest {
} }
private: private:
explicit HttpServiceRequest(
std::unique_ptr<credential_provider::WinHttpUrlFetcher> fetcher)
: fetcher_(std::move(fetcher)) {
DCHECK(fetcher_);
}
void OrphanRequest() { void OrphanRequest() {
bool delete_self = false; bool delete_self = false;
{ {
...@@ -158,6 +179,44 @@ class HttpServiceRequest { ...@@ -158,6 +179,44 @@ class HttpServiceRequest {
bool is_processing_ = true; bool is_processing_ = true;
}; };
HttpServiceRequest* HttpServiceRequest::Create(
const GURL& request_url,
const std::string& access_token,
const std::vector<std::pair<std::string, std::string>>& headers,
const std::string& request_body,
const base::TimeDelta& request_timeout) {
auto url_fetcher =
credential_provider::WinHttpUrlFetcher::Create(request_url);
if (!url_fetcher) {
LOGFN(ERROR) << "Could not create valid fetcher for url="
<< request_url.spec();
return nullptr;
}
url_fetcher->SetRequestHeader("Content-Type", "application/json");
url_fetcher->SetRequestHeader("Authorization",
("Bearer " + access_token).c_str());
for (auto& header : headers)
url_fetcher->SetRequestHeader(header.first.c_str(), header.second.c_str());
if (!request_body.empty()) {
HRESULT hr = url_fetcher->SetRequestBody(request_body.c_str());
if (FAILED(hr)) {
LOGFN(ERROR) << "fetcher.SetRequestBody hr="
<< credential_provider::putHR(hr);
return nullptr;
}
}
if (!request_timeout.is_zero()) {
url_fetcher->SetHttpRequestTimeout(request_timeout.InMilliseconds());
}
return (new HttpServiceRequest(std::move(url_fetcher)));
}
} // namespace
namespace credential_provider { namespace credential_provider {
// static // static
...@@ -353,49 +412,55 @@ HRESULT WinHttpUrlFetcher::BuildRequestAndFetchResultFromHttpService( ...@@ -353,49 +412,55 @@ HRESULT WinHttpUrlFetcher::BuildRequestAndFetchResultFromHttpService(
const std::vector<std::pair<std::string, std::string>>& headers, const std::vector<std::pair<std::string, std::string>>& headers,
const base::Value& request_dict, const base::Value& request_dict,
const base::TimeDelta& request_timeout, const base::TimeDelta& request_timeout,
unsigned int request_retries,
base::Optional<base::Value>* request_result) { base::Optional<base::Value>* request_result) {
DCHECK(request_result); DCHECK(request_result);
auto url_fetcher = WinHttpUrlFetcher::Create(request_url);
if (!url_fetcher) {
LOGFN(ERROR) << "Could not create valid fetcher for url="
<< request_url.spec();
return E_FAIL;
}
url_fetcher->SetRequestHeader("Content-Type", "application/json");
url_fetcher->SetRequestHeader("Authorization",
("Bearer " + access_token).c_str());
for (auto& header : headers)
url_fetcher->SetRequestHeader(header.first.c_str(), header.second.c_str());
HRESULT hr = S_OK; HRESULT hr = S_OK;
std::string request_body;
if (request_dict.is_dict()) { if (request_dict.is_dict()) {
std::string body; if (!base::JSONWriter::Write(request_dict, &request_body)) {
if (!base::JSONWriter::Write(request_dict, &body)) {
LOGFN(ERROR) << "base::JSONWriter::Write failed"; LOGFN(ERROR) << "base::JSONWriter::Write failed";
return E_FAIL; return E_FAIL;
} }
hr = url_fetcher->SetRequestBody(body.c_str());
if (FAILED(hr)) {
LOGFN(ERROR) << "fetcher.SetRequestBody hr=" << putHR(hr);
return E_FAIL;
}
} }
if (!request_timeout.is_zero()) { for (unsigned int try_count = 0; try_count <= request_retries; ++try_count) {
url_fetcher->SetHttpRequestTimeout(request_timeout.InMilliseconds()); HttpServiceRequest* request = HttpServiceRequest::Create(
} request_url, access_token, headers, request_body, request_timeout);
if (!request)
return E_FAIL;
auto extracted_param = (new HttpServiceRequest(std::move(url_fetcher))) auto extracted_param =
->WaitForResponseFromHttpService(request_timeout); request->WaitForResponseFromHttpService(request_timeout);
if (!extracted_param) if (!extracted_param) {
return E_FAIL; hr = E_FAIL;
continue;
}
*request_result = std::move(extracted_param);
base::Value* error_detail =
(*request_result)->FindDictKey(kErrorKeyInRequestResult);
if (error_detail) {
hr = E_FAIL;
LOGFN(ERROR) << "error: " << *error_detail;
// If error code is known, retry only on retryable server errors.
base::Optional<int> error_code =
error_detail->FindIntKey(kHttpErrorCodeKeyNameInResponse);
if (error_code.has_value() &&
kRetryableHttpErrorCodes.find(error_code.value()) ==
kRetryableHttpErrorCodes.end())
break;
continue;
}
*request_result = std::move(extracted_param); hr = S_OK;
break;
}
return hr; return hr;
} }
......
...@@ -30,13 +30,17 @@ class WinHttpUrlFetcher { ...@@ -30,13 +30,17 @@ class WinHttpUrlFetcher {
// value pairs to be sent with the request. |request_dict| is a dictionary of // value pairs to be sent with the request. |request_dict| is a dictionary of
// json parameters to be sent with the request. This argument will be // json parameters to be sent with the request. This argument will be
// converted to a json string and sent as the body of the request. // converted to a json string and sent as the body of the request.
// |request_timeout| is the maximum time to wait for a response. // |request_timeout| is the maximum time to wait for a response. If the HTTP
// request times out or fails with an error response code that signifies an
// internal server error (HTTP codes >= 500) then the request will be retried
// |request_retries| number of times before the call is marked failed.
static HRESULT BuildRequestAndFetchResultFromHttpService( static HRESULT BuildRequestAndFetchResultFromHttpService(
const GURL& request_url, const GURL& request_url,
std::string access_token, std::string access_token,
const std::vector<std::pair<std::string, std::string>>& headers, const std::vector<std::pair<std::string, std::string>>& headers,
const base::Value& request_dict, const base::Value& request_dict,
const base::TimeDelta& request_timeout, const base::TimeDelta& request_timeout,
unsigned int request_retries,
base::Optional<base::Value>* request_result); base::Optional<base::Value>* request_result);
virtual ~WinHttpUrlFetcher(); virtual ~WinHttpUrlFetcher();
......
...@@ -13,14 +13,22 @@ namespace testing { ...@@ -13,14 +13,22 @@ namespace testing {
// Test the WinHttpUrlFetcher::BuildRequestAndFetchResultFromHttpService method // Test the WinHttpUrlFetcher::BuildRequestAndFetchResultFromHttpService method
// used to make various HTTP requests. // used to make various HTTP requests.
// Parameters are: // Parameters are:
// bool true: HTTP call succeeds. // 1. int - 0: HTTP call succeeds.
// false: Fails due to invalid response from server. // 1: Fails due to invalid response from server.
class GcpWinHttpUrlFetcherTest : public GlsRunnerTestBase, // 2: Fails due to a retryable HTTP error (like 503).
public ::testing::WithParamInterface<bool> {}; // 3: Fails due to a non-retryable HTTP error (like 404).
// 2. int - Number of retries allowed for a HTTP request.
class GcpWinHttpUrlFetcherTest
: public GlsRunnerTestBase,
public ::testing::WithParamInterface<std::tuple<int, int>> {};
TEST_P(GcpWinHttpUrlFetcherTest, TEST_P(GcpWinHttpUrlFetcherTest,
BuildRequestAndFetchResultFromHttpServiceTest) { BuildRequestAndFetchResultFromHttpServiceTest) {
bool invalid_response = GetParam(); bool valid_response = std::get<0>(GetParam()) == 0;
bool invalid_response = std::get<0>(GetParam()) == 1;
bool retryable_error_response = std::get<0>(GetParam()) == 2;
bool nonretryable_error_response = std::get<0>(GetParam()) == 3;
int num_retries = std::get<1>(GetParam());
const int timeout_in_millis = 12000; const int timeout_in_millis = 12000;
const std::string header1 = "test-header-1"; const std::string header1 = "test-header-1";
...@@ -42,23 +50,64 @@ TEST_P(GcpWinHttpUrlFetcherTest, ...@@ -42,23 +50,64 @@ TEST_P(GcpWinHttpUrlFetcherTest,
std::string expected_response; std::string expected_response;
base::JSONWriter::Write(expected_result, &expected_response); base::JSONWriter::Write(expected_result, &expected_response);
fake_http_url_fetcher_factory()->SetFakeResponse( std::string response;
test_url, FakeWinHttpUrlFetcher::Headers(), if (invalid_response) {
invalid_response ? "Invalid json response" : expected_response); response = "Invalid json response";
} else if (retryable_error_response) {
response =
"{\n\"error\": {"
"\"code\": 503,\n"
"\"message\": \"Service unavailable\","
"\"status\": \"UNAVAILABLE\"\n}\n}";
} else if (nonretryable_error_response) {
response =
"{\n\"error\": {"
"\"code\": 403,\n"
"\"message\": \"The caller does not have permission\","
"\"status\": \"PERMISSION_DENIED\"\n}\n}";
} else {
response = expected_response;
}
if (num_retries == 0) {
fake_http_url_fetcher_factory()->SetFakeResponse(
test_url, FakeWinHttpUrlFetcher::Headers(), response);
} else {
fake_http_url_fetcher_factory()->SetFakeResponseForSpecifiedNumRequests(
test_url, FakeWinHttpUrlFetcher::Headers(), response, num_retries);
fake_http_url_fetcher_factory()->SetFakeResponseForSpecifiedNumRequests(
test_url, FakeWinHttpUrlFetcher::Headers(), expected_response, 1);
}
fake_http_url_fetcher_factory()->SetCollectRequestData(true); fake_http_url_fetcher_factory()->SetCollectRequestData(true);
HRESULT hr = WinHttpUrlFetcher::BuildRequestAndFetchResultFromHttpService( HRESULT hr = WinHttpUrlFetcher::BuildRequestAndFetchResultFromHttpService(
test_url, access_token, {{header1, header1_value}}, request, test_url, access_token, {{header1, header1_value}}, request,
request_timeout, &request_result); request_timeout, num_retries, &request_result);
if (invalid_response) { if (num_retries == 0) {
ASSERT_TRUE(FAILED(hr)); if (invalid_response || retryable_error_response ||
nonretryable_error_response) {
ASSERT_TRUE(FAILED(hr));
} else {
ASSERT_EQ(S_OK, hr);
ASSERT_EQ(expected_result, request_result.value());
}
} else {
if (nonretryable_error_response) {
ASSERT_TRUE(FAILED(hr));
} else {
ASSERT_EQ(S_OK, hr);
ASSERT_EQ(expected_result, request_result.value());
}
}
if (valid_response || nonretryable_error_response) {
ASSERT_EQ(1UL, fake_http_url_fetcher_factory()->requests_created());
} else { } else {
ASSERT_EQ(S_OK, hr); ASSERT_EQ(num_retries + 1UL,
ASSERT_EQ(expected_result, request_result.value()); fake_http_url_fetcher_factory()->requests_created());
} }
ASSERT_TRUE(fake_http_url_fetcher_factory()->requests_created() > 0);
for (size_t idx = 0; for (size_t idx = 0;
idx < fake_http_url_fetcher_factory()->requests_created(); ++idx) { idx < fake_http_url_fetcher_factory()->requests_created(); ++idx) {
FakeWinHttpUrlFetcherFactory::RequestData request_data = FakeWinHttpUrlFetcherFactory::RequestData request_data =
...@@ -78,7 +127,8 @@ TEST_P(GcpWinHttpUrlFetcherTest, ...@@ -78,7 +127,8 @@ TEST_P(GcpWinHttpUrlFetcherTest,
INSTANTIATE_TEST_SUITE_P(All, INSTANTIATE_TEST_SUITE_P(All,
GcpWinHttpUrlFetcherTest, GcpWinHttpUrlFetcherTest,
::testing::Values(true, false)); ::testing::Combine(::testing::Values(0, 1, 2, 3),
::testing::Values(0, 1, 3)));
} // namespace testing } // namespace testing
} // namespace credential_provider } // namespace credential_provider
...@@ -641,8 +641,26 @@ void FakeWinHttpUrlFetcherFactory::SetFakeResponse( ...@@ -641,8 +641,26 @@ void FakeWinHttpUrlFetcherFactory::SetFakeResponse(
const WinHttpUrlFetcher::Headers& headers, const WinHttpUrlFetcher::Headers& headers,
const std::string& response, const std::string& response,
HANDLE send_response_event_handle /*=INVALID_HANDLE_VALUE*/) { HANDLE send_response_event_handle /*=INVALID_HANDLE_VALUE*/) {
fake_responses_[url] = fake_responses_[url].clear();
Response(headers, response, send_response_event_handle); fake_responses_[url].push_back(
Response(headers, response, send_response_event_handle));
remove_fake_response_when_created_ = false;
}
void FakeWinHttpUrlFetcherFactory::SetFakeResponseForSpecifiedNumRequests(
const GURL& url,
const WinHttpUrlFetcher::Headers& headers,
const std::string& response,
unsigned int num_requests,
HANDLE send_response_event_handle /* =INVALID_HANDLE_VALUE */) {
if (fake_responses_.find(url) == fake_responses_.end()) {
fake_responses_[url] = std::deque<Response>();
}
for (unsigned int i = 0; i < num_requests; ++i) {
fake_responses_[url].push_back(
Response(headers, response, send_response_event_handle));
}
remove_fake_response_when_created_ = true;
} }
void FakeWinHttpUrlFetcherFactory::SetFakeFailedResponse(const GURL& url, void FakeWinHttpUrlFetcherFactory::SetFakeFailedResponse(const GURL& url,
...@@ -667,11 +685,17 @@ std::unique_ptr<WinHttpUrlFetcher> FakeWinHttpUrlFetcherFactory::Create( ...@@ -667,11 +685,17 @@ std::unique_ptr<WinHttpUrlFetcher> FakeWinHttpUrlFetcherFactory::Create(
FakeWinHttpUrlFetcher* fetcher = new FakeWinHttpUrlFetcher(std::move(url)); FakeWinHttpUrlFetcher* fetcher = new FakeWinHttpUrlFetcher(std::move(url));
if (fake_responses_.count(url) != 0) { if (fake_responses_.count(url) != 0) {
const Response& response = fake_responses_[url]; const Response& response = fake_responses_[url].front();
fetcher->response_headers_ = response.headers; fetcher->response_headers_ = response.headers;
fetcher->response_ = response.response; fetcher->response_ = response.response;
fetcher->send_response_event_handle_ = response.send_response_event_handle; fetcher->send_response_event_handle_ = response.send_response_event_handle;
if (remove_fake_response_when_created_) {
fake_responses_[url].pop_front();
if (fake_responses_[url].empty())
fake_responses_.erase(url);
}
} else { } else {
DCHECK(failed_http_fetch_hr_.count(url) > 0); DCHECK(failed_http_fetch_hr_.count(url) > 0);
fetcher->response_hr_ = failed_http_fetch_hr_[url]; fetcher->response_hr_ = failed_http_fetch_hr_[url];
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#ifndef CHROME_CREDENTIAL_PROVIDER_TEST_GCP_FAKES_H_ #ifndef CHROME_CREDENTIAL_PROVIDER_TEST_GCP_FAKES_H_
#define CHROME_CREDENTIAL_PROVIDER_TEST_GCP_FAKES_H_ #define CHROME_CREDENTIAL_PROVIDER_TEST_GCP_FAKES_H_
#include <deque>
#include <map> #include <map>
#include <memory> #include <memory>
#include <string> #include <string>
...@@ -296,12 +297,23 @@ class FakeWinHttpUrlFetcherFactory { ...@@ -296,12 +297,23 @@ class FakeWinHttpUrlFetcherFactory {
FakeWinHttpUrlFetcherFactory(); FakeWinHttpUrlFetcherFactory();
~FakeWinHttpUrlFetcherFactory(); ~FakeWinHttpUrlFetcherFactory();
// Sets the given |response| for any number of HTTP requests made for |url|.
void SetFakeResponse( void SetFakeResponse(
const GURL& url, const GURL& url,
const WinHttpUrlFetcher::Headers& headers, const WinHttpUrlFetcher::Headers& headers,
const std::string& response, const std::string& response,
HANDLE send_response_event_handle = INVALID_HANDLE_VALUE); HANDLE send_response_event_handle = INVALID_HANDLE_VALUE);
// Queues the given |response| for the specified |num_requests| number of HTTP
// requests made for |url|. Different responses for the URL can be set by
// calling this function multiple times with different responses.
void SetFakeResponseForSpecifiedNumRequests(
const GURL& url,
const WinHttpUrlFetcher::Headers& headers,
const std::string& response,
unsigned int num_requests,
HANDLE send_response_event_handle = INVALID_HANDLE_VALUE);
// Sets the response as a failed http attempt. The return result // Sets the response as a failed http attempt. The return result
// from http_url_fetcher.Fetch() would be set as the input HRESULT // from http_url_fetcher.Fetch() would be set as the input HRESULT
// to this method. // to this method.
...@@ -343,10 +355,11 @@ class FakeWinHttpUrlFetcherFactory { ...@@ -343,10 +355,11 @@ class FakeWinHttpUrlFetcherFactory {
HANDLE send_response_event_handle; HANDLE send_response_event_handle;
}; };
std::map<GURL, Response> fake_responses_; std::map<GURL, std::deque<Response>> fake_responses_;
std::map<GURL, HRESULT> failed_http_fetch_hr_; std::map<GURL, HRESULT> failed_http_fetch_hr_;
size_t requests_created_ = 0; size_t requests_created_ = 0;
bool collect_request_data_ = false; bool collect_request_data_ = false;
bool remove_fake_response_when_created_ = false;
std::vector<RequestData> requests_data_; std::vector<RequestData> requests_data_;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment