diff --git a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/utils.ts b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/utils.ts index 7e78e68b8d..3da4180894 100644 --- a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/utils.ts +++ b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/utils.ts @@ -32,7 +32,6 @@ export const download = ( } var req = new XMLHttpRequest(); - req.open("GET", path, true); req.addEventListener( "progress", @@ -52,9 +51,9 @@ export const download = ( const rspHeader = req.getResponseHeader("Content-Disposition"); let filename = "download"; - if (rspHeader) { - filename = rspHeader.split('"')[1]; + let rspHeaderDecoded = decodeURIComponent(rspHeader); + filename = rspHeaderDecoded.split('"')[1]; } if (completeCallback) { diff --git a/restapi/user_objects.go b/restapi/user_objects.go index ef997f73cb..2885d2a017 100644 --- a/restapi/user_objects.go +++ b/restapi/user_objects.go @@ -24,6 +24,7 @@ import ( "fmt" "io" "net/http" + "net/url" "path" "path/filepath" "regexp" @@ -395,6 +396,7 @@ func getDownloadObjectResponse(session *models.Principal, params user_api.Downlo filename = prefixElements[len(prefixElements)-1] } } + escapedName := url.PathEscape(filename) // indicate object size & content type stat, err := resp.Stat() @@ -411,11 +413,11 @@ func getDownloadObjectResponse(session *models.Principal, params user_api.Downlo } if isPreview { - rw.Header().Set("Content-Disposition", fmt.Sprintf("inline; filename=\"%s\"", filename)) + rw.Header().Set("Content-Disposition", fmt.Sprintf("inline; filename=\"%s\"", escapedName)) rw.Header().Set("X-Frame-Options", "SAMEORIGIN") rw.Header().Set("X-XSS-Protection", "1") } else { - rw.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename)) + rw.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", escapedName)) } rw.Header().Set("Last-Modified", stat.LastModified.UTC().Format(http.TimeFormat)) @@ -424,7 +426,7 @@ func getDownloadObjectResponse(session *models.Principal, params user_api.Downlo if isPreview { // In case content type was uploaded as octet-stream, we double verify content type if stat.ContentType == "application/octet-stream" { - contentType = mimedb.TypeByExtension(filepath.Ext(filename)) + contentType = mimedb.TypeByExtension(filepath.Ext(escapedName)) } } rw.Header().Set("Content-Type", contentType) @@ -523,8 +525,9 @@ func getDownloadFolderResponse(session *models.Principal, params user_api.Downlo filename = prefixElements[len(prefixElements)-1] } } + escapedName := url.PathEscape(filename) - rw.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s.zip\"", filename)) + rw.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s.zip\"", escapedName)) rw.Header().Set("Content-Type", "application/zip") // Copy the stream