Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(565)

Unified Diff: net/quic/quic_session.cc

Issue 23587004: If the stream is being closed locally (for example in the case of a (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix tests Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « net/quic/quic_session.h ('k') | net/quic/quic_session_test.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/quic/quic_session.cc
diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc
index aa83ab0cf0d60be59d3134f6cb8251bbb78c6b45..8f6403f08897f702d03ae3187a6bc081a084278f 100644
--- a/net/quic/quic_session.cc
+++ b/net/quic/quic_session.cc
@@ -18,6 +18,7 @@ using std::vector;
namespace net {
const size_t kMaxPrematurelyClosedStreamsTracked = 20;
+const size_t kMaxZombieStreams = 20;
#define ENDPOINT (is_server_ ? "Server: " : " Client: ")
@@ -133,9 +134,19 @@ bool QuicSession::OnPacket(const IPEndPoint& self_address,
}
for (size_t i = 0; i < frames.size(); ++i) {
- ReliableQuicStream* stream = GetStream(frames[i].stream_id);
- if (stream) {
- stream->OnStreamFrame(frames[i]);
+ QuicStreamId stream_id = frames[i].stream_id;
+ ReliableQuicStream* stream = GetStream(stream_id);
+ if (!stream) {
+ continue;
+ }
+ stream->OnStreamFrame(frames[i]);
+
+ // If the stream had been prematurely closed, and the
+ // headers are now decompressed, then we are finally finished
+ // with this stream.
+ if (ContainsKey(zombie_streams_, stream_id) &&
+ stream->headers_decompressed()) {
+ CloseZombieStream(stream_id);
}
}
@@ -162,6 +173,16 @@ void QuicSession::OnRstStream(const QuicRstStreamFrame& frame) {
if (!stream) {
return; // Errors are handled by GetStream.
}
+ if (ContainsKey(zombie_streams_, stream->id())) {
+ // If this was a zombie stream then we close it out now.
+ CloseZombieStream(stream->id());
+ // However, since the headers still have not been decompressed, we want to
+ // mark it a prematurely closed so that if we ever receive frames
+ // for this stream we can close the connection.
+ DCHECK(!stream->headers_decompressed());
+ AddPrematurelyClosedStream(frame.stream_id);
+ return;
+ }
stream->OnStreamReset(frame.error_code);
}
@@ -171,6 +192,7 @@ void QuicSession::OnGoAway(const QuicGoAwayFrame& frame) {
}
void QuicSession::ConnectionClose(QuicErrorCode error, bool from_peer) {
+ DCHECK(!connection_->connected());
if (error_ == QUIC_NO_ERROR) {
error_ = error;
}
@@ -221,7 +243,7 @@ QuicConsumedData QuicSession::WriteData(QuicStreamId id,
void QuicSession::SendRstStream(QuicStreamId id,
QuicRstStreamErrorCode error) {
connection_->SendRstStream(id, error);
- CloseStream(id);
+ CloseStreamInner(id, true);
}
void QuicSession::SendGoAway(QuicErrorCode error_code, const string& reason) {
@@ -230,6 +252,11 @@ void QuicSession::SendGoAway(QuicErrorCode error_code, const string& reason) {
}
void QuicSession::CloseStream(QuicStreamId stream_id) {
+ CloseStreamInner(stream_id, false);
+}
+
+void QuicSession::CloseStreamInner(QuicStreamId stream_id,
+ bool locally_reset) {
DLOG(INFO) << ENDPOINT << "Closing stream " << stream_id;
ReliableStreamMap::iterator it = stream_map_.find(stream_id);
@@ -238,18 +265,62 @@ void QuicSession::CloseStream(QuicStreamId stream_id) {
return;
}
ReliableQuicStream* stream = it->second;
- if (!stream->headers_decompressed()) {
- if (prematurely_closed_streams_.size() ==
- kMaxPrematurelyClosedStreamsTracked) {
- prematurely_closed_streams_.erase(prematurely_closed_streams_.begin());
+ if (connection_->connected() && !stream->headers_decompressed()) {
+ // If the stream is being closed locally (for example a client cancelling
+ // a request before receiving the response) then we need to make sure that
+ // we keep the stream alive long enough to process any response or
+ // RST_STREAM frames.
+ if (locally_reset && !is_server_) {
+ AddZombieStream(stream_id);
+ return;
}
- prematurely_closed_streams_.insert(make_pair(stream->id(), true));
+
+ // This stream has been closed before the headers were decompressed.
+ // This might cause problems with head of line blocking of headers.
+ // If the peer sent headers which were lost but we now close the stream
+ // we will never be able to decompress headers for other streams.
+ // To deal with this, we keep track of streams which have been closed
+ // prematurely. If we ever receive data frames for this steam, then we
+ // know there actually has been a problem and we close the connection.
+ AddPrematurelyClosedStream(stream->id());
}
closed_streams_.push_back(it->second);
stream_map_.erase(it);
stream->OnClose();
}
+void QuicSession::AddZombieStream(QuicStreamId stream_id) {
+ if (zombie_streams_.size() == kMaxZombieStreams) {
+ QuicStreamId oldest_zombie_stream_id = zombie_streams_.begin()->first;
+ CloseZombieStream(oldest_zombie_stream_id);
+ // However, since the headers still have not been decompressed, we want to
+ // mark it a prematurely closed so that if we ever receive frames
+ // for this stream we can close the connection.
+ AddPrematurelyClosedStream(oldest_zombie_stream_id);
+ }
+ zombie_streams_.insert(make_pair(stream_id, true));
+}
+
+void QuicSession::CloseZombieStream(QuicStreamId stream_id) {
+ DCHECK(ContainsKey(zombie_streams_, stream_id));
+ zombie_streams_.erase(stream_id);
+ ReliableQuicStream* stream = GetStream(stream_id);
+ if (!stream) {
+ return;
+ }
+ stream_map_.erase(stream_id);
+ stream->OnClose();
+ closed_streams_.push_back(stream);
+}
+
+void QuicSession::AddPrematurelyClosedStream(QuicStreamId stream_id) {
+ if (prematurely_closed_streams_.size() ==
+ kMaxPrematurelyClosedStreamsTracked) {
+ prematurely_closed_streams_.erase(prematurely_closed_streams_.begin());
+ }
+ prematurely_closed_streams_.insert(make_pair(stream_id, true));
+}
+
bool QuicSession::IsEncryptionEstablished() {
return GetCryptoStream()->encryption_established();
}
@@ -376,7 +447,10 @@ bool QuicSession::IsClosedStream(QuicStreamId id) {
if (id == kCryptoStreamId) {
return false;
}
- if (stream_map_.count(id) != 0) {
+ if (ContainsKey(zombie_streams_, id)) {
+ return true;
+ }
+ if (ContainsKey(stream_map_, id)) {
// Stream is active
return false;
}
@@ -392,7 +466,8 @@ bool QuicSession::IsClosedStream(QuicStreamId id) {
}
size_t QuicSession::GetNumOpenStreams() const {
- return stream_map_.size() + implicitly_created_streams_.size();
+ return stream_map_.size() + implicitly_created_streams_.size() -
+ zombie_streams_.size();
}
void QuicSession::MarkWriteBlocked(QuicStreamId id) {
« no previous file with comments | « net/quic/quic_session.h ('k') | net/quic/quic_session_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698