func serveDeflate(w http.ResponseWriter, r *http.Request, f *zip.File, readerAt io.ReaderAt) {
	acceptEncoding := r.Header.Get("Accept-Encoding")
	acceptsDeflate := strings.Contains(acceptEncoding, "deflate")
	if !acceptsDeflate {
		serveIdentity(w, r, f)
		return
	}
	contentLength := int64(f.CompressedSize64)
	if contentLength == 0 {
		contentLength = int64(f.CompressedSize)
	}
	w.Header().Set("Content-Encoding", "deflate")
	w.Header().Set("Content-Length", fmt.Sprintf("%d", contentLength))
	if r.Method == "HEAD" {
		return
	}
	var written int64
	remaining := contentLength
	offset, err := f.DataOffset()
	if err != nil {
		msg, code := toHTTPError(err)
		http.Error(w, msg, code)
		return
	}
	buf := bufPool.Get()
	defer bufPool.Free(buf)
	for remaining > 0 {
		size := len(buf)
		if int64(size) > remaining {
			size = int(remaining)
		}
		b := buf[:size]
		_, err := readerAt.ReadAt(b, offset)
		if err != nil {
			if written == 0 {
				msg, code := toHTTPError(err)
				http.Error(w, msg, code)
			}
			return
		}
		if _, err := w.Write(b); err != nil {
			return
		}
		written += int64(size)
		remaining -= int64(size)
		offset += int64(size)
	}
}
serveDeflat serves a zip file in deflate content-encoding if the
user agent can accept it. Otherwise it calls serveIdentity.
package zipfs
import (
	"archive/zip"
	"fmt"
	"io"
	"mime"
	"net/http"
	"os"
	"path"
	"path/filepath"
	"strings"
	"time"
)
func FileServer(fs *FileSystem) http.Handler {
	h := &fileHandler{
		fs: fs,
	}
	return h
}
type fileHandler struct {
	fs *FileSystem
}
func (h *fileHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	upath := r.URL.Path
	if !strings.HasPrefix(upath, "/") {
		upath = "/" + upath
		r.URL.Path = upath
	}
	serveFile(w, r, h.fs, path.Clean(upath), true)
}
func serveFile(w http.ResponseWriter, r *http.Request, fs *FileSystem, name string, redirect bool) {
	const indexPage = "/index.html"
	if strings.HasSuffix(r.URL.Path, indexPage) {
		localRedirect(w, r, "./")
		return
	}
	d, err := fs.openFileInfo(name)
	if err != nil {
		msg, code := toHTTPError(err)
		http.Error(w, msg, code)
		return
	}
	if redirect {
		url := r.URL.Path
		if d.IsDir() {
			if url[len(url)-1] != '/' {
				localRedirect(w, r, path.Base(url)+"/")
				return
			}
		} else {
			if url[len(url)-1] == '/' {
				localRedirect(w, r, "../"+path.Base(url))
				return
			}
		}
	}
	if d.IsDir() {
		index := strings.TrimSuffix(name, "/") + indexPage
		dd, err := fs.openFileInfo(index)
		if err == nil {
			d = dd
		}
	}
	if d.IsDir() {
		http.Error(w, "Forbidden", http.StatusForbidden)
		return
	}
	serveContent(w, r, fs, d)
}
func serveContent(w http.ResponseWriter, r *http.Request, fs *FileSystem, fi *fileInfo) {
	if checkLastModified(w, r, fi.ModTime()) {
		return
	}
	w.Header().Set("Etag", calcEtag(fi.zipFile))
	rangeReq, done := checkETag(w, r, fi.ModTime())
	if done {
		return
	}
	if rangeReq != "" {
		f := fi.openReader(r.URL.Path)
		defer f.Close()
		f.createTempFile()
		http.ServeContent(w, r, fi.Name(), fi.ModTime(), f.file)
		return
	}
	setContentType(w, fi.Name())
	switch fi.zipFile.Method {
	case zip.Store:
		serveIdentity(w, r, fi.zipFile)
	case zip.Deflate:
		serveDeflate(w, r, fi.zipFile, fs.readerAt)
	default:
		http.Error(w, fmt.Sprintf("unsupported zip method: %d", fi.zipFile.Method), http.StatusInternalServerError)
	}
}
func serveIdentity(w http.ResponseWriter, r *http.Request, zf *zip.File) {
	reader, err := zf.Open()
	if err != nil {
		msg, code := toHTTPError(err)
		http.Error(w, msg, code)
		return
	}
	defer reader.Close()
	size := zf.FileInfo().Size()
	w.Header().Del("Content-Encoding")
	w.Header().Set("Content-Length", fmt.Sprintf("%d", size))
	if r.Method != "HEAD" {
		io.CopyN(w, reader, int64(size))
	}
}