mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 18:51:03 +01:00
5e4b63acb2
# FAQ ### Looking for free support? http://support.iris-go.com https://kataras.rocket.chat/channel/iris ### Looking for previous versions? https://github.com/kataras/iris#version ### Should I upgrade my Iris? Developers are not forced to upgrade if they don't really need it. Upgrade whenever you feel ready. > Iris uses the [vendor directory](https://docs.google.com/document/d/1Bz5-UB7g2uPBdOx-rw5t9MxJwkfpx90cqG9AFL0JAYo) feature, so you get truly reproducible builds, as this method guards against upstream renames and deletes. **How to upgrade**: Open your command-line and execute this command: `go get -u github.com/kataras/iris`. For further installation support, please click [here](http://support.iris-go.com/d/16-how-to-install-iris-web-framework). ### About our new home page http://iris-go.com Thanks to [Santosh Anand](https://github.com/santoshanand) the http://iris-go.com has been upgraded and it's really awesome! [Santosh](https://github.com/santoshanand) is a freelancer, he has a great knowledge of nodejs and express js, Android, iOS, React Native, Vue.js etc, if you need a developer to find or create a solution for your problem or task, please contact with him. The amount of the next two or three donations you'll send they will be immediately transferred to his own account balance, so be generous please! Read more at https://github.com/kataras/iris/blob/master/HISTORY.md Former-commit-id: eec2d71bbe011d6b48d2526eb25919e36e5ad94e
136 lines
4.1 KiB
Go
136 lines
4.1 KiB
Go
// Copyright 2017 Gerasimos Maropoulos, ΓΜ. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package context
|
|
|
|
import (
|
|
"io"
|
|
"sync"
|
|
|
|
"github.com/klauspost/compress/gzip"
|
|
)
|
|
|
|
// compressionPool is a wrapper of sync.Pool, to initialize a new compression writer pool
|
|
type compressionPool struct {
|
|
sync.Pool
|
|
Level int
|
|
}
|
|
|
|
// +------------------------------------------------------------+
|
|
// |GZIP raw io.writer, our gzip response writer will use that. |
|
|
// +------------------------------------------------------------+
|
|
|
|
// default writer pool with Compressor's level setted to -1
|
|
var gzipPool = &compressionPool{Level: -1}
|
|
|
|
// acquireGzipWriter prepares a gzip writer and returns it.
|
|
//
|
|
// see releaseGzipWriter too.
|
|
func acquireGzipWriter(w io.Writer) *gzip.Writer {
|
|
v := gzipPool.Get()
|
|
if v == nil {
|
|
gzipWriter, err := gzip.NewWriterLevel(w, gzipPool.Level)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
return gzipWriter
|
|
}
|
|
gzipWriter := v.(*gzip.Writer)
|
|
gzipWriter.Reset(w)
|
|
return gzipWriter
|
|
}
|
|
|
|
// releaseGzipWriter called when flush/close and put the gzip writer back to the pool.
|
|
//
|
|
// see acquireGzipWriter too.
|
|
func releaseGzipWriter(gzipWriter *gzip.Writer) {
|
|
gzipWriter.Close()
|
|
gzipPool.Put(gzipWriter)
|
|
}
|
|
|
|
// writeGzip writes a compressed form of p to the underlying io.Writer. The
|
|
// compressed bytes are not necessarily flushed until the Writer is closed.
|
|
func writeGzip(w io.Writer, b []byte) (int, error) {
|
|
gzipWriter := acquireGzipWriter(w)
|
|
n, err := gzipWriter.Write(b)
|
|
releaseGzipWriter(gzipWriter)
|
|
return n, err
|
|
}
|
|
|
|
var gzpool = sync.Pool{New: func() interface{} { return &GzipResponseWriter{} }}
|
|
|
|
// AcquireGzipResponseWriter returns a new *GzipResponseWriter from the pool.
|
|
// Releasing is done automatically when request and response is done.
|
|
func AcquireGzipResponseWriter() *GzipResponseWriter {
|
|
w := gzpool.Get().(*GzipResponseWriter)
|
|
return w
|
|
}
|
|
|
|
func releaseGzipResponseWriter(w *GzipResponseWriter) {
|
|
releaseGzipWriter(w.gzipWriter)
|
|
gzpool.Put(w)
|
|
}
|
|
|
|
// GzipResponseWriter is an upgraded response writer which writes compressed data to the underline ResponseWriter.
|
|
//
|
|
// It's a separate response writer because Iris gives you the ability to "fallback" and "roll-back" the gzip encoding if something
|
|
// went wrong with the response, and write http errors in plain form instead.
|
|
type GzipResponseWriter struct {
|
|
ResponseWriter
|
|
gzipWriter *gzip.Writer
|
|
chunks []byte
|
|
disabled bool
|
|
}
|
|
|
|
var _ ResponseWriter = &GzipResponseWriter{}
|
|
|
|
func (w *GzipResponseWriter) BeginGzipResponse(underline ResponseWriter) {
|
|
w.ResponseWriter = underline
|
|
w.gzipWriter = acquireGzipWriter(w.ResponseWriter)
|
|
w.chunks = w.chunks[0:0]
|
|
w.disabled = false
|
|
}
|
|
|
|
func (w *GzipResponseWriter) EndResponse() {
|
|
releaseGzipResponseWriter(w)
|
|
w.ResponseWriter.EndResponse()
|
|
}
|
|
|
|
// Write compresses and writes that data to the underline response writer
|
|
func (w *GzipResponseWriter) Write(contents []byte) (int, error) {
|
|
// save the contents to serve them (only gzip data here)
|
|
w.chunks = append(w.chunks, contents...)
|
|
return len(w.chunks), nil
|
|
}
|
|
|
|
func (w *GzipResponseWriter) FlushResponse() {
|
|
if w.disabled {
|
|
w.ResponseWriter.Write(w.chunks)
|
|
// remove gzip headers: no need, we just add two of them if gzip was enabled, below
|
|
// headers := w.ResponseWriter.Header()
|
|
// headers[contentType] = nil
|
|
// headers["X-Content-Type-Options"] = nil
|
|
// headers[varyHeader] = nil
|
|
// headers[contentEncodingHeader] = nil
|
|
// headers[contentLength] = nil
|
|
} else {
|
|
// if it's not disable write all chunks gzip compressed with the correct response headers.
|
|
w.ResponseWriter.Header().Add(varyHeaderKey, "Accept-Encoding")
|
|
w.ResponseWriter.Header().Set(contentEncodingHeaderKey, "gzip")
|
|
w.gzipWriter.Write(w.chunks) // it writes to the underline ResponseWriter.
|
|
}
|
|
w.ResponseWriter.FlushResponse()
|
|
}
|
|
|
|
// ResetBody resets the response body.
|
|
func (w *GzipResponseWriter) ResetBody() {
|
|
w.chunks = w.chunks[0:0]
|
|
}
|
|
|
|
// Disable, disables the gzip compression for the next .Write's data,
|
|
// if called then the contents are being written in plain form.
|
|
func (w *GzipResponseWriter) Disable() {
|
|
w.disabled = true
|
|
}
|