summaryrefslogtreecommitdiffstats
path: root/net/spdy/spdy_session.cc
diff options
context:
space:
mode:
Diffstat (limited to 'net/spdy/spdy_session.cc')
-rw-r--r--net/spdy/spdy_session.cc449
1 files changed, 257 insertions, 192 deletions
diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc
index b607796..879d645 100644
--- a/net/spdy/spdy_session.cc
+++ b/net/spdy/spdy_session.cc
@@ -9,6 +9,7 @@
#include "base/basictypes.h"
#include "base/bind.h"
+#include "base/bind_helpers.h"
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/message_loop.h"
@@ -352,14 +353,14 @@ SpdySession::SpdySession(const SpdySessionKey& spdy_session_key,
http_server_properties_(http_server_properties),
read_buffer_(new IOBuffer(kReadBufferSize)),
stream_hi_water_mark_(kFirstStreamId),
- write_pending_(false),
in_flight_write_frame_type_(DATA),
in_flight_write_frame_size_(0),
- delayed_write_pending_(false),
is_secure_(false),
certificate_error_code_(OK),
- error_(OK),
- state_(STATE_IDLE),
+ availability_state_(STATE_AVAILABLE),
+ read_state_(READ_STATE_DO_READ),
+ write_state_(WRITE_STATE_DO_WRITE),
+ error_on_close_(OK),
max_concurrent_streams_(initial_max_concurrent_streams == 0 ?
kInitialMaxConcurrentStreams :
initial_max_concurrent_streams),
@@ -371,7 +372,6 @@ SpdySession::SpdySession(const SpdySessionKey& spdy_session_key,
streams_pushed_and_claimed_count_(0),
streams_abandoned_count_(0),
total_bytes_received_(0),
- bytes_read_(0),
sent_settings_(false),
received_settings_(false),
stalled_streams_(0),
@@ -412,8 +412,9 @@ SpdySession::SpdySession(const SpdySessionKey& spdy_session_key,
}
SpdySession::~SpdySession() {
- if (state_ != STATE_CLOSED) {
- state_ = STATE_CLOSED;
+ if (availability_state_ != STATE_CLOSED) {
+ availability_state_ = STATE_CLOSED;
+ error_on_close_ = ERR_ABORTED;
// Cleanup all the streams.
CloseAllStreams(ERR_ABORTED);
@@ -451,7 +452,10 @@ Error SpdySession::InitializeWithSocket(
base::StatsCounter spdy_sessions("spdy.sessions");
spdy_sessions.Increment();
- state_ = STATE_DO_READ;
+ DCHECK_EQ(availability_state_, STATE_AVAILABLE);
+ DCHECK_EQ(read_state_, READ_STATE_DO_READ);
+ DCHECK_EQ(write_state_, WRITE_STATE_DO_WRITE);
+
connection_ = connection.Pass();
is_secure_ = is_secure;
certificate_error_code_ = certificate_error_code;
@@ -500,15 +504,12 @@ Error SpdySession::InitializeWithSocket(
NetLog::TYPE_SPDY_SESSION_INITIALIZED,
connection_->socket()->NetLog().source().ToEventParametersCallback());
- int error = DoLoop(OK);
+ int error = DoReadLoop(READ_STATE_DO_READ, OK);
if (error == ERR_IO_PENDING)
error = OK;
if (error == OK) {
connection_->AddLayeredPool(this);
SendInitialSettings();
- // Write out any data that we might have to send, such as the
- // settings frame.
- WriteSocketLater();
spdy_session_pool_ = spdy_session_pool;
}
return static_cast<Error>(error);
@@ -518,7 +519,7 @@ bool SpdySession::VerifyDomainAuthentication(const std::string& domain) {
if (!verify_domain_authentication_)
return true;
- if (!IsConnected())
+ if (availability_state_ == STATE_CLOSED)
return false;
SSLInfo ssl_info;
@@ -538,7 +539,8 @@ int SpdySession::GetPushStream(
const GURL& url,
base::WeakPtr<SpdyStream>* stream,
const BoundNetLog& stream_net_log) {
- CHECK_NE(state_, STATE_CLOSED);
+ if (availability_state_ == STATE_CLOSED)
+ return ERR_CONNECTION_CLOSED;
stream->reset();
@@ -565,6 +567,11 @@ int SpdySession::GetPushStream(
int SpdySession::TryCreateStream(SpdyStreamRequest* request,
base::WeakPtr<SpdyStream>* stream) {
+ // TODO(akalin): Also refuse to create the stream when
+ // |availability_state_| == STATE_GOING_AWAY.
+ if (availability_state_ == STATE_CLOSED)
+ return ERR_CONNECTION_CLOSED;
+
if (!max_concurrent_streams_ ||
(active_streams_.size() + created_streams_.size() <
max_concurrent_streams_)) {
@@ -582,6 +589,11 @@ int SpdySession::CreateStream(const SpdyStreamRequest& request,
DCHECK_GE(request.priority(), MINIMUM_PRIORITY);
DCHECK_LT(request.priority(), NUM_PRIORITIES);
+ // TODO(akalin): Also refuse to create the stream when
+ // |availability_state_| == STATE_GOING_AWAY.
+ if (availability_state_ == STATE_CLOSED)
+ return ERR_CONNECTION_CLOSED;
+
// Make sure that we don't try to send https/wss over an unauthenticated, but
// encrypted SSL socket.
if (is_secure_ && certificate_error_code_ != OK &&
@@ -956,26 +968,11 @@ bool SpdySession::IsStreamActive(SpdyStreamId stream_id) const {
}
LoadState SpdySession::GetLoadState() const {
- // NOTE: The application only queries the LoadState via the
- // SpdyNetworkTransaction, and details are only needed when
- // we're in the process of connecting.
-
- // If we're connecting, defer to the connection to give us the actual
- // LoadState.
- if (state_ == STATE_CONNECTING)
- return connection_->GetLoadState();
-
// Just report that we're idle since the session could be doing
// many things concurrently.
return LOAD_STATE_IDLE;
}
-void SpdySession::OnReadComplete(int bytes_read) {
- DCHECK_NE(state_, STATE_DO_READ);
- DoLoop(bytes_read);
-}
-
-
void SpdySession::CloseActiveStreamIterator(ActiveStreamMap::iterator it,
int status) {
// TODO(mbelshe): We should send a RST_STREAM control frame here
@@ -1043,13 +1040,13 @@ void SpdySession::SendResetStreamFrame(SpdyStreamId stream_id,
static_cast<SpdyProtocolErrorDetails>(status + STATUS_CODE_INVALID));
}
-void SpdySession::StartRead() {
- DCHECK_NE(state_, STATE_DO_READ_COMPLETE);
- DoLoop(OK);
-}
+int SpdySession::DoReadLoop(ReadState expected_read_state, int result) {
+ DCHECK_EQ(read_state_, expected_read_state);
-int SpdySession::DoLoop(int result) {
- bytes_read_ = 0;
+ if (availability_state_ == STATE_CLOSED) {
+ DCHECK_LT(error_on_close_, ERR_IO_PENDING);
+ return error_on_close_;
+ }
// The SpdyFramer will use callbacks onto |this| as it parses frames.
// When errors occur, those callbacks can lead to teardown of all references
@@ -1057,106 +1054,221 @@ int SpdySession::DoLoop(int result) {
// cleanup.
scoped_refptr<SpdySession> self(this);
- do {
- switch (state_) {
- case STATE_DO_READ:
+ int bytes_read_without_yielding = 0;
+
+ // Loop until the session is closed, the read becomes blocked, or
+ // the read limit is exceeded.
+ while (true) {
+ switch (read_state_) {
+ case READ_STATE_DO_READ:
DCHECK_EQ(result, OK);
result = DoRead();
break;
- case STATE_DO_READ_COMPLETE:
+ case READ_STATE_DO_READ_COMPLETE:
+ if (result > 0)
+ bytes_read_without_yielding += result;
result = DoReadComplete(result);
break;
- case STATE_CLOSED:
- result = ERR_CONNECTION_CLOSED;
- break;
default:
- NOTREACHED() << "state_: " << state_;
+ NOTREACHED() << "read_state_: " << read_state_;
break;
}
- } while (result != ERR_IO_PENDING && state_ != STATE_CLOSED);
- DCHECK(result == ERR_IO_PENDING || result == ERR_CONNECTION_CLOSED);
- return result;
+ if (availability_state_ == STATE_CLOSED) {
+ DCHECK_EQ(result, error_on_close_);
+ DCHECK_LT(result, ERR_IO_PENDING);
+ return result;
+ }
+
+ if (result == ERR_IO_PENDING)
+ return ERR_IO_PENDING;
+
+ if (bytes_read_without_yielding > kMaxReadBytesWithoutYielding) {
+ read_state_ = READ_STATE_DO_READ;
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(base::IgnoreResult(&SpdySession::DoReadLoop),
+ weak_factory_.GetWeakPtr(), READ_STATE_DO_READ, OK));
+ return ERR_IO_PENDING;
+ }
+ }
}
int SpdySession::DoRead() {
- if (bytes_read_ > kMaxReadBytes) {
- state_ = STATE_DO_READ;
- base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&SpdySession::StartRead,
- weak_factory_.GetWeakPtr()));
- return ERR_IO_PENDING;
- }
+ DCHECK_NE(availability_state_, STATE_CLOSED);
CHECK(connection_);
CHECK(connection_->socket());
- state_ = STATE_DO_READ_COMPLETE;
+ read_state_ = READ_STATE_DO_READ_COMPLETE;
return connection_->socket()->Read(
read_buffer_.get(),
kReadBufferSize,
- base::Bind(&SpdySession::OnReadComplete, weak_factory_.GetWeakPtr()));
+ base::Bind(base::IgnoreResult(&SpdySession::DoReadLoop),
+ weak_factory_.GetWeakPtr(), READ_STATE_DO_READ_COMPLETE));
}
int SpdySession::DoReadComplete(int result) {
+ DCHECK_NE(availability_state_, STATE_CLOSED);
+
// Parse a frame. For now this code requires that the frame fit into our
- // buffer (32KB).
+ // buffer (kReadBufferSize).
// TODO(mbelshe): support arbitrarily large frames!
- if (result <= 0) {
- // Session is tearing down.
- Error error = static_cast<Error>(result);
- if (result == 0) {
- UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySession.BytesRead.EOF",
- total_bytes_received_, 1, 100000000, 50);
- error = ERR_CONNECTION_CLOSED;
- }
- CloseSessionOnError(error, "result is <= 0.");
+ if (result == 0) {
+ UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySession.BytesRead.EOF",
+ total_bytes_received_, 1, 100000000, 50);
+ CloseSessionOnError(ERR_CONNECTION_CLOSED, "Connection closed");
+ DCHECK_EQ(availability_state_, STATE_CLOSED);
+ DCHECK_EQ(error_on_close_, ERR_CONNECTION_CLOSED);
return ERR_CONNECTION_CLOSED;
}
+ if (result < 0) {
+ CloseSessionOnError(static_cast<Error>(result), "result is < 0.");
+ DCHECK_EQ(availability_state_, STATE_CLOSED);
+ DCHECK_EQ(error_on_close_, result);
+ return result;
+ }
+
total_bytes_received_ += result;
- bytes_read_ += result;
last_activity_time_ = base::TimeTicks::Now();
DCHECK(buffered_spdy_framer_.get());
char* data = read_buffer_->data();
- while (result &&
- buffered_spdy_framer_->error_code() ==
- SpdyFramer::SPDY_NO_ERROR) {
- uint32 bytes_processed =
- buffered_spdy_framer_->ProcessInput(data, result);
+ while (result > 0) {
+ uint32 bytes_processed = buffered_spdy_framer_->ProcessInput(data, result);
result -= bytes_processed;
data += bytes_processed;
- }
- if (!IsConnected())
- return ERR_CONNECTION_CLOSED;
+ if (availability_state_ == STATE_CLOSED) {
+ DCHECK_LT(error_on_close_, ERR_IO_PENDING);
+ return error_on_close_;
+ }
- state_ = STATE_DO_READ;
+ DCHECK_EQ(buffered_spdy_framer_->error_code(), SpdyFramer::SPDY_NO_ERROR);
+ }
+
+ read_state_ = READ_STATE_DO_READ;
return OK;
}
-void SpdySession::OnWriteComplete(int result) {
- // Releasing the in-flight write can have a side-effect of dropping
- // the last reference to |this|. Hold a reference through this
- // function.
+int SpdySession::DoWriteLoop(WriteState expected_write_state, int result) {
+ DCHECK_EQ(write_state_, expected_write_state);
+
+ if (availability_state_ == STATE_CLOSED) {
+ DCHECK_LT(error_on_close_, ERR_IO_PENDING);
+ return error_on_close_;
+ }
+
+ // Releasing the in-flight write in DoWriteComplete() can have a
+ // side-effect of dropping the last reference to |this|. Hold a
+ // reference through this function.
scoped_refptr<SpdySession> self(this);
- DCHECK(write_pending_);
+ // Loop until the session is closed or the write becomes blocked.
+ while (true) {
+ switch (write_state_) {
+ case WRITE_STATE_DO_WRITE:
+ DCHECK_EQ(result, OK);
+ result = DoWrite();
+ break;
+ case WRITE_STATE_DO_WRITE_COMPLETE:
+ result = DoWriteComplete(result);
+ break;
+ default:
+ NOTREACHED() << "write_state_: " << write_state_;
+ break;
+ }
+
+ if (availability_state_ == STATE_CLOSED) {
+ DCHECK_EQ(result, error_on_close_);
+ DCHECK_LT(result, ERR_IO_PENDING);
+ return result;
+ }
+
+ if (result == ERR_IO_PENDING)
+ return ERR_IO_PENDING;
+ }
+}
+
+int SpdySession::DoWrite() {
+ DCHECK_NE(availability_state_, STATE_CLOSED);
+
+ DCHECK(buffered_spdy_framer_);
+ if (in_flight_write_) {
+ DCHECK_GT(in_flight_write_->GetRemainingSize(), 0u);
+ } else {
+ // Grab the next frame to send.
+ SpdyFrameType frame_type = DATA;
+ scoped_ptr<SpdyBufferProducer> producer;
+ base::WeakPtr<SpdyStream> stream;
+ if (!write_queue_.Dequeue(&frame_type, &producer, &stream)) {
+ DCHECK_EQ(write_state_, WRITE_STATE_DO_WRITE);
+ return ERR_IO_PENDING;
+ }
+
+ if (stream.get())
+ DCHECK(!stream->IsClosed());
+
+ // Activate the stream only when sending the SYN_STREAM frame to
+ // guarantee monotonically-increasing stream IDs.
+ if (frame_type == SYN_STREAM) {
+ if (stream.get() && stream->stream_id() == 0) {
+ scoped_ptr<SpdyStream> owned_stream =
+ ActivateCreatedStream(stream.get());
+ InsertActivatedStream(owned_stream.Pass());
+ } else {
+ NOTREACHED();
+ return ERR_UNEXPECTED;
+ }
+ }
+
+ in_flight_write_ = producer->ProduceBuffer();
+ if (!in_flight_write_) {
+ NOTREACHED();
+ return ERR_UNEXPECTED;
+ }
+ in_flight_write_frame_type_ = frame_type;
+ in_flight_write_frame_size_ = in_flight_write_->GetRemainingSize();
+ DCHECK_GE(in_flight_write_frame_size_,
+ buffered_spdy_framer_->GetFrameMinimumSize());
+ in_flight_write_stream_ = stream;
+ }
+
+ write_state_ = WRITE_STATE_DO_WRITE_COMPLETE;
+
+ // Explicitly store in a scoped_refptr<IOBuffer> to avoid problems
+ // with Socket implementations that don't store their IOBuffer
+ // argument in a scoped_refptr<IOBuffer> (see crbug.com/232345).
+ scoped_refptr<IOBuffer> write_io_buffer =
+ in_flight_write_->GetIOBufferForRemainingData();
+ // We keep |in_flight_write_| alive until OnWriteComplete(), so it's
+ // okay to pass in |write_io_buffer| since the socket won't use it
+ // past OnWriteComplete().
+ return connection_->socket()->Write(
+ write_io_buffer.get(),
+ in_flight_write_->GetRemainingSize(),
+ base::Bind(base::IgnoreResult(&SpdySession::DoWriteLoop),
+ weak_factory_.GetWeakPtr(), WRITE_STATE_DO_WRITE_COMPLETE));
+}
+
+int SpdySession::DoWriteComplete(int result) {
+ DCHECK_NE(availability_state_, STATE_CLOSED);
+
DCHECK_GT(in_flight_write_->GetRemainingSize(), 0u);
last_activity_time_ = base::TimeTicks::Now();
- write_pending_ = false;
if (result < 0) {
+ DCHECK_NE(result, ERR_IO_PENDING);
in_flight_write_.reset();
in_flight_write_frame_type_ = DATA;
in_flight_write_frame_size_ = 0;
in_flight_write_stream_.reset();
CloseSessionOnError(static_cast<Error>(result), "Write error");
- return;
+ DCHECK_EQ(error_on_close_, result);
+ return result;
}
// It should not be possible to have written more bytes than our
@@ -1186,108 +1298,11 @@ void SpdySession::OnWriteComplete(int result) {
}
}
- // Write more data. We're already in a continuation, so we can go
- // ahead and write it immediately (without going back to the message
- // loop).
- WriteSocketLater();
-}
-
-void SpdySession::WriteSocketLater() {
- if (delayed_write_pending_)
- return;
-
- if (!IsConnected())
- return;
-
- delayed_write_pending_ = true;
- base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&SpdySession::WriteSocket, weak_factory_.GetWeakPtr()));
-}
-
-void SpdySession::WriteSocket() {
- // This function should only be called via WriteSocketLater.
- DCHECK(delayed_write_pending_);
- delayed_write_pending_ = false;
-
- // If the socket isn't connected yet, just wait; we'll get called
- // again when the socket connection completes. If the socket is
- // closed, just return.
- if (!IsConnected())
- return;
-
- if (write_pending_) // Another write is in progress still.
- return;
-
- // Loop sending frames until we've sent everything or until the write
- // returns error (or ERR_IO_PENDING).
- DCHECK(buffered_spdy_framer_.get());
- while (true) {
- if (in_flight_write_) {
- DCHECK_GT(in_flight_write_->GetRemainingSize(), 0u);
- } else {
- // Grab the next frame to send.
- SpdyFrameType frame_type = DATA;
- scoped_ptr<SpdyBufferProducer> producer;
- base::WeakPtr<SpdyStream> stream;
- if (!write_queue_.Dequeue(&frame_type, &producer, &stream))
- break;
-
- if (stream.get())
- DCHECK(!stream->IsClosed());
-
- // Activate the stream only when sending the SYN_STREAM frame to
- // guarantee monotonically-increasing stream IDs.
- if (frame_type == SYN_STREAM) {
- if (stream.get() && stream->stream_id() == 0) {
- scoped_ptr<SpdyStream> owned_stream =
- ActivateCreatedStream(stream.get());
- InsertActivatedStream(owned_stream.Pass());
- } else {
- NOTREACHED();
- continue;
- }
- }
-
- in_flight_write_ = producer->ProduceBuffer();
- if (!in_flight_write_) {
- NOTREACHED();
- continue;
- }
- in_flight_write_frame_type_ = frame_type;
- in_flight_write_frame_size_ = in_flight_write_->GetRemainingSize();
- DCHECK_GE(in_flight_write_frame_size_,
- buffered_spdy_framer_->GetFrameMinimumSize());
- in_flight_write_stream_ = stream;
- }
-
- write_pending_ = true;
- // Explicitly store in a scoped_refptr<IOBuffer> to avoid problems
- // with Socket implementations that don't store their IOBuffer
- // argument in a scoped_refptr<IOBuffer> (see crbug.com/232345).
- scoped_refptr<IOBuffer> write_io_buffer =
- in_flight_write_->GetIOBufferForRemainingData();
- // We keep |in_flight_write_| alive until OnWriteComplete(), so
- // it's okay to use GetIOBufferForRemainingData() since the socket
- // doesn't use the IOBuffer past OnWriteComplete().
- int rv = connection_->socket()->Write(
- write_io_buffer.get(),
- in_flight_write_->GetRemainingSize(),
- base::Bind(&SpdySession::OnWriteComplete, weak_factory_.GetWeakPtr()));
- // Avoid persisting |write_io_buffer| past |in_flight_write_|'s
- // lifetime (which will end if OnWriteComplete() is called below).
- write_io_buffer = NULL;
- if (rv == ERR_IO_PENDING)
- break;
-
- // We sent the frame successfully.
- OnWriteComplete(rv);
-
- // TODO(mbelshe): Test this error case. Maybe we should mark the socket
- // as in an error state.
- if (rv < 0)
- break;
- }
+ // This has to go after calling OnFrameWriteComplete() so that if
+ // that ends up calling EnqueueWrite(), it properly avoids posting
+ // another DoWriteLoop task.
+ write_state_ = WRITE_STATE_DO_WRITE;
+ return OK;
}
void SpdySession::CloseAllStreamsAfter(SpdyStreamId last_good_stream_id,
@@ -1359,7 +1374,7 @@ void SpdySession::CloseSessionOnError(Error err,
// to |this|. Hold a reference through this function.
scoped_refptr<SpdySession> self(this);
- DCHECK_LT(err, OK);
+ DCHECK_LT(err, ERR_IO_PENDING);
net_log_.AddEvent(
NetLog::TYPE_SPDY_SESSION_CLOSE,
base::Bind(&NetLogSpdySessionCloseCallback, err, &description));
@@ -1367,12 +1382,12 @@ void SpdySession::CloseSessionOnError(Error err,
// Don't close twice. This can occur because we can have both
// a read and a write outstanding, and each can complete with
// an error.
- if (!IsClosed()) {
+ if (availability_state_ != STATE_CLOSED) {
UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SpdySession.ClosedOnError", -err);
UMA_HISTOGRAM_CUSTOM_COUNTS("Net.SpdySession.BytesRead.OtherErrors",
total_bytes_received_, 1, 100000000, 50);
- state_ = STATE_CLOSED;
- error_ = err;
+ availability_state_ = STATE_CLOSED;
+ error_on_close_ = err;
// TODO(akalin): Move this after CloseAllStreams() once we're
// owned by the pool.
RemoveFromPool();
@@ -1409,7 +1424,7 @@ base::Value* SpdySession::GetInfoAsValue() const {
SSLClientSocket::NextProtoToString(
connection_->socket()->GetNegotiatedProtocol()));
- dict->SetInteger("error", error_);
+ dict->SetInteger("error", error_on_close_);
dict->SetInteger("max_concurrent_streams", max_concurrent_streams_);
dict->SetInteger("streams_initiated_count", streams_initiated_count_);
@@ -1483,8 +1498,19 @@ void SpdySession::EnqueueWrite(RequestPriority priority,
SpdyFrameType frame_type,
scoped_ptr<SpdyBufferProducer> producer,
const base::WeakPtr<SpdyStream>& stream) {
+ if (availability_state_ == STATE_CLOSED)
+ return;
+
+ bool was_idle = write_queue_.IsEmpty();
write_queue_.Enqueue(priority, frame_type, producer.Pass(), stream);
- WriteSocketLater();
+ // We only want to post a task when the queue was just empty *and*
+ // we're not being called from a callback from DoWriteComplete().
+ if (was_idle && write_state_ == WRITE_STATE_DO_WRITE) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(base::IgnoreResult(&SpdySession::DoWriteLoop),
+ weak_factory_.GetWeakPtr(), WRITE_STATE_DO_WRITE, OK));
+ }
}
void SpdySession::InsertCreatedStream(scoped_ptr<SpdyStream> stream) {
@@ -1588,6 +1614,9 @@ ServerBoundCertService* SpdySession::GetServerBoundCertService() const {
}
void SpdySession::OnError(SpdyFramer::SpdyError error_code) {
+ if (availability_state_ == STATE_CLOSED)
+ return;
+
RecordProtocolErrorHistogram(
static_cast<SpdyProtocolErrorDetails>(error_code));
std::string description = base::StringPrintf(
@@ -1597,6 +1626,9 @@ void SpdySession::OnError(SpdyFramer::SpdyError error_code) {
void SpdySession::OnStreamError(SpdyStreamId stream_id,
const std::string& description) {
+ if (availability_state_ == STATE_CLOSED)
+ return;
+
ActiveStreamMap::iterator it = active_streams_.find(stream_id);
if (it == active_streams_.end()) {
// We still want to send a frame to reset the stream even if we
@@ -1613,6 +1645,9 @@ void SpdySession::OnStreamFrameData(SpdyStreamId stream_id,
const char* data,
size_t len,
bool fin) {
+ if (availability_state_ == STATE_CLOSED)
+ return;
+
DCHECK_LT(len, 1u << 24);
if (net_log().IsLoggingAllEvents()) {
net_log().AddEvent(
@@ -1654,6 +1689,9 @@ void SpdySession::OnStreamFrameData(SpdyStreamId stream_id,
}
void SpdySession::OnSettings(bool clear_persisted) {
+ if (availability_state_ == STATE_CLOSED)
+ return;
+
if (clear_persisted)
http_server_properties_->ClearSpdySettings(host_port_pair());
@@ -1668,6 +1706,9 @@ void SpdySession::OnSettings(bool clear_persisted) {
void SpdySession::OnSetting(SpdySettingsIds id,
uint8 flags,
uint32 value) {
+ if (availability_state_ == STATE_CLOSED)
+ return;
+
HandleSetting(id, value);
http_server_properties_->SetSpdySetting(
host_port_pair(),
@@ -1730,6 +1771,12 @@ void SpdySession::OnSynStream(SpdyStreamId stream_id,
bool fin,
bool unidirectional,
const SpdyHeaderBlock& headers) {
+ if (availability_state_ == STATE_CLOSED)
+ return;
+
+ // TODO(akalin): Reset the stream when |availability_state_| ==
+ // STATE_GOING_AWAY.
+
base::Time response_time = base::Time::Now();
base::TimeTicks recv_first_byte_time = base::TimeTicks::Now();
@@ -1891,6 +1938,9 @@ void SpdySession::DeleteExpiredPushedStreams() {
void SpdySession::OnSynReply(SpdyStreamId stream_id,
bool fin,
const SpdyHeaderBlock& headers) {
+ if (availability_state_ == STATE_CLOSED)
+ return;
+
base::Time response_time = base::Time::Now();
base::TimeTicks recv_first_byte_time = base::TimeTicks::Now();
@@ -1927,6 +1977,9 @@ void SpdySession::OnSynReply(SpdyStreamId stream_id,
void SpdySession::OnHeaders(SpdyStreamId stream_id,
bool fin,
const SpdyHeaderBlock& headers) {
+ if (availability_state_ == STATE_CLOSED)
+ return;
+
if (net_log().IsLoggingAllEvents()) {
net_log().AddEvent(
NetLog::TYPE_SPDY_SESSION_RECV_HEADERS,
@@ -1954,6 +2007,9 @@ void SpdySession::OnHeaders(SpdyStreamId stream_id,
void SpdySession::OnRstStream(SpdyStreamId stream_id,
SpdyRstStreamStatus status) {
+ if (availability_state_ == STATE_CLOSED)
+ return;
+
std::string description;
net_log().AddEvent(
NetLog::TYPE_SPDY_SESSION_RST_STREAM,
@@ -1987,6 +2043,9 @@ void SpdySession::OnRstStream(SpdyStreamId stream_id,
void SpdySession::OnGoAway(SpdyStreamId last_accepted_stream_id,
SpdyGoAwayStatus status) {
+ if (availability_state_ == STATE_CLOSED)
+ return;
+
net_log_.AddEvent(NetLog::TYPE_SPDY_SESSION_GOAWAY,
base::Bind(&NetLogSpdyGoAwayCallback,
last_accepted_stream_id,
@@ -1999,6 +2058,9 @@ void SpdySession::OnGoAway(SpdyStreamId last_accepted_stream_id,
}
void SpdySession::OnPing(uint32 unique_id) {
+ if (availability_state_ == STATE_CLOSED)
+ return;
+
net_log_.AddEvent(
NetLog::TYPE_SPDY_SESSION_PING,
base::Bind(&NetLogSpdyPingCallback, unique_id, "received"));
@@ -2027,6 +2089,9 @@ void SpdySession::OnPing(uint32 unique_id) {
void SpdySession::OnWindowUpdate(SpdyStreamId stream_id,
uint32 delta_window_size) {
+ if (availability_state_ == STATE_CLOSED)
+ return;
+
DCHECK_LE(delta_window_size, static_cast<uint32>(kint32max));
net_log_.AddEvent(
NetLog::TYPE_SPDY_SESSION_RECEIVED_WINDOW_UPDATE_FRAME,
@@ -2580,7 +2645,7 @@ void SpdySession::ResumeSendStalledStreams() {
// have to worry about streams being closed, as well as ourselves
// being closed.
- while (!IsClosed() && !IsSendStalled()) {
+ while (availability_state_ != STATE_CLOSED && !IsSendStalled()) {
size_t old_size = 0;
if (DCHECK_IS_ON())
old_size = GetTotalSize(stream_send_unstall_queue_);