diff --git a/.github/workflows/tus-tests.yml b/.github/workflows/tus-tests.yml index 5e6041f48..7fa8818ce 100644 --- a/.github/workflows/tus-tests.yml +++ b/.github/workflows/tus-tests.yml @@ -15,7 +15,7 @@ on: - 'test/tus/**' concurrency: - group: ${{ github.head_ref }}/tus-tests + group: ${{ github.head_ref || github.ref }}/tus-tests cancel-in-progress: true permissions: diff --git a/test/tus/tus_integration_test.go b/test/tus/tus_integration_test.go index b95d36345..db3576f9b 100644 --- a/test/tus/tus_integration_test.go +++ b/test/tus/tus_integration_test.go @@ -36,15 +36,15 @@ type TestCluster struct { func (c *TestCluster) Stop() { if c.filerCmd != nil && c.filerCmd.Process != nil { - c.filerCmd.Process.Kill() + c.filerCmd.Process.Signal(os.Interrupt) c.filerCmd.Wait() } if c.volumeCmd != nil && c.volumeCmd.Process != nil { - c.volumeCmd.Process.Kill() + c.volumeCmd.Process.Signal(os.Interrupt) c.volumeCmd.Wait() } if c.masterCmd != nil && c.masterCmd.Process != nil { - c.masterCmd.Process.Kill() + c.masterCmd.Process.Signal(os.Interrupt) c.masterCmd.Wait() } } diff --git a/weed/server/filer_server_tus_handlers.go b/weed/server/filer_server_tus_handlers.go index 294204696..f4fa5959e 100644 --- a/weed/server/filer_server_tus_handlers.go +++ b/weed/server/filer_server_tus_handlers.go @@ -222,6 +222,12 @@ func (fs *FilerServer) tusPatchHandler(w http.ResponseWriter, r *http.Request, u return } + // TUS requires Content-Length header for PATCH requests + if r.ContentLength < 0 { + http.Error(w, "Content-Length header required", http.StatusBadRequest) + return + } + // Write data bytesWritten, err := fs.tusWriteData(ctx, session, uploadOffset, r.Body, r.ContentLength) if err != nil { @@ -309,12 +315,15 @@ func (fs *FilerServer) tusWriteData(ctx context.Context, session *TusSession, of return 0, fmt.Errorf("create uploader: %w", uploaderErr) } + // Detect MIME type from data + mimeType := http.DetectContentType(buf.Bytes()) + uploadResult, uploadErr, _ := uploader.Upload(ctx, bytes.NewReader(buf.Bytes()), &operation.UploadOption{ UploadUrl: urlLocation, Filename: "", - Cipher: false, + Cipher: fs.option.Cipher, IsInputCompressed: false, - MimeType: "", + MimeType: mimeType, PairMap: nil, Jwt: auth, }) diff --git a/weed/server/filer_server_tus_session.go b/weed/server/filer_server_tus_session.go index e0e811a8c..b0c0885a1 100644 --- a/weed/server/filer_server_tus_session.go +++ b/weed/server/filer_server_tus_session.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "os" + "sort" "time" "github.com/seaweedfs/seaweedfs/weed/filer" @@ -191,26 +192,28 @@ func (fs *FilerServer) completeTusUpload(ctx context.Context, session *TusSessio return fmt.Errorf("upload incomplete: offset=%d, expected=%d", session.Offset, session.Size) } + // Sort chunks by offset to ensure correct order + sort.Slice(session.Chunks, func(i, j int) bool { + return session.Chunks[i].Offset < session.Chunks[j].Offset + }) + // Assemble file chunks in order var fileChunks []*filer_pb.FileChunk - var offset int64 = 0 for _, chunk := range session.Chunks { fid, fidErr := filer_pb.ToFileIdObject(chunk.FileId) if fidErr != nil { - glog.Warningf("Invalid file ID %s: %v", chunk.FileId, fidErr) - continue + return fmt.Errorf("invalid file ID %s at offset %d: %w", chunk.FileId, chunk.Offset, fidErr) } fileChunk := &filer_pb.FileChunk{ FileId: chunk.FileId, - Offset: offset, + Offset: chunk.Offset, Size: uint64(chunk.Size), ModifiedTsNs: chunk.UploadAt, Fid: fid, } fileChunks = append(fileChunks, fileChunk) - offset += chunk.Size } // Determine content type from metadata