gitea

Development moved to Codeberg

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35
  36. 36
  37. 37
  38. 38
  39. 39
  40. 40
  41. 41
  42. 42
  43. 43
  44. 44
  45. 45
  46. 46
  47. 47
  48. 48
  49. 49
  50. 50
  51. 51
  52. 52
  53. 53
  54. 54
  55. 55
  56. 56
  57. 57
  58. 58
  59. 59
  60. 60
  61. 61
  62. 62
  63. 63
  64. 64
  65. 65
  66. 66
  67. 67
  68. 68
  69. 69
  70. 70
  71. 71
  72. 72
  73. 73
  74. 74
  75. 75
  76. 76
  77. 77
  78. 78
  79. 79
  80. 80
  81. 81
  82. 82
  83. 83
  84. 84
  85. 85
  86. 86
  87. 87
  88. 88
  89. 89
  90. 90
  91. 91
  92. 92
  93. 93
  94. 94
  95. 95
  96. 96
  97. 97
  98. 98
  99. 99
  100. 100
  101. 101
  102. 102
  103. 103
  104. 104
  105. 105
  106. 106
  107. 107
  108. 108
  109. 109
  110. 110
  111. 111
  112. 112
  113. 113
  114. 114
  115. 115
  116. 116
  117. 117
  118. 118
  119. 119
  120. 120
  121. 121
  122. 122
  123. 123
  124. 124
  125. 125
  126. 126
  127. 127
  128. 128
  129. 129
  130. 130
  131. 131
  132. 132
  133. 133
  134. 134
  135. 135
  136. 136
  137. 137
  138. 138
  139. 139
  140. 140
  141. 141
  142. 142
  143. 143
  144. 144
  145. 145
  146. 146
  147. 147
  148. 148
  149. 149
  150. 150
  151. 151
  152. 152
  153. 153
  154. 154
// -build windows

// Copyright 2015 go-swagger maintainers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package spec

import (
	"net/url"
	"os"
	"path"
	"path/filepath"
	"strings"
)

// absPath makes a file path absolute and compatible with a URI path component
//
// The parameter must be a path, not an URI.
func absPath(in string) string {
	// NOTE(windows): filepath.Abs exhibits a special behavior on windows for empty paths.
	// See https://github.com/golang/go/issues/24441
	if in == "" {
		in = "."
	}

	anchored, err := filepath.Abs(in)
	if err != nil {
		specLogger.Printf("warning: could not resolve current working directory: %v", err)
		return in
	}

	pth := strings.ReplaceAll(strings.ToLower(anchored), `\`, `/`)
	if !strings.HasPrefix(pth, "/") {
		pth = "/" + pth
	}

	return path.Clean(pth)
}

// repairURI tolerates invalid file URIs with common typos
// such as 'file://E:\folder\file', that break the regular URL parser.
//
// Adopting the same defaults as for unixes (e.g. return an empty path) would
// result into a counter-intuitive result for that case (e.g. E:\folder\file is
// eventually resolved as the current directory). The repair will detect the missing "/".
//
// Note that this only works for the file scheme.
func repairURI(in string) (*url.URL, string) {
	const prefix = fileScheme + "://"
	if !strings.HasPrefix(in, prefix) {
		// giving up: resolve to empty path
		u, _ := url.Parse("")

		return u, ""
	}

	// attempt the repair, stripping the scheme should be sufficient
	u, _ := url.Parse(strings.TrimPrefix(in, prefix))
	debugLog("repaired URI: original: %q, repaired: %q", in, u.String())

	return u, u.String()
}

// fixWindowsURI tolerates an absolute file path on windows such as C:\Base\File.yaml or \\host\share\Base\File.yaml
// and makes it a canonical URI: file:///c:/base/file.yaml
//
// Catch 22 notes for Windows:
//
// * There may be a drive letter on windows (it is lower-cased)
// * There may be a share UNC, e.g. \\server\folder\data.xml
// * Paths are case insensitive
// * Paths may already contain slashes
// * Paths must be slashed
//
// NOTE: there is no escaping. "/" may be valid separators just like "\".
// We don't use ToSlash() (which escapes everything) because windows now also
// tolerates the use of "/". Hence, both C:\File.yaml and C:/File.yaml will work.
func fixWindowsURI(u *url.URL, in string) {
	drive := filepath.VolumeName(in)

	if len(drive) > 0 {
		if len(u.Scheme) == 1 && strings.EqualFold(u.Scheme, drive[:1]) { // a path with a drive letter
			u.Scheme = fileScheme
			u.Host = ""
			u.Path = strings.Join([]string{drive, u.Opaque, u.Path}, `/`) // reconstruct the full path component (no fragment, no query)
		} else if u.Host == "" && strings.HasPrefix(u.Path, drive) { // a path with a \\host volume
			// NOTE: the special host@port syntax for UNC is not supported (yet)
			u.Scheme = fileScheme

			// this is a modified version of filepath.Dir() to apply on the VolumeName itself
			i := len(drive) - 1
			for i >= 0 && !os.IsPathSeparator(drive[i]) {
				i--
			}
			host := drive[:i] // \\host\share => host

			u.Path = strings.TrimPrefix(u.Path, host)
			u.Host = strings.TrimPrefix(host, `\\`)
		}

		u.Opaque = ""
		u.Path = strings.ReplaceAll(strings.ToLower(u.Path), `\`, `/`)

		// ensure we form an absolute path
		if !strings.HasPrefix(u.Path, "/") {
			u.Path = "/" + u.Path
		}

		u.Path = path.Clean(u.Path)

		return
	}

	if u.Scheme == fileScheme {
		// Handle dodgy cases for file://{...} URIs on windows.
		// A canonical URI should always be followed by an absolute path.
		//
		// Examples:
		//   * file:///folder/file => valid, unchanged
		//   * file:///c:\folder\file => slashed
		//   * file:///./folder/file => valid, cleaned to remove the dot
		//   * file:///.\folder\file => remapped to cwd
		//   * file:///. => dodgy, remapped to / (consistent with the behavior on unix)
		//   * file:///.. => dodgy, remapped to / (consistent with the behavior on unix)
		if (!path.IsAbs(u.Path) && !filepath.IsAbs(u.Path)) || (strings.HasPrefix(u.Path, `/.`) && strings.Contains(u.Path, `\`)) {
			// ensure we form an absolute path
			u.Path, _ = filepath.Abs(strings.TrimLeft(u.Path, `/`))
			if !strings.HasPrefix(u.Path, "/") {
				u.Path = "/" + u.Path
			}
		}
		u.Path = strings.ToLower(u.Path)
	}

	// NOTE: lower case normalization does not propagate to inner resources,
	// generated when rebasing: when joining a relative URI with a file to an absolute base,
	// only the base is currently lower-cased.
	//
	// For now, we assume this is good enough for most use cases
	// and try not to generate too many differences
	// between the output produced on different platforms.
	u.Path = path.Clean(strings.ReplaceAll(u.Path, `\`, `/`))
}