1- // Copyright 2021 The Hugo Authors. All rights reserved.
1+ // Copyright 2024 The Hugo Authors. All rights reserved.
22//
33// Licensed under the Apache License, Version 2.0 (the "License");
44// you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@ import (
1818 "net/url"
1919 "path"
2020 "path/filepath"
21+ "runtime"
2122 "strings"
2223)
2324
@@ -159,9 +160,77 @@ func Uglify(in string) string {
159160 return path .Clean (in )
160161}
161162
163+ // URLEscape escapes unicode letters.
164+ func URLEscape (uri string ) string {
165+ // escape unicode letters
166+ u , err := url .Parse (uri )
167+ if err != nil {
168+ panic (err )
169+ }
170+ return u .String ()
171+ }
172+
173+ // TrimExt trims the extension from a path..
174+ func TrimExt (in string ) string {
175+ return strings .TrimSuffix (in , path .Ext (in ))
176+ }
177+
178+ // From https://github.com/golang/go/blob/e0c76d95abfc1621259864adb3d101cf6f1f90fc/src/cmd/go/internal/web/url.go#L45
179+ func UrlFromFilename (filename string ) (* url.URL , error ) {
180+ if ! filepath .IsAbs (filename ) {
181+ return nil , fmt .Errorf ("filepath must be absolute" )
182+ }
183+
184+ // If filename has a Windows volume name, convert the volume to a host and prefix
185+ // per https://blogs.msdn.microsoft.com/ie/2006/12/06/file-uris-in-windows/.
186+ if vol := filepath .VolumeName (filename ); vol != "" {
187+ if strings .HasPrefix (vol , `\\` ) {
188+ filename = filepath .ToSlash (filename [2 :])
189+ i := strings .IndexByte (filename , '/' )
190+
191+ if i < 0 {
192+ // A degenerate case.
193+ // \\host.example.com (without a share name)
194+ // becomes
195+ // file://host.example.com/
196+ return & url.URL {
197+ Scheme : "file" ,
198+ Host : filename ,
199+ Path : "/" ,
200+ }, nil
201+ }
202+
203+ // \\host.example.com\Share\path\to\file
204+ // becomes
205+ // file://host.example.com/Share/path/to/file
206+ return & url.URL {
207+ Scheme : "file" ,
208+ Host : filename [:i ],
209+ Path : filepath .ToSlash (filename [i :]),
210+ }, nil
211+ }
212+
213+ // C:\path\to\file
214+ // becomes
215+ // file:///C:/path/to/file
216+ return & url.URL {
217+ Scheme : "file" ,
218+ Path : "/" + filepath .ToSlash (filename ),
219+ }, nil
220+ }
221+
222+ // /path/to/file
223+ // becomes
224+ // file:///path/to/file
225+ return & url.URL {
226+ Scheme : "file" ,
227+ Path : filepath .ToSlash (filename ),
228+ }, nil
229+ }
230+
162231// UrlToFilename converts the URL s to a filename.
163232// If ParseRequestURI fails, the input is just converted to OS specific slashes and returned.
164- func UrlToFilename (s string ) (string , bool ) {
233+ func UrlStringToFilename (s string ) (string , bool ) {
165234 u , err := url .ParseRequestURI (s )
166235 if err != nil {
167236 return filepath .FromSlash (s ), false
@@ -171,25 +240,34 @@ func UrlToFilename(s string) (string, bool) {
171240
172241 if p == "" {
173242 p , _ = url .QueryUnescape (u .Opaque )
174- return filepath .FromSlash (p ), true
243+ return filepath .FromSlash (p ), false
175244 }
176245
177- p = filepath . FromSlash ( p )
246+ isWindows := runtime . GOOS == "windows"
178247
179- if u .Host != "" {
180- // C:\data\file.txt
181- p = strings .ToUpper (u .Host ) + ":" + p
248+ if isWindows {
249+ if len (p ) == 0 || p [0 ] != '/' {
250+ return filepath .FromSlash (p ), false
251+ }
252+ p = filepath .FromSlash (p )
253+ if len (u .Host ) == 1 {
254+ // file://c/Users/...
255+ return strings .ToUpper (u .Host ) + ":" + p , true
256+ }
257+ if u .Host != "" && u .Host != "localhost" {
258+ if filepath .VolumeName (u .Host ) != "" {
259+ return "" , false
260+ }
261+ return `\\` + u .Host + p , true
262+ }
263+ if vol := filepath .VolumeName (p [1 :]); vol == "" || strings .HasPrefix (vol , `\\` ) {
264+ return "" , false
265+ }
266+ return p [1 :], true
182267 }
183268
184269 return p , true
185270}
186271
187- // URLEscape escapes unicode letters.
188- func URLEscape (uri string ) string {
189- // escape unicode letters
190- u , err := url .Parse (uri )
191- if err != nil {
192- panic (err )
193- }
194- return u .String ()
272+ func convertFileURLPathWindows (host , path string ) (string , bool ) {
195273}
0 commit comments