| // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| // 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 <utility> |
| |
| #include "base/bind.h" |
| #include "base/callback_helpers.h" |
| #include "base/location.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/single_thread_task_runner.h" |
| #include "base/strings/string_util.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "net/base/net_errors.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() |
| : state_(State::WAIT_FOR_INIT), |
| generate_async_(false), |
| generate_rv_(OK), |
| auth_token_(NULL), |
| first_round_(true), |
| connection_based_(false), |
| allows_default_credentials_(false), |
| allows_explicit_credentials_(true), |
| weak_factory_(this) {} |
| |
| HttpAuthHandlerMock::~HttpAuthHandlerMock() = default; |
| |
| void HttpAuthHandlerMock::SetGenerateExpectation(bool async, int rv) { |
| generate_async_ = async; |
| generate_rv_ = rv; |
| } |
| |
| HttpAuth::AuthorizationResult HttpAuthHandlerMock::HandleAnotherChallenge( |
| 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 (!base::LowerCaseEqualsASCII(challenge->scheme(), "mock")) { |
| state_ = State::DONE; |
| return HttpAuth::AUTHORIZATION_RESULT_INVALID; |
| } |
| |
| state_ = State::WAIT_FOR_GENERATE_AUTH_TOKEN; |
| return HttpAuth::AUTHORIZATION_RESULT_ACCEPT; |
| } |
| |
| 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) { |
| 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_ == NULL); |
| callback_ = std::move(callback); |
| auth_token_ = auth_token; |
| base::ThreadTaskRunnerHandle::Get()->PostTask( |
| FROM_HERE, base::Bind(&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_; |
| } |
| } |
| |
| 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_ = NULL; |
| base::ResetAndReturn(&callback_).Run(generate_rv_); |
| } |
| |
| HttpAuthHandlerMock::Factory::Factory() |
| : do_init_from_challenge_(false) { |
| // TODO(cbentzel): Default do_init_from_challenge_ to true. |
| } |
| |
| HttpAuthHandlerMock::Factory::~Factory() = default; |
| |
| void HttpAuthHandlerMock::Factory::AddMockHandler( |
| HttpAuthHandler* handler, HttpAuth::Target target) { |
| handlers_[target].push_back(base::WrapUnique(handler)); |
| } |
| |
| int HttpAuthHandlerMock::Factory::CreateAuthHandler( |
| HttpAuthChallengeTokenizer* challenge, |
| HttpAuth::Target target, |
| const SSLInfo& ssl_info, |
| const GURL& origin, |
| CreateReason reason, |
| int nonce_count, |
| const NetLogWithSource& net_log, |
| std::unique_ptr<HttpAuthHandler>* handler) { |
| if (handlers_[target].empty()) |
| return ERR_UNEXPECTED; |
| std::unique_ptr<HttpAuthHandler> tmp_handler = |
| std::move(handlers_[target][0]); |
| std::vector<std::unique_ptr<HttpAuthHandler>>& handlers = handlers_[target]; |
| handlers.erase(handlers.begin()); |
| if (do_init_from_challenge_ && |
| !tmp_handler->InitFromChallenge(challenge, target, ssl_info, origin, |
| net_log)) |
| return ERR_INVALID_RESPONSE; |
| handler->swap(tmp_handler); |
| return OK; |
| } |
| |
| } // namespace net |