mirror of
https://github.com/kataras/iris.git
synced 2025-12-31 00:37:05 +00:00
20 days of unstoppable work. Waiting fo go 1.8, I didn't finish yet, some touches remains.
Former-commit-id: ed84f99c89f43fe5e980a8e6d0ee22c186f0e1b9
This commit is contained in:
192
fs.go
Normal file
192
fs.go
Normal file
@@ -0,0 +1,192 @@
|
||||
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
|
||||
Except(r ...RouteInfo) StaticHandlerBuilder
|
||||
Build() HandlerFunc
|
||||
}
|
||||
|
||||
type fsHandler 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
|
||||
exceptions []RouteInfo
|
||||
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 &fsHandler{
|
||||
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 *fsHandler) 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 *fsHandler) Gzip(enable bool) StaticHandlerBuilder {
|
||||
w.gzip = enable
|
||||
return w
|
||||
}
|
||||
|
||||
// Listing turn on/off the 'show files and directories'.
|
||||
// Defaults to false
|
||||
func (w *fsHandler) Listing(listDirectoriesOnOff bool) StaticHandlerBuilder {
|
||||
w.listDirectories = listDirectoriesOnOff
|
||||
return w
|
||||
}
|
||||
|
||||
func (w *fsHandler) StripPath(yesNo bool) StaticHandlerBuilder {
|
||||
w.stripPath = yesNo
|
||||
return w
|
||||
}
|
||||
|
||||
// Except add a route exception,
|
||||
// gives priority to that Route over the static handler.
|
||||
func (w *fsHandler) Except(r ...RouteInfo) StaticHandlerBuilder {
|
||||
w.exceptions = append(w.exceptions, r...)
|
||||
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 *fsHandler) 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 *fsHandler) 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 = 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)
|
||||
}
|
||||
|
||||
h := func(ctx *Context) {
|
||||
writer := ctx.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)
|
||||
}
|
||||
|
||||
if len(w.exceptions) > 0 {
|
||||
middleware := make(Middleware, len(w.exceptions)+1)
|
||||
for i := range w.exceptions {
|
||||
middleware[i] = Prioritize(w.exceptions[i])
|
||||
}
|
||||
middleware[len(w.exceptions)] = HandlerFunc(h)
|
||||
|
||||
w.handler = func(ctx *Context) {
|
||||
ctx.Middleware = append(middleware, ctx.Middleware...)
|
||||
ctx.Do()
|
||||
}
|
||||
} else {
|
||||
w.handler = h
|
||||
}
|
||||
})
|
||||
|
||||
return w.handler
|
||||
}
|
||||
|
||||
// StripPrefix returns a handler that serves HTTP requests
|
||||
// by removing the given prefix from the request URL's Path
|
||||
// and invoking the handler h. StripPrefix handles a
|
||||
// request for a path that doesn't begin with prefix by
|
||||
// replying with an HTTP 404 not found error.
|
||||
func StripPrefix(prefix string, h HandlerFunc) HandlerFunc {
|
||||
if prefix == "" {
|
||||
return h
|
||||
}
|
||||
return func(ctx *Context) {
|
||||
if p := strings.TrimPrefix(ctx.Request.URL.Path, prefix); len(p) < len(ctx.Request.URL.Path) {
|
||||
ctx.Request.URL.Path = p
|
||||
h(ctx)
|
||||
} else {
|
||||
ctx.NotFound()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user