| 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 e14527cfb8d56d69219a7ebd1520ba736e46df8c..6840f7bf0823ca06c9c4732c7662331cfacdf9b7 100644
|
| --- a/net/socket/ssl_client_socket_openssl.cc
|
| +++ b/net/socket/ssl_client_socket_openssl.cc
|
| @@ -42,6 +42,7 @@ namespace {
|
|
|
| const int kSessionCacheTimeoutSeconds = 60 * 60;
|
| const size_t kSessionCacheMaxEntires = 1024;
|
| +const int kNoPendingReadResult = 1;
|
|
|
| // If a client doesn't have a list of protocols that it supports, but
|
| // the server supports NPN, choosing "http/1.1" is the best answer.
|
| @@ -425,6 +426,7 @@ SSLClientSocketOpenSSL::SSLClientSocketOpenSSL(
|
| : transport_send_busy_(false),
|
| transport_recv_busy_(false),
|
| transport_recv_eof_(false),
|
| + pending_read_error_(kNoPendingReadResult),
|
| completed_handshake_(false),
|
| client_auth_cert_needed_(false),
|
| cert_verifier_(context.cert_verifier),
|
| @@ -1340,20 +1342,59 @@ bool SSLClientSocketOpenSSL::SetSendBufferSize(int32 size) {
|
|
|
| int SSLClientSocketOpenSSL::DoPayloadRead() {
|
| crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
|
| - int rv = SSL_read(ssl_, user_read_buf_->data(), user_read_buf_len_);
|
| - // We don't need to invalidate the non-client-authenticated SSL session
|
| - // because the server will renegotiate anyway.
|
| - if (client_auth_cert_needed_)
|
| - return ERR_SSL_CLIENT_AUTH_CERT_NEEDED;
|
| +
|
| + int rv;
|
| + if (pending_read_error_ != kNoPendingReadResult) {
|
| + rv = pending_read_error_;
|
| + pending_read_error_ = kNoPendingReadResult;
|
| + if (rv == 0) {
|
| + net_log_.AddByteTransferEvent(NetLog::TYPE_SSL_SOCKET_BYTES_RECEIVED,
|
| + rv, user_read_buf_->data());
|
| + }
|
| + return rv;
|
| + }
|
| +
|
| + int total_bytes_read = 0;
|
| + 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.
|
| + //
|
| + // 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_;
|
| + }
|
| +
|
| + if (client_auth_cert_needed_) {
|
| + *next_result = ERR_SSL_CLIENT_AUTH_CERT_NEEDED;
|
| + } else if (*next_result < 0) {
|
| + int err = SSL_get_error(ssl_, *next_result);
|
| + *next_result = MapOpenSSLError(err, err_tracer);
|
| + }
|
| + }
|
|
|
| if (rv >= 0) {
|
| net_log_.AddByteTransferEvent(NetLog::TYPE_SSL_SOCKET_BYTES_RECEIVED, rv,
|
| user_read_buf_->data());
|
| - return rv;
|
| }
|
| -
|
| - int err = SSL_get_error(ssl_, rv);
|
| - return MapOpenSSLError(err, err_tracer);
|
| + return rv;
|
| }
|
|
|
| int SSLClientSocketOpenSSL::DoPayloadWrite() {
|
|
|