// errorPage serves a static error page to w according to the status // code. If there is an error serving the error page, a plaintext error // message is written instead, and the extra error is logged. func (h ErrorHandler) errorPage(w http.ResponseWriter, r *http.Request, code int) { // See if an error page for this status code was specified if pagePath, ok := h.ErrorPages[code]; ok { // Try to open it errorPage, err := os.Open(pagePath) if err != nil { // An additional error handling an error... <insert grumpy cat here> h.Log.Printf("%s [NOTICE %d %s] could not load error page: %v", time.Now().Format(timeFormat), code, r.URL.String(), err) httpserver.DefaultErrorFunc(w, r, code) return } defer errorPage.Close() // Copy the page body into the response w.Header().Set("Content-Type", "text/html; charset=utf-8") w.WriteHeader(code) _, err = io.Copy(w, errorPage) if err != nil { // Epic fail... sigh. h.Log.Printf("%s [NOTICE %d %s] could not respond with %s: %v", time.Now().Format(timeFormat), code, r.URL.String(), pagePath, err) httpserver.DefaultErrorFunc(w, r, code) } return } // Default error response httpserver.DefaultErrorFunc(w, r, code) }
// ServeHTTP serves a gzipped response if the client supports it. func (g Gzip) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) { if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") { return g.Next.ServeHTTP(w, r) } outer: for _, c := range g.Configs { // Check request filters to determine if gzipping is permitted for this request for _, filter := range c.RequestFilters { if !filter.ShouldCompress(r) { continue outer } } // Delete this header so gzipping is not repeated later in the chain r.Header.Del("Accept-Encoding") // gzipWriter modifies underlying writer at init, // use a discard writer instead to leave ResponseWriter in // original form. gzipWriter, err := newWriter(c, ioutil.Discard) if err != nil { // should not happen return http.StatusInternalServerError, err } defer gzipWriter.Close() gz := &gzipResponseWriter{Writer: gzipWriter, ResponseWriter: w} var rw http.ResponseWriter // if no response filter is used if len(c.ResponseFilters) == 0 { // replace discard writer with ResponseWriter gzipWriter.Reset(w) rw = gz } else { // wrap gzip writer with ResponseFilterWriter rw = NewResponseFilterWriter(c.ResponseFilters, gz) } // Any response in forward middleware will now be compressed status, err := g.Next.ServeHTTP(rw, r) // If there was an error that remained unhandled, we need // to send something back before gzipWriter gets closed at // the return of this method! if status >= 400 { httpserver.DefaultErrorFunc(w, r, status) return 0, err } return status, err } // no matching filter return g.Next.ServeHTTP(w, r) }