Skip to content

Commit

Permalink
handler: Fix data race in bodyReader when stopping upload
Browse files Browse the repository at this point in the history
  • Loading branch information
Acconut committed Oct 4, 2024
1 parent a576b7f commit 9b68f9f
Showing 1 changed file with 19 additions and 4 deletions.
23 changes: 19 additions & 4 deletions pkg/handler/body_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"net/http"
"os"
"strings"
"sync"
"sync/atomic"
"time"
)
Expand All @@ -28,8 +29,11 @@ type bodyReader struct {
bytesCounter int64
ctx *httpContext
reader io.ReadCloser
err error
onReadDone func()

// lock protects concurrent access to err.
lock sync.RWMutex
err error
}

func newBodyReader(c *httpContext, maxSize int64) *bodyReader {
Expand All @@ -41,7 +45,10 @@ func newBodyReader(c *httpContext, maxSize int64) *bodyReader {
}

func (r *bodyReader) Read(b []byte) (int, error) {
if r.err != nil {
r.lock.RLock()
hasErrored := r.err != nil
r.lock.RUnlock()
if hasErrored {
return 0, io.EOF
}

Expand Down Expand Up @@ -99,28 +106,36 @@ func (r *bodyReader) Read(b []byte) (int, error) {

// Other errors are stored for retrival with hasError, but is not returned
// to the consumer. We do not overwrite an error if it has been set already.
r.lock.Lock()
if r.err == nil {
r.err = err
}
r.lock.Unlock()
}

return n, nil
}

func (r bodyReader) hasError() error {

Check failure on line 119 in pkg/handler/body_reader.go

View workflow job for this annotation

GitHub Actions / test (stable, windows-latest)

hasError passes lock by value: github.com/tus/tusd/v2/pkg/handler.bodyReader contains sync.RWMutex

Check failure on line 119 in pkg/handler/body_reader.go

View workflow job for this annotation

GitHub Actions / test (stable, windows-latest)

hasError passes lock by value: github.com/tus/tusd/v2/pkg/handler.bodyReader contains sync.RWMutex

Check failure on line 119 in pkg/handler/body_reader.go

View workflow job for this annotation

GitHub Actions / test (oldstable, windows-latest)

hasError passes lock by value: github.com/tus/tusd/v2/pkg/handler.bodyReader contains sync.RWMutex
if r.err == io.EOF {
r.lock.RLock()
err := r.err
r.lock.RUnlock()

if err == io.EOF {
return nil
}

return r.err
return err
}

func (r *bodyReader) bytesRead() int64 {
return atomic.LoadInt64(&r.bytesCounter)
}

func (r *bodyReader) closeWithError(err error) {
r.lock.Lock()
r.err = err
r.lock.Unlock()

// SetReadDeadline with the current time causes concurrent reads to the body to time out,
// so the body will be closed sooner with less delay.
Expand Down

0 comments on commit 9b68f9f

Please sign in to comment.