github.com/gravitational/teleport/api@v0.0.0-20240507183017-3110591cbafc/breaker/round_tripper.go (about)

     1  // Copyright 2022 Gravitational, Inc
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package breaker
    16  
    17  import (
    18  	"net/http"
    19  )
    20  
    21  // RoundTripper wraps a http.RoundTripper with a CircuitBreaker
    22  type RoundTripper struct {
    23  	tripper http.RoundTripper
    24  	cb      *CircuitBreaker
    25  }
    26  
    27  // NewRoundTripper returns a RoundTripper
    28  func NewRoundTripper(cb *CircuitBreaker, tripper http.RoundTripper) *RoundTripper {
    29  	return &RoundTripper{
    30  		tripper: tripper,
    31  		cb:      cb,
    32  	}
    33  }
    34  
    35  // CloseIdleConnections ensures idle connections of the wrapped
    36  // [http.RoundTripper] are closed.
    37  func (t *RoundTripper) CloseIdleConnections() {
    38  	type closeIdler interface {
    39  		CloseIdleConnections()
    40  	}
    41  	if tr, ok := t.tripper.(closeIdler); ok {
    42  		tr.CloseIdleConnections()
    43  	}
    44  }
    45  
    46  // RoundTrip forwards the request on to the provided http.RoundTripper if
    47  // the CircuitBreaker allows it
    48  func (t *RoundTripper) RoundTrip(request *http.Request) (*http.Response, error) {
    49  	v, err := t.cb.Execute(func() (interface{}, error) {
    50  		//nolint:bodyclose // The interface{} conversion to *http.Response trips the linter even though this
    51  		// is merely a pass through function. Closing the body here would prevent the actual
    52  		// consumer to not be able to read it. Copying here to satisfy the linter seems wasteful.
    53  		return t.tripper.RoundTrip(request)
    54  	})
    55  
    56  	if v == nil {
    57  		return nil, err
    58  	}
    59  
    60  	return v.(*http.Response), err
    61  }
    62  
    63  // Unwrap returns the inner round tripper.
    64  func (t *RoundTripper) Unwrap() http.RoundTripper {
    65  	return t.tripper
    66  }