in fragmenting_reader.go [256:309]
func (r *fragmentingReader) recvAndParseNextFragment(initial bool) error {
if r.err != nil {
return r.err
}
if r.curFragment != nil {
r.curFragment.done()
}
r.curFragment, r.err = r.receiver.recvNextFragment(initial)
if r.err != nil {
if err, ok := r.err.(errorMessage); ok {
// Serialized system errors are still reported (e.g. latency, trace reporting).
r.err = err.AsSystemError()
r.doneReading(r.err)
}
return r.err
}
// Set checksum, or confirm new checksum is the same type as the prior checksum
if r.checksum == nil {
r.checksum = r.curFragment.checksumType.New()
} else if r.checksum.TypeCode() != r.curFragment.checksumType {
return errMismatchedChecksumTypes
}
// Split fragment into underlying chunks
r.hasMoreFragments = (r.curFragment.flags & hasMoreFragmentsFlag) == hasMoreFragmentsFlag
r.remainingChunks = nil
for r.curFragment.contents.BytesRemaining() > 0 && r.curFragment.contents.Err() == nil {
chunkSize := r.curFragment.contents.ReadUint16()
if chunkSize > uint16(r.curFragment.contents.BytesRemaining()) {
return errChunkExceedsFragmentSize
}
chunkData := r.curFragment.contents.ReadBytes(int(chunkSize))
r.remainingChunks = append(r.remainingChunks, chunkData)
r.checksum.Add(chunkData)
}
if r.curFragment.contents.Err() != nil {
return r.curFragment.contents.Err()
}
// Validate checksums
localChecksum := r.checksum.Sum()
if bytes.Compare(r.curFragment.checksum, localChecksum) != 0 {
r.err = errMismatchedChecksums
return r.err
}
// Pull out the first chunk to act as the current chunk
r.curChunk, r.remainingChunks = r.remainingChunks[0], r.remainingChunks[1:]
return nil
}