iris/webfs.go
Gerasimos (Makis) Maropoulos 8bbd9f8fc5 Happy new year! Update to 6.0.0 | HTTP/2 full support. https://github.com/kataras/iris/issues/565
full commit from development branch.

Examples, book, middleware, plugins are updated to the latest iris
version. Read HISTORY.md for more.

The 'old' v5 branch which relied on fasthttp exists for those who want
to use it navigate there: https://github.com/kataras/iris/tree/5.0.0
2017-01-02 21:20:17 +02:00

150 lines
3.9 KiB
Go

package iris
import (
"net/http"
"os"
"strings"
"sync"
)
// StaticHandlerBuilder is the web file system's Handler builder
// use that or the iris.StaticHandler/StaticWeb methods
type StaticHandlerBuilder interface {
Path(requestRoutePath string) StaticHandlerBuilder
Gzip(enable bool) StaticHandlerBuilder
Listing(listDirectoriesOnOff bool) StaticHandlerBuilder
StripPath(yesNo bool) StaticHandlerBuilder
Build() HandlerFunc
}
type webfs struct {
// user options, only directory is required.
directory http.Dir
requestPath string
stripPath bool
gzip bool
listDirectories bool
// these are init on the Build() call
filesystem http.FileSystem
once sync.Once
handler HandlerFunc
}
func toWebPath(systemPath string) string {
// winos slash to slash
webpath := strings.Replace(systemPath, "\\", slash, -1)
// double slashes to single
webpath = strings.Replace(webpath, slash+slash, slash, -1)
// remove all dots
webpath = strings.Replace(webpath, ".", "", -1)
return webpath
}
// NewStaticHandlerBuilder returns a new Handler which serves static files
// supports gzip, no listing and much more
// Note that, this static builder returns a Handler
// it doesn't cares about the rest of your iris configuration.
//
// Use the iris.StaticHandler/StaticWeb in order to serve static files on more automatic way
// this builder is used by people who have more complicated application
// structure and want a fluent api to work on.
func NewStaticHandlerBuilder(dir string) StaticHandlerBuilder {
return &webfs{
directory: http.Dir(dir),
// default route path is the same as the directory
requestPath: toWebPath(dir),
// enable strip path by-default
stripPath: true,
// gzip is disabled by default
gzip: false,
// list directories disabled by default
listDirectories: false,
}
}
// Path sets the request path.
// Defaults to same as system path
func (w *webfs) Path(requestRoutePath string) StaticHandlerBuilder {
w.requestPath = toWebPath(requestRoutePath)
return w
}
// Gzip if enable is true then gzip compression is enabled for this static directory
// Defaults to false
func (w *webfs) Gzip(enable bool) StaticHandlerBuilder {
w.gzip = enable
return w
}
// Listing turn on/off the 'show files and directories'.
// Defaults to false
func (w *webfs) Listing(listDirectoriesOnOff bool) StaticHandlerBuilder {
w.listDirectories = listDirectoriesOnOff
return w
}
func (w *webfs) StripPath(yesNo bool) StaticHandlerBuilder {
w.stripPath = yesNo
return w
}
type (
noListFile struct {
http.File
}
)
// Overrides the Readdir of the http.File in order to disable showing a list of the dirs/files
func (n noListFile) Readdir(count int) ([]os.FileInfo, error) {
return nil, nil
}
// Implements the http.Filesystem
// Do not call it.
func (w *webfs) Open(name string) (http.File, error) {
info, err := w.filesystem.Open(name)
if err != nil {
return nil, err
}
if !w.listDirectories {
return noListFile{info}, nil
}
return info, nil
}
// Build the handler (once) and returns it
func (w *webfs) Build() HandlerFunc {
// we have to ensure that Build is called ONLY one time,
// one instance per one static directory.
w.once.Do(func() {
w.filesystem = http.Dir(w.directory)
// set the filesystem to itself in order to be recognised of listing property (can be change at runtime too)
fileserver := http.FileServer(w)
fsHandler := fileserver
if w.stripPath {
prefix := w.requestPath
fsHandler = http.StripPrefix(prefix, fileserver)
}
w.handler = func(ctx *Context) {
writer := ctx.ResponseWriter.ResponseWriter
if w.gzip && ctx.clientAllowsGzip() {
ctx.ResponseWriter.Header().Add(varyHeader, acceptEncodingHeader)
ctx.SetHeader(contentEncodingHeader, "gzip")
gzipResWriter := acquireGzipResponseWriter(ctx.ResponseWriter.ResponseWriter)
writer = gzipResWriter
defer releaseGzipResponseWriter(gzipResWriter)
}
fsHandler.ServeHTTP(writer, ctx.Request)
}
})
return w.handler
}