Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "net/http/bidirectional_stream.h" | |
| 6 | |
| 7 #include <string> | |
| 8 | |
| 9 #include "base/memory/scoped_ptr.h" | |
| 10 #include "base/run_loop.h" | |
| 11 #include "base/stl_util.h" | |
| 12 #include "base/strings/string_piece.h" | |
| 13 #include "net/http/http_request_info.h" | |
| 14 #include "net/http/http_response_headers.h" | |
| 15 #include "net/http/http_response_info.h" | |
| 16 #include "net/socket/socket_test_util.h" | |
| 17 #include "net/spdy/spdy_read_queue.h" | |
| 18 #include "net/spdy/spdy_session.h" | |
| 19 #include "net/spdy/spdy_test_util_common.h" | |
| 20 #include "testing/gtest/include/gtest/gtest.h" | |
| 21 | |
| 22 namespace net { | |
| 23 | |
| 24 namespace { | |
| 25 | |
| 26 const char kBodyData[] = "Body data"; | |
| 27 const size_t kBodyDataSize = arraysize(kBodyData); | |
| 28 const base::StringPiece kBodyDataStringPiece(kBodyData, kBodyDataSize); | |
| 29 | |
| 30 class TestBidirectionalStreamDelegate : public BidirectionalStream::Delegate { | |
| 31 public: | |
| 32 TestBidirectionalStreamDelegate(base::WeakPtr<SpdySession> session) | |
| 33 : loop_(new base::RunLoop), stream_(new BidirectionalStream(session)) {} | |
| 34 | |
| 35 ~TestBidirectionalStreamDelegate() override {} | |
| 36 | |
| 37 void OnFailed(int rv) override { loop_->Quit(); } | |
| 38 | |
| 39 void OnRequestHeadersSent() override {} | |
| 40 | |
| 41 void OnHeaders(const SpdyHeaderBlock& response_headers) override { | |
| 42 response_headers_ = response_headers; | |
| 43 } | |
| 44 | |
| 45 void OnDataReceived(scoped_ptr<SpdyBuffer> buffer) override { | |
| 46 received_data_queue_.Enqueue(buffer.Pass()); | |
| 47 } | |
| 48 | |
| 49 void OnDataSent() override {} | |
| 50 | |
| 51 void OnTrailers(const SpdyHeaderBlock& trailers) override { | |
| 52 trailers_ = trailers; | |
| 53 } | |
| 54 | |
| 55 void OnClose(int status) override { loop_->Quit(); } | |
| 56 | |
| 57 void Start(HttpRequestInfo* request) { | |
| 58 stream_->Start(request, this); | |
| 59 loop_->Run(); | |
| 60 } | |
| 61 | |
| 62 void SendData(IOBuffer* data, int length, bool end_of_stream) { | |
| 63 stream_->SendData(data, length, end_of_stream); | |
| 64 } | |
| 65 | |
| 66 std::string TakeReceivedData() { | |
| 67 size_t len = received_data_queue_.GetTotalSize(); | |
| 68 std::string received_data(len, '\0'); | |
| 69 if (len > 0) { | |
| 70 EXPECT_EQ(len, received_data_queue_.Dequeue( | |
| 71 string_as_array(&received_data), len)); | |
| 72 } | |
| 73 return received_data; | |
| 74 } | |
| 75 | |
| 76 SpdyHeaderBlock response_headers_; | |
| 77 SpdyHeaderBlock trailers_; | |
| 78 | |
| 79 private: | |
| 80 scoped_ptr<base::RunLoop> loop_; | |
| 81 scoped_ptr<BidirectionalStream> stream_; | |
| 82 SpdyReadQueue received_data_queue_; | |
| 83 }; | |
| 84 | |
| 85 // A delegate that sends data after request headers are sent. | |
| 86 class SendDataDelegate : public TestBidirectionalStreamDelegate { | |
| 87 public: | |
| 88 SendDataDelegate(base::WeakPtr<SpdySession> session, base::StringPiece data) | |
| 89 : TestBidirectionalStreamDelegate(session), data_(data) {} | |
| 90 | |
| 91 ~SendDataDelegate() override {} | |
| 92 | |
| 93 void OnRequestHeadersSent() override { | |
| 94 TestBidirectionalStreamDelegate::OnRequestHeadersSent(); | |
| 95 if (data_.data()) { | |
| 96 scoped_refptr<StringIOBuffer> buf(new StringIOBuffer(data_.as_string())); | |
| 97 SendData(buf.get(), buf->size(), NO_MORE_DATA_TO_SEND); | |
| 98 } | |
| 99 } | |
| 100 | |
| 101 private: | |
| 102 base::StringPiece data_; | |
| 103 }; | |
| 104 | |
| 105 } // namespace | |
| 106 | |
| 107 class BidirectionalStreamTest : public testing::Test { | |
| 108 public: | |
| 109 BidirectionalStreamTest() | |
| 110 : spdy_util_(kProtoHTTP2), session_deps_(kProtoHTTP2) {} | |
| 111 | |
| 112 protected: | |
| 113 void TearDown() override { | |
| 114 EXPECT_TRUE(sequenced_data_->AllReadDataConsumed()); | |
| 115 EXPECT_TRUE(sequenced_data_->AllWriteDataConsumed()); | |
| 116 } | |
| 117 | |
| 118 // Initializes the session using SequencedSocketData. | |
| 119 void InitSession(MockRead* reads, | |
| 120 size_t reads_count, | |
| 121 MockWrite* writes, | |
| 122 size_t writes_count, | |
| 123 const SpdySessionKey& key) { | |
| 124 sequenced_data_.reset( | |
| 125 new SequencedSocketData(reads, reads_count, writes, writes_count)); | |
| 126 session_deps_.socket_factory->AddSocketDataProvider(sequenced_data_.get()); | |
| 127 http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_); | |
| 128 session_ = CreateInsecureSpdySession(http_session_, key, BoundNetLog()); | |
| 129 } | |
| 130 | |
| 131 SpdyTestUtil spdy_util_; | |
| 132 SpdySessionDependencies session_deps_; | |
| 133 scoped_ptr<SequencedSocketData> sequenced_data_; | |
| 134 scoped_refptr<HttpNetworkSession> http_session_; | |
| 135 base::WeakPtr<SpdySession> session_; | |
| 136 scoped_ptr<TestBidirectionalStreamDelegate> delegate_; | |
| 137 }; | |
| 138 | |
| 139 TEST_F(BidirectionalStreamTest, SendGetRequest) { | |
| 140 scoped_ptr<SpdyFrame> req( | |
| 141 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
| 142 MockWrite writes[] = { | |
| 143 CreateMockWrite(*req.get(), 0), | |
| 144 }; | |
| 145 | |
| 146 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
|
Bence
2015/10/01 05:29:28
Consider passing some extra_headers to ConstructSp
xunjieli
2015/10/01 18:41:16
Done. Good idea. Thanks!
| |
| 147 | |
| 148 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false)); | |
| 149 | |
| 150 const char* const kExtraHeaders[] = {"foo", "bar"}; | |
| 151 scoped_ptr<SpdyFrame> trailers( | |
| 152 spdy_util_.ConstructSpdyHeaderFrame(1, kExtraHeaders, 1, true)); | |
| 153 | |
| 154 MockRead reads[] = { | |
| 155 CreateMockRead(*resp, 1), CreateMockRead(*body, 2), | |
| 156 CreateMockRead(*trailers, 3), MockRead(SYNCHRONOUS, 0, 4), | |
| 157 }; | |
| 158 | |
| 159 HostPortPair host_port_pair("www.example.org", 80); | |
| 160 SpdySessionKey key(host_port_pair, ProxyServer::Direct(), | |
| 161 PRIVACY_MODE_DISABLED); | |
| 162 InitSession(reads, arraysize(reads), writes, arraysize(writes), key); | |
| 163 | |
| 164 HttpRequestInfo request; | |
| 165 request.method = "GET"; | |
| 166 request.url = GURL("http://www.example.org/"); | |
| 167 | |
| 168 delegate_.reset(new TestBidirectionalStreamDelegate(session_)); | |
| 169 delegate_->Start(&request); | |
| 170 base::StringPiece status = delegate_->response_headers_[":status"]; | |
| 171 EXPECT_EQ("200", status); | |
| 172 EXPECT_EQ(kUploadData, delegate_->TakeReceivedData()); | |
| 173 base::StringPiece trailer = delegate_->trailers_["foo"]; | |
| 174 EXPECT_EQ("bar", trailer); | |
| 175 } | |
| 176 | |
| 177 TEST_F(BidirectionalStreamTest, SendPostRequest) { | |
| 178 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false); | |
| 179 | |
| 180 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0)); | |
| 181 scoped_ptr<SpdyFrame> body( | |
| 182 framer.CreateDataFrame(1, kBodyData, kBodyDataSize, DATA_FLAG_FIN)); | |
| 183 MockWrite writes[] = { | |
| 184 CreateMockWrite(*req, 0), // request | |
| 185 CreateMockWrite(*body, 1), // POST upload frame | |
| 186 }; | |
| 187 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); | |
|
Bence
2015/10/01 05:29:28
Same thing here.
xunjieli
2015/10/01 18:41:16
Done.
| |
| 188 | |
| 189 scoped_ptr<SpdyFrame> resp_data( | |
| 190 framer.CreateDataFrame(1, kBodyData, kBodyDataSize, DATA_FLAG_NONE)); | |
| 191 | |
| 192 const char* const kExtraHeaders[] = {"foo", "bar"}; | |
| 193 scoped_ptr<SpdyFrame> trailers( | |
| 194 spdy_util_.ConstructSpdyHeaderFrame(1, kExtraHeaders, 1, true)); | |
| 195 | |
| 196 MockRead reads[] = { | |
| 197 CreateMockRead(*resp, 2), CreateMockRead(*resp_data, 3), | |
| 198 CreateMockRead(*trailers, 4), MockRead(SYNCHRONOUS, 0, 5) // EOF | |
| 199 }; | |
| 200 | |
| 201 HostPortPair host_port_pair("www.example.org", 80); | |
| 202 SpdySessionKey key(host_port_pair, ProxyServer::Direct(), | |
| 203 PRIVACY_MODE_DISABLED); | |
| 204 InitSession(reads, arraysize(reads), writes, arraysize(writes), key); | |
| 205 | |
| 206 HttpRequestInfo request; | |
| 207 request.method = "POST"; | |
| 208 request.url = GURL("http://www.example.org/"); | |
| 209 | |
| 210 delegate_.reset(new SendDataDelegate(session_, kBodyDataStringPiece)); | |
| 211 delegate_->Start(&request); | |
| 212 | |
| 213 base::StringPiece header = delegate_->response_headers_[":status"]; | |
| 214 EXPECT_EQ("200", header); | |
| 215 EXPECT_EQ(std::string(kBodyData, kBodyDataSize), | |
| 216 delegate_->TakeReceivedData()); | |
| 217 base::StringPiece trailer = delegate_->trailers_["foo"]; | |
| 218 EXPECT_EQ("bar", trailer); | |
| 219 } | |
| 220 | |
| 221 } // namespace net | |
| OLD | NEW |