123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685 |
- // Copyright 2014 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_transaction_test_util.h"
- #include <algorithm>
- #include <unordered_map>
- #include <utility>
- #include "base/bind.h"
- #include "base/callback_helpers.h"
- #include "base/location.h"
- #include "base/run_loop.h"
- #include "base/strings/stringprintf.h"
- #include "base/task/single_thread_task_runner.h"
- #include "base/threading/thread_task_runner_handle.h"
- #include "base/time/clock.h"
- #include "base/time/time.h"
- #include "net/base/ip_address.h"
- #include "net/base/ip_endpoint.h"
- #include "net/base/load_flags.h"
- #include "net/base/load_timing_info.h"
- #include "net/base/net_errors.h"
- #include "net/base/network_isolation_key.h"
- #include "net/base/schemeful_site.h"
- #include "net/cert/x509_certificate.h"
- #include "net/disk_cache/disk_cache.h"
- #include "net/http/http_cache.h"
- #include "net/http/http_request_info.h"
- #include "net/http/http_response_info.h"
- #include "net/http/http_transaction.h"
- #include "net/log/net_log.h"
- #include "net/log/net_log_source.h"
- #include "net/ssl/ssl_private_key.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #include "url/gurl.h"
- namespace net {
- namespace {
- using MockTransactionMap =
- std::unordered_map<std::string, const MockTransaction*>;
- static MockTransactionMap mock_transactions;
- } // namespace
- TransportInfo DefaultTransportInfo() {
- return TransportInfo(TransportType::kDirect,
- IPEndPoint(IPAddress::IPv4Localhost(), 80), "");
- }
- //-----------------------------------------------------------------------------
- // mock transaction data
- const MockTransaction kSimpleGET_Transaction = {
- "http://www.google.com/",
- "GET",
- base::Time(),
- "",
- LOAD_NORMAL,
- DefaultTransportInfo(),
- "HTTP/1.1 200 OK",
- "Cache-Control: max-age=10000\n",
- base::Time(),
- "<html><body>Google Blah Blah</body></html>",
- {},
- TEST_MODE_NORMAL,
- nullptr,
- nullptr,
- nullptr,
- 0,
- 0,
- OK,
- OK,
- };
- const MockTransaction kSimplePOST_Transaction = {
- "http://bugdatabase.com/edit",
- "POST",
- base::Time(),
- "",
- LOAD_NORMAL,
- DefaultTransportInfo(),
- "HTTP/1.1 200 OK",
- "",
- base::Time(),
- "<html><body>Google Blah Blah</body></html>",
- {},
- TEST_MODE_NORMAL,
- nullptr,
- nullptr,
- nullptr,
- 0,
- 0,
- OK,
- OK,
- };
- const MockTransaction kTypicalGET_Transaction = {
- "http://www.example.com/~foo/bar.html",
- "GET",
- base::Time(),
- "",
- LOAD_NORMAL,
- DefaultTransportInfo(),
- "HTTP/1.1 200 OK",
- "Date: Wed, 28 Nov 2007 09:40:09 GMT\n"
- "Last-Modified: Wed, 28 Nov 2007 00:40:09 GMT\n",
- base::Time(),
- "<html><body>Google Blah Blah</body></html>",
- {},
- TEST_MODE_NORMAL,
- nullptr,
- nullptr,
- nullptr,
- 0,
- 0,
- OK,
- OK,
- };
- const MockTransaction kETagGET_Transaction = {
- "http://www.google.com/foopy",
- "GET",
- base::Time(),
- "",
- LOAD_NORMAL,
- DefaultTransportInfo(),
- "HTTP/1.1 200 OK",
- "Cache-Control: max-age=10000\n"
- "Etag: \"foopy\"\n",
- base::Time(),
- "<html><body>Google Blah Blah</body></html>",
- {},
- TEST_MODE_NORMAL,
- nullptr,
- nullptr,
- nullptr,
- 0,
- 0,
- OK,
- OK,
- };
- const MockTransaction kRangeGET_Transaction = {
- "http://www.google.com/",
- "GET",
- base::Time(),
- "Range: 0-100\r\n",
- LOAD_NORMAL,
- DefaultTransportInfo(),
- "HTTP/1.1 200 OK",
- "Cache-Control: max-age=10000\n",
- base::Time(),
- "<html><body>Google Blah Blah</body></html>",
- {},
- TEST_MODE_NORMAL,
- nullptr,
- nullptr,
- nullptr,
- 0,
- 0,
- OK,
- OK,
- };
- static const MockTransaction* const kBuiltinMockTransactions[] = {
- &kSimpleGET_Transaction,
- &kSimplePOST_Transaction,
- &kTypicalGET_Transaction,
- &kETagGET_Transaction,
- &kRangeGET_Transaction
- };
- const MockTransaction* FindMockTransaction(const GURL& url) {
- // look for overrides:
- MockTransactionMap::const_iterator it = mock_transactions.find(url.spec());
- if (it != mock_transactions.end())
- return it->second;
- // look for builtins:
- for (const auto* transaction : kBuiltinMockTransactions) {
- if (url == GURL(transaction->url))
- return transaction;
- }
- return nullptr;
- }
- void AddMockTransaction(const MockTransaction* trans) {
- mock_transactions[GURL(trans->url).spec()] = trans;
- }
- void RemoveMockTransaction(const MockTransaction* trans) {
- mock_transactions.erase(GURL(trans->url).spec());
- }
- MockHttpRequest::MockHttpRequest(const MockTransaction& t) {
- url = GURL(t.url);
- method = t.method;
- extra_headers.AddHeadersFromString(t.request_headers);
- load_flags = t.load_flags;
- SchemefulSite site(url);
- network_isolation_key = NetworkIsolationKey(site, site);
- }
- std::string MockHttpRequest::CacheKey() {
- return *HttpCache::GenerateCacheKeyForRequest(this);
- }
- //-----------------------------------------------------------------------------
- // static
- int TestTransactionConsumer::quit_counter_ = 0;
- TestTransactionConsumer::TestTransactionConsumer(
- RequestPriority priority,
- HttpTransactionFactory* factory) {
- // Disregard the error code.
- factory->CreateTransaction(priority, &trans_);
- ++quit_counter_;
- }
- TestTransactionConsumer::~TestTransactionConsumer() = default;
- void TestTransactionConsumer::Start(const HttpRequestInfo* request,
- const NetLogWithSource& net_log) {
- state_ = State::kStarting;
- int result =
- trans_->Start(request,
- base::BindOnce(&TestTransactionConsumer::OnIOComplete,
- base::Unretained(this)),
- net_log);
- if (result != ERR_IO_PENDING)
- DidStart(result);
- }
- void TestTransactionConsumer::DidStart(int result) {
- if (result != OK) {
- DidFinish(result);
- } else {
- Read();
- }
- }
- void TestTransactionConsumer::DidRead(int result) {
- if (result <= 0) {
- DidFinish(result);
- } else {
- content_.append(read_buf_->data(), result);
- Read();
- }
- }
- void TestTransactionConsumer::DidFinish(int result) {
- state_ = State::kDone;
- error_ = result;
- if (--quit_counter_ == 0)
- base::RunLoop::QuitCurrentWhenIdleDeprecated();
- }
- void TestTransactionConsumer::Read() {
- state_ = State::kReading;
- read_buf_ = base::MakeRefCounted<IOBuffer>(1024);
- int result =
- trans_->Read(read_buf_.get(), 1024,
- base::BindOnce(&TestTransactionConsumer::OnIOComplete,
- base::Unretained(this)));
- if (result != ERR_IO_PENDING)
- DidRead(result);
- }
- void TestTransactionConsumer::OnIOComplete(int result) {
- switch (state_) {
- case State::kStarting:
- DidStart(result);
- break;
- case State::kReading:
- DidRead(result);
- break;
- default:
- NOTREACHED();
- }
- }
- MockNetworkTransaction::MockNetworkTransaction(RequestPriority priority,
- MockNetworkLayer* factory)
- : priority_(priority), transaction_factory_(factory->AsWeakPtr()) {}
- MockNetworkTransaction::~MockNetworkTransaction() {
- // Use request_ as in ~HttpNetworkTransaction to make sure its valid and not
- // already freed by the consumer. Only check till Read is invoked since
- // HttpNetworkTransaction sets request_ to nullptr when Read is invoked.
- // See crbug.com/734037.
- if (request_ && !reading_)
- DCHECK(request_->load_flags >= 0);
- }
- int MockNetworkTransaction::Start(const HttpRequestInfo* request,
- CompletionOnceCallback callback,
- const NetLogWithSource& net_log) {
- if (request_)
- return ERR_FAILED;
- request_ = request;
- return StartInternal(request, std::move(callback), net_log);
- }
- int MockNetworkTransaction::RestartIgnoringLastError(
- CompletionOnceCallback callback) {
- return ERR_FAILED;
- }
- int MockNetworkTransaction::RestartWithCertificate(
- scoped_refptr<X509Certificate> client_cert,
- scoped_refptr<SSLPrivateKey> client_private_key,
- CompletionOnceCallback callback) {
- return ERR_FAILED;
- }
- int MockNetworkTransaction::RestartWithAuth(const AuthCredentials& credentials,
- CompletionOnceCallback callback) {
- if (!IsReadyToRestartForAuth())
- return ERR_FAILED;
- HttpRequestInfo auth_request_info = *request_;
- auth_request_info.extra_headers.SetHeader("Authorization", "Bar");
- // Let the MockTransactionHandler worry about this: the only way for this
- // test to succeed is by using an explicit handler for the transaction so
- // that server behavior can be simulated.
- return StartInternal(&auth_request_info, std::move(callback),
- NetLogWithSource());
- }
- void MockNetworkTransaction::PopulateNetErrorDetails(
- NetErrorDetails* /*details*/) const {
- NOTIMPLEMENTED();
- }
- bool MockNetworkTransaction::IsReadyToRestartForAuth() {
- if (!request_)
- return false;
- if (!request_->extra_headers.HasHeader("X-Require-Mock-Auth"))
- return false;
- // Allow the mock server to decide whether authentication is required or not.
- std::string status_line = response_.headers->GetStatusLine();
- return status_line.find(" 401 ") != std::string::npos ||
- status_line.find(" 407 ") != std::string::npos;
- }
- int MockNetworkTransaction::Read(net::IOBuffer* buf,
- int buf_len,
- CompletionOnceCallback callback) {
- const MockTransaction* t = FindMockTransaction(request_->url);
- DCHECK(t);
- CHECK(!done_reading_called_);
- reading_ = true;
- int num = t->read_return_code;
- if (OK == num) {
- if (read_handler_) {
- num = (*read_handler_)(content_length_, data_cursor_, buf, buf_len);
- data_cursor_ += num;
- } else {
- int data_len = static_cast<int>(data_.size());
- num = std::min(static_cast<int64_t>(buf_len), data_len - data_cursor_);
- if (test_mode_ & TEST_MODE_SLOW_READ)
- num = std::min(num, 1);
- if (num) {
- memcpy(buf->data(), data_.data() + data_cursor_, num);
- data_cursor_ += num;
- }
- }
- }
- if (test_mode_ & TEST_MODE_SYNC_NET_READ)
- return num;
- CallbackLater(std::move(callback), num);
- return ERR_IO_PENDING;
- }
- void MockNetworkTransaction::StopCaching() {
- if (transaction_factory_.get())
- transaction_factory_->TransactionStopCaching();
- }
- int64_t MockNetworkTransaction::GetTotalReceivedBytes() const {
- return received_bytes_;
- }
- int64_t MockNetworkTransaction::GetTotalSentBytes() const {
- return sent_bytes_;
- }
- void MockNetworkTransaction::DoneReading() {
- CHECK(!done_reading_called_);
- done_reading_called_ = true;
- if (transaction_factory_.get())
- transaction_factory_->TransactionDoneReading();
- }
- const HttpResponseInfo* MockNetworkTransaction::GetResponseInfo() const {
- return &response_;
- }
- LoadState MockNetworkTransaction::GetLoadState() const {
- if (data_cursor_)
- return LOAD_STATE_READING_RESPONSE;
- return LOAD_STATE_IDLE;
- }
- void MockNetworkTransaction::SetQuicServerInfo(
- QuicServerInfo* quic_server_info) {
- }
- bool MockNetworkTransaction::GetLoadTimingInfo(
- LoadTimingInfo* load_timing_info) const {
- if (socket_log_id_ != NetLogSource::kInvalidId) {
- // The minimal set of times for a request that gets a response, assuming it
- // gets a new socket.
- load_timing_info->socket_reused = false;
- load_timing_info->socket_log_id = socket_log_id_;
- load_timing_info->connect_timing.connect_start = base::TimeTicks::Now();
- load_timing_info->connect_timing.connect_end = base::TimeTicks::Now();
- load_timing_info->send_start = base::TimeTicks::Now();
- load_timing_info->send_end = base::TimeTicks::Now();
- } else {
- // If there's no valid socket ID, just use the generic socket reused values.
- // No tests currently depend on this, just should not match the values set
- // by a cache hit.
- load_timing_info->socket_reused = true;
- load_timing_info->send_start = base::TimeTicks::Now();
- load_timing_info->send_end = base::TimeTicks::Now();
- }
- return true;
- }
- bool MockNetworkTransaction::GetRemoteEndpoint(IPEndPoint* endpoint) const {
- *endpoint = IPEndPoint(IPAddress(127, 0, 0, 1), 80);
- return true;
- }
- void MockNetworkTransaction::SetPriority(RequestPriority priority) {
- priority_ = priority;
- }
- void MockNetworkTransaction::SetWebSocketHandshakeStreamCreateHelper(
- WebSocketHandshakeStreamBase::CreateHelper* create_helper) {
- websocket_handshake_stream_create_helper_ = create_helper;
- }
- // static
- const int64_t MockNetworkTransaction::kTotalReceivedBytes = 1000;
- // static
- const int64_t MockNetworkTransaction::kTotalSentBytes = 100;
- int MockNetworkTransaction::StartInternal(const HttpRequestInfo* request,
- CompletionOnceCallback callback,
- const NetLogWithSource& net_log) {
- const MockTransaction* t = FindMockTransaction(request->url);
- if (!t)
- return ERR_FAILED;
- test_mode_ = t->test_mode;
- // Return immediately if we're returning an error.
- if (OK != t->start_return_code) {
- if (test_mode_ & TEST_MODE_SYNC_NET_START)
- return t->start_return_code;
- CallbackLater(std::move(callback), t->start_return_code);
- return ERR_IO_PENDING;
- }
- sent_bytes_ = kTotalSentBytes;
- received_bytes_ = kTotalReceivedBytes;
- std::string resp_status = t->status;
- std::string resp_headers = t->response_headers;
- std::string resp_data = t->data;
- if (t->handler)
- (t->handler)(request, &resp_status, &resp_headers, &resp_data);
- if (t->read_handler)
- read_handler_ = t->read_handler;
- std::string header_data = base::StringPrintf(
- "%s\n%s\n", resp_status.c_str(), resp_headers.c_str());
- std::replace(header_data.begin(), header_data.end(), '\n', '\0');
- response_.request_time = transaction_factory_->Now();
- if (!t->request_time.is_null())
- response_.request_time = t->request_time;
- response_.was_cached = false;
- response_.network_accessed = true;
- response_.remote_endpoint = t->transport_info.endpoint;
- response_.was_fetched_via_proxy =
- t->transport_info.type == TransportType::kProxied;
- response_.response_time = transaction_factory_->Now();
- if (!t->response_time.is_null())
- response_.response_time = t->response_time;
- response_.headers = base::MakeRefCounted<HttpResponseHeaders>(header_data);
- response_.ssl_info.cert = t->cert;
- response_.ssl_info.cert_status = t->cert_status;
- response_.ssl_info.connection_status = t->ssl_connection_status;
- response_.dns_aliases = t->dns_aliases;
- data_ = resp_data;
- content_length_ = response_.headers->GetContentLength();
- if (net_log.net_log())
- socket_log_id_ = net_log.net_log()->NextID();
- if (request_->load_flags & LOAD_PREFETCH)
- response_.unused_since_prefetch = true;
- if (request_->load_flags & LOAD_RESTRICTED_PREFETCH) {
- DCHECK(response_.unused_since_prefetch);
- response_.restricted_prefetch = true;
- }
- // Pause and resume.
- if (!before_network_start_callback_.is_null()) {
- bool defer = false;
- std::move(before_network_start_callback_).Run(&defer);
- if (defer) {
- resume_start_callback_ = std::move(callback);
- return net::ERR_IO_PENDING;
- }
- }
- if (test_mode_ & TEST_MODE_SYNC_NET_START)
- return OK;
- int result = OK;
- if (!connected_callback_.is_null()) {
- result = connected_callback_.Run(t->transport_info, base::DoNothing());
- }
- CallbackLater(std::move(callback), result);
- return ERR_IO_PENDING;
- }
- void MockNetworkTransaction::SetBeforeNetworkStartCallback(
- BeforeNetworkStartCallback callback) {
- before_network_start_callback_ = std::move(callback);
- }
- void MockNetworkTransaction::SetConnectedCallback(
- const ConnectedCallback& callback) {
- connected_callback_ = callback;
- }
- int MockNetworkTransaction::ResumeNetworkStart() {
- DCHECK(!resume_start_callback_.is_null());
- CallbackLater(std::move(resume_start_callback_), OK);
- return ERR_IO_PENDING;
- }
- ConnectionAttempts MockNetworkTransaction::GetConnectionAttempts() const {
- // TODO(ricea): Replace this with a proper implementation if needed.
- return {};
- }
- void MockNetworkTransaction::CloseConnectionOnDestruction() {
- NOTIMPLEMENTED();
- }
- void MockNetworkTransaction::CallbackLater(CompletionOnceCallback callback,
- int result) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(&MockNetworkTransaction::RunCallback,
- weak_factory_.GetWeakPtr(), std::move(callback), result));
- }
- void MockNetworkTransaction::RunCallback(CompletionOnceCallback callback,
- int result) {
- std::move(callback).Run(result);
- }
- MockNetworkLayer::MockNetworkLayer() = default;
- MockNetworkLayer::~MockNetworkLayer() = default;
- void MockNetworkLayer::TransactionDoneReading() {
- CHECK(!done_reading_called_);
- done_reading_called_ = true;
- }
- void MockNetworkLayer::TransactionStopCaching() {
- stop_caching_called_ = true;
- }
- void MockNetworkLayer::ResetTransactionCount() {
- transaction_count_ = 0;
- }
- int MockNetworkLayer::CreateTransaction(
- RequestPriority priority,
- std::unique_ptr<HttpTransaction>* trans) {
- transaction_count_++;
- last_create_transaction_priority_ = priority;
- auto mock_transaction =
- std::make_unique<MockNetworkTransaction>(priority, this);
- last_transaction_ = mock_transaction->AsWeakPtr();
- *trans = std::move(mock_transaction);
- return OK;
- }
- HttpCache* MockNetworkLayer::GetCache() {
- return nullptr;
- }
- HttpNetworkSession* MockNetworkLayer::GetSession() {
- return nullptr;
- }
- void MockNetworkLayer::SetClock(base::Clock* clock) {
- DCHECK(!clock_);
- clock_ = clock;
- }
- base::Time MockNetworkLayer::Now() {
- if (clock_)
- return clock_->Now();
- return base::Time::Now();
- }
- //-----------------------------------------------------------------------------
- // helpers
- int ReadTransaction(HttpTransaction* trans, std::string* result) {
- int rv;
- std::string content;
- do {
- TestCompletionCallback callback;
- scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(256);
- rv = trans->Read(buf.get(), 256, callback.callback());
- if (rv == ERR_IO_PENDING) {
- rv = callback.WaitForResult();
- base::RunLoop().RunUntilIdle();
- }
- if (rv > 0)
- content.append(buf->data(), rv);
- else if (rv < 0)
- return rv;
- } while (rv > 0);
- result->swap(content);
- return OK;
- }
- //-----------------------------------------------------------------------------
- // connected callback handler
- ConnectedHandler::ConnectedHandler() = default;
- ConnectedHandler::~ConnectedHandler() = default;
- ConnectedHandler::ConnectedHandler(const ConnectedHandler&) = default;
- ConnectedHandler& ConnectedHandler::operator=(const ConnectedHandler&) =
- default;
- ConnectedHandler::ConnectedHandler(ConnectedHandler&&) = default;
- ConnectedHandler& ConnectedHandler::operator=(ConnectedHandler&&) = default;
- int ConnectedHandler::OnConnected(const TransportInfo& info,
- CompletionOnceCallback callback) {
- transports_.push_back(info);
- if (run_callback_) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(std::move(callback), result_));
- return net::ERR_IO_PENDING;
- }
- return result_;
- }
- } // namespace net
|