66 lines
1.5 KiB
Go
Executable File
66 lines
1.5 KiB
Go
Executable File
package fetch
|
|
|
|
import (
|
|
"mime"
|
|
"net/http"
|
|
"path"
|
|
"path/filepath"
|
|
"strings"
|
|
"unicode/utf8"
|
|
)
|
|
|
|
const (
|
|
maxFileNameBytes = 200
|
|
maxExtensionBytes = 16
|
|
fallbackFileName = "download"
|
|
)
|
|
|
|
func FileNameFromResponse(response *http.Response) string {
|
|
if disposition := response.Header.Get("Content-Disposition"); disposition != "" {
|
|
if _, parameters, err := mime.ParseMediaType(disposition); err == nil {
|
|
if name := SanitizeFileName(parameters["filename"]); name != "" {
|
|
return name
|
|
}
|
|
}
|
|
}
|
|
if response.Request != nil && response.Request.URL != nil {
|
|
if name := SanitizeFileName(path.Base(response.Request.URL.Path)); name != "" {
|
|
return name
|
|
}
|
|
}
|
|
return fallbackFileName
|
|
}
|
|
|
|
func SanitizeFileName(raw string) string {
|
|
name := path.Base(strings.ReplaceAll(raw, "\\", "/"))
|
|
name = strings.Map(dropUnsafeRune, name)
|
|
name = strings.TrimSpace(strings.TrimLeft(name, ". "))
|
|
if name == "" {
|
|
return ""
|
|
}
|
|
return truncate(name)
|
|
}
|
|
|
|
func dropUnsafeRune(character rune) rune {
|
|
if character < 0x20 || character == 0x7f || character == '/' || character == utf8.RuneError {
|
|
return -1
|
|
}
|
|
return character
|
|
}
|
|
|
|
func truncate(name string) string {
|
|
if len(name) <= maxFileNameBytes {
|
|
return name
|
|
}
|
|
extension := filepath.Ext(name)
|
|
if len(extension) > maxExtensionBytes {
|
|
extension = ""
|
|
}
|
|
base := strings.TrimSuffix(name, extension)
|
|
for len(base)+len(extension) > maxFileNameBytes {
|
|
_, size := utf8.DecodeLastRuneInString(base)
|
|
base = base[:len(base)-size]
|
|
}
|
|
return base + extension
|
|
}
|