From 52424d0e8cddd38f999314ded22560385444f0c0 Mon Sep 17 00:00:00 2001 From: 0div Date: Fri, 4 Oct 2024 20:02:56 +0200 Subject: [PATCH 1/5] Small tweak to allow empty path string in file upload --- packages/envd/internal/api/upload.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/envd/internal/api/upload.go b/packages/envd/internal/api/upload.go index f6ce8619f..973bf7761 100644 --- a/packages/envd/internal/api/upload.go +++ b/packages/envd/internal/api/upload.go @@ -110,7 +110,7 @@ func processFile(r *http.Request, path string, part *multipart.Part, user *user. func resolvePath(part *multipart.Part, paths *UploadSuccess, u *user.User, params PostFilesParams) (string, error) { var pathToResolve string - if params.Path != nil { + if params.Path != nil && *params.Path != "" { pathToResolve = *params.Path } else { pathToResolve = part.FileName() @@ -142,6 +142,7 @@ func resolvePath(part *multipart.Part, paths *UploadSuccess, u *user.User, param return filePath, nil } + func (a *API) PostFiles(w http.ResponseWriter, r *http.Request, params PostFilesParams) { defer r.Body.Close() From de2f292a2fceecec3acd980926e79ef191b884bf Mon Sep 17 00:00:00 2001 From: 0div Date: Tue, 8 Oct 2024 17:16:32 +0200 Subject: [PATCH 2/5] create multipart wrapper to access full file path --- packages/envd/internal/api/upload.go | 8 ++++- packages/envd/internal/utils/multipart.go | 41 +++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 packages/envd/internal/utils/multipart.go diff --git a/packages/envd/internal/api/upload.go b/packages/envd/internal/api/upload.go index 973bf7761..dc8c5d65d 100644 --- a/packages/envd/internal/api/upload.go +++ b/packages/envd/internal/api/upload.go @@ -16,6 +16,7 @@ import ( "github.com/e2b-dev/infra/packages/envd/internal/logs" "github.com/e2b-dev/infra/packages/envd/internal/permissions" + "github.com/e2b-dev/infra/packages/envd/internal/utils" ) func freeDiskSpace(path string) (free uint64, err error) { @@ -113,7 +114,12 @@ func resolvePath(part *multipart.Part, paths *UploadSuccess, u *user.User, param if params.Path != nil && *params.Path != "" { pathToResolve = *params.Path } else { - pathToResolve = part.FileName() + var err error + customPart := utils.NewCustomPart(part) + pathToResolve, err = customPart.FileName() + if err != nil { + return "", fmt.Errorf("error getting multipart custom part file name: %w", err) + } } filePath, err := permissions.ExpandAndResolve(pathToResolve, u) diff --git a/packages/envd/internal/utils/multipart.go b/packages/envd/internal/utils/multipart.go new file mode 100644 index 000000000..9829aaeb2 --- /dev/null +++ b/packages/envd/internal/utils/multipart.go @@ -0,0 +1,41 @@ +package utils + +import ( + "errors" + "mime" + "mime/multipart" +) + +// CustomPart is a wrapper around multipart.Part that overloads the FileName method +type CustomPart struct { + *multipart.Part +} + +// FileName returns the filename parameter of the Part's Content-Disposition header. +// This method overrides the original FileName method to return the full filename +// without using filepath.Base. +func (p *CustomPart) FileName() (string, error) { + dispositionParams, err := p.parseContentDisposition() + if err != nil { + return "", err + } + filename, ok := dispositionParams["filename"] + if !ok { + return "", errors.New("filename not found in Content-Disposition header") + } + return filename, nil +} + +func (p *CustomPart) parseContentDisposition() (map[string]string, error) { + v := p.Header.Get("Content-Disposition") + _, dispositionParams, err := mime.ParseMediaType(v) + if err != nil { + return nil, err + } + return dispositionParams, nil +} + +// NewCustomPart creates a new CustomPart from a multipart.Part +func NewCustomPart(part *multipart.Part) *CustomPart { + return &CustomPart{Part: part} +} From dd7c9d3263f4c3519a67e1cfa765c5a549bc40c4 Mon Sep 17 00:00:00 2001 From: 0div Date: Tue, 8 Oct 2024 17:29:09 +0200 Subject: [PATCH 3/5] remove unnecessary empty path param string check --- packages/envd/internal/api/upload.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/envd/internal/api/upload.go b/packages/envd/internal/api/upload.go index dc8c5d65d..8fc21e30d 100644 --- a/packages/envd/internal/api/upload.go +++ b/packages/envd/internal/api/upload.go @@ -111,7 +111,7 @@ func processFile(r *http.Request, path string, part *multipart.Part, user *user. func resolvePath(part *multipart.Part, paths *UploadSuccess, u *user.User, params PostFilesParams) (string, error) { var pathToResolve string - if params.Path != nil && *params.Path != "" { + if params.Path != nil { pathToResolve = *params.Path } else { var err error From e955d7cf4a11981f6496d2cbe50923376691f550 Mon Sep 17 00:00:00 2001 From: 0div Date: Wed, 9 Oct 2024 11:31:09 +0200 Subject: [PATCH 4/5] create seperate multipart Part method to get file name with path --- packages/envd/internal/api/upload.go | 2 +- packages/envd/internal/utils/multipart.go | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/envd/internal/api/upload.go b/packages/envd/internal/api/upload.go index 8fc21e30d..c3dbca2da 100644 --- a/packages/envd/internal/api/upload.go +++ b/packages/envd/internal/api/upload.go @@ -116,7 +116,7 @@ func resolvePath(part *multipart.Part, paths *UploadSuccess, u *user.User, param } else { var err error customPart := utils.NewCustomPart(part) - pathToResolve, err = customPart.FileName() + pathToResolve, err = customPart.FileNameWithPath() if err != nil { return "", fmt.Errorf("error getting multipart custom part file name: %w", err) } diff --git a/packages/envd/internal/utils/multipart.go b/packages/envd/internal/utils/multipart.go index 9829aaeb2..8088d6588 100644 --- a/packages/envd/internal/utils/multipart.go +++ b/packages/envd/internal/utils/multipart.go @@ -11,10 +11,10 @@ type CustomPart struct { *multipart.Part } -// FileName returns the filename parameter of the Part's Content-Disposition header. -// This method overrides the original FileName method to return the full filename +// FileNameWithPath returns the filename parameter of the Part's Content-Disposition header. +// This method overrides the original FileNameWithPath method to return the full filename // without using filepath.Base. -func (p *CustomPart) FileName() (string, error) { +func (p *CustomPart) FileNameWithPath() (string, error) { dispositionParams, err := p.parseContentDisposition() if err != nil { return "", err From 5b7124baad832bc16c7a41dbad27b13bb6694959 Mon Sep 17 00:00:00 2001 From: 0div Date: Wed, 9 Oct 2024 11:33:10 +0200 Subject: [PATCH 5/5] update comment --- packages/envd/internal/utils/multipart.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/envd/internal/utils/multipart.go b/packages/envd/internal/utils/multipart.go index 8088d6588..dc757f709 100644 --- a/packages/envd/internal/utils/multipart.go +++ b/packages/envd/internal/utils/multipart.go @@ -12,8 +12,8 @@ type CustomPart struct { } // FileNameWithPath returns the filename parameter of the Part's Content-Disposition header. -// This method overrides the original FileNameWithPath method to return the full filename -// without using filepath.Base. +// This method borrows from the original FileName method implementation but returns the full +// filename without using `filepath.Base`. func (p *CustomPart) FileNameWithPath() (string, error) { dispositionParams, err := p.parseContentDisposition() if err != nil {