Commit 43527bf8 authored by David Benjamin's avatar David Benjamin Committed by Commit Bot

Run the read pipe in SSLClientSocket immediately after the handshake.

See https://boringssl-review.googlesource.com/c/boringssl/+/37944 for
the rationale.

Bug: 950706, 958638
Change-Id: I221b0e7f6f626968fc38e0bce84260e4141c5e44
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1838456Reviewed-by: default avatarSteven Valdez <svaldez@chromium.org>
Commit-Queue: David Benjamin <davidben@chromium.org>
Cr-Commit-Position: refs/heads/master@{#702944}
parent bde80fe4
......@@ -16,6 +16,7 @@
#include "base/containers/span.h"
#include "base/feature_list.h"
#include "base/lazy_instance.h"
#include "base/location.h"
#include "base/macros.h"
#include "base/memory/singleton.h"
#include "base/metrics/field_trial.h"
......@@ -26,6 +27,7 @@
#include "base/strings/string_piece.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/lock.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "base/trace_event/trace_event.h"
#include "base/values.h"
#include "build/build_config.h"
......@@ -401,6 +403,7 @@ SSLClientSocketImpl::SSLClientSocketImpl(
ssl_config_(ssl_config),
next_handshake_state_(STATE_NONE),
in_confirm_handshake_(false),
peek_complete_(false),
disconnected_(false),
negotiated_protocol_(kProtoUnknown),
certificate_requested_(false),
......@@ -871,8 +874,10 @@ int SSLClientSocketImpl::Init() {
// Configure BoringSSL to allow renegotiations. Once the initial handshake
// completes, if renegotiations are not allowed, the default reject value will
// be restored. This is done in this order to permit a BoringSSL
// optimization. See https://crbug.com/boringssl/123.
SSL_set_renegotiate_mode(ssl_.get(), ssl_renegotiate_freely);
// optimization. See https://crbug.com/boringssl/123. Use
// ssl_renegotiate_explicit rather than ssl_renegotiate_freely so DoPeek()
// does not trigger renegotiations.
SSL_set_renegotiate_mode(ssl_.get(), ssl_renegotiate_explicit);
SSL_set_shed_handshake_config(ssl_.get(), 1);
......@@ -1085,6 +1090,25 @@ int SSLClientSocketImpl::DoHandshakeComplete(int result) {
completed_connect_ = true;
next_handshake_state_ = STATE_NONE;
// Read from the transport immediately after the handshake, whether Read() is
// called immediately or not. This serves several purposes:
//
// First, if this socket is preconnected and negotiates 0-RTT, the ServerHello
// will not be processed. See https://crbug.com/950706
//
// Second, in False Start and TLS 1.3, the tickets arrive after immediately
// after the handshake. This allows preconnected sockets to process the
// tickets sooner. This also avoids a theoretical deadlock if the tickets are
// too large. See
// https://boringssl-review.googlesource.com/c/boringssl/+/34948.
//
// TODO(https://crbug.com/958638): It is also a step in making TLS 1.3 client
// certificate alerts less unreliable.
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&SSLClientSocketImpl::DoPeek, weak_factory_.GetWeakPtr()));
return OK;
}
......@@ -1320,22 +1344,29 @@ int SSLClientSocketImpl::DoPayloadRead(IOBuffer* buf, int buf_len) {
}
int total_bytes_read = 0;
int ssl_ret;
int ssl_ret, ssl_err;
do {
ssl_ret = SSL_read(ssl_.get(), buf->data() + total_bytes_read,
buf_len - total_bytes_read);
if (ssl_ret > 0)
ssl_err = SSL_get_error(ssl_.get(), ssl_ret);
if (ssl_ret > 0) {
total_bytes_read += ssl_ret;
} else if (ssl_err == SSL_ERROR_WANT_RENEGOTIATE) {
if (!SSL_renegotiate(ssl_.get())) {
ssl_err = SSL_ERROR_SSL;
}
}
// Continue processing records as long as there is more data available
// synchronously.
} while (total_bytes_read < buf_len && ssl_ret > 0 &&
transport_adapter_->HasPendingReadData());
} while (ssl_err == SSL_ERROR_WANT_RENEGOTIATE ||
(total_bytes_read < buf_len && ssl_ret > 0 &&
transport_adapter_->HasPendingReadData()));
// Although only the final SSL_read call may have failed, the failure needs to
// processed immediately, while the information still available in OpenSSL's
// error queue.
if (ssl_ret <= 0) {
pending_read_ssl_error_ = SSL_get_error(ssl_.get(), ssl_ret);
pending_read_ssl_error_ = ssl_err;
if (pending_read_ssl_error_ == SSL_ERROR_ZERO_RETURN) {
pending_read_error_ = 0;
} else if (pending_read_ssl_error_ == SSL_ERROR_WANT_X509_LOOKUP &&
......@@ -1419,6 +1450,22 @@ int SSLClientSocketImpl::DoPayloadWrite() {
return net_error;
}
void SSLClientSocketImpl::DoPeek() {
if (ssl_config_.disable_post_handshake_peek_for_testing ||
!completed_connect_ || peek_complete_) {
return;
}
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
char byte;
int rv = SSL_peek(ssl_.get(), &byte, 1);
int ssl_err = SSL_get_error(ssl_.get(), rv);
if (ssl_err != SSL_ERROR_WANT_READ && ssl_err != SSL_ERROR_WANT_WRITE) {
peek_complete_ = true;
}
}
void SSLClientSocketImpl::RetryAllOperations() {
// SSL_do_handshake, SSL_read, and SSL_write may all be retried when blocked,
// so retry all operations for simplicity. (Otherwise, SSL_get_error for each
......@@ -1436,6 +1483,8 @@ void SSLClientSocketImpl::RetryAllOperations() {
if (!guard.get())
return;
DoPeek();
int rv_read = ERR_IO_PENDING;
int rv_write = ERR_IO_PENDING;
if (user_read_buf_) {
......
......@@ -136,6 +136,7 @@ class SSLClientSocketImpl : public SSLClientSocket,
int DoHandshakeLoop(int last_io_result);
int DoPayloadRead(IOBuffer* buf, int buf_len);
int DoPayloadWrite();
void DoPeek();
// Called when an asynchronous event completes which may have blocked the
// pending Connect, Read or Write calls, if any. Retries all state machines
......@@ -272,6 +273,9 @@ class SSLClientSocketImpl : public SSLClientSocket,
// True if we are currently confirming the handshake.
bool in_confirm_handshake_;
// True if the post-handshake SSL_peek has completed.
bool peek_complete_;
// True if the socket has been disconnected.
bool disconnected_;
......
......@@ -1360,6 +1360,14 @@ class SSLClientSocketZeroRTTTest : public SSLClientSocketTest {
server_config);
}
// Makes a new connection to the test server and returns a
// FakeBlockingStreamSocket which may be used to block transport I/O.
//
// Most tests should call BlockReadResult() before calling Connect(). This
// avoid race conditions by controlling the order of events. 0-RTT typically
// races the ServerHello from the server with early data from the client. If
// the ServerHello arrives before client calls Write(), the data may be sent
// with 1-RTT keys rather than 0-RTT keys.
FakeBlockingStreamSocket* MakeClient(bool early_data_enabled) {
SSLConfig ssl_config;
ssl_config.early_data_enabled = early_data_enabled;
......@@ -1792,10 +1800,11 @@ TEST_P(SSLClientSocketReadTest, Read_WithSynchronousError) {
int rv = callback.GetResult(transport->Connect(callback.callback()));
EXPECT_THAT(rv, IsOk());
SSLConfig config;
config.disable_post_handshake_peek_for_testing = true;
SynchronousErrorStreamSocket* raw_transport = transport.get();
std::unique_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
std::move(transport), spawned_test_server()->host_port_pair(),
SSLConfig()));
std::move(transport), spawned_test_server()->host_port_pair(), config));
rv = callback.GetResult(sock->Connect(callback.callback()));
EXPECT_THAT(rv, IsOk());
......@@ -2012,9 +2021,10 @@ TEST_P(SSLClientSocketReadTest, Read_DeleteWhilePendingFullDuplex) {
int rv = callback.GetResult(transport->Connect(callback.callback()));
EXPECT_THAT(rv, IsOk());
SSLConfig config;
config.disable_post_handshake_peek_for_testing = true;
std::unique_ptr<SSLClientSocket> sock = CreateSSLClientSocket(
std::move(transport), spawned_test_server()->host_port_pair(),
SSLConfig());
std::move(transport), spawned_test_server()->host_port_pair(), config);
rv = callback.GetResult(sock->Connect(callback.callback()));
EXPECT_THAT(rv, IsOk());
......@@ -2174,10 +2184,11 @@ TEST_F(SSLClientSocketTest, Connect_WithZeroReturn) {
int rv = callback.GetResult(transport->Connect(callback.callback()));
EXPECT_THAT(rv, IsOk());
SSLConfig config;
config.disable_post_handshake_peek_for_testing = true;
SynchronousErrorStreamSocket* raw_transport = transport.get();
std::unique_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
std::move(transport), spawned_test_server()->host_port_pair(),
SSLConfig()));
std::move(transport), spawned_test_server()->host_port_pair(), config));
raw_transport->SetNextReadError(0);
......@@ -2200,10 +2211,11 @@ TEST_P(SSLClientSocketReadTest, Read_WithZeroReturn) {
int rv = callback.GetResult(transport->Connect(callback.callback()));
EXPECT_THAT(rv, IsOk());
SSLConfig config;
config.disable_post_handshake_peek_for_testing = true;
SynchronousErrorStreamSocket* raw_transport = transport.get();
std::unique_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
std::move(transport), spawned_test_server()->host_port_pair(),
SSLConfig()));
std::move(transport), spawned_test_server()->host_port_pair(), config));
rv = callback.GetResult(sock->Connect(callback.callback()));
EXPECT_THAT(rv, IsOk());
......@@ -2233,9 +2245,10 @@ TEST_P(SSLClientSocketReadTest, Read_WithAsyncZeroReturn) {
int rv = callback.GetResult(transport->Connect(callback.callback()));
EXPECT_THAT(rv, IsOk());
SSLConfig config;
config.disable_post_handshake_peek_for_testing = true;
std::unique_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
std::move(transport), spawned_test_server()->host_port_pair(),
SSLConfig()));
std::move(transport), spawned_test_server()->host_port_pair(), config));
rv = callback.GetResult(sock->Connect(callback.callback()));
EXPECT_THAT(rv, IsOk());
......@@ -2309,9 +2322,10 @@ TEST_P(SSLClientSocketReadTest, Read_ManySmallRecords) {
int rv = callback.GetResult(transport->Connect(callback.callback()));
ASSERT_THAT(rv, IsOk());
SSLConfig config;
config.disable_post_handshake_peek_for_testing = true;
std::unique_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
std::move(transport), spawned_test_server()->host_port_pair(),
SSLConfig()));
std::move(transport), spawned_test_server()->host_port_pair(), config));
rv = callback.GetResult(sock->Connect(callback.callback()));
ASSERT_THAT(rv, IsOk());
......@@ -3477,6 +3491,56 @@ TEST_F(SSLClientSocketFalseStartTest, SessionResumption) {
EXPECT_EQ(SSLInfo::HANDSHAKE_RESUME, ssl_info.handshake_type);
}
// Test that the client completes the handshake in the background and installs
// new sessions, even if the socket isn't used. This also avoids a theoretical
// deadlock if NewSessionTicket is sufficiently large that neither it nor the
// client's HTTP/1.1 POST fit in transport windows.
TEST_F(SSLClientSocketFalseStartTest, CompleteHandshakeWithoutRequest) {
// Start a server.
SpawnedTestServer::SSLOptions server_options;
server_options.key_exchanges =
SpawnedTestServer::SSLOptions::KEY_EXCHANGE_ECDHE_RSA;
server_options.bulk_ciphers =
SpawnedTestServer::SSLOptions::BULK_CIPHER_AES128GCM;
server_options.alpn_protocols.push_back("http/1.1");
ASSERT_TRUE(StartTestServer(server_options));
SSLConfig client_config;
client_config.alpn_protos.push_back(kProtoHTTP11);
// Start a handshake up to the server Finished message.
TestCompletionCallback callback;
FakeBlockingStreamSocket* raw_transport = nullptr;
std::unique_ptr<SSLClientSocket> sock;
ASSERT_NO_FATAL_FAILURE(CreateAndConnectUntilServerFinishedReceived(
client_config, &callback, &raw_transport, &sock));
// Wait for the server Finished to arrive, release it, and allow
// SSLClientSocket to process it. This should install a session.
// SpawnedTestServer, however, writes data in small chunks, so, even though it
// is only sending 51 bytes, it may take a few iterations to complete.
while (ssl_client_session_cache_->size() == 0) {
raw_transport->WaitForReadResult();
raw_transport->UnblockReadResult();
base::RunLoop().RunUntilIdle();
raw_transport->BlockReadResult();
}
// Drop the old socket. This is needed because the Python test server can't
// service two sockets in parallel.
sock.reset();
// Make a second connection.
int rv;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(client_config, &rv));
EXPECT_THAT(rv, IsOk());
// It should resume the session.
SSLInfo ssl_info;
EXPECT_TRUE(sock_->GetSSLInfo(&ssl_info));
EXPECT_EQ(SSLInfo::HANDSHAKE_RESUME, ssl_info.handshake_type);
}
// Test that False Started sessions are not resumable before receiving the
// server Finished message.
TEST_F(SSLClientSocketFalseStartTest, NoSessionResumptionBeforeFinished) {
......@@ -4738,16 +4802,21 @@ TEST_F(SSLClientSocketTest, AccessDeniedClientCerts) {
EXPECT_THAT(rv, IsError(ERR_BAD_SSL_CLIENT_AUTH_CERT));
}
TEST_F(SSLClientSocketZeroRTTTest, ZeroRTT) {
// Test the client can send application data before the ServerHello comes in.
TEST_F(SSLClientSocketZeroRTTTest, ZeroRTTEarlyDataBeforeServerHello) {
ASSERT_TRUE(StartServer());
ASSERT_TRUE(RunInitialConnection());
// 0-RTT Connection
MakeClient(true);
// Make a 0-RTT Connection. Connect() and Write() complete even though the
// ServerHello is blocked.
FakeBlockingStreamSocket* socket = MakeClient(true);
socket->BlockReadResult();
ASSERT_THAT(Connect(), IsOk());
constexpr base::StringPiece kRequest = "GET /zerortt HTTP/1.0\r\n\r\n";
EXPECT_EQ(static_cast<int>(kRequest.size()), WriteAndWait(kRequest));
// Release the ServerHello. Now reads complete.
socket->UnblockReadResult();
scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(4096);
int size = ReadAndWait(buf.get(), 4096);
EXPECT_GT(size, 0);
......@@ -4758,57 +4827,65 @@ TEST_F(SSLClientSocketZeroRTTTest, ZeroRTT) {
EXPECT_EQ(SSLInfo::HANDSHAKE_RESUME, ssl_info.handshake_type);
}
// Check that 0RTT is confirmed after a Write and Read.
TEST_F(SSLClientSocketZeroRTTTest, ZeroRTTConfirmedAfterRead) {
// Test that the client sends 1-RTT data if the ServerHello happens to come in
// before Write() is called. See https://crbug.com/950706.
TEST_F(SSLClientSocketZeroRTTTest, ZeroRTTEarlyDataAfterServerHello) {
ASSERT_TRUE(StartServer());
ASSERT_TRUE(RunInitialConnection());
// 0-RTT Connection
MakeClient(true);
// Make a 0-RTT Connection. Connect() completes even though the ServerHello is
// blocked.
FakeBlockingStreamSocket* socket = MakeClient(true);
socket->BlockReadResult();
ASSERT_THAT(Connect(), IsOk());
// Wait for the ServerHello to come in and for SSLClientSocket to process it.
socket->WaitForReadResult();
socket->UnblockReadResult();
base::RunLoop().RunUntilIdle();
// Now write to the socket.
constexpr base::StringPiece kRequest = "GET /zerortt HTTP/1.0\r\n\r\n";
EXPECT_EQ(static_cast<int>(kRequest.size()), WriteAndWait(kRequest));
// Although the socket was created in early data state and the client never
// explicitly called ReaD() or ConfirmHandshake(), SSLClientSocketImpl
// internally consumed the ServerHello and switch keys. The server then
// responds with '0'.
scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(4096);
int size = ReadAndWait(buf.get(), 4096);
EXPECT_GT(size, 0);
EXPECT_EQ('1', buf->data()[size - 1]);
// After the handshake is confirmed, ConfirmHandshake should return
// synchronously.
TestCompletionCallback callback;
ASSERT_THAT(ssl_socket()->ConfirmHandshake(callback.callback()), IsOk());
EXPECT_EQ('0', buf->data()[size - 1]);
SSLInfo ssl_info;
ASSERT_TRUE(GetSSLInfo(&ssl_info));
EXPECT_EQ(SSLInfo::HANDSHAKE_RESUME, ssl_info.handshake_type);
}
// Test that the client sends application data before the ServerHello comes in.
TEST_F(SSLClientSocketZeroRTTTest, ZeroRTTEarlyDataBeforeServerHello) {
// Check that 0RTT is confirmed after a Write and Read.
TEST_F(SSLClientSocketZeroRTTTest, ZeroRTTConfirmedAfterRead) {
ASSERT_TRUE(StartServer());
ASSERT_TRUE(RunInitialConnection());
// 0-RTT Connection
// Make a 0-RTT Connection. Connect() and Write() complete even though the
// ServerHello is blocked.
FakeBlockingStreamSocket* socket = MakeClient(true);
// Block the ServerHello.
socket->BlockReadResult();
// The handshake still completes.
ASSERT_THAT(Connect(), IsOk());
// Writes still complete.
constexpr base::StringPiece kRequest = "GET /zerortt HTTP/1.0\r\n\r\n";
EXPECT_EQ(static_cast<int>(kRequest.size()), WriteAndWait(kRequest));
// Release the ServerHello. Now reads complete.
socket->UnblockReadResult();
scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(4096);
int size = ReadAndWait(buf.get(), 4096);
EXPECT_GT(size, 0);
EXPECT_EQ('1', buf->data()[size - 1]);
// After the handshake is confirmed, ConfirmHandshake should return
// synchronously.
TestCompletionCallback callback;
ASSERT_THAT(ssl_socket()->ConfirmHandshake(callback.callback()), IsOk());
SSLInfo ssl_info;
ASSERT_TRUE(GetSSLInfo(&ssl_info));
EXPECT_EQ(SSLInfo::HANDSHAKE_RESUME, ssl_info.handshake_type);
......@@ -4820,13 +4897,10 @@ TEST_F(SSLClientSocketZeroRTTTest, ZeroRTTEarlyDataLimit) {
ASSERT_TRUE(StartServer());
ASSERT_TRUE(RunInitialConnection());
// 0-RTT Connection
// Make a 0-RTT Connection. Connect() completes even though the ServerHello is
// blocked.
FakeBlockingStreamSocket* socket = MakeClient(true);
// Block the ServerHello.
socket->BlockReadResult();
// The handshake still completes.
ASSERT_THAT(Connect(), IsOk());
// EmbeddedTestServer uses BoringSSL's hard-coded early data limit, which is
......@@ -4949,16 +5023,24 @@ TEST_F(SSLClientSocketZeroRTTTest, ZeroRTTReadBeforeWrite) {
ASSERT_TRUE(StartServer());
ASSERT_TRUE(RunInitialConnection());
// 0-RTT Connection
MakeClient(true);
// Make a 0-RTT Connection. Connect() completes even though the ServerHello is
// blocked.
FakeBlockingStreamSocket* socket = MakeClient(true);
socket->BlockReadResult();
ASSERT_THAT(Connect(), IsOk());
// Read() does not make progress.
scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(4096);
TestCompletionCallback read_callback;
ASSERT_THAT(Connect(), IsOk());
ASSERT_EQ(ERR_IO_PENDING,
ssl_socket()->Read(buf.get(), 4096, read_callback.callback()));
// Write() completes, even though reads are blocked.
constexpr base::StringPiece kRequest = "GET /zerortt HTTP/1.0\r\n\r\n";
EXPECT_EQ(static_cast<int>(kRequest.size()), WriteAndWait(kRequest));
// Release the ServerHello, etc. The Read() now completes.
socket->UnblockReadResult();
int size = read_callback.GetResult(ERR_IO_PENDING);
EXPECT_GT(size, 0);
EXPECT_EQ('1', buf->data()[size - 1]);
......@@ -5038,8 +5120,13 @@ TEST_F(SSLClientSocketZeroRTTTest, ZeroRTTParallelReadConfirm) {
TEST_P(SSLClientSocketReadTest, DumpMemoryStats) {
ASSERT_TRUE(StartTestServer(SpawnedTestServer::SSLOptions()));
// This test compares the memory usage when there is and isn't a pending read
// on the socket, so disable the post-handshake peek.
SSLConfig config;
config.disable_post_handshake_peek_for_testing = true;
int rv;
ASSERT_TRUE(CreateAndConnectSSLClientSocket(SSLConfig(), &rv));
ASSERT_TRUE(CreateAndConnectSSLClientSocket(config, &rv));
EXPECT_THAT(rv, IsOk());
StreamSocket::SocketMemoryStats stats;
sock_->DumpMemoryStats(&stats);
......
......@@ -21,13 +21,7 @@ SSLConfig::CertAndStatus::CertAndStatus(scoped_refptr<X509Certificate> cert_arg,
SSLConfig::CertAndStatus::CertAndStatus(const CertAndStatus& other) = default;
SSLConfig::CertAndStatus::~CertAndStatus() = default;
SSLConfig::SSLConfig()
: early_data_enabled(false),
require_ecdhe(false),
ignore_certificate_errors(false),
disable_cert_verification_network_fetches(false),
renego_allowed_default(false),
privacy_mode(PRIVACY_MODE_DISABLED) {}
SSLConfig::SSLConfig() = default;
SSLConfig::SSLConfig(const SSLConfig& other) = default;
......
......@@ -73,10 +73,10 @@ struct NET_EXPORT SSLConfig {
// high-level operation.
//
// If unsure, do not enable this option.
bool early_data_enabled;
bool early_data_enabled = false;
// If true, causes only ECDHE cipher suites to be enabled.
bool require_ecdhe;
bool require_ecdhe = false;
// TODO(wtc): move the following members to a new SSLParams structure. They
// are not SSL configuration settings.
......@@ -98,7 +98,7 @@ struct NET_EXPORT SSLConfig {
std::vector<CertAndStatus> allowed_bad_certs;
// True if all certificate errors should be ignored.
bool ignore_certificate_errors;
bool ignore_certificate_errors = false;
// True if, for a single connection, any dependent network fetches should
// be disabled. This can be used to avoid triggering re-entrancy in the
......@@ -106,7 +106,7 @@ struct NET_EXPORT SSLConfig {
// AIA, OCSP, or CRL fetches to block on retrieving the PAC script, while
// the PAC script fetch is waiting for those dependent fetches, creating a
// deadlock.
bool disable_cert_verification_network_fetches;
bool disable_cert_verification_network_fetches = false;
// The list of application level protocols supported with ALPN (Application
// Layer Protocol Negotiation), in decreasing order of preference. Protocols
......@@ -115,7 +115,7 @@ struct NET_EXPORT SSLConfig {
// True if renegotiation should be allowed for the default application-level
// protocol when the peer negotiates neither ALPN nor NPN.
bool renego_allowed_default;
bool renego_allowed_default = false;
// The list of application-level protocols to enable renegotiation for.
NextProtoVector renego_allowed_for_protos;
......@@ -132,7 +132,12 @@ struct NET_EXPORT SSLConfig {
// current session cache partitioning behavior will be needed to correctly
// implement it. For now, it acts as an incomplete version of
// PartitionSSLSessionsByNetworkIsolationKey.
PrivacyMode privacy_mode;
PrivacyMode privacy_mode = PRIVACY_MODE_DISABLED;
// True if the post-handshake peeking of the transport should be skipped. This
// logic ensures 0-RTT and tickets are resolved early, but can interfere with
// some unit tests.
bool disable_post_handshake_peek_for_testing = false;
};
} // namespace net
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment