cmd/go: fix GOAUTH parsing for trailing slash

We were treating a url with a trailing slash differently than one
without. This CL treats them the same.

Additionally this fixes a bug in the way we iteratively try different
prefixes. We were only trying the host url but this change now tries all
different prefixes.

Fixes: #71889
Change-Id: I5d5f43000ae0e18ea8682050037253aff75ec142
Reviewed-on: https://go-review.googlesource.com/c/go/+/662435
Reviewed-by: Michael Matloob <matloob@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Sam Thanawalla <samthanawalla@google.com>
This commit is contained in:
Sam Thanawalla 2025-04-02 20:30:37 +00:00 committed by Gopher Robot
parent 16dbd2be39
commit e8adc39332
4 changed files with 26 additions and 4 deletions

View File

@ -2618,7 +2618,7 @@
// BlankLine = '\n' .
//
// Example:
// https://example.com/
// https://example.com
// https://example.net/api/
//
// Authorization: Basic <token>

View File

@ -142,14 +142,18 @@ func runGoAuth(client *http.Client, res *http.Response, url string) {
// them to the request headers.
func loadCredential(req *http.Request, url string) bool {
currentPrefix := strings.TrimPrefix(url, "https://")
currentPrefix = strings.TrimSuffix(currentPrefix, "/")
// Iteratively try prefixes, moving up the path hierarchy.
// E.g. example.com/foo/bar, example.com/foo, example.com
for {
headers, ok := credentialCache.Load(currentPrefix)
if !ok {
currentPrefix, _, ok = strings.Cut(currentPrefix, "/")
if !ok {
lastSlash := strings.LastIndexByte(currentPrefix, '/')
if lastSlash == -1 {
return false
}
currentPrefix = currentPrefix[:lastSlash]
continue
}
for key, values := range headers.(http.Header) {
@ -166,6 +170,7 @@ func loadCredential(req *http.Request, url string) bool {
func storeCredential(prefix string, header http.Header) {
// Trim "https://" prefix to match the format used in .netrc files.
prefix = strings.TrimPrefix(prefix, "https://")
prefix = strings.TrimSuffix(prefix, "/")
if len(header) == 0 {
credentialCache.Delete(prefix)
} else {

View File

@ -71,3 +71,20 @@ func TestCredentialCacheDelete(t *testing.T) {
t.Errorf("loadCredential:\nhave %q\nwant %q", got.Header, want.Header)
}
}
func TestCredentialCacheTrailingSlash(t *testing.T) {
// Store a credential for api.github.com/foo/bar
want := http.Request{Header: make(http.Header)}
want.SetBasicAuth("user", "pwd")
storeCredential("api.github.com/foo", want.Header)
got := &http.Request{Header: make(http.Header)}
ok := loadCredential(got, "api.github.com/foo/bar")
if !ok || !reflect.DeepEqual(got.Header, want.Header) {
t.Errorf("parseNetrc:\nhave %q\nwant %q", got.Header, want.Header)
}
got2 := &http.Request{Header: make(http.Header)}
ok = loadCredential(got2, "https://api.github.com/foo/bar/")
if !ok || !reflect.DeepEqual(got2.Header, want.Header) {
t.Errorf("parseNetrc:\nhave %q\nwant %q", got2.Header, want.Header)
}
}

View File

@ -1027,7 +1027,7 @@ command
BlankLine = '\n' .
Example:
https://example.com/
https://example.com
https://example.net/api/
Authorization: Basic <token>