git subrepo clone (merge) https://github.com/kubernetes-incubator/metrics-server.git metrics-server
subrepo:
subdir: "metrics-server"
merged: "92d8412"
upstream:
origin: "https://github.com/kubernetes-incubator/metrics-server.git"
branch: "master"
commit: "92d8412"
git-subrepo:
version: "0.4.0"
origin: "???"
commit: "???"
diff --git a/metrics-server/vendor/k8s.io/apiserver/pkg/server/filters/compression.go b/metrics-server/vendor/k8s.io/apiserver/pkg/server/filters/compression.go
new file mode 100644
index 0000000..625cd5c
--- /dev/null
+++ b/metrics-server/vendor/k8s.io/apiserver/pkg/server/filters/compression.go
@@ -0,0 +1,181 @@
+/*
+Copyright 2017 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 (
+ "compress/gzip"
+ "compress/zlib"
+ "errors"
+ "fmt"
+ "io"
+ "net/http"
+ "strings"
+
+ "github.com/emicklei/go-restful"
+
+ "k8s.io/apimachinery/pkg/util/runtime"
+ "k8s.io/apiserver/pkg/endpoints/request"
+)
+
+// Compressor is an interface to compression writers
+type Compressor interface {
+ io.WriteCloser
+ Flush() error
+}
+
+const (
+ headerAcceptEncoding = "Accept-Encoding"
+ headerContentEncoding = "Content-Encoding"
+
+ encodingGzip = "gzip"
+ encodingDeflate = "deflate"
+)
+
+// WithCompression wraps an http.Handler with the Compression Handler
+func WithCompression(handler http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+ wantsCompression, encoding := wantsCompressedResponse(req)
+ w.Header().Set("Vary", "Accept-Encoding")
+ if wantsCompression {
+ compressionWriter, err := NewCompressionResponseWriter(w, encoding)
+ if err != nil {
+ handleError(w, req, err)
+ runtime.HandleError(fmt.Errorf("failed to compress HTTP response: %v", err))
+ return
+ }
+ compressionWriter.Header().Set("Content-Encoding", encoding)
+ handler.ServeHTTP(compressionWriter, req)
+ compressionWriter.(*compressionResponseWriter).Close()
+ } else {
+ handler.ServeHTTP(w, req)
+ }
+ })
+}
+
+// wantsCompressedResponse reads the Accept-Encoding header to see if and which encoding is requested.
+func wantsCompressedResponse(req *http.Request) (bool, string) {
+ // don't compress watches
+ ctx := req.Context()
+ info, ok := request.RequestInfoFrom(ctx)
+ if !ok {
+ return false, ""
+ }
+ if !info.IsResourceRequest {
+ return false, ""
+ }
+ if info.Verb == "watch" {
+ return false, ""
+ }
+ header := req.Header.Get(headerAcceptEncoding)
+ gi := strings.Index(header, encodingGzip)
+ zi := strings.Index(header, encodingDeflate)
+ // use in order of appearance
+ switch {
+ case gi == -1:
+ return zi != -1, encodingDeflate
+ case zi == -1:
+ return gi != -1, encodingGzip
+ case gi < zi:
+ return true, encodingGzip
+ default:
+ return true, encodingDeflate
+ }
+}
+
+type compressionResponseWriter struct {
+ writer http.ResponseWriter
+ compressor Compressor
+ encoding string
+}
+
+// NewCompressionResponseWriter returns wraps w with a compression ResponseWriter, using the given encoding
+func NewCompressionResponseWriter(w http.ResponseWriter, encoding string) (http.ResponseWriter, error) {
+ var compressor Compressor
+ switch encoding {
+ case encodingGzip:
+ compressor = gzip.NewWriter(w)
+ case encodingDeflate:
+ compressor = zlib.NewWriter(w)
+ default:
+ return nil, fmt.Errorf("%s is not a supported encoding type", encoding)
+ }
+ return &compressionResponseWriter{
+ writer: w,
+ compressor: compressor,
+ encoding: encoding,
+ }, nil
+}
+
+// compressionResponseWriter implements http.Responsewriter Interface
+var _ http.ResponseWriter = &compressionResponseWriter{}
+
+func (c *compressionResponseWriter) Header() http.Header {
+ return c.writer.Header()
+}
+
+// compress data according to compression method
+func (c *compressionResponseWriter) Write(p []byte) (int, error) {
+ if c.compressorClosed() {
+ return -1, errors.New("compressing error: tried to write data using closed compressor")
+ }
+ c.Header().Set(headerContentEncoding, c.encoding)
+ defer c.compressor.Flush()
+ return c.compressor.Write(p)
+}
+
+func (c *compressionResponseWriter) WriteHeader(status int) {
+ c.writer.WriteHeader(status)
+}
+
+// CloseNotify is part of http.CloseNotifier interface
+func (c *compressionResponseWriter) CloseNotify() <-chan bool {
+ return c.writer.(http.CloseNotifier).CloseNotify()
+}
+
+// Close the underlying compressor
+func (c *compressionResponseWriter) Close() error {
+ if c.compressorClosed() {
+ return errors.New("Compressing error: tried to close already closed compressor")
+ }
+
+ c.compressor.Close()
+ c.compressor = nil
+ return nil
+}
+
+func (c *compressionResponseWriter) Flush() {
+ if c.compressorClosed() {
+ return
+ }
+ c.compressor.Flush()
+}
+
+func (c *compressionResponseWriter) compressorClosed() bool {
+ return nil == c.compressor
+}
+
+// RestfulWithCompression wraps WithCompression to be compatible with go-restful
+func RestfulWithCompression(function restful.RouteFunction) restful.RouteFunction {
+ return restful.RouteFunction(func(request *restful.Request, response *restful.Response) {
+ handler := WithCompression(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+ response.ResponseWriter = w
+ request.Request = req
+ function(request, response)
+ }))
+ handler.ServeHTTP(response.ResponseWriter, request.Request)
+ })
+}