Skip to content

Commit

Permalink
refactor internal structures
Browse files Browse the repository at this point in the history
  • Loading branch information
abihf committed Dec 6, 2021
1 parent 07e33d1 commit 07239df
Show file tree
Hide file tree
Showing 7 changed files with 148 additions and 143 deletions.
53 changes: 53 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package compress

import (
"compress/gzip"
"regexp"
"sort"
)

var DefaultAllowedTypes = []*regexp.Regexp{
regexp.MustCompile(`^text/`),
regexp.MustCompile(`^application/json`),
regexp.MustCompile(`^application/javascript`),
regexp.MustCompile(`\+(xml|json)$`),
regexp.MustCompile(`^image/svg`),
}

type config struct {
supportedEncoding []string

encoders map[string]*encoder
allowedType []*regexp.Regexp
minSize uint64
silent bool
}

func newConfig(options ...Option) *config {
c := &config{minSize: 4 * 1024, allowedType: DefaultAllowedTypes, encoders: map[string]*encoder{}}
WithGzip(100, gzip.DefaultCompression)(c)
for _, o := range options {
o(c)
}
c.populateSupportedEncoding()
return c
}

func (c *config) populateSupportedEncoding() {
type encoderWithName struct {
*encoder
name string
}

encList := make([]encoderWithName, 0, len(c.encoders))
for name, enc := range c.encoders {
encList = append(encList, encoderWithName{enc, name})
}
sort.Slice(encList, func(i, j int) bool {
return encList[i].priority < encList[j].priority
})
c.supportedEncoding = make([]string, 0, len(encList))
for _, enc := range encList {
c.supportedEncoding = append(c.supportedEncoding, enc.name)
}
}
4 changes: 1 addition & 3 deletions middleware_test.go → config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,13 @@ package compress
import (
"context"
"io"
"net/http"
"testing"

"gotest.tools/assert"
)

func Test_populateSupportedEncoding(t *testing.T) {
var dummyFactory EncoderFactory = func(ctx context.Context, w io.Writer) (io.WriteCloser, error) { return nil, nil }
var h http.Handler
m := newMiddleware(h, WithEncoder("a", 1, dummyFactory), WithEncoder("b", 2, dummyFactory), WithEncoder("c", 3, dummyFactory), WihtoutEncoder("gzip"))
m := newConfig(WithEncoder("a", 1, dummyFactory), WithEncoder("b", 2, dummyFactory), WithEncoder("c", 3, dummyFactory), WihtoutEncoder("gzip"))
assert.DeepEqual(t, m.supportedEncoding, []string{"a", "b", "c"})
}
5 changes: 5 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ go 1.17

require (
github.com/kevinpollet/nego v0.0.0-20211010160919-a65cd48cee43

)

// test
require (
gotest.tools v2.2.0+incompatible
)

Expand Down
9 changes: 0 additions & 9 deletions handler.go

This file was deleted.

94 changes: 26 additions & 68 deletions middleware.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
package compress

import (
"compress/gzip"
"context"
"io"
"net/http"
"regexp"
"sort"

"github.com/kevinpollet/nego"
)
Expand All @@ -18,72 +15,33 @@ type encoder struct {
factory EncoderFactory
}

type middleware struct {
http.Handler

supportedEncoding []string

encoders map[string]*encoder
allowedType []*regexp.Regexp
minSize uint64
silent bool
}

var DefaultAllowedTypes = []*regexp.Regexp{
regexp.MustCompile(`^text/`),
regexp.MustCompile(`^application/json`),
regexp.MustCompile(`^application/javascript`),
regexp.MustCompile(`\+(xml|json)$`),
regexp.MustCompile(`^image/svg`),
}

func newMiddleware(h http.Handler, options ...Option) *middleware {
m := &middleware{Handler: h, minSize: 4 * 1024, allowedType: DefaultAllowedTypes, encoders: map[string]*encoder{}}
WithGzip(100, gzip.DefaultCompression)(m)
for _, o := range options {
o(m)
type Middleware func(http.Handler) http.Handler

func New(options ...Option) Middleware {
c := newConfig(options...)
return func(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Vary", "Accept-Encoding")

encoding := nego.NegotiateContentEncoding(r, c.supportedEncoding...)
enc, ok := c.encoders[encoding]
if ok {
mw := &responseWriter{
ResponseWriter: w,
ctx: r.Context(),
factory: enc.factory,
encoding: encoding,
c: c,
status: http.StatusOK,
}
defer mw.flush()
w = mw
}
h.ServeHTTP(w, r)
})
}
m.populateSupportedEncoding()
return m
}

func (m *middleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// for cache validation
w.Header().Add("Vary", "Accept-Encoding")

encoding := nego.NegotiateContentEncoding(r, m.supportedEncoding...)
enc, ok := m.encoders[encoding]
if ok {
mw := &middlewareWriter{
ResponseWriter: w,
ctx: r.Context(),
factory: enc.factory,
encoding: encoding,
m: m,
status: http.StatusOK,
}
defer mw.flush()
w = mw
}

m.Handler.ServeHTTP(w, r)
}

func (m *middleware) populateSupportedEncoding() {
type encoderWithName struct {
*encoder
name string
}

encList := make([]encoderWithName, 0, len(m.encoders))
for name, enc := range m.encoders {
encList = append(encList, encoderWithName{enc, name})
}
sort.Slice(encList, func(i, j int) bool {
return encList[i].priority < encList[j].priority
})
m.supportedEncoding = make([]string, 0, len(encList))
for _, enc := range encList {
m.supportedEncoding = append(m.supportedEncoding, enc.name)
}
func Handler(h http.Handler, options ...Option) http.Handler {
return New(options...)(h)
}
20 changes: 10 additions & 10 deletions option.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ import (
"regexp"
)

type Option func(m *middleware)
type Option func(*config)

func WithEncoder(encoding string, priotity int, factory EncoderFactory) Option {
return func(m *middleware) {
return func(m *config) {
m.encoders[encoding] = &encoder{priority: priotity, factory: factory}
}
}

func WihtoutEncoder(encoding string) Option {
return func(m *middleware) {
delete(m.encoders, encoding)
return func(c *config) {
delete(c.encoders, encoding)
}
}

Expand All @@ -28,19 +28,19 @@ func WithGzip(priority, level int) Option {
}

func WithAllowedTypes(list []*regexp.Regexp) Option {
return func(m *middleware) {
m.allowedType = list
return func(c *config) {
c.allowedType = list
}
}

func WithMinSize(minSize uint64) Option {
return func(m *middleware) {
m.minSize = minSize
return func(c *config) {
c.minSize = minSize
}
}

func WithSilent() Option {
return func(m *middleware) {
m.silent = true
return func(c *config) {
c.silent = true
}
}
Loading

0 comments on commit 07239df

Please sign in to comment.