Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

remote/transport: Make bearer transport go-routine-safe #1806

Merged

Conversation

2opremio
Copy link
Contributor

@2opremio 2opremio commented Oct 10, 2023

Make the bearer transport safe for use by multiple go-routines.

I found the following race conditions in my application, when using the transport in a client making multiple concurrent requests.

Data race backtraces
==================
WARNING: DATA RACE
Read at 0x00c00014c248 by goroutine 18:
  github.com/google/go-containerregistry/pkg/v1/remote/transport.(*bearerTransport).RoundTrip()
      /Users/fons/go/pkg/mod/github.com/google/go-containerregistry@v0.16.1/pkg/v1/remote/transport/bearer.go:163 +0x1fc
  github.com/google/go-containerregistry/pkg/v1/remote/transport.(*Wrapper).RoundTrip()
      /Users/fons/go/pkg/mod/github.com/google/go-containerregistry@v0.16.1/pkg/v1/remote/transport/transport.go:108 +0x4c
  net/http.send()
      /opt/local/lib/go/src/net/http/client.go:260 +0x6cc
  net/http.(*Client).send()
      /opt/local/lib/go/src/net/http/client.go:181 +0x100
  net/http.(*Client).do()
      /opt/local/lib/go/src/net/http/client.go:724 +0xc3c
  net/http.(*Client).Do()
      /opt/local/lib/go/src/net/http/client.go:590 +0x1cc
  dev.azure.com/cur8/TheRigg/_git/docker-registry-proxy/internal/proxy.Proxy.getResponse()
      /Users/fons/docker-registry-proxy/internal/proxy/main.go:124 +0x1c4
  dev.azure.com/cur8/TheRigg/_git/docker-registry-proxy/internal/proxy.Proxy.ServeHTTP()
      /Users/fons/docker-registry-proxy/internal/proxy/main.go:178 +0x714
  dev.azure.com/cur8/TheRigg/_git/docker-registry-proxy/internal/proxy.(*Proxy).ServeHTTP()
      <autogenerated>:1 +0x84
  net/http.serverHandler.ServeHTTP()
      /opt/local/lib/go/src/net/http/server.go:2938 +0x298
  net/http.(*conn).serve()
      /opt/local/lib/go/src/net/http/server.go:2009 +0x8ec
  net/http.(*Server).Serve.func3()
      /opt/local/lib/go/src/net/http/server.go:3086 +0x4c

Previous write at 0x00c00014c248 by goroutine 25:
  github.com/google/go-containerregistry/pkg/v1/remote/transport.(*bearerTransport).RoundTrip()
      /Users/fons/go/pkg/mod/github.com/google/go-containerregistry@v0.16.1/pkg/v1/remote/transport/bearer.go:174 +0x3d8
  github.com/google/go-containerregistry/pkg/v1/remote/transport.(*Wrapper).RoundTrip()
      /Users/fons/go/pkg/mod/github.com/google/go-containerregistry@v0.16.1/pkg/v1/remote/transport/transport.go:108 +0x4c
  net/http.send()
      /opt/local/lib/go/src/net/http/client.go:260 +0x6cc
  net/http.(*Client).send()
      /opt/local/lib/go/src/net/http/client.go:181 +0x100
  net/http.(*Client).do()
      /opt/local/lib/go/src/net/http/client.go:724 +0xc3c
  net/http.(*Client).Do()
      /opt/local/lib/go/src/net/http/client.go:590 +0x1cc
  dev.azure.com/cur8/TheRigg/_git/docker-registry-proxy/internal/proxy.Proxy.getResponse()
      /Users/fons/docker-registry-proxy/internal/proxy/main.go:124 +0x1c4
  dev.azure.com/cur8/TheRigg/_git/docker-registry-proxy/internal/proxy.Proxy.ServeHTTP()
      /Users/fons/docker-registry-proxy/internal/proxy/main.go:178 +0x714
  dev.azure.com/cur8/TheRigg/_git/docker-registry-proxy/internal/proxy.(*Proxy).ServeHTTP()
      <autogenerated>:1 +0x84
  net/http.serverHandler.ServeHTTP()
      /opt/local/lib/go/src/net/http/server.go:2938 +0x298
  net/http.(*conn).serve()
      /opt/local/lib/go/src/net/http/server.go:2009 +0x8ec
  net/http.(*Server).Serve.func3()
      /opt/local/lib/go/src/net/http/server.go:3086 +0x4c

Goroutine 18 (running) created at:
  net/http.(*Server).Serve()
      /opt/local/lib/go/src/net/http/server.go:3086 +0x5f4
  net/http.(*Server).ListenAndServe()
      /opt/local/lib/go/src/net/http/server.go:2985 +0xb0
  main.main.func3()
      /Users/fons/docker-registry-proxy/main.go:127 +0x2c

