mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-22 19:31:44 +00:00
Merge pull request #111896 from deads2k/revert-compression-disable
Revert "Add an option to conditionally disable compression based on client ip."
This commit is contained in:
commit
ae62cd6ce2
@ -1,43 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2022 The Kubernetes Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package filters
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"k8s.io/apiserver/pkg/endpoints/handlers/responsewriters"
|
|
||||||
"k8s.io/apiserver/pkg/endpoints/request"
|
|
||||||
)
|
|
||||||
|
|
||||||
// CompressionDisabledFunc checks if a given request should disable compression.
|
|
||||||
type CompressionDisabledFunc func(*http.Request) (bool, error)
|
|
||||||
|
|
||||||
// WithCompressionDisabled stores result of CompressionDisabledFunc in context.
|
|
||||||
func WithCompressionDisabled(handler http.Handler, predicate CompressionDisabledFunc) http.Handler {
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
|
||||||
ctx := req.Context()
|
|
||||||
decision, err := predicate(req)
|
|
||||||
if err != nil {
|
|
||||||
responsewriters.InternalError(w, req, fmt.Errorf("failed to determine if request should disable compression: %v", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
req = req.WithContext(request.WithCompressionDisabled(ctx, decision))
|
|
||||||
handler.ServeHTTP(w, req)
|
|
||||||
})
|
|
||||||
}
|
|
@ -1,79 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2022 The Kubernetes Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package filters
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"k8s.io/apiserver/pkg/endpoints/request"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestWithCompressionDisabled(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
checkDecision bool
|
|
||||||
checkErr error
|
|
||||||
want bool
|
|
||||||
wantHandlerCalled bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "decision=true",
|
|
||||||
checkDecision: true,
|
|
||||||
want: true,
|
|
||||||
wantHandlerCalled: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "decision=false",
|
|
||||||
checkDecision: false,
|
|
||||||
want: false,
|
|
||||||
wantHandlerCalled: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "check error",
|
|
||||||
checkErr: errors.New("check failed"),
|
|
||||||
want: false,
|
|
||||||
wantHandlerCalled: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
handlerCalled := false
|
|
||||||
handler := http.HandlerFunc(func(_ http.ResponseWriter, req *http.Request) {
|
|
||||||
handlerCalled = true
|
|
||||||
if got, want := request.CompressionDisabledFrom(req.Context()), tt.checkDecision; got != want {
|
|
||||||
t.Errorf("request.CompressionDisabledFrom(req.Context())=%v; want=%v", got, want)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
fake := func(*http.Request) (bool, error) {
|
|
||||||
return tt.checkDecision, tt.checkErr
|
|
||||||
}
|
|
||||||
wrapped := WithCompressionDisabled(handler, fake)
|
|
||||||
testRequest, err := http.NewRequest(http.MethodGet, "/path", nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
w := httptest.NewRecorder()
|
|
||||||
wrapped.ServeHTTP(w, testRequest)
|
|
||||||
if handlerCalled != tt.wantHandlerCalled {
|
|
||||||
t.Errorf("expected handlerCalled=%v, got=%v", handlerCalled, tt.wantHandlerCalled)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
@ -87,21 +87,19 @@ func StreamObject(statusCode int, gv schema.GroupVersion, s runtime.NegotiatedSe
|
|||||||
// The context is optional and can be nil. This method will perform optional content compression if requested by
|
// The context is optional and can be nil. This method will perform optional content compression if requested by
|
||||||
// a client and the feature gate for APIResponseCompression is enabled.
|
// a client and the feature gate for APIResponseCompression is enabled.
|
||||||
func SerializeObject(mediaType string, encoder runtime.Encoder, hw http.ResponseWriter, req *http.Request, statusCode int, object runtime.Object) {
|
func SerializeObject(mediaType string, encoder runtime.Encoder, hw http.ResponseWriter, req *http.Request, statusCode int, object runtime.Object) {
|
||||||
disableCompression := request.CompressionDisabledFrom(req.Context())
|
|
||||||
trace := utiltrace.New("SerializeObject",
|
trace := utiltrace.New("SerializeObject",
|
||||||
utiltrace.Field{"audit-id", request.GetAuditIDTruncated(req.Context())},
|
utiltrace.Field{"audit-id", request.GetAuditIDTruncated(req.Context())},
|
||||||
utiltrace.Field{"method", req.Method},
|
utiltrace.Field{"method", req.Method},
|
||||||
utiltrace.Field{"url", req.URL.Path},
|
utiltrace.Field{"url", req.URL.Path},
|
||||||
utiltrace.Field{"protocol", req.Proto},
|
utiltrace.Field{"protocol", req.Proto},
|
||||||
utiltrace.Field{"mediaType", mediaType},
|
utiltrace.Field{"mediaType", mediaType},
|
||||||
utiltrace.Field{"encoder", encoder.Identifier()},
|
utiltrace.Field{"encoder", encoder.Identifier()})
|
||||||
utiltrace.Field{"disableCompression", disableCompression})
|
|
||||||
defer trace.LogIfLong(5 * time.Second)
|
defer trace.LogIfLong(5 * time.Second)
|
||||||
|
|
||||||
w := &deferredResponseWriter{
|
w := &deferredResponseWriter{
|
||||||
mediaType: mediaType,
|
mediaType: mediaType,
|
||||||
statusCode: statusCode,
|
statusCode: statusCode,
|
||||||
contentEncoding: negotiateContentEncoding(req, disableCompression),
|
contentEncoding: negotiateContentEncoding(req),
|
||||||
hw: hw,
|
hw: hw,
|
||||||
trace: trace,
|
trace: trace,
|
||||||
}
|
}
|
||||||
@ -157,12 +155,12 @@ const (
|
|||||||
// negotiateContentEncoding returns a supported client-requested content encoding for the
|
// negotiateContentEncoding returns a supported client-requested content encoding for the
|
||||||
// provided request. It will return the empty string if no supported content encoding was
|
// provided request. It will return the empty string if no supported content encoding was
|
||||||
// found or if response compression is disabled.
|
// found or if response compression is disabled.
|
||||||
func negotiateContentEncoding(req *http.Request, disableCompression bool) string {
|
func negotiateContentEncoding(req *http.Request) string {
|
||||||
encoding := req.Header.Get("Accept-Encoding")
|
encoding := req.Header.Get("Accept-Encoding")
|
||||||
if len(encoding) == 0 {
|
if len(encoding) == 0 {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
if !utilfeature.DefaultFeatureGate.Enabled(features.APIResponseCompression) || disableCompression {
|
if !utilfeature.DefaultFeatureGate.Enabled(features.APIResponseCompression) {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
for len(encoding) > 0 {
|
for len(encoding) > 0 {
|
||||||
|
@ -19,7 +19,6 @@ package responsewriters
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"context"
|
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
@ -42,7 +41,6 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/apimachinery/pkg/util/diff"
|
"k8s.io/apimachinery/pkg/util/diff"
|
||||||
"k8s.io/apimachinery/pkg/util/uuid"
|
"k8s.io/apimachinery/pkg/util/uuid"
|
||||||
"k8s.io/apiserver/pkg/endpoints/request"
|
|
||||||
"k8s.io/apiserver/pkg/features"
|
"k8s.io/apiserver/pkg/features"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||||
@ -233,7 +231,7 @@ func TestSerializeObject(t *testing.T) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
name: "compress on gzip, request's context has no decision",
|
name: "compress on gzip",
|
||||||
compressionEnabled: true,
|
compressionEnabled: true,
|
||||||
out: largePayload,
|
out: largePayload,
|
||||||
mediaType: "application/json",
|
mediaType: "application/json",
|
||||||
@ -251,40 +249,6 @@ func TestSerializeObject(t *testing.T) {
|
|||||||
},
|
},
|
||||||
wantBody: gzipContent(largePayload, defaultGzipContentEncodingLevel),
|
wantBody: gzipContent(largePayload, defaultGzipContentEncodingLevel),
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "compress on gzip, request's context allows compression",
|
|
||||||
compressionEnabled: true,
|
|
||||||
out: largePayload,
|
|
||||||
mediaType: "application/json",
|
|
||||||
req: (&http.Request{
|
|
||||||
Header: http.Header{
|
|
||||||
"Accept-Encoding": []string{"gzip"},
|
|
||||||
},
|
|
||||||
URL: &url.URL{Path: "/path"},
|
|
||||||
}).WithContext(request.WithCompressionDisabled(context.Background(), false)),
|
|
||||||
wantCode: http.StatusOK,
|
|
||||||
wantHeaders: http.Header{
|
|
||||||
"Content-Type": []string{"application/json"},
|
|
||||||
"Content-Encoding": []string{"gzip"},
|
|
||||||
"Vary": []string{"Accept-Encoding"},
|
|
||||||
},
|
|
||||||
wantBody: gzipContent(largePayload, defaultGzipContentEncodingLevel),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "compress on gzip, request's context disables compression",
|
|
||||||
compressionEnabled: true,
|
|
||||||
out: largePayload,
|
|
||||||
mediaType: "application/json",
|
|
||||||
req: (&http.Request{
|
|
||||||
Header: http.Header{
|
|
||||||
"Accept-Encoding": []string{"gzip"},
|
|
||||||
},
|
|
||||||
URL: &url.URL{Path: "/path"},
|
|
||||||
}).WithContext(request.WithCompressionDisabled(context.Background(), true)),
|
|
||||||
wantCode: http.StatusOK,
|
|
||||||
wantHeaders: http.Header{"Content-Type": []string{"application/json"}},
|
|
||||||
wantBody: largePayload,
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
{
|
||||||
name: "compression is not performed on small objects",
|
name: "compression is not performed on small objects",
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2022 The Kubernetes Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package request
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
)
|
|
||||||
|
|
||||||
type disableCompressionIDKeyType int
|
|
||||||
|
|
||||||
const disableCompressionIDKey disableCompressionIDKeyType = iota
|
|
||||||
|
|
||||||
// WithCompressionDisabled stores bool in context.
|
|
||||||
func WithCompressionDisabled(parent context.Context, disableCompression bool) context.Context {
|
|
||||||
return WithValue(parent, disableCompressionIDKey, disableCompression)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CompressionDisabledFrom retrieves bool from context.
|
|
||||||
// Defaults to false if not set.
|
|
||||||
func CompressionDisabledFrom(ctx context.Context) bool {
|
|
||||||
decision, _ := ctx.Value(disableCompressionIDKey).(bool)
|
|
||||||
return decision
|
|
||||||
}
|
|
@ -1,43 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2022 The Kubernetes Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package request
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCompressionDisabled(t *testing.T) {
|
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
// Default value is false.
|
|
||||||
if got, want := CompressionDisabledFrom(ctx), false; got != want {
|
|
||||||
t.Errorf("CompressionDisabledFrom(ctx) = %v; want = %v", got, want)
|
|
||||||
}
|
|
||||||
|
|
||||||
// We retrieve stored true.
|
|
||||||
ctx = WithCompressionDisabled(ctx, true)
|
|
||||||
if got, want := CompressionDisabledFrom(ctx), true; got != want {
|
|
||||||
t.Errorf("CompressionDisabledFrom(ctx) = %v; want = %v", got, want)
|
|
||||||
}
|
|
||||||
|
|
||||||
// We retrieve stored false.
|
|
||||||
ctx = WithCompressionDisabled(ctx, false)
|
|
||||||
if got, want := CompressionDisabledFrom(ctx), false; got != want {
|
|
||||||
t.Errorf("CompressionDisabledFrom(ctx) = %v; want = %v", got, want)
|
|
||||||
}
|
|
||||||
}
|
|
@ -257,9 +257,6 @@ type Config struct {
|
|||||||
|
|
||||||
// StorageVersionManager holds the storage versions of the API resources installed by this server.
|
// StorageVersionManager holds the storage versions of the API resources installed by this server.
|
||||||
StorageVersionManager storageversion.Manager
|
StorageVersionManager storageversion.Manager
|
||||||
|
|
||||||
// CompressionDisabledFunc returns whether compression should be disabled for a given request.
|
|
||||||
CompressionDisabledFunc genericapifilters.CompressionDisabledFunc
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type RecommendedConfig struct {
|
type RecommendedConfig struct {
|
||||||
@ -859,9 +856,6 @@ func DefaultBuildHandlerChain(apiHandler http.Handler, c *Config) http.Handler {
|
|||||||
if c.ShutdownSendRetryAfter {
|
if c.ShutdownSendRetryAfter {
|
||||||
handler = genericfilters.WithRetryAfter(handler, c.lifecycleSignals.NotAcceptingNewRequest.Signaled())
|
handler = genericfilters.WithRetryAfter(handler, c.lifecycleSignals.NotAcceptingNewRequest.Signaled())
|
||||||
}
|
}
|
||||||
if c.CompressionDisabledFunc != nil {
|
|
||||||
handler = genericapifilters.WithCompressionDisabled(handler, c.CompressionDisabledFunc)
|
|
||||||
}
|
|
||||||
handler = genericfilters.WithHTTPLogging(handler)
|
handler = genericfilters.WithHTTPLogging(handler)
|
||||||
if utilfeature.DefaultFeatureGate.Enabled(genericfeatures.APIServerTracing) {
|
if utilfeature.DefaultFeatureGate.Enabled(genericfeatures.APIServerTracing) {
|
||||||
handler = genericapifilters.WithTracing(handler, c.TracerProvider)
|
handler = genericapifilters.WithTracing(handler, c.TracerProvider)
|
||||||
|
@ -26,9 +26,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||||
"k8s.io/apimachinery/pkg/util/errors"
|
"k8s.io/apimachinery/pkg/util/errors"
|
||||||
"k8s.io/apiserver/pkg/server"
|
"k8s.io/apiserver/pkg/server"
|
||||||
"k8s.io/apiserver/pkg/util/disablecompression"
|
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
netutils "k8s.io/utils/net"
|
|
||||||
|
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
)
|
)
|
||||||
@ -65,11 +63,6 @@ type ServerRunOptions struct {
|
|||||||
// If enabled, after ShutdownDelayDuration elapses, any incoming request is
|
// If enabled, after ShutdownDelayDuration elapses, any incoming request is
|
||||||
// rejected with a 429 status code and a 'Retry-After' response.
|
// rejected with a 429 status code and a 'Retry-After' response.
|
||||||
ShutdownSendRetryAfter bool
|
ShutdownSendRetryAfter bool
|
||||||
|
|
||||||
// DisableCompressionForClientIPs is a comma separated list of CIDR IP ranges
|
|
||||||
// (parsable by net.ParseCIDR, as defined in RFC 4632 and RFC 4291) for which
|
|
||||||
// traffic compression should be disabled.
|
|
||||||
DisableCompressionForClientIPs []string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServerRunOptions() *ServerRunOptions {
|
func NewServerRunOptions() *ServerRunOptions {
|
||||||
@ -85,7 +78,6 @@ func NewServerRunOptions() *ServerRunOptions {
|
|||||||
MaxRequestBodyBytes: defaults.MaxRequestBodyBytes,
|
MaxRequestBodyBytes: defaults.MaxRequestBodyBytes,
|
||||||
EnablePriorityAndFairness: true,
|
EnablePriorityAndFairness: true,
|
||||||
ShutdownSendRetryAfter: false,
|
ShutdownSendRetryAfter: false,
|
||||||
DisableCompressionForClientIPs: nil,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,13 +97,6 @@ func (s *ServerRunOptions) ApplyTo(c *server.Config) error {
|
|||||||
c.MaxRequestBodyBytes = s.MaxRequestBodyBytes
|
c.MaxRequestBodyBytes = s.MaxRequestBodyBytes
|
||||||
c.PublicAddress = s.AdvertiseAddress
|
c.PublicAddress = s.AdvertiseAddress
|
||||||
c.ShutdownSendRetryAfter = s.ShutdownSendRetryAfter
|
c.ShutdownSendRetryAfter = s.ShutdownSendRetryAfter
|
||||||
if len(s.DisableCompressionForClientIPs) != 0 {
|
|
||||||
pred, err := disablecompression.NewClientIPPredicate(s.DisableCompressionForClientIPs)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
c.CompressionDisabledFunc = pred.Predicate
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -176,10 +161,6 @@ func (s *ServerRunOptions) Validate() []error {
|
|||||||
if err := validateHSTSDirectives(s.HSTSDirectives); err != nil {
|
if err := validateHSTSDirectives(s.HSTSDirectives); err != nil {
|
||||||
errors = append(errors, err)
|
errors = append(errors, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := netutils.ParseCIDRs(s.DisableCompressionForClientIPs); err != nil {
|
|
||||||
errors = append(errors, err)
|
|
||||||
}
|
|
||||||
return errors
|
return errors
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,8 +256,5 @@ func (s *ServerRunOptions) AddUniversalFlags(fs *pflag.FlagSet) {
|
|||||||
"during this window all incoming requests will be rejected with a status code 429 and a 'Retry-After' response header, "+
|
"during this window all incoming requests will be rejected with a status code 429 and a 'Retry-After' response header, "+
|
||||||
"in addition 'Connection: close' response header is set in order to tear down the TCP connection when idle.")
|
"in addition 'Connection: close' response header is set in order to tear down the TCP connection when idle.")
|
||||||
|
|
||||||
fs.StringSliceVar(&s.DisableCompressionForClientIPs, "disable-compression-for-client-ips", s.DisableCompressionForClientIPs, ""+
|
|
||||||
"A comma separated list of client IP ranges in CIDR notation like \"192.0.2.0/24\" or \"2001:db8::/32\", as defined in RFC 4632 and RFC 4291, for which traffic compression will be disabled.")
|
|
||||||
|
|
||||||
utilfeature.DefaultMutableFeatureGate.AddFlag(fs)
|
utilfeature.DefaultMutableFeatureGate.AddFlag(fs)
|
||||||
}
|
}
|
||||||
|
@ -1,57 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2022 The Kubernetes Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package disablecompression
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
|
||||||
netutils "k8s.io/utils/net"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ClientIPPredicate.Predicate implements CompressionDisabledFunc interface that decides
|
|
||||||
// based on client IP.
|
|
||||||
type ClientIPPredicate struct {
|
|
||||||
cidrs []*net.IPNet
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewClientIPPredicate creates a new ClientIPPredicate instance.
|
|
||||||
func NewClientIPPredicate(cidrStrings []string) (*ClientIPPredicate, error) {
|
|
||||||
cidrs, err := netutils.ParseCIDRs(cidrStrings)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to parse cidrs: %v", err)
|
|
||||||
}
|
|
||||||
return &ClientIPPredicate{cidrs: cidrs}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Predicate checks if ClientIP matches any cidr.
|
|
||||||
func (c *ClientIPPredicate) Predicate(req *http.Request) (bool, error) {
|
|
||||||
ip := utilnet.GetClientIP(req)
|
|
||||||
if ip == nil {
|
|
||||||
return false, fmt.Errorf("unable to determine source IP for %v", req)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, cidr := range c.cidrs {
|
|
||||||
if cidr.Contains(ip) {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false, nil
|
|
||||||
}
|
|
@ -1,118 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2022 The Kubernetes Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package disablecompression
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestNewClientIPPredicate(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
cidrStrings []string
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "rfc1918",
|
|
||||||
cidrStrings: []string{"10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "rfc4193 (ipv6)",
|
|
||||||
cidrStrings: []string{"fc00::/7"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "ipv6 loopback",
|
|
||||||
cidrStrings: []string{"::1/128"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "bad cidr",
|
|
||||||
cidrStrings: []string{"not a cidr string"},
|
|
||||||
wantErr: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
got, err := NewClientIPPredicate(tt.cidrStrings)
|
|
||||||
if (err != nil) != tt.wantErr {
|
|
||||||
t.Fatalf("NewClientIPPredicate() error = %v, wantErr %v", err, tt.wantErr)
|
|
||||||
}
|
|
||||||
if tt.wantErr {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if got, want := len(got.cidrs), len(tt.cidrStrings); got != want {
|
|
||||||
t.Errorf("len(NewClientIPPredicate.cidrs()) = %v, want %v", got, want)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestClientIPPredicate_Predicate(t *testing.T) {
|
|
||||||
check, err := NewClientIPPredicate([]string{"::1/128", "10.0.0.0/8"})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("failed to construct NewClientIPPredicate: %v", err)
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
req *http.Request
|
|
||||||
want bool
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "ipv4, in range",
|
|
||||||
req: &http.Request{RemoteAddr: "10.0.0.1:123"},
|
|
||||||
want: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "ipv4, out of range",
|
|
||||||
req: &http.Request{RemoteAddr: "11.0.0.1:123"},
|
|
||||||
want: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "ipv6, in range",
|
|
||||||
req: &http.Request{RemoteAddr: "[::1]:123"},
|
|
||||||
want: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "ipv6, out of range",
|
|
||||||
req: &http.Request{RemoteAddr: "[::2]:123"},
|
|
||||||
want: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "no IP",
|
|
||||||
req: &http.Request{},
|
|
||||||
wantErr: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "RemoteAddr doesn't parse",
|
|
||||||
req: &http.Request{RemoteAddr: "this is definitely not an IP address and port"},
|
|
||||||
wantErr: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
got, err := check.Predicate(tt.req)
|
|
||||||
if (err != nil) != tt.wantErr {
|
|
||||||
t.Errorf("ClientIPPredicate.Predicate() error = %v, wantErr %v", err, tt.wantErr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if got != tt.want {
|
|
||||||
t.Errorf("ClientIPPredicate.Predicate() = %v, want %v", got, tt.want)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
1
vendor/modules.txt
vendored
1
vendor/modules.txt
vendored
@ -1656,7 +1656,6 @@ k8s.io/apiserver/pkg/storage/value/encrypt/identity
|
|||||||
k8s.io/apiserver/pkg/storage/value/encrypt/secretbox
|
k8s.io/apiserver/pkg/storage/value/encrypt/secretbox
|
||||||
k8s.io/apiserver/pkg/storageversion
|
k8s.io/apiserver/pkg/storageversion
|
||||||
k8s.io/apiserver/pkg/util/apihelpers
|
k8s.io/apiserver/pkg/util/apihelpers
|
||||||
k8s.io/apiserver/pkg/util/disablecompression
|
|
||||||
k8s.io/apiserver/pkg/util/dryrun
|
k8s.io/apiserver/pkg/util/dryrun
|
||||||
k8s.io/apiserver/pkg/util/feature
|
k8s.io/apiserver/pkg/util/feature
|
||||||
k8s.io/apiserver/pkg/util/flowcontrol
|
k8s.io/apiserver/pkg/util/flowcontrol
|
||||||
|
Loading…
Reference in New Issue
Block a user