1
0
mirror of https://github.com/kataras/iris.git synced 2026-01-08 20:41:57 +00:00

Update to version 8.5.8 | Read HISTORY.md

Former-commit-id: 82128ce7a2896a9a8bafd7a5268b0b42057fc21a
This commit is contained in:
kataras
2017-11-09 12:03:14 +02:00
parent 5a8b17f0e8
commit 2a0c6dade6
16 changed files with 480 additions and 29 deletions

View File

@@ -13,7 +13,7 @@ import (
const (
// Version is the string representation of the current local Iris Web Framework version.
Version = "8.5.7"
Version = "8.5.8"
)
// CheckForUpdates checks for any available updates

View File

@@ -21,6 +21,49 @@ import (
"github.com/kataras/iris/context"
)
func calculateAssetValidator(vdir string, assetFn func(name string) ([]byte, error), namesFn func() []string) AssetValidator {
if len(vdir) > 0 {
if vdir[0] == '.' {
vdir = vdir[1:]
}
if vdir[0] == '/' || vdir[0] == os.PathSeparator { // second check for /something, (or ./something if we had dot on 0 it will be removed
vdir = vdir[1:]
}
}
// collect the names we are care for,
// because not all Asset used here, we need the vdir's assets.
allNames := namesFn()
var names []string
for _, path := range allNames {
// i.e: path = public/css/main.css
// check if path is the path name we care for
if !strings.HasPrefix(path, vdir) {
continue
}
names = append(names, path)
}
return func(reqPath string) bool {
reqPath = strings.TrimPrefix(reqPath, "/"+vdir)
for _, path := range names {
// in order to map "/" as "/index.html"
if path == "/index.html" && reqPath == "/" {
reqPath = "/index.html"
}
if path == vdir+reqPath {
return true
}
}
return false
}
}
// StaticEmbeddedHandler returns a Handler which can serve
// embedded into executable files.
//
@@ -766,7 +809,7 @@ func serveFile(ctx context.Context, fs http.FileSystem, name string, redirect bo
// can't use Redirect() because that would make the path absolute,
// which would be a problem running under StripPrefix
if strings.HasSuffix(ctx.Request().URL.Path, indexPage) {
localRedirect(ctx, "./")
localRedirect(ctx.ResponseWriter(), ctx.Request(), "./")
return "", http.StatusMovedPermanently
}
@@ -787,12 +830,12 @@ func serveFile(ctx context.Context, fs http.FileSystem, name string, redirect bo
url := ctx.Request().URL.Path
if d.IsDir() {
if url[len(url)-1] != '/' {
localRedirect(ctx, path.Base(url)+"/")
localRedirect(ctx.ResponseWriter(), ctx.Request(), path.Base(url)+"/")
return "", http.StatusMovedPermanently
}
} else {
if url[len(url)-1] == '/' {
localRedirect(ctx, "../"+path.Base(url))
localRedirect(ctx.ResponseWriter(), ctx.Request(), "../"+path.Base(url))
return "", http.StatusMovedPermanently
}
}
@@ -802,7 +845,7 @@ func serveFile(ctx context.Context, fs http.FileSystem, name string, redirect bo
if d.IsDir() {
url := ctx.Request().URL.Path
if url[len(url)-1] != '/' {
localRedirect(ctx, path.Base(url)+"/")
localRedirect(ctx.ResponseWriter(), ctx.Request(), path.Base(url)+"/")
return "", http.StatusMovedPermanently
}
}
@@ -885,12 +928,14 @@ func toHTTPError(err error) (msg string, httpStatus int) {
// localRedirect gives a Moved Permanently response.
// It does not convert relative paths to absolute paths like Redirect does.
func localRedirect(ctx context.Context, newPath string) {
if q := ctx.Request().URL.RawQuery; q != "" {
func localRedirect(w http.ResponseWriter, r *http.Request, newPath string) {
if q := r.URL.RawQuery; q != "" {
newPath += "?" + q
}
ctx.Header("Location", newPath)
ctx.StatusCode(http.StatusMovedPermanently)
w.Header().Set("Location", newPath)
w.WriteHeader(http.StatusMovedPermanently)
// ctx.Header("Location", newPath)
// ctx.StatusCode(http.StatusMovedPermanently)
}
func containsDotDot(v string) bool {

View File

@@ -19,6 +19,15 @@ type SPABuilder struct {
AssetValidators []AssetValidator
}
// AddIndexName will add an index name.
// If path == $filename then it redirects to "/".
//
// It can be called after the `BuildWrapper ` as well but BEFORE the server start.
func (s *SPABuilder) AddIndexName(filename string) *SPABuilder {
s.IndexNames = append(s.IndexNames, filename)
return s
}
// NewSPABuilder returns a new Single Page Application builder
// It does what StaticWeb expected to do when serving files and routes at the same time
// from the root "/" path.
@@ -32,11 +41,13 @@ func NewSPABuilder(assetHandler context.Handler) *SPABuilder {
}
return &SPABuilder{
IndexNames: []string{"index.html"},
IndexNames: nil,
// IndexNames is empty by-default,
// if the user wants to redirect to "/" from "/index.html" she/he can chage that to []string{"index.html"} manually.
AssetHandler: assetHandler,
AssetValidators: []AssetValidator{
func(path string) bool {
return strings.Contains(path, ".")
return true // returns true by-default
},
},
}
@@ -61,23 +72,23 @@ func (s *SPABuilder) isAsset(reqPath string) bool {
func (s *SPABuilder) BuildWrapper(cPool *context.Pool) WrapperFunc {
fileServer := s.AssetHandler
indexNames := s.IndexNames
wrapper := func(w http.ResponseWriter, r *http.Request, router http.HandlerFunc) {
path := r.URL.Path
// make a validator call, by-default all paths are valid and this codeblock doesn't mean anything
// but for cases that users wants to bypass an asset she/he can do that by modifiying the `APIBuilder#AssetValidators` field.
//
// It's here for backwards compatibility as well, see #803.
if !s.isAsset(path) {
// it's not asset, execute the registered route's handlers
router(w, r)
return
}
ctx := cPool.Acquire(w, r)
for _, index := range indexNames {
for _, index := range s.IndexNames {
if strings.HasSuffix(path, index) {
localRedirect(ctx, "./")
cPool.Release(ctx)
localRedirect(w, r, "./")
// "/" should be manually registered.
// We don't setup an index handler here,
// let full control to the user
@@ -86,9 +97,28 @@ func (s *SPABuilder) BuildWrapper(cPool *context.Pool) WrapperFunc {
}
}
// execute file server for path
ctx := cPool.Acquire(w, r)
// convert to a recorder in order to not write the status and body directly but wait for a flush (EndRequest).
rec := ctx.Recorder() // rec and context.ResponseWriter() is the same thing now.
// execute the asset handler.
fileServer(ctx)
// check if body was written, if not then;
// 1. reset the whole response writer, its status code, headers and body
// 2. release only the object,
// so it doesn't fires the status code's handler to the client
// (we are eliminating the multiple response header calls this way)
// 3. execute the router itself, if route found then it will serve that, otherwise 404 or 405.
//
// we could also use the ctx.ResponseWriter().Written() > 0.
empty := len(rec.Body()) == 0
if empty {
rec.Reset()
cPool.ReleaseLight(ctx)
router(w, r)
return
}
// if body was written from the file server then release the context as usual,
// it will send everything to the client and reset the context.
cPool.Release(ctx)
}