k8s.io/apiserver@v0.31.1/pkg/server/filters/goaway.go (about)

     1  /*
     2  Copyright 2020 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package filters
    18  
    19  import (
    20  	"math/rand"
    21  	"net/http"
    22  	"sync"
    23  )
    24  
    25  // GoawayDecider decides if server should send a GOAWAY
    26  type GoawayDecider interface {
    27  	Goaway(r *http.Request) bool
    28  }
    29  
    30  var (
    31  	// randPool used to get a rand.Rand and generate a random number thread-safely,
    32  	// which improve the performance of using rand.Rand with a locker
    33  	randPool = &sync.Pool{
    34  		New: func() interface{} {
    35  			return rand.New(rand.NewSource(rand.Int63()))
    36  		},
    37  	}
    38  )
    39  
    40  // WithProbabilisticGoaway returns an http.Handler that send GOAWAY probabilistically
    41  // according to the given chance for HTTP2 requests. After client receive GOAWAY,
    42  // the in-flight long-running requests will not be influenced, and the new requests
    43  // will use a new TCP connection to re-balancing to another server behind the load balance.
    44  func WithProbabilisticGoaway(inner http.Handler, chance float64) http.Handler {
    45  	return &goaway{
    46  		handler: inner,
    47  		decider: &probabilisticGoawayDecider{
    48  			chance: chance,
    49  			next: func() float64 {
    50  				rnd := randPool.Get().(*rand.Rand)
    51  				ret := rnd.Float64()
    52  				randPool.Put(rnd)
    53  				return ret
    54  			},
    55  		},
    56  	}
    57  }
    58  
    59  // goaway send a GOAWAY to client according to decider for HTTP2 requests
    60  type goaway struct {
    61  	handler http.Handler
    62  	decider GoawayDecider
    63  }
    64  
    65  // ServeHTTP implement HTTP handler
    66  func (h *goaway) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    67  	if r.Proto == "HTTP/2.0" && h.decider.Goaway(r) {
    68  		// Send a GOAWAY and tear down the TCP connection when idle.
    69  		w.Header().Set("Connection", "close")
    70  	}
    71  
    72  	h.handler.ServeHTTP(w, r)
    73  }
    74  
    75  // probabilisticGoawayDecider send GOAWAY probabilistically according to chance
    76  type probabilisticGoawayDecider struct {
    77  	chance float64
    78  	next   func() float64
    79  }
    80  
    81  // Goaway implement GoawayDecider
    82  func (p *probabilisticGoawayDecider) Goaway(r *http.Request) bool {
    83  	return p.next() < p.chance
    84  }