mirror of
https://github.com/kataras/iris.git
synced 2026-01-08 12:31:58 +00:00
(#1554) Add support for all common compressions (write and read)
- Remove the context.Context interface and export the *context, the iris.Context now points to the pointer\nSupport compression and rate limiting in the FileServer\nBit of code organisation Former-commit-id: ad1c61bf968059510c6be9e7f2cceec7da70ba17
This commit is contained in:
@@ -116,7 +116,7 @@ func (repo *repository) register(route *Route, rule RouteRegisterRule) (*Route,
|
||||
return route, nil
|
||||
}
|
||||
|
||||
var defaultOverlapFilter = func(ctx context.Context) bool {
|
||||
var defaultOverlapFilter = func(ctx *context.Context) bool {
|
||||
if ctx.IsStopped() {
|
||||
// It's stopped and the response can be overridden by a new handler.
|
||||
rs, ok := ctx.ResponseWriter().(context.ResponseWriterReseter)
|
||||
@@ -131,7 +131,7 @@ func overlapRoute(r *Route, next *Route) {
|
||||
next.BuildHandlers()
|
||||
nextHandlers := next.Handlers[0:]
|
||||
|
||||
decisionHandler := func(ctx context.Context) {
|
||||
decisionHandler := func(ctx *context.Context) {
|
||||
ctx.Next()
|
||||
|
||||
if !defaultOverlapFilter(ctx) {
|
||||
@@ -925,7 +925,7 @@ func (api *APIBuilder) registerResourceRoute(reqPath string, h context.Handler)
|
||||
// Returns the GET *Route.
|
||||
func (api *APIBuilder) StaticContent(reqPath string, cType string, content []byte) *Route {
|
||||
modtime := time.Now()
|
||||
h := func(ctx context.Context) {
|
||||
h := func(ctx *context.Context) {
|
||||
ctx.ContentType(cType)
|
||||
if _, err := ctx.WriteWithExpiration(content, modtime); err != nil {
|
||||
ctx.StatusCode(http.StatusInternalServerError)
|
||||
@@ -975,7 +975,7 @@ func (api *APIBuilder) Favicon(favPath string, requestPath ...string) *Route {
|
||||
|
||||
modtime := time.Now()
|
||||
cType := TypeByFilename(favPath)
|
||||
h := func(ctx context.Context) {
|
||||
h := func(ctx *context.Context) {
|
||||
ctx.ContentType(cType)
|
||||
if _, err := ctx.WriteWithExpiration(cacheFav, modtime); err != nil {
|
||||
ctx.StatusCode(http.StatusInternalServerError)
|
||||
@@ -1030,7 +1030,7 @@ func (api *APIBuilder) OnAnyErrorCode(handlers ...context.Handler) (routes []*Ro
|
||||
//
|
||||
// Examples: https://github.com/kataras/iris/tree/master/_examples/view
|
||||
func (api *APIBuilder) Layout(tmplLayoutFile string) Party {
|
||||
api.Use(func(ctx context.Context) {
|
||||
api.Use(func(ctx *context.Context) {
|
||||
ctx.ViewLayout(tmplLayoutFile)
|
||||
ctx.Next()
|
||||
})
|
||||
|
||||
@@ -73,7 +73,7 @@ func genPaths(routesLength, minCharLength, maxCharLength int) []string {
|
||||
func BenchmarkAPIBuilder(b *testing.B) {
|
||||
rand.Seed(time.Now().Unix())
|
||||
|
||||
noOpHandler := func(ctx context.Context) {}
|
||||
noOpHandler := func(ctx *context.Context) {}
|
||||
handlersPerRoute := make(context.Handlers, 12)
|
||||
for i := 0; i < cap(handlersPerRoute); i++ {
|
||||
handlersPerRoute[i] = noOpHandler
|
||||
|
||||
@@ -42,9 +42,9 @@ func (api *APIContainer) PartyFunc(relativePath string, fn func(*APIContainer))
|
||||
// Container.GetErrorHandler = func(ctx iris.Context) hero.ErrorHandler { return errorHandler }
|
||||
//
|
||||
// See `RegisterDependency`, `Use`, `Done` and `Handle` too.
|
||||
func (api *APIContainer) OnError(errorHandler func(context.Context, error)) {
|
||||
func (api *APIContainer) OnError(errorHandler func(*context.Context, error)) {
|
||||
errHandler := hero.ErrorHandlerFunc(errorHandler)
|
||||
api.Container.GetErrorHandler = func(ctx context.Context) hero.ErrorHandler {
|
||||
api.Container.GetErrorHandler = func(ctx *context.Context) hero.ErrorHandler {
|
||||
return errHandler
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"html"
|
||||
"html/template"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
@@ -22,7 +21,7 @@ import (
|
||||
const indexName = "/index.html"
|
||||
|
||||
// DirListFunc is the function signature for customizing directory and file listing.
|
||||
type DirListFunc func(ctx context.Context, dirName string, dir http.File) error
|
||||
type DirListFunc func(ctx *context.Context, dirOptions DirOptions, dirName string, dir http.File) error
|
||||
|
||||
// Attachments options for files to be downloaded and saved locally by the client.
|
||||
// See `DirOptions`.
|
||||
@@ -46,7 +45,7 @@ type DirOptions struct {
|
||||
// if end developer does not managed to handle it by hand.
|
||||
IndexName string
|
||||
// When files should served under compression.
|
||||
Gzip bool
|
||||
Compress bool
|
||||
|
||||
// List the files inside the current requested directory if `IndexName` not found.
|
||||
ShowList bool
|
||||
@@ -56,8 +55,6 @@ type DirOptions struct {
|
||||
DirList DirListFunc
|
||||
|
||||
// Files downloaded and saved locally.
|
||||
// Gzip option MUST be false in order for this to work.
|
||||
// TODO(@kataras): find a way to make it work.
|
||||
Attachments Attachments
|
||||
|
||||
// When embedded.
|
||||
@@ -66,7 +63,7 @@ type DirOptions struct {
|
||||
AssetNames func() []string // called once.
|
||||
|
||||
// Optional validator that loops through each requested resource.
|
||||
AssetValidator func(ctx context.Context, name string) bool
|
||||
AssetValidator func(ctx *context.Context, name string) bool
|
||||
}
|
||||
|
||||
func getDirOptions(opts ...DirOptions) (options DirOptions) {
|
||||
@@ -80,6 +77,12 @@ func getDirOptions(opts ...DirOptions) (options DirOptions) {
|
||||
options.IndexName = prefix(options.IndexName, "/")
|
||||
}
|
||||
|
||||
if !options.Attachments.Enable {
|
||||
// make sure rate limiting is not used when attachments are not.
|
||||
options.Attachments.Limit = 0
|
||||
options.Attachments.Burst = 0
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -300,17 +303,16 @@ func FileServer(directory string, opts ...DirOptions) context.Handler {
|
||||
// panic("FileServer: system directory: " + directory + " does not exist")
|
||||
// }
|
||||
|
||||
plainStatusCode := func(ctx context.Context, statusCode int) {
|
||||
if writer, ok := ctx.ResponseWriter().(*context.GzipResponseWriter); ok && writer != nil {
|
||||
writer.ResetBody()
|
||||
writer.Disable()
|
||||
plainStatusCode := func(ctx *context.Context, statusCode int) {
|
||||
if writer, ok := ctx.ResponseWriter().(*context.CompressResponseWriter); ok {
|
||||
writer.Disabled = true
|
||||
}
|
||||
ctx.StatusCode(statusCode)
|
||||
}
|
||||
|
||||
dirList := options.DirList
|
||||
if dirList == nil {
|
||||
dirList = func(ctx context.Context, dirName string, dir http.File) error {
|
||||
dirList = func(ctx *context.Context, dirOptions DirOptions, dirName string, dir http.File) error {
|
||||
dirs, err := dir.Readdir(-1)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -323,6 +325,7 @@ func FileServer(directory string, opts ...DirOptions) context.Handler {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, d := range dirs {
|
||||
name := d.Name()
|
||||
if d.IsDir() {
|
||||
@@ -341,10 +344,14 @@ func FileServer(directory string, opts ...DirOptions) context.Handler {
|
||||
Path: upath,
|
||||
} // edit here to redirect correctly, standard library misses that.
|
||||
|
||||
downloadAttr := ""
|
||||
if dirOptions.Attachments.Enable && !d.IsDir() {
|
||||
downloadAttr = " download" // fixes chrome Resource interpreted, other browsers will just ignore this <a> attribute.
|
||||
}
|
||||
// name may contain '?' or '#', which must be escaped to remain
|
||||
// part of the URL path, and not indicate the start of a query
|
||||
// string or fragment.
|
||||
_, err = ctx.Writef("<a href=\"%s\">%s</a>\n", url.String(), html.EscapeString(name))
|
||||
_, err = ctx.Writef("<a href=\"%s\"%s>%s</a>\n", url.String(), downloadAttr, html.EscapeString(name))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -354,17 +361,10 @@ func FileServer(directory string, opts ...DirOptions) context.Handler {
|
||||
}
|
||||
}
|
||||
|
||||
h := func(ctx context.Context) {
|
||||
h := func(ctx *context.Context) {
|
||||
name := prefix(ctx.Request().URL.Path, "/")
|
||||
ctx.Request().URL.Path = name
|
||||
|
||||
gzip := options.Gzip
|
||||
if !gzip {
|
||||
// if false then check if the dev did something like `ctx.Gzip(true)`.
|
||||
_, gzip = ctx.ResponseWriter().(*context.GzipResponseWriter)
|
||||
}
|
||||
// ctx.Gzip(options.Gzip)
|
||||
|
||||
f, err := fs.Open(name)
|
||||
if err != nil {
|
||||
plainStatusCode(ctx, http.StatusNotFound)
|
||||
@@ -378,6 +378,7 @@ func FileServer(directory string, opts ...DirOptions) context.Handler {
|
||||
return
|
||||
}
|
||||
|
||||
indexFound := false
|
||||
// use contents of index.html for directory, if present
|
||||
if info.IsDir() && options.IndexName != "" {
|
||||
// Note that, in contrast of the default net/http mechanism;
|
||||
@@ -397,6 +398,7 @@ func FileServer(directory string, opts ...DirOptions) context.Handler {
|
||||
if err == nil {
|
||||
info = infoIndex
|
||||
f = fIndex
|
||||
indexFound = true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -414,7 +416,7 @@ func FileServer(directory string, opts ...DirOptions) context.Handler {
|
||||
return
|
||||
}
|
||||
ctx.SetLastModified(info.ModTime())
|
||||
err = dirList(ctx, info.Name(), f)
|
||||
err = dirList(ctx, options, info.Name(), f)
|
||||
if err != nil {
|
||||
ctx.Application().Logger().Errorf("FileServer: dirList: %v", err)
|
||||
plainStatusCode(ctx, http.StatusInternalServerError)
|
||||
@@ -451,32 +453,10 @@ func FileServer(directory string, opts ...DirOptions) context.Handler {
|
||||
// and the binary data inside "f".
|
||||
detectOrWriteContentType(ctx, info.Name(), f)
|
||||
|
||||
if gzip {
|
||||
// set the last modified as "serveContent" does.
|
||||
ctx.SetLastModified(info.ModTime())
|
||||
|
||||
// write the file to the response writer.
|
||||
contents, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
ctx.Application().Logger().Debugf("err reading file: %v", err)
|
||||
plainStatusCode(ctx, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Use `WriteNow` instead of `Write`
|
||||
// because we need to know the compressed written size before
|
||||
// the `FlushResponse`.
|
||||
_, err = ctx.GzipResponseWriter().Write(contents)
|
||||
if err != nil {
|
||||
ctx.Application().Logger().Debugf("short write: %v", err)
|
||||
plainStatusCode(ctx, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if options.Attachments.Enable {
|
||||
// if not index file and attachments should be force-sent:
|
||||
if !indexFound && options.Attachments.Enable {
|
||||
destName := info.Name()
|
||||
// diposition := "attachment"
|
||||
if nameFunc := options.Attachments.NameFunc; nameFunc != nil {
|
||||
destName = nameFunc(destName)
|
||||
}
|
||||
@@ -484,6 +464,14 @@ func FileServer(directory string, opts ...DirOptions) context.Handler {
|
||||
ctx.ResponseWriter().Header().Set(context.ContentDispositionHeaderKey, "attachment;filename="+destName)
|
||||
}
|
||||
|
||||
ctx.Compress(options.Compress)
|
||||
// if gzip {
|
||||
// ctx.Compress(true)
|
||||
// context.AddCompressHeaders(ctx.ResponseWriter().Header())
|
||||
// // to not write the content-length( see http.serveContent):
|
||||
// // ctx.ResponseWriter().Header().Set(context.ContentEncodingHeaderKey, context.GzipHeaderValue)
|
||||
// }
|
||||
|
||||
// If limit is 0 then same as ServeContent.
|
||||
ctx.ServeContentWithRate(f, info.Name(), info.ModTime(), options.Attachments.Limit, options.Attachments.Burst)
|
||||
if serveCode := ctx.GetStatusCode(); context.StatusCodeNotSuccessful(serveCode) {
|
||||
@@ -520,7 +508,7 @@ func StripPrefix(prefix string, h context.Handler) context.Handler {
|
||||
}
|
||||
canonicalPrefix = toWebPath(canonicalPrefix)
|
||||
|
||||
return func(ctx context.Context) {
|
||||
return func(ctx *context.Context) {
|
||||
if p := strings.TrimPrefix(ctx.Request().URL.Path, canonicalPrefix); len(p) < len(ctx.Request().URL.Path) {
|
||||
ctx.Request().URL.Path = p
|
||||
h(ctx)
|
||||
@@ -551,7 +539,7 @@ func Abs(path string) string {
|
||||
// The algorithm uses at most sniffLen bytes to make its decision.
|
||||
const sniffLen = 512
|
||||
|
||||
func detectOrWriteContentType(ctx context.Context, name string, content io.ReadSeeker) (string, error) {
|
||||
func detectOrWriteContentType(ctx *context.Context, name string, content io.ReadSeeker) (string, error) {
|
||||
// If Content-Type isn't set, use the file's extension to find it, but
|
||||
// if the Content-Type is unset explicitly, do not sniff the type.
|
||||
ctypes, haveType := ctx.ResponseWriter().Header()["Content-Type"]
|
||||
@@ -580,7 +568,7 @@ func detectOrWriteContentType(ctx context.Context, name string, content io.ReadS
|
||||
|
||||
// localRedirect gives a Moved Permanently response.
|
||||
// It does not convert relative paths to absolute paths like Redirect does.
|
||||
func localRedirect(ctx context.Context, newPath string) {
|
||||
func localRedirect(ctx *context.Context, newPath string) {
|
||||
if q := ctx.Request().URL.RawQuery; q != "" {
|
||||
newPath += "?" + q
|
||||
}
|
||||
@@ -619,7 +607,7 @@ func DirListRich(opts ...DirListRichOptions) DirListFunc {
|
||||
options.Tmpl = DirListRichTemplate
|
||||
}
|
||||
|
||||
return func(ctx context.Context, dirName string, dir http.File) error {
|
||||
return func(ctx *context.Context, dirOptions DirOptions, dirName string, dir http.File) error {
|
||||
dirs, err := dir.Readdir(-1)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -655,12 +643,14 @@ func DirListRich(opts ...DirListRichOptions) DirListFunc {
|
||||
|
||||
url := url.URL{Path: upath}
|
||||
|
||||
shouldDownload := dirOptions.Attachments.Enable && !d.IsDir()
|
||||
pageData.Files = append(pageData.Files, fileInfoData{
|
||||
Info: d,
|
||||
ModTime: d.ModTime().UTC().Format(http.TimeFormat),
|
||||
Path: url.String(),
|
||||
RelPath: path.Join(ctx.Path(), name),
|
||||
Name: html.EscapeString(name),
|
||||
Info: d,
|
||||
ModTime: d.ModTime().UTC().Format(http.TimeFormat),
|
||||
Path: url.String(),
|
||||
RelPath: path.Join(ctx.Path(), name),
|
||||
Name: html.EscapeString(name),
|
||||
Download: shouldDownload,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -679,11 +669,12 @@ type (
|
||||
}
|
||||
|
||||
fileInfoData struct {
|
||||
Info os.FileInfo
|
||||
ModTime string // format-ed time.
|
||||
Path string // the request path.
|
||||
RelPath string // file path without the system directory itself (we are not exposing it to the user).
|
||||
Name string // the html-escaped name.
|
||||
Info os.FileInfo
|
||||
ModTime string // format-ed time.
|
||||
Path string // the request path.
|
||||
RelPath string // file path without the system directory itself (we are not exposing it to the user).
|
||||
Name string // the html-escaped name.
|
||||
Download bool // the file should be downloaded (attachment instead of inline view).
|
||||
}
|
||||
)
|
||||
|
||||
@@ -786,7 +777,11 @@ var DirListRichTemplate = template.Must(template.New("dirlist").
|
||||
{{ range $idx, $file := .Files }}
|
||||
<tr>
|
||||
<td>{{ $idx }}</td>
|
||||
<td><a href="{{ $file.Path }}" title="{{ $file.ModTime }}">{{ $file.Name }}</a></td>
|
||||
{{ if $file.Download }}
|
||||
<td><a href="{{ $file.Path }}" title="{{ $file.ModTime }}" download>{{ $file.Name }}</a></td>
|
||||
{{ else }}
|
||||
<td><a href="{{ $file.Path }}" title="{{ $file.ModTime }}">{{ $file.Name }}</a></td>
|
||||
{{ end }}
|
||||
{{ if $file.Info.IsDir }}
|
||||
<td>Dir</td>
|
||||
{{ else }}
|
||||
|
||||
@@ -25,11 +25,11 @@ type (
|
||||
HTTPErrorHandler
|
||||
|
||||
// HandleRequest should handle the request based on the Context.
|
||||
HandleRequest(ctx context.Context)
|
||||
HandleRequest(ctx *context.Context)
|
||||
// Build should builds the handler, it's being called on router's BuildRouter.
|
||||
Build(provider RoutesProvider) error
|
||||
// RouteExists reports whether a particular route exists.
|
||||
RouteExists(ctx context.Context, method, path string) bool
|
||||
RouteExists(ctx *context.Context, method, path string) bool
|
||||
}
|
||||
|
||||
// HTTPErrorHandler should contain a method `FireErrorCode` which
|
||||
@@ -37,7 +37,7 @@ type (
|
||||
HTTPErrorHandler interface {
|
||||
// FireErrorCode should send an error response to the client based
|
||||
// on the given context's response status code.
|
||||
FireErrorCode(ctx context.Context)
|
||||
FireErrorCode(ctx *context.Context)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -294,7 +294,7 @@ func bindMultiParamTypesHandler(r *Route) {
|
||||
currentStatusCode = http.StatusOK
|
||||
}
|
||||
|
||||
decisionHandler := func(ctx context.Context) {
|
||||
decisionHandler := func(ctx *context.Context) {
|
||||
// println("core/router/handler.go: decision handler; " + ctx.Path() + " route.Name: " + r.Name + " vs context's " + ctx.GetCurrentRoute().Name())
|
||||
currentRoute := ctx.GetCurrentRoute()
|
||||
|
||||
@@ -318,7 +318,7 @@ func bindMultiParamTypesHandler(r *Route) {
|
||||
r.topLink.beginHandlers = append(context.Handlers{decisionHandler}, r.topLink.beginHandlers...)
|
||||
}
|
||||
|
||||
func (h *routerHandler) canHandleSubdomain(ctx context.Context, subdomain string) bool {
|
||||
func (h *routerHandler) canHandleSubdomain(ctx *context.Context, subdomain string) bool {
|
||||
if subdomain == "" {
|
||||
return true
|
||||
}
|
||||
@@ -356,7 +356,7 @@ func (h *routerHandler) canHandleSubdomain(ctx context.Context, subdomain string
|
||||
return true
|
||||
}
|
||||
|
||||
func (h *routerHandler) HandleRequest(ctx context.Context) {
|
||||
func (h *routerHandler) HandleRequest(ctx *context.Context) {
|
||||
method := ctx.Method()
|
||||
path := ctx.Path()
|
||||
config := h.config // ctx.Application().GetConfigurationReadOnly()
|
||||
@@ -445,18 +445,18 @@ func statusCodeSuccessful(statusCode int) bool {
|
||||
|
||||
// FireErrorCode handles the response's error response.
|
||||
// If `Configuration.ResetOnFireErrorCode()` is true
|
||||
// and the response writer was a recorder or a gzip writer one
|
||||
// and the response writer was a recorder one
|
||||
// then it will try to reset the headers and the body before calling the
|
||||
// registered (or default) error handler for that error code set by
|
||||
// `ctx.StatusCode` method.
|
||||
func (h *routerHandler) FireErrorCode(ctx context.Context) {
|
||||
func (h *routerHandler) FireErrorCode(ctx *context.Context) {
|
||||
// On common response writer, always check
|
||||
// if we can't reset the body and the body has been filled
|
||||
// which means that the status code already sent,
|
||||
// then do not fire this custom error code,
|
||||
// rel: context/context.go#EndRequest.
|
||||
//
|
||||
// Note that, this is set to 0 on recorder and gzip writer because they cache the response,
|
||||
// Note that, this is set to 0 on recorder because it holds the response before sent,
|
||||
// so we check their len(Body()) instead, look below.
|
||||
if ctx.ResponseWriter().Written() > 0 {
|
||||
return
|
||||
@@ -473,21 +473,17 @@ func (h *routerHandler) FireErrorCode(ctx context.Context) {
|
||||
// reset if previous content and it's recorder, keep the status code.
|
||||
w.ClearHeaders()
|
||||
w.ResetBody()
|
||||
} else if w, ok := ctx.ResponseWriter().(*context.GzipResponseWriter); ok {
|
||||
} else if w, ok := ctx.ResponseWriter().(*context.CompressResponseWriter); ok {
|
||||
// reset and disable the gzip in order to be an expected form of http error result
|
||||
w.ResetBody()
|
||||
w.Disable()
|
||||
w.Disabled = true
|
||||
}
|
||||
} else {
|
||||
// check if a body already set (the error response is handled by the handler itself, see `Context.EndRequest`)
|
||||
// check if a body already set (the error response is handled by the handler itself,
|
||||
// see `Context.EndRequest`)
|
||||
if w, ok := ctx.IsRecording(); ok {
|
||||
if len(w.Body()) > 0 {
|
||||
return
|
||||
}
|
||||
} else if w, ok := ctx.ResponseWriter().(*context.GzipResponseWriter); ok {
|
||||
if len(w.Body()) > 0 {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -526,7 +522,7 @@ func (h *routerHandler) FireErrorCode(ctx context.Context) {
|
||||
// because may the user want to add a fallback error code
|
||||
// i.e
|
||||
// users := app.Party("/users")
|
||||
// users.Done(func(ctx context.Context){ if ctx.StatusCode() == 400 { /* custom error code for /users */ }})
|
||||
// users.Done(func(ctx *context.Context){ if ctx.StatusCode() == 400 { /* custom error code for /users */ }})
|
||||
|
||||
// use .HandlerIndex
|
||||
// that sets the current handler index to zero
|
||||
@@ -556,7 +552,7 @@ func (h *routerHandler) FireErrorCode(ctx context.Context) {
|
||||
ctx.WriteString(context.StatusText(statusCode))
|
||||
}
|
||||
|
||||
func (h *routerHandler) subdomainAndPathAndMethodExists(ctx context.Context, t *trie, method, path string) bool {
|
||||
func (h *routerHandler) subdomainAndPathAndMethodExists(ctx *context.Context, t *trie, method, path string) bool {
|
||||
if method != "" && method != t.method {
|
||||
return false
|
||||
}
|
||||
@@ -599,7 +595,7 @@ func (h *routerHandler) subdomainAndPathAndMethodExists(ctx context.Context, t *
|
||||
|
||||
// RouteExists reports whether a particular route exists
|
||||
// It will search from the current subdomain of context's host, if not inside the root domain.
|
||||
func (h *routerHandler) RouteExists(ctx context.Context, method, path string) bool {
|
||||
func (h *routerHandler) RouteExists(ctx *context.Context, method, path string) bool {
|
||||
for i := range h.trees {
|
||||
t := h.trees[i]
|
||||
if h.subdomainAndPathAndMethodExists(ctx, t, method, path) {
|
||||
|
||||
@@ -72,7 +72,7 @@ func (e ExecutionOptions) buildHandler(h context.Handler) context.Handler {
|
||||
return h
|
||||
}
|
||||
|
||||
return func(ctx context.Context) {
|
||||
return func(ctx *context.Context) {
|
||||
// Proceed will fire the handler and return false here if it doesn't contain a `ctx.Next()`,
|
||||
// so we add the `ctx.Next()` wherever is necessary in order to eliminate any dev's misuse.
|
||||
if !ctx.Proceed(h) {
|
||||
|
||||
@@ -19,7 +19,7 @@ var (
|
||||
)
|
||||
|
||||
func writeStringHandler(text string, withNext bool) context.Handler {
|
||||
return func(ctx context.Context) {
|
||||
return func(ctx *context.Context) {
|
||||
ctx.WriteString(text)
|
||||
if withNext {
|
||||
ctx.Next()
|
||||
|
||||
@@ -154,7 +154,10 @@ type Party interface {
|
||||
//
|
||||
// Alternatively, to get just the handler for that look the FileServer function instead.
|
||||
//
|
||||
// api.HandleDir("/static", "./assets", DirOptions {ShowList: true, Gzip: true, IndexName: "index.html"})
|
||||
// api.HandleDir("/static", "./assets", DirOptions {
|
||||
// ShowList: true,
|
||||
// Compress: true,
|
||||
// IndexName: "index.html"})
|
||||
//
|
||||
// Returns all the registered routes, including GET index and path patterm and HEAD.
|
||||
//
|
||||
|
||||
@@ -194,7 +194,7 @@ func (router *Router) WrapRouter(wrapperFunc WrapperFunc) {
|
||||
}
|
||||
|
||||
// ServeHTTPC serves the raw context, useful if we have already a context, it by-pass the wrapper.
|
||||
func (router *Router) ServeHTTPC(ctx context.Context) {
|
||||
func (router *Router) ServeHTTPC(ctx *context.Context) {
|
||||
router.requestHandler.HandleRequest(ctx)
|
||||
}
|
||||
|
||||
@@ -204,6 +204,6 @@ func (router *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// RouteExists reports whether a particular route exists
|
||||
// It will search from the current subdomain of context's host, if not inside the root domain.
|
||||
func (router *Router) RouteExists(ctx context.Context, method, path string) bool {
|
||||
func (router *Router) RouteExists(ctx *context.Context, method, path string) bool {
|
||||
return router.requestHandler.RouteExists(ctx, method, path)
|
||||
}
|
||||
|
||||
@@ -20,43 +20,43 @@ import (
|
||||
// response should be the same at all cases.
|
||||
var (
|
||||
mainResponse = "main"
|
||||
mainHandler = func(ctx context.Context) {
|
||||
mainHandler = func(ctx *context.Context) {
|
||||
ctx.WriteString(mainResponse)
|
||||
ctx.Next()
|
||||
}
|
||||
|
||||
firstUseResponse = "use1"
|
||||
firstUseHandler = func(ctx context.Context) {
|
||||
firstUseHandler = func(ctx *context.Context) {
|
||||
ctx.WriteString(firstUseResponse)
|
||||
ctx.Next()
|
||||
}
|
||||
|
||||
secondUseResponse = "use2"
|
||||
secondUseHandler = func(ctx context.Context) {
|
||||
secondUseHandler = func(ctx *context.Context) {
|
||||
ctx.WriteString(secondUseResponse)
|
||||
ctx.Next()
|
||||
}
|
||||
|
||||
firstUseGlobalResponse = "useglobal1"
|
||||
firstUseGlobalHandler = func(ctx context.Context) {
|
||||
firstUseGlobalHandler = func(ctx *context.Context) {
|
||||
ctx.WriteString(firstUseGlobalResponse)
|
||||
ctx.Next()
|
||||
}
|
||||
|
||||
secondUseGlobalResponse = "useglobal2"
|
||||
secondUseGlobalHandler = func(ctx context.Context) {
|
||||
secondUseGlobalHandler = func(ctx *context.Context) {
|
||||
ctx.WriteString(secondUseGlobalResponse)
|
||||
ctx.Next()
|
||||
}
|
||||
|
||||
firstDoneResponse = "done1"
|
||||
firstDoneHandler = func(ctx context.Context) {
|
||||
firstDoneHandler = func(ctx *context.Context) {
|
||||
ctx.WriteString(firstDoneResponse)
|
||||
ctx.Next()
|
||||
}
|
||||
|
||||
secondDoneResponse = "done2"
|
||||
secondDoneHandler = func(ctx context.Context) {
|
||||
secondDoneHandler = func(ctx *context.Context) {
|
||||
ctx.WriteString(secondDoneResponse)
|
||||
}
|
||||
|
||||
|
||||
@@ -13,14 +13,14 @@ import (
|
||||
func TestRouteExists(t *testing.T) {
|
||||
// build the api
|
||||
app := iris.New()
|
||||
emptyHandler := func(context.Context) {}
|
||||
emptyHandler := func(*context.Context) {}
|
||||
|
||||
// setup the tested routes
|
||||
app.Handle("GET", "/route-exists", emptyHandler)
|
||||
app.Handle("POST", "/route-with-param/{param}", emptyHandler)
|
||||
|
||||
// check RouteExists
|
||||
app.Handle("GET", "/route-test", func(ctx context.Context) {
|
||||
app.Handle("GET", "/route-test", func(ctx *context.Context) {
|
||||
if ctx.RouteExists("GET", "/route-not-exists") {
|
||||
t.Error("Route with path should not exists")
|
||||
}
|
||||
|
||||
@@ -36,18 +36,18 @@ type testRoute struct {
|
||||
requests []testRouteRequest
|
||||
}
|
||||
|
||||
var h = func(ctx context.Context) {
|
||||
var h = func(ctx *context.Context) {
|
||||
ctx.WriteString(ctx.Path())
|
||||
}
|
||||
|
||||
var h2 = func(ctx context.Context) {
|
||||
var h2 = func(ctx *context.Context) {
|
||||
ctx.StatusCode(iris.StatusForbidden) // ! 200 but send the body as expected,
|
||||
// we need that kind of behavior to determinate which handler is executed for routes that
|
||||
// both having wildcard path but first one is registered on root level.
|
||||
ctx.WriteString(ctx.Path())
|
||||
}
|
||||
|
||||
func h3(ctx context.Context) {
|
||||
func h3(ctx *context.Context) {
|
||||
ctx.Writef(staticPathPrefixBody + ctx.Path())
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
"github.com/kataras/iris/v12/httptest"
|
||||
)
|
||||
|
||||
var defaultErrHandler = func(ctx context.Context) {
|
||||
var defaultErrHandler = func(ctx *context.Context) {
|
||||
text := http.StatusText(ctx.GetStatusCode())
|
||||
ctx.WriteString(text)
|
||||
}
|
||||
@@ -25,18 +25,18 @@ func TestOnAnyErrorCode(t *testing.T) {
|
||||
expectedPrintBeforeExecuteErr := "printed before error"
|
||||
|
||||
// with a middleware
|
||||
app.OnAnyErrorCode(func(ctx context.Context) {
|
||||
app.OnAnyErrorCode(func(ctx *context.Context) {
|
||||
buff.WriteString(expectedPrintBeforeExecuteErr)
|
||||
ctx.Next()
|
||||
}, defaultErrHandler)
|
||||
|
||||
expectedFoundResponse := "found"
|
||||
app.Get("/found", func(ctx context.Context) {
|
||||
app.Get("/found", func(ctx *context.Context) {
|
||||
ctx.WriteString(expectedFoundResponse)
|
||||
})
|
||||
|
||||
expected407 := "this should be sent, we manage the response response by ourselves"
|
||||
app.Get("/407", func(ctx context.Context) {
|
||||
app.Get("/407", func(ctx *context.Context) {
|
||||
ctx.Record()
|
||||
ctx.WriteString(expected407)
|
||||
ctx.StatusCode(iris.StatusProxyAuthRequired)
|
||||
@@ -64,12 +64,12 @@ func TestOnAnyErrorCode(t *testing.T) {
|
||||
app2 := iris.New()
|
||||
app2.Configure(iris.WithResetOnFireErrorCode)
|
||||
|
||||
app2.OnAnyErrorCode(func(ctx context.Context) {
|
||||
app2.OnAnyErrorCode(func(ctx *context.Context) {
|
||||
buff.WriteString(expectedPrintBeforeExecuteErr)
|
||||
ctx.Next()
|
||||
}, defaultErrHandler)
|
||||
|
||||
app2.Get("/406", func(ctx context.Context) {
|
||||
app2.Get("/406", func(ctx *context.Context) {
|
||||
ctx.Record()
|
||||
ctx.WriteString("this should not be sent, only status text will be sent")
|
||||
ctx.WriteString("the handler can handle 'rollback' of the text when error code fired because of the recorder")
|
||||
|
||||
Reference in New Issue
Block a user