Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CompressHandler: Ignore MIME types, re-use writers via sync.Pool #44

Closed
elithrar opened this issue Aug 6, 2015 · 6 comments
Closed

Comments

@elithrar
Copy link
Contributor

elithrar commented Aug 6, 2015

Note: raising this as an issue half as a reminder to address this, and to provide someone a chance to get to it before I can.

As per this great article on gzip performance: http://blog.klauspost.com/gzip-performance-for-go-webservers/

Quick example:

func (w *compressResponseWriter) Write(b []byte) (int, error) {
    // You'll need to *not* write the gzip content-encoding header based on the type.   
    h := w.ResponseWriter.Header()
    var ctype string
    if ctype = h.Get("Content-Type"); ctype == "" {
        ctype  = http.DetectContentType(b)
        h.Set("Content-Type", ctype)
    }

    // compressableTypes checks types against a []string of acceptable Content-Types
    if !compressableTypes(ctype) {
        // Write the uncompressed bytes to the response.
        w.ResponseWriter.Write(b)
        return
    }

    h.Del("Content-Length")
    return w.Writer.Write(b)
}

I'll update here before I begin work in earnest, but it won't be until after the weekend as I need to submit patches to the sessions stores first. If someone wants to pick this up before then (it's fairly straightforward patch) then just say so. Happy to guide you in writing tests as well.

@elithrar
Copy link
Contributor Author

elithrar commented Aug 9, 2015

In addition:

  • Tests need to explicitly check that a *gzip.Writer retrieved from the pool is correctly Reset(). This is a potential security issue waiting to happen otherwise.
  • Use a base64 encoded PNG to test the "don't gzip" case - http://www.gorillatoolkit.org/static/images/gorilla-icon-64.png is a good candidate (drop the base64 bytes into a var, decode into bytes during the test)
  • Update the docs on CompressHandler to indicate the selective gzipping.

@nwidger
Copy link
Contributor

nwidger commented Aug 24, 2015

+1

@elithrar
Copy link
Contributor Author

#48 has likely made this much harder now due to the limitations around defining a global pool:

  • If we create a global pool of gzip writers (we must if we want a pool) then we can't pass the "current" level to the pool per-instance of middleware:
var gzipPool = sync.Pool{
    // Can't pass the level when we call New()
    New: func() interface{} {
        return gzip.NewWriter(nil)
    },
}
  • We could set a package global level, but that creates implicit behaviour (all CompressHandler instances would need to use it) and also causes race conditions when you have more than one CompressHandlerLevel middleware in play. Effectively a non-starter here.
  • The level field on *gzip.Writer isn't exported and therefore you can't modify it after you type-assert the writer out of the pool.

Is there a solution here that I'm missing? I think this PR had more value as changing gzip levels should be done with caution in a HTTP context, but a pooled gzip writer nets everyone a performance gain, but unfortunately that's how things have shaken out.

@kisielk - would appreciate your feedback/input here.

@kisielk
Copy link
Contributor

kisielk commented Oct 25, 2015

How about a separate pool for every compression level? There's only 11 of them and the size overhead for a pool is not that large.

@elithrar elithrar self-assigned this Nov 18, 2015
@bernardolm
Copy link

👍

@stale
Copy link

stale bot commented Dec 9, 2018

This issue has been automatically marked as stale because it hasn't seen a recent update. It'll be automatically closed in a few days.

@stale stale bot added the stale label Dec 9, 2018
@stale stale bot closed this as completed Dec 17, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants