blob: 55387cf410a5ca039ded6a4ccb9fad3ca0ef4427 [file] [log] [blame]
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001// Copyright (c) 2012 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/spdy/spdy_http_stream.h"
6
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01007#include <vector>
8
Torne (Richard Coles)58218062012-11-14 11:43:16 +00009#include "base/memory/scoped_ptr.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010010#include "base/stl_util.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000011#include "base/threading/sequenced_worker_pool.h"
12#include "crypto/ec_private_key.h"
13#include "crypto/ec_signature_creator.h"
14#include "crypto/signature_creator.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000015#include "net/base/capturing_net_log.h"
16#include "net/base/load_timing_info.h"
17#include "net/base/load_timing_info_test_util.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000018#include "net/base/upload_data_stream.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000019#include "net/base/upload_element_reader.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010020#include "net/cert/asn1_util.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000021#include "net/http/http_request_info.h"
22#include "net/http/http_response_headers.h"
23#include "net/http/http_response_info.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010024#include "net/socket/next_proto.h"
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +010025#include "net/socket/socket_test_util.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000026#include "net/spdy/spdy_credential_builder.h"
27#include "net/spdy/spdy_http_utils.h"
28#include "net/spdy/spdy_session.h"
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +010029#include "net/spdy/spdy_test_util_common.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000030#include "net/ssl/default_server_bound_cert_store.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000031#include "testing/gtest/include/gtest/gtest.h"
32
Torne (Richard Coles)58218062012-11-14 11:43:16 +000033namespace net {
34
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000035namespace {
36
37// Tests the load timing of a stream that's connected and is not the first
38// request sent on a connection.
39void TestLoadTimingReused(const HttpStream& stream) {
40 LoadTimingInfo load_timing_info;
41 EXPECT_TRUE(stream.GetLoadTimingInfo(&load_timing_info));
42
43 EXPECT_TRUE(load_timing_info.socket_reused);
44 EXPECT_NE(NetLog::Source::kInvalidId, load_timing_info.socket_log_id);
45
46 ExpectConnectTimingHasNoTimes(load_timing_info.connect_timing);
47 ExpectLoadTimingHasOnlyConnectionTimes(load_timing_info);
48}
49
50// Tests the load timing of a stream that's connected and using a fresh
51// connection.
52void TestLoadTimingNotReused(const HttpStream& stream) {
53 LoadTimingInfo load_timing_info;
54 EXPECT_TRUE(stream.GetLoadTimingInfo(&load_timing_info));
55
56 EXPECT_FALSE(load_timing_info.socket_reused);
57 EXPECT_NE(NetLog::Source::kInvalidId, load_timing_info.socket_log_id);
58
59 ExpectConnectTimingHasTimes(load_timing_info.connect_timing,
60 CONNECT_TIMING_HAS_DNS_TIMES);
61 ExpectLoadTimingHasOnlyConnectionTimes(load_timing_info);
62}
63
64} // namespace
65
Ben Murdocheb525c52013-07-10 11:40:50 +010066class SpdyHttpStreamTest : public testing::Test,
67 public testing::WithParamInterface<NextProto> {
Torne (Richard Coles)58218062012-11-14 11:43:16 +000068 public:
Ben Murdocheb525c52013-07-10 11:40:50 +010069 SpdyHttpStreamTest()
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +010070 : spdy_util_(GetParam()),
71 session_deps_(GetParam()) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000072 session_deps_.net_log = &net_log_;
73 }
74
75 DeterministicSocketData* deterministic_data() {
76 return deterministic_data_.get();
77 }
78
Torne (Richard Coles)58218062012-11-14 11:43:16 +000079 OrderedSocketData* data() { return data_.get(); }
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000080
Torne (Richard Coles)58218062012-11-14 11:43:16 +000081 protected:
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000082 virtual void TearDown() OVERRIDE {
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +010083 crypto::ECSignatureCreator::SetFactoryForTesting(NULL);
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +010084 base::MessageLoop::current()->RunUntilIdle();
Torne (Richard Coles)58218062012-11-14 11:43:16 +000085 }
86
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000087 // Initializes the session using DeterministicSocketData. It's advisable
88 // to use this function rather than the OrderedSocketData, since the
89 // DeterministicSocketData behaves in a reasonable manner.
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010090 void InitSessionDeterministic(MockRead* reads, size_t reads_count,
91 MockWrite* writes, size_t writes_count,
92 const SpdySessionKey& key) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000093 deterministic_data_.reset(
94 new DeterministicSocketData(reads, reads_count, writes, writes_count));
95 session_deps_.deterministic_socket_factory->AddSocketDataProvider(
96 deterministic_data_.get());
97 http_session_ =
98 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010099 session_ = CreateInsecureSpdySession(http_session_, key, BoundNetLog());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000100 }
101
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000102 // Initializes the session using the finicky OrderedSocketData class.
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100103 void InitSession(MockRead* reads, size_t reads_count,
104 MockWrite* writes, size_t writes_count,
105 const SpdySessionKey& key) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000106 data_.reset(new OrderedSocketData(reads, reads_count,
107 writes, writes_count));
108 session_deps_.socket_factory->AddSocketDataProvider(data_.get());
109 http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100110 session_ = CreateInsecureSpdySession(http_session_, key, BoundNetLog());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000111 }
112
113 void TestSendCredentials(
114 ServerBoundCertService* server_bound_cert_service,
115 const std::string& cert,
116 const std::string& proof);
117
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100118 SpdyTestUtil spdy_util_;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000119 CapturingNetLog net_log_;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000120 SpdySessionDependencies session_deps_;
121 scoped_ptr<OrderedSocketData> data_;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000122 scoped_ptr<DeterministicSocketData> deterministic_data_;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000123 scoped_refptr<HttpNetworkSession> http_session_;
Ben Murdochca12bfa2013-07-23 11:17:05 +0100124 base::WeakPtr<SpdySession> session_;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000125
126 private:
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000127 MockECSignatureCreatorFactory ec_signature_creator_factory_;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000128};
129
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100130INSTANTIATE_TEST_CASE_P(
131 NextProto,
Ben Murdocheb525c52013-07-10 11:40:50 +0100132 SpdyHttpStreamTest,
Ben Murdoch558790d2013-07-30 15:19:42 +0100133 testing::Values(kProtoSPDY2, kProtoSPDY3, kProtoSPDY31, kProtoSPDY4a2,
134 kProtoHTTP2Draft04));
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100135
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100136// SpdyHttpStream::GetUploadProgress() should still work even before the
137// stream is initialized.
Ben Murdocheb525c52013-07-10 11:40:50 +0100138TEST_P(SpdyHttpStreamTest, GetUploadProgressBeforeInitialization) {
139 MockRead reads[] = {
140 MockRead(ASYNC, 0, 0) // EOF
141 };
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100142
Ben Murdocheb525c52013-07-10 11:40:50 +0100143 HostPortPair host_port_pair("www.google.com", 80);
144 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
145 kPrivacyModeDisabled);
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100146 InitSession(reads, arraysize(reads), NULL, 0, key);
Ben Murdocheb525c52013-07-10 11:40:50 +0100147
Ben Murdochca12bfa2013-07-23 11:17:05 +0100148 SpdyHttpStream stream(session_, false);
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100149 UploadProgress progress = stream.GetUploadProgress();
150 EXPECT_EQ(0u, progress.size());
151 EXPECT_EQ(0u, progress.position());
152}
153
Ben Murdocheb525c52013-07-10 11:40:50 +0100154TEST_P(SpdyHttpStreamTest, SendRequest) {
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100155 scoped_ptr<SpdyFrame> req(
156 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000157 MockWrite writes[] = {
158 CreateMockWrite(*req.get(), 1),
159 };
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100160 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000161 MockRead reads[] = {
162 CreateMockRead(*resp, 2),
163 MockRead(SYNCHRONOUS, 0, 3) // EOF
164 };
165
166 HostPortPair host_port_pair("www.google.com", 80);
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100167 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
168 kPrivacyModeDisabled);
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100169 InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000170
171 HttpRequestInfo request;
172 request.method = "GET";
173 request.url = GURL("http://www.google.com/");
174 TestCompletionCallback callback;
175 HttpResponseInfo response;
176 HttpRequestHeaders headers;
177 BoundNetLog net_log;
Ben Murdochca12bfa2013-07-23 11:17:05 +0100178 scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream(session_, true));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000179 // Make sure getting load timing information the stream early does not crash.
180 LoadTimingInfo load_timing_info;
181 EXPECT_FALSE(http_stream->GetLoadTimingInfo(&load_timing_info));
182
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000183 ASSERT_EQ(
184 OK,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000185 http_stream->InitializeStream(&request, DEFAULT_PRIORITY,
186 net_log, CompletionCallback()));
187 EXPECT_FALSE(http_stream->GetLoadTimingInfo(&load_timing_info));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000188
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000189 EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response,
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000190 callback.callback()));
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100191 EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000192 EXPECT_FALSE(http_stream->GetLoadTimingInfo(&load_timing_info));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000193
194 // This triggers the MockWrite and read 2
195 callback.WaitForResult();
196
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000197 // Can get timing information once the stream connects.
198 TestLoadTimingNotReused(*http_stream);
199
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000200 // This triggers read 3. The empty read causes the session to shut down.
201 data()->CompleteRead();
202
203 // Because we abandoned the stream, we don't expect to find a session in the
204 // pool anymore.
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100205 EXPECT_FALSE(HasSpdySession(http_session_->spdy_session_pool(), key));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000206 EXPECT_TRUE(data()->at_read_eof());
207 EXPECT_TRUE(data()->at_write_eof());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000208
209 TestLoadTimingNotReused(*http_stream);
210 http_stream->Close(true);
211 // Test that there's no crash when trying to get the load timing after the
212 // stream has been closed.
213 TestLoadTimingNotReused(*http_stream);
214}
215
Ben Murdocheb525c52013-07-10 11:40:50 +0100216TEST_P(SpdyHttpStreamTest, LoadTimingTwoRequests) {
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100217 scoped_ptr<SpdyFrame> req1(
218 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
219 scoped_ptr<SpdyFrame> req2(
220 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000221 MockWrite writes[] = {
222 CreateMockWrite(*req1, 0),
223 CreateMockWrite(*req2, 1),
224 };
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100225 scoped_ptr<SpdyFrame> resp1(
226 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
227 scoped_ptr<SpdyFrame> body1(
228 spdy_util_.ConstructSpdyBodyFrame(1, "", 0, true));
229 scoped_ptr<SpdyFrame> resp2(
230 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
231 scoped_ptr<SpdyFrame> body2(
232 spdy_util_.ConstructSpdyBodyFrame(3, "", 0, true));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000233 MockRead reads[] = {
234 CreateMockRead(*resp1, 2),
235 CreateMockRead(*body1, 3),
236 CreateMockRead(*resp2, 4),
237 CreateMockRead(*body2, 5),
238 MockRead(ASYNC, 0, 6) // EOF
239 };
240
241 HostPortPair host_port_pair("www.google.com", 80);
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100242 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
243 kPrivacyModeDisabled);
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100244 InitSessionDeterministic(reads, arraysize(reads),
245 writes, arraysize(writes),
246 key);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000247
248 HttpRequestInfo request1;
249 request1.method = "GET";
250 request1.url = GURL("http://www.google.com/");
251 TestCompletionCallback callback1;
252 HttpResponseInfo response1;
253 HttpRequestHeaders headers1;
Ben Murdochca12bfa2013-07-23 11:17:05 +0100254 scoped_ptr<SpdyHttpStream> http_stream1(new SpdyHttpStream(session_, true));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000255
Ben Murdochca12bfa2013-07-23 11:17:05 +0100256 HttpRequestInfo request2;
257 request2.method = "GET";
258 request2.url = GURL("http://www.google.com/");
259 TestCompletionCallback callback2;
260 HttpResponseInfo response2;
261 HttpRequestHeaders headers2;
262 scoped_ptr<SpdyHttpStream> http_stream2(new SpdyHttpStream(session_, true));
263
264 // First write.
Ben Murdoch9ab55632013-07-18 11:57:30 +0100265 ASSERT_EQ(OK,
266 http_stream1->InitializeStream(&request1, DEFAULT_PRIORITY,
267 BoundNetLog(),
268 CompletionCallback()));
269 EXPECT_EQ(ERR_IO_PENDING, http_stream1->SendRequest(headers1, &response1,
270 callback1.callback()));
271 EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key));
272
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000273 deterministic_data()->RunFor(1);
274 EXPECT_LE(0, callback1.WaitForResult());
275
276 TestLoadTimingNotReused(*http_stream1);
277 LoadTimingInfo load_timing_info1;
278 LoadTimingInfo load_timing_info2;
279 EXPECT_TRUE(http_stream1->GetLoadTimingInfo(&load_timing_info1));
280 EXPECT_FALSE(http_stream2->GetLoadTimingInfo(&load_timing_info2));
281
282 // Second write.
Ben Murdochca12bfa2013-07-23 11:17:05 +0100283 ASSERT_EQ(OK,
284 http_stream2->InitializeStream(&request2, DEFAULT_PRIORITY,
285 BoundNetLog(),
286 CompletionCallback()));
287 EXPECT_EQ(ERR_IO_PENDING, http_stream2->SendRequest(headers2, &response2,
288 callback2.callback()));
289 EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key));
290
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000291 deterministic_data()->RunFor(1);
292 EXPECT_LE(0, callback2.WaitForResult());
293 TestLoadTimingReused(*http_stream2);
294 EXPECT_TRUE(http_stream2->GetLoadTimingInfo(&load_timing_info2));
295 EXPECT_EQ(load_timing_info1.socket_log_id, load_timing_info2.socket_log_id);
296
297 // All the reads.
298 deterministic_data()->RunFor(6);
299
300 // Read stream 1 to completion, before making sure we can still read load
301 // timing from both streams.
302 scoped_refptr<IOBuffer> buf1(new IOBuffer(1));
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100303 ASSERT_EQ(
304 0, http_stream1->ReadResponseBody(buf1.get(), 1, callback1.callback()));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000305
306 // Stream 1 has been read to completion.
307 TestLoadTimingNotReused(*http_stream1);
308 // Stream 2 still has queued body data.
309 TestLoadTimingReused(*http_stream2);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000310}
311
Ben Murdocheb525c52013-07-10 11:40:50 +0100312TEST_P(SpdyHttpStreamTest, SendChunkedPost) {
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100313 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100314
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100315 scoped_ptr<SpdyFrame> req(
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100316 spdy_util_.ConstructChunkedSpdyPost(NULL, 0));
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100317 scoped_ptr<SpdyFrame> body(
318 framer.CreateDataFrame(1, kUploadData, kUploadDataSize, DATA_FLAG_FIN));
319 std::vector<MockWrite> writes;
320 int seq = 0;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100321 writes.push_back(CreateMockWrite(*req, seq++));
322 writes.push_back(CreateMockWrite(*body, seq++)); // POST upload frame
323
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100324 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100325 std::vector<MockRead> reads;
326 reads.push_back(CreateMockRead(*resp, seq++));
327 reads.push_back(CreateMockRead(*body, seq++));
328 reads.push_back(MockRead(SYNCHRONOUS, 0, seq++)); // EOF
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000329
330 HostPortPair host_port_pair("www.google.com", 80);
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100331 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
332 kPrivacyModeDisabled);
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100333 InitSession(vector_as_array(&reads), reads.size(),
334 vector_as_array(&writes), writes.size(),
335 key);
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100336 EXPECT_EQ(spdy_util_.spdy_version(), session_->GetProtocolVersion());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000337
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000338 UploadDataStream upload_stream(UploadDataStream::CHUNKED, 0);
339 const int kFirstChunkSize = kUploadDataSize/2;
340 upload_stream.AppendChunk(kUploadData, kFirstChunkSize, false);
341 upload_stream.AppendChunk(kUploadData + kFirstChunkSize,
342 kUploadDataSize - kFirstChunkSize, true);
343
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000344 HttpRequestInfo request;
345 request.method = "POST";
346 request.url = GURL("http://www.google.com/");
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000347 request.upload_data_stream = &upload_stream;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000348
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000349 ASSERT_EQ(OK, upload_stream.Init(CompletionCallback()));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000350
351 TestCompletionCallback callback;
352 HttpResponseInfo response;
353 HttpRequestHeaders headers;
354 BoundNetLog net_log;
Ben Murdochca12bfa2013-07-23 11:17:05 +0100355 SpdyHttpStream http_stream(session_, true);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000356 ASSERT_EQ(
357 OK,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000358 http_stream.InitializeStream(&request, DEFAULT_PRIORITY,
359 net_log, CompletionCallback()));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000360
361 EXPECT_EQ(ERR_IO_PENDING, http_stream.SendRequest(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000362 headers, &response, callback.callback()));
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100363 EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000364
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000365 // This results in writing the post body and reading the response headers.
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000366 callback.WaitForResult();
367
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000368 // This triggers reading the body and the EOF, causing the session to shut
369 // down.
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000370 data()->CompleteRead();
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100371 base::MessageLoop::current()->RunUntilIdle();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000372
373 // Because we abandoned the stream, we don't expect to find a session in the
374 // pool anymore.
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100375 EXPECT_FALSE(HasSpdySession(http_session_->spdy_session_pool(), key));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000376 EXPECT_TRUE(data()->at_read_eof());
377 EXPECT_TRUE(data()->at_write_eof());
378}
379
380// Test to ensure the SpdyStream state machine does not get confused when a
381// chunk becomes available while a write is pending.
Ben Murdocheb525c52013-07-10 11:40:50 +0100382TEST_P(SpdyHttpStreamTest, DelayedSendChunkedPost) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000383 const char kUploadData1[] = "12345678";
384 const int kUploadData1Size = arraysize(kUploadData1)-1;
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100385 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0));
386 scoped_ptr<SpdyFrame> chunk1(spdy_util_.ConstructSpdyBodyFrame(1, false));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000387 scoped_ptr<SpdyFrame> chunk2(
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100388 spdy_util_.ConstructSpdyBodyFrame(
389 1, kUploadData1, kUploadData1Size, false));
390 scoped_ptr<SpdyFrame> chunk3(spdy_util_.ConstructSpdyBodyFrame(1, true));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000391 MockWrite writes[] = {
392 CreateMockWrite(*req.get(), 0),
393 CreateMockWrite(*chunk1, 1), // POST upload frames
394 CreateMockWrite(*chunk2, 2),
395 CreateMockWrite(*chunk3, 3),
396 };
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100397 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000398 MockRead reads[] = {
399 CreateMockRead(*resp, 4),
400 CreateMockRead(*chunk1, 5),
401 CreateMockRead(*chunk2, 6),
402 CreateMockRead(*chunk3, 7),
403 MockRead(ASYNC, 0, 8) // EOF
404 };
405
406 HostPortPair host_port_pair("www.google.com", 80);
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100407 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
408 kPrivacyModeDisabled);
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100409 InitSessionDeterministic(reads, arraysize(reads),
410 writes, arraysize(writes),
411 key);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000412
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000413 UploadDataStream upload_stream(UploadDataStream::CHUNKED, 0);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000414
415 HttpRequestInfo request;
416 request.method = "POST";
417 request.url = GURL("http://www.google.com/");
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000418 request.upload_data_stream = &upload_stream;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000419
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000420 ASSERT_EQ(OK, upload_stream.Init(CompletionCallback()));
421 upload_stream.AppendChunk(kUploadData, kUploadDataSize, false);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000422
423 BoundNetLog net_log;
Ben Murdochca12bfa2013-07-23 11:17:05 +0100424 scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream(session_, true));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000425 ASSERT_EQ(OK, http_stream->InitializeStream(&request, DEFAULT_PRIORITY,
426 net_log, CompletionCallback()));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000427
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000428 TestCompletionCallback callback;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000429 HttpRequestHeaders headers;
430 HttpResponseInfo response;
431 // This will attempt to Write() the initial request and headers, which will
432 // complete asynchronously.
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000433 EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response,
434 callback.callback()));
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100435 EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000436
437 // Complete the initial request write and the first chunk.
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000438 deterministic_data()->RunFor(2);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000439 ASSERT_TRUE(callback.have_result());
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100440 EXPECT_EQ(OK, callback.WaitForResult());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000441
442 // Now append the final two chunks which will enqueue two more writes.
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000443 upload_stream.AppendChunk(kUploadData1, kUploadData1Size, false);
444 upload_stream.AppendChunk(kUploadData, kUploadDataSize, true);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000445
446 // Finish writing all the chunks.
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000447 deterministic_data()->RunFor(2);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000448
449 // Read response headers.
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000450 deterministic_data()->RunFor(1);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000451 ASSERT_EQ(OK, http_stream->ReadResponseHeaders(callback.callback()));
452
453 // Read and check |chunk1| response.
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000454 deterministic_data()->RunFor(1);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000455 scoped_refptr<IOBuffer> buf1(new IOBuffer(kUploadDataSize));
456 ASSERT_EQ(kUploadDataSize,
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100457 http_stream->ReadResponseBody(
458 buf1.get(), kUploadDataSize, callback.callback()));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000459 EXPECT_EQ(kUploadData, std::string(buf1->data(), kUploadDataSize));
460
461 // Read and check |chunk2| response.
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000462 deterministic_data()->RunFor(1);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000463 scoped_refptr<IOBuffer> buf2(new IOBuffer(kUploadData1Size));
464 ASSERT_EQ(kUploadData1Size,
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100465 http_stream->ReadResponseBody(
466 buf2.get(), kUploadData1Size, callback.callback()));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000467 EXPECT_EQ(kUploadData1, std::string(buf2->data(), kUploadData1Size));
468
469 // Read and check |chunk3| response.
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000470 deterministic_data()->RunFor(1);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000471 scoped_refptr<IOBuffer> buf3(new IOBuffer(kUploadDataSize));
472 ASSERT_EQ(kUploadDataSize,
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100473 http_stream->ReadResponseBody(
474 buf3.get(), kUploadDataSize, callback.callback()));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000475 EXPECT_EQ(kUploadData, std::string(buf3->data(), kUploadDataSize));
476
477 // Finish reading the |EOF|.
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000478 deterministic_data()->RunFor(1);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000479 ASSERT_TRUE(response.headers.get());
480 ASSERT_EQ(200, response.headers->response_code());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000481 EXPECT_TRUE(deterministic_data()->at_read_eof());
482 EXPECT_TRUE(deterministic_data()->at_write_eof());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000483}
484
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000485// Test case for bug: http://code.google.com/p/chromium/issues/detail?id=50058
Ben Murdocheb525c52013-07-10 11:40:50 +0100486TEST_P(SpdyHttpStreamTest, SpdyURLTest) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000487 const char * const full_url = "http://www.google.com/foo?query=what#anchor";
488 const char * const base_url = "http://www.google.com/foo?query=what";
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100489 scoped_ptr<SpdyFrame> req(
490 spdy_util_.ConstructSpdyGet(base_url, false, 1, LOWEST));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000491 MockWrite writes[] = {
492 CreateMockWrite(*req.get(), 1),
493 };
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100494 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000495 MockRead reads[] = {
496 CreateMockRead(*resp, 2),
497 MockRead(SYNCHRONOUS, 0, 3) // EOF
498 };
499
500 HostPortPair host_port_pair("www.google.com", 80);
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100501 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
502 kPrivacyModeDisabled);
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100503 InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000504
505 HttpRequestInfo request;
506 request.method = "GET";
507 request.url = GURL(full_url);
508 TestCompletionCallback callback;
509 HttpResponseInfo response;
510 HttpRequestHeaders headers;
511 BoundNetLog net_log;
Ben Murdochca12bfa2013-07-23 11:17:05 +0100512 scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream(session_, true));
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +0100513 ASSERT_EQ(OK,
514 http_stream->InitializeStream(
515 &request, DEFAULT_PRIORITY, net_log, CompletionCallback()));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000516
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000517 EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response,
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000518 callback.callback()));
519
Ben Murdochca12bfa2013-07-23 11:17:05 +0100520 EXPECT_EQ(base_url, http_stream->stream()->GetUrlFromHeaders().spec());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000521
522 // This triggers the MockWrite and read 2
523 callback.WaitForResult();
524
525 // This triggers read 3. The empty read causes the session to shut down.
526 data()->CompleteRead();
527
528 // Because we abandoned the stream, we don't expect to find a session in the
529 // pool anymore.
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100530 EXPECT_FALSE(HasSpdySession(http_session_->spdy_session_pool(), key));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000531 EXPECT_TRUE(data()->at_read_eof());
532 EXPECT_TRUE(data()->at_write_eof());
533}
534
535namespace {
536
537void GetECServerBoundCertAndProof(
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100538 const std::string& host,
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000539 ServerBoundCertService* server_bound_cert_service,
540 std::string* cert,
541 std::string* proof) {
542 TestCompletionCallback callback;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000543 std::string key;
544 ServerBoundCertService::RequestHandle request_handle;
545 int rv = server_bound_cert_service->GetDomainBoundCert(
Ben Murdochbb1529c2013-08-08 10:24:53 +0100546 host, &key, cert, callback.callback(),
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000547 &request_handle);
548 EXPECT_EQ(ERR_IO_PENDING, rv);
549 EXPECT_EQ(OK, callback.WaitForResult());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000550
551 SpdyCredential credential;
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100552 EXPECT_EQ(OK,
553 SpdyCredentialBuilder::Build(
Ben Murdochbb1529c2013-08-08 10:24:53 +0100554 MockClientSocket::kTlsUnique, key, *cert, 2, &credential));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000555
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100556 ASSERT_FALSE(credential.certs.empty());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000557 cert->assign(credential.certs[0]);
558 proof->assign(credential.proof);
559}
560
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000561// Constructs a standard SPDY SYN_STREAM frame for a GET request with
562// a credential set.
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100563SpdyFrame* ConstructCredentialRequestFrame(NextProto next_proto,
564 size_t slot, const GURL& url,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000565 SpdyStreamId stream_id) {
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100566 SpdyTestUtil util(next_proto);
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +0100567
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000568 const SpdyHeaderInfo syn_headers = {
569 SYN_STREAM,
570 stream_id,
571 0,
572 ConvertRequestPriorityToSpdyPriority(LOWEST, 3),
573 slot,
574 CONTROL_FLAG_FIN,
575 false,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000576 RST_STREAM_INVALID,
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000577 NULL,
578 0,
579 DATA_FLAG_NONE
580 };
581
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100582 scoped_ptr<SpdyHeaderBlock> headers(util.ConstructGetHeaderBlock(url.spec()));
583 return util.ConstructSpdyFrame(syn_headers, headers.Pass());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000584}
585
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100586} // namespace
587
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000588// TODO(rch): When openssl supports server bound certifictes, this
589// guard can be removed
590#if !defined(USE_OPENSSL)
591// Test that if we request a resource for a new origin on a session that
592// used domain bound certificates, that we send a CREDENTIAL frame for
593// the new domain before we send the new request.
Ben Murdocheb525c52013-07-10 11:40:50 +0100594void SpdyHttpStreamTest::TestSendCredentials(
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000595 ServerBoundCertService* server_bound_cert_service,
596 const std::string& cert,
597 const std::string& proof) {
598 const char* kUrl1 = "https://www.google.com/";
599 const char* kUrl2 = "https://www.gmail.com/";
600
601 SpdyCredential cred;
602 cred.slot = 2;
603 cred.proof = proof;
604 cred.certs.push_back(cert);
605
606 scoped_ptr<SpdyFrame> req(ConstructCredentialRequestFrame(
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100607 GetParam(), 1, GURL(kUrl1), 1));
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100608 scoped_ptr<SpdyFrame> credential(
609 spdy_util_.ConstructSpdyCredential(cred));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000610 scoped_ptr<SpdyFrame> req2(ConstructCredentialRequestFrame(
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100611 GetParam(), 2, GURL(kUrl2), 3));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000612 MockWrite writes[] = {
613 CreateMockWrite(*req.get(), 0),
614 CreateMockWrite(*credential.get(), 2),
615 CreateMockWrite(*req2.get(), 3),
616 };
617
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100618 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
619 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000620 MockRead reads[] = {
621 CreateMockRead(*resp, 1),
622 CreateMockRead(*resp2, 4),
623 MockRead(SYNCHRONOUS, 0, 5) // EOF
624 };
625
626 HostPortPair host_port_pair(HostPortPair::FromURL(GURL(kUrl1)));
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100627 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
628 kPrivacyModeDisabled);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000629
630 DeterministicMockClientSocketFactory* socket_factory =
631 session_deps_.deterministic_socket_factory.get();
632 DeterministicSocketData data(reads, arraysize(reads),
633 writes, arraysize(writes));
634 socket_factory->AddSocketDataProvider(&data);
635 SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
636 ssl.channel_id_sent = true;
637 ssl.server_bound_cert_service = server_bound_cert_service;
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100638 ssl.protocol_negotiated = GetParam();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000639 socket_factory->AddSSLSocketDataProvider(&ssl);
640 http_session_ = SpdySessionDependencies::SpdyCreateSessionDeterministic(
641 &session_deps_);
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100642 session_ = CreateSecureSpdySession(http_session_, key, BoundNetLog());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000643
644 HttpRequestInfo request;
645 request.method = "GET";
646 request.url = GURL(kUrl1);
647 HttpResponseInfo response;
648 HttpRequestHeaders headers;
649 BoundNetLog net_log;
Ben Murdochca12bfa2013-07-23 11:17:05 +0100650 scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream(session_, true));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000651 ASSERT_EQ(
652 OK,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000653 http_stream->InitializeStream(&request, DEFAULT_PRIORITY,
654 net_log, CompletionCallback()));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000655
656 // EXPECT_FALSE(session_->NeedsCredentials(request.url));
657 // GURL new_origin(kUrl2);
658 // EXPECT_TRUE(session_->NeedsCredentials(new_origin));
659
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100660 TestCompletionCallback callback;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000661 EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response,
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000662 callback.callback()));
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100663 EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000664
665 data.RunFor(2);
666 callback.WaitForResult();
667
668 // Start up second request for resource on a new origin.
Ben Murdochca12bfa2013-07-23 11:17:05 +0100669 scoped_ptr<SpdyHttpStream> http_stream2(new SpdyHttpStream(session_, true));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000670 request.url = GURL(kUrl2);
671 ASSERT_EQ(
672 OK,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000673 http_stream2->InitializeStream(&request, DEFAULT_PRIORITY,
674 net_log, CompletionCallback()));
675 EXPECT_EQ(ERR_IO_PENDING, http_stream2->SendRequest(headers, &response,
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000676 callback.callback()));
677 data.RunFor(2);
678 callback.WaitForResult();
679
680 EXPECT_EQ(ERR_IO_PENDING, http_stream2->ReadResponseHeaders(
681 callback.callback()));
682 data.RunFor(1);
683 EXPECT_EQ(OK, callback.WaitForResult());
684 ASSERT_TRUE(response.headers.get() != NULL);
685 ASSERT_EQ(200, response.headers->response_code());
686}
687
Ben Murdocheb525c52013-07-10 11:40:50 +0100688// The tests below are only for SPDY/3 and above.
689
690// Test the receipt of a WINDOW_UPDATE frame while waiting for a chunk to be
691// made available is handled correctly.
692TEST_P(SpdyHttpStreamTest, DelayedSendChunkedPostWithWindowUpdate) {
693 if (GetParam() < kProtoSPDY3)
694 return;
695
696 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0));
697 scoped_ptr<SpdyFrame> chunk1(spdy_util_.ConstructSpdyBodyFrame(1, true));
698 MockWrite writes[] = {
699 CreateMockWrite(*req.get(), 0),
700 CreateMockWrite(*chunk1, 1),
701 };
702 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
703 scoped_ptr<SpdyFrame> window_update(
704 spdy_util_.ConstructSpdyWindowUpdate(1, kUploadDataSize));
705 MockRead reads[] = {
706 CreateMockRead(*window_update, 2),
707 CreateMockRead(*resp, 3),
708 CreateMockRead(*chunk1, 4),
709 MockRead(ASYNC, 0, 5) // EOF
710 };
711
712 HostPortPair host_port_pair("www.google.com", 80);
713 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
714 kPrivacyModeDisabled);
715
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100716 InitSessionDeterministic(reads, arraysize(reads),
717 writes, arraysize(writes),
718 key);
Ben Murdocheb525c52013-07-10 11:40:50 +0100719
720 UploadDataStream upload_stream(UploadDataStream::CHUNKED, 0);
721
722 HttpRequestInfo request;
723 request.method = "POST";
724 request.url = GURL("http://www.google.com/");
725 request.upload_data_stream = &upload_stream;
726
727 ASSERT_EQ(OK, upload_stream.Init(CompletionCallback()));
728 upload_stream.AppendChunk(kUploadData, kUploadDataSize, true);
729
730 BoundNetLog net_log;
Ben Murdochca12bfa2013-07-23 11:17:05 +0100731 scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream(session_, true));
Ben Murdocheb525c52013-07-10 11:40:50 +0100732 ASSERT_EQ(OK, http_stream->InitializeStream(&request, DEFAULT_PRIORITY,
733 net_log, CompletionCallback()));
734
735 HttpRequestHeaders headers;
736 HttpResponseInfo response;
737 // This will attempt to Write() the initial request and headers, which will
738 // complete asynchronously.
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100739 TestCompletionCallback callback;
Ben Murdocheb525c52013-07-10 11:40:50 +0100740 EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response,
741 callback.callback()));
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100742 EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key));
Ben Murdocheb525c52013-07-10 11:40:50 +0100743
744 // Complete the initial request write and first chunk.
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100745 deterministic_data_->RunFor(2);
Ben Murdocheb525c52013-07-10 11:40:50 +0100746 ASSERT_TRUE(callback.have_result());
747 EXPECT_EQ(OK, callback.WaitForResult());
748
749 // Verify that the window size has decreased.
750 ASSERT_TRUE(http_stream->stream() != NULL);
751 EXPECT_NE(static_cast<int>(kSpdyStreamInitialWindowSize),
752 http_stream->stream()->send_window_size());
753
754 // Read window update.
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100755 deterministic_data_->RunFor(1);
Ben Murdocheb525c52013-07-10 11:40:50 +0100756
757 // Verify the window update.
758 ASSERT_TRUE(http_stream->stream() != NULL);
759 EXPECT_EQ(static_cast<int>(kSpdyStreamInitialWindowSize),
760 http_stream->stream()->send_window_size());
761
762 // Read response headers.
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100763 deterministic_data_->RunFor(1);
Ben Murdocheb525c52013-07-10 11:40:50 +0100764 ASSERT_EQ(OK, http_stream->ReadResponseHeaders(callback.callback()));
765
766 // Read and check |chunk1| response.
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100767 deterministic_data_->RunFor(1);
Ben Murdocheb525c52013-07-10 11:40:50 +0100768 scoped_refptr<IOBuffer> buf1(new IOBuffer(kUploadDataSize));
769 ASSERT_EQ(kUploadDataSize,
770 http_stream->ReadResponseBody(
771 buf1.get(), kUploadDataSize, callback.callback()));
772 EXPECT_EQ(kUploadData, std::string(buf1->data(), kUploadDataSize));
773
774 // Finish reading the |EOF|.
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100775 deterministic_data_->RunFor(1);
Ben Murdocheb525c52013-07-10 11:40:50 +0100776 ASSERT_TRUE(response.headers.get());
777 ASSERT_EQ(200, response.headers->response_code());
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100778 EXPECT_TRUE(deterministic_data_->at_read_eof());
779 EXPECT_TRUE(deterministic_data_->at_write_eof());
Ben Murdocheb525c52013-07-10 11:40:50 +0100780}
781
782TEST_P(SpdyHttpStreamTest, SendCredentialsEC) {
783 if (GetParam() < kProtoSPDY3)
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100784 return;
785
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000786 scoped_refptr<base::SequencedWorkerPool> sequenced_worker_pool =
787 new base::SequencedWorkerPool(1, "SpdyHttpStreamSpdy3Test");
788 scoped_ptr<ServerBoundCertService> server_bound_cert_service(
789 new ServerBoundCertService(new DefaultServerBoundCertStore(NULL),
790 sequenced_worker_pool));
791 std::string cert;
792 std::string proof;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100793 GetECServerBoundCertAndProof("www.gmail.com",
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000794 server_bound_cert_service.get(),
795 &cert, &proof);
796
797 TestSendCredentials(server_bound_cert_service.get(), cert, proof);
798
799 sequenced_worker_pool->Shutdown();
800}
801
Ben Murdocheb525c52013-07-10 11:40:50 +0100802TEST_P(SpdyHttpStreamTest, DontSendCredentialsForHttpUrlsEC) {
803 if (GetParam() < kProtoSPDY3)
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100804 return;
805
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100806 scoped_refptr<base::SequencedWorkerPool> sequenced_worker_pool =
807 new base::SequencedWorkerPool(1, "SpdyHttpStreamSpdy3Test");
808 scoped_ptr<ServerBoundCertService> server_bound_cert_service(
809 new ServerBoundCertService(new DefaultServerBoundCertStore(NULL),
810 sequenced_worker_pool));
811 std::string cert;
812 std::string proof;
813 GetECServerBoundCertAndProof("proxy.google.com",
814 server_bound_cert_service.get(),
815 &cert, &proof);
816
817 const char* kUrl1 = "http://www.google.com/";
818 const char* kUrl2 = "http://www.gmail.com/";
819
820 SpdyCredential cred;
821 cred.slot = 2;
822 cred.proof = proof;
823 cred.certs.push_back(cert);
824
825 scoped_ptr<SpdyFrame> req(ConstructCredentialRequestFrame(
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100826 GetParam(), 0, GURL(kUrl1), 1));
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100827 scoped_ptr<SpdyFrame> req2(ConstructCredentialRequestFrame(
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100828 GetParam(), 0, GURL(kUrl2), 3));
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100829 MockWrite writes[] = {
830 CreateMockWrite(*req.get(), 0),
831 CreateMockWrite(*req2.get(), 2),
832 };
833
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100834 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
835 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100836 MockRead reads[] = {
837 CreateMockRead(*resp, 1),
838 CreateMockRead(*resp2, 3),
839 MockRead(ASYNC, 0, 4) // EOF
840 };
841
842 HostPortPair host_port_pair(HostPortPair::FromURL(GURL(kUrl1)));
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100843 SpdySessionKey key(host_port_pair,
844 ProxyServer::FromURI("proxy.google.com",
845 ProxyServer::SCHEME_HTTPS),
846 kPrivacyModeDisabled);
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100847 InitSessionDeterministic(reads, arraysize(reads),
848 writes, arraysize(writes),
849 key);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100850
851 HttpRequestInfo request;
852 request.method = "GET";
853 request.url = GURL(kUrl1);
854 HttpResponseInfo response;
855 HttpRequestHeaders headers;
856 BoundNetLog net_log;
Ben Murdochca12bfa2013-07-23 11:17:05 +0100857 scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream(session_, true));
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100858 ASSERT_EQ(
859 OK,
860 http_stream->InitializeStream(&request, DEFAULT_PRIORITY,
861 net_log, CompletionCallback()));
862
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100863 TestCompletionCallback callback;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100864 EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response,
865 callback.callback()));
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100866 EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key));
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100867
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100868 deterministic_data_->RunFor(2);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100869 EXPECT_EQ(OK, callback.WaitForResult());
870
871 // Start up second request for resource on a new origin.
Ben Murdochca12bfa2013-07-23 11:17:05 +0100872 scoped_ptr<SpdyHttpStream> http_stream2(new SpdyHttpStream(session_, true));
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100873 request.url = GURL(kUrl2);
874 ASSERT_EQ(
875 OK,
876 http_stream2->InitializeStream(&request, DEFAULT_PRIORITY,
877 net_log, CompletionCallback()));
878 EXPECT_EQ(ERR_IO_PENDING, http_stream2->SendRequest(headers, &response,
879 callback.callback()));
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100880 deterministic_data_->RunFor(1);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100881 EXPECT_EQ(OK, callback.WaitForResult());
882
883 EXPECT_EQ(ERR_IO_PENDING, http_stream2->ReadResponseHeaders(
884 callback.callback()));
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100885 deterministic_data_->RunFor(1);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100886 EXPECT_EQ(OK, callback.WaitForResult());
887 ASSERT_TRUE(response.headers.get() != NULL);
888 ASSERT_EQ(200, response.headers->response_code());
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100889 deterministic_data_->RunFor(1);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100890 sequenced_worker_pool->Shutdown();
891}
892
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000893#endif // !defined(USE_OPENSSL)
894
895// TODO(willchan): Write a longer test for SpdyStream that exercises all
896// methods.
897
898} // namespace net