mirror of
https://github.com/kataras/iris.git
synced 2025-02-02 15:30:36 +01:00
Nothing special here, read HISTORY.md
This commit is contained in:
parent
053588babd
commit
e4ab993760
10
HISTORY.md
10
HISTORY.md
|
@ -375,7 +375,7 @@ Downloads the [basic](https://github.com/iris-contrib/examples/tree/master/AIO_
|
|||
**outline**
|
||||
```go
|
||||
|
||||
// StaticEmbedded used when files are distrubuted inside the app executable, using go-bindata mostly
|
||||
// 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(second parameter) will be served to, for example "/static"
|
||||
// Second parameter is the (virtual) directory path, for example "./assets"
|
||||
// Third parameter is the Asset function
|
||||
|
@ -832,7 +832,7 @@ iris.Set(iris.OptionDisableBanner(true))
|
|||
|
||||
**List** of all available options:
|
||||
```go
|
||||
// OptionDisablePathCorrection corrects and redirects the requested path to the registed path
|
||||
// OptionDisablePathCorrection corrects and redirects the requested path to the registered path
|
||||
// for example, if /home/ path is requested but no handler for this Route found,
|
||||
// then the Router checks if /home handler exists, if yes,
|
||||
// (permant)redirects the client to the correct path /home
|
||||
|
@ -880,7 +880,7 @@ OptionTimeFormat(val string)
|
|||
OptionCharset(val string)
|
||||
|
||||
// OptionGzip enables gzip compression on your Render actions, this includes any type of render, templates and pure/raw content
|
||||
// If you don't want to enable it globaly, you could just use the third parameter on context.Render("myfileOrResponse", structBinding{}, iris.RenderOptions{"gzip": true})
|
||||
// If you don't want to enable it globally, you could just use the third parameter on context.Render("myfileOrResponse", structBinding{}, iris.RenderOptions{"gzip": true})
|
||||
// Default is false
|
||||
OptionGzip(val bool)
|
||||
|
||||
|
@ -1124,7 +1124,7 @@ Notes: if you compare it with previous releases (13+ versions before v3 stable),
|
|||
If you're **willing to donate** click [here](DONATIONS.md)!
|
||||
|
||||
|
||||
- `iris.Config.Gzip`, enables gzip compression on your Render actions, this includes any type of render, templates and pure/raw content. If you don't want to enable it globaly, you could just use the third parameter on context.Render("myfileOrResponse", structBinding{}, iris.RenderOptions{"gzip": true}). It defaults to false
|
||||
- `iris.Config.Gzip`, enables gzip compression on your Render actions, this includes any type of render, templates and pure/raw content. If you don't want to enable it globally, you could just use the third parameter on context.Render("myfileOrResponse", structBinding{}, iris.RenderOptions{"gzip": true}). It defaults to false
|
||||
|
||||
|
||||
- **Added** `config.Server.Name` as requested
|
||||
|
@ -1551,7 +1551,7 @@ OnDisconnect(func(){})
|
|||
We have some base-config's changed, these configs which are defaulted to true renamed to 'Disable+$oldName'
|
||||
```go
|
||||
|
||||
// DisablePathCorrection corrects and redirects the requested path to the registed path
|
||||
// DisablePathCorrection corrects and redirects the requested path to the registered path
|
||||
// for example, if /home/ path is requested but no handler for this Route found,
|
||||
// then the Router checks if /home handler exists, if yes,
|
||||
// (permant)redirects the client to the correct path /home
|
||||
|
|
|
@ -378,7 +378,7 @@ Serve files or directories, use the correct for your case, if you don't know whi
|
|||
// you can declare your own path if you have more than one favicon (desktop, mobile and so on)
|
||||
//
|
||||
// this func will add a route for you which will static serve the /yuorpath/yourfile.ico to the /yourfile.ico (nothing special that you can't handle by yourself)
|
||||
// Note that you have to call it on every favicon you have to serve automatically (dekstop, mobile and so on)
|
||||
// Note that you have to call it on every favicon you have to serve automatically (desktop, mobile and so on)
|
||||
//
|
||||
// panics on error
|
||||
Favicon(favPath string, requestPath ...string) RouteNameFunc
|
||||
|
@ -393,7 +393,7 @@ StaticHandler(reqPath string, systemPath string, showList bool, enableGzip bool)
|
|||
// second parameter is the system directory (string)
|
||||
StaticWeb(reqPath string, systemPath string) RouteNameFunc
|
||||
|
||||
// StaticEmbedded used when files are distrubuted inside the app executable, using go-bindata mostly
|
||||
// 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"
|
||||
// Second parameter is the (virtual) directory path, for example "./assets"
|
||||
// Third parameter is the Asset function
|
||||
|
|
|
@ -119,7 +119,7 @@ type Configuration struct {
|
|||
// Default is false
|
||||
CheckForUpdatesSync bool
|
||||
|
||||
// DisablePathCorrection corrects and redirects the requested path to the registed path
|
||||
// DisablePathCorrection corrects and redirects the requested path to the registered path
|
||||
// for example, if /home/ path is requested but no handler for this Route found,
|
||||
// then the Router checks if /home handler exists, if yes,
|
||||
// (permant)redirects the client to the correct path /home
|
||||
|
@ -177,7 +177,7 @@ type Configuration struct {
|
|||
Charset string
|
||||
|
||||
// Gzip enables gzip compression on your Render actions, this includes any type of render, templates and pure/raw content
|
||||
// If you don't want to enable it globaly, you could just use the third parameter on context.Render("myfileOrResponse", structBinding{}, iris.RenderOptions{"gzip": true})
|
||||
// If you don't want to enable it globally, you could just use the third parameter on context.Render("myfileOrResponse", structBinding{}, iris.RenderOptions{"gzip": true})
|
||||
// Defaults to false
|
||||
Gzip bool
|
||||
|
||||
|
@ -312,7 +312,7 @@ var (
|
|||
}
|
||||
}
|
||||
|
||||
// OptionDisablePathCorrection corrects and redirects the requested path to the registed path
|
||||
// OptionDisablePathCorrection corrects and redirects the requested path to the registered path
|
||||
// for example, if /home/ path is requested but no handler for this Route found,
|
||||
// then the Router checks if /home handler exists, if yes,
|
||||
// (permant)redirects the client to the correct path /home
|
||||
|
@ -401,7 +401,7 @@ var (
|
|||
}
|
||||
|
||||
// OptionGzip enables gzip compression on your Render actions, this includes any type of render, templates and pure/raw content
|
||||
// If you don't want to enable it globaly, you could just use the third parameter on context.Render("myfileOrResponse", structBinding{}, iris.RenderOptions{"gzip": true})
|
||||
// If you don't want to enable it globally, you could just use the third parameter on context.Render("myfileOrResponse", structBinding{}, iris.RenderOptions{"gzip": true})
|
||||
// Default is false
|
||||
OptionGzip = func(val bool) OptionSet {
|
||||
return func(c *Configuration) {
|
||||
|
|
10
context.go
10
context.go
|
@ -64,7 +64,7 @@ const (
|
|||
// CacheControl "Cache-Control"
|
||||
cacheControl = "Cache-Control"
|
||||
|
||||
// stopExecutionPosition used inside the Context, is the number which shows us that the context's middleware manualy stop the execution
|
||||
// stopExecutionPosition used inside the Context, is the number which shows us that the context's middleware manually stop the execution
|
||||
stopExecutionPosition = 255
|
||||
)
|
||||
|
||||
|
@ -132,7 +132,7 @@ type (
|
|||
Request *http.Request
|
||||
values requestValues
|
||||
framework *Framework
|
||||
//keep track all registed middleware (handlers)
|
||||
//keep track all registered middleware (handlers)
|
||||
Middleware Middleware // exported because is useful for debugging
|
||||
session sessions.Session
|
||||
// Pos is the position number of the Context, look .Next to understand
|
||||
|
@ -313,7 +313,7 @@ func (ctx *Context) URLParam(key string) string {
|
|||
return ctx.Request.URL.Query().Get(key)
|
||||
}
|
||||
|
||||
// URLParams returns a map of GET query parameters seperated by comma if more than one
|
||||
// URLParams returns a map of GET query parameters separated by comma if more than one
|
||||
// it returns an empty map if nothing founds
|
||||
func (ctx *Context) URLParams() map[string]string {
|
||||
values := map[string]string{}
|
||||
|
@ -1192,7 +1192,7 @@ func (ctx *Context) RemoveCookie(name string) {
|
|||
c.Expires = exp
|
||||
c.MaxAge = -1
|
||||
ctx.SetCookie(c)
|
||||
// delete request's cookie also, which is temporarly available
|
||||
// delete request's cookie also, which is temporary available
|
||||
ctx.Request.Header.Set("Cookie", "")
|
||||
}
|
||||
|
||||
|
@ -1292,7 +1292,7 @@ var errTransactionInterrupted = errors.New("Transaction Interrupted, recovery fr
|
|||
// BeginTransaction starts a scoped transaction.
|
||||
//
|
||||
// Can't say a lot here because it will take more than 200 lines to write about.
|
||||
// You can search third-party articles or books on how Business Transaction works (it's quite simple, especialy here).
|
||||
// You can search third-party articles or books on how Business Transaction works (it's quite simple, especially here).
|
||||
//
|
||||
// Note that this is unique and new
|
||||
// (=I haver never seen any other examples or code in Golang on this subject, so far, as with the most of iris features...)
|
||||
|
|
|
@ -684,7 +684,7 @@ func TestTransactions(t *testing.T) {
|
|||
|
||||
// OPTIONAl STEP:
|
||||
// but useful if we want to post back an error message to the client if the transaction failed.
|
||||
// if the reason is empty then the transaction completed succesfuly,
|
||||
// if the reason is empty then the transaction completed successfully,
|
||||
// otherwise we rollback the whole response body and cookies and everything lives inside the transaction.Request.
|
||||
t.Complete(err)
|
||||
}
|
||||
|
|
8
http.go
8
http.go
|
@ -697,7 +697,7 @@ type (
|
|||
Path() string
|
||||
// SetPath changes/sets the path for this route
|
||||
SetPath(string)
|
||||
// Middleware returns the slice of Handler([]Handler) registed to this route
|
||||
// Middleware returns the slice of Handler([]Handler) registered to this route
|
||||
Middleware() Middleware
|
||||
// SetMiddleware changes/sets the middleware(handler(s)) for this route
|
||||
SetMiddleware(Middleware)
|
||||
|
@ -817,9 +817,9 @@ func (r *route) hasCors() bool {
|
|||
}
|
||||
|
||||
const (
|
||||
// subdomainIndicator where './' exists in a registed path then it contains subdomain
|
||||
// subdomainIndicator where './' exists in a registered path then it contains subdomain
|
||||
subdomainIndicator = "./"
|
||||
// dynamicSubdomainIndicator where a registed path starts with '*.' then it contains a dynamic subdomain, if subdomain == "*." then its dynamic
|
||||
// dynamicSubdomainIndicator where a registered path starts with '*.' then it contains a dynamic subdomain, if subdomain == "*." then its dynamic
|
||||
dynamicSubdomainIndicator = "*."
|
||||
)
|
||||
|
||||
|
@ -958,7 +958,7 @@ func (mux *serveMux) build() (methodEqual func(string, string) bool) {
|
|||
tree = &muxTree{method: r.method, subdomain: r.subdomain, entry: &muxEntry{}}
|
||||
mux.garden = append(mux.garden, tree)
|
||||
}
|
||||
// I decide that it's better to explicit give subdomain and a path to it than registedPath(mysubdomain./something) now its: subdomain: mysubdomain., path: /something
|
||||
// I decide that it's better to explicit give subdomain and a path to it than registeredPath(mysubdomain./something) now its: subdomain: mysubdomain., path: /something
|
||||
// we have different tree for each of subdomains, now you can use everything you can use with the normal paths ( before you couldn't set /any/*path)
|
||||
if err := tree.entry.add(r.path, r.middleware); err != nil {
|
||||
mux.logger.Panic(err)
|
||||
|
|
75
http_test.go
75
http_test.go
|
@ -293,7 +293,7 @@ type testRoute struct {
|
|||
|
||||
func TestMuxSimple(t *testing.T) {
|
||||
testRoutes := []testRoute{
|
||||
// FOUND - registed
|
||||
// FOUND - registered
|
||||
{"GET", "/test_get", "/test_get", "", "hello, get!", 200, true, nil, nil},
|
||||
{"POST", "/test_post", "/test_post", "", "hello, post!", 200, true, nil, nil},
|
||||
{"PUT", "/test_put", "/test_put", "", "hello, put!", 200, true, nil, nil},
|
||||
|
@ -303,7 +303,7 @@ func TestMuxSimple(t *testing.T) {
|
|||
{"CONNECT", "/test_connect", "/test_connect", "", "hello, connect!", 200, true, nil, nil},
|
||||
{"PATCH", "/test_patch", "/test_patch", "", "hello, patch!", 200, true, nil, nil},
|
||||
{"TRACE", "/test_trace", "/test_trace", "", "hello, trace!", 200, true, nil, nil},
|
||||
// NOT FOUND - not registed
|
||||
// NOT FOUND - not registered
|
||||
{"GET", "/test_get_nofound", "/test_get_nofound", "", "Not Found", 404, false, nil, nil},
|
||||
{"POST", "/test_post_nofound", "/test_post_nofound", "", "Not Found", 404, false, nil, nil},
|
||||
{"PUT", "/test_put_nofound", "/test_put_nofound", "", "Not Found", 404, false, nil, nil},
|
||||
|
@ -519,7 +519,7 @@ func TestMuxCustomErrors(t *testing.T) {
|
|||
notFoundMessage = "Iris custom message for 404 not found"
|
||||
internalServerMessage = "Iris custom message for 500 internal server error"
|
||||
testRoutesCustomErrors = []testRoute{
|
||||
// NOT FOUND CUSTOM ERRORS - not registed
|
||||
// NOT FOUND CUSTOM ERRORS - not registered
|
||||
{"GET", "/test_get_nofound_custom", "/test_get_nofound_custom", "", notFoundMessage, 404, false, nil, nil},
|
||||
{"POST", "/test_post_nofound_custom", "/test_post_nofound_custom", "", notFoundMessage, 404, false, nil, nil},
|
||||
{"PUT", "/test_put_nofound_custom", "/test_put_nofound_custom", "", notFoundMessage, 404, false, nil, nil},
|
||||
|
@ -529,7 +529,7 @@ func TestMuxCustomErrors(t *testing.T) {
|
|||
{"CONNECT", "/test_connect_nofound_custom", "/test_connect_nofound_custom", "", notFoundMessage, 404, false, nil, nil},
|
||||
{"PATCH", "/test_patch_nofound_custom", "/test_patch_nofound_custom", "", notFoundMessage, 404, false, nil, nil},
|
||||
{"TRACE", "/test_trace_nofound_custom", "/test_trace_nofound_custom", "", notFoundMessage, 404, false, nil, nil},
|
||||
// SERVER INTERNAL ERROR 500 PANIC CUSTOM ERRORS - registed
|
||||
// SERVER INTERNAL ERROR 500 PANIC CUSTOM ERRORS - registered
|
||||
{"GET", "/test_get_panic_custom", "/test_get_panic_custom", "", internalServerMessage, 500, true, nil, nil},
|
||||
{"POST", "/test_post_panic_custom", "/test_post_panic_custom", "", internalServerMessage, 500, true, nil, nil},
|
||||
{"PUT", "/test_put_panic_custom", "/test_put_panic_custom", "", internalServerMessage, 500, true, nil, nil},
|
||||
|
@ -618,7 +618,7 @@ func TestMuxAPI(t *testing.T) {
|
|||
}}
|
||||
|
||||
iris.API("/users", testUserAPI{}, h...)
|
||||
// test a simple .Party with compination of .API
|
||||
// test a simple .Party with combination of .API
|
||||
iris.Party("sites/:site").API("/users", testUserAPI{}, h...)
|
||||
|
||||
e := httptest.New(iris.Default, t)
|
||||
|
@ -716,70 +716,6 @@ func TestMuxFireMethodNotAllowed(t *testing.T) {
|
|||
iris.Close()
|
||||
}
|
||||
|
||||
/*
|
||||
var (
|
||||
cacheDuration = 2 * time.Second
|
||||
errCacheTestFailed = errors.New("Expected the main handler to be executed %d times instead of %d.")
|
||||
)
|
||||
|
||||
// ~14secs
|
||||
func runCacheTest(e *httpexpect.Expect, path string, counterPtr *uint32, expectedBodyStr, expectedContentType string) error {
|
||||
e.GET(path).Expect().Status(iris.StatusOK).Body().Equal(expectedBodyStr)
|
||||
time.Sleep(cacheDuration / 5) // lets wait for a while, cache should be saved and ready
|
||||
e.GET(path).Expect().Status(iris.StatusOK).Body().Equal(expectedBodyStr)
|
||||
counter := atomic.LoadUint32(counterPtr)
|
||||
if counter > 1 {
|
||||
// n should be 1 because it doesn't changed after the first call
|
||||
return errCacheTestFailed.Format(1, counter)
|
||||
}
|
||||
time.Sleep(cacheDuration)
|
||||
|
||||
// cache should be cleared now
|
||||
e.GET(path).Expect().Status(iris.StatusOK).ContentType(expectedContentType, "utf-8").Body().Equal(expectedBodyStr)
|
||||
time.Sleep(cacheDuration / 5)
|
||||
// let's call again , the cache should be saved
|
||||
e.GET(path).Expect().Status(iris.StatusOK).ContentType(expectedContentType, "utf-8").Body().Equal(expectedBodyStr)
|
||||
counter = atomic.LoadUint32(counterPtr)
|
||||
if counter != 2 {
|
||||
return errCacheTestFailed.Format(2, counter)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Inside github.com/geekypanda/httpcache are enough, no need to add 10+ seconds of testing here.
|
||||
func TestCache(t *testing.T) {
|
||||
|
||||
iris.ResetDefault()
|
||||
|
||||
expectedBodyStr := "Imagine it as a big message to achieve x20 response performance!"
|
||||
var textCounter, htmlCounter uint32
|
||||
|
||||
iris.Get("/text", iris.Cache(func(ctx *iris.Context) {
|
||||
atomic.AddUint32(&textCounter, 1)
|
||||
ctx.Text(iris.StatusOK, expectedBodyStr)
|
||||
}, cacheDuration))
|
||||
|
||||
iris.Get("/html", iris.Cache(func(ctx *iris.Context) {
|
||||
atomic.AddUint32(&htmlCounter, 1)
|
||||
ctx.HTML(iris.StatusOK, expectedBodyStr)
|
||||
}, cacheDuration))
|
||||
|
||||
e := httptest.New(iris.Default, t)
|
||||
|
||||
// test cache on text/plain
|
||||
if err := runCacheTest(e, "/text", &textCounter, expectedBodyStr, "text/plain"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// text cache on text/html
|
||||
if err := runCacheTest(e, "/html", &htmlCounter, expectedBodyStr, "text/html"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
func TestRedirectHTTPS(t *testing.T) {
|
||||
|
||||
api := iris.New(iris.OptionIsDevelopment(true))
|
||||
|
@ -794,5 +730,4 @@ func TestRedirectHTTPS(t *testing.T) {
|
|||
|
||||
e := httptest.New(api, t)
|
||||
e.GET("/redirect").Expect().Status(iris.StatusOK).Body().Equal(expectedBody)
|
||||
|
||||
}
|
||||
|
|
75
iris.go
75
iris.go
|
@ -335,12 +335,12 @@ func (s *Framework) Set(setters ...OptionSetter) {
|
|||
}
|
||||
}
|
||||
|
||||
// Must panics on error, it panics on registed iris' logger
|
||||
// Must panics on error, it panics on registered iris' logger
|
||||
func Must(err error) {
|
||||
Default.Must(err)
|
||||
}
|
||||
|
||||
// Must panics on error, it panics on registed iris' logger
|
||||
// Must panics on error, it panics on registered iris' logger
|
||||
func (s *Framework) Must(err error) {
|
||||
if err != nil {
|
||||
// s.Logger.Panicf("%s. Trace:\n%s", err, debug.Stack())
|
||||
|
@ -411,7 +411,7 @@ func (s *Framework) Build() {
|
|||
s.mux.setFireMethodNotAllowed(s.Config.FireMethodNotAllowed)
|
||||
|
||||
// prepare the server's handler, we do that check because iris supports
|
||||
// custom routers (you can take the routes registed by iris using iris.Lookups function)
|
||||
// custom routers (you can take the routes registered by iris using iris.Lookups function)
|
||||
if s.Router == nil {
|
||||
// build and get the default mux' handler(*Context)
|
||||
serve := s.mux.BuildHandler()
|
||||
|
@ -437,6 +437,7 @@ func (s *Framework) Build() {
|
|||
ConnState: s.Config.ConnState,
|
||||
Handler: s.Router,
|
||||
Addr: s.Config.VHost,
|
||||
ErrorLog: s.Logger,
|
||||
}
|
||||
if s.Config.TLSNextProto != nil {
|
||||
s.srv.TLSNextProto = s.Config.TLSNextProto
|
||||
|
@ -973,17 +974,17 @@ func (s *Framework) UseGlobalFunc(handlersFn ...HandlerFunc) {
|
|||
s.UseGlobal(convertToHandlers(handlersFn)...)
|
||||
}
|
||||
|
||||
// Lookup returns a registed route by its name
|
||||
// Lookup returns a registered route by its name
|
||||
func Lookup(routeName string) Route {
|
||||
return Default.Lookup(routeName)
|
||||
}
|
||||
|
||||
// Lookups returns all registed routes
|
||||
// Lookups returns all registered routes
|
||||
func Lookups() []Route {
|
||||
return Default.Lookups()
|
||||
}
|
||||
|
||||
// Lookup returns a registed route by its name
|
||||
// Lookup returns a registered route by its name
|
||||
func (s *Framework) Lookup(routeName string) Route {
|
||||
r := s.mux.lookup(routeName)
|
||||
if nil == r {
|
||||
|
@ -992,7 +993,7 @@ func (s *Framework) Lookup(routeName string) Route {
|
|||
return r
|
||||
}
|
||||
|
||||
// Lookups returns all registed routes
|
||||
// Lookups returns all registered routes
|
||||
func (s *Framework) Lookups() (routes []Route) {
|
||||
// silly but...
|
||||
for i := range s.mux.lookups {
|
||||
|
@ -1411,27 +1412,27 @@ func (api *muxAPI) DoneFunc(handlersFn ...HandlerFunc) MuxAPI {
|
|||
|
||||
// Handle registers a route to the server's router
|
||||
// if empty method is passed then registers handler(s) for all methods, same as .Any, but returns nil as result
|
||||
func Handle(method string, registedPath string, handlers ...Handler) RouteNameFunc {
|
||||
return Default.Handle(method, registedPath, handlers...)
|
||||
func Handle(method string, registeredPath string, handlers ...Handler) RouteNameFunc {
|
||||
return Default.Handle(method, registeredPath, handlers...)
|
||||
}
|
||||
|
||||
// HandleFunc registers and returns a route with a method string, path string and a handler
|
||||
// registedPath is the relative url path
|
||||
func HandleFunc(method string, registedPath string, handlersFn ...HandlerFunc) RouteNameFunc {
|
||||
return Default.HandleFunc(method, registedPath, handlersFn...)
|
||||
// registeredPath is the relative url path
|
||||
func HandleFunc(method string, registeredPath string, handlersFn ...HandlerFunc) RouteNameFunc {
|
||||
return Default.HandleFunc(method, registeredPath, handlersFn...)
|
||||
}
|
||||
|
||||
// Handle registers a route to the server's router
|
||||
// if empty method is passed then registers handler(s) for all methods, same as .Any, but returns nil as result
|
||||
func (api *muxAPI) Handle(method string, registedPath string, handlers ...Handler) RouteNameFunc {
|
||||
func (api *muxAPI) Handle(method string, registeredPath string, handlers ...Handler) RouteNameFunc {
|
||||
if method == "" { // then use like it was .Any
|
||||
for _, k := range AllMethods {
|
||||
api.Handle(k, registedPath, handlers...)
|
||||
api.Handle(k, registeredPath, handlers...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
fullpath := api.relativePath + registedPath // for now, keep the last "/" if any, "/xyz/"
|
||||
fullpath := api.relativePath + registeredPath // for now, keep the last "/" if any, "/xyz/"
|
||||
|
||||
middleware := joinMiddleware(api.middleware, handlers)
|
||||
|
||||
|
@ -1450,7 +1451,7 @@ func (api *muxAPI) Handle(method string, registedPath string, handlers ...Handle
|
|||
//: /beta/ then should disable the path correction OR register it like: beta.Get("//")
|
||||
// this is only for the party's roots in order to have expected paths,
|
||||
// as we do with iris.Get("/") which is localhost:8080 as RFC points, not localhost:8080/
|
||||
if api.mux.correctPath && registedPath == slash { // check the given relative path
|
||||
if api.mux.correctPath && registeredPath == slash { // check the given relative path
|
||||
// remove last "/" if any, "/xyz/"
|
||||
if len(path) > 1 { // if it's the root, then keep it*
|
||||
if path[len(path)-1] == slashByte {
|
||||
|
@ -1473,9 +1474,9 @@ func (api *muxAPI) Handle(method string, registedPath string, handlers ...Handle
|
|||
}
|
||||
|
||||
// HandleFunc registers and returns a route with a method string, path string and a handler
|
||||
// registedPath is the relative url path
|
||||
func (api *muxAPI) HandleFunc(method string, registedPath string, handlersFn ...HandlerFunc) RouteNameFunc {
|
||||
return api.Handle(method, registedPath, convertToHandlers(handlersFn)...)
|
||||
// registeredPath is the relative url path
|
||||
func (api *muxAPI) HandleFunc(method string, registeredPath string, handlersFn ...HandlerFunc) RouteNameFunc {
|
||||
return api.Handle(method, registeredPath, convertToHandlers(handlersFn)...)
|
||||
}
|
||||
|
||||
// API converts & registers a custom struct to the router
|
||||
|
@ -1484,7 +1485,7 @@ func (api *muxAPI) HandleFunc(method string, registedPath string, handlersFn ...
|
|||
// second is the custom struct (interface{}) which can be anything that has a *iris.Context as field.
|
||||
// third is the common middlewares, it's optional
|
||||
//
|
||||
// Note that API's routes have their default-name to the full registed path,
|
||||
// Note that API's routes have their default-name to the full registered path,
|
||||
// no need to give a special name for it, because it's not supposed to be used inside your templates.
|
||||
//
|
||||
// Recommend to use when you retrieve data from an external database,
|
||||
|
@ -1501,7 +1502,7 @@ func API(path string, restAPI HandlerAPI, middleware ...HandlerFunc) {
|
|||
// second is the custom struct (interface{}) which can be anything that has a *iris.Context as field.
|
||||
// third is the common middleware, it's optional
|
||||
//
|
||||
// Note that API's routes have their default-name to the full registed path,
|
||||
// Note that API's routes have their default-name to the full registered path,
|
||||
// no need to give a special name for it, because it's not supposed to be used inside your templates.
|
||||
//
|
||||
// Recommend to use when you retrieve data from an external database,
|
||||
|
@ -1509,7 +1510,7 @@ func API(path string, restAPI HandlerAPI, middleware ...HandlerFunc) {
|
|||
//
|
||||
// This is a slow method, if you care about router-performance use the Handle/HandleFunc/Get/Post/Put/Delete/Trace/Options... instead
|
||||
func (api *muxAPI) API(path string, restAPI HandlerAPI, middleware ...HandlerFunc) {
|
||||
// here we need to find the registed methods and convert them to handler funcs
|
||||
// here we need to find the registered methods and convert them to handler funcs
|
||||
// methods are collected by method naming: Get(),GetBy(...), Post(),PostBy(...), Put() and so on
|
||||
if len(path) == 0 {
|
||||
path = "/"
|
||||
|
@ -1572,17 +1573,17 @@ func (api *muxAPI) API(path string, restAPI HandlerAPI, middleware ...HandlerFun
|
|||
}
|
||||
methodFuncType := methodFunc.Type()
|
||||
numInLen := methodFuncType.NumIn() // how much data we should receive from the request
|
||||
registedPath := path
|
||||
registeredPath := path
|
||||
|
||||
for i := 1; i < numInLen; i++ { // from 1 because the first is the 'object'
|
||||
if registedPath[len(registedPath)-1] == slashByte {
|
||||
registedPath += ":" + string(paramPrefix) + strconv.Itoa(i)
|
||||
if registeredPath[len(registeredPath)-1] == slashByte {
|
||||
registeredPath += ":" + string(paramPrefix) + strconv.Itoa(i)
|
||||
} else {
|
||||
registedPath += "/:" + string(paramPrefix) + strconv.Itoa(i)
|
||||
registeredPath += "/:" + string(paramPrefix) + strconv.Itoa(i)
|
||||
}
|
||||
}
|
||||
|
||||
func(registedPath string, typ reflect.Type, contextField reflect.StructField, methodFunc reflect.Value, paramsLen int, method string) {
|
||||
func(registeredPath string, typ reflect.Type, contextField reflect.StructField, methodFunc reflect.Value, paramsLen int, method string) {
|
||||
var handlersFn []HandlerFunc
|
||||
|
||||
handlersFn = append(handlersFn, middleware...)
|
||||
|
@ -1604,8 +1605,8 @@ func (api *muxAPI) API(path string, restAPI HandlerAPI, middleware ...HandlerFun
|
|||
methodFunc.Call(args)
|
||||
})
|
||||
// register route
|
||||
api.HandleFunc(method, registedPath, handlersFn...)
|
||||
}(registedPath, typ, contextField, methodFunc, numInLen-1, methodName)
|
||||
api.HandleFunc(method, registeredPath, handlersFn...)
|
||||
}(registeredPath, typ, contextField, methodFunc, numInLen-1, methodName)
|
||||
|
||||
}
|
||||
|
||||
|
@ -1659,8 +1660,8 @@ func Trace(path string, handlersFn ...HandlerFunc) RouteNameFunc {
|
|||
}
|
||||
|
||||
// Any registers a route for ALL of the http methods (Get,Post,Put,Head,Patch,Options,Connect,Delete)
|
||||
func Any(registedPath string, handlersFn ...HandlerFunc) {
|
||||
Default.Any(registedPath, handlersFn...)
|
||||
func Any(registeredPath string, handlersFn ...HandlerFunc) {
|
||||
Default.Any(registeredPath, handlersFn...)
|
||||
|
||||
}
|
||||
|
||||
|
@ -1710,9 +1711,9 @@ func (api *muxAPI) Trace(path string, handlersFn ...HandlerFunc) RouteNameFunc {
|
|||
}
|
||||
|
||||
// Any registers a route for ALL of the http methods (Get,Post,Put,Head,Patch,Options,Connect,Delete)
|
||||
func (api *muxAPI) Any(registedPath string, handlersFn ...HandlerFunc) {
|
||||
func (api *muxAPI) Any(registeredPath string, handlersFn ...HandlerFunc) {
|
||||
for _, k := range AllMethods {
|
||||
api.HandleFunc(k, registedPath, handlersFn...)
|
||||
api.HandleFunc(k, registeredPath, handlersFn...)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1790,7 +1791,7 @@ func (api *muxAPI) StaticContent(reqPath string, cType string, content []byte) R
|
|||
return api.registerResourceRoute(reqPath, h)
|
||||
}
|
||||
|
||||
// StaticEmbedded used when files are distrubuted inside the app executable, using go-bindata mostly
|
||||
// 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(second parameter) will be served to, for example "/static"
|
||||
// Second parameter is the (virtual) directory path, for example "./assets"
|
||||
// Third parameter is the Asset function
|
||||
|
@ -1802,7 +1803,7 @@ func StaticEmbedded(requestPath string, vdir string, assetFn func(name string) (
|
|||
return Default.StaticEmbedded(requestPath, vdir, assetFn, namesFn)
|
||||
}
|
||||
|
||||
// StaticEmbedded used when files are distrubuted inside the app executable, using go-bindata mostly
|
||||
// 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"
|
||||
// Second parameter is the (virtual) directory path, for example "./assets"
|
||||
// Third parameter is the Asset function
|
||||
|
@ -1899,7 +1900,7 @@ func (api *muxAPI) StaticEmbedded(requestPath string, vdir string, assetFn func(
|
|||
// you can declare your own path if you have more than one favicon (desktop, mobile and so on)
|
||||
//
|
||||
// this func will add a route for you which will static serve the /yuorpath/yourfile.ico to the /yourfile.ico (nothing special that you can't handle by yourself)
|
||||
// Note that you have to call it on every favicon you have to serve automatically (dekstop, mobile and so on)
|
||||
// Note that you have to call it on every favicon you have to serve automatically (desktop, mobile and so on)
|
||||
//
|
||||
// panics on error
|
||||
func Favicon(favPath string, requestPath ...string) RouteNameFunc {
|
||||
|
@ -1913,7 +1914,7 @@ func Favicon(favPath string, requestPath ...string) RouteNameFunc {
|
|||
// you can declare your own path if you have more than one favicon (desktop, mobile and so on)
|
||||
//
|
||||
// this func will add a route for you which will static serve the /yuorpath/yourfile.ico to the /yourfile.ico (nothing special that you can't handle by yourself)
|
||||
// Note that you have to call it on every favicon you have to serve automatically (dekstop, mobile and so on)
|
||||
// Note that you have to call it on every favicon you have to serve automatically (desktop, mobile and so on)
|
||||
//
|
||||
// panics on error
|
||||
func (api *muxAPI) Favicon(favPath string, requestPath ...string) RouteNameFunc {
|
||||
|
|
10
plugin.go
10
plugin.go
|
@ -1,5 +1,7 @@
|
|||
package iris
|
||||
|
||||
///TODO: Be ready for go v1.8 in order to accomplish my first idea.
|
||||
|
||||
import (
|
||||
"log"
|
||||
"sync"
|
||||
|
@ -13,8 +15,8 @@ var (
|
|||
errPluginAlreadyExists = errors.New("Cannot use the same plugin again, '%s[%s]' is already exists")
|
||||
// errPluginActivate returns an error with message: 'While trying to activate plugin '+plugin name'. Trace: +specific error'
|
||||
errPluginActivate = errors.New("While trying to activate plugin '%s'. Trace: %s")
|
||||
// errPluginRemoveNoPlugins returns an error with message: 'No plugins are registed yet, you cannot remove a plugin from an empty list!'
|
||||
errPluginRemoveNoPlugins = errors.New("No plugins are registed yet, you cannot remove a plugin from an empty list!")
|
||||
// errPluginRemoveNoPlugins returns an error with message: 'No plugins are registered yet, you cannot remove a plugin from an empty list!'
|
||||
errPluginRemoveNoPlugins = errors.New("No plugins are registered yet, you cannot remove a plugin from an empty list!")
|
||||
// errPluginRemoveEmptyName returns an error with message: 'Plugin with an empty name cannot be removed'
|
||||
errPluginRemoveEmptyName = errors.New("Plugin with an empty name cannot be removed")
|
||||
// errPluginRemoveNotFound returns an error with message: 'Cannot remove a plugin which doesn't exists'
|
||||
|
@ -248,7 +250,7 @@ func (d *pluginDownloadManager) Install(remoteFileZip string, targetDirectory st
|
|||
return fs.Install(remoteFileZip, targetDirectory, true)
|
||||
}
|
||||
|
||||
// pluginContainer is the base container of all Iris, registed plugins
|
||||
// pluginContainer is the base container of all Iris, registered plugins
|
||||
type pluginContainer struct {
|
||||
activatedPlugins []Plugin
|
||||
customEvents map[string][]func()
|
||||
|
@ -379,7 +381,7 @@ func (p *pluginContainer) GetDownloader() PluginDownloadManager {
|
|||
return p.downloader
|
||||
}
|
||||
|
||||
// Printf sends plain text to any registed logger (future), some plugins maybe want use this method
|
||||
// Printf sends plain text to any registered logger (future), some plugins maybe want use this method
|
||||
// maybe at the future I change it, instead of sync even-driven to async channels...
|
||||
func (p *pluginContainer) Printf(format string, a ...interface{}) {
|
||||
if p.logger != nil {
|
||||
|
|
|
@ -125,7 +125,7 @@ func (t testPluginActivationType) Activate(p iris.PluginContainer) error {
|
|||
// if an error happened then all of them are not activated/added to the plugin container
|
||||
func AddPluginTo(t *testing.T, plugins iris.PluginContainer, plugin iris.Plugin, expectingCount int) {
|
||||
plugins.Add(plugin)
|
||||
if plugins.Len() != expectingCount { // 2 because it registeres a second plugin also
|
||||
if plugins.Len() != expectingCount { // 2 because it registers a second plugin also
|
||||
t.Fatalf("Expected activated plugins to be: %d but we got: %d", expectingCount, plugins.Len())
|
||||
}
|
||||
}
|
||||
|
@ -165,7 +165,7 @@ func TestPluginEvents(t *testing.T) {
|
|||
myplugin := &testPluginEx{}
|
||||
plugins.Add(myplugin)
|
||||
if plugins.Len() != 4 {
|
||||
t.Fatalf("Expected: %d plugins to be registed but we got: %d", 4, plugins.Len())
|
||||
t.Fatalf("Expected: %d plugins to be registered but we got: %d", 4, plugins.Len())
|
||||
}
|
||||
desc := plugins.GetDescription(myplugin)
|
||||
if desc != testPluginExDescription {
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package iris_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/kataras/iris"
|
||||
"github.com/kataras/iris/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// most tests lives inside context_test.go:Transactions, there lives the response writer's full and coblex tests
|
||||
|
@ -63,3 +65,35 @@ func TestResponseWriterToRecorderMiddleware(t *testing.T) {
|
|||
|
||||
e.GET("/").Expect().Status(iris.StatusForbidden).Body().Equal(beforeFlushBody)
|
||||
}
|
||||
|
||||
func ExampleResponseWriter_WriteHeader() {
|
||||
// func TestResponseWriterMultipleWriteHeader(t *testing.T) {
|
||||
iris.ResetDefault()
|
||||
iris.Default.Set(iris.OptionDisableBanner(true))
|
||||
|
||||
expectedOutput := "Hey"
|
||||
iris.Get("/", func(ctx *iris.Context) {
|
||||
|
||||
// here
|
||||
for i := 0; i < 10; i++ {
|
||||
ctx.ResponseWriter.WriteHeader(iris.StatusOK)
|
||||
}
|
||||
|
||||
ctx.Writef(expectedOutput)
|
||||
|
||||
// here
|
||||
fmt.Println(expectedOutput)
|
||||
|
||||
// here
|
||||
for i := 0; i < 10; i++ {
|
||||
ctx.SetStatusCode(iris.StatusOK)
|
||||
}
|
||||
})
|
||||
|
||||
e := httptest.New(iris.Default, nil)
|
||||
e.GET("/").Expect().Status(iris.StatusOK).Body().Equal(expectedOutput)
|
||||
// here it shouldn't log an error that status code write multiple times (by the net/http package.)
|
||||
|
||||
// Output:
|
||||
// Hey
|
||||
}
|
||||
|
|
|
@ -124,7 +124,7 @@ func (tsf TransactionScopeFunc) EndTransaction(maybeErr TransactionErrResult, ct
|
|||
return tsf(maybeErr, ctx)
|
||||
}
|
||||
|
||||
// TransientTransactionScope explaination:
|
||||
// TransientTransactionScope explanation:
|
||||
//
|
||||
// independent 'silent' scope, if transaction fails (if transaction.IsFailure() == true)
|
||||
// then its response is not written to the real context no error is provided to the user.
|
||||
|
@ -136,7 +136,7 @@ var TransientTransactionScope = TransactionScopeFunc(func(maybeErr TransactionEr
|
|||
return true
|
||||
})
|
||||
|
||||
// RequestTransactionScope explaination:
|
||||
// RequestTransactionScope explanation:
|
||||
//
|
||||
// if scope fails (if transaction.IsFailure() == true)
|
||||
// then the rest of the context's response (transaction or normal flow)
|
||||
|
|
Loading…
Reference in New Issue
Block a user