Goroutine 25 (running) created at:
  net/http.(*Server).Serve()
      /opt/local/lib/go/src/net/http/server.go:3086 +0x5f4
  net/http.(*Server).ListenAndServe()
      /opt/local/lib/go/src/net/http/server.go:2985 +0xb0
  main.main.func3()
      /Users/fons/docker-registry-proxy/main.go:127 +0x2c
==================
==================
WARNING: DATA RACE
Read at 0x00c00039a1c0 by goroutine 18:
  github.com/google/go-containerregistry/pkg/v1/remote/transport.stringSet()
      /Users/fons/go/pkg/mod/github.com/google/go-containerregistry@v0.16.1/pkg/v1/remote/transport/bearer.go:127 +0x4f4
  github.com/google/go-containerregistry/pkg/v1/remote/transport.(*bearerTransport).RoundTrip()
      /Users/fons/go/pkg/mod/github.com/google/go-containerregistry@v0.16.1/pkg/v1/remote/transport/bearer.go:163 +0x1f0
  github.com/google/go-containerregistry/pkg/v1/remote/transport.(*Wrapper).RoundTrip()
      /Users/fons/go/pkg/mod/github.com/google/go-containerregistry@v0.16.1/pkg/v1/remote/transport/transport.go:108 +0x4c
  net/http.send()
      /opt/local/lib/go/src/net/http/client.go:260 +0x6cc
  net/http.(*Client).send()
      /opt/local/lib/go/src/net/http/client.go:181 +0x100
  net/http.(*Client).do()
      /opt/local/lib/go/src/net/http/client.go:724 +0xc3c
  net/http.(*Client).Do()
      /opt/local/lib/go/src/net/http/client.go:590 +0x1cc
  dev.azure.com/cur8/TheRigg/_git/docker-registry-proxy/internal/proxy.Proxy.getResponse()
      /Users/fons/docker-registry-proxy/internal/proxy/main.go:124 +0x1c4
  dev.azure.com/cur8/TheRigg/_git/docker-registry-proxy/internal/proxy.Proxy.ServeHTTP()
      /Users/fons/docker-registry-proxy/internal/proxy/main.go:178 +0x714
  dev.azure.com/cur8/TheRigg/_git/docker-registry-proxy/internal/proxy.(*Proxy).ServeHTTP()
      <autogenerated>:1 +0x84
  net/http.serverHandler.ServeHTTP()
      /opt/local/lib/go/src/net/http/server.go:2938 +0x298
  net/http.(*conn).serve()
      /opt/local/lib/go/src/net/http/server.go:2009 +0x8ec
  net/http.(*Server).Serve.func3()
      /opt/local/lib/go/src/net/http/server.go:3086 +0x4c

Previous write at 0x00c00039a1c0 by goroutine 25:
  runtime.slicecopy()
      /opt/local/lib/go/src/runtime/slice.go:310 +0x0
  github.com/google/go-containerregistry/pkg/v1/remote/transport.(*bearerTransport).RoundTrip()
      /Users/fons/go/pkg/mod/github.com/google/go-containerregistry@v0.16.1/pkg/v1/remote/transport/bearer.go:173 +0x3d0
  github.com/google/go-containerregistry/pkg/v1/remote/transport.(*Wrapper).RoundTrip()
      /Users/fons/go/pkg/mod/github.com/google/go-containerregistry@v0.16.1/pkg/v1/remote/transport/transport.go:108 +0x4c
  net/http.send()
      /opt/local/lib/go/src/net/http/client.go:260 +0x6cc
  net/http.(*Client).send()
      /opt/local/lib/go/src/net/http/client.go:181 +0x100
  net/http.(*Client).do()
      /opt/local/lib/go/src/net/http/client.go:724 +0xc3c
  net/http.(*Client).Do()
      /opt/local/lib/go/src/net/http/client.go:590 +0x1cc
  dev.azure.com/cur8/TheRigg/_git/docker-registry-proxy/internal/proxy.Proxy.getResponse()
      /Users/fons/docker-registry-proxy/internal/proxy/main.go:124 +0x1c4
  dev.azure.com/cur8/TheRigg/_git/docker-registry-proxy/internal/proxy.Proxy.ServeHTTP()
      /Users/fons/docker-registry-proxy/internal/proxy/main.go:178 +0x714
  dev.azure.com/cur8/TheRigg/_git/docker-registry-proxy/internal/proxy.(*Proxy).ServeHTTP()
      <autogenerated>:1 +0x84
  net/http.serverHandler.ServeHTTP()
      /opt/local/lib/go/src/net/http/server.go:2938 +0x298
  net/http.(*conn).serve()
      /opt/local/lib/go/src/net/http/server.go:2009 +0x8ec
  net/http.(*Server).Serve.func3()
      /opt/local/lib/go/src/net/http/server.go:3086 +0x4c

