diff options
author | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-09-21 15:15:01 +0000 |
---|---|---|
committer | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-09-21 15:15:01 +0000 |
commit | b3e12d4a13e468036a2f59c11a820adb4c36aeac (patch) | |
tree | 10d9f36880cf6aebf48894c10a62d721565e2f0f | |
parent | 486f3378bfef5343691f23296b60265b08ea9213 (diff) | |
download | chromium_src-b3e12d4a13e468036a2f59c11a820adb4c36aeac.zip chromium_src-b3e12d4a13e468036a2f59c11a820adb4c36aeac.tar.gz chromium_src-b3e12d4a13e468036a2f59c11a820adb4c36aeac.tar.bz2 |
net: add test for False Start corking.
See r58838 for details of why we do False Start corking.
BUG=none
TEST=net_unittests
http://codereview.chromium.org/3427014
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@60056 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | net/socket/ssl_client_socket_unittest.cc | 38 | ||||
-rw-r--r-- | net/tools/testserver/testserver.py | 24 | ||||
-rw-r--r-- | third_party/tlslite/README.chromium | 4 | ||||
-rw-r--r-- | third_party/tlslite/patches/false_start_corking.patch | 27 | ||||
-rw-r--r-- | third_party/tlslite/tlslite/TLSRecordLayer.py | 9 |
5 files changed, 96 insertions, 6 deletions
diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc index 70540f9..cc69721 100644 --- a/net/socket/ssl_client_socket_unittest.cc +++ b/net/socket/ssl_client_socket_unittest.cc @@ -32,6 +32,11 @@ class SSLClientSocketTest : public PlatformTest { socket_factory_(net::ClientSocketFactory::GetDefaultFactory()) { } + // PerformHTTPSRequest makes an HTTPS request to the testserver by requesting + // the given path (i.e. "/"). If |response| is non-NULL then any resulting + // bytes (including any HTTP headers etc) are appended to |response|. + void PerformHTTPSRequest(const std::string& path, std::string* response); + protected: scoped_refptr<net::HostResolver> resolver_; net::ClientSocketFactory* socket_factory_; @@ -276,7 +281,8 @@ TEST_F(SSLClientSocketTest, ConnectClientAuthSendNullCert) { // - Server closes the underlying TCP connection directly. // - Server sends data unexpectedly. -TEST_F(SSLClientSocketTest, Read) { +void SSLClientSocketTest::PerformHTTPSRequest(const std::string& path, + std::string* response) { net::TestServer test_server(net::TestServer::TYPE_HTTPS, FilePath()); ASSERT_TRUE(test_server.Start()); @@ -305,17 +311,17 @@ TEST_F(SSLClientSocketTest, Read) { } EXPECT_TRUE(sock->IsConnected()); - const char request_text[] = "GET / HTTP/1.0\r\n\r\n"; + const std::string request_text = "GET " + path + " HTTP/1.0\r\n\r\n"; scoped_refptr<net::IOBuffer> request_buffer = - new net::IOBuffer(arraysize(request_text) - 1); - memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1); + new net::IOBuffer(request_text.size()); + memcpy(request_buffer->data(), request_text.data(), request_text.size()); - rv = sock->Write(request_buffer, arraysize(request_text) - 1, &callback); + rv = sock->Write(request_buffer, request_text.size(), &callback); EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING); if (rv == net::ERR_IO_PENDING) rv = callback.WaitForResult(); - EXPECT_EQ(static_cast<int>(arraysize(request_text) - 1), rv); + EXPECT_EQ(static_cast<int>(request_text.size()), rv); scoped_refptr<net::IOBuffer> buf = new net::IOBuffer(4096); for (;;) { @@ -328,9 +334,15 @@ TEST_F(SSLClientSocketTest, Read) { EXPECT_GE(rv, 0); if (rv <= 0) break; + if (response) + *response += std::string(buf->data(), rv); } } +TEST_F(SSLClientSocketTest, Read) { + PerformHTTPSRequest("/", NULL /* don't care about reply contents */); +} + // Test the full duplex mode, with Read and Write pending at the same time. // This test also serves as a regression test for http://crbug.com/29815. TEST_F(SSLClientSocketTest, Read_FullDuplex) { @@ -541,3 +553,17 @@ TEST_F(SSLClientSocketTest, PrematureApplicationData) { rv = sock->Connect(&callback); EXPECT_EQ(net::ERR_SSL_PROTOCOL_ERROR, rv); } + +// CorkedFalseStart tries to test that, in a full handshake, an application +// data record is contained in the same packet as the Finished handshake +// message. This test is inheriently false-negative-flaky: if everything is +// good it'll always pass but, if things break, it'll non-deterministicly fail. +// +// WARNING: do not mark this test as flaky. See above. +TEST_F(SSLClientSocketTest, CorkedFalseStart) { + std::string response; + PerformHTTPSRequest("/corked-false-start", &response); + // "979bdf01cb3c" is a random string which is included in the response to + // make it easy to grep for. + ASSERT_TRUE(std::string::npos != response.find("979bdf01cb3c")); +} diff --git a/net/tools/testserver/testserver.py b/net/tools/testserver/testserver.py index 8a864a8..081517e 100644 --- a/net/tools/testserver/testserver.py +++ b/net/tools/testserver/testserver.py @@ -88,6 +88,7 @@ class HTTPSServer(tlslite.api.TLSSocketServerMixIn, StoppableHTTPServer): sessionCache=self.session_cache, reqCert=self.ssl_client_auth, reqCAs=self.ssl_client_cas) + self.corkedFalseStart = tlsConnection.corkedFalseStart tlsConnection.ignoreAbruptClose = True return True except tlslite.api.TLSAbruptCloseError: @@ -124,6 +125,7 @@ class TestPageHandler(BaseHTTPServer.BaseHTTPRequestHandler): self.EchoHeader, self.EchoHeaderOverride, self.EchoAllHandler, + self.FalseStartHandler, self.FileHandler, self.RealFileWithCommonHeaderHandler, self.RealBZ2FileWithCommonHeaderHandler, @@ -587,6 +589,28 @@ class TestPageHandler(BaseHTTPServer.BaseHTTPRequestHandler): self.end_headers() return True + def FalseStartHandler(self): + """This handler returns kMagic1 if the request was made over a corked False + Start connection and kMagic2 otherwise.""" + + # These are easy to grep for in the reply. + kMagic1 = "979bdf01cb3c\n" + kMagic2 = "71733287b84e\n" + + if not self._ShouldHandleRequest("/corked-false-start"): + return False + + self.send_response(200) + self.send_header('Content-type', 'text/plain') + self.end_headers() + if self.server.corkedFalseStart: + self.wfile.write("Client did corked False Start correctly\n") + self.wfile.write(kMagic1) + else: + self.wfile.write("Client didn't do corked False Start\n") + self.wfile.write(kMagic2) + return True + def FileHandler(self): """This handler sends the contents of the requested file. Wow, it's like a real webserver!""" diff --git a/third_party/tlslite/README.chromium b/third_party/tlslite/README.chromium index 3fc9665..c9b8845 100644 --- a/third_party/tlslite/README.chromium +++ b/third_party/tlslite/README.chromium @@ -25,3 +25,7 @@ Local Modifications: default to a certificate_types of [rsa_sign] in CertificateRequest. Apple's Secure Transport library rejects an empty list and raises an SSL protocol error. +- patches/false_start_corking.patch: tlslite/TLSRecordLayer.py was changed to + report if data was pending on the socket when a Finished handshake message is + processed. This allows us to test that our SSL client sockets are corking + False Start application data correctly. diff --git a/third_party/tlslite/patches/false_start_corking.patch b/third_party/tlslite/patches/false_start_corking.patch new file mode 100644 index 0000000..feebe34 --- /dev/null +++ b/third_party/tlslite/patches/false_start_corking.patch @@ -0,0 +1,27 @@ +diff --git a/tlslite/TLSRecordLayer.py b/tlslite/TLSRecordLayer.py +index 1bbd09d..44cd33e 100644 +--- a/tlslite/TLSRecordLayer.py ++++ b/tlslite/TLSRecordLayer.py +@@ -161,6 +161,10 @@ class TLSRecordLayer: + #Fault we will induce, for testing purposes + self.fault = None + ++ # Set to true if we observe a corked False Start (i.e., there's a ++ # record pending when we read the Finished.) ++ self.corkedFalseStart = False ++ + #********************************************************* + # Public Functions START + #********************************************************* +@@ -713,6 +717,11 @@ class TLSRecordLayer: + yield ClientKeyExchange(constructorType, \ + self.version).parse(p) + elif subType == HandshakeType.finished: ++ try: ++ m = self.sock.recv(1, socket.MSG_PEEK | socket.MSG_DONTWAIT) ++ self.corkedFalseStart = len(m) == 1 ++ except: ++ pass + yield Finished(self.version).parse(p) + else: + raise AssertionError() diff --git a/third_party/tlslite/tlslite/TLSRecordLayer.py b/third_party/tlslite/tlslite/TLSRecordLayer.py index 1bbd09d..44cd33e 100644 --- a/third_party/tlslite/tlslite/TLSRecordLayer.py +++ b/third_party/tlslite/tlslite/TLSRecordLayer.py @@ -161,6 +161,10 @@ class TLSRecordLayer: #Fault we will induce, for testing purposes self.fault = None + # Set to true if we observe a corked False Start (i.e., there's a + # record pending when we read the Finished.) + self.corkedFalseStart = False + #********************************************************* # Public Functions START #********************************************************* @@ -713,6 +717,11 @@ class TLSRecordLayer: yield ClientKeyExchange(constructorType, \ self.version).parse(p) elif subType == HandshakeType.finished: + try: + m = self.sock.recv(1, socket.MSG_PEEK | socket.MSG_DONTWAIT) + self.corkedFalseStart = len(m) == 1 + except: + pass yield Finished(self.version).parse(p) else: raise AssertionError() |