1
0

cdv.go 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. package httpheaders
  2. import (
  3. "fmt"
  4. "mime"
  5. "path/filepath"
  6. "strings"
  7. )
  8. const (
  9. // fallbackStem is used when the stem cannot be determined from the URL.
  10. fallbackStem = "image"
  11. // Content-Disposition header format
  12. contentDispositionsHeader = "%s; filename=\"%s%s\""
  13. // "inline" disposition types
  14. inlineDisposition = "inline"
  15. // "attachment" disposition type
  16. attachmentDisposition = "attachment"
  17. )
  18. // ContentDispositionValue generates the content-disposition header value.
  19. //
  20. // It uses the following priorities:
  21. // 1. By default, it uses the filename and extension from the URL.
  22. // 2. If `filename` is provided, it overrides the URL filename.
  23. // 3. If `contentType` is provided, it tries to determine the extension from the content type.
  24. // 4. If `ext` is provided, it overrides any extension determined from the URL or header.
  25. // 5. If the filename is still empty, it uses fallback stem.
  26. func ContentDispositionValue(url, filename, ext, contentType string, returnAttachment bool) string {
  27. // By default, let's use the URL filename and extension
  28. _, urlFilename := filepath.Split(url)
  29. urlExt := filepath.Ext(urlFilename)
  30. var rStem string
  31. // Avoid strings.TrimSuffix allocation by using slice operation
  32. if urlExt != "" {
  33. rStem = urlFilename[:len(urlFilename)-len(urlExt)]
  34. } else {
  35. rStem = urlFilename
  36. }
  37. var rExt = urlExt
  38. // If filename is provided explicitly, use it
  39. if len(filename) > 0 {
  40. rStem = filename
  41. }
  42. // If ext is provided explicitly, use it
  43. if len(ext) > 0 {
  44. rExt = ext
  45. } else if len(contentType) > 0 && rExt == "" {
  46. exts, err := mime.ExtensionsByType(contentType)
  47. if err == nil && len(exts) != 0 {
  48. rExt = exts[0]
  49. }
  50. }
  51. // If fallback is requested, and filename is still empty, override it with fallbackStem
  52. if len(rStem) == 0 {
  53. rStem = fallbackStem
  54. }
  55. disposition := inlineDisposition
  56. // Create the content-disposition header value
  57. if returnAttachment {
  58. disposition = attachmentDisposition
  59. }
  60. return fmt.Sprintf(contentDispositionsHeader, disposition, strings.ReplaceAll(rStem, `"`, "%22"), rExt)
  61. }