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

Unified Diff: net/socket/ssl_client_socket_openssl.cc

Issue 1000813002: Tidy up SSL_read error handling. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@openssl-alert
Patch Set: sleevi comments Created 5 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/socket/ssl_client_socket_openssl.cc
diff --git a/net/socket/ssl_client_socket_openssl.cc b/net/socket/ssl_client_socket_openssl.cc
index f5e858d2d27ff71c8532a88a04d70d6be50e6ca9..069ba0720aed3b42c477edd735e5aefb159f89f8 100644
--- a/net/socket/ssl_client_socket_openssl.cc
+++ b/net/socket/ssl_client_socket_openssl.cc
@@ -1434,6 +1434,9 @@ int SSLClientSocketOpenSSL::DoWriteLoop() {
int SSLClientSocketOpenSSL::DoPayloadRead() {
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
+ DCHECK_LT(0, user_read_buf_len_);
+ DCHECK(user_read_buf_.get());
+
int rv;
if (pending_read_error_ != kNoPendingReadResult) {
rv = pending_read_error_;
@@ -1453,71 +1456,61 @@ int SSLClientSocketOpenSSL::DoPayloadRead() {
}
int total_bytes_read = 0;
+ int ssl_ret;
do {
- rv = SSL_read(ssl_, user_read_buf_->data() + total_bytes_read,
- user_read_buf_len_ - total_bytes_read);
- if (rv > 0)
- total_bytes_read += rv;
- } while (total_bytes_read < user_read_buf_len_ && rv > 0);
-
- if (total_bytes_read == user_read_buf_len_) {
- rv = total_bytes_read;
- } else {
- // Otherwise, an error occurred (rv <= 0). The error needs to be handled
- // immediately, while the OpenSSL errors are still available in
- // thread-local storage. However, the handled/remapped error code should
- // only be returned if no application data was already read; if it was, the
- // error code should be deferred until the next call of DoPayloadRead.
+ ssl_ret = SSL_read(ssl_, user_read_buf_->data() + total_bytes_read,
+ user_read_buf_len_ - total_bytes_read);
+ if (ssl_ret > 0)
+ total_bytes_read += ssl_ret;
+ } while (total_bytes_read < user_read_buf_len_ && ssl_ret > 0);
+
+ // 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 (client_auth_cert_needed_) {
+ pending_read_error_ = ERR_SSL_CLIENT_AUTH_CERT_NEEDED;
+ } else if (ssl_ret <= 0) {
+ // A zero return from SSL_read may mean any of:
+ // - The underlying BIO_read returned 0.
+ // - The peer sent a close_notify.
+ // - Any arbitrary error. https://crbug.com/466303
//
- // If no data was read, |*next_result| will point to the return value of
- // this function. If at least some data was read, |*next_result| will point
- // to |pending_read_error_|, to be returned in a future call to
- // DoPayloadRead() (e.g.: after the current data is handled).
- int *next_result = &rv;
- if (total_bytes_read > 0) {
- pending_read_error_ = rv;
- rv = total_bytes_read;
- next_result = &pending_read_error_;
+ // TransportReadComplete converts the first to an ERR_CONNECTION_CLOSED
+ // error, so it does not occur. The second and third are distinguished by
+ // SSL_ERROR_ZERO_RETURN.
+ pending_read_ssl_error_ = SSL_get_error(ssl_, ssl_ret);
+ if (pending_read_ssl_error_ == SSL_ERROR_ZERO_RETURN) {
+ pending_read_error_ = 0;
+ } else {
+ pending_read_error_ = MapOpenSSLErrorWithDetails(
+ pending_read_ssl_error_, err_tracer, &pending_read_error_info_);
}
- if (client_auth_cert_needed_) {
- *next_result = ERR_SSL_CLIENT_AUTH_CERT_NEEDED;
- } else if (*next_result <= 0) {
- // A zero return from SSL_read may mean any of:
- // - The underlying BIO_read returned 0.
- // - The peer sent a close_notify.
- // - Any arbitrary error. https://crbug.com/466303
- //
- // TransportReadComplete converts the first to an ERR_CONNECTION_CLOSED
- // error, so it does not occur. The second and third are distinguished by
- // SSL_ERROR_ZERO_RETURN.
- pending_read_ssl_error_ = SSL_get_error(ssl_, *next_result);
- if (pending_read_ssl_error_ == SSL_ERROR_ZERO_RETURN) {
- *next_result = 0;
- } else {
- *next_result = MapOpenSSLErrorWithDetails(
- pending_read_ssl_error_, err_tracer, &pending_read_error_info_);
- }
+ // Many servers do not reliably send a close_notify alert when shutting down
+ // a connection, and instead terminate the TCP connection. This is reported
+ // as ERR_CONNECTION_CLOSED. Because of this, map the unclean shutdown to a
+ // graceful EOF, instead of treating it as an error as it should be.
+ if (pending_read_error_ == ERR_CONNECTION_CLOSED)
+ pending_read_error_ = 0;
+ }
- // Many servers do not reliably send a close_notify alert when shutting
- // down a connection, and instead terminate the TCP connection. This is
- // reported as ERR_CONNECTION_CLOSED. Because of this, map the unclean
- // shutdown to a graceful EOF, instead of treating it as an error as it
- // should be.
- if (*next_result == ERR_CONNECTION_CLOSED)
- *next_result = 0;
-
- if (rv > 0 && *next_result == ERR_IO_PENDING) {
- // If at least some data was read from SSL_read(), do not treat
- // insufficient data as an error to return in the next call to
- // DoPayloadRead() - instead, let the call fall through to check
- // SSL_read() again. This is because DoTransportIO() may complete
- // in between the next call to DoPayloadRead(), and thus it is
- // important to check SSL_read() on subsequent invocations to see
- // if a complete record may now be read.
- *next_result = kNoPendingReadResult;
- }
- }
+ if (total_bytes_read > 0) {
+ // Return any bytes read to the caller. The error will be deferred to the
+ // next call of DoPayloadRead.
+ rv = total_bytes_read;
+
+ // Do not treat insufficient data as an error to return in the next call to
+ // DoPayloadRead() - instead, let the call fall through to check SSL_read()
+ // again. This is because DoTransportIO() may complete in between the next
+ // call to DoPayloadRead(), and thus it is important to check SSL_read() on
+ // subsequent invocations to see if a complete record may now be read.
+ if (pending_read_error_ == ERR_IO_PENDING)
+ pending_read_error_ = kNoPendingReadResult;
+ } else {
+ // No bytes were returned. Return the pending read error immediately.
+ DCHECK_NE(kNoPendingReadResult, pending_read_error_);
+ rv = pending_read_error_;
+ pending_read_error_ = kNoPendingReadResult;
}
if (rv >= 0) {
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698