From 02caeafb5d9eeaa7a55b269ae5fccfb806b19e66 Mon Sep 17 00:00:00 2001 From: Darren Shepherd Date: Mon, 9 Mar 2020 23:17:40 -0700 Subject: [PATCH] Support gzip encoding --- pkg/schemaserver/server/server.go | 26 ++++++++++------ pkg/schemaserver/writer/gzip.go | 52 +++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 10 deletions(-) create mode 100644 pkg/schemaserver/writer/gzip.go diff --git a/pkg/schemaserver/server/server.go b/pkg/schemaserver/server/server.go index efe88cc..e742719 100644 --- a/pkg/schemaserver/server/server.go +++ b/pkg/schemaserver/server/server.go @@ -41,19 +41,25 @@ func DefaultAPIServer() *Server { s := &Server{ Schemas: types.EmptyAPISchemas().MustAddSchemas(builtin.Schemas), ResponseWriters: map[string]types.ResponseWriter{ - "json": &writer.EncodingResponseWriter{ - ContentType: "application/json", - Encoder: types.JSONEncoder, - }, - "html": &writer.HTMLResponseWriter{ - EncodingResponseWriter: writer.EncodingResponseWriter{ - Encoder: types.JSONEncoder, + "json": &writer.GzipWriter{ + ResponseWriter: &writer.EncodingResponseWriter{ ContentType: "application/json", + Encoder: types.JSONEncoder, }, }, - "yaml": &writer.EncodingResponseWriter{ - ContentType: "application/yaml", - Encoder: types.YAMLEncoder, + "html": &writer.GzipWriter{ + ResponseWriter: &writer.HTMLResponseWriter{ + EncodingResponseWriter: writer.EncodingResponseWriter{ + Encoder: types.JSONEncoder, + ContentType: "application/json", + }, + }, + }, + "yaml": &writer.GzipWriter{ + ResponseWriter: &writer.EncodingResponseWriter{ + ContentType: "application/yaml", + Encoder: types.YAMLEncoder, + }, }, }, AccessControl: &SchemaBasedAccess{}, diff --git a/pkg/schemaserver/writer/gzip.go b/pkg/schemaserver/writer/gzip.go new file mode 100644 index 0000000..c028fae --- /dev/null +++ b/pkg/schemaserver/writer/gzip.go @@ -0,0 +1,52 @@ +package writer + +import ( + "compress/gzip" + "io" + "io/ioutil" + "net/http" + "strings" + + "github.com/rancher/steve/pkg/schemaserver/types" +) + +type GzipWriter struct { + types.ResponseWriter +} + +func setup(apiOp *types.APIRequest) (*types.APIRequest, io.Closer) { + if !strings.Contains(apiOp.Request.Header.Get("Accept-Encoding"), "gzip") { + return apiOp, ioutil.NopCloser(nil) + } + + apiOp.Response.Header().Set("Content-Encoding", "gzip") + apiOp.Response.Header().Del("Content-Length") + + gz := gzip.NewWriter(apiOp.Response) + gzw := &gzipResponseWriter{Writer: gz, ResponseWriter: apiOp.Response} + + newOp := *apiOp + newOp.Response = gzw + return &newOp, gz +} + +func (g *GzipWriter) Write(apiOp *types.APIRequest, code int, obj types.APIObject) { + apiOp, closer := setup(apiOp) + defer closer.Close() + g.ResponseWriter.Write(apiOp, code, obj) +} + +func (g *GzipWriter) WriteList(apiOp *types.APIRequest, code int, obj types.APIObjectList) { + apiOp, closer := setup(apiOp) + defer closer.Close() + g.ResponseWriter.WriteList(apiOp, code, obj) +} + +type gzipResponseWriter struct { + io.Writer + http.ResponseWriter +} + +func (g gzipResponseWriter) Write(b []byte) (int, error) { + return g.Writer.Write(b) +}