// Copyright 2011 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "net/http/http_auth_handler_mock.h" #include #include "base/bind.h" #include "base/location.h" #include "base/memory/ptr_util.h" #include "base/strings/string_util.h" #include "base/task/single_thread_task_runner.h" #include "base/threading/thread_task_runner_handle.h" #include "net/base/net_errors.h" #include "net/dns/host_resolver.h" #include "net/http/http_auth_challenge_tokenizer.h" #include "net/http/http_request_info.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" namespace net { void PrintTo(const HttpAuthHandlerMock::State& state, ::std::ostream* os) { switch (state) { case HttpAuthHandlerMock::State::WAIT_FOR_INIT: *os << "WAIT_FOR_INIT"; break; case HttpAuthHandlerMock::State::WAIT_FOR_CHALLENGE: *os << "WAIT_FOR_CHALLENGE"; break; case HttpAuthHandlerMock::State::WAIT_FOR_GENERATE_AUTH_TOKEN: *os << "WAIT_FOR_GENERATE_AUTH_TOKEN"; break; case HttpAuthHandlerMock::State::TOKEN_PENDING: *os << "TOKEN_PENDING"; break; case HttpAuthHandlerMock::State::DONE: *os << "DONE"; break; } } HttpAuthHandlerMock::HttpAuthHandlerMock() = default; HttpAuthHandlerMock::~HttpAuthHandlerMock() = default; void HttpAuthHandlerMock::SetGenerateExpectation(bool async, int rv) { generate_async_ = async; generate_rv_ = rv; } bool HttpAuthHandlerMock::NeedsIdentity() { return first_round_; } bool HttpAuthHandlerMock::AllowsDefaultCredentials() { return allows_default_credentials_; } bool HttpAuthHandlerMock::AllowsExplicitCredentials() { return allows_explicit_credentials_; } bool HttpAuthHandlerMock::Init( HttpAuthChallengeTokenizer* challenge, const SSLInfo& ssl_info, const NetworkAnonymizationKey& network_anonymization_key) { EXPECT_EQ(State::WAIT_FOR_INIT, state_); state_ = State::WAIT_FOR_GENERATE_AUTH_TOKEN; auth_scheme_ = HttpAuth::AUTH_SCHEME_MOCK; score_ = 1; properties_ = connection_based_ ? IS_CONNECTION_BASED : 0; return true; } int HttpAuthHandlerMock::GenerateAuthTokenImpl( const AuthCredentials* credentials, const HttpRequestInfo* request, CompletionOnceCallback callback, std::string* auth_token) { EXPECT_EQ(State::WAIT_FOR_GENERATE_AUTH_TOKEN, state_); first_round_ = false; request_url_ = request->url; if (generate_async_) { EXPECT_TRUE(callback_.is_null()); EXPECT_TRUE(auth_token_ == nullptr); callback_ = std::move(callback); auth_token_ = auth_token; base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(&HttpAuthHandlerMock::OnGenerateAuthToken, weak_factory_.GetWeakPtr())); state_ = State::TOKEN_PENDING; return ERR_IO_PENDING; } else { if (generate_rv_ == OK) { *auth_token = "auth_token"; state_ = is_connection_based() ? State::WAIT_FOR_CHALLENGE : State::WAIT_FOR_GENERATE_AUTH_TOKEN; } else { state_ = State::DONE; } return generate_rv_; } } HttpAuth::AuthorizationResult HttpAuthHandlerMock::HandleAnotherChallengeImpl( HttpAuthChallengeTokenizer* challenge) { EXPECT_THAT(state_, ::testing::AnyOf(State::WAIT_FOR_CHALLENGE, State::WAIT_FOR_GENERATE_AUTH_TOKEN)); // If we receive an empty challenge for a connection based scheme, or a second // challenge for a non connection based scheme, assume it's a rejection. if (!is_connection_based() || challenge->base64_param().empty()) { state_ = State::DONE; return HttpAuth::AUTHORIZATION_RESULT_REJECT; } if (challenge->auth_scheme() != "mock") { state_ = State::DONE; return HttpAuth::AUTHORIZATION_RESULT_INVALID; } state_ = State::WAIT_FOR_GENERATE_AUTH_TOKEN; return HttpAuth::AUTHORIZATION_RESULT_ACCEPT; } void HttpAuthHandlerMock::OnGenerateAuthToken() { EXPECT_TRUE(generate_async_); EXPECT_TRUE(!callback_.is_null()); EXPECT_EQ(State::TOKEN_PENDING, state_); if (generate_rv_ == OK) { *auth_token_ = "auth_token"; state_ = is_connection_based() ? State::WAIT_FOR_CHALLENGE : State::WAIT_FOR_GENERATE_AUTH_TOKEN; } else { state_ = State::DONE; } auth_token_ = nullptr; std::move(callback_).Run(generate_rv_); } HttpAuthHandlerMock::Factory::Factory() { // TODO(cbentzel): Default do_init_from_challenge_ to true. } HttpAuthHandlerMock::Factory::~Factory() = default; void HttpAuthHandlerMock::Factory::AddMockHandler( std::unique_ptr handler, HttpAuth::Target target) { handlers_[target].push_back(std::move(handler)); } int HttpAuthHandlerMock::Factory::CreateAuthHandler( HttpAuthChallengeTokenizer* challenge, HttpAuth::Target target, const SSLInfo& ssl_info, const NetworkAnonymizationKey& network_anonymization_key, const url::SchemeHostPort& scheme_host_port, CreateReason reason, int nonce_count, const NetLogWithSource& net_log, HostResolver* host_resolver, std::unique_ptr* handler) { if (handlers_[target].empty()) return ERR_UNEXPECTED; std::unique_ptr tmp_handler = std::move(handlers_[target][0]); std::vector>& handlers = handlers_[target]; handlers.erase(handlers.begin()); if (do_init_from_challenge_ && !tmp_handler->InitFromChallenge(challenge, target, ssl_info, network_anonymization_key, scheme_host_port, net_log)) { return ERR_INVALID_RESPONSE; } handler->swap(tmp_handler); return OK; } } // namespace net