void receive(InputStream in, int byteCount) throws IOException { assert (!Thread.holdsLock(SpdyStream.this)); if (byteCount == 0) { return; } int pos; int limit; int firstNewByte; boolean finished; boolean flowControlError; synchronized (SpdyStream.this) { finished = this.finished; pos = this.pos; firstNewByte = this.limit; limit = this.limit; flowControlError = byteCount > buffer.length - available(); } // If the peer sends more data than we can handle, discard it and close the connection. if (flowControlError) { Util.skipByReading(in, byteCount); closeLater(ErrorCode.FLOW_CONTROL_ERROR); return; } // Discard data received after the stream is finished. It's probably a benign race. if (finished) { Util.skipByReading(in, byteCount); return; } // Fill the buffer without holding any locks. First fill [limit..buffer.length) if that // won't overwrite unread data. Then fill [limit..pos). We can't hold a lock, otherwise // writes will be blocked until reads complete. if (pos < limit) { int firstCopyCount = Math.min(byteCount, buffer.length - limit); Util.readFully(in, buffer, limit, firstCopyCount); limit += firstCopyCount; byteCount -= firstCopyCount; if (limit == buffer.length) { limit = 0; } } if (byteCount > 0) { Util.readFully(in, buffer, limit, byteCount); limit += byteCount; } synchronized (SpdyStream.this) { // Update the new limit, and mark the position as readable if necessary. this.limit = limit; if (this.pos == -1) { this.pos = firstNewByte; SpdyStream.this.notifyAll(); } } }