root/net/http/http_pipelined_network_transaction_unittest.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. AddObserver
  2. RemoveObserver
  3. GetLatestProxyConfig
  4. IncrementConfigId
  5. pool_
  6. Initialize
  7. AddExpectedConnection
  8. GetRequestInfo
  9. ExpectResponse
  10. CompleteTwoRequests
  11. CompleteFourRequests
  12. TEST_F
  13. TEST_F
  14. TEST_F
  15. TEST_F
  16. TEST_F
  17. TEST_F
  18. TEST_F
  19. TEST_F
  20. TEST_F
  21. TEST_F
  22. TEST_F
  23. TEST_F
  24. current_task_
  25. WillProcessTask
  26. DidProcessTask
  27. TEST_F
  28. TEST_F
  29. TEST_F
  30. TEST_F
  31. TEST_F
  32. TEST_F

// Copyright (c) 2012 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 <string>

#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "net/base/address_list.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
#include "net/base/request_priority.h"
#include "net/dns/host_cache.h"
#include "net/dns/mock_host_resolver.h"
#include "net/http/http_auth_challenge_tokenizer.h"
#include "net/http/http_auth_handler_mock.h"
#include "net/http/http_network_session.h"
#include "net/http/http_network_transaction.h"
#include "net/http/http_request_info.h"
#include "net/http/http_server_properties_impl.h"
#include "net/proxy/proxy_config_service.h"
#include "net/proxy/proxy_service.h"
#include "net/socket/client_socket_handle.h"
#include "net/socket/client_socket_pool_histograms.h"
#include "net/socket/client_socket_pool_manager.h"
#include "net/socket/socket_test_util.h"
#include "net/ssl/ssl_config_service_defaults.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

using testing::StrEq;

namespace net {

namespace {

class SimpleProxyConfigService : public ProxyConfigService {
 public:
  virtual void AddObserver(Observer* observer) OVERRIDE {
    observer_ = observer;
  }

  virtual void RemoveObserver(Observer* observer) OVERRIDE {
    if (observer_ == observer) {
      observer_ = NULL;
    }
  }

  virtual ConfigAvailability GetLatestProxyConfig(
      ProxyConfig* config) OVERRIDE {
    *config = config_;
    return CONFIG_VALID;
  }

  void IncrementConfigId() {
    config_.set_id(config_.id() + 1);
    observer_->OnProxyConfigChanged(config_, ProxyConfigService::CONFIG_VALID);
  }

 private:
  ProxyConfig config_;
  Observer* observer_;
};

class HttpPipelinedNetworkTransactionTest : public testing::Test {
 public:
  HttpPipelinedNetworkTransactionTest()
      : histograms_("a"),
        pool_(1, 1, &histograms_, &factory_) {
  }

  void Initialize(bool force_http_pipelining) {
    // Normally, this code could just go in SetUp(). For a few of these tests,
    // we change the default number of sockets per group. That needs to be done
    // before we construct the HttpNetworkSession.
    proxy_config_service_ = new SimpleProxyConfigService();
    proxy_service_.reset(new ProxyService(proxy_config_service_, NULL, NULL));
    ssl_config_ = new SSLConfigServiceDefaults;
    auth_handler_factory_.reset(new HttpAuthHandlerMock::Factory());

    HttpNetworkSession::Params session_params;
    session_params.client_socket_factory = &factory_;
    session_params.proxy_service = proxy_service_.get();
    session_params.host_resolver = &mock_resolver_;
    session_params.ssl_config_service = ssl_config_.get();
    session_params.http_auth_handler_factory = auth_handler_factory_.get();
    session_params.http_server_properties =
        http_server_properties_.GetWeakPtr();
    session_params.force_http_pipelining = force_http_pipelining;
    session_params.http_pipelining_enabled = true;
    session_ = new HttpNetworkSession(session_params);
  }

  void AddExpectedConnection(MockRead* reads, size_t reads_count,
                             MockWrite* writes, size_t writes_count) {
    DeterministicSocketData* data = new DeterministicSocketData(
        reads, reads_count, writes, writes_count);
    data->set_connect_data(MockConnect(SYNCHRONOUS, OK));
    if (reads_count || writes_count) {
      data->StopAfter(reads_count + writes_count);
    }
    factory_.AddSocketDataProvider(data);
    data_vector_.push_back(data);
  }

  enum RequestInfoOptions {
    REQUEST_DEFAULT,
    REQUEST_MAIN_RESOURCE,
  };

  HttpRequestInfo* GetRequestInfo(
      const char* filename, RequestInfoOptions options = REQUEST_DEFAULT) {
    std::string url = base::StringPrintf("http://localhost/%s", filename);
    HttpRequestInfo* request_info = new HttpRequestInfo;
    request_info->url = GURL(url);
    request_info->method = "GET";
    if (options == REQUEST_MAIN_RESOURCE) {
      request_info->load_flags = LOAD_MAIN_FRAME;
    }
    request_info_vector_.push_back(request_info);
    return request_info;
  }

  void ExpectResponse(const std::string& expected,
                      HttpNetworkTransaction& transaction,
                      IoMode io_mode) {
    scoped_refptr<IOBuffer> buffer(new IOBuffer(expected.size()));
    if (io_mode == ASYNC) {
      EXPECT_EQ(ERR_IO_PENDING, transaction.Read(buffer.get(), expected.size(),
                                                 callback_.callback()));
      data_vector_[0]->RunFor(1);
      EXPECT_EQ(static_cast<int>(expected.length()), callback_.WaitForResult());
    } else {
      EXPECT_EQ(static_cast<int>(expected.size()),
                transaction.Read(buffer.get(), expected.size(),
                                 callback_.callback()));
    }
    std::string actual(buffer->data(), expected.size());
    EXPECT_THAT(actual, StrEq(expected));
    EXPECT_EQ(OK, transaction.Read(buffer.get(), expected.size(),
                                   callback_.callback()));
  }

