12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790 |
- // Copyright 2015 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "net/http/bidirectional_stream.h"
- #include <memory>
- #include <string>
- #include <utility>
- #include <vector>
- #include "base/containers/span.h"
- #include "base/memory/ptr_util.h"
- #include "base/memory/raw_ptr.h"
- #include "base/run_loop.h"
- #include "base/strings/string_number_conversions.h"
- #include "base/time/time.h"
- #include "base/timer/mock_timer.h"
- #include "base/timer/timer.h"
- #include "build/build_config.h"
- #include "net/base/completion_once_callback.h"
- #include "net/base/load_timing_info.h"
- #include "net/base/load_timing_info_test_util.h"
- #include "net/base/net_errors.h"
- #include "net/dns/public/secure_dns_policy.h"
- #include "net/http/bidirectional_stream_request_info.h"
- #include "net/http/http_network_session.h"
- #include "net/http/http_response_headers.h"
- #include "net/http/http_server_properties.h"
- #include "net/log/net_log.h"
- #include "net/log/net_log_capture_mode.h"
- #include "net/log/net_log_event_type.h"
- #include "net/log/net_log_source_type.h"
- #include "net/log/test_net_log.h"
- #include "net/log/test_net_log_util.h"
- #include "net/socket/socket_tag.h"
- #include "net/socket/socket_test_util.h"
- #include "net/spdy/spdy_session.h"
- #include "net/spdy/spdy_test_util_common.h"
- #include "net/ssl/ssl_cert_request_info.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/url_request/url_request_test_util.h"
- #include "testing/gmock/include/gmock/gmock.h"
- #include "testing/gtest/include/gtest/gtest.h"
- using net::test::IsError;
- using net::test::IsOk;
- namespace net {
- namespace {
- const char kBodyData[] = "Body data";
- const size_t kBodyDataSize = std::size(kBodyData);
- const std::string kBodyDataString(kBodyData, kBodyDataSize);
- // Size of the buffer to be allocated for each read.
- const size_t kReadBufferSize = 4096;
- // Expects that fields of |load_timing_info| are valid time stamps.
- void ExpectLoadTimingValid(const LoadTimingInfo& load_timing_info) {
- EXPECT_FALSE(load_timing_info.request_start.is_null());
- EXPECT_FALSE(load_timing_info.request_start_time.is_null());
- EXPECT_FALSE(load_timing_info.receive_headers_end.is_null());
- EXPECT_FALSE(load_timing_info.send_start.is_null());
- EXPECT_FALSE(load_timing_info.send_end.is_null());
- EXPECT_TRUE(load_timing_info.request_start <=
- load_timing_info.receive_headers_end);
- EXPECT_TRUE(load_timing_info.send_start <= load_timing_info.send_end);
- }
- // Tests the load timing of a stream that's connected and is not the first
- // request sent on a connection.
- void TestLoadTimingReused(const LoadTimingInfo& load_timing_info) {
- EXPECT_TRUE(load_timing_info.socket_reused);
- ExpectConnectTimingHasNoTimes(load_timing_info.connect_timing);
- ExpectLoadTimingValid(load_timing_info);
- }
- // Tests the load timing of a stream that's connected and using a fresh
- // connection.
- void TestLoadTimingNotReused(const LoadTimingInfo& load_timing_info) {
- EXPECT_FALSE(load_timing_info.socket_reused);
- ExpectConnectTimingHasTimes(
- load_timing_info.connect_timing,
- CONNECT_TIMING_HAS_SSL_TIMES | CONNECT_TIMING_HAS_DNS_TIMES);
- ExpectLoadTimingValid(load_timing_info);
- }
- // Delegate that reads data but does not send any data.
- class TestDelegateBase : public BidirectionalStream::Delegate {
- public:
- TestDelegateBase(IOBuffer* read_buf, int read_buf_len)
- : TestDelegateBase(read_buf,
- read_buf_len,
- std::make_unique<base::OneShotTimer>()) {}
- TestDelegateBase(IOBuffer* read_buf,
- int read_buf_len,
- std::unique_ptr<base::OneShotTimer> timer)
- : read_buf_(read_buf),
- read_buf_len_(read_buf_len),
- timer_(std::move(timer)) {}
- TestDelegateBase(const TestDelegateBase&) = delete;
- TestDelegateBase& operator=(const TestDelegateBase&) = delete;
- ~TestDelegateBase() override = default;
- void OnStreamReady(bool request_headers_sent) override {
- // Request headers should always be sent in H2's case, because the
- // functionality to combine header frame with data frames is not
- // implemented.
- EXPECT_TRUE(request_headers_sent);
- if (callback_.is_null())
- return;
- std::move(callback_).Run(OK);
- }
- void OnHeadersReceived(
- const spdy::Http2HeaderBlock& response_headers) override {
- CHECK(!not_expect_callback_);
- response_headers_ = response_headers.Clone();
- if (!do_not_start_read_)
- StartOrContinueReading();
- }
- void OnDataRead(int bytes_read) override {
- CHECK(!not_expect_callback_);
- ++on_data_read_count_;
- CHECK_GE(bytes_read, OK);
- data_received_.append(read_buf_->data(), bytes_read);
- if (!do_not_start_read_)
- StartOrContinueReading();
- }
- void OnDataSent() override {
- CHECK(!not_expect_callback_);
- ++on_data_sent_count_;
- }
- void OnTrailersReceived(const spdy::Http2HeaderBlock& trailers) override {
- CHECK(!not_expect_callback_);
- trailers_ = trailers.Clone();
- if (run_until_completion_)
- loop_->Quit();
- }
- void OnFailed(int error) override {
- CHECK(!not_expect_callback_);
- CHECK_EQ(OK, error_);
- CHECK_NE(OK, error);
- error_ = error;
- if (run_until_completion_)
- loop_->Quit();
- }
- void Start(std::unique_ptr<BidirectionalStreamRequestInfo> request_info,
- HttpNetworkSession* session) {
- stream_ = std::make_unique<BidirectionalStream>(
- std::move(request_info), session, true, this, std::move(timer_));
- if (run_until_completion_)
- loop_->Run();
- }
- void Start(std::unique_ptr<BidirectionalStreamRequestInfo> request_info,
- HttpNetworkSession* session,
- CompletionOnceCallback cb) {
- callback_ = std::move(cb);
- stream_ = std::make_unique<BidirectionalStream>(
- std::move(request_info), session, true, this, std::move(timer_));
- if (run_until_completion_)
- WaitUntilCompletion();
- }
- void WaitUntilCompletion() { loop_->Run(); }
- void SendData(const scoped_refptr<IOBuffer>& data,
- int length,
- bool end_of_stream) {
- SendvData({data}, {length}, end_of_stream);
- }
- void SendvData(const std::vector<scoped_refptr<IOBuffer>>& data,
- const std::vector<int>& length,
- bool end_of_stream) {
- not_expect_callback_ = true;
- stream_->SendvData(data, length, end_of_stream);
- not_expect_callback_ = false;
- }
- // Starts or continues reading data from |stream_| until no more bytes
- // can be read synchronously.
- void StartOrContinueReading() {
- int rv = ReadData();
- while (rv > 0) {
- rv = ReadData();
- }
- if (run_until_completion_ && rv == 0)
- loop_->Quit();
- }
- // Calls ReadData on the |stream_| and updates internal states.
- int ReadData() {
- not_expect_callback_ = true;
- int rv = stream_->ReadData(read_buf_.get(), read_buf_len_);
- not_expect_callback_ = false;
- if (rv > 0)
- data_received_.append(read_buf_->data(), rv);
- return rv;
- }
- // Deletes |stream_|.
- void DeleteStream() {
- next_proto_ = stream_->GetProtocol();
- received_bytes_ = stream_->GetTotalReceivedBytes();
- sent_bytes_ = stream_->GetTotalSentBytes();
- stream_->GetLoadTimingInfo(&load_timing_info_);
- stream_.reset();
- }
- NextProto GetProtocol() const {
- if (stream_)
- return stream_->GetProtocol();
- return next_proto_;
- }
- int64_t GetTotalReceivedBytes() const {
- if (stream_)
- return stream_->GetTotalReceivedBytes();
- return received_bytes_;
- }
- int64_t GetTotalSentBytes() const {
- if (stream_)
- return stream_->GetTotalSentBytes();
- return sent_bytes_;
- }
- void GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const {
- if (stream_) {
- stream_->GetLoadTimingInfo(load_timing_info);
- return;
- }
- *load_timing_info = load_timing_info_;
- }
- // Const getters for internal states.
- const std::string& data_received() const { return data_received_; }
- int error() const { return error_; }
- const spdy::Http2HeaderBlock& response_headers() const {
- return response_headers_;
- }
- const spdy::Http2HeaderBlock& trailers() const { return trailers_; }
- int on_data_read_count() const { return on_data_read_count_; }
- int on_data_sent_count() const { return on_data_sent_count_; }
- // Sets whether the delegate should automatically start reading.
- void set_do_not_start_read(bool do_not_start_read) {
- do_not_start_read_ = do_not_start_read;
- }
- // Sets whether the delegate should wait until the completion of the stream.
- void SetRunUntilCompletion(bool run_until_completion) {
- run_until_completion_ = run_until_completion;
- loop_ = std::make_unique<base::RunLoop>();
- }
- protected:
- // Quits |loop_|.
- void QuitLoop() { loop_->Quit(); }
- private:
- std::unique_ptr<BidirectionalStream> stream_;
- scoped_refptr<IOBuffer> read_buf_;
- int read_buf_len_;
- std::unique_ptr<base::OneShotTimer> timer_;
- std::string data_received_;
- std::unique_ptr<base::RunLoop> loop_;
- spdy::Http2HeaderBlock response_headers_;
- spdy::Http2HeaderBlock trailers_;
- NextProto next_proto_;
- int64_t received_bytes_ = 0;
- int64_t sent_bytes_ = 0;
- LoadTimingInfo load_timing_info_;
- int error_ = OK;
- int on_data_read_count_ = 0;
- int on_data_sent_count_ = 0;
- bool do_not_start_read_ = false;
- bool run_until_completion_ = false;
- // This is to ensure that delegate callback is not invoked synchronously when
- // calling into |stream_|.
- bool not_expect_callback_ = false;
- CompletionOnceCallback callback_;
- };
- // A delegate that deletes the stream in a particular callback.
- class DeleteStreamDelegate : public TestDelegateBase {
- public:
- // Specifies in which callback the stream can be deleted.
- enum Phase {
- ON_HEADERS_RECEIVED,
- ON_DATA_READ,
- ON_TRAILERS_RECEIVED,
- ON_FAILED,
- };
- DeleteStreamDelegate(IOBuffer* buf, int buf_len, Phase phase)
- : TestDelegateBase(buf, buf_len), phase_(phase) {}
- DeleteStreamDelegate(const DeleteStreamDelegate&) = delete;
- DeleteStreamDelegate& operator=(const DeleteStreamDelegate&) = delete;
- ~DeleteStreamDelegate() override = default;
- void OnHeadersReceived(
- const spdy::Http2HeaderBlock& response_headers) override {
- TestDelegateBase::OnHeadersReceived(response_headers);
- if (phase_ == ON_HEADERS_RECEIVED) {
- DeleteStream();
- QuitLoop();
- }
- }
- void OnDataSent() override { NOTREACHED(); }
- void OnDataRead(int bytes_read) override {
- if (phase_ == ON_HEADERS_RECEIVED) {
- NOTREACHED();
- return;
- }
- TestDelegateBase::OnDataRead(bytes_read);
- if (phase_ == ON_DATA_READ) {
- DeleteStream();
- QuitLoop();
- }
- }
- void OnTrailersReceived(const spdy::Http2HeaderBlock& trailers) override {
- if (phase_ == ON_HEADERS_RECEIVED || phase_ == ON_DATA_READ) {
- NOTREACHED();
- return;
- }
- TestDelegateBase::OnTrailersReceived(trailers);
- if (phase_ == ON_TRAILERS_RECEIVED) {
- DeleteStream();
- QuitLoop();
- }
- }
- void OnFailed(int error) override {
- if (phase_ != ON_FAILED) {
- NOTREACHED();
- return;
- }
- TestDelegateBase::OnFailed(error);
- DeleteStream();
- QuitLoop();
- }
- private:
- // Indicates in which callback the delegate should cancel or delete the
- // stream.
- Phase phase_;
- };
- // A Timer that does not start a delayed task unless the timer is fired.
- class MockTimer : public base::MockOneShotTimer {
- public:
- MockTimer() = default;
- MockTimer(const MockTimer&) = delete;
- MockTimer& operator=(const MockTimer&) = delete;
- ~MockTimer() override = default;
- void Start(const base::Location& posted_from,
- base::TimeDelta delay,
- base::OnceClosure user_task) override {
- // Sets a maximum delay, so the timer does not fire unless it is told to.
- base::TimeDelta infinite_delay = base::TimeDelta::Max();
- base::MockOneShotTimer::Start(posted_from, infinite_delay,
- std::move(user_task));
- }
- };
- } // namespace
- class BidirectionalStreamTest : public TestWithTaskEnvironment {
- public:
- BidirectionalStreamTest()
- : default_url_(kDefaultUrl),
- host_port_pair_(HostPortPair::FromURL(default_url_)),
- ssl_data_(SSLSocketDataProvider(ASYNC, OK)) {
- ssl_data_.next_proto = kProtoHTTP2;
- ssl_data_.ssl_info.cert =
- ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem");
- net_log_observer_.SetObserverCaptureMode(NetLogCaptureMode::kEverything);
- auto socket_factory = std::make_unique<MockTaggingClientSocketFactory>();
- socket_factory_ = socket_factory.get();
- session_deps_.socket_factory = std::move(socket_factory);
- }
- protected:
- void TearDown() override {
- if (sequenced_data_) {
- EXPECT_TRUE(sequenced_data_->AllReadDataConsumed());
- EXPECT_TRUE(sequenced_data_->AllWriteDataConsumed());
- }
- }
- // Initializes the session using SequencedSocketData.
- void InitSession(base::span<const MockRead> reads,
- base::span<const MockWrite> writes,
- const SocketTag& socket_tag) {
- ASSERT_TRUE(ssl_data_.ssl_info.cert.get());
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data_);
- sequenced_data_ = std::make_unique<SequencedSocketData>(reads, writes);
- session_deps_.socket_factory->AddSocketDataProvider(sequenced_data_.get());
- session_deps_.net_log = NetLog::Get();
- http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
- SpdySessionKey key(host_port_pair_, ProxyServer::Direct(),
- PRIVACY_MODE_DISABLED,
- SpdySessionKey::IsProxySession::kFalse, socket_tag,
- NetworkIsolationKey(), SecureDnsPolicy::kAllow);
- session_ =
- CreateSpdySession(http_session_.get(), key,
- NetLogWithSource::Make(NetLogSourceType::NONE));
- }
- RecordingNetLogObserver net_log_observer_;
- SpdyTestUtil spdy_util_;
- SpdySessionDependencies session_deps_;
- const GURL default_url_;
- const HostPortPair host_port_pair_;
- std::unique_ptr<SequencedSocketData> sequenced_data_;
- std::unique_ptr<HttpNetworkSession> http_session_;
- raw_ptr<MockTaggingClientSocketFactory> socket_factory_;
- private:
- SSLSocketDataProvider ssl_data_;
- base::WeakPtr<SpdySession> session_;
- };
- TEST_F(BidirectionalStreamTest, CreateInsecureStream) {
- auto request_info = std::make_unique<BidirectionalStreamRequestInfo>();
- request_info->method = "GET";
- request_info->url = GURL("http://www.example.org/");
- TestDelegateBase delegate(nullptr, 0);
- auto session = std::make_unique<HttpNetworkSession>(
- SpdySessionDependencies::CreateSessionParams(&session_deps_),
- SpdySessionDependencies::CreateSessionContext(&session_deps_));
- delegate.SetRunUntilCompletion(true);
- delegate.Start(std::move(request_info), session.get());
- EXPECT_THAT(delegate.error(), IsError(ERR_DISALLOWED_URL_SCHEME));
- }
- TEST_F(BidirectionalStreamTest, SimplePostRequest) {
- spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
- kDefaultUrl, 1, kBodyDataSize, LOW, nullptr, 0));
- spdy::SpdySerializedFrame data_frame(
- spdy_util_.ConstructSpdyDataFrame(1, kBodyDataString, /*fin=*/true));
- MockWrite writes[] = {
- CreateMockWrite(req, 0), CreateMockWrite(data_frame, 3),
- };
- spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
- spdy::SpdySerializedFrame response_body_frame(
- spdy_util_.ConstructSpdyDataFrame(1, /*fin=*/true));
- MockRead reads[] = {
- CreateMockRead(resp, 1),
- MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause.
- CreateMockRead(response_body_frame, 4), MockRead(ASYNC, 0, 5),
- };
- InitSession(reads, writes, SocketTag());
- auto request_info = std::make_unique<BidirectionalStreamRequestInfo>();
- request_info->method = "POST";
- request_info->url = default_url_;
- request_info->extra_headers.SetHeader(net::HttpRequestHeaders::kContentLength,
- base::NumberToString(kBodyDataSize));
- scoped_refptr<IOBuffer> read_buffer =
- base::MakeRefCounted<IOBuffer>(kReadBufferSize);
- auto delegate =
- std::make_unique<TestDelegateBase>(read_buffer.get(), kReadBufferSize);
- delegate->Start(std::move(request_info), http_session_.get());
- sequenced_data_->RunUntilPaused();
- scoped_refptr<StringIOBuffer> buf =
- base::MakeRefCounted<StringIOBuffer>(kBodyDataString);
- delegate->SendData(buf.get(), buf->size(), true);
- sequenced_data_->Resume();
- base::RunLoop().RunUntilIdle();
- LoadTimingInfo load_timing_info;
- delegate->GetLoadTimingInfo(&load_timing_info);
- TestLoadTimingNotReused(load_timing_info);
- EXPECT_EQ(1, delegate->on_data_read_count());
- EXPECT_EQ(1, delegate->on_data_sent_count());
- EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
- EXPECT_EQ(CountWriteBytes(writes), delegate->GetTotalSentBytes());
- EXPECT_EQ(CountReadBytes(reads), delegate->GetTotalReceivedBytes());
- }
- TEST_F(BidirectionalStreamTest, LoadTimingTwoRequests) {
- spdy::SpdySerializedFrame req(
- spdy_util_.ConstructSpdyGet(nullptr, 0, /*stream_id=*/1, LOW));
- spdy::SpdySerializedFrame req2(
- spdy_util_.ConstructSpdyGet(nullptr, 0, /*stream_id=*/3, LOW));
- MockWrite writes[] = {
- CreateMockWrite(req, 0), CreateMockWrite(req2, 2),
- };
- spdy::SpdySerializedFrame resp(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, /*stream_id=*/1));
- spdy::SpdySerializedFrame resp2(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, /*stream_id=*/3));
- spdy::SpdySerializedFrame resp_body(
- spdy_util_.ConstructSpdyDataFrame(/*stream_id=*/1, /*fin=*/true));
- spdy::SpdySerializedFrame resp_body2(
- spdy_util_.ConstructSpdyDataFrame(/*stream_id=*/3, /*fin=*/true));
- MockRead reads[] = {CreateMockRead(resp, 1), CreateMockRead(resp_body, 3),
- CreateMockRead(resp2, 4), CreateMockRead(resp_body2, 5),
- MockRead(ASYNC, 0, 6)};
- InitSession(reads, writes, SocketTag());
- auto request_info = std::make_unique<BidirectionalStreamRequestInfo>();
- request_info->method = "GET";
- request_info->url = default_url_;
- request_info->end_stream_on_headers = true;
- auto request_info2 = std::make_unique<BidirectionalStreamRequestInfo>();
- request_info2->method = "GET";
- request_info2->url = default_url_;
- request_info2->end_stream_on_headers = true;
- scoped_refptr<IOBuffer> read_buffer =
- base::MakeRefCounted<IOBuffer>(kReadBufferSize);
- scoped_refptr<IOBuffer> read_buffer2 =
- base::MakeRefCounted<IOBuffer>(kReadBufferSize);
- auto delegate =
- std::make_unique<TestDelegateBase>(read_buffer.get(), kReadBufferSize);
- auto delegate2 =
- std::make_unique<TestDelegateBase>(read_buffer2.get(), kReadBufferSize);
- delegate->Start(std::move(request_info), http_session_.get());
- delegate2->Start(std::move(request_info2), http_session_.get());
- delegate->SetRunUntilCompletion(true);
- delegate2->SetRunUntilCompletion(true);
- base::RunLoop().RunUntilIdle();
- delegate->WaitUntilCompletion();
- delegate2->WaitUntilCompletion();
- LoadTimingInfo load_timing_info;
- delegate->GetLoadTimingInfo(&load_timing_info);
- TestLoadTimingNotReused(load_timing_info);
- LoadTimingInfo load_timing_info2;
- delegate2->GetLoadTimingInfo(&load_timing_info2);
- TestLoadTimingReused(load_timing_info2);
- }
- // Creates a BidirectionalStream with an insecure scheme. Destroy the stream
- // without waiting for the OnFailed task to be executed.
- TEST_F(BidirectionalStreamTest,
- CreateInsecureStreamAndDestroyStreamRightAfter) {
- auto request_info = std::make_unique<BidirectionalStreamRequestInfo>();
- request_info->method = "GET";
- request_info->url = GURL("http://www.example.org/");
- auto delegate = std::make_unique<TestDelegateBase>(nullptr, 0);
- auto session = std::make_unique<HttpNetworkSession>(
- SpdySessionDependencies::CreateSessionParams(&session_deps_),
- SpdySessionDependencies::CreateSessionContext(&session_deps_));
- delegate->Start(std::move(request_info), session.get());
- // Reset stream right before the OnFailed task is executed.
- delegate.reset();
- base::RunLoop().RunUntilIdle();
- }
- TEST_F(BidirectionalStreamTest, ClientAuthRequestIgnored) {
- auto cert_request = base::MakeRefCounted<SSLCertRequestInfo>();
- cert_request->host_and_port = host_port_pair_;
- // First attempt receives client auth request.
- SSLSocketDataProvider ssl_data1(ASYNC, ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
- ssl_data1.next_proto = kProtoHTTP2;
- ssl_data1.cert_request_info = cert_request.get();
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data1);
- StaticSocketDataProvider socket_data1;
- session_deps_.socket_factory->AddSocketDataProvider(&socket_data1);
- // Second attempt succeeds.
- spdy::SpdySerializedFrame req(
- spdy_util_.ConstructSpdyGet(kDefaultUrl, 1, LOWEST));
- MockWrite writes[] = {
- CreateMockWrite(req, 0),
- };
- spdy::SpdySerializedFrame resp(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame body_frame(
- spdy_util_.ConstructSpdyDataFrame(1, true));
- MockRead reads[] = {
- CreateMockRead(resp, 1), CreateMockRead(body_frame, 2),
- MockRead(SYNCHRONOUS, net::OK, 3),
- };
- SSLSocketDataProvider ssl_data2(ASYNC, OK);
- ssl_data2.next_proto = kProtoHTTP2;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data2);
- SequencedSocketData socket_data2(reads, writes);
- session_deps_.socket_factory->AddSocketDataProvider(&socket_data2);
- http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
- SpdySessionKey key(host_port_pair_, ProxyServer::Direct(),
- PRIVACY_MODE_DISABLED,
- SpdySessionKey::IsProxySession::kFalse, SocketTag(),
- NetworkIsolationKey(), SecureDnsPolicy::kAllow);
- auto request_info = std::make_unique<BidirectionalStreamRequestInfo>();
- request_info->method = "GET";
- request_info->url = default_url_;
- request_info->end_stream_on_headers = true;
- request_info->priority = LOWEST;
- scoped_refptr<IOBuffer> read_buffer =
- base::MakeRefCounted<IOBuffer>(kReadBufferSize);
- auto delegate =
- std::make_unique<TestDelegateBase>(read_buffer.get(), kReadBufferSize);
- delegate->SetRunUntilCompletion(true);
- delegate->Start(std::move(request_info), http_session_.get());
- // Ensure the certificate was added to the client auth cache.
- scoped_refptr<X509Certificate> client_cert;
- scoped_refptr<SSLPrivateKey> client_private_key;
- ASSERT_TRUE(http_session_->ssl_client_context()->GetClientCertificate(
- host_port_pair_, &client_cert, &client_private_key));
- ASSERT_FALSE(client_cert);
- ASSERT_FALSE(client_private_key);
- const spdy::Http2HeaderBlock& response_headers = delegate->response_headers();
- EXPECT_EQ("200", response_headers.find(":status")->second);
- EXPECT_EQ(1, delegate->on_data_read_count());
- EXPECT_EQ(0, delegate->on_data_sent_count());
- EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
- }
- // Simulates user calling ReadData after END_STREAM has been received in
- // BidirectionalStreamSpdyImpl.
- TEST_F(BidirectionalStreamTest, TestReadDataAfterClose) {
- spdy::SpdySerializedFrame req(
- spdy_util_.ConstructSpdyGet(kDefaultUrl, 1, LOWEST));
- MockWrite writes[] = {
- CreateMockWrite(req, 0),
- };
- const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
- spdy::SpdySerializedFrame resp(
- spdy_util_.ConstructSpdyGetReply(kExtraResponseHeaders, 1, 1));
- spdy::SpdySerializedFrame body_frame(
- spdy_util_.ConstructSpdyDataFrame(1, false));
- // Last body frame has END_STREAM flag set.
- spdy::SpdySerializedFrame last_body_frame(
- spdy_util_.ConstructSpdyDataFrame(1, true));
- MockRead reads[] = {
- CreateMockRead(resp, 1),
- MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause.
- CreateMockRead(body_frame, 3),
- MockRead(ASYNC, ERR_IO_PENDING, 4), // Force a pause.
- CreateMockRead(body_frame, 5),
- CreateMockRead(last_body_frame, 6),
- MockRead(SYNCHRONOUS, 0, 7),
- };
- InitSession(reads, writes, SocketTag());
- auto request_info = std::make_unique<BidirectionalStreamRequestInfo>();
- request_info->method = "GET";
- request_info->url = default_url_;
- request_info->end_stream_on_headers = true;
- request_info->priority = LOWEST;
- scoped_refptr<IOBuffer> read_buffer =
- base::MakeRefCounted<IOBuffer>(kReadBufferSize);
- // Create a MockTimer. Retain a raw pointer since the underlying
- // BidirectionalStreamImpl owns it.
- auto timer = std::make_unique<MockTimer>();
- MockTimer* timer_ptr = timer.get();
- auto delegate = std::make_unique<TestDelegateBase>(
- read_buffer.get(), kReadBufferSize, std::move(timer));
- delegate->set_do_not_start_read(true);
- delegate->Start(std::move(request_info), http_session_.get());
- // Write request, and deliver response headers.
- sequenced_data_->RunUntilPaused();
- EXPECT_FALSE(timer_ptr->IsRunning());
- // ReadData returns asynchronously because no data is buffered.
- int rv = delegate->ReadData();
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- // Deliver a DATA frame.
- sequenced_data_->Resume();
- base::RunLoop().RunUntilIdle();
- timer_ptr->Fire();
- // Asynchronous completion callback is invoke.
- EXPECT_EQ(1, delegate->on_data_read_count());
- EXPECT_EQ(kUploadDataSize * 1,
- static_cast<int>(delegate->data_received().size()));
- // Deliver the rest. Note that user has not called a second ReadData.
- sequenced_data_->Resume();
- base::RunLoop().RunUntilIdle();
- // ReadData now. Read should complete synchronously.
- rv = delegate->ReadData();
- EXPECT_EQ(kUploadDataSize * 2, rv);
- rv = delegate->ReadData();
- EXPECT_THAT(rv, IsOk()); // EOF.
- const spdy::Http2HeaderBlock& response_headers = delegate->response_headers();
- EXPECT_EQ("200", response_headers.find(":status")->second);
- EXPECT_EQ("header-value", response_headers.find("header-name")->second);
- EXPECT_EQ(1, delegate->on_data_read_count());
- EXPECT_EQ(0, delegate->on_data_sent_count());
- EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
- EXPECT_EQ(CountWriteBytes(writes), delegate->GetTotalSentBytes());
- EXPECT_EQ(CountReadBytes(reads), delegate->GetTotalReceivedBytes());
- }
- // Tests that the NetLog contains correct entries.
- TEST_F(BidirectionalStreamTest, TestNetLogContainEntries) {
- spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
- kDefaultUrl, 1, kBodyDataSize * 3, LOWEST, nullptr, 0));
- spdy::SpdySerializedFrame data_frame(
- spdy_util_.ConstructSpdyDataFrame(1, kBodyDataString, /*fin=*/true));
- MockWrite writes[] = {
- CreateMockWrite(req, 0), CreateMockWrite(data_frame, 3),
- };
- spdy::SpdySerializedFrame resp(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame response_body_frame1(
- spdy_util_.ConstructSpdyDataFrame(1, false));
- spdy::SpdySerializedFrame response_body_frame2(
- spdy_util_.ConstructSpdyDataFrame(1, false));
- spdy::Http2HeaderBlock trailers;
- trailers["foo"] = "bar";
- spdy::SpdySerializedFrame response_trailers(
- spdy_util_.ConstructSpdyResponseHeaders(1, std::move(trailers), true));
- MockRead reads[] = {
- CreateMockRead(resp, 1),
- MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause.
- CreateMockRead(response_body_frame1, 4),
- MockRead(ASYNC, ERR_IO_PENDING, 5), // Force a pause.
- CreateMockRead(response_body_frame2, 6),
- CreateMockRead(response_trailers, 7),
- MockRead(ASYNC, 0, 8),
- };
- InitSession(reads, writes, SocketTag());
- auto request_info = std::make_unique<BidirectionalStreamRequestInfo>();
- request_info->method = "POST";
- request_info->url = default_url_;
- request_info->priority = LOWEST;
- request_info->extra_headers.SetHeader(
- net::HttpRequestHeaders::kContentLength,
- base::NumberToString(kBodyDataSize * 3));
- scoped_refptr<IOBuffer> read_buffer =
- base::MakeRefCounted<IOBuffer>(kReadBufferSize);
- auto timer = std::make_unique<MockTimer>();
- MockTimer* timer_ptr = timer.get();
- auto delegate = std::make_unique<TestDelegateBase>(
- read_buffer.get(), kReadBufferSize, std::move(timer));
- delegate->set_do_not_start_read(true);
- delegate->Start(std::move(request_info), http_session_.get());
- // Send the request and receive response headers.
- sequenced_data_->RunUntilPaused();
- EXPECT_FALSE(timer_ptr->IsRunning());
- scoped_refptr<StringIOBuffer> buf =
- base::MakeRefCounted<StringIOBuffer>(kBodyDataString);
- // Send a DATA frame.
- delegate->SendData(buf, buf->size(), true);
- // ReadData returns asynchronously because no data is buffered.
- int rv = delegate->ReadData();
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- // Deliver the first DATA frame.
- sequenced_data_->Resume();
- sequenced_data_->RunUntilPaused();
- // |sequenced_data_| is now stopped after delivering first DATA frame but
- // before the second DATA frame.
- // Fire the timer to allow the first ReadData to complete asynchronously.
- timer_ptr->Fire();
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(1, delegate->on_data_read_count());
- // Now let |sequenced_data_| run until completion.
- sequenced_data_->Resume();
- base::RunLoop().RunUntilIdle();
- // All data has been delivered, and OnClosed() has been invoked.
- // Read now, and it should complete synchronously.
- rv = delegate->ReadData();
- EXPECT_EQ(kUploadDataSize, rv);
- EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
- EXPECT_EQ(1, delegate->on_data_read_count());
- EXPECT_EQ(1, delegate->on_data_sent_count());
- EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
- EXPECT_EQ("bar", delegate->trailers().find("foo")->second);
- EXPECT_EQ(CountWriteBytes(writes), delegate->GetTotalSentBytes());
- EXPECT_EQ(CountReadBytes(reads), delegate->GetTotalReceivedBytes());
- // Destroy the delegate will destroy the stream, so we can get an end event
- // for BIDIRECTIONAL_STREAM_ALIVE.
- delegate.reset();
- auto entries = net_log_observer_.GetEntries();
- size_t index = ExpectLogContainsSomewhere(
- entries, 0, NetLogEventType::BIDIRECTIONAL_STREAM_ALIVE,
- NetLogEventPhase::BEGIN);
- // HTTP_STREAM_REQUEST is nested inside in BIDIRECTIONAL_STREAM_ALIVE.
- index = ExpectLogContainsSomewhere(entries, index,
- NetLogEventType::HTTP_STREAM_REQUEST,
- NetLogEventPhase::BEGIN);
- index = ExpectLogContainsSomewhere(entries, index,
- NetLogEventType::HTTP_STREAM_REQUEST,
- NetLogEventPhase::END);
- // Headers received should happen after HTTP_STREAM_REQUEST.
- index = ExpectLogContainsSomewhere(
- entries, index, NetLogEventType::BIDIRECTIONAL_STREAM_RECV_HEADERS,
- NetLogEventPhase::NONE);
- // Trailers received should happen after headers received. It might happen
- // before the reads complete.
- ExpectLogContainsSomewhere(
- entries, index, NetLogEventType::BIDIRECTIONAL_STREAM_RECV_TRAILERS,
- NetLogEventPhase::NONE);
- index = ExpectLogContainsSomewhere(
- entries, index, NetLogEventType::BIDIRECTIONAL_STREAM_SENDV_DATA,
- NetLogEventPhase::NONE);
- index = ExpectLogContainsSomewhere(
- entries, index, NetLogEventType::BIDIRECTIONAL_STREAM_READ_DATA,
- NetLogEventPhase::NONE);
- EXPECT_EQ(ERR_IO_PENDING, GetIntegerValueFromParams(entries[index], "rv"));
- // Sent bytes. Sending data is always asynchronous.
- index = ExpectLogContainsSomewhere(
- entries, index, NetLogEventType::BIDIRECTIONAL_STREAM_BYTES_SENT,
- NetLogEventPhase::NONE);
- EXPECT_EQ(NetLogSourceType::BIDIRECTIONAL_STREAM, entries[index].source.type);
- // Received bytes for asynchronous read.
- index = ExpectLogContainsSomewhere(
- entries, index, NetLogEventType::BIDIRECTIONAL_STREAM_BYTES_RECEIVED,
- NetLogEventPhase::NONE);
- EXPECT_EQ(NetLogSourceType::BIDIRECTIONAL_STREAM, entries[index].source.type);
- // Received bytes for synchronous read.
- index = ExpectLogContainsSomewhere(
- entries, index, NetLogEventType::BIDIRECTIONAL_STREAM_BYTES_RECEIVED,
- NetLogEventPhase::NONE);
- EXPECT_EQ(NetLogSourceType::BIDIRECTIONAL_STREAM, entries[index].source.type);
- ExpectLogContainsSomewhere(entries, index,
- NetLogEventType::BIDIRECTIONAL_STREAM_ALIVE,
- NetLogEventPhase::END);
- }
- TEST_F(BidirectionalStreamTest, TestInterleaveReadDataAndSendData) {
- spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
- kDefaultUrl, 1, kBodyDataSize * 3, LOWEST, nullptr, 0));
- spdy::SpdySerializedFrame data_frame1(
- spdy_util_.ConstructSpdyDataFrame(1, kBodyDataString, /*fin=*/false));
- spdy::SpdySerializedFrame data_frame2(
- spdy_util_.ConstructSpdyDataFrame(1, kBodyDataString, /*fin=*/false));
- spdy::SpdySerializedFrame data_frame3(
- spdy_util_.ConstructSpdyDataFrame(1, kBodyDataString, /*fin=*/true));
- MockWrite writes[] = {
- CreateMockWrite(req, 0), CreateMockWrite(data_frame1, 3),
- CreateMockWrite(data_frame2, 6), CreateMockWrite(data_frame3, 9),
- };
- spdy::SpdySerializedFrame resp(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame response_body_frame1(
- spdy_util_.ConstructSpdyDataFrame(1, false));
- spdy::SpdySerializedFrame response_body_frame2(
- spdy_util_.ConstructSpdyDataFrame(1, true));
- MockRead reads[] = {
- CreateMockRead(resp, 1),
- MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause.
- CreateMockRead(response_body_frame1, 4),
- MockRead(ASYNC, ERR_IO_PENDING, 5), // Force a pause.
- CreateMockRead(response_body_frame2, 7),
- MockRead(ASYNC, ERR_IO_PENDING, 8), // Force a pause.
- MockRead(ASYNC, 0, 10),
- };
- InitSession(reads, writes, SocketTag());
- auto request_info = std::make_unique<BidirectionalStreamRequestInfo>();
- request_info->method = "POST";
- request_info->url = default_url_;
- request_info->priority = LOWEST;
- request_info->extra_headers.SetHeader(
- net::HttpRequestHeaders::kContentLength,
- base::NumberToString(kBodyDataSize * 3));
- scoped_refptr<IOBuffer> read_buffer =
- base::MakeRefCounted<IOBuffer>(kReadBufferSize);
- auto timer = std::make_unique<MockTimer>();
- MockTimer* timer_ptr = timer.get();
- auto delegate = std::make_unique<TestDelegateBase>(
- read_buffer.get(), kReadBufferSize, std::move(timer));
- delegate->set_do_not_start_read(true);
- delegate->Start(std::move(request_info), http_session_.get());
- // Send the request and receive response headers.
- sequenced_data_->RunUntilPaused();
- EXPECT_FALSE(timer_ptr->IsRunning());
- // Send a DATA frame.
- scoped_refptr<StringIOBuffer> buf =
- base::MakeRefCounted<StringIOBuffer>(kBodyDataString);
- // Send a DATA frame.
- delegate->SendData(buf, buf->size(), false);
- // ReadData and it should return asynchronously because no data is buffered.
- int rv = delegate->ReadData();
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- // Deliver a DATA frame, and fire the timer.
- sequenced_data_->Resume();
- sequenced_data_->RunUntilPaused();
- timer_ptr->Fire();
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(1, delegate->on_data_sent_count());
- EXPECT_EQ(1, delegate->on_data_read_count());
- // Send a DATA frame.
- delegate->SendData(buf, buf->size(), false);
- // ReadData and it should return asynchronously because no data is buffered.
- rv = delegate->ReadData();
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- // Deliver a DATA frame, and fire the timer.
- sequenced_data_->Resume();
- sequenced_data_->RunUntilPaused();
- timer_ptr->Fire();
- base::RunLoop().RunUntilIdle();
- // Last DATA frame is read. Server half closes.
- EXPECT_EQ(2, delegate->on_data_read_count());
- EXPECT_EQ(2, delegate->on_data_sent_count());
- // Send the last body frame. Client half closes.
- delegate->SendData(buf, buf->size(), true);
- sequenced_data_->Resume();
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(3, delegate->on_data_sent_count());
- // OnClose is invoked since both sides are closed.
- rv = delegate->ReadData();
- EXPECT_THAT(rv, IsOk());
- EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
- EXPECT_EQ(2, delegate->on_data_read_count());
- EXPECT_EQ(3, delegate->on_data_sent_count());
- EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
- EXPECT_EQ(CountWriteBytes(writes), delegate->GetTotalSentBytes());
- EXPECT_EQ(CountReadBytes(reads), delegate->GetTotalReceivedBytes());
- }
- TEST_F(BidirectionalStreamTest, TestCoalesceSmallDataBuffers) {
- spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
- kDefaultUrl, 1, kBodyDataSize * 1, LOWEST, nullptr, 0));
- std::string body_data = "some really long piece of data";
- spdy::SpdySerializedFrame data_frame1(
- spdy_util_.ConstructSpdyDataFrame(1, body_data, /*fin=*/true));
- MockWrite writes[] = {
- CreateMockWrite(req, 0), CreateMockWrite(data_frame1, 1),
- };
- spdy::SpdySerializedFrame resp(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame response_body_frame1(
- spdy_util_.ConstructSpdyDataFrame(1, true));
- MockRead reads[] = {
- CreateMockRead(resp, 2),
- MockRead(ASYNC, ERR_IO_PENDING, 3), // Force a pause.
- CreateMockRead(response_body_frame1, 4), MockRead(ASYNC, 0, 5),
- };
- InitSession(reads, writes, SocketTag());
- auto request_info = std::make_unique<BidirectionalStreamRequestInfo>();
- request_info->method = "POST";
- request_info->url = default_url_;
- request_info->priority = LOWEST;
- request_info->extra_headers.SetHeader(
- net::HttpRequestHeaders::kContentLength,
- base::NumberToString(kBodyDataSize * 1));
- scoped_refptr<IOBuffer> read_buffer =
- base::MakeRefCounted<IOBuffer>(kReadBufferSize);
- auto timer = std::make_unique<MockTimer>();
- auto delegate = std::make_unique<TestDelegateBase>(
- read_buffer.get(), kReadBufferSize, std::move(timer));
- delegate->set_do_not_start_read(true);
- TestCompletionCallback callback;
- delegate->Start(std::move(request_info), http_session_.get(),
- callback.callback());
- // Wait until the stream is ready.
- callback.WaitForResult();
- // Send a DATA frame.
- scoped_refptr<StringIOBuffer> buf =
- base::MakeRefCounted<StringIOBuffer>(body_data.substr(0, 5));
- scoped_refptr<StringIOBuffer> buf2 = base::MakeRefCounted<StringIOBuffer>(
- body_data.substr(5, body_data.size() - 5));
- delegate->SendvData({buf, buf2.get()}, {buf->size(), buf2->size()}, true);
- sequenced_data_->RunUntilPaused(); // OnHeadersReceived.
- // ReadData and it should return asynchronously because no data is buffered.
- EXPECT_THAT(delegate->ReadData(), IsError(ERR_IO_PENDING));
- sequenced_data_->Resume();
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(1, delegate->on_data_sent_count());
- EXPECT_EQ(1, delegate->on_data_read_count());
- EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
- EXPECT_EQ(1, delegate->on_data_read_count());
- EXPECT_EQ(1, delegate->on_data_sent_count());
- EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
- EXPECT_EQ(CountWriteBytes(writes), delegate->GetTotalSentBytes());
- EXPECT_EQ(CountReadBytes(reads), delegate->GetTotalReceivedBytes());
- auto entries = net_log_observer_.GetEntries();
- size_t index = ExpectLogContainsSomewhere(
- entries, 0, NetLogEventType::BIDIRECTIONAL_STREAM_SENDV_DATA,
- NetLogEventPhase::NONE);
- EXPECT_EQ(2, GetIntegerValueFromParams(entries[index], "num_buffers"));
- index = ExpectLogContainsSomewhereAfter(
- entries, index,
- NetLogEventType::BIDIRECTIONAL_STREAM_BYTES_SENT_COALESCED,
- NetLogEventPhase::BEGIN);
- EXPECT_EQ(2,
- GetIntegerValueFromParams(entries[index], "num_buffers_coalesced"));
- index = ExpectLogContainsSomewhereAfter(
- entries, index, NetLogEventType::BIDIRECTIONAL_STREAM_BYTES_SENT,
- NetLogEventPhase::NONE);
- EXPECT_EQ(buf->size(),
- GetIntegerValueFromParams(entries[index], "byte_count"));
- index = ExpectLogContainsSomewhereAfter(
- entries, index + 1, NetLogEventType::BIDIRECTIONAL_STREAM_BYTES_SENT,
- NetLogEventPhase::NONE);
- EXPECT_EQ(buf2->size(),
- GetIntegerValueFromParams(entries[index], "byte_count"));
- ExpectLogContainsSomewhere(
- entries, index,
- NetLogEventType::BIDIRECTIONAL_STREAM_BYTES_SENT_COALESCED,
- NetLogEventPhase::END);
- }
- // Tests that BidirectionalStreamSpdyImpl::OnClose will complete any remaining
- // read even if the read queue is empty.
- TEST_F(BidirectionalStreamTest, TestCompleteAsyncRead) {
- spdy::SpdySerializedFrame req(
- spdy_util_.ConstructSpdyGet(kDefaultUrl, 1, LOWEST));
- MockWrite writes[] = {CreateMockWrite(req, 0)};
- spdy::SpdySerializedFrame resp(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame response_body_frame(
- spdy_util_.ConstructSpdyDataFrame(1, "", true));
- MockRead reads[] = {
- CreateMockRead(resp, 1),
- MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause.
- CreateMockRead(response_body_frame, 3), MockRead(SYNCHRONOUS, 0, 4),
- };
- InitSession(reads, writes, SocketTag());
- auto request_info = std::make_unique<BidirectionalStreamRequestInfo>();
- request_info->method = "GET";
- request_info->url = default_url_;
- request_info->priority = LOWEST;
- request_info->end_stream_on_headers = true;
- scoped_refptr<IOBuffer> read_buffer =
- base::MakeRefCounted<IOBuffer>(kReadBufferSize);
- auto timer = std::make_unique<MockTimer>();
- MockTimer* timer_ptr = timer.get();
- auto delegate = std::make_unique<TestDelegateBase>(
- read_buffer.get(), kReadBufferSize, std::move(timer));
- delegate->set_do_not_start_read(true);
- delegate->Start(std::move(request_info), http_session_.get());
- // Write request, and deliver response headers.
- sequenced_data_->RunUntilPaused();
- EXPECT_FALSE(timer_ptr->IsRunning());
- // ReadData should return asynchronously because no data is buffered.
- int rv = delegate->ReadData();
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- // Deliver END_STREAM.
- // OnClose should trigger completion of the remaining read.
- sequenced_data_->Resume();
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
- EXPECT_EQ(1, delegate->on_data_read_count());
- EXPECT_EQ(0u, delegate->data_received().size());
- EXPECT_EQ(0, delegate->on_data_sent_count());
- EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
- EXPECT_EQ(CountWriteBytes(writes), delegate->GetTotalSentBytes());
- EXPECT_EQ(CountReadBytes(reads), delegate->GetTotalReceivedBytes());
- }
- TEST_F(BidirectionalStreamTest, TestBuffering) {
- spdy::SpdySerializedFrame req(
- spdy_util_.ConstructSpdyGet(kDefaultUrl, 1, LOWEST));
- MockWrite writes[] = {CreateMockWrite(req, 0)};
- const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
- spdy::SpdySerializedFrame resp(
- spdy_util_.ConstructSpdyGetReply(kExtraResponseHeaders, 1, 1));
- spdy::SpdySerializedFrame body_frame(
- spdy_util_.ConstructSpdyDataFrame(1, false));
- // Last body frame has END_STREAM flag set.
- spdy::SpdySerializedFrame last_body_frame(
- spdy_util_.ConstructSpdyDataFrame(1, true));
- MockRead reads[] = {
- CreateMockRead(resp, 1),
- CreateMockRead(body_frame, 2),
- CreateMockRead(body_frame, 3),
- MockRead(ASYNC, ERR_IO_PENDING, 4), // Force a pause.
- CreateMockRead(last_body_frame, 5),
- MockRead(SYNCHRONOUS, 0, 6),
- };
- InitSession(reads, writes, SocketTag());
- auto request_info = std::make_unique<BidirectionalStreamRequestInfo>();
- request_info->method = "GET";
- request_info->url = default_url_;
- request_info->priority = LOWEST;
- request_info->end_stream_on_headers = true;
- scoped_refptr<IOBuffer> read_buffer =
- base::MakeRefCounted<IOBuffer>(kReadBufferSize);
- auto timer = std::make_unique<MockTimer>();
- MockTimer* timer_ptr = timer.get();
- auto delegate = std::make_unique<TestDelegateBase>(
- read_buffer.get(), kReadBufferSize, std::move(timer));
- delegate->Start(std::move(request_info), http_session_.get());
- // Deliver two DATA frames together.
- sequenced_data_->RunUntilPaused();
- EXPECT_TRUE(timer_ptr->IsRunning());
- timer_ptr->Fire();
- base::RunLoop().RunUntilIdle();
- // This should trigger |more_read_data_pending_| to execute the task at a
- // later time, and Delegate::OnReadComplete should not have been called.
- EXPECT_TRUE(timer_ptr->IsRunning());
- EXPECT_EQ(0, delegate->on_data_read_count());
- // Fire the timer now, the two DATA frame should be combined into one
- // single Delegate::OnReadComplete callback.
- timer_ptr->Fire();
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(1, delegate->on_data_read_count());
- EXPECT_EQ(kUploadDataSize * 2,
- static_cast<int>(delegate->data_received().size()));
- // Deliver last DATA frame and EOF. There will be an additional
- // Delegate::OnReadComplete callback.
- sequenced_data_->Resume();
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(2, delegate->on_data_read_count());
- EXPECT_EQ(kUploadDataSize * 3,
- static_cast<int>(delegate->data_received().size()));
- const spdy::Http2HeaderBlock& response_headers = delegate->response_headers();
- EXPECT_EQ("200", response_headers.find(":status")->second);
- EXPECT_EQ("header-value", response_headers.find("header-name")->second);
- EXPECT_EQ(0, delegate->on_data_sent_count());
- EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
- EXPECT_EQ(CountWriteBytes(writes), delegate->GetTotalSentBytes());
- EXPECT_EQ(CountReadBytes(reads), delegate->GetTotalReceivedBytes());
- }
- TEST_F(BidirectionalStreamTest, TestBufferingWithTrailers) {
- spdy::SpdySerializedFrame req(
- spdy_util_.ConstructSpdyGet(kDefaultUrl, 1, LOWEST));
- MockWrite writes[] = {
- CreateMockWrite(req, 0),
- };
- const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
- spdy::SpdySerializedFrame resp(
- spdy_util_.ConstructSpdyGetReply(kExtraResponseHeaders, 1, 1));
- spdy::SpdySerializedFrame body_frame(
- spdy_util_.ConstructSpdyDataFrame(1, false));
- spdy::Http2HeaderBlock trailers;
- trailers["foo"] = "bar";
- spdy::SpdySerializedFrame response_trailers(
- spdy_util_.ConstructSpdyResponseHeaders(1, std::move(trailers), true));
- MockRead reads[] = {
- CreateMockRead(resp, 1),
- CreateMockRead(body_frame, 2),
- CreateMockRead(body_frame, 3),
- CreateMockRead(body_frame, 4),
- MockRead(ASYNC, ERR_IO_PENDING, 5), // Force a pause.
- CreateMockRead(response_trailers, 6),
- MockRead(SYNCHRONOUS, 0, 7),
- };
- InitSession(reads, writes, SocketTag());
- scoped_refptr<IOBuffer> read_buffer =
- base::MakeRefCounted<IOBuffer>(kReadBufferSize);
- auto timer = std::make_unique<MockTimer>();
- MockTimer* timer_ptr = timer.get();
- auto delegate = std::make_unique<TestDelegateBase>(
- read_buffer.get(), kReadBufferSize, std::move(timer));
- auto request_info = std::make_unique<BidirectionalStreamRequestInfo>();
- request_info->method = "GET";
- request_info->url = default_url_;
- request_info->priority = LOWEST;
- request_info->end_stream_on_headers = true;
- delegate->Start(std::move(request_info), http_session_.get());
- // Deliver all three DATA frames together.
- sequenced_data_->RunUntilPaused();
- EXPECT_TRUE(timer_ptr->IsRunning());
- timer_ptr->Fire();
- base::RunLoop().RunUntilIdle();
- // This should trigger |more_read_data_pending_| to execute the task at a
- // later time, and Delegate::OnReadComplete should not have been called.
- EXPECT_TRUE(timer_ptr->IsRunning());
- EXPECT_EQ(0, delegate->on_data_read_count());
- // Deliver trailers. Remaining read should be completed, since OnClose is
- // called right after OnTrailersReceived. The three DATA frames should be
- // delivered in a single OnReadCompleted callback.
- sequenced_data_->Resume();
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(1, delegate->on_data_read_count());
- EXPECT_EQ(kUploadDataSize * 3,
- static_cast<int>(delegate->data_received().size()));
- const spdy::Http2HeaderBlock& response_headers = delegate->response_headers();
- EXPECT_EQ("200", response_headers.find(":status")->second);
- EXPECT_EQ("header-value", response_headers.find("header-name")->second);
- EXPECT_EQ("bar", delegate->trailers().find("foo")->second);
- EXPECT_EQ(0, delegate->on_data_sent_count());
- EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
- EXPECT_EQ(CountWriteBytes(writes), delegate->GetTotalSentBytes());
- EXPECT_EQ(CountReadBytes(reads), delegate->GetTotalReceivedBytes());
- }
- TEST_F(BidirectionalStreamTest, DeleteStreamAfterSendData) {
- spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
- kDefaultUrl, 1, kBodyDataSize * 3, LOWEST, nullptr, 0));
- spdy::SpdySerializedFrame data_frame(
- spdy_util_.ConstructSpdyDataFrame(1, kBodyDataString, /*fin=*/false));
- spdy::SpdySerializedFrame rst(
- spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_CANCEL));
- MockWrite writes[] = {
- CreateMockWrite(req, 0), CreateMockWrite(data_frame, 3),
- CreateMockWrite(rst, 5),
- };
- spdy::SpdySerializedFrame resp(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- MockRead reads[] = {
- CreateMockRead(resp, 1),
- MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause.
- MockRead(ASYNC, ERR_IO_PENDING, 4), // Force a pause.
- MockRead(ASYNC, 0, 6),
- };
- InitSession(reads, writes, SocketTag());
- auto request_info = std::make_unique<BidirectionalStreamRequestInfo>();
- request_info->method = "POST";
- request_info->url = default_url_;
- request_info->priority = LOWEST;
- request_info->extra_headers.SetHeader(
- net::HttpRequestHeaders::kContentLength,
- base::NumberToString(kBodyDataSize * 3));
- scoped_refptr<IOBuffer> read_buffer =
- base::MakeRefCounted<IOBuffer>(kReadBufferSize);
- auto delegate =
- std::make_unique<TestDelegateBase>(read_buffer.get(), kReadBufferSize);
- delegate->set_do_not_start_read(true);
- delegate->Start(std::move(request_info), http_session_.get());
- // Send the request and receive response headers.
- sequenced_data_->RunUntilPaused();
- EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
- // Send a DATA frame.
- scoped_refptr<StringIOBuffer> buf =
- base::MakeRefCounted<StringIOBuffer>(kBodyDataString);
- delegate->SendData(buf, buf->size(), false);
- sequenced_data_->Resume();
- base::RunLoop().RunUntilIdle();
- delegate->DeleteStream();
- sequenced_data_->Resume();
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
- EXPECT_EQ(0, delegate->on_data_read_count());
- // OnDataSent may or may not have been invoked.
- EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
- // Bytes sent excludes the RST frame.
- EXPECT_EQ(
- CountWriteBytes(base::make_span(writes).first(std::size(writes) - 1)),
- delegate->GetTotalSentBytes());
- EXPECT_EQ(CountReadBytes(reads), delegate->GetTotalReceivedBytes());
- }
- TEST_F(BidirectionalStreamTest, DeleteStreamDuringReadData) {
- spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
- kDefaultUrl, 1, kBodyDataSize * 3, LOWEST, nullptr, 0));
- spdy::SpdySerializedFrame rst(
- spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_CANCEL));
- MockWrite writes[] = {
- CreateMockWrite(req, 0), CreateMockWrite(rst, 4),
- };
- spdy::SpdySerializedFrame resp(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame response_body_frame(
- spdy_util_.ConstructSpdyDataFrame(1, false));
- MockRead reads[] = {
- CreateMockRead(resp, 1),
- MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause.
- CreateMockRead(response_body_frame, 3), MockRead(ASYNC, 0, 5),
- };
- InitSession(reads, writes, SocketTag());
- auto request_info = std::make_unique<BidirectionalStreamRequestInfo>();
- request_info->method = "POST";
- request_info->url = default_url_;
- request_info->priority = LOWEST;
- request_info->extra_headers.SetHeader(
- net::HttpRequestHeaders::kContentLength,
- base::NumberToString(kBodyDataSize * 3));
- scoped_refptr<IOBuffer> read_buffer =
- base::MakeRefCounted<IOBuffer>(kReadBufferSize);
- auto delegate =
- std::make_unique<TestDelegateBase>(read_buffer.get(), kReadBufferSize);
- delegate->set_do_not_start_read(true);
- delegate->Start(std::move(request_info), http_session_.get());
- // Send the request and receive response headers.
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
- // Delete the stream after ReadData returns ERR_IO_PENDING.
- int rv = delegate->ReadData();
- EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- delegate->DeleteStream();
- sequenced_data_->Resume();
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(0, delegate->on_data_read_count());
- EXPECT_EQ(0, delegate->on_data_sent_count());
- EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
- // Bytes sent excludes the RST frame.
- EXPECT_EQ(
- CountWriteBytes(base::make_span(writes).first(std::size(writes) - 1)),
- delegate->GetTotalSentBytes());
- // Response body frame isn't read becase stream is deleted once read returns
- // ERR_IO_PENDING.
- EXPECT_EQ(CountReadBytes(base::make_span(reads).first(std::size(reads) - 2)),
- delegate->GetTotalReceivedBytes());
- }
- // Receiving a header with uppercase ASCII will result in a protocol error,
- // which should be propagated via Delegate::OnFailed.
- TEST_F(BidirectionalStreamTest, PropagateProtocolError) {
- spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
- kDefaultUrl, 1, kBodyDataSize * 3, LOW, nullptr, 0));
- spdy::SpdySerializedFrame rst(
- spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_PROTOCOL_ERROR));
- MockWrite writes[] = {
- CreateMockWrite(req, 0), CreateMockWrite(rst, 2),
- };
- const char* const kExtraHeaders[] = {"X-UpperCase", "yes"};
- spdy::SpdySerializedFrame resp(
- spdy_util_.ConstructSpdyGetReply(kExtraHeaders, 1, 1));
- MockRead reads[] = {
- CreateMockRead(resp, 1), MockRead(ASYNC, 0, 3),
- };
- InitSession(reads, writes, SocketTag());
- auto request_info = std::make_unique<BidirectionalStreamRequestInfo>();
- request_info->method = "POST";
- request_info->url = default_url_;
- request_info->extra_headers.SetHeader(
- net::HttpRequestHeaders::kContentLength,
- base::NumberToString(kBodyDataSize * 3));
- scoped_refptr<IOBuffer> read_buffer =
- base::MakeRefCounted<IOBuffer>(kReadBufferSize);
- auto delegate =
- std::make_unique<TestDelegateBase>(read_buffer.get(), kReadBufferSize);
- delegate->SetRunUntilCompletion(true);
- delegate->Start(std::move(request_info), http_session_.get());
- base::RunLoop().RunUntilIdle();
- EXPECT_THAT(delegate->error(), IsError(ERR_HTTP2_PROTOCOL_ERROR));
- EXPECT_EQ(delegate->response_headers().end(),
- delegate->response_headers().find(":status"));
- EXPECT_EQ(0, delegate->on_data_read_count());
- EXPECT_EQ(0, delegate->on_data_sent_count());
- EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
- // BidirectionalStreamSpdyStreamJob does not count the bytes sent for |rst|
- // because it is sent after SpdyStream::Delegate::OnClose is called.
- EXPECT_EQ(CountWriteBytes(base::make_span(writes, 1)),
- delegate->GetTotalSentBytes());
- EXPECT_EQ(0, delegate->GetTotalReceivedBytes());
- auto entries = net_log_observer_.GetEntries();
- size_t index = ExpectLogContainsSomewhere(
- entries, 0, NetLogEventType::BIDIRECTIONAL_STREAM_READY,
- NetLogEventPhase::NONE);
- EXPECT_TRUE(
- GetBooleanValueFromParams(entries[index], "request_headers_sent"));
- index = ExpectLogContainsSomewhere(
- entries, index, NetLogEventType::BIDIRECTIONAL_STREAM_FAILED,
- NetLogEventPhase::NONE);
- EXPECT_EQ(ERR_HTTP2_PROTOCOL_ERROR,
- GetNetErrorCodeFromParams(entries[index]));
- }
- TEST_F(BidirectionalStreamTest, DeleteStreamDuringOnHeadersReceived) {
- spdy::SpdySerializedFrame req(
- spdy_util_.ConstructSpdyGet(kDefaultUrl, 1, LOWEST));
- spdy::SpdySerializedFrame rst(
- spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_CANCEL));
- MockWrite writes[] = {
- CreateMockWrite(req, 0), CreateMockWrite(rst, 2),
- };
- const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
- spdy::SpdySerializedFrame resp(
- spdy_util_.ConstructSpdyGetReply(kExtraResponseHeaders, 1, 1));
- MockRead reads[] = {
- CreateMockRead(resp, 1), MockRead(ASYNC, 0, 3),
- };
- InitSession(reads, writes, SocketTag());
- auto request_info = std::make_unique<BidirectionalStreamRequestInfo>();
- request_info->method = "GET";
- request_info->url = default_url_;
- request_info->priority = LOWEST;
- request_info->end_stream_on_headers = true;
- scoped_refptr<IOBuffer> read_buffer =
- base::MakeRefCounted<IOBuffer>(kReadBufferSize);
- auto delegate = std::make_unique<DeleteStreamDelegate>(
- read_buffer.get(), kReadBufferSize,
- DeleteStreamDelegate::Phase::ON_HEADERS_RECEIVED);
- delegate->SetRunUntilCompletion(true);
- delegate->Start(std::move(request_info), http_session_.get());
- // Makes sure delegate does not get called.
- base::RunLoop().RunUntilIdle();
- const spdy::Http2HeaderBlock& response_headers = delegate->response_headers();
- EXPECT_EQ("200", response_headers.find(":status")->second);
- EXPECT_EQ("header-value", response_headers.find("header-name")->second);
- EXPECT_EQ(0u, delegate->data_received().size());
- EXPECT_EQ(0, delegate->on_data_sent_count());
- EXPECT_EQ(0, delegate->on_data_read_count());
- EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
- // Bytes sent excludes the RST frame.
- EXPECT_EQ(
- CountWriteBytes(base::make_span(writes).first(std::size(writes) - 1)),
- delegate->GetTotalSentBytes());
- EXPECT_EQ(CountReadBytes(reads), delegate->GetTotalReceivedBytes());
- }
- TEST_F(BidirectionalStreamTest, DeleteStreamDuringOnDataRead) {
- spdy::SpdySerializedFrame req(
- spdy_util_.ConstructSpdyGet(kDefaultUrl, 1, LOWEST));
- spdy::SpdySerializedFrame rst(
- spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_CANCEL));
- MockWrite writes[] = {
- CreateMockWrite(req, 0), CreateMockWrite(rst, 3),
- };
- const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
- spdy::SpdySerializedFrame resp(
- spdy_util_.ConstructSpdyGetReply(kExtraResponseHeaders, 1, 1));
- spdy::SpdySerializedFrame response_body_frame(
- spdy_util_.ConstructSpdyDataFrame(1, false));
- MockRead reads[] = {
- CreateMockRead(resp, 1), CreateMockRead(response_body_frame, 2),
- MockRead(ASYNC, 0, 4),
- };
- InitSession(reads, writes, SocketTag());
- auto request_info = std::make_unique<BidirectionalStreamRequestInfo>();
- request_info->method = "GET";
- request_info->url = default_url_;
- request_info->priority = LOWEST;
- request_info->end_stream_on_headers = true;
- scoped_refptr<IOBuffer> read_buffer =
- base::MakeRefCounted<IOBuffer>(kReadBufferSize);
- auto delegate = std::make_unique<DeleteStreamDelegate>(
- read_buffer.get(), kReadBufferSize,
- DeleteStreamDelegate::Phase::ON_DATA_READ);
- delegate->SetRunUntilCompletion(true);
- delegate->Start(std::move(request_info), http_session_.get());
- // Makes sure delegate does not get called.
- base::RunLoop().RunUntilIdle();
- const spdy::Http2HeaderBlock& response_headers = delegate->response_headers();
- EXPECT_EQ("200", response_headers.find(":status")->second);
- EXPECT_EQ("header-value", response_headers.find("header-name")->second);
- EXPECT_EQ(kUploadDataSize * 1,
- static_cast<int>(delegate->data_received().size()));
- EXPECT_EQ(0, delegate->on_data_sent_count());
- EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
- // Bytes sent excludes the RST frame.
- EXPECT_EQ(
- CountWriteBytes(base::make_span(writes).first(std::size(writes) - 1)),
- delegate->GetTotalSentBytes());
- EXPECT_EQ(CountReadBytes(reads), delegate->GetTotalReceivedBytes());
- }
- TEST_F(BidirectionalStreamTest, DeleteStreamDuringOnTrailersReceived) {
- spdy::SpdySerializedFrame req(
- spdy_util_.ConstructSpdyGet(kDefaultUrl, 1, LOWEST));
- spdy::SpdySerializedFrame rst(
- spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_CANCEL));
- MockWrite writes[] = {
- CreateMockWrite(req, 0), CreateMockWrite(rst, 4),
- };
- const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
- spdy::SpdySerializedFrame resp(
- spdy_util_.ConstructSpdyGetReply(kExtraResponseHeaders, 1, 1));
- spdy::SpdySerializedFrame response_body_frame(
- spdy_util_.ConstructSpdyDataFrame(1, false));
- spdy::Http2HeaderBlock trailers;
- trailers["foo"] = "bar";
- spdy::SpdySerializedFrame response_trailers(
- spdy_util_.ConstructSpdyResponseHeaders(1, std::move(trailers), true));
- MockRead reads[] = {
- CreateMockRead(resp, 1), CreateMockRead(response_body_frame, 2),
- CreateMockRead(response_trailers, 3), MockRead(ASYNC, 0, 5),
- };
- InitSession(reads, writes, SocketTag());
- auto request_info = std::make_unique<BidirectionalStreamRequestInfo>();
- request_info->method = "GET";
- request_info->url = default_url_;
- request_info->priority = LOWEST;
- request_info->end_stream_on_headers = true;
- scoped_refptr<IOBuffer> read_buffer =
- base::MakeRefCounted<IOBuffer>(kReadBufferSize);
- auto delegate = std::make_unique<DeleteStreamDelegate>(
- read_buffer.get(), kReadBufferSize,
- DeleteStreamDelegate::Phase::ON_TRAILERS_RECEIVED);
- delegate->SetRunUntilCompletion(true);
- delegate->Start(std::move(request_info), http_session_.get());
- // Makes sure delegate does not get called.
- base::RunLoop().RunUntilIdle();
- const spdy::Http2HeaderBlock& response_headers = delegate->response_headers();
- EXPECT_EQ("200", response_headers.find(":status")->second);
- EXPECT_EQ("header-value", response_headers.find("header-name")->second);
- EXPECT_EQ("bar", delegate->trailers().find("foo")->second);
- EXPECT_EQ(0, delegate->on_data_sent_count());
- // OnDataRead may or may not have been fired before the stream is
- // deleted.
- EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
- // Bytes sent excludes the RST frame.
- EXPECT_EQ(
- CountWriteBytes(base::make_span(writes).first(std::size(writes) - 1)),
- delegate->GetTotalSentBytes());
- EXPECT_EQ(CountReadBytes(reads), delegate->GetTotalReceivedBytes());
- }
- TEST_F(BidirectionalStreamTest, DeleteStreamDuringOnFailed) {
- spdy::SpdySerializedFrame req(
- spdy_util_.ConstructSpdyGet(kDefaultUrl, 1, LOWEST));
- spdy::SpdySerializedFrame rst(
- spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_PROTOCOL_ERROR));
- MockWrite writes[] = {
- CreateMockWrite(req, 0), CreateMockWrite(rst, 2),
- };
- const char* const kExtraHeaders[] = {"X-UpperCase", "yes"};
- spdy::SpdySerializedFrame resp(
- spdy_util_.ConstructSpdyGetReply(kExtraHeaders, 1, 1));
- MockRead reads[] = {
- CreateMockRead(resp, 1), MockRead(ASYNC, 0, 3),
- };
- InitSession(reads, writes, SocketTag());
- auto request_info = std::make_unique<BidirectionalStreamRequestInfo>();
- request_info->method = "GET";
- request_info->url = default_url_;
- request_info->priority = LOWEST;
- request_info->end_stream_on_headers = true;
- scoped_refptr<IOBuffer> read_buffer =
- base::MakeRefCounted<IOBuffer>(kReadBufferSize);
- auto delegate = std::make_unique<DeleteStreamDelegate>(
- read_buffer.get(), kReadBufferSize,
- DeleteStreamDelegate::Phase::ON_FAILED);
- delegate->SetRunUntilCompletion(true);
- delegate->Start(std::move(request_info), http_session_.get());
- // Makes sure delegate does not get called.
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(delegate->response_headers().end(),
- delegate->response_headers().find(":status"));
- EXPECT_EQ(0, delegate->on_data_sent_count());
- EXPECT_EQ(0, delegate->on_data_read_count());
- EXPECT_THAT(delegate->error(), IsError(ERR_HTTP2_PROTOCOL_ERROR));
- EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
- // Bytes sent excludes the RST frame.
- EXPECT_EQ(
- CountWriteBytes(base::make_span(writes).first(std::size(writes) - 1)),
- delegate->GetTotalSentBytes());
- EXPECT_EQ(0, delegate->GetTotalReceivedBytes());
- }
- TEST_F(BidirectionalStreamTest, TestHonorAlternativeServiceHeader) {
- spdy::SpdySerializedFrame req(
- spdy_util_.ConstructSpdyGet(kDefaultUrl, 1, LOWEST));
- MockWrite writes[] = {CreateMockWrite(req, 0)};
- std::string alt_svc_header_value =
- quic::AlpnForVersion(DefaultSupportedQuicVersions().front());
- alt_svc_header_value.append("=\"www.example.org:443\"");
- const char* const kExtraResponseHeaders[] = {"alt-svc",
- alt_svc_header_value.c_str()};
- spdy::SpdySerializedFrame resp(
- spdy_util_.ConstructSpdyGetReply(kExtraResponseHeaders, 1, 1));
- spdy::SpdySerializedFrame body_frame(
- spdy_util_.ConstructSpdyDataFrame(1, true));
- MockRead reads[] = {
- CreateMockRead(resp, 1), CreateMockRead(body_frame, 2),
- MockRead(SYNCHRONOUS, 0, 3),
- };
- // Enable QUIC so that the alternative service header can be added to
- // HttpServerProperties.
- session_deps_.enable_quic = true;
- InitSession(reads, writes, SocketTag());
- auto request_info = std::make_unique<BidirectionalStreamRequestInfo>();
- request_info->method = "GET";
- request_info->url = default_url_;
- request_info->priority = LOWEST;
- request_info->end_stream_on_headers = true;
- scoped_refptr<IOBuffer> read_buffer =
- base::MakeRefCounted<IOBuffer>(kReadBufferSize);
- auto timer = std::make_unique<MockTimer>();
- auto delegate = std::make_unique<TestDelegateBase>(
- read_buffer.get(), kReadBufferSize, std::move(timer));
- delegate->SetRunUntilCompletion(true);
- delegate->Start(std::move(request_info), http_session_.get());
- const spdy::Http2HeaderBlock& response_headers = delegate->response_headers();
- EXPECT_EQ("200", response_headers.find(":status")->second);
- EXPECT_EQ(alt_svc_header_value, response_headers.find("alt-svc")->second);
- EXPECT_EQ(0, delegate->on_data_sent_count());
- EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
- EXPECT_EQ(kUploadData, delegate->data_received());
- EXPECT_EQ(CountWriteBytes(writes), delegate->GetTotalSentBytes());
- EXPECT_EQ(CountReadBytes(reads), delegate->GetTotalReceivedBytes());
- AlternativeServiceInfoVector alternative_service_info_vector =
- http_session_->http_server_properties()->GetAlternativeServiceInfos(
- url::SchemeHostPort(default_url_), NetworkIsolationKey());
- ASSERT_EQ(1u, alternative_service_info_vector.size());
- AlternativeService alternative_service(kProtoQUIC, "www.example.org", 443);
- EXPECT_EQ(alternative_service,
- alternative_service_info_vector[0].alternative_service());
- }
- // Test that a BidirectionalStream created with a specific tag, tags the
- // underlying socket appropriately.
- TEST_F(BidirectionalStreamTest, Tagging) {
- spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
- kDefaultUrl, 1, kBodyDataSize, LOW, nullptr, 0));
- spdy::SpdySerializedFrame data_frame(
- spdy_util_.ConstructSpdyDataFrame(1, kBodyDataString, /*fin=*/true));
- MockWrite writes[] = {
- CreateMockWrite(req, 0), CreateMockWrite(data_frame, 3),
- };
- spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
- spdy::SpdySerializedFrame response_body_frame(
- spdy_util_.ConstructSpdyDataFrame(1, /*fin=*/true));
- MockRead reads[] = {
- CreateMockRead(resp, 1),
- MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause.
- CreateMockRead(response_body_frame, 4), MockRead(ASYNC, 0, 5),
- };
- #if BUILDFLAG(IS_ANDROID)
- SocketTag tag(0x12345678, 0x87654321);
- #else
- SocketTag tag;
- #endif
- InitSession(reads, writes, tag);
- auto request_info = std::make_unique<BidirectionalStreamRequestInfo>();
- request_info->method = "POST";
- request_info->url = default_url_;
- request_info->extra_headers.SetHeader(net::HttpRequestHeaders::kContentLength,
- base::NumberToString(kBodyDataSize));
- request_info->socket_tag = tag;
- scoped_refptr<IOBuffer> read_buffer =
- base::MakeRefCounted<IOBuffer>(kReadBufferSize);
- auto delegate =
- std::make_unique<TestDelegateBase>(read_buffer.get(), kReadBufferSize);
- delegate->Start(std::move(request_info), http_session_.get());
- sequenced_data_->RunUntilPaused();
- EXPECT_EQ(socket_factory_->GetLastProducedTCPSocket()->tag(), tag);
- EXPECT_TRUE(
- socket_factory_->GetLastProducedTCPSocket()->tagged_before_connected());
- void* socket = socket_factory_->GetLastProducedTCPSocket();
- scoped_refptr<StringIOBuffer> buf =
- base::MakeRefCounted<StringIOBuffer>(kBodyDataString);
- delegate->SendData(buf.get(), buf->size(), true);
- sequenced_data_->Resume();
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(socket, socket_factory_->GetLastProducedTCPSocket());
- }
- } // namespace net
|