Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 4 additions & 13 deletions compressor.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,12 @@ type CompressorProvider interface {
// Get returns a writer that writes compressed output to the supplied parent io.Writer.
// Callers of Get() must ensure to always call Close() when the compressor is not needed
// anymore. Callers of Close() must also ensure to not use the io.WriteCloser once Close()
// is called.
// Implementations of CompressorProvider are allowed to recycle the compressor (e.g. put the
// WriteCloser in a pool to be reused by a later call to Get) when Close() is called.
// The returned io.WriteCloser can optionally implement the Flusher interface if it is
// able to flush data buffered internally.
// is called. Implementations of CompressorProvider are allowed to recycle the compressor
// (e.g. put the WriteCloser in a pool to be reused by a later call to Get) when
// Close() is called.
Get(parent io.Writer) (compressor io.WriteCloser)
}

// Flusher is an optional interface that can be implemented by the compressors returned by
// CompressorProvider.Get().
type Flusher interface {
// Flush flushes the data buffered internally by the Writer.
// Implementations of Flush do not need to internally flush the parent Writer.
Flush() error
}

// Compressor returns an Option that sets the CompressorProvider for a specific Content-Encoding.
// If multiple CompressorProviders are set for the same Content-Encoding, the last one is used.
// If compressor is nil, it disables the specified Content-Encoding.
Expand All @@ -41,3 +31,4 @@ func Compressor(contentEncoding string, priority int, compressor CompressorProvi
return nil
}
}

41 changes: 5 additions & 36 deletions response_writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,21 +35,6 @@ var (
_ io.StringWriter = &compressWriter{}
)

type compressWriterWithCloseNotify struct {
*compressWriter
}

func (w compressWriterWithCloseNotify) CloseNotify() <-chan bool {
return w.ResponseWriter.(http.CloseNotifier).CloseNotify()
}

var (
_ io.WriteCloser = compressWriterWithCloseNotify{}
_ http.Flusher = compressWriterWithCloseNotify{}
_ http.Hijacker = compressWriterWithCloseNotify{}
_ io.StringWriter = compressWriterWithCloseNotify{}
)

const maxBuf = 1 << 16 // maximum size of recycled buffer

// Write compresses and appends the given byte slice to the underlying ResponseWriter.
Expand Down Expand Up @@ -252,31 +237,14 @@ func (w *compressWriter) Close() error {

// Flush flushes the underlying compressor Writer and then the underlying
// http.ResponseWriter if it is an http.Flusher. This makes compressWriter
// an http.Flusher.
// Flush is a no-op until enough data has been written to decide whether the
// response should be compressed or not (e.g. less than MinSize bytes have
// been written).
// an http.Flusher. Flush is a no-op until the compress writer is initialized.
func (w *compressWriter) Flush() {
if w.w == nil {
// Flush is thus a no-op until we're certain whether a plain
// or compressed response will be served.
return
}

// Flush the compressor, if supported.
// note: http.ResponseWriter does not implement Flusher (http.Flusher does not return an error),
// so we need to later call ResponseWriter.Flush anyway:
// - in case we are bypassing compression, w.w is the parent ResponseWriter, and therefore we skip
// this as the parent ResponseWriter does not implement Flusher.
// - in case we are NOT bypassing compression, w.w is the compressor, and therefore we flush the
// compressor and then we flush the parent ResponseWriter.
if fw, ok := w.w.(Flusher); ok {
_ = fw.Flush()
}

// Flush the ResponseWriter (the previous Flusher is not expected to flush the parent writer).
if fw, ok := w.ResponseWriter.(http.Flusher); ok {
fw.Flush()
// Flush the compressor and then the underlying http.ResponseWriter.
if f, ok := w.w.(http.Flusher); ok {
f.Flush()
}
}

Expand Down Expand Up @@ -316,3 +284,4 @@ func (w *compressWriter) recycleBuffer() {
}
w.pool.Put(buf)
}