path.go 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. package utils
  2. import (
  3. "errors"
  4. "net/url"
  5. stdpath "path"
  6. "strings"
  7. )
  8. // FixAndCleanPath
  9. // The upper layer of the root directory is still the root directory.
  10. // So ".." And "." will be cleared
  11. // for example
  12. // 1. ".." or "." => "/"
  13. // 2. "../..." or "./..." => "/..."
  14. // 3. "../.x." or "./.x." => "/.x."
  15. // 4. "x//\\y" = > "/z/x"
  16. func FixAndCleanPath(path string) string {
  17. path = strings.ReplaceAll(path, "\\", "/")
  18. if !strings.HasPrefix(path, "/") {
  19. path = "/" + path
  20. }
  21. return stdpath.Clean(path)
  22. }
  23. // PathAddSeparatorSuffix Add path '/' suffix
  24. // for example /root => /root/
  25. func PathAddSeparatorSuffix(path string) string {
  26. if !strings.HasSuffix(path, "/") {
  27. path = path + "/"
  28. }
  29. return path
  30. }
  31. // PathEqual judge path is equal
  32. func PathEqual(path1, path2 string) bool {
  33. return FixAndCleanPath(path1) == FixAndCleanPath(path2)
  34. }
  35. func IsSubPath(path string, subPath string) bool {
  36. path, subPath = FixAndCleanPath(path), FixAndCleanPath(subPath)
  37. return path == subPath || strings.HasPrefix(subPath, PathAddSeparatorSuffix(path))
  38. }
  39. func Ext(path string) string {
  40. ext := stdpath.Ext(path)
  41. if strings.HasPrefix(ext, ".") {
  42. return ext[1:]
  43. }
  44. return ext
  45. }
  46. func EncodePath(path string, all ...bool) string {
  47. seg := strings.Split(path, "/")
  48. toReplace := []struct {
  49. Src string
  50. Dst string
  51. }{
  52. {Src: "%", Dst: "%25"},
  53. {"%", "%25"},
  54. {"?", "%3F"},
  55. {"#", "%23"},
  56. }
  57. for i := range seg {
  58. if len(all) > 0 && all[0] {
  59. seg[i] = url.PathEscape(seg[i])
  60. } else {
  61. for j := range toReplace {
  62. seg[i] = strings.ReplaceAll(seg[i], toReplace[j].Src, toReplace[j].Dst)
  63. }
  64. }
  65. }
  66. return strings.Join(seg, "/")
  67. }
  68. func JoinBasePath(basePath, reqPath string) (string, error) {
  69. if strings.HasSuffix(reqPath, "..") || strings.Contains(reqPath, "../") {
  70. return "", errors.New("access using relative path is not allowed")
  71. }
  72. return stdpath.Join(FixAndCleanPath(basePath), FixAndCleanPath(reqPath)), nil
  73. }