Index: net/spdy/spdy_session.cc |
diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc |
index 9b10d2afc45b5d624a3e6e9253b5b4ed4c22775a..ba8018ca767be4ae1f73d0168e4ec0034f82f192 100644 |
--- a/net/spdy/spdy_session.cc |
+++ b/net/spdy/spdy_session.cc |
@@ -311,6 +311,26 @@ void SpdyStreamRequest::Reset() { |
callback_.Reset(); |
} |
+SpdySession::ActiveStreamInfo::ActiveStreamInfo() |
+ : stream(NULL), |
+ waiting_for_syn_reply(false) {} |
+ |
+SpdySession::ActiveStreamInfo::ActiveStreamInfo(SpdyStream* stream) |
+ : stream(stream), |
+ waiting_for_syn_reply(stream->type() != SPDY_PUSH_STREAM) {} |
+ |
+SpdySession::ActiveStreamInfo::~ActiveStreamInfo() {} |
+ |
+SpdySession::PushedStreamInfo::PushedStreamInfo() : stream_id(0) {} |
+ |
+SpdySession::PushedStreamInfo::PushedStreamInfo( |
+ SpdyStreamId stream_id, |
+ base::TimeTicks creation_time) |
+ : stream_id(stream_id), |
+ creation_time(creation_time) {} |
+ |
+SpdySession::PushedStreamInfo::~PushedStreamInfo() {} |
+ |
SpdySession::SpdySession(const SpdySessionKey& spdy_session_key, |
SpdySessionPool* spdy_session_pool, |
HttpServerProperties* http_server_properties, |
@@ -705,7 +725,7 @@ scoped_ptr<SpdyFrame> SpdySession::CreateSynStream( |
const SpdyHeaderBlock& headers) { |
ActiveStreamMap::const_iterator it = active_streams_.find(stream_id); |
CHECK(it != active_streams_.end()); |
- CHECK_EQ(it->second->stream_id(), stream_id); |
+ CHECK_EQ(it->second.stream->stream_id(), stream_id); |
SendPrefacePingIfNoneInFlight(); |
@@ -772,7 +792,7 @@ scoped_ptr<SpdyBuffer> SpdySession::CreateDataBuffer(SpdyStreamId stream_id, |
SpdyDataFlags flags) { |
ActiveStreamMap::const_iterator it = active_streams_.find(stream_id); |
CHECK(it != active_streams_.end()); |
- SpdyStream* stream = it->second; |
+ SpdyStream* stream = it->second.stream; |
CHECK_EQ(stream->stream_id(), stream_id); |
if (len < 0) { |
@@ -900,7 +920,7 @@ void SpdySession::CloseActiveStream(SpdyStreamId stream_id, int status) { |
if (status != OK) { |
for (PushedStreamMap::iterator it = unclaimed_pushed_streams_.begin(); |
it != unclaimed_pushed_streams_.end(); ++it) { |
- if (stream_id == it->second.first->stream_id()) { |
+ if (stream_id == it->second.stream_id) { |
unclaimed_pushed_streams_.erase(it); |
break; |
} |
@@ -912,7 +932,7 @@ void SpdySession::CloseActiveStream(SpdyStreamId stream_id, int status) { |
if (it == active_streams_.end()) |
return; |
- scoped_ptr<SpdyStream> owned_stream(it->second); |
+ scoped_ptr<SpdyStream> owned_stream(it->second.stream); |
active_streams_.erase(it); |
DeleteStream(owned_stream.Pass(), status); |
@@ -1240,7 +1260,7 @@ void SpdySession::CloseAllStreamsAfter(SpdyStreamId last_good_stream_id, |
break; |
SpdyStreamId stream_id = it->first; |
streams_abandoned_count_++; |
- LogAbandonedStream(it->second, status); |
+ LogAbandonedStream(it->second.stream, status); |
CloseActiveStream(stream_id, status); |
} |
@@ -1436,7 +1456,8 @@ void SpdySession::InsertActivatedStream(scoped_ptr<SpdyStream> stream) { |
SpdyStreamId stream_id = stream->stream_id(); |
DCHECK_NE(stream_id, 0u); |
std::pair<ActiveStreamMap::iterator, bool> result = |
- active_streams_.insert(std::make_pair(stream_id, stream.get())); |
+ active_streams_.insert( |
+ std::make_pair(stream_id, ActiveStreamInfo(stream.get()))); |
if (result.second) { |
ignore_result(stream.release()); |
} else { |
@@ -1475,14 +1496,21 @@ base::WeakPtr<SpdyStream> SpdySession::GetActivePushStream( |
base::StatsCounter used_push_streams("spdy.claimed_push_streams"); |
PushedStreamMap::iterator it = unclaimed_pushed_streams_.find(path); |
- if (it != unclaimed_pushed_streams_.end()) { |
- net_log_.AddEvent(NetLog::TYPE_SPDY_STREAM_ADOPTED_PUSH_STREAM); |
- base::WeakPtr<SpdyStream> stream = it->second.first->GetWeakPtr(); |
- unclaimed_pushed_streams_.erase(it); |
- used_push_streams.Increment(); |
- return stream; |
+ if (it == unclaimed_pushed_streams_.end()) |
+ return base::WeakPtr<SpdyStream>(); |
+ |
+ SpdyStreamId stream_id = it->second.stream_id; |
+ unclaimed_pushed_streams_.erase(it); |
+ |
+ ActiveStreamMap::iterator it2 = active_streams_.find(stream_id); |
+ if (it2 == active_streams_.end()) { |
+ NOTREACHED(); |
+ return base::WeakPtr<SpdyStream>(); |
} |
- return base::WeakPtr<SpdyStream>(); |
+ |
+ net_log_.AddEvent(NetLog::TYPE_SPDY_STREAM_ADOPTED_PUSH_STREAM); |
+ used_push_streams.Increment(); |
+ return it2->second.stream->GetWeakPtr(); |
} |
bool SpdySession::GetSSLInfo(SSLInfo* ssl_info, |
@@ -1521,7 +1549,7 @@ void SpdySession::OnStreamError(SpdyStreamId stream_id, |
// We still want to reset the stream even if we don't know anything |
// about it. |
RequestPriority priority = |
- (it == active_streams_.end()) ? IDLE : it->second->priority(); |
+ (it == active_streams_.end()) ? IDLE : it->second.stream->priority(); |
ResetStream(stream_id, priority, RST_STREAM_PROTOCOL_ERROR, description); |
} |
@@ -1542,6 +1570,17 @@ void SpdySession::OnStreamFrameData(SpdyStreamId stream_id, |
if (it == active_streams_.end()) |
return; |
+ SpdyStream* stream = it->second.stream; |
+ CHECK_EQ(stream->stream_id(), stream_id); |
+ |
+ if (it->second.waiting_for_syn_reply) { |
+ const std::string& error = "Data received before SYN_REPLY."; |
+ stream->LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error); |
+ ResetStream(stream_id, stream->priority(), |
+ RST_STREAM_PROTOCOL_ERROR, error); |
+ return; |
+ } |
+ |
scoped_ptr<SpdyBuffer> buffer; |
if (data) { |
DCHECK_GT(len, 0u); |
@@ -1556,7 +1595,7 @@ void SpdySession::OnStreamFrameData(SpdyStreamId stream_id, |
} else { |
DCHECK_EQ(len, 0u); |
} |
- it->second->OnDataReceived(buffer.Pass()); |
+ stream->OnDataReceived(buffer.Pass()); |
} |
void SpdySession::OnSettings(bool clear_persisted) { |
@@ -1686,7 +1725,7 @@ void SpdySession::OnSynStream(SpdyStreamId stream_id, |
associated_stream_id)); |
} |
} else { |
- GURL associated_url(associated_it->second->GetUrl()); |
+ GURL associated_url(associated_it->second.stream->GetUrl()); |
if (associated_url.GetOrigin() != gurl.GetOrigin()) { |
ResetStream(stream_id, request_priority, RST_STREAM_REFUSED_STREAM, |
base::StringPrintf( |
@@ -1712,8 +1751,7 @@ void SpdySession::OnSynStream(SpdyStreamId stream_id, |
stream->set_stream_id(stream_id); |
DeleteExpiredPushedStreams(); |
- unclaimed_pushed_streams_[url] = |
- std::pair<SpdyStream*, base::TimeTicks>(stream.get(), time_func_()); |
+ unclaimed_pushed_streams_[url] = PushedStreamInfo(stream_id, time_func_()); |
stream->set_response_received(); |
InsertActivatedStream(stream.Pass()); |
@@ -1725,7 +1763,7 @@ void SpdySession::OnSynStream(SpdyStreamId stream_id, |
} |
// Parse the headers. |
- if (!Respond(headers, it->second)) |
+ if (!Respond(headers, it->second.stream)) |
return; |
base::StatsCounter push_requests("spdy.pushed_streams"); |
@@ -1740,27 +1778,29 @@ void SpdySession::DeleteExpiredPushedStreams() { |
if (time_func_() < next_unclaimed_push_stream_sweep_time_) |
return; |
- // Delete old streams. |
+ // Gather old streams to delete. |
base::TimeTicks minimum_freshness = time_func_() - |
base::TimeDelta::FromSeconds(kMinPushedStreamLifetimeSeconds); |
- PushedStreamMap::iterator it; |
- for (it = unclaimed_pushed_streams_.begin(); |
- it != unclaimed_pushed_streams_.end(); ) { |
- SpdyStream* stream = it->second.first; |
- base::TimeTicks creation_time = it->second.second; |
- // CloseActiveStream() will invalidate the current iterator, so |
- // move to next. |
- ++it; |
- if (minimum_freshness > creation_time) { |
- base::StatsCounter abandoned_push_streams( |
- "spdy.abandoned_push_streams"); |
- base::StatsCounter abandoned_streams("spdy.abandoned_streams"); |
- abandoned_push_streams.Increment(); |
- abandoned_streams.Increment(); |
- streams_abandoned_count_++; |
- CloseActiveStream(stream->stream_id(), ERR_INVALID_SPDY_STREAM); |
- } |
+ std::vector<SpdyStreamId> streams_to_close; |
+ for (PushedStreamMap::iterator it = unclaimed_pushed_streams_.begin(); |
+ it != unclaimed_pushed_streams_.end(); ++it) { |
+ if (minimum_freshness > it->second.creation_time) |
+ streams_to_close.push_back(it->second.stream_id); |
+ } |
+ |
+ for (std::vector<SpdyStreamId>::const_iterator it = streams_to_close.begin(); |
+ it != streams_to_close.end(); ++it) { |
+ base::StatsCounter abandoned_push_streams( |
+ "spdy.abandoned_push_streams"); |
+ base::StatsCounter abandoned_streams("spdy.abandoned_streams"); |
+ abandoned_push_streams.Increment(); |
+ abandoned_streams.Increment(); |
+ streams_abandoned_count_++; |
+ // CloseActiveStream() will remove the stream from |
+ // |unclaimed_pushed_streams_|. |
+ CloseActiveStream(*it, ERR_INVALID_SPDY_STREAM); |
} |
+ |
next_unclaimed_push_stream_sweep_time_ = time_func_() + |
base::TimeDelta::FromSeconds(kMinPushedStreamLifetimeSeconds); |
} |
@@ -1782,17 +1822,19 @@ void SpdySession::OnSynReply(SpdyStreamId stream_id, |
return; |
} |
- SpdyStream* stream = it->second; |
+ SpdyStream* stream = it->second.stream; |
CHECK_EQ(stream->stream_id(), stream_id); |
- if (stream->response_received()) { |
- stream->LogStreamError(ERR_SYN_REPLY_NOT_RECEIVED, |
- "Received duplicate SYN_REPLY for stream."); |
- RecordProtocolErrorHistogram(PROTOCOL_ERROR_SYN_REPLY_NOT_RECEIVED); |
Ryan Hamilton
2013/06/21 15:35:37
Did this get lost or is it called by LogStreamErro
akalin
2013/06/21 18:30:44
Called by ResetStream
|
- CloseActiveStream(stream->stream_id(), ERR_SPDY_PROTOCOL_ERROR); |
+ if (!it->second.waiting_for_syn_reply) { |
+ const std::string& error = |
+ "Received duplicate SYN_REPLY for stream."; |
+ stream->LogStreamError(ERR_SPDY_PROTOCOL_ERROR, error); |
+ ResetStream(stream_id, stream->priority(), |
+ RST_STREAM_STREAM_IN_USE, error); |
return; |
} |
stream->set_response_received(); |
+ it->second.waiting_for_syn_reply = false; |
Respond(headers, stream); |
} |
@@ -1815,9 +1857,10 @@ void SpdySession::OnHeaders(SpdyStreamId stream_id, |
return; |
} |
- CHECK_EQ(it->second->stream_id(), stream_id); |
+ SpdyStream* stream = it->second.stream; |
+ CHECK_EQ(stream->stream_id(), stream_id); |
- int rv = it->second->OnHeaders(headers); |
+ int rv = stream->OnHeaders(headers); |
if (rv < 0) { |
DCHECK_NE(rv, ERR_IO_PENDING); |
CloseActiveStream(stream_id, rv); |
@@ -1839,16 +1882,16 @@ void SpdySession::OnRstStream(SpdyStreamId stream_id, |
return; |
} |
- CHECK_EQ(it->second->stream_id(), stream_id); |
+ CHECK_EQ(it->second.stream->stream_id(), stream_id); |
if (status == 0) { |
- it->second->OnDataReceived(scoped_ptr<SpdyBuffer>()); |
+ it->second.stream->OnDataReceived(scoped_ptr<SpdyBuffer>()); |
} else if (status == RST_STREAM_REFUSED_STREAM) { |
CloseActiveStream(stream_id, ERR_SPDY_SERVER_REFUSED_STREAM); |
} else { |
RecordProtocolErrorHistogram( |
PROTOCOL_ERROR_RST_STREAM_FOR_NON_ACTIVE_STREAM); |
- it->second->LogStreamError( |
+ it->second.stream->LogStreamError( |
ERR_SPDY_PROTOCOL_ERROR, |
base::StringPrintf("SPDY stream closed with status: %d", status)); |
// TODO(mbelshe): Map from Spdy-protocol errors to something sensical. |
@@ -1937,13 +1980,16 @@ void SpdySession::OnWindowUpdate(SpdyStreamId stream_id, |
ActiveStreamMap::const_iterator it = active_streams_.find(stream_id); |
if (it == active_streams_.end()) { |
- // TODO(akalin): Record an error and close the session. |
+ // NOTE: it may just be that the stream was cancelled. |
LOG(WARNING) << "Received WINDOW_UPDATE for invalid stream " << stream_id; |
return; |
} |
+ SpdyStream* stream = it->second.stream; |
+ CHECK_EQ(stream->stream_id(), stream_id); |
+ |
if (delta_window_size < 1u) { |
- ResetStream(stream_id, it->second->priority(), |
+ ResetStream(stream_id, it->second.stream->priority(), |
RST_STREAM_FLOW_CONTROL_ERROR, |
base::StringPrintf( |
"Received WINDOW_UPDATE with an invalid " |
@@ -1951,8 +1997,9 @@ void SpdySession::OnWindowUpdate(SpdyStreamId stream_id, |
return; |
} |
- CHECK_EQ(it->second->stream_id(), stream_id); |
- it->second->IncreaseSendWindowSize(static_cast<int32>(delta_window_size)); |
+ CHECK_EQ(it->second.stream->stream_id(), stream_id); |
+ it->second.stream->IncreaseSendWindowSize( |
+ static_cast<int32>(delta_window_size)); |
} |
} |
@@ -1961,8 +2008,9 @@ void SpdySession::SendStreamWindowUpdate(SpdyStreamId stream_id, |
CHECK_GE(flow_control_state_, FLOW_CONTROL_STREAM); |
ActiveStreamMap::const_iterator it = active_streams_.find(stream_id); |
CHECK(it != active_streams_.end()); |
- CHECK_EQ(it->second->stream_id(), stream_id); |
- SendWindowUpdateFrame(stream_id, delta_window_size, it->second->priority()); |
+ CHECK_EQ(it->second.stream->stream_id(), stream_id); |
+ SendWindowUpdateFrame( |
+ stream_id, delta_window_size, it->second.stream->priority()); |
} |
void SpdySession::SendInitialSettings() { |
@@ -2061,7 +2109,7 @@ void SpdySession::UpdateStreamsSendWindowSize(int32 delta_window_size) { |
DCHECK_GE(flow_control_state_, FLOW_CONTROL_STREAM); |
for (ActiveStreamMap::iterator it = active_streams_.begin(); |
it != active_streams_.end(); ++it) { |
- it->second->AdjustSendWindowSize(delta_window_size); |
+ it->second.stream->AdjustSendWindowSize(delta_window_size); |
} |
for (CreatedStreamSet::const_iterator it = created_streams_.begin(); |
@@ -2090,7 +2138,7 @@ void SpdySession::SendWindowUpdateFrame(SpdyStreamId stream_id, |
CHECK_GE(flow_control_state_, FLOW_CONTROL_STREAM); |
ActiveStreamMap::const_iterator it = active_streams_.find(stream_id); |
if (it != active_streams_.end()) { |
- CHECK_EQ(it->second->stream_id(), stream_id); |
+ CHECK_EQ(it->second.stream->stream_id(), stream_id); |
} else { |
CHECK_EQ(flow_control_state_, FLOW_CONTROL_STREAM_AND_SESSION); |
CHECK_EQ(stream_id, kSessionFlowControlStreamId); |
@@ -2444,7 +2492,7 @@ void SpdySession::ResumeSendStalledStreams() { |
// to its own send window) but that's okay -- it'll then be |
// resumed once its send window increases. |
if (it != active_streams_.end()) |
- it->second->PossiblyResumeIfSendStalled(); |
+ it->second.stream->PossiblyResumeIfSendStalled(); |
// The size should decrease unless we got send-stalled again. |
if (!IsSendStalled()) |