Comments + IRoutes + IRouter + unexported AbortIndex
This commit is contained in:
parent
13f57702d4
commit
8f3047814e
14
auth.go
14
auth.go
@ -10,9 +10,7 @@ import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
AuthUserKey = "user"
|
||||
)
|
||||
const AuthUserKey = "user"
|
||||
|
||||
type (
|
||||
Accounts map[string]string
|
||||
@ -35,8 +33,9 @@ func (a authPairs) searchCredential(authValue string) (string, bool) {
|
||||
return "", false
|
||||
}
|
||||
|
||||
// Implements a basic Basic HTTP Authorization. It takes as arguments a map[string]string where
|
||||
// the key is the user name and the value is the password, as well as the name of the Realm
|
||||
// BasicAuthForRealm returns a Basic HTTP Authorization middleware. It takes as arguments a map[string]string where
|
||||
// the key is the user name and the value is the password, as well as the name of the Realm.
|
||||
// If the realm is empty, "Authorization Required" will be used by default.
|
||||
// (see http://tools.ietf.org/html/rfc2617#section-1.2)
|
||||
func BasicAuthForRealm(accounts Accounts, realm string) HandlerFunc {
|
||||
if realm == "" {
|
||||
@ -59,7 +58,7 @@ func BasicAuthForRealm(accounts Accounts, realm string) HandlerFunc {
|
||||
}
|
||||
}
|
||||
|
||||
// Implements a basic Basic HTTP Authorization. It takes as argument a map[string]string where
|
||||
// BasicAuth returns a Basic HTTP Authorization middleware. It takes as argument a map[string]string where
|
||||
// the key is the user name and the value is the password.
|
||||
func BasicAuth(accounts Accounts) HandlerFunc {
|
||||
return BasicAuthForRealm(accounts, "")
|
||||
@ -91,8 +90,7 @@ func authorizationHeader(user, password string) string {
|
||||
func secureCompare(given, actual string) bool {
|
||||
if subtle.ConstantTimeEq(int32(len(given)), int32(len(actual))) == 1 {
|
||||
return subtle.ConstantTimeCompare([]byte(given), []byte(actual)) == 1
|
||||
} else {
|
||||
}
|
||||
/* Securely compare actual to itself to keep constant time, but always return false */
|
||||
return subtle.ConstantTimeCompare([]byte(actual), []byte(actual)) == 1 && false
|
||||
}
|
||||
}
|
||||
|
26
context.go
26
context.go
@ -18,6 +18,7 @@ import (
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// Content-Type MIME of the most common data formats
|
||||
const (
|
||||
MIMEJSON = binding.MIMEJSON
|
||||
MIMEHTML = binding.MIMEHTML
|
||||
@ -28,7 +29,7 @@ const (
|
||||
MIMEMultipartPOSTForm = binding.MIMEMultipartPOSTForm
|
||||
)
|
||||
|
||||
const AbortIndex int8 = math.MaxInt8 / 2
|
||||
const abortIndex int8 = math.MaxInt8 / 2
|
||||
|
||||
// Context is the most important part of gin. It allows us to pass variables between middleware,
|
||||
// manage the flow, validate the JSON of a request and render a JSON response for example.
|
||||
@ -63,16 +64,18 @@ func (c *Context) reset() {
|
||||
c.Accepted = nil
|
||||
}
|
||||
|
||||
// Copy returns a copy of the current context that can be safely used outside the request's scope.
|
||||
// This have to be used then the context has to be passed to a goroutine.
|
||||
func (c *Context) Copy() *Context {
|
||||
var cp Context = *c
|
||||
cp.writermem.ResponseWriter = nil
|
||||
cp.Writer = &cp.writermem
|
||||
cp.index = AbortIndex
|
||||
cp.index = abortIndex
|
||||
cp.handlers = nil
|
||||
return &cp
|
||||
}
|
||||
|
||||
// Returns the main handle's name. For example if the handler is "handleGetUsers()", this
|
||||
// HandlerName returns the main handle's name. For example if the handler is "handleGetUsers()", this
|
||||
// function will return "main.handleGetUsers"
|
||||
func (c *Context) HandlerName() string {
|
||||
return nameOfFunction(c.handlers.Last())
|
||||
@ -93,27 +96,27 @@ func (c *Context) Next() {
|
||||
}
|
||||
}
|
||||
|
||||
// Returns if the currect context was aborted.
|
||||
// IsAborted returns true if the currect context was aborted.
|
||||
func (c *Context) IsAborted() bool {
|
||||
return c.index >= AbortIndex
|
||||
return c.index >= abortIndex
|
||||
}
|
||||
|
||||
// Stops the system to continue calling the pending handlers in the chain.
|
||||
// Abort stops the system to continue calling the pending handlers in the chain.
|
||||
// Let's say you have an authorization middleware that validates if the request is authorized
|
||||
// if the authorization fails (the password does not match). This method (Abort()) should be called
|
||||
// in order to stop the execution of the actual handler.
|
||||
func (c *Context) Abort() {
|
||||
c.index = AbortIndex
|
||||
c.index = abortIndex
|
||||
}
|
||||
|
||||
// It calls Abort() and writes the headers with the specified status code.
|
||||
// AbortWithStatus calls `Abort()` and writes the headers with the specified status code.
|
||||
// For example, a failed attempt to authentificate a request could use: context.AbortWithStatus(401).
|
||||
func (c *Context) AbortWithStatus(code int) {
|
||||
c.Writer.WriteHeader(code)
|
||||
c.Abort()
|
||||
}
|
||||
|
||||
// It calls AbortWithStatus() and Error() internally. This method stops the chain, writes the status code and
|
||||
// AbortWithError calls `AbortWithStatus()` and `Error()` internally. This method stops the chain, writes the status code and
|
||||
// pushes the specified error to `c.Errors`.
|
||||
// See Context.Error() for more details.
|
||||
func (c *Context) AbortWithError(code int, err error) *Error {
|
||||
@ -371,7 +374,7 @@ func (c *Context) Redirect(code int, location string) {
|
||||
})
|
||||
}
|
||||
|
||||
// Writes some data into the body stream and updates the HTTP code.
|
||||
// Data writes some data into the body stream and updates the HTTP code.
|
||||
func (c *Context) Data(code int, contentType string, data []byte) {
|
||||
c.Render(code, render.Data{
|
||||
ContentType: contentType,
|
||||
@ -379,11 +382,12 @@ func (c *Context) Data(code int, contentType string, data []byte) {
|
||||
})
|
||||
}
|
||||
|
||||
// Writes the specified file into the body stream in a efficient way.
|
||||
// File writes the specified file into the body stream in a efficient way.
|
||||
func (c *Context) File(filepath string) {
|
||||
http.ServeFile(c.Writer, c.Request, filepath)
|
||||
}
|
||||
|
||||
// SSEvent writes a Server-Sent Event into the body stream.
|
||||
func (c *Context) SSEvent(name string, message interface{}) {
|
||||
c.Render(-1, sse.Event{
|
||||
Event: name,
|
||||
|
@ -129,7 +129,7 @@ func TestContextCopy(t *testing.T) {
|
||||
assert.Nil(t, cp.writermem.ResponseWriter)
|
||||
assert.Equal(t, &cp.writermem, cp.Writer.(*responseWriter))
|
||||
assert.Equal(t, cp.Request, c.Request)
|
||||
assert.Equal(t, cp.index, AbortIndex)
|
||||
assert.Equal(t, cp.index, abortIndex)
|
||||
assert.Equal(t, cp.Keys, c.Keys)
|
||||
assert.Equal(t, cp.engine, c.engine)
|
||||
assert.Equal(t, cp.Params, c.Params)
|
||||
@ -418,7 +418,7 @@ func TestContextIsAborted(t *testing.T) {
|
||||
c.Next()
|
||||
assert.True(t, c.IsAborted())
|
||||
|
||||
c.Next()
|
||||
c.index++
|
||||
assert.True(t, c.IsAborted())
|
||||
}
|
||||
|
||||
@ -430,7 +430,7 @@ func TestContextAbortWithStatus(t *testing.T) {
|
||||
c.AbortWithStatus(401)
|
||||
c.Writer.WriteHeaderNow()
|
||||
|
||||
assert.Equal(t, c.index, AbortIndex)
|
||||
assert.Equal(t, c.index, abortIndex)
|
||||
assert.Equal(t, c.Writer.Status(), 401)
|
||||
assert.Equal(t, w.Code, 401)
|
||||
assert.True(t, c.IsAborted())
|
||||
@ -482,7 +482,7 @@ func TestContextAbortWithError(t *testing.T) {
|
||||
c.Writer.WriteHeaderNow()
|
||||
|
||||
assert.Equal(t, w.Code, 401)
|
||||
assert.Equal(t, c.index, AbortIndex)
|
||||
assert.Equal(t, c.index, abortIndex)
|
||||
assert.True(t, c.IsAborted())
|
||||
}
|
||||
|
||||
|
7
debug.go
7
debug.go
@ -9,6 +9,9 @@ import "log"
|
||||
func init() {
|
||||
log.SetFlags(0)
|
||||
}
|
||||
|
||||
// IsDebugging returns true if the framework is running in debug mode.
|
||||
// Use SetMode(gin.Release) to switch to disable the debug mode.
|
||||
func IsDebugging() bool {
|
||||
return ginMode == debugCode
|
||||
}
|
||||
@ -27,7 +30,7 @@ func debugPrint(format string, values ...interface{}) {
|
||||
}
|
||||
}
|
||||
|
||||
func debugPrintWARNING_New() {
|
||||
func debugPrintWARNINGNew() {
|
||||
debugPrint(`[WARNING] Running in "debug" mode. Switch to "release" mode in production.
|
||||
- using env: export GIN_MODE=release
|
||||
- using code: gin.SetMode(gin.ReleaseMode)
|
||||
@ -35,7 +38,7 @@ func debugPrintWARNING_New() {
|
||||
`)
|
||||
}
|
||||
|
||||
func debugPrintWARNING_SetHTMLTemplate() {
|
||||
func debugPrintWARNINGSetHTMLTemplate() {
|
||||
debugPrint(`[WARNING] Since SetHTMLTemplate() is NOT thread-safe. It should only be called
|
||||
at initialization. ie. before any route is registered or the router is listening in a socket:
|
||||
|
||||
|
33
gin.go
33
gin.go
@ -14,6 +14,7 @@ import (
|
||||
"github.com/gin-gonic/gin/render"
|
||||
)
|
||||
|
||||
// Framework's version
|
||||
const Version = "v1.0rc2"
|
||||
|
||||
var default404Body = []byte("404 page not found")
|
||||
@ -22,6 +23,7 @@ var default405Body = []byte("405 method not allowed")
|
||||
type HandlerFunc func(*Context)
|
||||
type HandlersChain []HandlerFunc
|
||||
|
||||
// Last returns the last handler in the chain. ie. the last handler is the main own.
|
||||
func (c HandlersChain) Last() HandlerFunc {
|
||||
length := len(c)
|
||||
if length > 0 {
|
||||
@ -38,7 +40,8 @@ type (
|
||||
Handler string
|
||||
}
|
||||
|
||||
// Represents the web framework, it wraps the blazing fast httprouter multiplexer and a list of global middlewares.
|
||||
// Engine is the framework's instance, it contains the muxer, middlewares and configuration settings.
|
||||
// Create an instance of Engine, by using New() or Default()
|
||||
Engine struct {
|
||||
RouterGroup
|
||||
HTMLRender render.HTMLRender
|
||||
@ -78,12 +81,16 @@ type (
|
||||
}
|
||||
)
|
||||
|
||||
var _ RoutesInterface = &Engine{}
|
||||
var _ IRouter = &Engine{}
|
||||
|
||||
// Returns a new blank Engine instance without any middleware attached.
|
||||
// The most basic configuration
|
||||
// New returns a new blank Engine instance without any middleware attached.
|
||||
// By default the configuration is:
|
||||
// - RedirectTrailingSlash: true
|
||||
// - RedirectFixedPath: false
|
||||
// - HandleMethodNotAllowed: false
|
||||
// - ForwardedByClientIP: true
|
||||
func New() *Engine {
|
||||
debugPrintWARNING_New()
|
||||
debugPrintWARNINGNew()
|
||||
engine := &Engine{
|
||||
RouterGroup: RouterGroup{
|
||||
Handlers: nil,
|
||||
@ -103,7 +110,7 @@ func New() *Engine {
|
||||
return engine
|
||||
}
|
||||
|
||||
// Returns a Engine instance with the Logger and Recovery already attached.
|
||||
// Default returns an Engine instance with the Logger and Recovery middleware already attached.
|
||||
func Default() *Engine {
|
||||
engine := New()
|
||||
engine.Use(Recovery(), Logger())
|
||||
@ -134,7 +141,7 @@ func (engine *Engine) LoadHTMLFiles(files ...string) {
|
||||
|
||||
func (engine *Engine) SetHTMLTemplate(templ *template.Template) {
|
||||
if len(engine.trees) > 0 {
|
||||
debugPrintWARNING_SetHTMLTemplate()
|
||||
debugPrintWARNINGSetHTMLTemplate()
|
||||
}
|
||||
engine.HTMLRender = render.HTMLProduction{Template: templ}
|
||||
}
|
||||
@ -154,7 +161,7 @@ func (engine *Engine) NoMethod(handlers ...HandlerFunc) {
|
||||
// Attachs a global middleware to the router. ie. the middlewares attached though Use() will be
|
||||
// included in the handlers chain for every single request. Even 404, 405, static files...
|
||||
// For example, this is the right place for a logger or error management middleware.
|
||||
func (engine *Engine) Use(middlewares ...HandlerFunc) routesInterface {
|
||||
func (engine *Engine) Use(middlewares ...HandlerFunc) IRoutes {
|
||||
engine.RouterGroup.Use(middlewares...)
|
||||
engine.rebuild404Handlers()
|
||||
engine.rebuild405Handlers()
|
||||
@ -193,6 +200,8 @@ func (engine *Engine) addRoute(method, path string, handlers HandlersChain) {
|
||||
root.addRoute(path, handlers)
|
||||
}
|
||||
|
||||
// Routes returns a slice of registered routes, including some useful information, such as:
|
||||
// the http method, path and the handler name.
|
||||
func (engine *Engine) Routes() (routes RoutesInfo) {
|
||||
for _, tree := range engine.trees {
|
||||
routes = iterate("", tree.method, routes, tree.root)
|
||||
@ -215,7 +224,7 @@ func iterate(path, method string, routes RoutesInfo, root *node) RoutesInfo {
|
||||
return routes
|
||||
}
|
||||
|
||||
// The router is attached to a http.Server and starts listening and serving HTTP requests.
|
||||
// Run attaches the router to a http.Server and starts listening and serving HTTP requests.
|
||||
// It is a shortcut for http.ListenAndServe(addr, router)
|
||||
// Note: this method will block the calling goroutine undefinitelly unless an error happens.
|
||||
func (engine *Engine) Run(addr string) (err error) {
|
||||
@ -226,7 +235,7 @@ func (engine *Engine) Run(addr string) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// The router is attached to a http.Server and starts listening and serving HTTPS requests.
|
||||
// RunTLS attaches the router to a http.Server and starts listening and serving HTTPS (secure) requests.
|
||||
// It is a shortcut for http.ListenAndServeTLS(addr, certFile, keyFile, router)
|
||||
// Note: this method will block the calling goroutine undefinitelly unless an error happens.
|
||||
func (engine *Engine) RunTLS(addr string, certFile string, keyFile string) (err error) {
|
||||
@ -237,8 +246,8 @@ func (engine *Engine) RunTLS(addr string, certFile string, keyFile string) (err
|
||||
return
|
||||
}
|
||||
|
||||
// The router is attached to a http.Server and starts listening and serving HTTP requests
|
||||
// through the specified unix socket (ie. a file)
|
||||
// RunUnix attaches the router to a http.Server and starts listening and serving HTTP requests
|
||||
// through the specified unix socket (ie. a file).
|
||||
// Note: this method will block the calling goroutine undefinitelly unless an error happens.
|
||||
func (engine *Engine) RunUnix(file string) (err error) {
|
||||
debugPrint("Listening and serving HTTP on unix:/%s", file)
|
||||
|
@ -23,10 +23,20 @@ type (
|
||||
http.Flusher
|
||||
http.CloseNotifier
|
||||
|
||||
// Returns the HTTP response status code of the current request.
|
||||
Status() int
|
||||
|
||||
// Returns the number of bytes already written into the response http body.
|
||||
// See Written()
|
||||
Size() int
|
||||
|
||||
// Writes the string into the response body.
|
||||
WriteString(string) (int, error)
|
||||
|
||||
// Returns true if the response body was already written.
|
||||
Written() bool
|
||||
|
||||
// Forces to write the http header (status code + headers).
|
||||
WriteHeaderNow()
|
||||
}
|
||||
|
||||
|
@ -12,30 +12,30 @@ import (
|
||||
)
|
||||
|
||||
type (
|
||||
RoutesInterface interface {
|
||||
routesInterface
|
||||
IRouter interface {
|
||||
IRoutes
|
||||
Group(string, ...HandlerFunc) *RouterGroup
|
||||
}
|
||||
|
||||
routesInterface interface {
|
||||
Use(...HandlerFunc) routesInterface
|
||||
IRoutes interface {
|
||||
Use(...HandlerFunc) IRoutes
|
||||
|
||||
Handle(string, string, ...HandlerFunc) routesInterface
|
||||
Any(string, ...HandlerFunc) routesInterface
|
||||
GET(string, ...HandlerFunc) routesInterface
|
||||
POST(string, ...HandlerFunc) routesInterface
|
||||
DELETE(string, ...HandlerFunc) routesInterface
|
||||
PATCH(string, ...HandlerFunc) routesInterface
|
||||
PUT(string, ...HandlerFunc) routesInterface
|
||||
OPTIONS(string, ...HandlerFunc) routesInterface
|
||||
HEAD(string, ...HandlerFunc) routesInterface
|
||||
Handle(string, string, ...HandlerFunc) IRoutes
|
||||
Any(string, ...HandlerFunc) IRoutes
|
||||
GET(string, ...HandlerFunc) IRoutes
|
||||
POST(string, ...HandlerFunc) IRoutes
|
||||
DELETE(string, ...HandlerFunc) IRoutes
|
||||
PATCH(string, ...HandlerFunc) IRoutes
|
||||
PUT(string, ...HandlerFunc) IRoutes
|
||||
OPTIONS(string, ...HandlerFunc) IRoutes
|
||||
HEAD(string, ...HandlerFunc) IRoutes
|
||||
|
||||
StaticFile(string, string) routesInterface
|
||||
Static(string, string) routesInterface
|
||||
StaticFS(string, http.FileSystem) routesInterface
|
||||
StaticFile(string, string) IRoutes
|
||||
Static(string, string) IRoutes
|
||||
StaticFS(string, http.FileSystem) IRoutes
|
||||
}
|
||||
|
||||
// Used internally to configure router, a RouterGroup is associated with a prefix
|
||||
// RouterGroup is used internally to configure router, a RouterGroup is associated with a prefix
|
||||
// and an array of handlers (middlewares)
|
||||
RouterGroup struct {
|
||||
Handlers HandlersChain
|
||||
@ -45,15 +45,15 @@ type (
|
||||
}
|
||||
)
|
||||
|
||||
var _ RoutesInterface = &RouterGroup{}
|
||||
var _ IRouter = &RouterGroup{}
|
||||
|
||||
// Adds middlewares to the group, see example code in github.
|
||||
func (group *RouterGroup) Use(middlewares ...HandlerFunc) routesInterface {
|
||||
// Use adds middlewares to the group, see example code in github.
|
||||
func (group *RouterGroup) Use(middlewares ...HandlerFunc) IRoutes {
|
||||
group.Handlers = append(group.Handlers, middlewares...)
|
||||
return group.returnObj()
|
||||
}
|
||||
|
||||
// Creates a new router group. You should add all the routes that have common middlwares or the same path prefix.
|
||||
// Group creates a new router group. You should add all the routes that have common middlwares or the same path prefix.
|
||||
// For example, all the routes that use a common middlware for authorization could be grouped.
|
||||
func (group *RouterGroup) Group(relativePath string, handlers ...HandlerFunc) *RouterGroup {
|
||||
return &RouterGroup{
|
||||
@ -63,6 +63,13 @@ func (group *RouterGroup) Group(relativePath string, handlers ...HandlerFunc) *R
|
||||
}
|
||||
}
|
||||
|
||||
func (group *RouterGroup) handle(httpMethod, relativePath string, handlers HandlersChain) IRoutes {
|
||||
absolutePath := group.calculateAbsolutePath(relativePath)
|
||||
handlers = group.combineHandlers(handlers)
|
||||
group.engine.addRoute(httpMethod, absolutePath, handlers)
|
||||
return group.returnObj()
|
||||
}
|
||||
|
||||
// Handle registers a new request handle and middlewares with the given path and method.
|
||||
// The last handler should be the real handler, the other ones should be middlewares that can and should be shared among different routes.
|
||||
// See the example code in github.
|
||||
@ -73,14 +80,7 @@ func (group *RouterGroup) Group(relativePath string, handlers ...HandlerFunc) *R
|
||||
// This function is intended for bulk loading and to allow the usage of less
|
||||
// frequently used, non-standardized or custom methods (e.g. for internal
|
||||
// communication with a proxy).
|
||||
func (group *RouterGroup) handle(httpMethod, relativePath string, handlers HandlersChain) routesInterface {
|
||||
absolutePath := group.calculateAbsolutePath(relativePath)
|
||||
handlers = group.combineHandlers(handlers)
|
||||
group.engine.addRoute(httpMethod, absolutePath, handlers)
|
||||
return group.returnObj()
|
||||
}
|
||||
|
||||
func (group *RouterGroup) Handle(httpMethod, relativePath string, handlers ...HandlerFunc) routesInterface {
|
||||
func (group *RouterGroup) Handle(httpMethod, relativePath string, handlers ...HandlerFunc) IRoutes {
|
||||
if matches, err := regexp.MatchString("^[A-Z]+$", httpMethod); !matches || err != nil {
|
||||
panic("http method " + httpMethod + " is not valid")
|
||||
}
|
||||
@ -88,42 +88,43 @@ func (group *RouterGroup) Handle(httpMethod, relativePath string, handlers ...Ha
|
||||
}
|
||||
|
||||
// POST is a shortcut for router.Handle("POST", path, handle)
|
||||
func (group *RouterGroup) POST(relativePath string, handlers ...HandlerFunc) routesInterface {
|
||||
func (group *RouterGroup) POST(relativePath string, handlers ...HandlerFunc) IRoutes {
|
||||
return group.handle("POST", relativePath, handlers)
|
||||
}
|
||||
|
||||
// GET is a shortcut for router.Handle("GET", path, handle)
|
||||
func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) routesInterface {
|
||||
func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes {
|
||||
return group.handle("GET", relativePath, handlers)
|
||||
}
|
||||
|
||||
// DELETE is a shortcut for router.Handle("DELETE", path, handle)
|
||||
func (group *RouterGroup) DELETE(relativePath string, handlers ...HandlerFunc) routesInterface {
|
||||
func (group *RouterGroup) DELETE(relativePath string, handlers ...HandlerFunc) IRoutes {
|
||||
return group.handle("DELETE", relativePath, handlers)
|
||||
}
|
||||
|
||||
// PATCH is a shortcut for router.Handle("PATCH", path, handle)
|
||||
func (group *RouterGroup) PATCH(relativePath string, handlers ...HandlerFunc) routesInterface {
|
||||
func (group *RouterGroup) PATCH(relativePath string, handlers ...HandlerFunc) IRoutes {
|
||||
return group.handle("PATCH", relativePath, handlers)
|
||||
}
|
||||
|
||||
// PUT is a shortcut for router.Handle("PUT", path, handle)
|
||||
func (group *RouterGroup) PUT(relativePath string, handlers ...HandlerFunc) routesInterface {
|
||||
func (group *RouterGroup) PUT(relativePath string, handlers ...HandlerFunc) IRoutes {
|
||||
return group.handle("PUT", relativePath, handlers)
|
||||
}
|
||||
|
||||
// OPTIONS is a shortcut for router.Handle("OPTIONS", path, handle)
|
||||
func (group *RouterGroup) OPTIONS(relativePath string, handlers ...HandlerFunc) routesInterface {
|
||||
func (group *RouterGroup) OPTIONS(relativePath string, handlers ...HandlerFunc) IRoutes {
|
||||
return group.handle("OPTIONS", relativePath, handlers)
|
||||
}
|
||||
|
||||
// HEAD is a shortcut for router.Handle("HEAD", path, handle)
|
||||
func (group *RouterGroup) HEAD(relativePath string, handlers ...HandlerFunc) routesInterface {
|
||||
func (group *RouterGroup) HEAD(relativePath string, handlers ...HandlerFunc) IRoutes {
|
||||
return group.handle("HEAD", relativePath, handlers)
|
||||
}
|
||||
|
||||
func (group *RouterGroup) Any(relativePath string, handlers ...HandlerFunc) routesInterface {
|
||||
// Any registers a route that matches all the HTTP methods.
|
||||
// GET, POST, PUT, PATCH, HEAD, OPTIONS, DELETE, CONNECT, TRACE
|
||||
func (group *RouterGroup) Any(relativePath string, handlers ...HandlerFunc) IRoutes {
|
||||
group.handle("GET", relativePath, handlers)
|
||||
group.handle("POST", relativePath, handlers)
|
||||
group.handle("PUT", relativePath, handlers)
|
||||
@ -136,7 +137,9 @@ func (group *RouterGroup) Any(relativePath string, handlers ...HandlerFunc) rout
|
||||
return group.returnObj()
|
||||
}
|
||||
|
||||
func (group *RouterGroup) StaticFile(relativePath, filepath string) routesInterface {
|
||||
// StaticFile registers a single route in order to server a single file of the local filesystem.
|
||||
// router.StaticFile("favicon.ico", "./resources/favicon.ico")
|
||||
func (group *RouterGroup) StaticFile(relativePath, filepath string) IRoutes {
|
||||
if strings.Contains(relativePath, ":") || strings.Contains(relativePath, "*") {
|
||||
panic("URL parameters can not be used when serving a static file")
|
||||
}
|
||||
@ -154,11 +157,13 @@ func (group *RouterGroup) StaticFile(relativePath, filepath string) routesInterf
|
||||
// To use the operating system's file system implementation,
|
||||
// use :
|
||||
// router.Static("/static", "/var/www")
|
||||
func (group *RouterGroup) Static(relativePath, root string) routesInterface {
|
||||
func (group *RouterGroup) Static(relativePath, root string) IRoutes {
|
||||
return group.StaticFS(relativePath, Dir(root, false))
|
||||
}
|
||||
|
||||
func (group *RouterGroup) StaticFS(relativePath string, fs http.FileSystem) routesInterface {
|
||||
// StaticFS works just like `Static()` but a custom `http.FileSystem` can be used instead.
|
||||
// Gin by default user: gin.Dir()
|
||||
func (group *RouterGroup) StaticFS(relativePath string, fs http.FileSystem) IRoutes {
|
||||
if strings.Contains(relativePath, ":") || strings.Contains(relativePath, "*") {
|
||||
panic("URL parameters can not be used when serving a static folder")
|
||||
}
|
||||
@ -185,7 +190,7 @@ func (group *RouterGroup) createStaticHandler(relativePath string, fs http.FileS
|
||||
|
||||
func (group *RouterGroup) combineHandlers(handlers HandlersChain) HandlersChain {
|
||||
finalSize := len(group.Handlers) + len(handlers)
|
||||
if finalSize >= int(AbortIndex) {
|
||||
if finalSize >= int(abortIndex) {
|
||||
panic("too many handlers")
|
||||
}
|
||||
mergedHandlers := make(HandlersChain, finalSize)
|
||||
@ -198,10 +203,9 @@ func (group *RouterGroup) calculateAbsolutePath(relativePath string) string {
|
||||
return joinPaths(group.BasePath, relativePath)
|
||||
}
|
||||
|
||||
func (group *RouterGroup) returnObj() routesInterface {
|
||||
func (group *RouterGroup) returnObj() IRoutes {
|
||||
if group.root {
|
||||
return group.engine
|
||||
} else {
|
||||
}
|
||||
return group
|
||||
}
|
||||
}
|
||||
|
@ -157,7 +157,7 @@ func TestRouterGroupPipeline(t *testing.T) {
|
||||
testRoutesInterface(t, v1)
|
||||
}
|
||||
|
||||
func testRoutesInterface(t *testing.T, r RoutesInterface) {
|
||||
func testRoutesInterface(t *testing.T, r IRoutes) {
|
||||
handler := func(c *Context) {}
|
||||
assert.Equal(t, r, r.Use(handler))
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user