Skip to content

Commit

Permalink
pool enabled and wrap gzip with aah response
Browse files Browse the repository at this point in the history
  • Loading branch information
jeevatkm committed May 7, 2017
1 parent 5de6297 commit 49cab38
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 24 deletions.
57 changes: 49 additions & 8 deletions gzip_response.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"io"
"net"
"net/http"
"sync"

"aahframework.org/essentials.v0"
)
Expand All @@ -21,8 +22,19 @@ type GzipResponse struct {
gw *gzip.Writer
}

// interface compliance
var (
// GzipLevel holds value from app config.
GzipLevel int

grPool = sync.Pool{
New: func() interface{} {
return &GzipResponse{}
},
}

gwPool = sync.Pool{}

// interface compliance
_ http.CloseNotifier = &GzipResponse{}
_ http.Flusher = &GzipResponse{}
_ http.Hijacker = &GzipResponse{}
Expand All @@ -35,15 +47,22 @@ var (
// Global methods
//___________________________________

// WrapGzipResponseWriter wraps `http.ResponseWriter`, returns aah framework response
// GetGzipResponseWriter wraps `http.ResponseWriter`, returns aah framework response
// writer that allows to advantage of response process.
func WrapGzipResponseWriter(w http.ResponseWriter, level int) ResponseWriter {
rw := WrapResponseWriter(w)
func GetGzipResponseWriter(w ResponseWriter) ResponseWriter {
gr := grPool.Get().(*GzipResponse)
gr.gw = getGzipWriter(w)
gr.r = w.(*Response)
return gr
}

// Since Gzip level is validated in the framework while loading,
// so expected to have valid level which between 1 and 9.
gzw, _ := gzip.NewWriterLevel(rw, level)
return &GzipResponse{gw: gzw, r: rw.(*Response)}
// PutGzipResponseWiriter method resets and puts the gzip writer into pool.
func PutGzipResponseWiriter(rw ResponseWriter) {
gw := rw.(*GzipResponse)
putGzipWriter(gw.gw)
PutResponseWriter(gw.r)
_ = gw.Close()
grPool.Put(gw)
}

//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
Expand Down Expand Up @@ -119,3 +138,25 @@ func (g *GzipResponse) Hijack() (net.Conn, *bufio.ReadWriter, error) {
func (g *GzipResponse) Push(target string, opts *http.PushOptions) error {
return g.r.Push(target, opts)
}

//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// GzipResponse Unexported methods
//___________________________________

func getGzipWriter(w io.Writer) *gzip.Writer {
gw := gwPool.Get()
if gw == nil {
if ngw, err := gzip.NewWriterLevel(w, GzipLevel); err == nil {
return ngw
}
return nil
}
ngw := gw.(*gzip.Writer)
ngw.Reset(w)
return ngw
}

func putGzipWriter(gw *gzip.Writer) {
_ = gw.Close()
gwPool.Put(gw)
}
10 changes: 7 additions & 3 deletions gzip_response_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ import (

func TestHTTPGzipWriter(t *testing.T) {
handler := func(w http.ResponseWriter, r *http.Request) {
gw := WrapGzipResponseWriter(w, gzip.BestSpeed)
defer ess.CloseQuietly(gw)
GzipLevel = gzip.BestSpeed
gw := GetGzipResponseWriter(GetResponseWriter(w))
defer PutGzipResponseWiriter(gw)

gw.Header().Set(HeaderVary, HeaderAcceptEncoding)
gw.Header().Set(HeaderContentEncoding, "gzip")
Expand All @@ -42,6 +43,8 @@ func TestHTTPGzipWriter(t *testing.T) {

gw.(http.Flusher).Flush()

_ = gw.(http.Pusher).Push("/test/sample.txt", nil)

ch := gw.(http.CloseNotifier).CloseNotify()
assert.NotNil(t, ch)
}
Expand All @@ -53,7 +56,8 @@ func TestHTTPGzipWriter(t *testing.T) {

func TestHTTPGzipHijack(t *testing.T) {
handler := func(w http.ResponseWriter, r *http.Request) {
gw := WrapGzipResponseWriter(w, gzip.BestSpeed)
GzipLevel = gzip.BestSpeed
gw := GetGzipResponseWriter(GetResponseWriter(w))

con, rw, err := gw.(http.Hijacker).Hijack()
assert.FailOnError(t, err, "")
Expand Down
29 changes: 24 additions & 5 deletions response.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"io"
"net"
"net/http"
"sync"

"aahframework.org/essentials.v0"
)
Expand Down Expand Up @@ -40,8 +41,14 @@ type (
}
)

// interface compliance
var (
rPool = sync.Pool{
New: func() interface{} {
return &Response{}
},
}

// interface compliance
_ http.CloseNotifier = &Response{}
_ http.Flusher = &Response{}
_ http.Hijacker = &Response{}
Expand All @@ -54,10 +61,22 @@ var (
// Global methods
//___________________________________

// WrapResponseWriter wraps `http.ResponseWriter`, returns aah framework response
// writer that allows to advantage of response process.
func WrapResponseWriter(w http.ResponseWriter) ResponseWriter {
return &Response{w: w}
// GetResponseWriter method wraps given writer and returns the aah response writer.
func GetResponseWriter(w http.ResponseWriter) ResponseWriter {
rw := rPool.Get().(*Response)
rw.w = w
return rw
}

// PutResponseWriter method puts response writer back to pool.
func PutResponseWriter(aw ResponseWriter) {
r := aw.(*Response)
_ = r.Close()
r.w = nil
r.status = 0
r.bytesWritten = 0
r.wroteStatus = false
rPool.Put(r)
}

//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
Expand Down
17 changes: 9 additions & 8 deletions response_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ import (

func TestHTTPResponseWriter(t *testing.T) {
handler := func(w http.ResponseWriter, r *http.Request) {
writer := WrapResponseWriter(w)
defer ess.CloseQuietly(writer)
writer := GetResponseWriter(w)
defer PutResponseWriter(writer)

writer.WriteHeader(http.StatusOK)
assert.Equal(t, http.StatusOK, writer.Status())
Expand All @@ -35,8 +35,8 @@ func TestHTTPResponseWriter(t *testing.T) {

func TestHTTPNoStatusWritten(t *testing.T) {
handler := func(w http.ResponseWriter, r *http.Request) {
writer := WrapResponseWriter(w)
defer ess.CloseQuietly(writer)
writer := GetResponseWriter(w)
defer PutResponseWriter(writer)

_, _ = writer.Write([]byte("aah framework no status written"))
assert.Equal(t, 31, writer.BytesWritten())
Expand All @@ -47,8 +47,8 @@ func TestHTTPNoStatusWritten(t *testing.T) {

func TestHTTPMultipleStatusWritten(t *testing.T) {
handler := func(w http.ResponseWriter, r *http.Request) {
writer := WrapResponseWriter(w)
defer ess.CloseQuietly(writer)
writer := GetResponseWriter(w)
defer PutResponseWriter(writer)

writer.WriteHeader(http.StatusOK)
writer.WriteHeader(http.StatusAccepted)
Expand All @@ -62,7 +62,7 @@ func TestHTTPMultipleStatusWritten(t *testing.T) {

func TestHTTPHijackCall(t *testing.T) {
handler := func(w http.ResponseWriter, r *http.Request) {
writer := WrapResponseWriter(w)
writer := GetResponseWriter(w)

con, rw, err := writer.(http.Hijacker).Hijack()
assert.FailOnError(t, err, "")
Expand All @@ -85,7 +85,8 @@ func TestHTTPHijackCall(t *testing.T) {

func TestHTTPCallCloseNotifyAndFlush(t *testing.T) {
handler := func(w http.ResponseWriter, r *http.Request) {
writer := WrapResponseWriter(w)
writer := GetResponseWriter(w)
defer PutResponseWriter(writer)

_, _ = writer.Write([]byte("aah framework calling close notify and flush"))
assert.Equal(t, 44, writer.BytesWritten())
Expand Down

0 comments on commit 49cab38

Please sign in to comment.