Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(97)

Side by Side Diff: net/spdy/spdy_http_stream_unittest.cc

Issue 9582034: Fork SPDY/2 and SPDY/3 versions of our SPDY tests, in preparation for landing (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Fix merge bug Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // 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
7 #include "crypto/ec_private_key.h"
8 #include "crypto/ec_signature_creator.h"
9 #include "crypto/signature_creator.h"
10 #include "net/base/asn1_util.h"
11 #include "net/base/default_origin_bound_cert_store.h"
12 #include "net/http/http_response_headers.h"
13 #include "net/http/http_response_info.h"
14 #include "net/spdy/spdy_session.h"
15 #include "net/spdy/spdy_test_util.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17
18 namespace net {
19
20 class SpdyHttpStreamTest : public testing::Test {
21 public:
22 OrderedSocketData* data() { return data_.get(); }
23 protected:
24 SpdyHttpStreamTest() {}
25
26 void EnableCompression(bool enabled) {
27 spdy::SpdyFramer::set_enable_compression_default(enabled);
28 }
29
30 virtual void TearDown() {
31 crypto::ECSignatureCreator::SetFactoryForTesting(NULL);
32 MessageLoop::current()->RunAllPending();
33 }
34 int InitSession(MockRead* reads, size_t reads_count,
35 MockWrite* writes, size_t writes_count,
36 HostPortPair& host_port_pair) {
37 HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
38 data_.reset(new OrderedSocketData(reads, reads_count,
39 writes, writes_count));
40 session_deps_.socket_factory->AddSocketDataProvider(data_.get());
41 http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
42 session_ = http_session_->spdy_session_pool()->Get(pair, BoundNetLog());
43 transport_params_ = new TransportSocketParams(host_port_pair,
44 MEDIUM, false, false);
45 TestCompletionCallback callback;
46 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
47 EXPECT_EQ(ERR_IO_PENDING,
48 connection->Init(host_port_pair.ToString(),
49 transport_params_,
50 MEDIUM,
51 callback.callback(),
52 http_session_->GetTransportSocketPool(),
53 BoundNetLog()));
54 EXPECT_EQ(OK, callback.WaitForResult());
55 return session_->InitializeWithSocket(connection.release(), false, OK);
56 }
57
58 void TestSendCredentials(
59 OriginBoundCertService* obc_service,
60 const std::string& cert,
61 const std::string& proof,
62 SSLClientCertType type);
63
64 SpdySessionDependencies session_deps_;
65 scoped_ptr<OrderedSocketData> data_;
66 scoped_refptr<HttpNetworkSession> http_session_;
67 scoped_refptr<SpdySession> session_;
68 scoped_refptr<TransportSocketParams> transport_params_;
69 };
70
71 TEST_F(SpdyHttpStreamTest, SendRequest) {
72 EnableCompression(false);
73 SpdySession::SetSSLMode(false);
74
75 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
76 MockWrite writes[] = {
77 CreateMockWrite(*req.get(), 1),
78 };
79 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
80 MockRead reads[] = {
81 CreateMockRead(*resp, 2),
82 MockRead(SYNCHRONOUS, 0, 3) // EOF
83 };
84
85 HostPortPair host_port_pair("www.google.com", 80);
86 HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
87 EXPECT_EQ(OK, InitSession(reads, arraysize(reads), writes, arraysize(writes),
88 host_port_pair));
89
90 HttpRequestInfo request;
91 request.method = "GET";
92 request.url = GURL("http://www.google.com/");
93 TestCompletionCallback callback;
94 HttpResponseInfo response;
95 HttpRequestHeaders headers;
96 BoundNetLog net_log;
97 scoped_ptr<SpdyHttpStream> http_stream(
98 new SpdyHttpStream(session_.get(), true));
99 ASSERT_EQ(
100 OK,
101 http_stream->InitializeStream(&request, net_log, CompletionCallback()));
102
103 EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, NULL, &response,
104 callback.callback()));
105 EXPECT_TRUE(http_session_->spdy_session_pool()->HasSession(pair));
106
107 // This triggers the MockWrite and read 2
108 callback.WaitForResult();
109
110 // This triggers read 3. The empty read causes the session to shut down.
111 data()->CompleteRead();
112
113 // Because we abandoned the stream, we don't expect to find a session in the
114 // pool anymore.
115 EXPECT_FALSE(http_session_->spdy_session_pool()->HasSession(pair));
116 EXPECT_TRUE(data()->at_read_eof());
117 EXPECT_TRUE(data()->at_write_eof());
118 }
119
120 TEST_F(SpdyHttpStreamTest, SendChunkedPost) {
121 EnableCompression(false);
122 SpdySession::SetSSLMode(false);
123 UploadDataStream::set_merge_chunks(false);
124
125 scoped_ptr<spdy::SpdyFrame> req(ConstructChunkedSpdyPost(NULL, 0));
126 scoped_ptr<spdy::SpdyFrame> chunk1(ConstructSpdyBodyFrame(1, false));
127 scoped_ptr<spdy::SpdyFrame> chunk2(ConstructSpdyBodyFrame(1, true));
128 MockWrite writes[] = {
129 CreateMockWrite(*req.get(), 1),
130 CreateMockWrite(*chunk1, 2), // POST upload frames
131 CreateMockWrite(*chunk2, 3),
132 };
133 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyPostSynReply(NULL, 0));
134 MockRead reads[] = {
135 CreateMockRead(*resp, 4),
136 CreateMockRead(*chunk1, 5),
137 CreateMockRead(*chunk2, 5),
138 MockRead(SYNCHRONOUS, 0, 6) // EOF
139 };
140
141 HostPortPair host_port_pair("www.google.com", 80);
142 HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
143 EXPECT_EQ(OK, InitSession(reads, arraysize(reads), writes, arraysize(writes),
144 host_port_pair));
145
146 HttpRequestInfo request;
147 request.method = "POST";
148 request.url = GURL("http://www.google.com/");
149 request.upload_data = new UploadData();
150 request.upload_data->set_is_chunked(true);
151 request.upload_data->AppendChunk(kUploadData, kUploadDataSize, false);
152 request.upload_data->AppendChunk(kUploadData, kUploadDataSize, true);
153 TestCompletionCallback callback;
154 HttpResponseInfo response;
155 HttpRequestHeaders headers;
156 BoundNetLog net_log;
157 SpdyHttpStream http_stream(session_.get(), true);
158 ASSERT_EQ(
159 OK,
160 http_stream.InitializeStream(&request, net_log, CompletionCallback()));
161
162 // http_stream.SendRequest() will take ownership of upload_stream.
163 UploadDataStream* upload_stream = new UploadDataStream(request.upload_data);
164 ASSERT_EQ(OK, upload_stream->Init());
165 EXPECT_EQ(ERR_IO_PENDING, http_stream.SendRequest(
166 headers, upload_stream, &response, callback.callback()));
167 EXPECT_TRUE(http_session_->spdy_session_pool()->HasSession(pair));
168
169 // This triggers the MockWrite and read 2
170 callback.WaitForResult();
171
172 // This triggers read 3. The empty read causes the session to shut down.
173 data()->CompleteRead();
174 MessageLoop::current()->RunAllPending();
175
176 // Because we abandoned the stream, we don't expect to find a session in the
177 // pool anymore.
178 EXPECT_FALSE(http_session_->spdy_session_pool()->HasSession(pair));
179 EXPECT_TRUE(data()->at_read_eof());
180 EXPECT_TRUE(data()->at_write_eof());
181 }
182
183 // Test case for bug: http://code.google.com/p/chromium/issues/detail?id=50058
184 TEST_F(SpdyHttpStreamTest, SpdyURLTest) {
185 EnableCompression(false);
186 SpdySession::SetSSLMode(false);
187
188 const char * const full_url = "http://www.google.com/foo?query=what#anchor";
189 const char * const base_url = "http://www.google.com/foo?query=what";
190 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(base_url, false, 1, LOWEST));
191 MockWrite writes[] = {
192 CreateMockWrite(*req.get(), 1),
193 };
194 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
195 MockRead reads[] = {
196 CreateMockRead(*resp, 2),
197 MockRead(SYNCHRONOUS, 0, 3) // EOF
198 };
199
200 HostPortPair host_port_pair("www.google.com", 80);
201 HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
202 EXPECT_EQ(OK, InitSession(reads, arraysize(reads), writes, arraysize(writes),
203 host_port_pair));
204
205 HttpRequestInfo request;
206 request.method = "GET";
207 request.url = GURL(full_url);
208 TestCompletionCallback callback;
209 HttpResponseInfo response;
210 HttpRequestHeaders headers;
211 BoundNetLog net_log;
212 scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream(session_, true));
213 ASSERT_EQ(
214 OK,
215 http_stream->InitializeStream(&request, net_log, CompletionCallback()));
216
217 EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, NULL, &response,
218 callback.callback()));
219
220 spdy::SpdyHeaderBlock* spdy_header =
221 http_stream->stream()->spdy_headers().get();
222 EXPECT_TRUE(spdy_header != NULL);
223 if (spdy_header->find("url") != spdy_header->end())
224 EXPECT_EQ("/foo?query=what", spdy_header->find("url")->second);
225 else
226 FAIL() << "No url is set in spdy_header!";
227
228 // This triggers the MockWrite and read 2
229 callback.WaitForResult();
230
231 // This triggers read 3. The empty read causes the session to shut down.
232 data()->CompleteRead();
233
234 // Because we abandoned the stream, we don't expect to find a session in the
235 // pool anymore.
236 EXPECT_FALSE(http_session_->spdy_session_pool()->HasSession(pair));
237 EXPECT_TRUE(data()->at_read_eof());
238 EXPECT_TRUE(data()->at_write_eof());
239 }
240
241 void GetECOriginBoundCertAndProof(const std::string& origin,
242 OriginBoundCertService* obc_service,
243 std::string* cert,
244 std::string* proof) {
245 TestCompletionCallback callback;
246 std::vector<uint8> requested_cert_types;
247 requested_cert_types.push_back(CLIENT_CERT_ECDSA_SIGN);
248 SSLClientCertType cert_type;
249 std::string key;
250 OriginBoundCertService::RequestHandle request_handle;
251 int rv = obc_service->GetOriginBoundCert(origin, requested_cert_types,
252 &cert_type, &key, cert,
253 callback.callback(),
254 &request_handle);
255 EXPECT_EQ(ERR_IO_PENDING, rv);
256 EXPECT_EQ(OK, callback.WaitForResult());
257 EXPECT_EQ(CLIENT_CERT_ECDSA_SIGN, cert_type);
258
259 unsigned char secret[32];
260 memset(secret, 'A', arraysize(secret));
261
262 // Convert the key string into a vector<unit8>
263 std::vector<uint8> key_data(key.begin(), key.end());
264
265 base::StringPiece spki_piece;
266 ASSERT_TRUE(asn1::ExtractSPKIFromDERCert(*cert, &spki_piece));
267 std::vector<uint8> spki(spki_piece.data(),
268 spki_piece.data() + spki_piece.size());
269
270 std::vector<uint8> proof_data;
271 scoped_ptr<crypto::ECPrivateKey> private_key(
272 crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
273 OriginBoundCertService::kEPKIPassword, key_data, spki));
274 scoped_ptr<crypto::ECSignatureCreator> creator(
275 crypto::ECSignatureCreator::Create(private_key.get()));
276 creator->Sign(secret, arraysize(secret), &proof_data);
277 proof->assign(proof_data.begin(), proof_data.end());
278 }
279
280 // TODO(rch): When openssl supports origin bound certifictes, this
281 // guard can be removed
282 #if !defined(USE_OPENSSL)
283 // Test that if we request a resource for a new origin on a session that
284 // used origin bound certificates, that we send a CREDENTIAL frame for
285 // the new origin before we send the new request.
286 void SpdyHttpStreamTest::TestSendCredentials(
287 OriginBoundCertService* obc_service,
288 const std::string& cert,
289 const std::string& proof,
290 SSLClientCertType type) {
291 EnableCompression(false);
292
293 spdy::SpdyCredential cred;
294 cred.slot = 1;
295 cred.proof = proof;
296 cred.certs.push_back(cert);
297
298 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
299 scoped_ptr<spdy::SpdyFrame> credential(ConstructSpdyCredential(cred));
300 scoped_ptr<spdy::SpdyFrame> req2(ConstructSpdyGet("http://www.gmail.com",
301 false, 3, LOWEST));
302 MockWrite writes[] = {
303 CreateMockWrite(*req.get(), 0),
304 CreateMockWrite(*credential.get(), 2),
305 CreateMockWrite(*req2.get(), 3),
306 };
307
308 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
309 scoped_ptr<spdy::SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 3));
310 MockRead reads[] = {
311 CreateMockRead(*resp, 1),
312 CreateMockRead(*resp2, 4),
313 MockRead(SYNCHRONOUS, 0, 5) // EOF
314 };
315
316 HostPortPair host_port_pair("www.google.com", 80);
317 HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
318
319 DeterministicMockClientSocketFactory* socket_factory =
320 session_deps_.deterministic_socket_factory.get();
321 scoped_refptr<DeterministicSocketData> data(
322 new DeterministicSocketData(reads, arraysize(reads),
323 writes, arraysize(writes)));
324 socket_factory->AddSocketDataProvider(data.get());
325 SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
326 ssl.origin_bound_cert_type = type;
327 ssl.origin_bound_cert_service = obc_service;
328 ssl.protocol_negotiated = SSLClientSocket::kProtoSPDY3;
329 socket_factory->AddSSLSocketDataProvider(&ssl);
330 http_session_ = SpdySessionDependencies::SpdyCreateSessionDeterministic(
331 &session_deps_);
332 session_ = http_session_->spdy_session_pool()->Get(pair, BoundNetLog());
333 transport_params_ = new TransportSocketParams(host_port_pair,
334 MEDIUM, false, false);
335 TestCompletionCallback callback;
336 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
337 SSLConfig ssl_config;
338 scoped_refptr<SOCKSSocketParams> socks_params;
339 scoped_refptr<HttpProxySocketParams> http_proxy_params;
340 scoped_refptr<SSLSocketParams> ssl_params(
341 new SSLSocketParams(transport_params_,
342 socks_params,
343 http_proxy_params,
344 ProxyServer::SCHEME_DIRECT,
345 host_port_pair,
346 ssl_config,
347 0,
348 false,
349 false));
350 EXPECT_EQ(ERR_IO_PENDING,
351 connection->Init(host_port_pair.ToString(),
352 ssl_params,
353 MEDIUM,
354 callback.callback(),
355 http_session_->GetSSLSocketPool(),
356 BoundNetLog()));
357 callback.WaitForResult();
358 EXPECT_EQ(OK,
359 session_->InitializeWithSocket(connection.release(), true, OK));
360
361 HttpRequestInfo request;
362 request.method = "GET";
363 request.url = GURL("http://www.google.com/");
364 HttpResponseInfo response;
365 HttpRequestHeaders headers;
366 BoundNetLog net_log;
367 scoped_ptr<SpdyHttpStream> http_stream(
368 new SpdyHttpStream(session_.get(), true));
369 ASSERT_EQ(
370 OK,
371 http_stream->InitializeStream(&request, net_log, CompletionCallback()));
372
373 EXPECT_FALSE(session_->NeedsCredentials(host_port_pair));
374 HostPortPair new_host_port_pair("www.gmail.com", 80);
375 EXPECT_TRUE(session_->NeedsCredentials(new_host_port_pair));
376
377 EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, NULL, &response,
378 callback.callback()));
379 EXPECT_TRUE(http_session_->spdy_session_pool()->HasSession(pair));
380
381 data->RunFor(2);
382 callback.WaitForResult();
383
384 // Start up second request for resource on a new origin.
385 scoped_ptr<SpdyHttpStream> http_stream2(
386 new SpdyHttpStream(session_.get(), true));
387 request.url = GURL("http://www.gmail.com/");
388 ASSERT_EQ(
389 OK,
390 http_stream2->InitializeStream(&request, net_log, CompletionCallback()));
391 EXPECT_EQ(ERR_IO_PENDING, http_stream2->SendRequest(headers, NULL, &response,
392 callback.callback()));
393 data->RunFor(2);
394 callback.WaitForResult();
395
396 EXPECT_EQ(ERR_IO_PENDING, http_stream2->ReadResponseHeaders(
397 callback.callback()));
398 data->RunFor(1);
399 EXPECT_EQ(OK, callback.WaitForResult());
400 ASSERT_TRUE(response.headers.get() != NULL);
401 ASSERT_EQ(200, response.headers->response_code());
402 }
403
404 class MockECSignatureCreator : public crypto::ECSignatureCreator {
405 public:
406 explicit MockECSignatureCreator(crypto::ECPrivateKey* key) : key_(key) {}
407
408 virtual bool Sign(const uint8* data,
409 int data_len,
410 std::vector<uint8>* signature) OVERRIDE {
411 std::vector<uint8> private_key_value;
412 key_->ExportValue(&private_key_value);
413 std::string head = "fakesignature";
414 std::string tail = "/fakesignature";
415
416 signature->clear();
417 signature->insert(signature->end(), head.begin(), head.end());
418 signature->insert(signature->end(), private_key_value.begin(),
419 private_key_value.end());
420 signature->insert(signature->end(), '-');
421 signature->insert(signature->end(), data, data + data_len);
422 signature->insert(signature->end(), tail.begin(), tail.end());
423 return true;
424 }
425
426 private:
427 crypto::ECPrivateKey* key_;
428 DISALLOW_COPY_AND_ASSIGN(MockECSignatureCreator);
429 };
430
431 class MockECSignatureCreatorFactory : public crypto::ECSignatureCreatorFactory {
432 public:
433 MockECSignatureCreatorFactory() {}
434 virtual ~MockECSignatureCreatorFactory() {}
435
436 virtual crypto::ECSignatureCreator* Create(
437 crypto::ECPrivateKey* key) OVERRIDE {
438 return new MockECSignatureCreator(key);
439 }
440 private:
441 DISALLOW_COPY_AND_ASSIGN(MockECSignatureCreatorFactory);
442 };
443
444 TEST_F(SpdyHttpStreamTest, SendCredentialsEC) {
445 scoped_ptr<crypto::ECSignatureCreatorFactory> ec_signature_creator_factory(
446 new MockECSignatureCreatorFactory());
447 crypto::ECSignatureCreator::SetFactoryForTesting(
448 ec_signature_creator_factory.get());
449
450 scoped_ptr<OriginBoundCertService> obc_service(
451 new OriginBoundCertService(new DefaultOriginBoundCertStore(NULL)));
452 std::string cert;
453 std::string proof;
454 GetECOriginBoundCertAndProof("http://www.gmail.com/", obc_service.get(),
455 &cert, &proof);
456
457 TestSendCredentials(obc_service.get(), cert, proof, CLIENT_CERT_ECDSA_SIGN);
458 }
459
460 #endif // !defined(USE_OPENSSL)
461
462 // TODO(willchan): Write a longer test for SpdyStream that exercises all
463 // methods.
464
465 } // namespace net
OLDNEW
« no previous file with comments | « net/spdy/spdy_http_stream_spdy3_unittest.cc ('k') | net/spdy/spdy_network_transaction_spdy21_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698