Read reads data from the stream. Read returns as soon as at least one byte of data is available. If the peer closes the stream cleanly, Read returns io.EOF after returning all data sent by the peer. If the peer aborts reads on the stream, Read returns an error wrapping StreamResetCode. It is not
(b []byte)
| 239 | // |
| 240 | // It is not safe to call Read concurrently. |
| 241 | func (s *Stream) Read(b []byte) (n int, err error) { |
| 242 | if s.IsWriteOnly() { |
| 243 | return 0, errors.New("read from write-only stream") |
| 244 | } |
| 245 | |
| 246 | fastPath := false |
| 247 | s.inbufmu.Lock() |
| 248 | if len(s.inbuf) > s.inbufoff { |
| 249 | // Fast path: If s.inbuf contains unread bytes, return them |
| 250 | // immediately. |
| 251 | n = copy(b, s.inbuf[s.inbufoff:]) |
| 252 | s.inbufoff += n |
| 253 | fastPath = true |
| 254 | } |
| 255 | s.inbufmu.Unlock() |
| 256 | if fastPath { |
| 257 | return n, nil |
| 258 | } |
| 259 | |
| 260 | if err := s.ingate.waitAndLock(s.inctx); err != nil { |
| 261 | return 0, err |
| 262 | } |
| 263 | |
| 264 | if s.inbufoff > 0 { |
| 265 | // Discard bytes consumed by the fast path above. |
| 266 | s.in.discardBefore(s.in.start + int64(s.inbufoff)) |
| 267 | s.inbufmu.Lock() |
| 268 | s.inbufoff = 0 |
| 269 | s.inbuf = nil |
| 270 | s.inbufmu.Unlock() |
| 271 | } |
| 272 | |
| 273 | // bytesRead contains the number of bytes of connection-level flow control to return. |
| 274 | // We return flow control for bytes read by this Read call, as well as bytes moved |
| 275 | // to the fast-path read buffer (s.inbuf). |
| 276 | var bytesRead int64 |
| 277 | defer func() { |
| 278 | s.inUnlock() |
| 279 | s.conn.handleStreamBytesReadOffLoop(bytesRead) // must be done with ingate unlocked |
| 280 | }() |
| 281 | if s.inresetcode != -1 { |
| 282 | if s.inresetcode == streamResetByConnClose { |
| 283 | if err := s.conn.finalError(); err != nil { |
| 284 | return 0, err |
| 285 | } |
| 286 | } |
| 287 | return 0, fmt.Errorf("stream reset by peer: %w", StreamErrorCode(s.inresetcode)) |
| 288 | } |
| 289 | if s.inclosed.isSet() { |
| 290 | return 0, errors.New("read from closed stream") |
| 291 | } |
| 292 | if s.insize == s.in.start { |
| 293 | return 0, io.EOF |
| 294 | } |
| 295 | // Getting here indicates the stream contains data to be read. |
| 296 | if len(s.inset) < 1 || s.inset[0].start != 0 || s.inset[0].end <= s.in.start { |
| 297 | panic("BUG: inconsistent input stream state") |
| 298 | } |