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

Side by Side Diff: net/quic/quic_network_transaction_unittest.cc

Issue 1305293004: Notfiy NQE of QUIC RTT (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed rch comments, now using quic connection logger Created 5 years, 3 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
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <vector> 5 #include <vector>
6 6
7 #include "base/basictypes.h" 7 #include "base/basictypes.h"
8 #include "base/compiler_specific.h" 8 #include "base/compiler_specific.h"
9 #include "base/memory/scoped_ptr.h" 9 #include "base/memory/scoped_ptr.h"
10 #include "base/stl_util.h" 10 #include "base/stl_util.h"
11 #include "net/base/socket_performance_watcher.h"
12 #include "net/base/socket_performance_watcher_factory.h"
11 #include "net/base/test_completion_callback.h" 13 #include "net/base/test_completion_callback.h"
12 #include "net/base/test_data_directory.h" 14 #include "net/base/test_data_directory.h"
13 #include "net/cert/mock_cert_verifier.h" 15 #include "net/cert/mock_cert_verifier.h"
14 #include "net/dns/mock_host_resolver.h" 16 #include "net/dns/mock_host_resolver.h"
15 #include "net/http/http_auth_handler_factory.h" 17 #include "net/http/http_auth_handler_factory.h"
16 #include "net/http/http_network_session.h" 18 #include "net/http/http_network_session.h"
17 #include "net/http/http_network_transaction.h" 19 #include "net/http/http_network_transaction.h"
18 #include "net/http/http_server_properties_impl.h" 20 #include "net/http/http_server_properties_impl.h"
19 #include "net/http/http_stream.h" 21 #include "net/http/http_stream.h"
20 #include "net/http/http_stream_factory.h" 22 #include "net/http/http_stream_factory.h"
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
132 134
133 void OnBeforeProxyHeadersSent(const ProxyInfo& proxy_info, 135 void OnBeforeProxyHeadersSent(const ProxyInfo& proxy_info,
134 HttpRequestHeaders* request_headers) { 136 HttpRequestHeaders* request_headers) {
135 was_called_ = true; 137 was_called_ = true;
136 } 138 }
137 139
138 private: 140 private:
139 bool was_called_; 141 bool was_called_;
140 }; 142 };
141 143
144 // Verifies whether the socket performance watcher was notified of updated RTT.
145 class WatcherNotificationVerifier {
146 public:
147 WatcherNotificationVerifier()
148 : received_updated_rtt_available_notification_(false) {}
149
150 virtual ~WatcherNotificationVerifier() {}
151
152 void OnUpdatedRTTAvailable() {
153 received_updated_rtt_available_notification_ = true;
154 }
155
156 bool IsRTTAvailableRTTNotificationReceived() const {
157 return received_updated_rtt_available_notification_;
158 }
159
160 private:
161 bool received_updated_rtt_available_notification_;
162 DISALLOW_COPY_AND_ASSIGN(WatcherNotificationVerifier);
163 };
164
165 class TestSocketPerformanceWatcher : public SocketPerformanceWatcher {
166 public:
167 TestSocketPerformanceWatcher(WatcherNotificationVerifier* watcher_checker)
168 : watcher_notification_verifier_(watcher_checker) {}
169
170 ~TestSocketPerformanceWatcher() override {}
171
172 void OnUpdatedRTTAvailable(const base::TimeDelta& rtt) override {
173 watcher_notification_verifier_->OnUpdatedRTTAvailable();
174 }
175
176 private:
177 WatcherNotificationVerifier* watcher_notification_verifier_;
178 DISALLOW_COPY_AND_ASSIGN(TestSocketPerformanceWatcher);
179 };
180
181 class TestSocketPerformanceWatcherFactory
182 : public SocketPerformanceWatcherFactory {
183 public:
184 TestSocketPerformanceWatcherFactory()
185 : watcher_notification_verifier_(new WatcherNotificationVerifier()) {}
186
187 ~TestSocketPerformanceWatcherFactory() override {}
188
189 scoped_ptr<SocketPerformanceWatcher> CreateUDPSocketPerformanceWatcher()
190 const override {
191 return scoped_ptr<TestSocketPerformanceWatcher>(
192 new TestSocketPerformanceWatcher(watcher_notification_verifier_.get()));
193 }
194
195 scoped_ptr<SocketPerformanceWatcher> CreateTCPSocketPerformanceWatcher()
196 const override {
197 return scoped_ptr<SocketPerformanceWatcher>(
198 new TestSocketPerformanceWatcher(nullptr));
199 }
200
201 bool IsRTTAvailableRTTNotificationReceived() const {
202 return watcher_notification_verifier_
203 ->IsRTTAvailableRTTNotificationReceived();
204 }
205
206 private:
207 scoped_ptr<WatcherNotificationVerifier> watcher_notification_verifier_;
208 DISALLOW_COPY_AND_ASSIGN(TestSocketPerformanceWatcherFactory);
209 };
210
142 class QuicNetworkTransactionTest 211 class QuicNetworkTransactionTest
143 : public PlatformTest, 212 : public PlatformTest,
144 public ::testing::WithParamInterface<QuicVersion> { 213 public ::testing::WithParamInterface<QuicVersion> {
145 protected: 214 protected:
146 QuicNetworkTransactionTest() 215 QuicNetworkTransactionTest()
147 : clock_(new MockClock), 216 : clock_(new MockClock),
148 maker_(GetParam(), 0, clock_, kDefaultServerHostName), 217 maker_(GetParam(), 0, clock_, kDefaultServerHostName),
218 socket_performance_watcher_factory_(
219 new TestSocketPerformanceWatcherFactory()),
149 ssl_config_service_(new SSLConfigServiceDefaults), 220 ssl_config_service_(new SSLConfigServiceDefaults),
150 proxy_service_(ProxyService::CreateDirect()), 221 proxy_service_(ProxyService::CreateDirect()),
151 auth_handler_factory_( 222 auth_handler_factory_(
152 HttpAuthHandlerFactory::CreateDefault(&host_resolver_)), 223 HttpAuthHandlerFactory::CreateDefault(&host_resolver_)),
153 random_generator_(0), 224 random_generator_(0),
154 hanging_data_(nullptr, 0, nullptr, 0) { 225 hanging_data_(nullptr, 0, nullptr, 0) {
155 request_.method = "GET"; 226 request_.method = "GET";
156 std::string url("http://"); 227 std::string url("http://");
157 url.append(kDefaultServerHostName); 228 url.append(kDefaultServerHostName);
158 request_.url = GURL(url); 229 request_.url = GURL(url);
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
241 void CreateSessionWithFactory(ClientSocketFactory* socket_factory, 312 void CreateSessionWithFactory(ClientSocketFactory* socket_factory,
242 bool use_next_protos) { 313 bool use_next_protos) {
243 params_.enable_quic = true; 314 params_.enable_quic = true;
244 params_.quic_clock = clock_; 315 params_.quic_clock = clock_;
245 params_.quic_random = &random_generator_; 316 params_.quic_random = &random_generator_;
246 params_.client_socket_factory = socket_factory; 317 params_.client_socket_factory = socket_factory;
247 params_.quic_crypto_client_stream_factory = &crypto_client_stream_factory_; 318 params_.quic_crypto_client_stream_factory = &crypto_client_stream_factory_;
248 params_.host_resolver = &host_resolver_; 319 params_.host_resolver = &host_resolver_;
249 params_.cert_verifier = &cert_verifier_; 320 params_.cert_verifier = &cert_verifier_;
250 params_.transport_security_state = &transport_security_state_; 321 params_.transport_security_state = &transport_security_state_;
322 params_.socket_performance_watcher_factory =
323 socket_performance_watcher_factory_.get();
251 params_.proxy_service = proxy_service_.get(); 324 params_.proxy_service = proxy_service_.get();
252 params_.ssl_config_service = ssl_config_service_.get(); 325 params_.ssl_config_service = ssl_config_service_.get();
253 params_.http_auth_handler_factory = auth_handler_factory_.get(); 326 params_.http_auth_handler_factory = auth_handler_factory_.get();
254 params_.http_server_properties = http_server_properties_.GetWeakPtr(); 327 params_.http_server_properties = http_server_properties_.GetWeakPtr();
255 params_.quic_supported_versions = SupportedVersions(GetParam()); 328 params_.quic_supported_versions = SupportedVersions(GetParam());
256 329
257 if (use_next_protos) { 330 if (use_next_protos) {
258 params_.use_alternative_services = true; 331 params_.use_alternative_services = true;
259 params_.next_protos = NextProtosWithSpdyAndQuic(true, true); 332 params_.next_protos = NextProtosWithSpdyAndQuic(true, true);
260 } 333 }
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
365 } 438 }
366 439
367 MockClock* clock_; // Owned by QuicStreamFactory after CreateSession. 440 MockClock* clock_; // Owned by QuicStreamFactory after CreateSession.
368 QuicTestPacketMaker maker_; 441 QuicTestPacketMaker maker_;
369 scoped_refptr<HttpNetworkSession> session_; 442 scoped_refptr<HttpNetworkSession> session_;
370 MockClientSocketFactory socket_factory_; 443 MockClientSocketFactory socket_factory_;
371 MockCryptoClientStreamFactory crypto_client_stream_factory_; 444 MockCryptoClientStreamFactory crypto_client_stream_factory_;
372 MockHostResolver host_resolver_; 445 MockHostResolver host_resolver_;
373 MockCertVerifier cert_verifier_; 446 MockCertVerifier cert_verifier_;
374 TransportSecurityState transport_security_state_; 447 TransportSecurityState transport_security_state_;
448 scoped_ptr<TestSocketPerformanceWatcherFactory>
449 socket_performance_watcher_factory_;
375 scoped_refptr<SSLConfigServiceDefaults> ssl_config_service_; 450 scoped_refptr<SSLConfigServiceDefaults> ssl_config_service_;
376 scoped_ptr<ProxyService> proxy_service_; 451 scoped_ptr<ProxyService> proxy_service_;
377 scoped_ptr<HttpAuthHandlerFactory> auth_handler_factory_; 452 scoped_ptr<HttpAuthHandlerFactory> auth_handler_factory_;
378 MockRandom random_generator_; 453 MockRandom random_generator_;
379 HttpServerPropertiesImpl http_server_properties_; 454 HttpServerPropertiesImpl http_server_properties_;
380 HttpNetworkSession::Params params_; 455 HttpNetworkSession::Params params_;
381 HttpRequestInfo request_; 456 HttpRequestInfo request_;
382 BoundTestNetLog net_log_; 457 BoundTestNetLog net_log_;
383 StaticSocketDataProvider hanging_data_; 458 StaticSocketDataProvider hanging_data_;
384 459
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
485 ConstructResponseHeadersPacket(1, kClientDataStreamId1, false, false, 560 ConstructResponseHeadersPacket(1, kClientDataStreamId1, false, false,
486 GetResponseHeaders("200 OK"))); 561 GetResponseHeaders("200 OK")));
487 mock_quic_data.AddRead( 562 mock_quic_data.AddRead(
488 ConstructDataPacket(2, kClientDataStreamId1, false, true, 0, "hello!")); 563 ConstructDataPacket(2, kClientDataStreamId1, false, true, 0, "hello!"));
489 mock_quic_data.AddWrite(ConstructAckPacket(2, 1)); 564 mock_quic_data.AddWrite(ConstructAckPacket(2, 1));
490 mock_quic_data.AddRead(ASYNC, ERR_IO_PENDING); // No more data to read 565 mock_quic_data.AddRead(ASYNC, ERR_IO_PENDING); // No more data to read
491 mock_quic_data.AddRead(SYNCHRONOUS, 0); // EOF 566 mock_quic_data.AddRead(SYNCHRONOUS, 0); // EOF
492 567
493 mock_quic_data.AddSocketDataToFactory(&socket_factory_); 568 mock_quic_data.AddSocketDataToFactory(&socket_factory_);
494 569
570 DCHECK(!socket_performance_watcher_factory_
571 ->IsRTTAvailableRTTNotificationReceived());
495 // There is no need to set up an alternate protocol job, because 572 // There is no need to set up an alternate protocol job, because
496 // no attempt will be made to speak to the proxy over TCP. 573 // no attempt will be made to speak to the proxy over TCP.
497 574
498 CreateSession(); 575 CreateSession();
499 576
500 SendRequestAndExpectQuicResponseFromProxyOnPort("hello!", 70); 577 SendRequestAndExpectQuicResponseFromProxyOnPort("hello!", 70);
578 DCHECK(socket_performance_watcher_factory_
579 ->IsRTTAvailableRTTNotificationReceived());
501 } 580 }
502 581
503 // Regression test for https://crbug.com/492458. Test that for an HTTP 582 // Regression test for https://crbug.com/492458. Test that for an HTTP
504 // connection through a QUIC proxy, the certificate exhibited by the proxy is 583 // connection through a QUIC proxy, the certificate exhibited by the proxy is
505 // checked against the proxy hostname, not the origin hostname. 584 // checked against the proxy hostname, not the origin hostname.
506 TEST_P(QuicNetworkTransactionTest, QuicProxyWithCert) { 585 TEST_P(QuicNetworkTransactionTest, QuicProxyWithCert) {
507 const std::string origin_host = "news.example.com"; 586 const std::string origin_host = "news.example.com";
508 const std::string proxy_host = "www.example.org"; 587 const std::string proxy_host = "www.example.org";
509 588
510 params_.enable_insecure_quic = true; 589 params_.enable_insecure_quic = true;
(...skipping 24 matching lines...) Expand all
535 EXPECT_FALSE(cert->VerifyNameMatch(origin_host, &common_name_fallback_used)); 614 EXPECT_FALSE(cert->VerifyNameMatch(origin_host, &common_name_fallback_used));
536 ProofVerifyDetailsChromium verify_details; 615 ProofVerifyDetailsChromium verify_details;
537 verify_details.cert_verify_result.verified_cert = cert; 616 verify_details.cert_verify_result.verified_cert = cert;
538 crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); 617 crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
539 618
540 request_.url = GURL("http://" + origin_host); 619 request_.url = GURL("http://" + origin_host);
541 AddHangingNonAlternateProtocolSocketData(); 620 AddHangingNonAlternateProtocolSocketData();
542 CreateSessionWithNextProtos(); 621 CreateSessionWithNextProtos();
543 AddQuicAlternateProtocolMapping(MockCryptoClientStream::CONFIRM_HANDSHAKE); 622 AddQuicAlternateProtocolMapping(MockCryptoClientStream::CONFIRM_HANDSHAKE);
544 SendRequestAndExpectQuicResponseFromProxyOnPort("hello!", 70); 623 SendRequestAndExpectQuicResponseFromProxyOnPort("hello!", 70);
624 DCHECK(socket_performance_watcher_factory_
Ryan Hamilton 2015/09/17 01:59:49 s/DCHECK/EXPECT_TRUE/ ?
tbansal1 2015/09/17 22:23:42 Done.
625 ->IsRTTAvailableRTTNotificationReceived());
545 } 626 }
546 627
547 TEST_P(QuicNetworkTransactionTest, ForceQuicWithErrorConnecting) { 628 TEST_P(QuicNetworkTransactionTest, ForceQuicWithErrorConnecting) {
548 params_.enable_insecure_quic = true; 629 params_.enable_insecure_quic = true;
549 params_.origin_to_force_quic_on = 630 params_.origin_to_force_quic_on =
550 HostPortPair::FromString("www.google.com:80"); 631 HostPortPair::FromString("www.google.com:80");
551 632
552 MockQuicData mock_quic_data; 633 MockQuicData mock_quic_data;
553 mock_quic_data.AddRead(ASYNC, ERR_SOCKET_NOT_CONNECTED); 634 mock_quic_data.AddRead(ASYNC, ERR_SOCKET_NOT_CONNECTED);
554 635
(...skipping 22 matching lines...) Expand all
577 }; 658 };
578 659
579 StaticSocketDataProvider data(http_reads, arraysize(http_reads), nullptr, 0); 660 StaticSocketDataProvider data(http_reads, arraysize(http_reads), nullptr, 0);
580 socket_factory_.AddSocketDataProvider(&data); 661 socket_factory_.AddSocketDataProvider(&data);
581 SSLSocketDataProvider ssl(ASYNC, OK); 662 SSLSocketDataProvider ssl(ASYNC, OK);
582 socket_factory_.AddSSLSocketDataProvider(&ssl); 663 socket_factory_.AddSSLSocketDataProvider(&ssl);
583 664
584 CreateSession(); 665 CreateSession();
585 666
586 SendRequestAndExpectHttpResponse("hello world"); 667 SendRequestAndExpectHttpResponse("hello world");
668 DCHECK(!socket_performance_watcher_factory_
669 ->IsRTTAvailableRTTNotificationReceived());
587 } 670 }
588 671
589 TEST_P(QuicNetworkTransactionTest, UseAlternativeServiceForQuic) { 672 TEST_P(QuicNetworkTransactionTest, UseAlternativeServiceForQuic) {
590 params_.enable_insecure_quic = true; 673 params_.enable_insecure_quic = true;
591 674
592 MockRead http_reads[] = { 675 MockRead http_reads[] = {
593 MockRead("HTTP/1.1 200 OK\r\n"), 676 MockRead("HTTP/1.1 200 OK\r\n"),
594 MockRead(kQuicAlternativeServiceHttpHeader), MockRead("hello world"), 677 MockRead(kQuicAlternativeServiceHttpHeader), MockRead("hello world"),
595 MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), 678 MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
596 MockRead(ASYNC, OK)}; 679 MockRead(ASYNC, OK)};
(...skipping 884 matching lines...) Expand 10 before | Expand all | Expand 10 after
1481 }; 1564 };
1482 1565
1483 StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), 1566 StaticSocketDataProvider http_data(http_reads, arraysize(http_reads),
1484 nullptr, 0); 1567 nullptr, 0);
1485 socket_factory_.AddSocketDataProvider(&http_data); 1568 socket_factory_.AddSocketDataProvider(&http_data);
1486 1569
1487 CreateSessionWithNextProtos(); 1570 CreateSessionWithNextProtos();
1488 AddQuicAlternateProtocolMapping(MockCryptoClientStream::COLD_START); 1571 AddQuicAlternateProtocolMapping(MockCryptoClientStream::COLD_START);
1489 SendRequestAndExpectHttpResponse("hello from http"); 1572 SendRequestAndExpectHttpResponse("hello from http");
1490 ExpectBrokenAlternateProtocolMapping(); 1573 ExpectBrokenAlternateProtocolMapping();
1574 DCHECK(socket_performance_watcher_factory_
1575 ->IsRTTAvailableRTTNotificationReceived());
1491 } 1576 }
1492 1577
1493 TEST_P(QuicNetworkTransactionTest, BrokenAlternateProtocolReadError) { 1578 TEST_P(QuicNetworkTransactionTest, BrokenAlternateProtocolReadError) {
1494 params_.enable_insecure_quic = true; 1579 params_.enable_insecure_quic = true;
1495 // Alternate-protocol job 1580 // Alternate-protocol job
1496 MockRead quic_reads[] = { 1581 MockRead quic_reads[] = {
1497 MockRead(ASYNC, ERR_SOCKET_NOT_CONNECTED), 1582 MockRead(ASYNC, ERR_SOCKET_NOT_CONNECTED),
1498 }; 1583 };
1499 StaticSocketDataProvider quic_data(quic_reads, arraysize(quic_reads), 1584 StaticSocketDataProvider quic_data(quic_reads, arraysize(quic_reads),
1500 nullptr, 0); 1585 nullptr, 0);
1501 socket_factory_.AddSocketDataProvider(&quic_data); 1586 socket_factory_.AddSocketDataProvider(&quic_data);
1502 1587
1503 // Main job which will succeed even though the alternate job fails. 1588 // Main job which will succeed even though the alternate job fails.
1504 MockRead http_reads[] = { 1589 MockRead http_reads[] = {
1505 MockRead("HTTP/1.1 200 OK\r\n\r\n"), 1590 MockRead("HTTP/1.1 200 OK\r\n\r\n"),
1506 MockRead("hello from http"), 1591 MockRead("hello from http"),
1507 MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), 1592 MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
1508 MockRead(ASYNC, OK) 1593 MockRead(ASYNC, OK)
1509 }; 1594 };
1510 1595
1511 StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), 1596 StaticSocketDataProvider http_data(http_reads, arraysize(http_reads),
1512 nullptr, 0); 1597 nullptr, 0);
1513 socket_factory_.AddSocketDataProvider(&http_data); 1598 socket_factory_.AddSocketDataProvider(&http_data);
1514 1599
1515 CreateSessionWithNextProtos(); 1600 CreateSessionWithNextProtos();
1516 1601
1517 AddQuicAlternateProtocolMapping(MockCryptoClientStream::COLD_START); 1602 AddQuicAlternateProtocolMapping(MockCryptoClientStream::COLD_START);
1518 SendRequestAndExpectHttpResponse("hello from http"); 1603 SendRequestAndExpectHttpResponse("hello from http");
1519 ExpectBrokenAlternateProtocolMapping(); 1604 ExpectBrokenAlternateProtocolMapping();
1605 DCHECK(!socket_performance_watcher_factory_
1606 ->IsRTTAvailableRTTNotificationReceived());
1520 } 1607 }
1521 1608
1522 TEST_P(QuicNetworkTransactionTest, NoBrokenAlternateProtocolIfTcpFails) { 1609 TEST_P(QuicNetworkTransactionTest, NoBrokenAlternateProtocolIfTcpFails) {
1523 params_.enable_insecure_quic = true; 1610 params_.enable_insecure_quic = true;
1524 // Alternate-protocol job will fail when the session attempts to read. 1611 // Alternate-protocol job will fail when the session attempts to read.
1525 MockRead quic_reads[] = { 1612 MockRead quic_reads[] = {
1526 MockRead(ASYNC, ERR_SOCKET_NOT_CONNECTED), 1613 MockRead(ASYNC, ERR_SOCKET_NOT_CONNECTED),
1527 }; 1614 };
1528 StaticSocketDataProvider quic_data(quic_reads, arraysize(quic_reads), 1615 StaticSocketDataProvider quic_data(quic_reads, arraysize(quic_reads),
1529 nullptr, 0); 1616 nullptr, 0);
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after
1747 1834
1748 request_.url = GURL("https://www.example.org:443"); 1835 request_.url = GURL("https://www.example.org:443");
1749 AddHangingNonAlternateProtocolSocketData(); 1836 AddHangingNonAlternateProtocolSocketData();
1750 CreateSessionWithNextProtos(); 1837 CreateSessionWithNextProtos();
1751 AddQuicAlternateProtocolMapping(MockCryptoClientStream::CONFIRM_HANDSHAKE); 1838 AddQuicAlternateProtocolMapping(MockCryptoClientStream::CONFIRM_HANDSHAKE);
1752 SendRequestAndExpectQuicResponse("hello!"); 1839 SendRequestAndExpectQuicResponse("hello!");
1753 } 1840 }
1754 1841
1755 } // namespace test 1842 } // namespace test
1756 } // namespace net 1843 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698