| Index: net/socket_stream/socket_stream.cc
|
| diff --git a/net/socket_stream/socket_stream.cc b/net/socket_stream/socket_stream.cc
|
| index fe3afeb5ccd9d28324a2103a6bb4c92ec13e86c9..448ebbbcdbabce85e222c5fcc42b09ab69ac780d 100644
|
| --- a/net/socket_stream/socket_stream.cc
|
| +++ b/net/socket_stream/socket_stream.cc
|
| @@ -66,6 +66,7 @@ SocketStream::SocketStream(const GURL& url, Delegate* delegate)
|
| write_buf_offset_(0),
|
| write_buf_size_(0),
|
| closing_(false),
|
| + server_closed_(false),
|
| metrics_(new SocketStreamMetrics(url)) {
|
| DCHECK(MessageLoop::current()) <<
|
| "The current MessageLoop must exist";
|
| @@ -188,12 +189,29 @@ void SocketStream::Close() {
|
| // of AddRef() and Release() in Connect() and Finish(), respectively.
|
| if (next_state_ == STATE_NONE)
|
| return;
|
| - closing_ = true;
|
| - // Close asynchronously, so that delegate won't be called
|
| - // back before returning Close().
|
| MessageLoop::current()->PostTask(
|
| FROM_HERE,
|
| - NewRunnableMethod(this, &SocketStream::DoLoop, OK));
|
| + NewRunnableMethod(this, &SocketStream::DoClose));
|
| +}
|
| +
|
| +void SocketStream::DoClose() {
|
| + closing_ = true;
|
| + // If next_state_ is STATE_TCP_CONNECT, it's waiting other socket establishing
|
| + // connection. If next_state_ is STATE_AUTH_REQUIRED, it's waiting for
|
| + // restarting. In these states, we'll close the SocketStream now.
|
| + if (next_state_ == STATE_TCP_CONNECT || next_state_ == STATE_AUTH_REQUIRED) {
|
| + DoLoop(ERR_ABORTED);
|
| + return;
|
| + }
|
| + // If next_state_ is STATE_READ_WRITE, we'll run DoLoop and close
|
| + // the SocketStream.
|
| + // If it's writing now, we should defer the closing after the current
|
| + // writing is completed.
|
| + if (next_state_ == STATE_READ_WRITE && !current_write_buf_)
|
| + DoLoop(ERR_ABORTED);
|
| +
|
| + // In other next_state_, we'll wait for callback of other APIs, such as
|
| + // ResolveProxy().
|
| }
|
|
|
| void SocketStream::RestartWithAuth(
|
| @@ -330,7 +348,8 @@ void SocketStream::OnIOCompleted(int result) {
|
| void SocketStream::OnReadCompleted(int result) {
|
| if (result == 0) {
|
| // 0 indicates end-of-file, so socket was closed.
|
| - next_state_ = STATE_CLOSE;
|
| + // Don't close the socket if it's still writing.
|
| + server_closed_ = true;
|
| } else if (result > 0 && read_buf_) {
|
| result = DidReceiveData(result);
|
| }
|
| @@ -408,12 +427,16 @@ void SocketStream::DoLoop(int result) {
|
| case STATE_READ_WRITE:
|
| result = DoReadWrite(result);
|
| break;
|
| + case STATE_AUTH_REQUIRED:
|
| + NOTREACHED() << "Should not run DoLoop in STATE_AUTH_REQUIRED state.";
|
| + Finish(result);
|
| + return;
|
| case STATE_CLOSE:
|
| DCHECK_LE(result, OK);
|
| Finish(result);
|
| return;
|
| default:
|
| - NOTREACHED() << "bad state";
|
| + NOTREACHED() << "bad state " << state;
|
| Finish(result);
|
| return;
|
| }
|
| @@ -841,26 +864,32 @@ int SocketStream::DoReadWrite(int result) {
|
|
|
| next_state_ = STATE_READ_WRITE;
|
|
|
| - if (!read_buf_) {
|
| - // No read pending.
|
| - read_buf_ = new IOBuffer(kReadBufferSize);
|
| - result = socket_->Read(read_buf_, kReadBufferSize, &read_callback_);
|
| - if (result > 0) {
|
| - return DidReceiveData(result);
|
| - } else if (result == 0) {
|
| - // 0 indicates end-of-file, so socket was closed.
|
| - next_state_ = STATE_CLOSE;
|
| - return ERR_CONNECTION_CLOSED;
|
| - }
|
| - // If read is pending, try write as well.
|
| - // Otherwise, return the result and do next loop (to close the connection).
|
| - if (result != ERR_IO_PENDING) {
|
| - next_state_ = STATE_CLOSE;
|
| - return result;
|
| + // If server already closed the socket, we don't try to read.
|
| + if (!server_closed_) {
|
| + if (!read_buf_) {
|
| + // No read pending and server didn't close the socket.
|
| + read_buf_ = new IOBuffer(kReadBufferSize);
|
| + result = socket_->Read(read_buf_, kReadBufferSize, &read_callback_);
|
| + if (result > 0) {
|
| + return DidReceiveData(result);
|
| + } else if (result == 0) {
|
| + // 0 indicates end-of-file, so socket was closed.
|
| + next_state_ = STATE_CLOSE;
|
| + server_closed_ = true;
|
| + return ERR_CONNECTION_CLOSED;
|
| + }
|
| + // If read is pending, try write as well.
|
| + // Otherwise, return the result and do next loop (to close the
|
| + // connection).
|
| + if (result != ERR_IO_PENDING) {
|
| + next_state_ = STATE_CLOSE;
|
| + server_closed_ = true;
|
| + return result;
|
| + }
|
| }
|
| + // Read is pending.
|
| + DCHECK(read_buf_);
|
| }
|
| - // Read is pending.
|
| - DCHECK(read_buf_);
|
|
|
| if (write_buf_ && !current_write_buf_) {
|
| // No write pending.
|
|
|