1
0
mirror of https://github.com/kataras/iris.git synced 2026-05-12 17:13:50 +00:00

Add notes for the new lead maintainer of the open-source iris project and align with @get-ion/ion by @hiveminded

Former-commit-id: da4f38eb9034daa49446df3ee529423b98f9b331
This commit is contained in:
kataras
2017-07-10 18:32:42 +03:00
parent 2d4c2779a7
commit 9f85b74fc9
344 changed files with 4842 additions and 5174 deletions

View File

@@ -1,7 +1,3 @@
// Copyright 2017 Gerasimos Maropoulos, ΓΜ. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package router
import (
@@ -62,13 +58,6 @@ func (r *repository) getAll() []*Route {
return r.routes
}
// RoutesProvider should be implemented by
// iteral which contains the registered routes.
type RoutesProvider interface { // api builder
GetRoutes() []*Route
GetRoute(routeName string) *Route
}
// APIBuilder the visible API for constructing the router
// and child routers.
type APIBuilder struct {
@@ -81,6 +70,11 @@ type APIBuilder struct {
// the api builder global route path reverser object
// used by the view engine but it can be used anywhere.
reverser *RoutePathReverser
// the api builder global errors, can be filled by the Subdomain, WildcardSubdomain, Handle...
// the list of possible errors that can be
// collected on the build state to log
// to the end-user.
reporter *errors.Reporter
// the per-party middleware
middleware context.Handlers
@@ -101,6 +95,7 @@ func NewAPIBuilder() *APIBuilder {
rb := &APIBuilder{
macros: defaultMacros(),
errorCodeHandlers: defaultErrorCodeHandlers(),
reporter: errors.NewReporter(),
relativePath: "/",
routes: new(repository),
}
@@ -108,17 +103,22 @@ func NewAPIBuilder() *APIBuilder {
return rb
}
// GetReport returns an error may caused by party's methods.
func (rb *APIBuilder) GetReport() error {
return rb.reporter.Return()
}
// Handle registers a route to the server's rb.
// if empty method is passed then handler(s) are being registered to all methods, same as .Any.
//
// Returns a *Route and an error which will be filled if route wasn't registered successfully.
func (rb *APIBuilder) Handle(method string, registeredPath string, handlers ...context.Handler) (*Route, error) {
// Returns a *Route, app will throw any errors later on.
func (rb *APIBuilder) Handle(method string, registeredPath string, handlers ...context.Handler) *Route {
// if registeredPath[0] != '/' {
// return nil, errors.New("path should start with slash and should not be empty")
// }
if method == "" || method == "ALL" || method == "ANY" { // then use like it was .Any
return nil, rb.Any(registeredPath, handlers...)
return rb.Any(registeredPath, handlers...)[0]
}
// no clean path yet because of subdomain indicator/separator which contains a dot.
@@ -136,31 +136,33 @@ func (rb *APIBuilder) Handle(method string, registeredPath string, handlers ...c
routeHandlers := joinHandlers(rb.middleware, handlers)
// here we separate the subdomain and relative path
subdomain, path := exctractSubdomain(fullpath)
subdomain, path := splitSubdomainAndPath(fullpath)
if len(rb.doneHandlers) > 0 {
routeHandlers = append(routeHandlers, rb.doneHandlers...) // register the done middleware, if any
}
r, err := NewRoute(method, subdomain, path, routeHandlers, rb.macros)
if err != nil {
return nil, err
if err != nil { // template path parser errors:
rb.reporter.Add("%v -> %s:%s:%s", err, method, subdomain, path)
return nil
}
// global
rb.routes.register(r)
// per -party
// per -party, used for done handlers
rb.apiRoutes = append(rb.apiRoutes, r)
// should we remove the rb.apiRoutes on the .Party (new children party) ?, No, because the user maybe use this party later
// should we add to the 'inheritance tree' the rb.apiRoutes, No, these are for this specific party only, because the user propably, will have unexpected behavior when using Use/Use, Done/DoneFunc
return r, nil
return r
}
// Party is just a group joiner of routes which have the same prefix and share same middleware(s) also.
// Party could also be named as 'Join' or 'Node' or 'Group' , Party chosen because it is fun.
func (rb *APIBuilder) Party(relativePath string, handlers ...context.Handler) Party {
parentPath := rb.relativePath
dot := string(SubdomainIndicator[0])
if len(parentPath) > 0 && parentPath[0] == '/' && strings.HasSuffix(relativePath, dot) { // if ends with . , example: admin., it's subdomain->
dot := string(SubdomainPrefix[0])
if len(parentPath) > 0 && parentPath[0] == '/' && strings.HasSuffix(relativePath, dot) {
// if ends with . , i.e admin., it's subdomain->
parentPath = parentPath[1:] // remove first slash
}
@@ -169,6 +171,16 @@ func (rb *APIBuilder) Party(relativePath string, handlers ...context.Handler) Pa
parentPath = parentPath[1:] // remove first slash if parent ended with / and new one started with /.
}
// if it's subdomain then it has priority, i.e:
// rb.relativePath == "admin."
// relativePath == "panel."
// then it should be panel.admin.
// instead of admin.panel.
if hasSubdomain(parentPath) && hasSubdomain(relativePath) {
relativePath = relativePath + parentPath
parentPath = ""
}
fullpath := parentPath + relativePath
// append the parent's +child's handlers
middleware := joinHandlers(rb.middleware, handlers)
@@ -179,16 +191,46 @@ func (rb *APIBuilder) Party(relativePath string, handlers ...context.Handler) Pa
routes: rb.routes,
errorCodeHandlers: rb.errorCodeHandlers,
doneHandlers: rb.doneHandlers,
reporter: rb.reporter,
// per-party/children
middleware: middleware,
relativePath: fullpath,
}
}
// Subdomain returns a new party which is responsible to register routes to
// this specific "subdomain".
//
// If called from a child party then the subdomain will be prepended to the path instead of appended.
// So if app.Subdomain("admin.").Subdomain("panel.") then the result is: "panel.admin.".
func (rb *APIBuilder) Subdomain(subdomain string, middleware ...context.Handler) Party {
if rb.relativePath == SubdomainWildcardIndicator {
// cannot concat wildcard subdomain with something else
rb.reporter.Add("cannot concat parent wildcard subdomain with anything else -> %s , %s",
rb.relativePath, subdomain)
return rb
}
return rb.Party(subdomain, middleware...)
}
// WildcardSubdomain returns a new party which is responsible to register routes to
// a dynamic, wildcard(ed) subdomain. A dynamic subdomain is a subdomain which
// can reply to any subdomain requests. Server will accept any subdomain
// (if not static subdomain found) and it will search and execute the handlers of this party.
func (rb *APIBuilder) WildcardSubdomain(middleware ...context.Handler) Party {
if hasSubdomain(rb.relativePath) {
// cannot concat static subdomain with a dynamic one, wildcard should be at the root level
rb.reporter.Add("cannot concat static subdomain with a dynamic one. Dynamic subdomains should be at the root level -> %s",
rb.relativePath)
return rb
}
return rb.Subdomain(SubdomainWildcardIndicator, middleware...)
}
// Macros returns the macro map which is responsible
// to register custom macro functions for all routes.
//
// Learn more at: https://github.com/kataras/iris/tree/master/_examples/beginner/routing/dynamic-path
// Learn more at: https://github.com/kataras/iris/tree/master/_examples/routing/dynamic-path
func (rb *APIBuilder) Macros() *macro.Map {
return rb.macros
}
@@ -209,8 +251,8 @@ func (rb *APIBuilder) GetRoute(routeName string) *Route {
// Use appends Handler(s) to the current Party's routes and child routes.
// If the current Party is the root, then it registers the middleware to all child Parties' routes too.
func (rb *APIBuilder) Use(handlers ...context.Handler) {
rb.middleware = append(rb.middleware, handlers...)
func (rb *APIBuilder) Use(middleware ...context.Handler) {
rb.middleware = append(rb.middleware, middleware...)
}
// Done appends to the very end, Handler(s) to the current Party's routes and child routes
@@ -245,83 +287,84 @@ func (rb *APIBuilder) UseGlobal(handlers ...context.Handler) {
// Offline(handleResultRouteInfo)
//
// Returns a *Route and an error which will be filled if route wasn't registered successfully.
func (rb *APIBuilder) None(path string, handlers ...context.Handler) (*Route, error) {
func (rb *APIBuilder) None(path string, handlers ...context.Handler) *Route {
return rb.Handle(MethodNone, path, handlers...)
}
// Get registers a route for the Get http method.
//
// Returns a *Route and an error which will be filled if route wasn't registered successfully.
func (rb *APIBuilder) Get(path string, handlers ...context.Handler) (*Route, error) {
func (rb *APIBuilder) Get(path string, handlers ...context.Handler) *Route {
return rb.Handle(http.MethodGet, path, handlers...)
}
// Post registers a route for the Post http method.
//
// Returns a *Route and an error which will be filled if route wasn't registered successfully.
func (rb *APIBuilder) Post(path string, handlers ...context.Handler) (*Route, error) {
func (rb *APIBuilder) Post(path string, handlers ...context.Handler) *Route {
return rb.Handle(http.MethodPost, path, handlers...)
}
// Put registers a route for the Put http method.
//
// Returns a *Route and an error which will be filled if route wasn't registered successfully.
func (rb *APIBuilder) Put(path string, handlers ...context.Handler) (*Route, error) {
func (rb *APIBuilder) Put(path string, handlers ...context.Handler) *Route {
return rb.Handle(http.MethodPut, path, handlers...)
}
// Delete registers a route for the Delete http method.
//
// Returns a *Route and an error which will be filled if route wasn't registered successfully.
func (rb *APIBuilder) Delete(path string, handlers ...context.Handler) (*Route, error) {
func (rb *APIBuilder) Delete(path string, handlers ...context.Handler) *Route {
return rb.Handle(http.MethodDelete, path, handlers...)
}
// Connect registers a route for the Connect http method.
//
// Returns a *Route and an error which will be filled if route wasn't registered successfully.
func (rb *APIBuilder) Connect(path string, handlers ...context.Handler) (*Route, error) {
func (rb *APIBuilder) Connect(path string, handlers ...context.Handler) *Route {
return rb.Handle(http.MethodConnect, path, handlers...)
}
// Head registers a route for the Head http method.
//
// Returns a *Route and an error which will be filled if route wasn't registered successfully.
func (rb *APIBuilder) Head(path string, handlers ...context.Handler) (*Route, error) {
func (rb *APIBuilder) Head(path string, handlers ...context.Handler) *Route {
return rb.Handle(http.MethodHead, path, handlers...)
}
// Options registers a route for the Options http method.
//
// Returns a *Route and an error which will be filled if route wasn't registered successfully.
func (rb *APIBuilder) Options(path string, handlers ...context.Handler) (*Route, error) {
func (rb *APIBuilder) Options(path string, handlers ...context.Handler) *Route {
return rb.Handle(http.MethodOptions, path, handlers...)
}
// Patch registers a route for the Patch http method.
//
// Returns a *Route and an error which will be filled if route wasn't registered successfully.
func (rb *APIBuilder) Patch(path string, handlers ...context.Handler) (*Route, error) {
func (rb *APIBuilder) Patch(path string, handlers ...context.Handler) *Route {
return rb.Handle(http.MethodPatch, path, handlers...)
}
// Trace registers a route for the Trace http method.
//
// Returns a *Route and an error which will be filled if route wasn't registered successfully.
func (rb *APIBuilder) Trace(path string, handlers ...context.Handler) (*Route, error) {
func (rb *APIBuilder) Trace(path string, handlers ...context.Handler) *Route {
return rb.Handle(http.MethodTrace, path, handlers...)
}
// Any registers a route for ALL of the http methods
// (Get,Post,Put,Head,Patch,Options,Connect,Delete).
func (rb *APIBuilder) Any(registeredPath string, handlers ...context.Handler) error {
for _, k := range AllMethods {
if _, err := rb.Handle(k, registeredPath, handlers...); err != nil {
return err
}
func (rb *APIBuilder) Any(registeredPath string, handlers ...context.Handler) []*Route {
routes := make([]*Route, len(AllMethods), len(AllMethods))
for i, k := range AllMethods {
r := rb.Handle(k, registeredPath, handlers...)
routes[i] = r
}
return nil
return routes
}
// StaticCacheDuration expiration duration for INACTIVE file handlers, it's the only one global configuration
@@ -341,10 +384,8 @@ const (
varyHeaderKey = "Vary"
)
func (rb *APIBuilder) registerResourceRoute(reqPath string, h context.Handler) (*Route, error) {
if _, err := rb.Head(reqPath, h); err != nil {
return nil, err
}
func (rb *APIBuilder) registerResourceRoute(reqPath string, h context.Handler) *Route {
rb.Head(reqPath, h)
return rb.Get(reqPath, h)
}
@@ -365,7 +406,7 @@ func (rb *APIBuilder) registerResourceRoute(reqPath string, h context.Handler) (
// mySubdomainFsServer.Get("/static", h)
// ...
//
func (rb *APIBuilder) StaticHandler(systemPath string, showList bool, enableGzip bool, exceptRoutes ...*Route) context.Handler {
func (rb *APIBuilder) StaticHandler(systemPath string, showList bool, enableGzip bool) context.Handler {
// Note: this doesn't need to be here but we'll keep it for consistently
return StaticHandler(systemPath, showList, enableGzip)
}
@@ -379,7 +420,7 @@ func (rb *APIBuilder) StaticHandler(systemPath string, showList bool, enableGzip
// it uses gzip compression (compression on each request, no file cache).
//
// Returns the GET *Route.
func (rb *APIBuilder) StaticServe(systemPath string, requestPath ...string) (*Route, error) {
func (rb *APIBuilder) StaticServe(systemPath string, requestPath ...string) *Route {
var reqPath string
if len(requestPath) == 0 {
@@ -411,12 +452,13 @@ func (rb *APIBuilder) StaticServe(systemPath string, requestPath ...string) (*Ro
// that are ready to serve raw static bytes, memory cached.
//
// Returns the GET *Route.
func (rb *APIBuilder) StaticContent(reqPath string, cType string, content []byte) (*Route, error) {
func (rb *APIBuilder) StaticContent(reqPath string, cType string, content []byte) *Route {
modtime := time.Now()
h := func(ctx context.Context) {
if err := ctx.WriteWithExpiration(content, cType, modtime); err != nil {
ctx.NotFound()
// ctx.Application().Log("error while serving []byte via StaticContent: %s", err.Error())
ctx.ContentType(cType)
if _, err := ctx.WriteWithExpiration(content, modtime); err != nil {
ctx.StatusCode(http.StatusInternalServerError)
// ctx.Application().Logger().Infof("error while serving []byte via StaticContent: %s", err.Error())
}
}
@@ -444,7 +486,7 @@ func (rb *APIBuilder) StaticEmbeddedHandler(vdir string, assetFn func(name strin
// Returns the GET *Route.
//
// Examples: https://github.com/kataras/iris/tree/master/_examples/file-server
func (rb *APIBuilder) StaticEmbedded(requestPath string, vdir string, assetFn func(name string) ([]byte, error), namesFn func() []string) (*Route, error) {
func (rb *APIBuilder) StaticEmbedded(requestPath string, vdir string, assetFn func(name string) ([]byte, error), namesFn func() []string) *Route {
fullpath := joinPath(rb.relativePath, requestPath)
requestPath = joinPath(fullpath, WildcardParam("file"))
@@ -466,12 +508,13 @@ var errDirectoryFileNotFound = errors.New("Directory or file %s couldn't found.
// Note that you have to call it on every favicon you have to serve automatically (desktop, mobile and so on).
//
// Returns the GET *Route.
func (rb *APIBuilder) Favicon(favPath string, requestPath ...string) (*Route, error) {
func (rb *APIBuilder) Favicon(favPath string, requestPath ...string) *Route {
favPath = Abs(favPath)
f, err := os.Open(favPath)
if err != nil {
return nil, errDirectoryFileNotFound.Format(favPath, err.Error())
rb.reporter.AddErr(errDirectoryFileNotFound.Format(favPath, err.Error()))
return nil
}
// ignore error f.Close()
@@ -496,8 +539,9 @@ func (rb *APIBuilder) Favicon(favPath string, requestPath ...string) (*Route, er
// So we could panic but we don't,
// we just interrupt with a message
// to the (user-defined) logger.
return nil, errDirectoryFileNotFound.
Format(favPath, "favicon: couldn't read the data bytes for file: "+err.Error())
rb.reporter.AddErr(errDirectoryFileNotFound.
Format(favPath, "favicon: couldn't read the data bytes for file: "+err.Error()))
return nil
}
modtime := ""
h := func(ctx context.Context) {
@@ -516,7 +560,7 @@ func (rb *APIBuilder) Favicon(favPath string, requestPath ...string) (*Route, er
ctx.ResponseWriter().Header().Set(lastModifiedHeaderKey, modtime)
ctx.StatusCode(http.StatusOK)
if _, err := ctx.Write(cacheFav); err != nil {
// ctx.Application().Log("error while trying to serve the favicon: %s", err.Error())
// ctx.Application().Logger().Infof("error while trying to serve the favicon: %s", err.Error())
ctx.StatusCode(http.StatusInternalServerError)
}
}
@@ -534,9 +578,8 @@ func (rb *APIBuilder) Favicon(favPath string, requestPath ...string) (*Route, er
//
// first parameter: the route path
// second parameter: the system directory
// third OPTIONAL parameter: the exception routes
// (= give priority to these routes instead of the static handler)
// for more options look rb.StaticHandler.
//
// for more options look router.StaticHandler.
//
// rb.StaticWeb("/static", "./static")
//
@@ -547,13 +590,13 @@ func (rb *APIBuilder) Favicon(favPath string, requestPath ...string) (*Route, er
// StaticWeb calls the StaticHandler(systemPath, listingDirectories: false, gzip: false ).
//
// Returns the GET *Route.
func (rb *APIBuilder) StaticWeb(requestPath string, systemPath string, exceptRoutes ...*Route) (*Route, error) {
func (rb *APIBuilder) StaticWeb(requestPath string, systemPath string) *Route {
paramName := "file"
fullpath := joinPath(rb.relativePath, requestPath)
h := StripPrefix(fullpath, rb.StaticHandler(systemPath, false, false, exceptRoutes...))
h := StripPrefix(fullpath, rb.StaticHandler(systemPath, false, false))
handler := func(ctx context.Context) {
h(ctx)

View File

@@ -1,10 +1,7 @@
// Copyright 2017 Gerasimos Maropoulos, ΓΜ & Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package router
import (
"errors"
"fmt"
"io"
"mime/multipart"
@@ -21,7 +18,6 @@ import (
"time"
"github.com/kataras/iris/context"
"github.com/kataras/iris/core/errors"
)
// StaticEmbeddedHandler returns a Handler which can serve
@@ -86,8 +82,8 @@ func StaticEmbeddedHandler(vdir string, assetFn func(name string) ([]byte, error
if err != nil {
continue
}
if err := ctx.WriteWithExpiration(buf, cType, modtime); err != nil {
ctx.ContentType(cType)
if _, err := ctx.WriteWithExpiration(buf, modtime); err != nil {
ctx.StatusCode(http.StatusInternalServerError)
ctx.StopExecution()
}
@@ -102,36 +98,6 @@ func StaticEmbeddedHandler(vdir string, assetFn func(name string) ([]byte, error
return h
}
// Prioritize is a middleware which executes a route against this path
// when the request's Path has a prefix of the route's STATIC PART
// is not executing ExecRoute to determinate if it's valid, for performance reasons
// if this function is not enough for you and you want to test more than one parameterized path
// then use the: if c := ExecRoute(r); c == nil { /* move to the next, the route is not valid */ }
//
// You can find the Route by iris.Default.Routes().Lookup("theRouteName")
// you can set a route name as: myRoute := iris.Default.Get("/mypath", handler)("theRouteName")
// that will set a name to the route and returns its iris.Route instance for further usage.
//
// if the route found then it executes that and don't continue to the next handler
// if not found then continue to the next handler
func Prioritize(r *Route) context.Handler {
if r != nil {
return func(ctx context.Context) {
reqPath := ctx.Path()
staticPath := ResolveStaticPath(reqPath)
if strings.HasPrefix(reqPath, staticPath) {
ctx.Exec(r.Method, reqPath) // execute the route based on this request path
// we are done here.
return
}
// execute the next handler if no prefix
// here look, the only error we catch is the 404.
ctx.Next()
}
}
return func(ctx context.Context) { ctx.Next() }
}
// StaticHandler returns a new Handler which is ready
// to serve all kind of static files.
//
@@ -148,20 +114,18 @@ func Prioritize(r *Route) context.Handler {
// app.Get("/static", h)
// ...
//
func StaticHandler(systemPath string, showList bool, enableGzip bool, exceptRoutes ...*Route) context.Handler {
func StaticHandler(systemPath string, showList bool, enableGzip bool) context.Handler {
return NewStaticHandlerBuilder(systemPath).
Listing(showList).
Gzip(enableGzip).
Except(exceptRoutes...).
Build()
}
// StaticHandlerBuilder is the web file system's Handler builder
// use that or the iris.StaticHandler/StaticWeb methods
// use that or the iris.StaticHandler/StaticWeb methods.
type StaticHandlerBuilder interface {
Gzip(enable bool) StaticHandlerBuilder
Listing(listDirectoriesOnOff bool) StaticHandlerBuilder
Except(r ...*Route) StaticHandlerBuilder
Build() context.Handler
}
@@ -179,7 +143,6 @@ type fsHandler struct {
// these are init on the Build() call
filesystem http.FileSystem
once sync.Once
exceptions []*Route
handler context.Handler
}
@@ -235,13 +198,6 @@ func (w *fsHandler) Listing(listDirectoriesOnOff bool) StaticHandlerBuilder {
return w
}
// Except add a route exception,
// gives priority to that Route over the static handler.
func (w *fsHandler) Except(r ...*Route) StaticHandlerBuilder {
w.exceptions = append(w.exceptions, r...)
return w
}
type (
noListFile struct {
http.File
@@ -308,7 +264,7 @@ func (w *fsHandler) Build() context.Handler {
// headers[contentEncodingHeader] = nil
// headers[contentLength] = nil
}
// ctx.Application().Log(errMsg)
// ctx.Application().Logger().Infof(errMsg)
ctx.StatusCode(prevStatusCode)
return
}
@@ -317,21 +273,6 @@ func (w *fsHandler) Build() context.Handler {
ctx.Next()
}
if len(w.exceptions) > 0 {
middleware := make(context.Handlers, len(w.exceptions)+1)
for i := range w.exceptions {
middleware[i] = Prioritize(w.exceptions[i])
}
middleware[len(w.exceptions)] = fileserver
w.handler = func(ctx context.Context) {
ctxHandlers := ctx.Handlers()
ctx.SetHandlers(append(middleware, ctxHandlers...))
ctx.Handlers()[0](ctx)
}
return
}
w.handler = fileserver
})
@@ -357,7 +298,7 @@ func StripPrefix(prefix string, h context.Handler) context.Handler {
// here we separate the path from the subdomain (if any), we care only for the path
// fixes a bug when serving static files via a subdomain
fixedPrefix := prefix
if dotWSlashIdx := strings.Index(fixedPrefix, SubdomainIndicator); dotWSlashIdx > 0 {
if dotWSlashIdx := strings.Index(fixedPrefix, SubdomainPrefix); dotWSlashIdx > 0 {
fixedPrefix = fixedPrefix[dotWSlashIdx+1:]
}
fixedPrefix = toWebPath(fixedPrefix)

View File

@@ -1,7 +1,3 @@
// Copyright 2017 Gerasimos Maropoulos, ΓΜ. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package router
import (
@@ -11,7 +7,9 @@ import (
"strings"
"github.com/kataras/iris/context"
"github.com/kataras/iris/core/nettools"
"github.com/kataras/iris/core/errors"
"github.com/kataras/iris/core/netutil"
"github.com/kataras/iris/core/router/node"
)
@@ -70,6 +68,13 @@ func NewDefaultHandler() RequestHandler {
return h
}
// RoutesProvider should be implemented by
// iteral which contains the registered routes.
type RoutesProvider interface { // api builder
GetRoutes() []*Route
GetRoute(routeName string) *Route
}
func (h *routerHandler) Build(provider RoutesProvider) error {
registeredRoutes := provider.GetRoutes()
h.trees = h.trees[0:0] // reset, inneed when rebuilding.
@@ -79,20 +84,24 @@ func (h *routerHandler) Build(provider RoutesProvider) error {
return len(registeredRoutes[i].Subdomain) >= len(registeredRoutes[j].Subdomain)
})
rp := errors.NewReporter()
for _, r := range registeredRoutes {
if r.Subdomain != "" {
h.hosts = true
}
// the only "bad" with this is if the user made an error
// on route, it will be stacked shown in this build state
// and no in the lines of the user's action, they should read
// the docs better. Or TODO: add a link here in order to help new users.
if err := h.addRoute(r.Method, r.Subdomain, r.Path, r.Handlers); err != nil {
return err
// node errors:
rp.Add("%v -> %s", err, r.String())
}
}
return nil
return rp.Return()
}
func (h *routerHandler) HandleRequest(ctx context.Context) {
@@ -134,14 +143,14 @@ func (h *routerHandler) HandleRequest(ctx context.Context) {
if h.hosts && t.Subdomain != "" {
requestHost := ctx.Host()
if nettools.IsLoopbackSubdomain(requestHost) {
if netutil.IsLoopbackSubdomain(requestHost) {
// this fixes a bug when listening on
// 127.0.0.1:8080 for example
// and have a wildcard subdomain and a route registered to root domain.
continue // it's not a subdomain, it's something like 127.0.0.1 probably
}
// it's a dynamic wildcard subdomain, we have just to check if ctx.subdomain is not empty
if t.Subdomain == DynamicSubdomainIndicator {
if t.Subdomain == SubdomainWildcardIndicator {
// mydomain.com -> invalid
// localhost -> invalid
// sub.mydomain.com -> valid

View File

@@ -1,7 +1,3 @@
// Copyright 2017 Gerasimos Maropoulos, ΓΜ. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package router
import (

View File

@@ -1,27 +0,0 @@
Copyright (c) 2017 Gerasimos Maropoulos, ΓΜ. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Gerasimos Maropoulos nor the name of his
username, kataras, may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -1,7 +1,3 @@
// Copyright 2017 Gerasimos Maropoulos. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ast
import (

View File

@@ -1,7 +1,3 @@
// Copyright 2017 Gerasimos Maropoulos. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package lexer
import (

View File

@@ -1,7 +1,3 @@
// Copyright 2017 Gerasimos Maropoulos. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package lexer
import (

View File

@@ -1,7 +1,3 @@
// Copyright 2017 Gerasimos Maropoulos. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package parser
import (

View File

@@ -1,7 +1,3 @@
// Copyright 2017 Gerasimos Maropoulos. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package parser
import (

View File

@@ -1,7 +1,3 @@
// Copyright 2017 Gerasimos Maropoulos. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package token
// Type is a specific type of int which describes the symbols.

View File

@@ -1,7 +1,3 @@
// Copyright 2017 Gerasimos Maropoulos, ΓΜ. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package macro
import (
@@ -239,7 +235,7 @@ type Map struct {
// NewMap returns a new macro Map with default
// type evaluators.
//
// Learn more at: https://github.com/kataras/iris/tree/master/_examples/beginner/routing/dynamic-path
// Learn more at: https://github.com/kataras/iris/tree/master/_examples/routing/dynamic-path
func NewMap() *Map {
return &Map{
// it allows everything, so no need for a regexp here.

View File

@@ -1,7 +1,3 @@
// Copyright 2017 Gerasimos Maropoulos, ΓΜ. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package macro
import (
@@ -179,7 +175,7 @@ func TestPathEvaluatorRaw(t *testing.T) {
// }
// })
// p, err := Parse("/user/@kataras")
// p, err := Parse("/user/@iris")
// if err != nil {
// t.Fatalf(err)
// }

View File

@@ -1,7 +1,3 @@
// Copyright 2017 Gerasimos Maropoulos, ΓΜ. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package macro
import (

View File

@@ -20,8 +20,8 @@ type node struct {
root bool
}
// ErrDublicate returned from MakeChild when more than one routes have the same registered path.
var ErrDublicate = errors.New("more than one routes have the same registered path")
// ErrDublicate returnned from `Add` when two or more routes have the same registered path.
var ErrDublicate = errors.New("two or more routes have the same registered path")
// Add adds a node to the tree, returns an ErrDublicate error on failure.
func (nodes *Nodes) Add(path string, handlers context.Handlers) error {
@@ -48,12 +48,22 @@ func (nodes *Nodes) Add(path string, handlers context.Handlers) error {
paramEnd -= paramEnd - paramStart
}
for _, idx := range paramsPos(path) {
var p []int
for i := 0; i < len(path); i++ {
idx := strings.IndexByte(path[i:], ':')
if idx == -1 {
break
}
p = append(p, idx+i)
i = idx + i
}
if err := nodes.add(path[:idx], nil, nil, true); err != nil { // take the static path to its own node
for _, idx := range p {
if err := nodes.add(path[:idx], nil, nil, true); err != nil {
return err
}
// create a second, empty, dynamic parameter node without the last slash
if nidx := idx + 1; len(path) > nidx {
if err := nodes.add(path[:nidx], nil, nil, true); err != nil {
return err
@@ -61,13 +71,12 @@ func (nodes *Nodes) Add(path string, handlers context.Handlers) error {
}
}
// last, create the node filled by the full path, parameters and its handlers
if err := nodes.add(path, params, handlers, true); err != nil {
return err
}
// sort by static path, remember, they were already sorted by subdomains too.
nodes.Sort()
// prioritize by static path remember, they were already sorted by subdomains too.
nodes.prioritize()
return nil
}
@@ -153,7 +162,7 @@ loop:
return nil
}
if len(n.handlers) > 0 { // n.handlers already setted
return ErrDublicate.Append("for: %s", n.s)
return ErrDublicate
}
n.paramNames = paramNames
n.handlers = handlers
@@ -216,7 +225,7 @@ func (nodes Nodes) findChild(path string, params []string) (*node, []string) {
continue
}
if len(path) == len(n.s) { // Node matched until the end of path.
if len(path) == len(n.s) {
if len(n.handlers) == 0 {
return nil, nil
}
@@ -226,7 +235,7 @@ func (nodes Nodes) findChild(path string, params []string) (*node, []string) {
child, childParamNames := n.children.findChild(path[len(n.s):], params)
if child == nil || len(child.handlers) == 0 {
// is wildcard and it is not root neither has children
if n.s[len(n.s)-1] == '/' && !(n.root && (n.s == "/" || len(n.children) > 0)) {
if len(n.handlers) == 0 {
return nil, nil
@@ -254,8 +263,8 @@ func (n *node) isDynamic() bool {
return n.s == ":"
}
// Sort sets the static paths first.
func (nodes Nodes) Sort() {
// prioritize sets the static paths first.
func (nodes Nodes) prioritize() {
sort.Slice(nodes, func(i, j int) bool {
if nodes[i].isDynamic() {
@@ -268,18 +277,6 @@ func (nodes Nodes) Sort() {
})
for _, n := range nodes {
n.children.Sort()
n.children.prioritize()
}
}
func paramsPos(s string) (pos []int) {
for i := 0; i < len(s); i++ {
p := strings.IndexByte(s[i:], ':')
if p == -1 {
break
}
pos = append(pos, p+i)
i = p + i
}
return
}

View File

@@ -1,7 +1,3 @@
// Copyright 2017 Gerasimos Maropoulos, ΓΜ. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package router
import (
@@ -15,11 +11,17 @@ import (
// Look the "APIBuilder" for its implementation.
type Party interface {
// Party creates and returns a new child Party with the following features.
Party(relativePath string, handlers ...context.Handler) Party
Party(relativePath string, middleware ...context.Handler) Party
// Subdomain returns a new party which is responsible to register routes to
// this specific "subdomain".
//
// If called from a child party then the subdomain will be prepended to the path instead of appended.
// So if app.Subdomain("admin.").Subdomain("panel.") then the result is: "panel.admin.".
Subdomain(subdomain string, middleware ...context.Handler) Party
// Use appends Handler(s) to the current Party's routes and child routes.
// If the current Party is the root, then it registers the middleware to all child Parties' routes too.
Use(handlers ...context.Handler)
Use(middleware ...context.Handler)
// Done appends to the very end, Handler(s) to the current Party's routes and child routes
// The difference from .Use is that this/or these Handler(s) are being always running last.
@@ -29,7 +31,7 @@ type Party interface {
// if empty method is passed then handler(s) are being registered to all methods, same as .Any.
//
// Returns the read-only route information.
Handle(method string, registeredPath string, handlers ...context.Handler) (*Route, error)
Handle(method string, registeredPath string, handlers ...context.Handler) *Route
// None registers an "offline" route
// see context.ExecRoute(routeName) and
@@ -37,47 +39,47 @@ type Party interface {
// Offline(handleResultregistry.*Route)
//
// Returns the read-only route information.
None(path string, handlers ...context.Handler) (*Route, error)
None(path string, handlers ...context.Handler) *Route
// Get registers a route for the Get http method.
//
// Returns the read-only route information.
Get(path string, handlers ...context.Handler) (*Route, error)
Get(path string, handlers ...context.Handler) *Route
// Post registers a route for the Post http method.
//
// Returns the read-only route information.
Post(path string, handlers ...context.Handler) (*Route, error)
Post(path string, handlers ...context.Handler) *Route
// Put registers a route for the Put http method.
//
// Returns the read-only route information.
Put(path string, handlers ...context.Handler) (*Route, error)
Put(path string, handlers ...context.Handler) *Route
// Delete registers a route for the Delete http method.
//
// Returns the read-only route information.
Delete(path string, handlers ...context.Handler) (*Route, error)
Delete(path string, handlers ...context.Handler) *Route
// Connect registers a route for the Connect http method.
//
// Returns the read-only route information.
Connect(path string, handlers ...context.Handler) (*Route, error)
Connect(path string, handlers ...context.Handler) *Route
// Head registers a route for the Head http method.
//
// Returns the read-only route information.
Head(path string, handlers ...context.Handler) (*Route, error)
Head(path string, handlers ...context.Handler) *Route
// Options registers a route for the Options http method.
//
// Returns the read-only route information.
Options(path string, handlers ...context.Handler) (*Route, error)
Options(path string, handlers ...context.Handler) *Route
// Patch registers a route for the Patch http method.
//
// Returns the read-only route information.
Patch(path string, handlers ...context.Handler) (*Route, error)
Patch(path string, handlers ...context.Handler) *Route
// Trace registers a route for the Trace http method.
//
// Returns the read-only route information.
Trace(path string, handlers ...context.Handler) (*Route, error)
Trace(path string, handlers ...context.Handler) *Route
// Any registers a route for ALL of the http methods
// (Get,Post,Put,Head,Patch,Options,Connect,Delete).
Any(registeredPath string, handlers ...context.Handler) error
Any(registeredPath string, handlers ...context.Handler) []*Route
// StaticHandler returns a new Handler which is ready
// to serve all kind of static files.
@@ -96,7 +98,7 @@ type Party interface {
// mySubdomainFsServer.Get("/static", h)
// ...
//
StaticHandler(systemPath string, showList bool, enableGzip bool, exceptRoutes ...*Route) context.Handler
StaticHandler(systemPath string, showList bool, enableGzip bool) context.Handler
// StaticServe serves a directory as web resource
// it's the simpliest form of the Static* functions
@@ -107,12 +109,12 @@ type Party interface {
// it uses gzip compression (compression on each request, no file cache).
//
// Returns the GET *Route.
StaticServe(systemPath string, requestPath ...string) (*Route, error)
StaticServe(systemPath string, requestPath ...string) *Route
// StaticContent registers a GET and HEAD method routes to the requestPath
// that are ready to serve raw static bytes, memory cached.
//
// Returns the GET *Route.
StaticContent(requestPath string, cType string, content []byte) (*Route, error)
StaticContent(requestPath string, cType string, content []byte) *Route
// StaticEmbedded used when files are distributed inside the app executable, using go-bindata mostly
// First parameter is the request path, the path which the files in the vdir will be served to, for example "/static"
@@ -122,8 +124,8 @@ type Party interface {
//
// Returns the GET *Route.
//
// Example: https://github.com/kataras/iris/tree/master/_examples/intermediate/serve-embedded-files
StaticEmbedded(requestPath string, vdir string, assetFn func(name string) ([]byte, error), namesFn func() []string) (*Route, error)
// Example: https://github.com/kataras/iris/tree/master/_examples/file-server/embedding-files-into-app
StaticEmbedded(requestPath string, vdir string, assetFn func(name string) ([]byte, error), namesFn func() []string) *Route
// Favicon serves static favicon
// accepts 2 parameters, second is optional
@@ -136,14 +138,13 @@ type Party interface {
// Note that you have to call it on every favicon you have to serve automatically (desktop, mobile and so on).
//
// Returns the GET *Route.
Favicon(favPath string, requestPath ...string) (*Route, error)
Favicon(favPath string, requestPath ...string) *Route
// StaticWeb returns a handler that serves HTTP requests
// with the contents of the file system rooted at directory.
//
// first parameter: the route path
// second parameter: the system directory
// third OPTIONAL parameter: the exception routes
// (= give priority to these routes instead of the static handler)
//
// for more options look router.StaticHandler.
//
// router.StaticWeb("/static", "./static")
@@ -155,7 +156,7 @@ type Party interface {
// StaticWeb calls the StaticHandler(systemPath, listingDirectories: false, gzip: false ).
//
// Returns the GET *Route.
StaticWeb(requestPath string, systemPath string, exceptRoutes ...*Route) (*Route, error)
StaticWeb(requestPath string, systemPath string) *Route
// Layout oerrides the parent template layout with a more specific layout for this Party
// returns this Party, to continue as normal

View File

@@ -1,7 +1,3 @@
// Copyright 2017 Gerasimos Maropoulos, ΓΜ. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package router
import (
@@ -10,8 +6,7 @@ import (
"strconv"
"strings"
"github.com/esemplastic/unis"
"github.com/kataras/iris/core/nettools"
"github.com/kataras/iris/core/netutil"
)
const (
@@ -22,18 +17,6 @@ const (
WildcardParamStart = "*"
)
// ResolveStaticPath receives a (dynamic) path and tries to return its static path part.
func ResolveStaticPath(original string) string {
i := strings.Index(original, ParamStart)
v := strings.Index(original, WildcardParamStart)
return unis.NewChain(
unis.NewConditional(
unis.NewRangeEnd(i),
unis.NewRangeEnd(v)),
cleanPath).Process(original)
}
// Param receives a parameter name prefixed with the ParamStart symbol.
func Param(name string) string {
return prefix(name, ParamStart)
@@ -47,8 +30,19 @@ func WildcardParam(name string) string {
return prefix(name, WildcardParamStart)
}
func prefix(str string, prefix string) string {
return unis.NewExclusivePrepender(prefix).Process(str)
func prefix(s string, prefix string) string {
if !strings.HasPrefix(s, prefix) {
return prefix + s
}
return s
}
func suffix(s string, suffix string) string {
if !strings.HasSuffix(s, suffix) {
return s + suffix
}
return s
}
func joinPath(path1 string, path2 string) string {
@@ -65,59 +59,78 @@ func joinPath(path1 string, path2 string) string {
// that is, replace "/.." by "/" at the beginning of a path.
//
// The returned path ends in a slash only if it is the root "/".
var cleanPath = unis.NewChain(
unis.NewSuffixRemover("/"),
unis.NewTargetedJoiner(0, '/'),
unis.ProcessorFunc(path.Clean),
unis.NewReplacer(map[string]string{
"//": "/",
"\\": "/",
}),
unis.ProcessorFunc(func(s string) string {
if s == "" || s == "." {
return "/"
}
return s
}),
)
const (
// DynamicSubdomainIndicator where a registered path starts with '*.' then it contains a dynamic subdomain, if subdomain == "*." then its dynamic
//
// used internally by URLPath and the router serve.
DynamicSubdomainIndicator = "*."
// SubdomainIndicator where './' exists in a registered path then it contains subdomain
//
// used on router builder
SubdomainIndicator = "./"
)
func newSubdomainDivider(sep string) unis.DividerFunc {
// invert if indiciator not found
// because we need the first parameter to be the subdomain
// even if empty, but the second parameter
// should be the path, in order to normalize it
// (because of the reason of subdomains shouldn't be normalized as path)
subdomainDevider := unis.NewInvertOnFailureDivider(unis.NewDivider(sep))
return func(fullpath string) (string, string) {
subdomain, path := subdomainDevider.Divide(fullpath)
if len(path) > 1 {
if path[0] == '/' && path[1] == '/' {
path = path[1:]
}
}
return subdomain, path //cleanPath(path)
func cleanPath(s string) string {
if s == "" || s == "." {
return "/"
}
// remove suffix "/"
if lidx := len(s) - 1; s[lidx] == '/' {
s = s[:lidx]
}
// prefix with "/"
s = prefix(s, "/")
// remove the os specific dir sep
s = strings.Replace(s, "\\", "/", -1)
// use std path to clean the path
s = path.Clean(s)
return s
}
// ExctractSubdomain checks if the path has subdomain and if it's
const (
// SubdomainWildcardIndicator where a registered path starts with '*.'.
// if subdomain == "*." then its wildcard.
//
// used internally by router and api builder.
SubdomainWildcardIndicator = "*."
// SubdomainWildcardPrefix where a registered path starts with "*./",
// then this route should accept any subdomain.
SubdomainWildcardPrefix = SubdomainWildcardIndicator + "/"
// SubdomainPrefix where './' exists in a registered path then it contains subdomain
//
// used on api builder.
SubdomainPrefix = "./" // i.e subdomain./ -> Subdomain: subdomain. Path: /
)
func hasSubdomain(s string) bool {
if s == "" {
return false
}
// subdomain./path
// .*/path
//
// remember: path always starts with "/"
// if not start with "/" then it should be something else,
// we don't assume anything else but subdomain.
slashIdx := strings.IndexByte(s, '/')
return slashIdx > 0 || s[0] == SubdomainPrefix[0] || (len(s) >= 2 && s[0:2] == SubdomainWildcardIndicator)
}
// splitSubdomainAndPath checks if the path has subdomain and if it's
// it splits the subdomain and path and returns them, otherwise it returns
// an empty subdomain and the given path.
// an empty subdomain and the clean path.
//
// First return value is the subdomain, second is the path.
var exctractSubdomain = newSubdomainDivider(SubdomainIndicator)
func splitSubdomainAndPath(fullUnparsedPath string) (subdomain string, path string) {
s := fullUnparsedPath
if s == "" || s == "/" {
return "", "/"
}
slashIdx := strings.IndexByte(s, '/')
if slashIdx == 0 {
// no subdomain
return "", cleanPath(s)
}
return s[0:slashIdx], cleanPath(s[slashIdx:]) // return subdomain without slash, path with slash
}
// RoutePathReverserOption option signature for the RoutePathReverser.
type RoutePathReverserOption func(*RoutePathReverser)
@@ -142,7 +155,7 @@ func WithHost(host string) RoutePathReverserOption {
return func(ps *RoutePathReverser) {
ps.vhost = host
if ps.vscheme == "" {
ps.vscheme = nettools.ResolveScheme(host)
ps.vscheme = netutil.ResolveSchemeFromVHost(host)
}
}
}
@@ -152,8 +165,8 @@ func WithHost(host string) RoutePathReverserOption {
// a scheme and a host to be used in the URL function.
func WithServer(srv *http.Server) RoutePathReverserOption {
return func(ps *RoutePathReverser) {
ps.vhost = nettools.ResolveVHost(srv.Addr)
ps.vscheme = nettools.ResolveSchemeFromServer(srv)
ps.vhost = netutil.ResolveVHost(srv.Addr)
ps.vscheme = netutil.ResolveSchemeFromServer(srv)
}
}
@@ -222,7 +235,7 @@ func toStringSlice(args []interface{}) []string {
// Remove the URL for now, it complicates things for the whole framework without a specific benefits,
// developers can just concat the subdomain, (host can be auto-retrieve by browser using the Path).
// URL same as Path but returns the full uri, i.e https://mysubdomain.mydomain.com/hello/kataras
// URL same as Path but returns the full uri, i.e https://mysubdomain.mydomain.com/hello/iris
func (ps *RoutePathReverser) URL(routeName string, paramValues ...interface{}) (url string) {
if ps.vhost == "" || ps.vscheme == "" {
return "not supported"
@@ -243,7 +256,7 @@ func (ps *RoutePathReverser) URL(routeName string, paramValues ...interface{}) (
scheme := ps.vscheme
// if it's dynamic subdomain then the first argument is the subdomain part
// for this part we are responsible not the custom routers
if r.Subdomain == DynamicSubdomainIndicator {
if r.Subdomain == SubdomainWildcardIndicator {
subdomain := args[0]
host = subdomain + "." + host
args = args[1:] // remove the subdomain part for the arguments,

29
core/router/path_test.go Normal file
View File

@@ -0,0 +1,29 @@
package router
import (
"testing"
)
func TestSplitSubdomainAndPath(t *testing.T) {
tests := []struct {
original string
subdomain string
path string
}{
{"admin./users/42", "admin.", "/users/42"},
{"//api/users\\42", "", "/api/users/42"},
{"admin./users/\\42", "admin.", "/users/42"},
{"*./users/\\42", "*.", "/users/42"},
}
for i, tt := range tests {
subdomain, path := splitSubdomainAndPath(tt.original)
if expected, got := tt.subdomain, subdomain; expected != got {
t.Fatalf("[%d] - expected subdomain '%s' but got '%s'", i, expected, got)
}
if expected, got := tt.path, path; expected != got {
t.Fatalf("[%d] - expected path '%s' but got '%s'", i, expected, got)
}
}
}

View File

@@ -1,7 +1,3 @@
// Copyright 2017 Gerasimos Maropoulos, ΓΜ. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package router
import (
@@ -61,6 +57,12 @@ func NewRoute(method, subdomain, unparsedPath string,
return route, nil
}
// String returns the form of METHOD, SUBDOMAIN, TMPL PATH
func (r Route) String() string {
return fmt.Sprintf("%s %s%s",
r.Method, r.Subdomain, r.Tmpl().Src)
}
// Tmpl returns the path template, i
// it contains the parsed template
// for the route's path.

View File

@@ -1,7 +1,3 @@
// Copyright 2017 Gerasimos Maropoulos, ΓΜ. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package router
import (

View File

@@ -57,7 +57,7 @@ func (s *SPABuilder) isAsset(reqPath string) bool {
// It should be passed to the router's `WrapRouter`:
// https://godoc.org/github.com/kataras/iris/core/router#Router.WrapRouter
//
// Example: https://github.com/kataras/iris/tree/master/_examples/beginner/file-server/single-page-application-builder
// Example: https://github.com/kataras/iris/tree/master/_examples/file-server/single-page-application-builder
func (s *SPABuilder) BuildWrapper(cPool *context.Pool) WrapperFunc {
fileServer := s.AssetHandler

View File

@@ -1,7 +1,3 @@
// Copyright 2017 Gerasimos Maropoulos, ΓΜ. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package router
import (
@@ -81,7 +77,7 @@ func defaultErrorCodeHandlers() *ErrorCodeHandlers {
func statusText(statusCode int) context.Handler {
return func(ctx context.Context) {
if _, err := ctx.WriteString(http.StatusText(statusCode)); err != nil {
// ctx.Application().Log("(status code: %d) %s",
// ctx.Application().Logger().Infof("(status code: %d) %s",
// err.Error(), statusCode)
}
}