  void CompleteTwoRequests(int data_index, int stop_at_step) {
    scoped_ptr<HttpNetworkTransaction> one_transaction(
        new HttpNetworkTransaction(DEFAULT_PRIORITY, session_.get()));
    TestCompletionCallback one_callback;
    EXPECT_EQ(ERR_IO_PENDING,
              one_transaction->Start(GetRequestInfo("one.html"),
                                     one_callback.callback(), BoundNetLog()));
    EXPECT_EQ(OK, one_callback.WaitForResult());

    HttpNetworkTransaction two_transaction(DEFAULT_PRIORITY, session_.get());
    TestCompletionCallback two_callback;
    EXPECT_EQ(ERR_IO_PENDING,
              two_transaction.Start(GetRequestInfo("two.html"),
                                    two_callback.callback(), BoundNetLog()));

    TestCompletionCallback one_read_callback;
    scoped_refptr<IOBuffer> buffer(new IOBuffer(8));
    EXPECT_EQ(ERR_IO_PENDING,
              one_transaction->Read(buffer.get(), 8,
                                    one_read_callback.callback()));

    data_vector_[data_index]->SetStop(stop_at_step);
    data_vector_[data_index]->Run();
    EXPECT_EQ(8, one_read_callback.WaitForResult());
    data_vector_[data_index]->SetStop(10);
    std::string actual(buffer->data(), 8);
    EXPECT_THAT(actual, StrEq("one.html"));
    EXPECT_EQ(OK, one_transaction->Read(buffer.get(), 8,
                                        one_read_callback.callback()));

    EXPECT_EQ(OK, two_callback.WaitForResult());
    ExpectResponse("two.html", two_transaction, SYNCHRONOUS);
  }

  void CompleteFourRequests(RequestInfoOptions options) {
    scoped_ptr<HttpNetworkTransaction> one_transaction(
        new HttpNetworkTransaction(DEFAULT_PRIORITY, session_.get()));
    TestCompletionCallback one_callback;
    EXPECT_EQ(ERR_IO_PENDING,
              one_transaction->Start(GetRequestInfo("one.html", options),
                                     one_callback.callback(), BoundNetLog()));
    EXPECT_EQ(OK, one_callback.WaitForResult());

    HttpNetworkTransaction two_transaction(DEFAULT_PRIORITY, session_.get());
    TestCompletionCallback two_callback;
    EXPECT_EQ(ERR_IO_PENDING,
              two_transaction.Start(GetRequestInfo("two.html", options),
                                    two_callback.callback(), BoundNetLog()));

    HttpNetworkTransaction three_transaction(DEFAULT_PRIORITY, session_.get());
    TestCompletionCallback three_callback;
    EXPECT_EQ(ERR_IO_PENDING,
              three_transaction.Start(GetRequestInfo("three.html", options),
                                      three_callback.callback(),
                                      BoundNetLog()));

    HttpNetworkTransaction four_transaction(DEFAULT_PRIORITY, session_.get());
    TestCompletionCallback four_callback;
    EXPECT_EQ(ERR_IO_PENDING,
              four_transaction.Start(GetRequestInfo("four.html", options),
                                     four_callback.callback(), BoundNetLog()));

    ExpectResponse("one.html", *one_transaction.get(), SYNCHRONOUS);
    EXPECT_EQ(OK, two_callback.WaitForResult());
    ExpectResponse("two.html", two_transaction, SYNCHRONOUS);
    EXPECT_EQ(OK, three_callback.WaitForResult());
    ExpectResponse("three.html", three_transaction, SYNCHRONOUS);

    one_transaction.reset();
    EXPECT_EQ(OK, four_callback.WaitForResult());
    ExpectResponse("four.html", four_transaction, SYNCHRONOUS);
  }

  DeterministicMockClientSocketFactory factory_;
  ClientSocketPoolHistograms histograms_;
  MockTransportClientSocketPool pool_;
  ScopedVector<DeterministicSocketData> data_vector_;
  TestCompletionCallback callback_;
  ScopedVector<HttpRequestInfo> request_info_vector_;

