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 |