123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677 |
- // 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 "net/spdy/spdy_proxy_client_socket.h"
- #include <utility>
- #include "base/bind.h"
- #include "base/callback_helpers.h"
- #include "base/memory/raw_ptr.h"
- #include "base/run_loop.h"
- #include "base/strings/string_piece.h"
- #include "base/strings/utf_string_conversions.h"
- #include "net/base/address_list.h"
- #include "net/base/host_port_pair.h"
- #include "net/base/load_timing_info.h"
- #include "net/base/proxy_server.h"
- #include "net/base/test_completion_callback.h"
- #include "net/base/winsock_init.h"
- #include "net/dns/mock_host_resolver.h"
- #include "net/dns/public/secure_dns_policy.h"
- #include "net/http/http_proxy_connect_job.h"
- #include "net/http/http_response_headers.h"
- #include "net/http/http_response_info.h"
- #include "net/log/net_log.h"
- #include "net/log/net_log_event_type.h"
- #include "net/log/net_log_source.h"
- #include "net/log/test_net_log.h"
- #include "net/log/test_net_log_util.h"
- #include "net/socket/client_socket_factory.h"
- #include "net/socket/connect_job_test_util.h"
- #include "net/socket/next_proto.h"
- #include "net/socket/socket_tag.h"
- #include "net/socket/socket_test_util.h"
- #include "net/socket/socks_connect_job.h"
- #include "net/socket/ssl_client_socket.h"
- #include "net/socket/ssl_connect_job.h"
- #include "net/socket/stream_socket.h"
- #include "net/socket/tcp_client_socket.h"
- #include "net/socket/transport_connect_job.h"
- #include "net/spdy/buffered_spdy_framer.h"
- #include "net/spdy/spdy_http_utils.h"
- #include "net/spdy/spdy_session_pool.h"
- #include "net/spdy/spdy_test_util_common.h"
- #include "net/test/cert_test_util.h"
- #include "net/test/gtest_util.h"
- #include "net/test/test_data_directory.h"
- #include "net/test/test_with_task_environment.h"
- #include "net/third_party/quiche/src/quiche/spdy/core/spdy_protocol.h"
- #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
- #include "testing/gmock/include/gmock/gmock.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #include "testing/platform_test.h"
- #include "url/gurl.h"
- #include "url/scheme_host_port.h"
- using net::test::IsError;
- using net::test::IsOk;
- //-----------------------------------------------------------------------------
- namespace net {
- namespace {
- static const char kRequestUrl[] = "https://www.google.com/";
- static const char kOriginHost[] = "www.google.com";
- static const int kOriginPort = 443;
- static const char kOriginHostPort[] = "www.google.com:443";
- static const char kProxyUrl[] = "https://myproxy:6121/";
- static const char kProxyHost[] = "myproxy";
- static const int kProxyPort = 6121;
- static const char kUserAgent[] = "Mozilla/1.0";
- static const int kStreamId = 1;
- static const char kMsg1[] = "\0hello!\xff";
- static const int kLen1 = 8;
- static const char kMsg2[] = "\0a2345678\0";
- static const int kLen2 = 10;
- static const char kMsg3[] = "bye!";
- static const int kLen3 = 4;
- static const char kMsg33[] = "bye!bye!";
- static const int kLen33 = kLen3 + kLen3;
- static const char kMsg333[] = "bye!bye!bye!";
- static const int kLen333 = kLen3 + kLen3 + kLen3;
- static const char kRedirectUrl[] = "https://example.com/";
- // Creates a SpdySession with a StreamSocket, instead of a ClientSocketHandle.
- base::WeakPtr<SpdySession> CreateSpdyProxySession(
- const url::SchemeHostPort& destination,
- HttpNetworkSession* http_session,
- const SpdySessionKey& key,
- const CommonConnectJobParams* common_connect_job_params) {
- EXPECT_FALSE(http_session->spdy_session_pool()->FindAvailableSession(
- key, true /* enable_ip_based_pooling */, false /* is_websocket */,
- NetLogWithSource()));
- auto transport_params = base::MakeRefCounted<TransportSocketParams>(
- destination, NetworkIsolationKey(), SecureDnsPolicy::kAllow,
- OnHostResolutionCallback(),
- /*supported_alpns=*/base::flat_set<std::string>{"h2", "http/1.1"});
- SSLConfig ssl_config;
- auto ssl_params = base::MakeRefCounted<SSLSocketParams>(
- transport_params, nullptr, nullptr,
- HostPortPair::FromSchemeHostPort(destination), ssl_config,
- key.privacy_mode(), key.network_isolation_key());
- TestConnectJobDelegate connect_job_delegate;
- SSLConnectJob connect_job(MEDIUM, SocketTag(), common_connect_job_params,
- ssl_params, &connect_job_delegate,
- nullptr /* net_log */);
- connect_job_delegate.StartJobExpectingResult(&connect_job, OK,
- false /* expect_sync_result */);
- base::WeakPtr<SpdySession> spdy_session =
- http_session->spdy_session_pool()->CreateAvailableSessionFromSocket(
- key, connect_job_delegate.ReleaseSocket(),
- LoadTimingInfo::ConnectTiming(), NetLogWithSource());
- // Failure is reported asynchronously.
- EXPECT_TRUE(spdy_session);
- EXPECT_TRUE(HasSpdySession(http_session->spdy_session_pool(), key));
- return spdy_session;
- }
- } // namespace
- class SpdyProxyClientSocketTest : public PlatformTest,
- public WithTaskEnvironment,
- public ::testing::WithParamInterface<bool> {
- public:
- SpdyProxyClientSocketTest();
- SpdyProxyClientSocketTest(const SpdyProxyClientSocketTest&) = delete;
- SpdyProxyClientSocketTest& operator=(const SpdyProxyClientSocketTest&) =
- delete;
- ~SpdyProxyClientSocketTest() override;
- void TearDown() override;
- protected:
- void Initialize(base::span<const MockRead> reads,
- base::span<const MockWrite> writes);
- void PopulateConnectRequestIR(spdy::Http2HeaderBlock* syn_ir);
- void PopulateConnectReplyIR(spdy::Http2HeaderBlock* block,
- const char* status);
- spdy::SpdySerializedFrame ConstructConnectRequestFrame(
- RequestPriority priority = LOWEST);
- spdy::SpdySerializedFrame ConstructConnectAuthRequestFrame();
- spdy::SpdySerializedFrame ConstructConnectReplyFrame();
- spdy::SpdySerializedFrame ConstructConnectAuthReplyFrame();
- spdy::SpdySerializedFrame ConstructConnectRedirectReplyFrame();
- spdy::SpdySerializedFrame ConstructConnectErrorReplyFrame();
- spdy::SpdySerializedFrame ConstructBodyFrame(const char* data,
- int length,
- bool fin = false);
- scoped_refptr<IOBufferWithSize> CreateBuffer(const char* data, int size);
- void AssertConnectSucceeds();
- void AssertConnectFails(int result);
- void AssertConnectionEstablished();
- void AssertSyncReadEquals(const char* data, int len);
- void AssertSyncReadEOF();
- void AssertAsyncReadEquals(const char* data, int len, bool fin = false);
- void AssertReadStarts(const char* data, int len);
- void AssertReadReturns(const char* data, int len);
- void AssertAsyncWriteSucceeds(const char* data, int len);
- void AssertWriteReturns(const char* data, int len, int rv);
- void AssertWriteLength(int len);
- void AddAuthToCache() {
- const std::u16string kFoo(u"foo");
- const std::u16string kBar(u"bar");
- session_->http_auth_cache()->Add(
- url::SchemeHostPort{GURL(kProxyUrl)}, HttpAuth::AUTH_PROXY, "MyRealm1",
- HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey(),
- "Basic realm=MyRealm1", AuthCredentials(kFoo, kBar), "/");
- }
- void ResumeAndRun() {
- // Run until the pause, if the provider isn't paused yet.
- data_->RunUntilPaused();
- data_->Resume();
- base::RunLoop().RunUntilIdle();
- }
- void CloseSpdySession(Error error, const std::string& description) {
- spdy_session_->CloseSessionOnError(error, description);
- }
- // Whether to use net::Socket::ReadIfReady() instead of net::Socket::Read().
- bool use_read_if_ready() const { return GetParam(); }
- NetLogWithSource net_log_with_source_{
- NetLogWithSource::Make(NetLogSourceType::NONE)};
- RecordingNetLogObserver net_log_observer_;
- SpdyTestUtil spdy_util_;
- std::unique_ptr<SpdyProxyClientSocket> sock_;
- TestCompletionCallback read_callback_;
- TestCompletionCallback write_callback_;
- std::unique_ptr<SequencedSocketData> data_;
- private:
- scoped_refptr<IOBuffer> read_buf_;
- SpdySessionDependencies session_deps_;
- std::unique_ptr<HttpNetworkSession> session_;
- MockConnect connect_data_;
- base::WeakPtr<SpdySession> spdy_session_;
- std::string user_agent_;
- GURL url_;
- HostPortPair proxy_host_port_;
- HostPortPair endpoint_host_port_pair_;
- ProxyServer proxy_;
- SpdySessionKey endpoint_spdy_session_key_;
- std::unique_ptr<CommonConnectJobParams> common_connect_job_params_;
- SSLSocketDataProvider ssl_;
- };
- SpdyProxyClientSocketTest::SpdyProxyClientSocketTest()
- : connect_data_(SYNCHRONOUS, OK),
- user_agent_(kUserAgent),
- url_(kRequestUrl),
- proxy_host_port_(kProxyHost, kProxyPort),
- endpoint_host_port_pair_(kOriginHost, kOriginPort),
- proxy_(ProxyServer::SCHEME_HTTPS, proxy_host_port_),
- endpoint_spdy_session_key_(endpoint_host_port_pair_,
- proxy_,
- PRIVACY_MODE_DISABLED,
- SpdySessionKey::IsProxySession::kFalse,
- SocketTag(),
- NetworkIsolationKey(),
- SecureDnsPolicy::kAllow),
- ssl_(SYNCHRONOUS, OK) {
- session_deps_.net_log = NetLog::Get();
- }
- SpdyProxyClientSocketTest::~SpdyProxyClientSocketTest() {
- if (data_) {
- EXPECT_TRUE(data_->AllWriteDataConsumed());
- EXPECT_TRUE(data_->AllReadDataConsumed());
- }
- }
- void SpdyProxyClientSocketTest::TearDown() {
- if (session_)
- session_->spdy_session_pool()->CloseAllSessions();
- // Empty the current queue.
- base::RunLoop().RunUntilIdle();
- PlatformTest::TearDown();
- }
- void SpdyProxyClientSocketTest::Initialize(base::span<const MockRead> reads,
- base::span<const MockWrite> writes) {
- data_ = std::make_unique<SequencedSocketData>(reads, writes);
- data_->set_connect_data(connect_data_);
- session_deps_.socket_factory->AddSocketDataProvider(data_.get());
- ssl_.ssl_info.cert =
- ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
- ASSERT_TRUE(ssl_.ssl_info.cert);
- ssl_.next_proto = NextProto::kProtoHTTP2;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_);
- session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
- common_connect_job_params_ = std::make_unique<CommonConnectJobParams>(
- session_->CreateCommonConnectJobParams());
- // Creates the SPDY session and stream.
- spdy_session_ = CreateSpdyProxySession(
- url::SchemeHostPort(url_), session_.get(), endpoint_spdy_session_key_,
- common_connect_job_params_.get());
- base::WeakPtr<SpdyStream> spdy_stream(
- CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM, spdy_session_, url_,
- LOWEST, net_log_with_source_));
- ASSERT_TRUE(spdy_stream.get() != nullptr);
- // Create the SpdyProxyClientSocket.
- sock_ = std::make_unique<SpdyProxyClientSocket>(
- spdy_stream, ProxyServer(ProxyServer::SCHEME_HTTPS, proxy_host_port_),
- user_agent_, endpoint_host_port_pair_, net_log_with_source_,
- base::MakeRefCounted<HttpAuthController>(
- HttpAuth::AUTH_PROXY, GURL("https://" + proxy_host_port_.ToString()),
- NetworkIsolationKey(), session_->http_auth_cache(),
- session_->http_auth_handler_factory(), session_->host_resolver()),
- // Testing with the proxy delegate is in HttpProxyConnectJobTest.
- nullptr);
- }
- scoped_refptr<IOBufferWithSize> SpdyProxyClientSocketTest::CreateBuffer(
- const char* data, int size) {
- scoped_refptr<IOBufferWithSize> buf =
- base::MakeRefCounted<IOBufferWithSize>(size);
- memcpy(buf->data(), data, size);
- return buf;
- }
- void SpdyProxyClientSocketTest::AssertConnectSucceeds() {
- ASSERT_THAT(sock_->Connect(read_callback_.callback()),
- IsError(ERR_IO_PENDING));
- ASSERT_THAT(read_callback_.WaitForResult(), IsOk());
- }
- void SpdyProxyClientSocketTest::AssertConnectFails(int result) {
- ASSERT_THAT(sock_->Connect(read_callback_.callback()),
- IsError(ERR_IO_PENDING));
- ASSERT_EQ(result, read_callback_.WaitForResult());
- }
- void SpdyProxyClientSocketTest::AssertConnectionEstablished() {
- const HttpResponseInfo* response = sock_->GetConnectResponseInfo();
- ASSERT_TRUE(response != nullptr);
- ASSERT_EQ(200, response->headers->response_code());
- // Although the underlying HTTP/2 connection uses TLS and negotiates ALPN, the
- // tunnel itself is a TCP connection to the origin and should not report these
- // values.
- net::SSLInfo ssl_info;
- EXPECT_FALSE(sock_->GetSSLInfo(&ssl_info));
- EXPECT_FALSE(sock_->WasAlpnNegotiated());
- EXPECT_EQ(sock_->GetNegotiatedProtocol(), NextProto::kProtoUnknown);
- }
- void SpdyProxyClientSocketTest::AssertSyncReadEquals(const char* data,
- int len) {
- scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(len);
- if (use_read_if_ready()) {
- ASSERT_EQ(len,
- sock_->ReadIfReady(buf.get(), len, CompletionOnceCallback()));
- } else {
- ASSERT_EQ(len, sock_->Read(buf.get(), len, CompletionOnceCallback()));
- }
- ASSERT_EQ(std::string(data, len), std::string(buf->data(), len));
- ASSERT_TRUE(sock_->IsConnected());
- }
- void SpdyProxyClientSocketTest::AssertSyncReadEOF() {
- if (use_read_if_ready()) {
- ASSERT_EQ(0, sock_->ReadIfReady(nullptr, 1, read_callback_.callback()));
- } else {
- ASSERT_EQ(0, sock_->Read(nullptr, 1, read_callback_.callback()));
- }
- }
- void SpdyProxyClientSocketTest::AssertAsyncReadEquals(const char* data,
- int len,
- bool fin) {
- // Issue the read, which will be completed asynchronously
- scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(len);
- if (use_read_if_ready()) {
- ASSERT_EQ(ERR_IO_PENDING,
- sock_->ReadIfReady(buf.get(), len, read_callback_.callback()));
- } else {
- ASSERT_EQ(ERR_IO_PENDING,
- sock_->Read(buf.get(), len, read_callback_.callback()));
- }
- EXPECT_TRUE(sock_->IsConnected());
- ResumeAndRun();
- if (use_read_if_ready()) {
- EXPECT_EQ(OK, read_callback_.WaitForResult());
- ASSERT_EQ(len,
- sock_->ReadIfReady(buf.get(), len, read_callback_.callback()));
- } else {
- EXPECT_EQ(len, read_callback_.WaitForResult());
- }
- if (fin) {
- EXPECT_FALSE(sock_->IsConnected());
- } else {
- EXPECT_TRUE(sock_->IsConnected());
- }
- ASSERT_EQ(std::string(data, len), std::string(buf->data(), len));
- }
- void SpdyProxyClientSocketTest::AssertReadStarts(const char* data, int len) {
- // Issue the read, which will be completed asynchronously.
- read_buf_ = base::MakeRefCounted<IOBuffer>(len);
- if (use_read_if_ready()) {
- ASSERT_EQ(ERR_IO_PENDING, sock_->ReadIfReady(read_buf_.get(), len,
- read_callback_.callback()));
- } else {
- ASSERT_EQ(ERR_IO_PENDING,
- sock_->Read(read_buf_.get(), len, read_callback_.callback()));
- }
- EXPECT_TRUE(sock_->IsConnected());
- }
- void SpdyProxyClientSocketTest::AssertReadReturns(const char* data, int len) {
- EXPECT_TRUE(sock_->IsConnected());
- // Now the read will return
- if (use_read_if_ready()) {
- EXPECT_EQ(OK, read_callback_.WaitForResult());
- ASSERT_EQ(len, sock_->ReadIfReady(read_buf_.get(), len,
- read_callback_.callback()));
- } else {
- EXPECT_EQ(len, read_callback_.WaitForResult());
- }
- ASSERT_EQ(std::string(data, len), std::string(read_buf_->data(), len));
- }
- void SpdyProxyClientSocketTest::AssertAsyncWriteSucceeds(const char* data,
- int len) {
- AssertWriteReturns(data, len, ERR_IO_PENDING);
- AssertWriteLength(len);
- }
- void SpdyProxyClientSocketTest::AssertWriteReturns(const char* data,
- int len,
- int rv) {
- scoped_refptr<IOBufferWithSize> buf(CreateBuffer(data, len));
- EXPECT_EQ(rv, sock_->Write(buf.get(), buf->size(), write_callback_.callback(),
- TRAFFIC_ANNOTATION_FOR_TESTS));
- }
- void SpdyProxyClientSocketTest::AssertWriteLength(int len) {
- EXPECT_EQ(len, write_callback_.WaitForResult());
- }
- void SpdyProxyClientSocketTest::PopulateConnectRequestIR(
- spdy::Http2HeaderBlock* block) {
- (*block)[spdy::kHttp2MethodHeader] = "CONNECT";
- (*block)[spdy::kHttp2AuthorityHeader] = kOriginHostPort;
- (*block)["user-agent"] = kUserAgent;
- }
- void SpdyProxyClientSocketTest::PopulateConnectReplyIR(
- spdy::Http2HeaderBlock* block,
- const char* status) {
- (*block)[spdy::kHttp2StatusHeader] = status;
- }
- // Constructs a standard SPDY HEADERS frame for a CONNECT request.
- spdy::SpdySerializedFrame
- SpdyProxyClientSocketTest::ConstructConnectRequestFrame(
- RequestPriority priority) {
- spdy::Http2HeaderBlock block;
- PopulateConnectRequestIR(&block);
- return spdy_util_.ConstructSpdyHeaders(kStreamId, std::move(block), priority,
- false);
- }
- // Constructs a SPDY HEADERS frame for a CONNECT request which includes
- // Proxy-Authorization headers.
- spdy::SpdySerializedFrame
- SpdyProxyClientSocketTest::ConstructConnectAuthRequestFrame() {
- spdy::Http2HeaderBlock block;
- PopulateConnectRequestIR(&block);
- block["proxy-authorization"] = "Basic Zm9vOmJhcg==";
- return spdy_util_.ConstructSpdyHeaders(kStreamId, std::move(block), LOWEST,
- false);
- }
- // Constructs a standard SPDY HEADERS frame to match the SPDY CONNECT.
- spdy::SpdySerializedFrame
- SpdyProxyClientSocketTest::ConstructConnectReplyFrame() {
- spdy::Http2HeaderBlock block;
- PopulateConnectReplyIR(&block, "200");
- return spdy_util_.ConstructSpdyReply(kStreamId, std::move(block));
- }
- // Constructs a standard SPDY HEADERS frame to match the SPDY CONNECT,
- // including Proxy-Authenticate headers.
- spdy::SpdySerializedFrame
- SpdyProxyClientSocketTest::ConstructConnectAuthReplyFrame() {
- spdy::Http2HeaderBlock block;
- PopulateConnectReplyIR(&block, "407");
- block["proxy-authenticate"] = "Basic realm=\"MyRealm1\"";
- return spdy_util_.ConstructSpdyReply(kStreamId, std::move(block));
- }
- // Constructs a SPDY HEADERS frame with an HTTP 302 redirect.
- spdy::SpdySerializedFrame
- SpdyProxyClientSocketTest::ConstructConnectRedirectReplyFrame() {
- spdy::Http2HeaderBlock block;
- PopulateConnectReplyIR(&block, "302");
- block["location"] = kRedirectUrl;
- block["set-cookie"] = "foo=bar";
- return spdy_util_.ConstructSpdyReply(kStreamId, std::move(block));
- }
- // Constructs a SPDY HEADERS frame with an HTTP 500 error.
- spdy::SpdySerializedFrame
- SpdyProxyClientSocketTest::ConstructConnectErrorReplyFrame() {
- spdy::Http2HeaderBlock block;
- PopulateConnectReplyIR(&block, "500");
- return spdy_util_.ConstructSpdyReply(kStreamId, std::move(block));
- }
- spdy::SpdySerializedFrame SpdyProxyClientSocketTest::ConstructBodyFrame(
- const char* data,
- int length,
- bool fin) {
- return spdy_util_.ConstructSpdyDataFrame(
- kStreamId, base::StringPiece(data, length), fin);
- }
- // ----------- Connect
- INSTANTIATE_TEST_SUITE_P(All,
- SpdyProxyClientSocketTest,
- ::testing::Bool());
- TEST_P(SpdyProxyClientSocketTest, ConnectSendsCorrectRequest) {
- spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame());
- MockWrite writes[] = {
- CreateMockWrite(conn, 0, SYNCHRONOUS),
- };
- spdy::SpdySerializedFrame resp(ConstructConnectReplyFrame());
- MockRead reads[] = {
- CreateMockRead(resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
- };
- Initialize(reads, writes);
- ASSERT_FALSE(sock_->IsConnected());
- AssertConnectSucceeds();
- AssertConnectionEstablished();
- }
- TEST_P(SpdyProxyClientSocketTest, ConnectWithAuthRequested) {
- spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame());
- MockWrite writes[] = {
- CreateMockWrite(conn, 0, SYNCHRONOUS),
- };
- spdy::SpdySerializedFrame resp(ConstructConnectAuthReplyFrame());
- MockRead reads[] = {
- CreateMockRead(resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
- };
- Initialize(reads, writes);
- AssertConnectFails(ERR_PROXY_AUTH_REQUESTED);
- const HttpResponseInfo* response = sock_->GetConnectResponseInfo();
- ASSERT_TRUE(response != nullptr);
- ASSERT_EQ(407, response->headers->response_code());
- }
- TEST_P(SpdyProxyClientSocketTest, ConnectWithAuthCredentials) {
- spdy::SpdySerializedFrame conn(ConstructConnectAuthRequestFrame());
- MockWrite writes[] = {
- CreateMockWrite(conn, 0, SYNCHRONOUS),
- };
- spdy::SpdySerializedFrame resp(ConstructConnectReplyFrame());
- MockRead reads[] = {
- CreateMockRead(resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
- };
- Initialize(reads, writes);
- AddAuthToCache();
- AssertConnectSucceeds();
- AssertConnectionEstablished();
- }
- TEST_P(SpdyProxyClientSocketTest, ConnectRedirects) {
- spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame());
- spdy::SpdySerializedFrame rst(
- spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_CANCEL));
- MockWrite writes[] = {
- CreateMockWrite(conn, 0, SYNCHRONOUS),
- };
- spdy::SpdySerializedFrame resp(ConstructConnectRedirectReplyFrame());
- MockRead reads[] = {
- CreateMockRead(resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
- };
- Initialize(reads, writes);
- AssertConnectFails(ERR_TUNNEL_CONNECTION_FAILED);
- const HttpResponseInfo* response = sock_->GetConnectResponseInfo();
- ASSERT_TRUE(response != nullptr);
- const HttpResponseHeaders* headers = response->headers.get();
- ASSERT_EQ(302, headers->response_code());
- ASSERT_TRUE(headers->HasHeader("set-cookie"));
- std::string location;
- ASSERT_TRUE(headers->IsRedirect(&location));
- ASSERT_EQ(location, kRedirectUrl);
- // Let the RST_STREAM write while |rst| is in-scope.
- base::RunLoop().RunUntilIdle();
- }
- TEST_P(SpdyProxyClientSocketTest, ConnectFails) {
- spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame());
- MockWrite writes[] = {
- CreateMockWrite(conn, 0, SYNCHRONOUS),
- };
- spdy::SpdySerializedFrame resp(ConstructConnectReplyFrame());
- MockRead reads[] = {
- MockRead(ASYNC, 0, 1), // EOF
- };
- Initialize(reads, writes);
- ASSERT_FALSE(sock_->IsConnected());
- AssertConnectFails(ERR_CONNECTION_CLOSED);
- ASSERT_FALSE(sock_->IsConnected());
- }
- TEST_P(SpdyProxyClientSocketTest, SetStreamPriority) {
- spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame(LOWEST));
- MockWrite writes[] = {
- CreateMockWrite(conn, 0, SYNCHRONOUS),
- };
- spdy::SpdySerializedFrame resp(ConstructConnectReplyFrame());
- MockRead reads[] = {
- CreateMockRead(resp, 1, ASYNC),
- MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
- };
- Initialize(reads, writes);
- // Set the stream priority. Since a connection was already established, it's
- // too late to adjust the HTTP2 stream's priority, and the request is ignored.
- sock_->SetStreamPriority(HIGHEST);
- AssertConnectSucceeds();
- }
- // ----------- WasEverUsed
- TEST_P(SpdyProxyClientSocketTest, WasEverUsedReturnsCorrectValues) {
- spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame());
- spdy::SpdySerializedFrame rst(
- spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_CANCEL));
- MockWrite writes[] = {
- CreateMockWrite(conn, 0, SYNCHRONOUS), CreateMockWrite(rst, 3),
- };
- spdy::SpdySerializedFrame resp(ConstructConnectReplyFrame());
- MockRead reads[] = {
- CreateMockRead(resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
- };
- Initialize(reads, writes);
- EXPECT_FALSE(sock_->WasEverUsed());
- AssertConnectSucceeds();
- EXPECT_TRUE(sock_->WasEverUsed());
- sock_->Disconnect();
- EXPECT_TRUE(sock_->WasEverUsed());
- // Let the RST_STREAM write while |rst| is in-scope.
- base::RunLoop().RunUntilIdle();
- }
- // ----------- GetPeerAddress
- TEST_P(SpdyProxyClientSocketTest, GetPeerAddressReturnsCorrectValues) {
- spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame());
- MockWrite writes[] = {
- CreateMockWrite(conn, 0, SYNCHRONOUS),
- };
- spdy::SpdySerializedFrame resp(ConstructConnectReplyFrame());
- MockRead reads[] = {
- CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2),
- MockRead(ASYNC, 0, 3), // EOF
- };
- Initialize(reads, writes);
- IPEndPoint addr;
- EXPECT_THAT(sock_->GetPeerAddress(&addr), IsError(ERR_SOCKET_NOT_CONNECTED));
- AssertConnectSucceeds();
- EXPECT_TRUE(sock_->IsConnected());
- EXPECT_THAT(sock_->GetPeerAddress(&addr), IsOk());
- ResumeAndRun();
- EXPECT_FALSE(sock_->IsConnected());
- EXPECT_THAT(sock_->GetPeerAddress(&addr), IsError(ERR_SOCKET_NOT_CONNECTED));
- sock_->Disconnect();
- EXPECT_THAT(sock_->GetPeerAddress(&addr), IsError(ERR_SOCKET_NOT_CONNECTED));
- }
- // ----------- Write
- TEST_P(SpdyProxyClientSocketTest, WriteSendsDataInDataFrame) {
- spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame());
- spdy::SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1));
- spdy::SpdySerializedFrame msg2(ConstructBodyFrame(kMsg2, kLen2));
- MockWrite writes[] = {
- CreateMockWrite(conn, 0, SYNCHRONOUS),
- CreateMockWrite(msg1, 3, SYNCHRONOUS),
- CreateMockWrite(msg2, 4, SYNCHRONOUS),
- };
- spdy::SpdySerializedFrame resp(ConstructConnectReplyFrame());
- MockRead reads[] = {
- CreateMockRead(resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
- };
- Initialize(reads, writes);
- AssertConnectSucceeds();
- AssertAsyncWriteSucceeds(kMsg1, kLen1);
- AssertAsyncWriteSucceeds(kMsg2, kLen2);
- }
- TEST_P(SpdyProxyClientSocketTest, WriteSplitsLargeDataIntoMultipleFrames) {
- std::string chunk_data(kMaxSpdyFrameChunkSize, 'x');
- spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame());
- spdy::SpdySerializedFrame chunk(
- ConstructBodyFrame(chunk_data.data(), chunk_data.length()));
- MockWrite writes[] = {CreateMockWrite(conn, 0, SYNCHRONOUS),
- CreateMockWrite(chunk, 3, SYNCHRONOUS),
- CreateMockWrite(chunk, 4, SYNCHRONOUS),
- CreateMockWrite(chunk, 5, SYNCHRONOUS)};
- spdy::SpdySerializedFrame resp(ConstructConnectReplyFrame());
- MockRead reads[] = {
- CreateMockRead(resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
- };
- Initialize(reads, writes);
- AssertConnectSucceeds();
- std::string big_data(kMaxSpdyFrameChunkSize * 3, 'x');
- scoped_refptr<IOBufferWithSize> buf(CreateBuffer(big_data.data(),
- big_data.length()));
- EXPECT_EQ(ERR_IO_PENDING,
- sock_->Write(buf.get(), buf->size(), write_callback_.callback(),
- TRAFFIC_ANNOTATION_FOR_TESTS));
- EXPECT_EQ(buf->size(), write_callback_.WaitForResult());
- }
- // ----------- Read
- TEST_P(SpdyProxyClientSocketTest, ReadReadsDataInDataFrame) {
- spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame());
- MockWrite writes[] = {
- CreateMockWrite(conn, 0, SYNCHRONOUS),
- };
- spdy::SpdySerializedFrame resp(ConstructConnectReplyFrame());
- spdy::SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1));
- MockRead reads[] = {
- CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(msg1, 3, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 4),
- };
- Initialize(reads, writes);
- AssertConnectSucceeds();
- // SpdySession consumes the next read and sends it to sock_ to be buffered.
- ResumeAndRun();
- AssertSyncReadEquals(kMsg1, kLen1);
- }
- TEST_P(SpdyProxyClientSocketTest, ReadDataFromBufferedFrames) {
- spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame());
- MockWrite writes[] = {
- CreateMockWrite(conn, 0, SYNCHRONOUS),
- };
- spdy::SpdySerializedFrame resp(ConstructConnectReplyFrame());
- spdy::SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1));
- spdy::SpdySerializedFrame msg2(ConstructBodyFrame(kMsg2, kLen2));
- MockRead reads[] = {
- CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(msg1, 3, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 4),
- CreateMockRead(msg2, 5, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6),
- };
- Initialize(reads, writes);
- AssertConnectSucceeds();
- // SpdySession consumes the next read and sends it to sock_ to be buffered.
- ResumeAndRun();
- AssertSyncReadEquals(kMsg1, kLen1);
- // SpdySession consumes the next read and sends it to sock_ to be buffered.
- ResumeAndRun();
- AssertSyncReadEquals(kMsg2, kLen2);
- }
- TEST_P(SpdyProxyClientSocketTest, ReadDataMultipleBufferedFrames) {
- spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame());
- MockWrite writes[] = {
- CreateMockWrite(conn, 0, SYNCHRONOUS),
- };
- spdy::SpdySerializedFrame resp(ConstructConnectReplyFrame());
- spdy::SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1));
- spdy::SpdySerializedFrame msg2(ConstructBodyFrame(kMsg2, kLen2));
- MockRead reads[] = {
- CreateMockRead(resp, 1, ASYNC),
- MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(msg1, 3, ASYNC),
- CreateMockRead(msg2, 4, ASYNC),
- MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5),
- };
- Initialize(reads, writes);
- AssertConnectSucceeds();
- // SpdySession consumes the next two reads and sends then to sock_ to be
- // buffered.
- ResumeAndRun();
- AssertSyncReadEquals(kMsg1, kLen1);
- AssertSyncReadEquals(kMsg2, kLen2);
- }
- TEST_P(SpdyProxyClientSocketTest, LargeReadWillMergeDataFromDifferentFrames) {
- spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame());
- MockWrite writes[] = {
- CreateMockWrite(conn, 0, SYNCHRONOUS),
- };
- spdy::SpdySerializedFrame resp(ConstructConnectReplyFrame());
- spdy::SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1));
- spdy::SpdySerializedFrame msg3(ConstructBodyFrame(kMsg3, kLen3));
- MockRead reads[] = {
- CreateMockRead(resp, 1, ASYNC),
- MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(msg3, 3, ASYNC),
- CreateMockRead(msg3, 4, ASYNC),
- MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5),
- };
- Initialize(reads, writes);
- AssertConnectSucceeds();
- // SpdySession consumes the next two reads and sends then to sock_ to be
- // buffered.
- ResumeAndRun();
- // The payload from two data frames, each with kMsg3 will be combined
- // together into a single read().
- AssertSyncReadEquals(kMsg33, kLen33);
- }
- TEST_P(SpdyProxyClientSocketTest, MultipleShortReadsThenMoreRead) {
- spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame());
- MockWrite writes[] = {
- CreateMockWrite(conn, 0, SYNCHRONOUS),
- };
- spdy::SpdySerializedFrame resp(ConstructConnectReplyFrame());
- spdy::SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1));
- spdy::SpdySerializedFrame msg3(ConstructBodyFrame(kMsg3, kLen3));
- spdy::SpdySerializedFrame msg2(ConstructBodyFrame(kMsg2, kLen2));
- MockRead reads[] = {
- CreateMockRead(resp, 1, ASYNC),
- MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(msg1, 3, ASYNC),
- CreateMockRead(msg3, 4, ASYNC),
- CreateMockRead(msg3, 5, ASYNC),
- CreateMockRead(msg2, 6, ASYNC),
- MockRead(SYNCHRONOUS, ERR_IO_PENDING, 7),
- };
- Initialize(reads, writes);
- AssertConnectSucceeds();
- // SpdySession consumes the next four reads and sends then to sock_ to be
- // buffered.
- ResumeAndRun();
- AssertSyncReadEquals(kMsg1, kLen1);
- // The payload from two data frames, each with kMsg3 will be combined
- // together into a single read().
- AssertSyncReadEquals(kMsg33, kLen33);
- AssertSyncReadEquals(kMsg2, kLen2);
- }
- TEST_P(SpdyProxyClientSocketTest, ReadWillSplitDataFromLargeFrame) {
- spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame());
- MockWrite writes[] = {
- CreateMockWrite(conn, 0, SYNCHRONOUS),
- };
- spdy::SpdySerializedFrame resp(ConstructConnectReplyFrame());
- spdy::SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1));
- spdy::SpdySerializedFrame msg33(ConstructBodyFrame(kMsg33, kLen33));
- spdy::SpdySerializedFrame msg2(ConstructBodyFrame(kMsg2, kLen2));
- MockRead reads[] = {
- CreateMockRead(resp, 1, ASYNC),
- MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(msg1, 3, ASYNC),
- CreateMockRead(msg33, 4, ASYNC),
- MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5),
- };
- Initialize(reads, writes);
- AssertConnectSucceeds();
- // SpdySession consumes the next two reads and sends then to sock_ to be
- // buffered.
- ResumeAndRun();
- AssertSyncReadEquals(kMsg1, kLen1);
- // The payload from the single large data frame will be read across
- // two different reads.
- AssertSyncReadEquals(kMsg3, kLen3);
- AssertSyncReadEquals(kMsg3, kLen3);
- }
- TEST_P(SpdyProxyClientSocketTest, MultipleReadsFromSameLargeFrame) {
- spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame());
- MockWrite writes[] = {
- CreateMockWrite(conn, 0, SYNCHRONOUS),
- };
- spdy::SpdySerializedFrame resp(ConstructConnectReplyFrame());
- spdy::SpdySerializedFrame msg333(ConstructBodyFrame(kMsg333, kLen333));
- MockRead reads[] = {
- CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(msg333, 3, ASYNC),
- MockRead(SYNCHRONOUS, ERR_IO_PENDING, 4),
- };
- Initialize(reads, writes);
- AssertConnectSucceeds();
- // SpdySession consumes the next read and sends it to sock_ to be buffered.
- ResumeAndRun();
- // The payload from the single large data frame will be read across
- // two different reads.
- AssertSyncReadEquals(kMsg33, kLen33);
- // Now attempt to do a read of more data than remains buffered
- AssertSyncReadEquals(kMsg3, kLen3);
- ASSERT_TRUE(sock_->IsConnected());
- }
- TEST_P(SpdyProxyClientSocketTest, ReadAuthResponseBody) {
- spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame());
- MockWrite writes[] = {
- CreateMockWrite(conn, 0, SYNCHRONOUS),
- };
- spdy::SpdySerializedFrame resp(ConstructConnectAuthReplyFrame());
- spdy::SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1));
- spdy::SpdySerializedFrame msg2(ConstructBodyFrame(kMsg2, kLen2));
- MockRead reads[] = {
- CreateMockRead(resp, 1, ASYNC),
- MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(msg1, 3, ASYNC),
- CreateMockRead(msg2, 4, ASYNC),
- MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5),
- };
- Initialize(reads, writes);
- AssertConnectFails(ERR_PROXY_AUTH_REQUESTED);
- // SpdySession consumes the next two reads and sends then to sock_ to be
- // buffered.
- ResumeAndRun();
- AssertSyncReadEquals(kMsg1, kLen1);
- AssertSyncReadEquals(kMsg2, kLen2);
- }
- TEST_P(SpdyProxyClientSocketTest, ReadErrorResponseBody) {
- spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame());
- MockWrite writes[] = {
- CreateMockWrite(conn, 0, SYNCHRONOUS),
- };
- spdy::SpdySerializedFrame resp(ConstructConnectErrorReplyFrame());
- spdy::SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1));
- spdy::SpdySerializedFrame msg2(ConstructBodyFrame(kMsg2, kLen2));
- MockRead reads[] = {
- CreateMockRead(resp, 1, ASYNC), CreateMockRead(msg1, 2, SYNCHRONOUS),
- CreateMockRead(msg2, 3, SYNCHRONOUS), MockRead(SYNCHRONOUS, 0, 4), // EOF
- };
- Initialize(reads, writes);
- AssertConnectFails(ERR_TUNNEL_CONNECTION_FAILED);
- }
- TEST_P(SpdyProxyClientSocketTest, SocketDestroyedWhenReadIsPending) {
- spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame());
- MockWrite writes[] = {CreateMockWrite(conn, 0, SYNCHRONOUS)};
- spdy::SpdySerializedFrame resp(ConstructConnectReplyFrame());
- spdy::SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1));
- MockRead reads[] = {
- CreateMockRead(resp, 1, ASYNC), CreateMockRead(msg1, 2, ASYNC),
- MockRead(SYNCHRONOUS, ERR_IO_PENDING, 3),
- };
- Initialize(reads, writes);
- AssertConnectSucceeds();
- // Make Read()/ReadIfReady() pending.
- AssertReadStarts(kMsg1, kLen1);
- // Destroying socket.
- sock_ = nullptr;
- // Read data is not consumed.
- EXPECT_TRUE(data_->AllWriteDataConsumed());
- EXPECT_FALSE(data_->AllReadDataConsumed());
- // Reset |data_| so the test destructor doesn't check it.
- data_ = nullptr;
- }
- // ----------- Reads and Writes
- TEST_P(SpdyProxyClientSocketTest, AsyncReadAroundWrite) {
- spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame());
- spdy::SpdySerializedFrame msg2(ConstructBodyFrame(kMsg2, kLen2));
- MockWrite writes[] = {
- CreateMockWrite(conn, 0, SYNCHRONOUS),
- CreateMockWrite(msg2, 4, SYNCHRONOUS),
- };
- spdy::SpdySerializedFrame resp(ConstructConnectReplyFrame());
- spdy::SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1));
- spdy::SpdySerializedFrame msg3(ConstructBodyFrame(kMsg3, kLen3));
- MockRead reads[] = {
- CreateMockRead(resp, 1, ASYNC),
- MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(msg1, 3, ASYNC), // sync read
- MockRead(ASYNC, ERR_IO_PENDING, 5),
- CreateMockRead(msg3, 6, ASYNC), // async read
- MockRead(SYNCHRONOUS, ERR_IO_PENDING, 7),
- };
- Initialize(reads, writes);
- AssertConnectSucceeds();
- ResumeAndRun();
- AssertSyncReadEquals(kMsg1, kLen1);
- AssertReadStarts(kMsg3, kLen3);
- // Read should block until after the write succeeds.
- AssertAsyncWriteSucceeds(kMsg2, kLen2); // Advances past paused read.
- ASSERT_FALSE(read_callback_.have_result());
- ResumeAndRun();
- // Now the read will return.
- AssertReadReturns(kMsg3, kLen3);
- }
- TEST_P(SpdyProxyClientSocketTest, AsyncWriteAroundReads) {
- spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame());
- spdy::SpdySerializedFrame msg2(ConstructBodyFrame(kMsg2, kLen2));
- MockWrite writes[] = {
- CreateMockWrite(conn, 0, SYNCHRONOUS),
- MockWrite(ASYNC, ERR_IO_PENDING, 7), CreateMockWrite(msg2, 8, ASYNC),
- };
- spdy::SpdySerializedFrame resp(ConstructConnectReplyFrame());
- spdy::SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1));
- spdy::SpdySerializedFrame msg3(ConstructBodyFrame(kMsg3, kLen3));
- MockRead reads[] = {
- CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(msg1, 3, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 4),
- CreateMockRead(msg3, 5, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6),
- };
- Initialize(reads, writes);
- AssertConnectSucceeds();
- ResumeAndRun();
- AssertSyncReadEquals(kMsg1, kLen1);
- // Write should block until the read completes
- AssertWriteReturns(kMsg2, kLen2, ERR_IO_PENDING);
- AssertAsyncReadEquals(kMsg3, kLen3);
- ASSERT_FALSE(write_callback_.have_result());
- // Now the write will complete
- ResumeAndRun();
- AssertWriteLength(kLen2);
- }
- // ----------- Reading/Writing on Closed socket
- // Reading from an already closed socket should return 0
- TEST_P(SpdyProxyClientSocketTest, ReadOnClosedSocketReturnsZero) {
- spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame());
- MockWrite writes[] = {
- CreateMockWrite(conn, 0, SYNCHRONOUS),
- };
- spdy::SpdySerializedFrame resp(ConstructConnectReplyFrame());
- MockRead reads[] = {
- CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2),
- MockRead(ASYNC, 0, 3), // EOF
- };
- Initialize(reads, writes);
- AssertConnectSucceeds();
- ResumeAndRun();
- ASSERT_FALSE(sock_->IsConnected());
- AssertSyncReadEOF();
- AssertSyncReadEOF();
- AssertSyncReadEOF();
- ASSERT_FALSE(sock_->IsConnectedAndIdle());
- }
- // Read pending when socket is closed should return 0
- TEST_P(SpdyProxyClientSocketTest, PendingReadOnCloseReturnsZero) {
- spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame());
- MockWrite writes[] = {
- CreateMockWrite(conn, 0, SYNCHRONOUS),
- };
- spdy::SpdySerializedFrame resp(ConstructConnectReplyFrame());
- MockRead reads[] = {
- CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2),
- MockRead(ASYNC, 0, 3), // EOF
- };
- Initialize(reads, writes);
- AssertConnectSucceeds();
- AssertReadStarts(kMsg1, kLen1);
- ResumeAndRun();
- ASSERT_EQ(0, read_callback_.WaitForResult());
- }
- // Reading from a disconnected socket is an error
- TEST_P(SpdyProxyClientSocketTest, ReadOnDisconnectSocketReturnsNotConnected) {
- spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame());
- spdy::SpdySerializedFrame rst(
- spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_CANCEL));
- MockWrite writes[] = {
- CreateMockWrite(conn, 0, SYNCHRONOUS), CreateMockWrite(rst, 3),
- };
- spdy::SpdySerializedFrame resp(ConstructConnectReplyFrame());
- MockRead reads[] = {
- CreateMockRead(resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
- };
- Initialize(reads, writes);
- AssertConnectSucceeds();
- sock_->Disconnect();
- if (use_read_if_ready()) {
- ASSERT_EQ(ERR_SOCKET_NOT_CONNECTED,
- sock_->ReadIfReady(nullptr, 1, CompletionOnceCallback()));
- } else {
- ASSERT_EQ(ERR_SOCKET_NOT_CONNECTED,
- sock_->Read(nullptr, 1, CompletionOnceCallback()));
- }
- // Let the RST_STREAM write while |rst| is in-scope.
- base::RunLoop().RunUntilIdle();
- }
- // Reading buffered data from an already closed socket should return
- // buffered data, then 0.
- TEST_P(SpdyProxyClientSocketTest, ReadOnClosedSocketReturnsBufferedData) {
- spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame());
- MockWrite writes[] = {
- CreateMockWrite(conn, 0, SYNCHRONOUS),
- };
- spdy::SpdySerializedFrame resp(ConstructConnectReplyFrame());
- spdy::SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1));
- MockRead reads[] = {
- CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(msg1, 3, ASYNC), MockRead(ASYNC, 0, 4), // EOF
- };
- Initialize(reads, writes);
- AssertConnectSucceeds();
- ResumeAndRun();
- ASSERT_FALSE(sock_->IsConnected());
- scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(kLen1);
- ASSERT_EQ(kLen1, sock_->Read(buf.get(), kLen1, CompletionOnceCallback()));
- ASSERT_EQ(std::string(kMsg1, kLen1), std::string(buf->data(), kLen1));
- ASSERT_EQ(0, sock_->Read(nullptr, 1, CompletionOnceCallback()));
- ASSERT_EQ(0, sock_->Read(nullptr, 1, CompletionOnceCallback()));
- sock_->Disconnect();
- ASSERT_EQ(ERR_SOCKET_NOT_CONNECTED,
- sock_->Read(nullptr, 1, CompletionOnceCallback()));
- }
- // Calling Write() on a closed socket is an error
- TEST_P(SpdyProxyClientSocketTest, WriteOnClosedStream) {
- spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame());
- MockWrite writes[] = {
- CreateMockWrite(conn, 0, SYNCHRONOUS),
- };
- spdy::SpdySerializedFrame resp(ConstructConnectReplyFrame());
- spdy::SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1));
- MockRead reads[] = {
- CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2),
- MockRead(ASYNC, 0, 3), // EOF
- };
- Initialize(reads, writes);
- AssertConnectSucceeds();
- // Read EOF which will close the stream.
- ResumeAndRun();
- scoped_refptr<IOBufferWithSize> buf(CreateBuffer(kMsg1, kLen1));
- EXPECT_EQ(ERR_SOCKET_NOT_CONNECTED,
- sock_->Write(buf.get(), buf->size(), CompletionOnceCallback(),
- TRAFFIC_ANNOTATION_FOR_TESTS));
- }
- // Calling Write() on a disconnected socket is an error.
- TEST_P(SpdyProxyClientSocketTest, WriteOnDisconnectedSocket) {
- spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame());
- spdy::SpdySerializedFrame rst(
- spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_CANCEL));
- MockWrite writes[] = {
- CreateMockWrite(conn, 0, SYNCHRONOUS), CreateMockWrite(rst, 3),
- };
- spdy::SpdySerializedFrame resp(ConstructConnectReplyFrame());
- spdy::SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1));
- MockRead reads[] = {
- CreateMockRead(resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
- };
- Initialize(reads, writes);
- AssertConnectSucceeds();
- sock_->Disconnect();
- scoped_refptr<IOBufferWithSize> buf(CreateBuffer(kMsg1, kLen1));
- EXPECT_EQ(ERR_SOCKET_NOT_CONNECTED,
- sock_->Write(buf.get(), buf->size(), CompletionOnceCallback(),
- TRAFFIC_ANNOTATION_FOR_TESTS));
- // Let the RST_STREAM write while |rst| is in-scope.
- base::RunLoop().RunUntilIdle();
- }
- // If the socket is closed with a pending Write(), the callback
- // should be called with ERR_CONNECTION_CLOSED.
- TEST_P(SpdyProxyClientSocketTest, WritePendingOnClose) {
- spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame());
- MockWrite writes[] = {
- CreateMockWrite(conn, 0, SYNCHRONOUS),
- MockWrite(SYNCHRONOUS, ERR_IO_PENDING, 3),
- };
- spdy::SpdySerializedFrame resp(ConstructConnectReplyFrame());
- MockRead reads[] = {
- CreateMockRead(resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
- };
- Initialize(reads, writes);
- AssertConnectSucceeds();
- EXPECT_TRUE(sock_->IsConnected());
- scoped_refptr<IOBufferWithSize> buf(CreateBuffer(kMsg1, kLen1));
- EXPECT_EQ(ERR_IO_PENDING,
- sock_->Write(buf.get(), buf->size(), write_callback_.callback(),
- TRAFFIC_ANNOTATION_FOR_TESTS));
- // Make sure the write actually starts.
- base::RunLoop().RunUntilIdle();
- CloseSpdySession(ERR_ABORTED, std::string());
- EXPECT_THAT(write_callback_.WaitForResult(), IsError(ERR_CONNECTION_CLOSED));
- }
- // If the socket is Disconnected with a pending Write(), the callback
- // should not be called.
- TEST_P(SpdyProxyClientSocketTest, DisconnectWithWritePending) {
- spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame());
- spdy::SpdySerializedFrame rst(
- spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_CANCEL));
- MockWrite writes[] = {
- CreateMockWrite(conn, 0, SYNCHRONOUS), CreateMockWrite(rst, 3),
- };
- spdy::SpdySerializedFrame resp(ConstructConnectReplyFrame());
- MockRead reads[] = {
- CreateMockRead(resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
- };
- Initialize(reads, writes);
- AssertConnectSucceeds();
- EXPECT_TRUE(sock_->IsConnected());
- scoped_refptr<IOBufferWithSize> buf(CreateBuffer(kMsg1, kLen1));
- EXPECT_EQ(ERR_IO_PENDING,
- sock_->Write(buf.get(), buf->size(), write_callback_.callback(),
- TRAFFIC_ANNOTATION_FOR_TESTS));
- sock_->Disconnect();
- EXPECT_FALSE(sock_->IsConnected());
- EXPECT_FALSE(write_callback_.have_result());
- // Let the RST_STREAM write while |rst| is in-scope.
- base::RunLoop().RunUntilIdle();
- }
- // If the socket is Disconnected with a pending Read(), the callback
- // should not be called.
- TEST_P(SpdyProxyClientSocketTest, DisconnectWithReadPending) {
- spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame());
- spdy::SpdySerializedFrame rst(
- spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_CANCEL));
- MockWrite writes[] = {
- CreateMockWrite(conn, 0, SYNCHRONOUS), CreateMockWrite(rst, 3),
- };
- spdy::SpdySerializedFrame resp(ConstructConnectReplyFrame());
- MockRead reads[] = {
- CreateMockRead(resp, 1, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
- };
- Initialize(reads, writes);
- AssertConnectSucceeds();
- EXPECT_TRUE(sock_->IsConnected());
- scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(kLen1);
- ASSERT_EQ(ERR_IO_PENDING,
- sock_->Read(buf.get(), kLen1, read_callback_.callback()));
- sock_->Disconnect();
- EXPECT_FALSE(sock_->IsConnected());
- EXPECT_FALSE(read_callback_.have_result());
- // Let the RST_STREAM write while |rst| is in-scope.
- base::RunLoop().RunUntilIdle();
- }
- // If the socket is Reset when both a read and write are pending,
- // both should be called back.
- TEST_P(SpdyProxyClientSocketTest, RstWithReadAndWritePending) {
- spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame());
- MockWrite writes[] = {
- CreateMockWrite(conn, 0, SYNCHRONOUS),
- };
- spdy::SpdySerializedFrame resp(ConstructConnectReplyFrame());
- spdy::SpdySerializedFrame rst(
- spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_CANCEL));
- MockRead reads[] = {
- CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(rst, 3, ASYNC), MockRead(ASYNC, 0, 4) // EOF
- };
- Initialize(reads, writes);
- AssertConnectSucceeds();
- EXPECT_TRUE(sock_->IsConnected());
- scoped_refptr<IOBuffer> read_buf = base::MakeRefCounted<IOBuffer>(kLen1);
- ASSERT_EQ(ERR_IO_PENDING,
- sock_->Read(read_buf.get(), kLen1, read_callback_.callback()));
- scoped_refptr<IOBufferWithSize> write_buf(CreateBuffer(kMsg1, kLen1));
- EXPECT_EQ(ERR_IO_PENDING, sock_->Write(write_buf.get(), write_buf->size(),
- write_callback_.callback(),
- TRAFFIC_ANNOTATION_FOR_TESTS));
- ResumeAndRun();
- EXPECT_TRUE(sock_.get());
- EXPECT_TRUE(read_callback_.have_result());
- EXPECT_TRUE(write_callback_.have_result());
- // Let the RST_STREAM write while |rst| is in-scope.
- base::RunLoop().RunUntilIdle();
- }
- // Makes sure the proxy client socket's source gets the expected NetLog events
- // and only the expected NetLog events (No SpdySession events).
- TEST_P(SpdyProxyClientSocketTest, NetLog) {
- spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame());
- spdy::SpdySerializedFrame rst(
- spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_CANCEL));
- MockWrite writes[] = {
- CreateMockWrite(conn, 0, SYNCHRONOUS), CreateMockWrite(rst, 5),
- };
- spdy::SpdySerializedFrame resp(ConstructConnectReplyFrame());
- spdy::SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1));
- MockRead reads[] = {
- CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(msg1, 3, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 4),
- };
- Initialize(reads, writes);
- AssertConnectSucceeds();
- // SpdySession consumes the next read and sends it to sock_ to be buffered.
- ResumeAndRun();
- AssertSyncReadEquals(kMsg1, kLen1);
- NetLogSource sock_source = sock_->NetLog().source();
- sock_.reset();
- auto entry_list = net_log_observer_.GetEntriesForSource(sock_source);
- ASSERT_EQ(entry_list.size(), 10u);
- EXPECT_TRUE(
- LogContainsBeginEvent(entry_list, 0, NetLogEventType::SOCKET_ALIVE));
- EXPECT_TRUE(LogContainsEvent(entry_list, 1,
- NetLogEventType::HTTP2_PROXY_CLIENT_SESSION,
- NetLogEventPhase::NONE));
- EXPECT_TRUE(LogContainsBeginEvent(
- entry_list, 2, NetLogEventType::HTTP_TRANSACTION_TUNNEL_SEND_REQUEST));
- EXPECT_TRUE(LogContainsEvent(
- entry_list, 3, NetLogEventType::HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
- NetLogEventPhase::NONE));
- EXPECT_TRUE(LogContainsEndEvent(
- entry_list, 4, NetLogEventType::HTTP_TRANSACTION_TUNNEL_SEND_REQUEST));
- EXPECT_TRUE(LogContainsBeginEvent(
- entry_list, 5, NetLogEventType::HTTP_TRANSACTION_TUNNEL_READ_HEADERS));
- EXPECT_TRUE(LogContainsEvent(
- entry_list, 6,
- NetLogEventType::HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
- NetLogEventPhase::NONE));
- EXPECT_TRUE(LogContainsEndEvent(
- entry_list, 7, NetLogEventType::HTTP_TRANSACTION_TUNNEL_READ_HEADERS));
- EXPECT_TRUE(LogContainsEvent(entry_list, 8,
- NetLogEventType::SOCKET_BYTES_RECEIVED,
- NetLogEventPhase::NONE));
- EXPECT_TRUE(
- LogContainsEndEvent(entry_list, 9, NetLogEventType::SOCKET_ALIVE));
- // Let the RST_STREAM write while |rst| is in-scope.
- base::RunLoop().RunUntilIdle();
- }
- // A helper class that will delete |sock| when the callback is invoked.
- class DeleteSockCallback : public TestCompletionCallbackBase {
- public:
- explicit DeleteSockCallback(std::unique_ptr<SpdyProxyClientSocket>* sock)
- : sock_(sock) {}
- DeleteSockCallback(const DeleteSockCallback&) = delete;
- DeleteSockCallback& operator=(const DeleteSockCallback&) = delete;
- ~DeleteSockCallback() override = default;
- CompletionOnceCallback callback() {
- return base::BindOnce(&DeleteSockCallback::OnComplete,
- base::Unretained(this));
- }
- private:
- void OnComplete(int result) {
- sock_->reset(nullptr);
- SetResult(result);
- }
- raw_ptr<std::unique_ptr<SpdyProxyClientSocket>> sock_;
- };
- // If the socket is Reset when both a read and write are pending, and the
- // read callback causes the socket to be deleted, the write callback should
- // not be called.
- TEST_P(SpdyProxyClientSocketTest, RstWithReadAndWritePendingDelete) {
- spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame());
- MockWrite writes[] = {
- CreateMockWrite(conn, 0, SYNCHRONOUS),
- };
- spdy::SpdySerializedFrame resp(ConstructConnectReplyFrame());
- spdy::SpdySerializedFrame rst(
- spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_CANCEL));
- MockRead reads[] = {
- CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(rst, 3, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 4),
- };
- Initialize(reads, writes);
- AssertConnectSucceeds();
- EXPECT_TRUE(sock_->IsConnected());
- DeleteSockCallback read_callback(&sock_);
- scoped_refptr<IOBuffer> read_buf = base::MakeRefCounted<IOBuffer>(kLen1);
- ASSERT_EQ(ERR_IO_PENDING,
- sock_->Read(read_buf.get(), kLen1, read_callback.callback()));
- scoped_refptr<IOBufferWithSize> write_buf(CreateBuffer(kMsg1, kLen1));
- EXPECT_EQ(ERR_IO_PENDING, sock_->Write(write_buf.get(), write_buf->size(),
- write_callback_.callback(),
- TRAFFIC_ANNOTATION_FOR_TESTS));
- ResumeAndRun();
- EXPECT_FALSE(sock_.get());
- EXPECT_TRUE(read_callback.have_result());
- EXPECT_FALSE(write_callback_.have_result());
- // Let the RST_STREAM write while |rst| is in-scope.
- base::RunLoop().RunUntilIdle();
- }
- // ----------- Canceling a ReadIfReady
- TEST_P(SpdyProxyClientSocketTest, CancelReadIfReady) {
- // Not relevant if not ReadIfReady().
- if (!use_read_if_ready())
- return;
- spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame());
- MockWrite writes[] = {CreateMockWrite(conn, 0, SYNCHRONOUS)};
- spdy::SpdySerializedFrame resp(ConstructConnectReplyFrame());
- spdy::SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1));
- spdy::SpdySerializedFrame msg3(ConstructBodyFrame(kMsg3, kLen3));
- MockRead reads[] = {
- CreateMockRead(resp, 1, ASYNC), CreateMockRead(msg1, 2, ASYNC),
- CreateMockRead(msg3, 3, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 4),
- };
- Initialize(reads, writes);
- AssertConnectSucceeds();
- AssertReadStarts(kMsg1, kLen1);
- EXPECT_EQ(OK, sock_->CancelReadIfReady());
- // Perform ReadIfReady again should succeed after cancelation.
- AssertReadStarts(kMsg1, kLen1);
- AssertReadReturns(kMsg1, kLen1);
- AssertReadStarts(kMsg3, kLen3);
- AssertReadReturns(kMsg3, kLen3);
- // Canceling ReadIfReady() when none is in progress is an no-op.
- EXPECT_EQ(OK, sock_->CancelReadIfReady());
- }
- // ----------- Handling END_STREAM from the peer
- TEST_P(SpdyProxyClientSocketTest, HandleEndStreamAsEOF) {
- spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame());
- spdy::SpdySerializedFrame end_stream(
- ConstructBodyFrame(/*data=*/nullptr, /*length=*/0, /*fin=*/true));
- MockWrite writes[] = {
- CreateMockWrite(conn, 0, SYNCHRONOUS),
- CreateMockWrite(end_stream, 7, SYNCHRONOUS),
- };
- spdy::SpdySerializedFrame resp(ConstructConnectReplyFrame());
- spdy::SpdySerializedFrame msg1(ConstructBodyFrame(kMsg1, kLen1));
- spdy::SpdySerializedFrame msg2(
- ConstructBodyFrame(kMsg2, kLen2, /*fin=*/true));
- MockRead reads[] = {
- CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(msg1, 3, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 4),
- CreateMockRead(msg2, 5, ASYNC), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6),
- };
- Initialize(reads, writes);
- AssertConnectSucceeds();
- AssertAsyncReadEquals(kMsg1, kLen1);
- AssertAsyncReadEquals(kMsg2, kLen2, /*fin=*/true);
- }
- TEST_P(SpdyProxyClientSocketTest, SendEndStreamAfterWrite) {
- spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame());
- spdy::SpdySerializedFrame write_msg(ConstructBodyFrame(kMsg1, kLen1));
- spdy::SpdySerializedFrame end_stream(
- ConstructBodyFrame(/*data=*/nullptr, /*length=*/0, /*fin=*/true));
- MockWrite writes[] = {
- CreateMockWrite(conn, 0, SYNCHRONOUS),
- CreateMockWrite(write_msg, 4, ASYNC),
- CreateMockWrite(end_stream, 6, ASYNC),
- };
- spdy::SpdySerializedFrame resp(ConstructConnectReplyFrame());
- spdy::SpdySerializedFrame read_msg(
- ConstructBodyFrame(kMsg2, kLen2, /*fin=*/true));
- MockRead reads[] = {
- CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(read_msg, 3, ASYNC), MockRead(ASYNC, ERR_IO_PENDING, 5),
- MockRead(SYNCHRONOUS, 0, 7),
- };
- Initialize(reads, writes);
- AssertConnectSucceeds();
- AssertWriteReturns(kMsg1, kLen1, ERR_IO_PENDING);
- AssertAsyncReadEquals(kMsg2, kLen2, /*fin=*/false);
- ResumeAndRun();
- AssertWriteLength(kLen1);
- AssertSyncReadEOF();
- }
- // Regression test for https://crbug.com/1320256
- TEST_P(SpdyProxyClientSocketTest, WriteAfterStreamEndSent) {
- spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame());
- MockWrite writes[] = {
- CreateMockWrite(conn, 0, SYNCHRONOUS),
- // The following mock write blocks SpdyStream::SendData() in
- // SpdyProxyClientSocket::MaybeSendEndStream().
- MockWrite(SYNCHRONOUS, ERR_IO_PENDING, 5),
- };
- spdy::SpdySerializedFrame resp(ConstructConnectReplyFrame());
- spdy::SpdySerializedFrame read_msg(
- ConstructBodyFrame(kMsg1, kLen1, /*fin=*/true));
- MockRead reads[] = {
- CreateMockRead(resp, 1, ASYNC),
- MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(read_msg, 3, ASYNC),
- MockRead(SYNCHRONOUS, ERR_IO_PENDING, 4),
- };
- Initialize(reads, writes);
- AssertConnectSucceeds();
- AssertAsyncReadEquals(kMsg1, kLen1);
- AssertWriteReturns(kMsg2, kLen2, ERR_CONNECTION_CLOSED);
- }
- } // namespace net
|