  SimpleProxyConfigService* proxy_config_service_;
  scoped_ptr<ProxyService> proxy_service_;
  MockHostResolver mock_resolver_;
  scoped_refptr<SSLConfigService> ssl_config_;
  scoped_ptr<HttpAuthHandlerMock::Factory> auth_handler_factory_;
  HttpServerPropertiesImpl http_server_properties_;
  scoped_refptr<HttpNetworkSession> session_;
};

TEST_F(HttpPipelinedNetworkTransactionTest, OneRequest) {
  Initialize(false);

  MockWrite writes[] = {
    MockWrite(SYNCHRONOUS, 0, "GET /test.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"),
  };
  MockRead reads[] = {
    MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n"),
    MockRead(SYNCHRONOUS, 2, "Content-Length: 9\r\n\r\n"),
    MockRead(SYNCHRONOUS, 3, "test.html"),
  };
  AddExpectedConnection(reads, arraysize(reads), writes, arraysize(writes));

  HttpNetworkTransaction transaction(DEFAULT_PRIORITY, session_.get());
  EXPECT_EQ(ERR_IO_PENDING,
            transaction.Start(GetRequestInfo("test.html"), callback_.callback(),
                              BoundNetLog()));
  EXPECT_EQ(OK, callback_.WaitForResult());
  ExpectResponse("test.html", transaction, SYNCHRONOUS);
}

TEST_F(HttpPipelinedNetworkTransactionTest, ReusePipeline) {
  Initialize(false);

  MockWrite writes[] = {
    MockWrite(SYNCHRONOUS, 0, "GET /one.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"),
    MockWrite(SYNCHRONOUS, 3, "GET /two.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"),
  };
  MockRead reads[] = {
    MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n"),
    MockRead(SYNCHRONOUS, 2, "Content-Length: 8\r\n\r\n"),
    MockRead(ASYNC, 4, "one.html"),
    MockRead(SYNCHRONOUS, 5, "HTTP/1.1 200 OK\r\n"),
    MockRead(SYNCHRONOUS, 6, "Content-Length: 8\r\n\r\n"),
    MockRead(SYNCHRONOUS, 7, "two.html"),
  };
  AddExpectedConnection(reads, arraysize(reads), writes, arraysize(writes));

  CompleteTwoRequests(0, 5);
}

TEST_F(HttpPipelinedNetworkTransactionTest, ReusesOnSpaceAvailable) {
  int old_max_sockets = ClientSocketPoolManager::max_sockets_per_group(
      HttpNetworkSession::NORMAL_SOCKET_POOL);
  ClientSocketPoolManager::set_max_sockets_per_group(
      HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
  Initialize(false);

  MockWrite writes[] = {
    MockWrite(SYNCHRONOUS, 0, "GET /one.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"),
    MockWrite(SYNCHRONOUS, 4, "GET /two.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"),
    MockWrite(SYNCHRONOUS, 7, "GET /three.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"),
    MockWrite(SYNCHRONOUS, 12, "GET /four.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"),
  };
  MockRead reads[] = {
    MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n"),
    MockRead(SYNCHRONOUS, 2, "Content-Length: 8\r\n\r\n"),
    MockRead(SYNCHRONOUS, 3, "one.html"),
    MockRead(SYNCHRONOUS, 5, "HTTP/1.1 200 OK\r\n"),
    MockRead(SYNCHRONOUS, 6, "Content-Length: 8\r\n\r\n"),
    MockRead(SYNCHRONOUS, 8, "two.html"),
    MockRead(SYNCHRONOUS, 9, "HTTP/1.1 200 OK\r\n"),
    MockRead(SYNCHRONOUS, 10, "Content-Length: 10\r\n\r\n"),
    MockRead(SYNCHRONOUS, 11, "three.html"),
    MockRead(SYNCHRONOUS, 13, "HTTP/1.1 200 OK\r\n"),
    MockRead(SYNCHRONOUS, 14, "Content-Length: 9\r\n\r\n"),
    MockRead(SYNCHRONOUS, 15, "four.html"),
  };
  AddExpectedConnection(reads, arraysize(reads), writes, arraysize(writes));

  CompleteFourRequests(REQUEST_DEFAULT);

  ClientSocketPoolManager::set_max_sockets_per_group(
      HttpNetworkSession::NORMAL_SOCKET_POOL, old_max_sockets);
}

TEST_F(HttpPipelinedNetworkTransactionTest, WontPipelineMainResource) {
  int old_max_sockets = ClientSocketPoolManager::max_sockets_per_group(
      HttpNetworkSession::NORMAL_SOCKET_POOL);
  ClientSocketPoolManager::set_max_sockets_per_group(
      HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
  Initialize(false);

  MockWrite writes[] = {
    MockWrite(SYNCHRONOUS, 0, "GET /one.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"),
    MockWrite(SYNCHRONOUS, 4, "GET /two.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"),
    MockWrite(SYNCHRONOUS, 8, "GET /three.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"),
    MockWrite(SYNCHRONOUS, 12, "GET /four.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"),
  };
  MockRead reads[] = {
    MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n"),
    MockRead(SYNCHRONOUS, 2, "Content-Length: 8\r\n\r\n"),
    MockRead(SYNCHRONOUS, 3, "one.html"),
    MockRead(SYNCHRONOUS, 5, "HTTP/1.1 200 OK\r\n"),
    MockRead(SYNCHRONOUS, 6, "Content-Length: 8\r\n\r\n"),
    MockRead(SYNCHRONOUS, 7, "two.html"),
    MockRead(SYNCHRONOUS, 9, "HTTP/1.1 200 OK\r\n"),
    MockRead(SYNCHRONOUS, 10, "Content-Length: 10\r\n\r\n"),
    MockRead(SYNCHRONOUS, 11, "three.html"),
    MockRead(SYNCHRONOUS, 13, "HTTP/1.1 200 OK\r\n"),
    MockRead(SYNCHRONOUS, 14, "Content-Length: 9\r\n\r\n"),
    MockRead(SYNCHRONOUS, 15, "four.html"),
  };
  AddExpectedConnection(reads, arraysize(reads), writes, arraysize(writes));

  CompleteFourRequests(REQUEST_MAIN_RESOURCE);

  ClientSocketPoolManager::set_max_sockets_per_group(
      HttpNetworkSession::NORMAL_SOCKET_POOL, old_max_sockets);
}

TEST_F(HttpPipelinedNetworkTransactionTest, UnknownSizeEvictsToNewPipeline) {
  Initialize(false);

  MockWrite writes[] = {
    MockWrite(SYNCHRONOUS, 0, "GET /one.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"),
  };
  MockRead reads[] = {
    MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n\r\n"),
    MockRead(ASYNC, 2, "one.html"),
    MockRead(SYNCHRONOUS, OK, 3),
  };
  AddExpectedConnection(reads, arraysize(reads), writes, arraysize(writes));

  MockWrite writes2[] = {
    MockWrite(SYNCHRONOUS, 0, "GET /two.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"),
  };
  MockRead reads2[] = {
    MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n"),
    MockRead(SYNCHRONOUS, 2, "Content-Length: 8\r\n\r\n"),
    MockRead(SYNCHRONOUS, 3, "two.html"),
  };
  AddExpectedConnection(reads2, arraysize(reads2), writes2, arraysize(writes2));

  CompleteTwoRequests(0, 3);
}

TEST_F(HttpPipelinedNetworkTransactionTest, ConnectionCloseEvictToNewPipeline) {
  Initialize(false);

  MockWrite writes[] = {
    MockWrite(SYNCHRONOUS, 0, "GET /one.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"),
    MockWrite(SYNCHRONOUS, 3, "GET /two.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"),
  };
  MockRead reads[] = {
    MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n"),
    MockRead(SYNCHRONOUS, 2, "Content-Length: 8\r\n\r\n"),
    MockRead(ASYNC, 4, "one.html"),
    MockRead(SYNCHRONOUS, ERR_SOCKET_NOT_CONNECTED, 5),
  };
  AddExpectedConnection(reads, arraysize(reads), writes, arraysize(writes));

  MockWrite writes2[] = {
    MockWrite(SYNCHRONOUS, 0, "GET /two.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"),
  };
  MockRead reads2[] = {
    MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n"),
    MockRead(SYNCHRONOUS, 2, "Content-Length: 8\r\n\r\n"),
    MockRead(SYNCHRONOUS, 3, "two.html"),
  };
  AddExpectedConnection(reads2, arraysize(reads2), writes2, arraysize(writes2));

  CompleteTwoRequests(0, 5);
}

TEST_F(HttpPipelinedNetworkTransactionTest, ErrorEvictsToNewPipeline) {
  Initialize(false);

  MockWrite writes[] = {
    MockWrite(SYNCHRONOUS, 0, "GET /one.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"),
    MockWrite(SYNCHRONOUS, 3, "GET /two.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"),
  };
  MockRead reads[] = {
    MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n\r\n"),
    MockRead(SYNCHRONOUS, ERR_FAILED, 2),
  };
  AddExpectedConnection(reads, arraysize(reads), writes, arraysize(writes));

  MockWrite writes2[] = {
    MockWrite(SYNCHRONOUS, 0, "GET /two.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"),
  };
  MockRead reads2[] = {
    MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n"),
    MockRead(SYNCHRONOUS, 2, "Content-Length: 8\r\n\r\n"),
    MockRead(SYNCHRONOUS, 3, "two.html"),
  };
  AddExpectedConnection(reads2, arraysize(reads2), writes2, arraysize(writes2));

  HttpNetworkTransaction one_transaction(DEFAULT_PRIORITY, session_.get());
  TestCompletionCallback one_callback;
  EXPECT_EQ(ERR_IO_PENDING,
            one_transaction.Start(GetRequestInfo("one.html"),
                                  one_callback.callback(), BoundNetLog()));
  EXPECT_EQ(OK, one_callback.WaitForResult());

  HttpNetworkTransaction two_transaction(DEFAULT_PRIORITY, session_.get());
  TestCompletionCallback two_callback;
  EXPECT_EQ(ERR_IO_PENDING,
            two_transaction.Start(GetRequestInfo("two.html"),
                                  two_callback.callback(), BoundNetLog()));

  scoped_refptr<IOBuffer> buffer(new IOBuffer(1));
  EXPECT_EQ(ERR_FAILED,
            one_transaction.Read(buffer.get(), 1, callback_.callback()));
  EXPECT_EQ(OK, two_callback.WaitForResult());
  ExpectResponse("two.html", two_transaction, SYNCHRONOUS);
}

TEST_F(HttpPipelinedNetworkTransactionTest, SendErrorEvictsToNewPipeline) {
  Initialize(false);

  MockWrite writes[] = {
    MockWrite(ASYNC, ERR_FAILED, 0),
  };
  AddExpectedConnection(NULL, 0, writes, arraysize(writes));

  MockWrite writes2[] = {
    MockWrite(SYNCHRONOUS, 0, "GET /two.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"),
  };
  MockRead reads2[] = {
    MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n"),
    MockRead(SYNCHRONOUS, 2, "Content-Length: 8\r\n\r\n"),
    MockRead(SYNCHRONOUS, 3, "two.html"),
  };
  AddExpectedConnection(reads2, arraysize(reads2), writes2, arraysize(writes2));

  HttpNetworkTransaction one_transaction(DEFAULT_PRIORITY, session_.get());
  TestCompletionCallback one_callback;
  EXPECT_EQ(ERR_IO_PENDING,
            one_transaction.Start(GetRequestInfo("one.html"),
                                  one_callback.callback(), BoundNetLog()));

  HttpNetworkTransaction two_transaction(DEFAULT_PRIORITY, session_.get());
  TestCompletionCallback two_callback;
  EXPECT_EQ(ERR_IO_PENDING,
            two_transaction.Start(GetRequestInfo("two.html"),
                                  two_callback.callback(), BoundNetLog()));

  data_vector_[0]->RunFor(1);
  EXPECT_EQ(ERR_FAILED, one_callback.WaitForResult());

  EXPECT_EQ(OK, two_callback.WaitForResult());
  ExpectResponse("two.html", two_transaction, SYNCHRONOUS);
}

TEST_F(HttpPipelinedNetworkTransactionTest, RedirectDrained) {
  Initialize(false);

  MockWrite writes[] = {
    MockWrite(SYNCHRONOUS, 0, "GET /redirect.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"),
    MockWrite(SYNCHRONOUS, 3, "GET /two.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"),
  };
  MockRead reads[] = {
    MockRead(SYNCHRONOUS, 1, "HTTP/1.1 302 OK\r\n"),
    MockRead(SYNCHRONOUS, 2, "Content-Length: 8\r\n\r\n"),
    MockRead(ASYNC, 4, "redirect"),
    MockRead(SYNCHRONOUS, 5, "HTTP/1.1 200 OK\r\n"),
    MockRead(SYNCHRONOUS, 6, "Content-Length: 8\r\n\r\n"),
    MockRead(SYNCHRONOUS, 7, "two.html"),
  };
  AddExpectedConnection(reads, arraysize(reads), writes, arraysize(writes));

  scoped_ptr<HttpNetworkTransaction> one_transaction(
      new HttpNetworkTransaction(DEFAULT_PRIORITY, session_.get()));
  TestCompletionCallback one_callback;
  EXPECT_EQ(ERR_IO_PENDING,
            one_transaction->Start(GetRequestInfo("redirect.html"),
                                   one_callback.callback(), BoundNetLog()));
  EXPECT_EQ(OK, one_callback.WaitForResult());

  HttpNetworkTransaction two_transaction(DEFAULT_PRIORITY, session_.get());
  TestCompletionCallback two_callback;
  EXPECT_EQ(ERR_IO_PENDING,
            two_transaction.Start(GetRequestInfo("two.html"),
                                  two_callback.callback(), BoundNetLog()));

  one_transaction.reset();
  data_vector_[0]->RunFor(2);
  data_vector_[0]->SetStop(10);

  EXPECT_EQ(OK, two_callback.WaitForResult());
  ExpectResponse("two.html", two_transaction, SYNCHRONOUS);
}

TEST_F(HttpPipelinedNetworkTransactionTest, BasicHttpAuthentication) {
  Initialize(false);

  MockWrite writes[] = {
    MockWrite(SYNCHRONOUS, 0, "GET /one.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"),
    MockWrite(SYNCHRONOUS, 5, "GET /one.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n"
              "Authorization: auth_token\r\n\r\n"),
  };
  MockRead reads[] = {
    MockRead(SYNCHRONOUS, 1, "HTTP/1.1 401 Authentication Required\r\n"),
    MockRead(SYNCHRONOUS, 2,
             "WWW-Authenticate: Basic realm=\"Secure Area\"\r\n"),
    MockRead(SYNCHRONOUS, 3, "Content-Length: 20\r\n\r\n"),
    MockRead(SYNCHRONOUS, 4, "needs authentication"),
    MockRead(SYNCHRONOUS, 6, "HTTP/1.1 200 OK\r\n"),
    MockRead(SYNCHRONOUS, 7, "Content-Length: 8\r\n\r\n"),
    MockRead(SYNCHRONOUS, 8, "one.html"),
  };
  AddExpectedConnection(reads, arraysize(reads), writes, arraysize(writes));

  HttpAuthHandlerMock* mock_auth = new HttpAuthHandlerMock;
  std::string challenge_text = "Basic";
  HttpAuthChallengeTokenizer challenge(challenge_text.begin(),
                                         challenge_text.end());
  GURL origin("localhost");
  EXPECT_TRUE(mock_auth->InitFromChallenge(&challenge,
                                           HttpAuth::AUTH_SERVER,
                                           origin,
                                           BoundNetLog()));
  auth_handler_factory_->AddMockHandler(mock_auth, HttpAuth::AUTH_SERVER);

  HttpNetworkTransaction transaction(DEFAULT_PRIORITY, session_.get());
  EXPECT_EQ(ERR_IO_PENDING,
            transaction.Start(GetRequestInfo("one.html"),
                              callback_.callback(),
                              BoundNetLog()));
  EXPECT_EQ(OK, callback_.WaitForResult());

  AuthCredentials credentials(base::ASCIIToUTF16("user"),
                              base::ASCIIToUTF16("pass"));
  EXPECT_EQ(OK, transaction.RestartWithAuth(credentials, callback_.callback()));

  ExpectResponse("one.html", transaction, SYNCHRONOUS);
}

TEST_F(HttpPipelinedNetworkTransactionTest, OldVersionDisablesPipelining) {
  Initialize(false);

  MockWrite writes[] = {
    MockWrite(SYNCHRONOUS, 0, "GET /pipelined.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"),
  };
  MockRead reads[] = {
    MockRead(SYNCHRONOUS, 1, "HTTP/1.0 200 OK\r\n"),
    MockRead(SYNCHRONOUS, 2, "Content-Length: 14\r\n\r\n"),
    MockRead(SYNCHRONOUS, 3, "pipelined.html"),
  };
  AddExpectedConnection(reads, arraysize(reads), writes, arraysize(writes));

  MockWrite writes2[] = {
    MockWrite(SYNCHRONOUS, 0, "GET /one.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"),
  };
  MockRead reads2[] = {
    MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n"),
    MockRead(SYNCHRONOUS, 2, "Content-Length: 8\r\n\r\n"),
    MockRead(ASYNC, 3, "one.html"),
    MockRead(SYNCHRONOUS, OK, 4),
  };
  AddExpectedConnection(reads2, arraysize(reads2), writes2, arraysize(writes2));

  MockWrite writes3[] = {
    MockWrite(SYNCHRONOUS, 0, "GET /two.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"),
  };
  MockRead reads3[] = {
    MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n"),
    MockRead(SYNCHRONOUS, 2, "Content-Length: 8\r\n\r\n"),
    MockRead(SYNCHRONOUS, 3, "two.html"),
    MockRead(SYNCHRONOUS, OK, 4),
  };
  AddExpectedConnection(reads3, arraysize(reads3), writes3, arraysize(writes3));

  HttpNetworkTransaction one_transaction(DEFAULT_PRIORITY, session_.get());
  TestCompletionCallback one_callback;
  EXPECT_EQ(ERR_IO_PENDING,
            one_transaction.Start(GetRequestInfo("pipelined.html"),
                                  one_callback.callback(), BoundNetLog()));
  EXPECT_EQ(OK, one_callback.WaitForResult());
  ExpectResponse("pipelined.html", one_transaction, SYNCHRONOUS);

  CompleteTwoRequests(1, 4);
}

TEST_F(HttpPipelinedNetworkTransactionTest, PipelinesImmediatelyIfKnownGood) {
  // The first request gets us an HTTP/1.1. The next 3 test pipelining. When the
  // 3rd request completes, we know pipelining is safe. After the first 4
  // complete, the 5th and 6th should then be immediately sent pipelined on a
  // new HttpPipelinedConnection.
  int old_max_sockets = ClientSocketPoolManager::max_sockets_per_group(
      HttpNetworkSession::NORMAL_SOCKET_POOL);
  ClientSocketPoolManager::set_max_sockets_per_group(
      HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
  Initialize(false);

  MockWrite writes[] = {
    MockWrite(SYNCHRONOUS, 0, "GET /one.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"),
    MockWrite(SYNCHRONOUS, 4, "GET /two.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"),
    MockWrite(SYNCHRONOUS, 7, "GET /three.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"),
    MockWrite(SYNCHRONOUS, 12, "GET /four.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"),
    MockWrite(SYNCHRONOUS, 16, "GET /second-pipeline-one.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"),
    MockWrite(SYNCHRONOUS, 17, "GET /second-pipeline-two.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"),
  };
  MockRead reads[] = {
    MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n"),
    MockRead(SYNCHRONOUS, 2, "Content-Length: 8\r\n\r\n"),
    MockRead(SYNCHRONOUS, 3, "one.html"),
    MockRead(SYNCHRONOUS, 5, "HTTP/1.1 200 OK\r\n"),
    MockRead(SYNCHRONOUS, 6, "Content-Length: 8\r\n\r\n"),
    MockRead(SYNCHRONOUS, 8, "two.html"),
    MockRead(SYNCHRONOUS, 9, "HTTP/1.1 200 OK\r\n"),
    MockRead(SYNCHRONOUS, 10, "Content-Length: 10\r\n\r\n"),
    MockRead(SYNCHRONOUS, 11, "three.html"),
    MockRead(SYNCHRONOUS, 13, "HTTP/1.1 200 OK\r\n"),
    MockRead(SYNCHRONOUS, 14, "Content-Length: 9\r\n\r\n"),
    MockRead(SYNCHRONOUS, 15, "four.html"),
    MockRead(ASYNC, 18, "HTTP/1.1 200 OK\r\n"),
    MockRead(ASYNC, 19, "Content-Length: 24\r\n\r\n"),
    MockRead(SYNCHRONOUS, 20, "second-pipeline-one.html"),
    MockRead(SYNCHRONOUS, 21, "HTTP/1.1 200 OK\r\n"),
    MockRead(SYNCHRONOUS, 22, "Content-Length: 24\r\n\r\n"),
    MockRead(SYNCHRONOUS, 23, "second-pipeline-two.html"),
  };
  AddExpectedConnection(reads, arraysize(reads), writes, arraysize(writes));

  CompleteFourRequests(REQUEST_DEFAULT);

  HttpNetworkTransaction second_one_transaction(
      DEFAULT_PRIORITY, session_.get());
  TestCompletionCallback second_one_callback;
  EXPECT_EQ(ERR_IO_PENDING,
            second_one_transaction.Start(
                GetRequestInfo("second-pipeline-one.html"),
                second_one_callback.callback(), BoundNetLog()));
  base::MessageLoop::current()->RunUntilIdle();

  HttpNetworkTransaction second_two_transaction(
      DEFAULT_PRIORITY, session_.get());
  TestCompletionCallback second_two_callback;
  EXPECT_EQ(ERR_IO_PENDING,
            second_two_transaction.Start(
                GetRequestInfo("second-pipeline-two.html"),
                second_two_callback.callback(), BoundNetLog()));

  data_vector_[0]->RunFor(3);
  EXPECT_EQ(OK, second_one_callback.WaitForResult());
  data_vector_[0]->StopAfter(100);
  ExpectResponse("second-pipeline-one.html", second_one_transaction,
                 SYNCHRONOUS);
  EXPECT_EQ(OK, second_two_callback.WaitForResult());
  ExpectResponse("second-pipeline-two.html", second_two_transaction,
                 SYNCHRONOUS);

  ClientSocketPoolManager::set_max_sockets_per_group(
      HttpNetworkSession::NORMAL_SOCKET_POOL, old_max_sockets);
}

class DataRunnerObserver : public base::MessageLoop::TaskObserver {
 public:
  DataRunnerObserver(DeterministicSocketData* data, int run_before_task)
      : data_(data),
        run_before_task_(run_before_task),
        current_task_(0) { }

  virtual void WillProcessTask(const base::PendingTask& pending_task) OVERRIDE {
    ++current_task_;
    if (current_task_ == run_before_task_) {
      data_->Run();
      base::MessageLoop::current()->RemoveTaskObserver(this);
    }
  }

  virtual void DidProcessTask(const base::PendingTask& pending_task) OVERRIDE {}

 private:
  DeterministicSocketData* data_;
  int run_before_task_;
  int current_task_;
};

TEST_F(HttpPipelinedNetworkTransactionTest, OpenPipelinesWhileBinding) {
  // There was a racy crash in the pipelining code. This test recreates that
  // race. The steps are:
  // 1. The first request starts a pipeline and requests headers.
  // 2. HttpStreamFactoryImpl::Job tries to bind a pending request to a new
  // pipeline and queues a task to do so.
  // 3. Before that task runs, the first request receives its headers and
  // determines this host is probably capable of pipelining.
  // 4. All of the hosts' pipelines are notified they have capacity in a loop.
  // 5. On the first iteration, the first pipeline is opened up to accept new
  // requests and steals the request from step #2.
  // 6. The pipeline from #2 is deleted because it has no streams.
  // 7. On the second iteration, the host tries to notify the pipeline from step
  // #2 that it has capacity. This is a use-after-free.
  Initialize(false);

  MockWrite writes[] = {
    MockWrite(SYNCHRONOUS, 0, "GET /one.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"),
    MockWrite(ASYNC, 3, "GET /two.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"),
  };
  MockRead reads[] = {
    MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n"),
    MockRead(ASYNC, 2, "Content-Length: 8\r\n\r\n"),
    MockRead(SYNCHRONOUS, 4, "one.html"),
    MockRead(SYNCHRONOUS, 5, "HTTP/1.1 200 OK\r\n"),
    MockRead(SYNCHRONOUS, 6, "Content-Length: 8\r\n\r\n"),
    MockRead(SYNCHRONOUS, 7, "two.html"),
  };
  AddExpectedConnection(reads, arraysize(reads), writes, arraysize(writes));

  AddExpectedConnection(NULL, 0, NULL, 0);

  HttpNetworkTransaction one_transaction(DEFAULT_PRIORITY, session_.get());
  TestCompletionCallback one_callback;
  EXPECT_EQ(ERR_IO_PENDING,
            one_transaction.Start(GetRequestInfo("one.html"),
                                  one_callback.callback(), BoundNetLog()));

  data_vector_[0]->SetStop(2);
  data_vector_[0]->Run();

  HttpNetworkTransaction two_transaction(DEFAULT_PRIORITY, session_.get());
  TestCompletionCallback two_callback;
  EXPECT_EQ(ERR_IO_PENDING,
            two_transaction.Start(GetRequestInfo("two.html"),
                                  two_callback.callback(), BoundNetLog()));
  // Posted tasks should be:
  // 1. MockHostResolverBase::ResolveNow
  // 2. HttpStreamFactoryImpl::Job::OnStreamReadyCallback for job 1
  // 3. HttpStreamFactoryImpl::Job::OnStreamReadyCallback for job 2
  //
  // We need to make sure that the response that triggers OnPipelineFeedback(OK)
  // is called in between when task #3 is scheduled and when it runs. The
  // DataRunnerObserver does that.
  DataRunnerObserver observer(data_vector_[0], 3);
  base::MessageLoop::current()->AddTaskObserver(&observer);
  data_vector_[0]->SetStop(4);
  base::MessageLoop::current()->RunUntilIdle();
  data_vector_[0]->SetStop(10);

  EXPECT_EQ(OK, one_callback.WaitForResult());
  ExpectResponse("one.html", one_transaction, SYNCHRONOUS);
  EXPECT_EQ(OK, two_callback.WaitForResult());
  ExpectResponse("two.html", two_transaction, SYNCHRONOUS);
}

TEST_F(HttpPipelinedNetworkTransactionTest, ProxyChangesWhileConnecting) {
  Initialize(false);

  DeterministicSocketData data(NULL, 0, NULL, 0);
  data.set_connect_data(MockConnect(ASYNC, ERR_CONNECTION_REFUSED));
  factory_.AddSocketDataProvider(&data);

  DeterministicSocketData data2(NULL, 0, NULL, 0);
  data2.set_connect_data(MockConnect(ASYNC, ERR_FAILED));
  factory_.AddSocketDataProvider(&data2);

  HttpNetworkTransaction transaction(DEFAULT_PRIORITY, session_.get());
  EXPECT_EQ(ERR_IO_PENDING,
            transaction.Start(GetRequestInfo("test.html"), callback_.callback(),
                              BoundNetLog()));

  proxy_config_service_->IncrementConfigId();

  EXPECT_EQ(ERR_FAILED, callback_.WaitForResult());
}

TEST_F(HttpPipelinedNetworkTransactionTest, ForcedPipelineSharesConnection) {
  Initialize(true);

  MockWrite writes[] = {
    MockWrite(ASYNC, 0, "GET /one.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"
              "GET /two.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"),
  };
  MockRead reads[] = {
    MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n"),
    MockRead(ASYNC, 2, "Content-Length: 8\r\n\r\n"),
    MockRead(ASYNC, 3, "one.html"),
    MockRead(ASYNC, 4, "HTTP/1.1 200 OK\r\n"),
    MockRead(ASYNC, 5, "Content-Length: 8\r\n\r\n"),
    MockRead(ASYNC, 6, "two.html"),
  };
  AddExpectedConnection(reads, arraysize(reads), writes, arraysize(writes));

  scoped_ptr<HttpNetworkTransaction> one_transaction(
      new HttpNetworkTransaction(DEFAULT_PRIORITY, session_.get()));
  TestCompletionCallback one_callback;
  EXPECT_EQ(ERR_IO_PENDING,
            one_transaction->Start(GetRequestInfo("one.html"),
                                   one_callback.callback(), BoundNetLog()));

  HttpNetworkTransaction two_transaction(DEFAULT_PRIORITY, session_.get());
  TestCompletionCallback two_callback;
  EXPECT_EQ(ERR_IO_PENDING,
            two_transaction.Start(GetRequestInfo("two.html"),
                                  two_callback.callback(), BoundNetLog()));

  data_vector_[0]->RunFor(3);  // Send + 2 lines of headers.
  EXPECT_EQ(OK, one_callback.WaitForResult());
  ExpectResponse("one.html", *one_transaction.get(), ASYNC);
  one_transaction.reset();

  data_vector_[0]->RunFor(2);  // 2 lines of headers.
  EXPECT_EQ(OK, two_callback.WaitForResult());
  ExpectResponse("two.html", two_transaction, ASYNC);
}

TEST_F(HttpPipelinedNetworkTransactionTest,
       ForcedPipelineConnectionErrorFailsBoth) {
  Initialize(true);

  DeterministicSocketData data(NULL, 0, NULL, 0);
  data.set_connect_data(MockConnect(ASYNC, ERR_FAILED));
  factory_.AddSocketDataProvider(&data);

  scoped_ptr<HttpNetworkTransaction> one_transaction(
      new HttpNetworkTransaction(DEFAULT_PRIORITY, session_.get()));
  TestCompletionCallback one_callback;
  EXPECT_EQ(ERR_IO_PENDING,
            one_transaction->Start(GetRequestInfo("one.html"),
                                   one_callback.callback(), BoundNetLog()));

  HttpNetworkTransaction two_transaction(DEFAULT_PRIORITY, session_.get());
  TestCompletionCallback two_callback;
  EXPECT_EQ(ERR_IO_PENDING,
            two_transaction.Start(GetRequestInfo("two.html"),
                                  two_callback.callback(), BoundNetLog()));

  data.Run();
  EXPECT_EQ(ERR_FAILED, one_callback.WaitForResult());
  EXPECT_EQ(ERR_FAILED, two_callback.WaitForResult());
}

TEST_F(HttpPipelinedNetworkTransactionTest, ForcedPipelineEvictionIsFatal) {
  Initialize(true);

  MockWrite writes[] = {
    MockWrite(ASYNC, 0, "GET /one.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"
              "GET /two.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"),
  };
  MockRead reads[] = {
    MockRead(ASYNC, ERR_FAILED, 1),
  };
  AddExpectedConnection(reads, arraysize(reads), writes, arraysize(writes));

  scoped_ptr<HttpNetworkTransaction> one_transaction(
      new HttpNetworkTransaction(DEFAULT_PRIORITY, session_.get()));
  TestCompletionCallback one_callback;
  EXPECT_EQ(ERR_IO_PENDING,
            one_transaction->Start(GetRequestInfo("one.html"),
                                   one_callback.callback(), BoundNetLog()));

  HttpNetworkTransaction two_transaction(DEFAULT_PRIORITY, session_.get());
  TestCompletionCallback two_callback;
  EXPECT_EQ(ERR_IO_PENDING,
            two_transaction.Start(GetRequestInfo("two.html"),
                                  two_callback.callback(), BoundNetLog()));

  data_vector_[0]->RunFor(2);
  EXPECT_EQ(ERR_FAILED, one_callback.WaitForResult());
  one_transaction.reset();
  EXPECT_EQ(ERR_PIPELINE_EVICTION, two_callback.WaitForResult());
}

TEST_F(HttpPipelinedNetworkTransactionTest, ForcedPipelineOrder) {
  Initialize(true);

  MockWrite writes[] = {
    MockWrite(ASYNC, 0,
              "GET /one.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"
              "GET /two.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"
              "GET /three.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"
              "GET /four.html HTTP/1.1\r\n"
              "Host: localhost\r\n"
              "Connection: keep-alive\r\n\r\n"
              ),
  };
  MockRead reads[] = {
    MockRead(ASYNC, ERR_FAILED, 1),
  };
  DeterministicSocketData data(
      reads, arraysize(reads), writes, arraysize(writes));
  data.set_connect_data(MockConnect(ASYNC, OK));
  factory_.AddSocketDataProvider(&data);

  scoped_ptr<HttpNetworkTransaction> one_transaction(
      new HttpNetworkTransaction(DEFAULT_PRIORITY, session_.get()));
  TestCompletionCallback one_callback;
  EXPECT_EQ(ERR_IO_PENDING,
            one_transaction->Start(GetRequestInfo("one.html"),
                                   one_callback.callback(), BoundNetLog()));

  scoped_ptr<HttpNetworkTransaction> two_transaction(
      new HttpNetworkTransaction(DEFAULT_PRIORITY, session_.get()));
  TestCompletionCallback two_callback;
  EXPECT_EQ(ERR_IO_PENDING,
            two_transaction->Start(GetRequestInfo("two.html"),
                                   two_callback.callback(), BoundNetLog()));

  scoped_ptr<HttpNetworkTransaction> three_transaction(
      new HttpNetworkTransaction(DEFAULT_PRIORITY, session_.get()));
  TestCompletionCallback three_callback;
  EXPECT_EQ(ERR_IO_PENDING,
            three_transaction->Start(GetRequestInfo("three.html"),
                                     three_callback.callback(), BoundNetLog()));

  scoped_ptr<HttpNetworkTransaction> four_transaction(
      new HttpNetworkTransaction(DEFAULT_PRIORITY, session_.get()));
  TestCompletionCallback four_callback;
  EXPECT_EQ(ERR_IO_PENDING,
            four_transaction->Start(GetRequestInfo("four.html"),
                                    four_callback.callback(), BoundNetLog()));

  data.RunFor(3);
  EXPECT_EQ(ERR_FAILED, one_callback.WaitForResult());
  one_transaction.reset();
  EXPECT_EQ(ERR_PIPELINE_EVICTION, two_callback.WaitForResult());
  two_transaction.reset();
  EXPECT_EQ(ERR_PIPELINE_EVICTION, three_callback.WaitForResult());
  three_transaction.reset();
  EXPECT_EQ(ERR_PIPELINE_EVICTION, four_callback.WaitForResult());
}

}  // anonymous namespace

}  // namespace net

/* [<][>][^][v][top][bottom][index][help] */