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 d81b24b5177cf4618fd98c7938ae245527b5d87c..1db73d74ea33de33e23c343d82d68b8616707b32 100644 |
--- a/net/socket/ssl_client_socket_openssl.cc |
+++ b/net/socket/ssl_client_socket_openssl.cc |
@@ -1534,71 +1534,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) { |
Ryan Sleevi
2015/03/17 00:33:14
Why is this change correct?
Previously, this code
davidben
2015/03/20 20:46:04
Claim: Exactly one of ssl_ret <= 0 and total_bytes
|
+ // 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 || user_read_buf_len_ == 0) { |
Ryan Sleevi
2015/03/17 00:33:14
How is it possible for user_read_buf_len to equal
davidben
2015/03/20 20:46:04
I noticed that we don't actually have any checks t
|
+ // 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) { |