diff options
| author | Michael Matloob <matloob@golang.org> | 2026-03-16 13:53:17 -0400 |
|---|---|---|
| committer | Michael Matloob <matloob@google.com> | 2026-03-17 09:42:03 -0700 |
| commit | 084157e2536c982e9dc669e8f289ec26dcc27891 (patch) | |
| tree | 6d83a7cfc7468b4c20adf4d3805df00829c35115 | |
| parent | 5094a1a5a9f9b9011c89d9121785968c467f8839 (diff) | |
| download | go-x-pkgsite-084157e2536c982e9dc669e8f289ec26dcc27891.tar.xz | |
internal/vuln: add convertFileURLPath on Windows
This addresses bcmills's comment in CL 508503.
Change-Id: I528465feb074c220ca2fc8a1f50eb6c1376f6b75
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/755581
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Ethan Lee <ethanalee@google.com>
Reviewed-by: Michael Matloob <matloob@google.com>
Auto-Submit: Michael Matloob <matloob@golang.org>
Run-TryBot: Michael Matloob <matloob@google.com>
kokoro-CI: kokoro <noreply+kokoro@google.com>
TryBot-Bypass: Michael Matloob <matloob@google.com>
| -rw-r--r-- | internal/vuln/source_test.go | 4 | ||||
| -rw-r--r-- | internal/vuln/url.go | 13 | ||||
| -rw-r--r-- | internal/vuln/url_other.go | 21 | ||||
| -rw-r--r-- | internal/vuln/url_test.go | 2 | ||||
| -rw-r--r-- | internal/vuln/url_windows.go | 43 |
5 files changed, 65 insertions, 18 deletions
diff --git a/internal/vuln/source_test.go b/internal/vuln/source_test.go index 6eff01c8..03893e41 100644 --- a/internal/vuln/source_test.go +++ b/internal/vuln/source_test.go @@ -12,16 +12,12 @@ import ( "net/http/httptest" "os" "path/filepath" - "runtime" "testing" "golang.org/x/pkgsite/internal/osv" ) func TestNewSource(t *testing.T) { - if runtime.GOOS == "windows" { - t.Skip("windows is not supported (see convertFileURLPath") - } t.Run("https", func(t *testing.T) { url := "https://vuln.go.dev" s, err := NewSource(url) diff --git a/internal/vuln/url.go b/internal/vuln/url.go index 60e2d1ea..67774c13 100644 --- a/internal/vuln/url.go +++ b/internal/vuln/url.go @@ -12,7 +12,6 @@ import ( "errors" "net/url" "path/filepath" - "runtime" ) var errNotAbsolute = errors.New("path is not absolute") @@ -43,15 +42,3 @@ func URLToFilePath(u *url.URL) (string, error) { } return checkAbs(path) } - -func convertFileURLPath(host, path string) (string, error) { - if runtime.GOOS == "windows" { - return "", errors.New("windows not supported") - } - switch host { - case "", "localhost": - default: - return "", errors.New("file URL specifies non-local host") - } - return filepath.FromSlash(path), nil -} diff --git a/internal/vuln/url_other.go b/internal/vuln/url_other.go new file mode 100644 index 00000000..6694390b --- /dev/null +++ b/internal/vuln/url_other.go @@ -0,0 +1,21 @@ +// Copyright 2026 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !windows + +package vuln + +import ( + "errors" + "path/filepath" +) + +func convertFileURLPath(host, path string) (string, error) { + switch host { + case "", "localhost": + default: + return "", errors.New("file URL specifies non-local host") + } + return filepath.FromSlash(path), nil +} diff --git a/internal/vuln/url_test.go b/internal/vuln/url_test.go index 22334cb7..46908568 100644 --- a/internal/vuln/url_test.go +++ b/internal/vuln/url_test.go @@ -12,7 +12,7 @@ import ( func TestURLToFilePath(t *testing.T) { if runtime.GOOS == "windows" { - t.Skip("windows is not supported (see convertFileURLPath") + t.Skip("windows is not supported (see convertFileURLPath)") } for _, tc := range urlTests { if tc.url == "" { diff --git a/internal/vuln/url_windows.go b/internal/vuln/url_windows.go new file mode 100644 index 00000000..bb649697 --- /dev/null +++ b/internal/vuln/url_windows.go @@ -0,0 +1,43 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package vuln + +import ( + "errors" + "path/filepath" + "strings" +) + +func convertFileURLPath(host, path string) (string, error) { + if len(path) == 0 || path[0] != '/' { + return "", errNotAbsolute + } + + path = filepath.FromSlash(path) + + // We interpret Windows file URLs per the description in + // https://blogs.msdn.microsoft.com/ie/2006/12/06/file-uris-in-windows/. + + // The host part of a file URL (if any) is the UNC volume name, + // but RFC 8089 reserves the authority "localhost" for the local machine. + if host != "" && host != "localhost" { + // A common "legacy" format omits the leading slash before a drive letter, + // encoding the drive letter as the host instead of part of the path. + // (See https://blogs.msdn.microsoft.com/freeassociations/2005/05/19/the-bizarre-and-unhappy-story-of-file-urls/.) + // We do not support that format, but we should at least emit a more + // helpful error message for it. + if filepath.VolumeName(host) != "" { + return "", errors.New("file URL encodes drive letter in host field (example file:///C:/path)") + } + return `\\` + host + path, nil + } + + // If host is empty, path must contain an initial slash followed by a + // drive letter and path. Remove the slash and verify that the path is valid. + if vol := filepath.VolumeName(path[1:]); vol == "" || strings.HasPrefix(vol, `\\`) { + return "", errors.New("file URL missing drive letter (e.g., file:///C:/path)") + } + return filepath.Clean(path[1:]), nil +} |
