diff --git a/okhttp/src/main/java/com/squareup/okhttp/internal/spdy/SpdyConnection.java b/okhttp/src/main/java/com/squareup/okhttp/internal/spdy/SpdyConnection.java index 0b6fa2d5f17b..d3ebee2e31b7 100644 --- a/okhttp/src/main/java/com/squareup/okhttp/internal/spdy/SpdyConnection.java +++ b/okhttp/src/main/java/com/squareup/okhttp/internal/spdy/SpdyConnection.java @@ -24,7 +24,6 @@ import java.net.InetSocketAddress; import java.net.Socket; import java.util.HashMap; -import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; @@ -734,18 +733,19 @@ private void ackSettingsLater(final Settings peerSettings) { @Override public void goAway(int lastGoodStreamId, ErrorCode errorCode, ByteString debugData) { if (debugData.size() > 0) { // TODO: log the debugData } + + // Copy the streams first. We don't want to hold a lock when we call receiveRstStream(). + SpdyStream[] streamsCopy; synchronized (SpdyConnection.this) { + streamsCopy = streams.values().toArray(new SpdyStream[streams.size()]); shutdown = true; + } - // Fail all streams created after the last good stream ID. - for (Iterator> i = streams.entrySet().iterator(); - i.hasNext(); ) { - Map.Entry entry = i.next(); - int streamId = entry.getKey(); - if (streamId > lastGoodStreamId && entry.getValue().isLocallyInitiated()) { - entry.getValue().receiveRstStream(ErrorCode.REFUSED_STREAM); - i.remove(); - } + // Fail all streams created after the last good stream ID. + for (SpdyStream spdyStream : streamsCopy) { + if (spdyStream.getId() > lastGoodStreamId && spdyStream.isLocallyInitiated()) { + spdyStream.receiveRstStream(ErrorCode.REFUSED_STREAM); + removeStream(spdyStream.getId()); } } }