taildrop: improve the functionality and reliability of put (#9762)

Changes made:
* Move all HTTP related functionality from taildrop to ipnlocal.
* Add two arguments to taildrop.Manager.PutFile to specify
  an opaque client ID and a resume offset (both unused for now).
* Cleanup the logic of taildrop.Manager.PutFile
  to be easier to follow.
* Implement file conflict handling where duplicate files are renamed
  (e.g., "IMG_1234.jpg" -> "IMG_1234 (2).jpg").
* Implement file de-duplication where "renaming" a partial file
  simply deletes it if it already exists with the same contents.
* Detect conflicting active puts where a second concurrent put
  results in an error.

Updates tailscale/corp#14772

Signed-off-by: Joe Tsai <joetsai@digital-static.net>
Co-authored-by: Rhea Ghosh <rhea@tailscale.com>
This commit is contained in:
Joe Tsai
2023-10-12 09:28:46 -07:00
committed by GitHub
parent 1294b89792
commit 37c646d9d3
7 changed files with 409 additions and 187 deletions
+30 -1
View File
@@ -16,7 +16,7 @@ import (
// Tests "foo.jpg.deleted" marks (for Windows).
func TestDeletedMarkers(t *testing.T) {
dir := t.TempDir()
h := &Handler{Dir: dir}
h := &Manager{Dir: dir}
nothingWaiting := func() {
t.Helper()
@@ -153,3 +153,32 @@ func TestRedactErr(t *testing.T) {
})
}
}
func TestNextFilename(t *testing.T) {
tests := []struct {
in string
want string
want2 string
}{
{"foo", "foo (1)", "foo (2)"},
{"foo(1)", "foo(1) (1)", "foo(1) (2)"},
{"foo.tar", "foo (1).tar", "foo (2).tar"},
{"foo.tar.gz", "foo (1).tar.gz", "foo (2).tar.gz"},
{".bashrc", ".bashrc (1)", ".bashrc (2)"},
{"fizz buzz.torrent", "fizz buzz (1).torrent", "fizz buzz (2).torrent"},
{"rawr 2023.12.15.txt", "rawr 2023.12.15 (1).txt", "rawr 2023.12.15 (2).txt"},
{"IMG_7934.JPEG", "IMG_7934 (1).JPEG", "IMG_7934 (2).JPEG"},
{"my song.mp3", "my song (1).mp3", "my song (2).mp3"},
{"archive.7z", "archive (1).7z", "archive (2).7z"},
{"foo/bar/fizz", "foo/bar/fizz (1)", "foo/bar/fizz (2)"},
}
for _, tt := range tests {
if got := NextFilename(tt.in); got != tt.want {
t.Errorf("NextFilename(%q) = %q, want %q", tt.in, got, tt.want)
}
if got2 := NextFilename(tt.want); got2 != tt.want2 {
t.Errorf("NextFilename(%q) = %q, want %q", tt.want, got2, tt.want2)
}
}
}