Speech refactoring: Reimplemented SpeechRecognitionManagerImpl as a FSM. (CL1.7)
[chromium-blink-merge.git] / net / spdy / spdy_http_stream_spdy3_unittest.cc
blob460215ecd06f7927bec93371c415dea349d58e3e
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.
5 #include "net/spdy/spdy_http_stream.h"
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_server_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_http_utils.h"
15 #include "net/spdy/spdy_session.h"
16 #include "net/spdy/spdy_test_util_spdy3.h"
17 #include "testing/gtest/include/gtest/gtest.h"
19 using namespace net::test_spdy3;
21 namespace net {
23 class SpdyHttpStreamSpdy3Test : public testing::Test {
24 public:
25 OrderedSocketData* data() { return data_.get(); }
26 protected:
27 SpdyHttpStreamSpdy3Test() {}
29 virtual void SetUp() {
30 SpdySession::set_default_protocol(kProtoSPDY3);
33 virtual void TearDown() {
34 crypto::ECSignatureCreator::SetFactoryForTesting(NULL);
35 MessageLoop::current()->RunAllPending();
38 int InitSession(MockRead* reads, size_t reads_count,
39 MockWrite* writes, size_t writes_count,
40 HostPortPair& host_port_pair) {
41 HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
42 data_.reset(new OrderedSocketData(reads, reads_count,
43 writes, writes_count));
44 session_deps_.socket_factory->AddSocketDataProvider(data_.get());
45 http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
46 session_ = http_session_->spdy_session_pool()->Get(pair, BoundNetLog());
47 transport_params_ = new TransportSocketParams(host_port_pair,
48 MEDIUM, false, false);
49 TestCompletionCallback callback;
50 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
51 EXPECT_EQ(ERR_IO_PENDING,
52 connection->Init(host_port_pair.ToString(),
53 transport_params_,
54 MEDIUM,
55 callback.callback(),
56 http_session_->GetTransportSocketPool(
57 HttpNetworkSession::NORMAL_SOCKET_POOL),
58 BoundNetLog()));
59 EXPECT_EQ(OK, callback.WaitForResult());
60 return session_->InitializeWithSocket(connection.release(), false, OK);
63 void TestSendCredentials(
64 ServerBoundCertService* server_bound_cert_service,
65 const std::string& cert,
66 const std::string& proof,
67 SSLClientCertType type);
69 SpdySessionDependencies session_deps_;
70 scoped_ptr<OrderedSocketData> data_;
71 scoped_refptr<HttpNetworkSession> http_session_;
72 scoped_refptr<SpdySession> session_;
73 scoped_refptr<TransportSocketParams> transport_params_;
75 private:
76 SpdyTestStateHelper spdy_state_;
79 TEST_F(SpdyHttpStreamSpdy3Test, SendRequest) {
80 scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
81 MockWrite writes[] = {
82 CreateMockWrite(*req.get(), 1),
84 scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
85 MockRead reads[] = {
86 CreateMockRead(*resp, 2),
87 MockRead(SYNCHRONOUS, 0, 3) // EOF
90 HostPortPair host_port_pair("www.google.com", 80);
91 HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
92 EXPECT_EQ(OK, InitSession(reads, arraysize(reads), writes, arraysize(writes),
93 host_port_pair));
95 HttpRequestInfo request;
96 request.method = "GET";
97 request.url = GURL("http://www.google.com/");
98 TestCompletionCallback callback;
99 HttpResponseInfo response;
100 HttpRequestHeaders headers;
101 BoundNetLog net_log;
102 scoped_ptr<SpdyHttpStream> http_stream(
103 new SpdyHttpStream(session_.get(), true));
104 ASSERT_EQ(
106 http_stream->InitializeStream(&request, net_log, CompletionCallback()));
108 EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, NULL, &response,
109 callback.callback()));
110 EXPECT_TRUE(http_session_->spdy_session_pool()->HasSession(pair));
112 // This triggers the MockWrite and read 2
113 callback.WaitForResult();
115 // This triggers read 3. The empty read causes the session to shut down.
116 data()->CompleteRead();
118 // Because we abandoned the stream, we don't expect to find a session in the
119 // pool anymore.
120 EXPECT_FALSE(http_session_->spdy_session_pool()->HasSession(pair));
121 EXPECT_TRUE(data()->at_read_eof());
122 EXPECT_TRUE(data()->at_write_eof());
125 TEST_F(SpdyHttpStreamSpdy3Test, SendChunkedPost) {
126 UploadDataStream::set_merge_chunks(false);
128 scoped_ptr<SpdyFrame> req(ConstructChunkedSpdyPost(NULL, 0));
129 scoped_ptr<SpdyFrame> chunk1(ConstructSpdyBodyFrame(1, false));
130 scoped_ptr<SpdyFrame> chunk2(ConstructSpdyBodyFrame(1, true));
131 MockWrite writes[] = {
132 CreateMockWrite(*req.get(), 1),
133 CreateMockWrite(*chunk1, 2), // POST upload frames
134 CreateMockWrite(*chunk2, 3),
136 scoped_ptr<SpdyFrame> resp(ConstructSpdyPostSynReply(NULL, 0));
137 MockRead reads[] = {
138 CreateMockRead(*resp, 4),
139 CreateMockRead(*chunk1, 5),
140 CreateMockRead(*chunk2, 5),
141 MockRead(SYNCHRONOUS, 0, 6) // EOF
144 HostPortPair host_port_pair("www.google.com", 80);
145 HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
146 EXPECT_EQ(OK, InitSession(reads, arraysize(reads), writes, arraysize(writes),
147 host_port_pair));
149 HttpRequestInfo request;
150 request.method = "POST";
151 request.url = GURL("http://www.google.com/");
152 request.upload_data = new UploadData();
153 request.upload_data->set_is_chunked(true);
154 request.upload_data->AppendChunk(kUploadData, kUploadDataSize, false);
155 request.upload_data->AppendChunk(kUploadData, kUploadDataSize, true);
156 TestCompletionCallback callback;
157 HttpResponseInfo response;
158 HttpRequestHeaders headers;
159 BoundNetLog net_log;
160 SpdyHttpStream http_stream(session_.get(), true);
161 ASSERT_EQ(
163 http_stream.InitializeStream(&request, net_log, CompletionCallback()));
165 // http_stream.SendRequest() will take ownership of upload_stream.
166 UploadDataStream* upload_stream = new UploadDataStream(request.upload_data);
167 ASSERT_EQ(OK, upload_stream->Init());
168 EXPECT_EQ(ERR_IO_PENDING, http_stream.SendRequest(
169 headers, upload_stream, &response, callback.callback()));
170 EXPECT_TRUE(http_session_->spdy_session_pool()->HasSession(pair));
172 // This triggers the MockWrite and read 2
173 callback.WaitForResult();
175 // This triggers read 3. The empty read causes the session to shut down.
176 data()->CompleteRead();
177 MessageLoop::current()->RunAllPending();
179 // Because we abandoned the stream, we don't expect to find a session in the
180 // pool anymore.
181 EXPECT_FALSE(http_session_->spdy_session_pool()->HasSession(pair));
182 EXPECT_TRUE(data()->at_read_eof());
183 EXPECT_TRUE(data()->at_write_eof());
186 // Test case for bug: http://code.google.com/p/chromium/issues/detail?id=50058
187 TEST_F(SpdyHttpStreamSpdy3Test, SpdyURLTest) {
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<SpdyFrame> req(ConstructSpdyGet(base_url, false, 1, LOWEST));
191 MockWrite writes[] = {
192 CreateMockWrite(*req.get(), 1),
194 scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
195 MockRead reads[] = {
196 CreateMockRead(*resp, 2),
197 MockRead(SYNCHRONOUS, 0, 3) // EOF
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));
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(
215 http_stream->InitializeStream(&request, net_log, CompletionCallback()));
217 EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, NULL, &response,
218 callback.callback()));
220 SpdyHeaderBlock* spdy_header =
221 http_stream->stream()->spdy_headers().get();
222 EXPECT_TRUE(spdy_header != NULL);
223 if (spdy_header->find(":path") != spdy_header->end())
224 EXPECT_EQ("/foo?query=what", spdy_header->find(":path")->second);
225 else
226 FAIL() << "No url is set in spdy_header!";
228 // This triggers the MockWrite and read 2
229 callback.WaitForResult();
231 // This triggers read 3. The empty read causes the session to shut down.
232 data()->CompleteRead();
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());
241 namespace {
243 void GetECServerBoundCertAndProof(
244 const std::string& origin,
245 ServerBoundCertService* server_bound_cert_service,
246 std::string* cert,
247 std::string* proof) {
248 TestCompletionCallback callback;
249 std::vector<uint8> requested_cert_types;
250 requested_cert_types.push_back(CLIENT_CERT_ECDSA_SIGN);
251 SSLClientCertType cert_type;
252 std::string key;
253 ServerBoundCertService::RequestHandle request_handle;
254 int rv = server_bound_cert_service->GetDomainBoundCert(
255 origin, requested_cert_types, &cert_type, &key, cert, callback.callback(),
256 &request_handle);
257 EXPECT_EQ(ERR_IO_PENDING, rv);
258 EXPECT_EQ(OK, callback.WaitForResult());
259 EXPECT_EQ(CLIENT_CERT_ECDSA_SIGN, cert_type);
261 unsigned char secret[32];
262 memset(secret, 'A', arraysize(secret));
264 // Convert the key string into a vector<unit8>
265 std::vector<uint8> key_data(key.begin(), key.end());
267 base::StringPiece spki_piece;
268 ASSERT_TRUE(asn1::ExtractSPKIFromDERCert(*cert, &spki_piece));
269 std::vector<uint8> spki(spki_piece.data(),
270 spki_piece.data() + spki_piece.size());
272 std::vector<uint8> proof_data;
273 scoped_ptr<crypto::ECPrivateKey> private_key(
274 crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
275 ServerBoundCertService::kEPKIPassword, key_data, spki));
276 scoped_ptr<crypto::ECSignatureCreator> creator(
277 crypto::ECSignatureCreator::Create(private_key.get()));
278 creator->Sign(secret, arraysize(secret), &proof_data);
279 proof->assign(proof_data.begin(), proof_data.end());
282 } // namespace
284 // Constructs a standard SPDY SYN_STREAM frame for a GET request with
285 // a credential set.
286 SpdyFrame* ConstructCredentialRequestFrame(int slot, const GURL& url,
287 int stream_id) {
288 const SpdyHeaderInfo syn_headers = {
289 SYN_STREAM,
290 stream_id,
292 ConvertRequestPriorityToSpdyPriority(LOWEST, 3),
293 slot,
294 CONTROL_FLAG_FIN,
295 false,
296 INVALID,
297 NULL,
299 DATA_FLAG_NONE
302 // TODO(rch): this is ugly. Clean up.
303 std::string str_path = url.PathForRequest();
304 std::string str_scheme = url.scheme();
305 std::string str_host = url.host();
306 if (url.has_port()) {
307 str_host += ":";
308 str_host += url.port();
310 scoped_array<char> req(new char[str_path.size() + 1]);
311 scoped_array<char> scheme(new char[str_scheme.size() + 1]);
312 scoped_array<char> host(new char[str_host.size() + 1]);
313 memcpy(req.get(), str_path.c_str(), str_path.size());
314 memcpy(scheme.get(), str_scheme.c_str(), str_scheme.size());
315 memcpy(host.get(), str_host.c_str(), str_host.size());
316 req.get()[str_path.size()] = '\0';
317 scheme.get()[str_scheme.size()] = '\0';
318 host.get()[str_host.size()] = '\0';
320 const char* const headers[] = {
321 ":method",
322 "GET",
323 ":path",
324 req.get(),
325 ":host",
326 host.get(),
327 ":scheme",
328 scheme.get(),
329 ":version",
330 "HTTP/1.1"
332 return ConstructSpdyPacket(
333 syn_headers, NULL, 0, headers, arraysize(headers)/2);
336 // TODO(rch): When openssl supports server bound certifictes, this
337 // guard can be removed
338 #if !defined(USE_OPENSSL)
339 // Test that if we request a resource for a new origin on a session that
340 // used domain bound certificates, that we send a CREDENTIAL frame for
341 // the new domain before we send the new request.
342 void SpdyHttpStreamSpdy3Test::TestSendCredentials(
343 ServerBoundCertService* server_bound_cert_service,
344 const std::string& cert,
345 const std::string& proof,
346 SSLClientCertType type) {
347 const char* kUrl1 = "https://www.google.com/";
348 const char* kUrl2 = "https://www.gmail.com/";
350 SpdyCredential cred;
351 cred.slot = 2;
352 cred.proof = proof;
353 cred.certs.push_back(cert);
355 scoped_ptr<SpdyFrame> req(ConstructCredentialRequestFrame(
356 1, GURL(kUrl1), 1));
357 scoped_ptr<SpdyFrame> credential(ConstructSpdyCredential(cred));
358 scoped_ptr<SpdyFrame> req2(ConstructCredentialRequestFrame(
359 2, GURL(kUrl2), 3));
360 MockWrite writes[] = {
361 CreateMockWrite(*req.get(), 0),
362 CreateMockWrite(*credential.get(), 2),
363 CreateMockWrite(*req2.get(), 3),
366 scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
367 scoped_ptr<SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 3));
368 MockRead reads[] = {
369 CreateMockRead(*resp, 1),
370 CreateMockRead(*resp2, 4),
371 MockRead(SYNCHRONOUS, 0, 5) // EOF
374 HostPortPair host_port_pair(HostPortPair::FromURL(GURL(kUrl1)));
375 HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
377 DeterministicMockClientSocketFactory* socket_factory =
378 session_deps_.deterministic_socket_factory.get();
379 scoped_refptr<DeterministicSocketData> data(
380 new DeterministicSocketData(reads, arraysize(reads),
381 writes, arraysize(writes)));
382 socket_factory->AddSocketDataProvider(data.get());
383 SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
384 ssl.domain_bound_cert_type = type;
385 ssl.server_bound_cert_service = server_bound_cert_service;
386 ssl.protocol_negotiated = kProtoSPDY3;
387 socket_factory->AddSSLSocketDataProvider(&ssl);
388 http_session_ = SpdySessionDependencies::SpdyCreateSessionDeterministic(
389 &session_deps_);
390 session_ = http_session_->spdy_session_pool()->Get(pair, BoundNetLog());
391 transport_params_ = new TransportSocketParams(host_port_pair,
392 MEDIUM, false, false);
393 TestCompletionCallback callback;
394 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
395 SSLConfig ssl_config;
396 scoped_refptr<SOCKSSocketParams> socks_params;
397 scoped_refptr<HttpProxySocketParams> http_proxy_params;
398 scoped_refptr<SSLSocketParams> ssl_params(
399 new SSLSocketParams(transport_params_,
400 socks_params,
401 http_proxy_params,
402 ProxyServer::SCHEME_DIRECT,
403 host_port_pair,
404 ssl_config,
406 false,
407 false));
408 EXPECT_EQ(ERR_IO_PENDING,
409 connection->Init(host_port_pair.ToString(),
410 ssl_params,
411 MEDIUM,
412 callback.callback(),
413 http_session_->GetSSLSocketPool(
414 HttpNetworkSession::NORMAL_SOCKET_POOL),
415 BoundNetLog()));
416 callback.WaitForResult();
417 EXPECT_EQ(OK,
418 session_->InitializeWithSocket(connection.release(), true, OK));
420 HttpRequestInfo request;
421 request.method = "GET";
422 request.url = GURL(kUrl1);
423 HttpResponseInfo response;
424 HttpRequestHeaders headers;
425 BoundNetLog net_log;
426 scoped_ptr<SpdyHttpStream> http_stream(
427 new SpdyHttpStream(session_.get(), true));
428 ASSERT_EQ(
430 http_stream->InitializeStream(&request, net_log, CompletionCallback()));
432 // EXPECT_FALSE(session_->NeedsCredentials(request.url));
433 // GURL new_origin(kUrl2);
434 // EXPECT_TRUE(session_->NeedsCredentials(new_origin));
436 EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, NULL, &response,
437 callback.callback()));
438 EXPECT_TRUE(http_session_->spdy_session_pool()->HasSession(pair));
440 data->RunFor(2);
441 callback.WaitForResult();
443 // Start up second request for resource on a new origin.
444 scoped_ptr<SpdyHttpStream> http_stream2(
445 new SpdyHttpStream(session_.get(), true));
446 request.url = GURL(kUrl2);
447 ASSERT_EQ(
449 http_stream2->InitializeStream(&request, net_log, CompletionCallback()));
450 EXPECT_EQ(ERR_IO_PENDING, http_stream2->SendRequest(headers, NULL, &response,
451 callback.callback()));
452 data->RunFor(2);
453 callback.WaitForResult();
455 EXPECT_EQ(ERR_IO_PENDING, http_stream2->ReadResponseHeaders(
456 callback.callback()));
457 data->RunFor(1);
458 EXPECT_EQ(OK, callback.WaitForResult());
459 ASSERT_TRUE(response.headers.get() != NULL);
460 ASSERT_EQ(200, response.headers->response_code());
463 class MockECSignatureCreator : public crypto::ECSignatureCreator {
464 public:
465 explicit MockECSignatureCreator(crypto::ECPrivateKey* key) : key_(key) {}
467 virtual bool Sign(const uint8* data,
468 int data_len,
469 std::vector<uint8>* signature) OVERRIDE {
470 std::vector<uint8> private_key_value;
471 key_->ExportValue(&private_key_value);
472 std::string head = "fakesignature";
473 std::string tail = "/fakesignature";
475 signature->clear();
476 signature->insert(signature->end(), head.begin(), head.end());
477 signature->insert(signature->end(), private_key_value.begin(),
478 private_key_value.end());
479 signature->insert(signature->end(), '-');
480 signature->insert(signature->end(), data, data + data_len);
481 signature->insert(signature->end(), tail.begin(), tail.end());
482 return true;
485 private:
486 crypto::ECPrivateKey* key_;
487 DISALLOW_COPY_AND_ASSIGN(MockECSignatureCreator);
490 class MockECSignatureCreatorFactory : public crypto::ECSignatureCreatorFactory {
491 public:
492 MockECSignatureCreatorFactory() {}
493 virtual ~MockECSignatureCreatorFactory() {}
495 virtual crypto::ECSignatureCreator* Create(
496 crypto::ECPrivateKey* key) OVERRIDE {
497 return new MockECSignatureCreator(key);
499 private:
500 DISALLOW_COPY_AND_ASSIGN(MockECSignatureCreatorFactory);
503 TEST_F(SpdyHttpStreamSpdy3Test, SendCredentialsEC) {
504 scoped_ptr<crypto::ECSignatureCreatorFactory> ec_signature_creator_factory(
505 new MockECSignatureCreatorFactory());
506 crypto::ECSignatureCreator::SetFactoryForTesting(
507 ec_signature_creator_factory.get());
509 scoped_ptr<ServerBoundCertService> server_bound_cert_service(
510 new ServerBoundCertService(new DefaultServerBoundCertStore(NULL)));
511 std::string cert;
512 std::string proof;
513 GetECServerBoundCertAndProof("http://www.gmail.com/",
514 server_bound_cert_service.get(),
515 &cert, &proof);
517 TestSendCredentials(server_bound_cert_service.get(), cert, proof,
518 CLIENT_CERT_ECDSA_SIGN);
521 #endif // !defined(USE_OPENSSL)
523 // TODO(willchan): Write a longer test for SpdyStream that exercises all
524 // methods.
526 } // namespace net