Skip to content
This repository has been archived by the owner on Dec 7, 2020. It is now read-only.

Commit

Permalink
Using compress/gzip
Browse files Browse the repository at this point in the history
  • Loading branch information
zt-sv authored and Bruno Oliveira da Silva committed Jun 19, 2020
1 parent 4c3331a commit b48a022
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 0 deletions.
2 changes: 2 additions & 0 deletions config_sample.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ skip-upstream-tls-verify: true|false
scopes: []
# enables more extra security features
enable-security-filter: true
# enables gzip compression for response
enable-compression: true
# headers permits you to inject custom headers into all requests
headers:
myheader_name: my_header_value
Expand Down
2 changes: 2 additions & 0 deletions doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,8 @@ type Config struct {
ContentSecurityPolicy string `json:"content-security-policy" yaml:"content-security-policy" usage:"specify the content security policy"`
// LocalhostMetrics indicated the metrics can only be consume via localhost
LocalhostMetrics bool `json:"localhost-metrics" yaml:"localhost-metrics" usage:"enforces the metrics page can only been requested from 127.0.0.1"`
// EnableCompression enables gzip compression for response
EnableCompression bool `json:"enable-compression" yaml:"enable-compression" usage:"enable gzip compression for response"`

// AccessTokenDuration is default duration applied to the access token cookie
AccessTokenDuration time.Duration `json:"access-token-duration" yaml:"access-token-duration" usage:"fallback cookie duration for the access token when using refresh tokens"`
Expand Down
45 changes: 45 additions & 0 deletions middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,15 @@ limitations under the License.
package main

import (
"compress/gzip"
"context"
"fmt"
"io"
"io/ioutil"
"net/http"
"regexp"
"strings"
"sync"
"time"

uuid "github.com/gofrs/uuid"
Expand All @@ -38,6 +42,47 @@ const (
normalizeFlags purell.NormalizationFlags = purell.FlagRemoveDotSegments | purell.FlagRemoveDuplicateSlashes
)

var gzPool = sync.Pool{
New: func() interface{} {
w := gzip.NewWriter(ioutil.Discard)
return w
},
}

type gzipResponseWriter struct {
io.Writer
http.ResponseWriter
}

func (w *gzipResponseWriter) WriteHeader(status int) {
w.Header().Del("Content-Length")
w.ResponseWriter.WriteHeader(status)
}

func (w *gzipResponseWriter) Write(b []byte) (int, error) {
return w.Writer.Write(b)
}

// gzipMiddleware is responsible for compressing a response
func gzipMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
if !strings.Contains(req.Header.Get("Accept-Encoding"), "gzip") {
next.ServeHTTP(w, req)
return
}

w.Header().Set("Content-Encoding", "gzip")

gz := gzPool.Get().(*gzip.Writer)
defer gzPool.Put(gz)

gz.Reset(w)
defer gz.Close()

next.ServeHTTP(&gzipResponseWriter{ResponseWriter: w, Writer: gz}, req)
})
}

// entrypointMiddleware is custom filtering for incoming requests
func entrypointMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
Expand Down
63 changes: 63 additions & 0 deletions middleware_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1598,3 +1598,66 @@ func TestRolesAdmissionHandlerClaims(t *testing.T) {
newFakeProxy(cfg).RunTests(t, []fakeRequest{c.Request})
}
}

func TestGzipCompression(t *testing.T) {
requests := []struct {
EnableCompression bool
Request fakeRequest
}{
{
EnableCompression: true,
Request: fakeRequest{
URI: "/gambol99.htm",
ExpectedProxy: true,
Headers: map[string]string{
"Accept-Encoding": "gzip, deflate, br",
},
ExpectedHeaders: map[string]string{
"Content-Encoding": "gzip",
},
},
},
{
EnableCompression: true,
Request: fakeRequest{
URI: testAdminURI,
ExpectedProxy: false,
Headers: map[string]string{
"Accept-Encoding": "gzip, deflate, br",
},
ExpectedHeaders: map[string]string{
"Content-Encoding": "gzip",
},
},
},
{
EnableCompression: false,
Request: fakeRequest{
URI: "/gambol99.htm",
ExpectedProxy: true,
Headers: map[string]string{
"Accept-Encoding": "gzip, deflate, br",
},
ExpectedNoProxyHeaders: []string{"Content-Encoding"},
},
},
{
EnableCompression: false,
Request: fakeRequest{
URI: testAdminURI,
ExpectedProxy: false,
Headers: map[string]string{
"Accept-Encoding": "gzip, deflate, br",
},
ExpectedNoProxyHeaders: []string{"Content-Encoding"},
},
},
}

for _, c := range requests {
cfg := newFakeKeycloakConfig()
cfg.Resources = []*Resource{{URL: "/admin*", Methods: allHTTPMethods}}
cfg.EnableCompression = c.EnableCompression
newFakeProxy(cfg).RunTests(t, []fakeRequest{c.Request})
}
}
3 changes: 3 additions & 0 deletions server.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,9 @@ func (r *oauthProxy) createReverseProxy() error {
// @step: enable the entrypoint middleware
engine.Use(entrypointMiddleware)

if r.config.EnableCompression {
engine.Use(gzipMiddleware)
}
if r.config.EnableLogging {
engine.Use(r.loggingMiddleware)
}
Expand Down
1 change: 1 addition & 0 deletions server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,7 @@ func newFakeKeycloakConfig() *Config {
EnableLogging: false,
EnableLoginHandler: true,
EnableTokenHeader: true,
EnableCompression: false,
Listen: "127.0.0.1:0",
OAuthURI: "/oauth",
OpenIDProviderTimeout: time.Second * 5,
Expand Down

0 comments on commit b48a022

Please sign in to comment.