accounting: stop --max-transfer overshoot in Account.WriteTo
Account.WriteTo wrote each buffer to the destination in full before trimming the byte count for --max-transfer, so up to one buffer past the limit could reach the wire and go unaccounted. This matters now that NoCloser forwards WriteTo. Truncate the write to the remaining allowance before writing.
This commit is contained in:
@@ -521,9 +521,17 @@ type accountWriteTo struct {
|
|||||||
func (awt *accountWriteTo) Write(p []byte) (n int, err error) {
|
func (awt *accountWriteTo) Write(p []byte) (n int, err error) {
|
||||||
bytesUntilLimit, err := awt.acc.checkReadBefore()
|
bytesUntilLimit, err := awt.acc.checkReadBefore()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
// Truncate the write to the transfer limit
|
||||||
|
truncated := int64(len(p)) > bytesUntilLimit
|
||||||
|
if truncated {
|
||||||
|
p = p[:bytesUntilLimit]
|
||||||
|
}
|
||||||
n, err = awt.w.Write(p)
|
n, err = awt.w.Write(p)
|
||||||
n, err = awt.acc.checkReadAfter(bytesUntilLimit, n, err)
|
n, err = awt.acc.checkReadAfter(bytesUntilLimit, n, err)
|
||||||
awt.acc.accountRead(n)
|
awt.acc.accountRead(n)
|
||||||
|
if truncated && err == nil {
|
||||||
|
err = ErrorMaxTransferLimitReachedFatal
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -321,6 +321,8 @@ func TestAccountMaxTransferWriteTo(t *testing.T) {
|
|||||||
n, err := acc.WriteTo(&b)
|
n, err := acc.WriteTo(&b)
|
||||||
assert.Equal(t, int64(15), n)
|
assert.Equal(t, int64(15), n)
|
||||||
assert.Equal(t, ErrorMaxTransferLimitReachedFatal, err)
|
assert.Equal(t, ErrorMaxTransferLimitReachedFatal, err)
|
||||||
|
// Nothing past the limit must reach the writer
|
||||||
|
assert.Equal(t, 15, b.Len())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAccountReadCtx(t *testing.T) {
|
func TestAccountReadCtx(t *testing.T) {
|
||||||
|
|||||||
Reference in New Issue
Block a user