88 "net/http"
99 "strconv"
1010 "strings"
11+ "time"
1112
1213 "github.com/cenkalti/log"
1314)
@@ -49,6 +50,14 @@ func CreateUpload(baseCtx context.Context, token string, filename string, parent
4950
5051func SendFile (ctx context.Context , token string , r io.Reader , location string , offset int64 ) (fileID int64 , crc32 string , err error ) {
5152 log .Debugf ("Sending file %q offset=%d" , location , offset )
53+
54+ ctx , cancel := context .WithCancel (ctx )
55+ defer cancel ()
56+
57+ // Stop upload if speed is too slow.
58+ // Wrap reader so each read call resets the timer that cancels the request on certain duration.
59+ r = & TimerResetReader {r : r , timer : time .AfterFunc (defaultTimeout , cancel )}
60+
5261 req , err := http .NewRequestWithContext (ctx , http .MethodPatch , location , r )
5362 if err != nil {
5463 return
@@ -63,8 +72,6 @@ func SendFile(ctx context.Context, token string, r io.Reader, location string, o
6372 }
6473 defer resp .Body .Close ()
6574
66- // TODO fail upload if stuck
67-
6875 log .Debugln ("Status code:" , resp .StatusCode )
6976 if resp .StatusCode != http .StatusNoContent {
7077 err = fmt .Errorf ("unexpected status: %d" , resp .StatusCode )
@@ -136,3 +143,13 @@ func encodeMetadata(metadata map[string]string) string {
136143 }
137144 return strings .Join (encoded , "," )
138145}
146+
147+ type TimerResetReader struct {
148+ r io.Reader
149+ timer * time.Timer
150+ }
151+
152+ func (r * TimerResetReader ) Read (p []byte ) (int , error ) {
153+ r .timer .Reset (defaultTimeout )
154+ return r .r .Read (p )
155+ }
0 commit comments