Skip to content

Commit

Permalink
fixup! Fix close in use certificate providers after double Close()
Browse files Browse the repository at this point in the history
…method call on wrapper object
  • Loading branch information
bozaro committed May 11, 2024
1 parent 3bf8e1f commit 64fdac1
Showing 1 changed file with 25 additions and 19 deletions.
44 changes: 25 additions & 19 deletions credentials/tls/certprovider/store.go
Expand Up @@ -45,7 +45,7 @@ type storeKey struct {

// wrappedProvider wraps a provider instance with a reference count.
type wrappedProvider struct {
provider Provider
Provider
refCount int

// A reference to the key and store are also kept here to override the
Expand All @@ -54,11 +54,21 @@ type wrappedProvider struct {
store *store
}

// wrappedProviderCloser wraps a provider instance with a reference count to avoid double
// closedProvider always returns errProviderClosed error.
type closedProvider struct{}

func (c closedProvider) KeyMaterial(ctx context.Context) (*KeyMaterial, error) {
return nil, errProviderClosed
}

func (c closedProvider) Close() {
}

// singleCloseWrappedProvider wraps a provider instance with a reference count to avoid double
// close still in use provider.
type wrappedProviderCloser struct {
mu sync.RWMutex
wp *wrappedProvider
type singleCloseWrappedProvider struct {
mu sync.RWMutex
provider Provider
}

// store is a collection of provider instances, safe for concurrent access.
Expand All @@ -78,32 +88,28 @@ func (wp *wrappedProvider) Close() {

wp.refCount--
if wp.refCount == 0 {
wp.provider.Close()
wp.Provider.Close()
delete(ps.providers, wp.storeKey)
}
}

// Close overrides the Close method of the embedded provider to avoid release the
// already released reference.
func (w *wrappedProviderCloser) Close() {
func (w *singleCloseWrappedProvider) Close() {
w.mu.Lock()
defer w.mu.Unlock()
if wp := w.wp; wp != nil {
w.wp = nil
wp.Close()
}

w.provider.Close()
w.provider = closedProvider{}
}

// KeyMaterial returns the key material sourced by the Provider.
// Callers are expected to use the returned value as read-only.
func (w *wrappedProviderCloser) KeyMaterial(ctx context.Context) (*KeyMaterial, error) {
func (w *singleCloseWrappedProvider) KeyMaterial(ctx context.Context) (*KeyMaterial, error) {
w.mu.RLock()
defer w.mu.RUnlock()

if w.wp == nil {
return nil, errProviderClosed
}
return w.wp.provider.KeyMaterial(ctx)
return w.provider.KeyMaterial(ctx)
}

// BuildableConfig wraps parsed provider configuration and functionality to
Expand Down Expand Up @@ -143,21 +149,21 @@ func (bc *BuildableConfig) Build(opts BuildOptions) (Provider, error) {
}
if wp, ok := provStore.providers[sk]; ok {
wp.refCount++
return &wrappedProviderCloser{wp: wp}, nil
return &singleCloseWrappedProvider{provider: wp}, nil
}

provider := bc.starter(opts)
if provider == nil {
return nil, fmt.Errorf("provider(%q, %q).Build(%v) failed", sk.name, sk.config, opts)
}
wp := &wrappedProvider{
provider: provider,
Provider: provider,
refCount: 1,
storeKey: sk,
store: provStore,
}
provStore.providers[sk] = wp
return &wrappedProviderCloser{wp: wp}, nil
return &singleCloseWrappedProvider{provider: wp}, nil
}

// String returns the provider name and config as a colon separated string.
Expand Down

0 comments on commit 64fdac1

Please sign in to comment.