Goroutine 18 (running) created at:
  net/http.(*Server).Serve()
      /opt/local/lib/go/src/net/http/server.go:3086 +0x5f4
  net/http.(*Server).ListenAndServe()
      /opt/local/lib/go/src/net/http/server.go:2985 +0xb0
  main.main.func3()
      /Users/fons/docker-registry-proxy/main.go:127 +0x2c

Goroutine 25 (running) created at:
  net/http.(*Server).Serve()
      /opt/local/lib/go/src/net/http/server.go:3086 +0x5f4
  net/http.(*Server).ListenAndServe()
      /opt/local/lib/go/src/net/http/server.go:2985 +0xb0
  main.main.func3()
      /Users/fons/docker-registry-proxy/main.go:127 +0x2c
==================

A simplified application could be:

package main

import (
	"net/http"
	
	"github.com/google/go-containerregistry/pkg/authn"
	"github.com/google/go-containerregistry/pkg/name"
	"github.com/google/go-containerregistry/pkg/v1/remote/transport"
)

func newAuthenticatingClient(host, user, password string) (*http.Client, error) {
	registry, err := name.NewRegistry(host)
	if err != nil {
		return nil, err
	}
	basicAuth := &authn.Basic{
		Username: user,
		Password: password,
	}
	tr, err := transport.New(registry, basicAuth, http.DefaultTransport, nil)
	if err != nil {
	  return nil, err
	}
	return &http.Client{Transport: tr}
}

func main() {
	client, err := newAuthenticatingClient("foo", "bar", "buzz")
	if err != nil {
		panic(err)
	}
	// make a lot of concurrent requests with client
}

@google-cla
Copy link

google-cla bot commented Oct 10, 2023

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@2opremio 2opremio force-pushed the make-bearer-transport-thread-safe branch from 95eb9fd to ef93d22 Compare October 10, 2023 02:42
@codecov-commenter
Copy link

codecov-commenter commented Oct 10, 2023

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 71.69%. Comparing base (55ffb00) to head (b666669).
Report is 15 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1806      +/-   ##
==========================================
+ Coverage   71.65%   71.69%   +0.03%     
==========================================
  Files         123      123              
  Lines        9928     9941      +13     
==========================================
+ Hits         7114     7127      +13     
  Misses       2115     2115              
  Partials      699      699              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@dmitris
Copy link

dmitris commented Nov 24, 2023

@2opremio - could you rebase the branch of this PR on the current trunk to pick up the latest changes, please?

Make the bearer transport safe for use by multiple go-routines.
@2opremio 2opremio force-pushed the make-bearer-transport-thread-safe branch from ef93d22 to b666669 Compare January 2, 2024 16:21
@2opremio
Copy link
Contributor Author

2opremio commented Jan 2, 2024

@dmitris done!

@dmitris
Copy link

dmitris commented Jan 11, 2024

It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

any chance you could do the CLA, @2opremio? Want to see your change in the main repo rather than having to apply it as a patch in CI 😄

@2opremio
Copy link
Contributor Author

I did! It should be approved, isn't it?

@dmitris
Copy link

dmitris commented Feb 9, 2024

@jonjohnsonjr - is this ready to merge or what do we need to move this ahead? Could you please review it? 🙏 Thanks!

Copy link

This Pull Request is stale because it has been open for 90 days with
no activity. It will automatically close after 30 more days of
inactivity. Keep fresh with the 'lifecycle/frozen' label.

Copy link

github-actions bot commented Aug 9, 2024

This Pull Request is stale because it has been open for 90 days with
no activity. It will automatically close after 30 more days of
inactivity. Keep fresh with the 'lifecycle/frozen' label.

@2opremio
Copy link
Contributor Author

2opremio commented Aug 9, 2024

@dmitris can we please get this merged?

@dmitris
Copy link

dmitris commented Aug 9, 2024

@dmitris can we please get this merged?

@2opremio I would love to but I'm not a repo owner or admin, don't have the rights to do this.

@jonjohnsonjr jonjohnsonjr merged commit b8e87ed into google:main Aug 10, 2024
18 checks passed
@dmitris
Copy link

dmitris commented Aug 21, 2024

thanks @jonjohnsonjr - could you also cut a new release (v0.20.3), please? /cc @imjasonh

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants