Esempio n. 1
0
// BasicAuth returns an HTTP basic authentication middleware.
//
// For valid credentials it calls the next handler.
// For invalid credentials, it sends "401 - Unauthorized" response.
func BasicAuth(fn BasicValidateFunc) echo.MiddlewareFunc {
	return func(h echo.Handler) echo.Handler {
		return echo.HandlerFunc(func(c echo.Context) error {
			auth := c.Request().Header().Get(echo.HeaderAuthorization)
			l := len(basic)

			if len(auth) > l+1 && auth[:l] == basic {
				b, err := base64.StdEncoding.DecodeString(auth[l+1:])
				if err == nil {
					cred := string(b)
					for i := 0; i < len(cred); i++ {
						if cred[i] == ':' {
							// Verify credentials
							if fn(cred[:i], cred[i+1:]) {
								return nil
							}
						}
					}
				}
			}
			c.Response().Header().Set(echo.HeaderWWWAuthenticate, basic+" realm=Restricted")
			return echo.NewHTTPError(http.StatusUnauthorized)
		})
	}
}
Esempio n. 2
0
// BodyLimitWithConfig returns a body limit middleware from config.
// See: `BodyLimit()`.
func BodyLimitWithConfig(config BodyLimitConfig) echo.MiddlewareFunc {
	limit, err := bytes.Parse(config.Limit)
	if err != nil {
		panic(fmt.Errorf("invalid body-limit=%s", config.Limit))
	}
	config.limit = limit
	pool := limitedReaderPool(config)

	return func(next echo.Handler) echo.Handler {
		return echo.HandlerFunc(func(c echo.Context) error {
			req := c.Request()

			// Based on content length
			if req.Size() > config.limit {
				return echo.ErrStatusRequestEntityTooLarge
			}

			// Based on content read
			r := pool.Get().(*limitedReader)
			r.Reset(req.Body(), c)
			defer pool.Put(r)
			req.SetBody(r)

			return next.Handle(c)
		})
	}
}
Esempio n. 3
0
File: jwt.go Progetto: webx-top/webx
func (j *JWT) Validate() echo.MiddlewareFunc {
	return echo.MiddlewareFunc(func(h echo.Handler) echo.Handler {
		return echo.HandlerFunc(func(c echo.Context) error {
			if j.CondFn != nil && j.CondFn(c) == false {
				return h.Handle(c)
			}
			/*//Test
			tokenString, err := j.Response(map[string]interface{}{"uid": "1", "username": "******"})
			if err == nil {
				println("jwt token:", tokenString)
			}
			//*/
			token, err := ParseFromRequest(c.Request(), func(token *jwt.Token) (interface{}, error) {
				b := ([]byte(j.Secret))
				return b, nil
			})
			if err != nil {
				return err
			}
			if !token.Valid {
				return errors.New(`Incorrect signature.`)
			}
			c.Set(`webx:jwtClaims`, token.Claims)
			return h.Handle(c)
		})
	})
}
Esempio n. 4
0
// Gzip returns a middleware which compresses HTTP response using gzip compression
// scheme.
func Gzip() echo.MiddlewareFunc {
	return func(h echo.Handler) echo.Handler {
		scheme := `gzip`
		return echo.HandlerFunc(func(c echo.Context) error {
			c.Response().Header().Add(echo.HeaderVary, echo.HeaderAcceptEncoding)
			if strings.Contains(c.Request().Header().Get(echo.HeaderAcceptEncoding), scheme) {
				rw := c.Response().Writer()
				w := writerPool.Get().(*gzip.Writer)
				w.Reset(rw)
				defer func() {
					if c.Response().Size() == 0 {
						// We have to reset response to it's pristine state when
						// nothing is written to body or error is returned.
						// See issue #424, #407.
						c.Response().SetWriter(rw)
						c.Response().Header().Del(echo.HeaderContentEncoding)
						w.Reset(ioutil.Discard)
					}
					w.Close()
					writerPool.Put(w)
				}()
				gw := gzipWriter{Writer: w, Response: c.Response()}
				c.Response().Header().Set(echo.HeaderContentEncoding, scheme)
				c.Response().SetWriter(gw)
			}
			return h.Handle(c)
		})
	}
}
Esempio n. 5
0
//路由注册方案1:注册函数(可匿名)或静态实例的成员函数
//例如:Controller.R(`/index`,Index.Index,"GET","POST")
func (a *Wrapper) R(path string, h HandlerFunc, methods ...string) *Wrapper {
	if len(methods) < 1 {
		methods = append(methods, "GET")
	}
	_, ctl, act := a.App.Server.URL.Set(path, h)
	a.Webx.Match(methods, path, echo.HandlerFunc(a.wrapHandler(h, ctl, act)))
	return a
}
Esempio n. 6
0
func webxHeader() echo.MiddlewareFunc {
	return echo.MiddlewareFunc(func(h echo.Handler) echo.Handler {
		return echo.HandlerFunc(func(c echo.Context) error {
			c.Response().Header().Set(`Server`, `webx v`+VERSION)
			return h.Handle(c)
		})
	})
}
Esempio n. 7
0
func LimitMiddleware(limiter *config.Limiter) echo.MiddlewareFunc {
	return func(h echo.Handler) echo.Handler {
		return echo.HandlerFunc(func(c echo.Context) error {
			httpError := LimitByRequest(limiter, c.Request())
			if httpError != nil {
				return c.String(httpError.StatusCode, httpError.Message)
			}
			return h.Handle(c)
		})
	}
}
Esempio n. 8
0
func main() {
	e := echo.New()

	// Create a limiter struct.
	limiter := tollbooth.NewLimiter(1, time.Second)

	e.Get("/", echo.HandlerFunc(func(c echo.Context) error {
		return c.String(200, "Hello, World!")
	}), tollbooth_echo.LimitHandler(limiter))

	e.Run(standard.New(":4444"))
}
Esempio n. 9
0
File: app.go Progetto: webx-top/webx
// 注册路由:app.R(`/index`,Index.Index,"GET","POST")
func (a *App) R(path string, h HandlerFunc, methods ...string) *App {
	if len(methods) < 1 {
		methods = append(methods, "GET")
	}
	_, ctl, act := a.Server.URL.Set(path, h)
	a.Webx().Match(methods, path, echo.HandlerFunc(func(ctx echo.Context) error {
		c := X(ctx)
		if err := c.Init(a, nil, ctl, act); err != nil {
			return err
		}
		return h(c)
	}))
	return a
}
Esempio n. 10
0
func Sessions(name string, store ss.Store) echo.MiddlewareFunc {
	return echo.MiddlewareFunc(func(h echo.Handler) echo.Handler {
		return echo.HandlerFunc(func(ctx echo.Context) error {
			c := X.X(ctx)
			s := ss.NewMySession(store, name, ctx)
			if se, ok := interface{}(c).(Sessionser); ok {
				se.InitSession(s)
			}
			err := h.Handle(c)
			s.Save()
			return err
		})
	})
}
Esempio n. 11
0
func (a *Language) Middleware() echo.MiddlewareFunc {
	return echo.MiddlewareFunc(func(h echo.Handler) echo.Handler {
		return echo.HandlerFunc(func(c echo.Context) error {
			lang := a.DetectURI(c.Response(), c.Request())
			c.SetFunc("Lang", func() string {
				return lang
			})
			c.SetFunc("T", func(key string, args ...interface{}) string {
				return i18n.T(lang, key, args...)
			})
			X.X(c).Language = lang
			return h.Handle(c)
		})
	})
}
Esempio n. 12
0
// Override checks for the X-HTTP-Method-Override header
// or the HTML for parameter, `_method`
// and uses (if valid) the http method instead of
// Request.Method.
// This is especially useful for http clients
// that don't support many http verbs.
// It isn't secure to override e.g a GET to a POST,
// so only Request.Method which are POSTs are considered.
func Override() echo.HandlerFunc {
	return echo.HandlerFunc(func(c echo.Context) error {
		if c.Request().Method() == "POST" {
			m := c.Form(ParamHTTPMethodOverride)
			if isValidOverrideMethod(m) {
				OverrideRequestMethod(c, m)
			}
			m = c.Request().Header().Get(HeaderHTTPMethodOverride)
			if isValidOverrideMethod(m) {
				c.Request().SetMethod(m)
			}
		}
		return nil
	})
}
Esempio n. 13
0
// Recover returns a middleware which recovers from panics anywhere in the chain
// and handles the control to the centralized HTTPErrorHandler.
func Recover() echo.MiddlewareFunc {
	return func(h echo.Handler) echo.Handler {
		// TODO: Provide better stack trace `https://github.com/go-errors/errors` `https://github.com/docker/libcontainer/tree/master/stacktrace`
		return echo.HandlerFunc(func(c echo.Context) error {
			defer func() {
				if err := recover(); err != nil {
					trace := make([]byte, 1<<16)
					n := runtime.Stack(trace, true)
					c.Error(echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("panic recover\n %v\n stack trace %d bytes\n %s",
						err, n, trace[:n])))
				}
			}()
			return h.Handle(c)
		})
	}
}
Esempio n. 14
0
func (c *Config) Middleware() echo.MiddlewareFunc {
	return echo.MiddlewareFunc(func(h echo.Handler) echo.Handler {
		return echo.HandlerFunc(func(ctx echo.Context) error {
			if c.Read(ctx) {
				return nil
			}
			if err := h.Handle(ctx); err != nil {
				return err
			}
			if X.X(ctx).Exit {
				return nil
			}
			c.Write(ctx.Response().Body(), ctx)
			return nil
		})
	})
}
Esempio n. 15
0
func main() {
	e := echo.New()
	e.Use(mw.Log(), mw.Recover())
	e.Use(markdown.Markdown(&markdown.Options{
		Path:   "/book/",
		Root:   filepath.Join(os.Getenv(`GOPATH`), `src`, `github.com/admpub/gopl-zh`),
		Browse: true,
	}))

	e.Get("/", echo.HandlerFunc(func(c echo.Context) error {
		return c.String(200, "Hello, World!")
	}))

	// FastHTTP
	// e.Run(fasthttp.New(":4444"))

	// Standard
	e.Run(standard.New(":4444"))
}
Esempio n. 16
0
func (c *Xsrf) Middleware() echo.MiddlewareFunc {
	return echo.MiddlewareFunc(func(h echo.Handler) echo.Handler {
		return echo.HandlerFunc(func(ctx echo.Context) error {
			if !c.On {
				return h.Handle(ctx)
			}
			if ignore, _ := ctx.Get(`webx:ignoreXsrf`).(bool); ignore {
				return h.Handle(ctx)
			}
			c.Register(ctx)
			val := c.Value(ctx)
			if ctx.Request().Method() == `POST` {
				formVal := ctx.Form(c.FieldName)
				if formVal == "" || val != formVal {
					return errors.New("xsrf token error.")
				}
			}
			return h.Handle(ctx)
		})
	})
}
Esempio n. 17
0
File: log.go Progetto: webx-top/echo
func Log() echo.MiddlewareFunc {
	return func(h echo.Handler) echo.Handler {
		return echo.HandlerFunc(func(c echo.Context) error {
			req := c.Request()
			res := c.Response()
			logger := c.Logger()

			start := time.Now()
			if err := h.Handle(c); err != nil {
				c.Error(err)
			}

			remoteAddr := req.RealIP()
			stop := time.Now()
			method := req.Method()
			uri := req.URI()
			size := res.Size()
			code := res.Status()
			logger.Info(remoteAddr + " " + method + " " + uri + " " + fmt.Sprint(code) + " " + stop.Sub(start).String() + " " + fmt.Sprint(size))
			return nil
		})
	}
}
Esempio n. 18
0
//路由注册方案2:从动态实例内Mapper类型字段标签中获取路由信息
func (a *Wrapper) RouteTags() {
	if _, valid := a.Controller.(Initer); !valid {
		a.Server.Core.Logger().Infof("%T is no method Init(*Context),skip.", a.Controller)
		return
	}
	t := reflect.TypeOf(a.Controller)
	e := t.Elem()
	v := reflect.ValueOf(a.Controller)
	ctlPath := e.PkgPath() + ".(*" + e.Name() + ")."
	//github.com/webx-top/{Project}/app/{App}/controller.(*Index).
	ctl := strings.ToLower(e.Name())

	for i := 0; i < e.NumField(); i++ {
		f := e.Field(i)
		if f.Type != mapperType {
			continue
		}
		fn := strings.Title(f.Name)
		name := fn
		m := v.MethodByName(fn)
		if !m.IsValid() {
			continue
		}

		//支持的tag:
		// 1. webx - 路由规则
		// 2. memo - 注释说明
		//webx标签内容支持以下格式:
		// 1、只指定http请求方式,如`webx:"POST|GET"`
		// 2、只指定路由规则,如`webx:"index"`
		// 3、只指定扩展名规则,如`webx:".JSON|XML"`
		// 4、指定以上全部规则,如`webx:"GET|POST.JSON|XML index"`
		tag := e.Field(i).Tag
		tagv := tag.Get("webx")
		methods := []string{}
		extends := []string{}
		var p, w string
		if tagv != "" {
			tags := strings.Split(tagv, " ")
			length := len(tags)
			if length >= 2 { //`webx:"GET|POST /index"`
				w = tags[0]
				p = tags[1]
			} else if length == 1 {
				if matched, _ := regexp.MatchString(`^[A-Z.]+(\|[A-Z]+)*$`, tags[0]); !matched {
					//非全大写字母时,判断为网址规则
					p = tags[0]
				} else { //`webx:"GET|POST"`
					w = tags[0]
				}
			}
		}
		if p == "" {
			p = "/" + f.Name
		} else if p[0] != '/' {
			p = "/" + p
		}
		path := "/" + ctl + p
		met := ""
		ext := ""
		if w != "" {
			me := strings.Split(w, ".")
			met = me[0]
			if len(me) > 1 {
				ext = me[1]
			}
		}
		if met != "" {
			methods = strings.Split(met, "|")
		}
		if ext != "" {
			ext = strings.ToLower(ext)
			extends = strings.Split(ext, "|")
		}
		k := ctlPath + name + "-fm"
		u := a.App.Server.URL.SetByKey(path, k, tag.Get("memo"))
		u.SetExts(extends)
		h := echo.HandlerFunc(func(ctx echo.Context) error {
			c := X(ctx)
			if !u.ValidExt(c.Format) {
				return c.HTML(404, `The contents can not be displayed in this format: `+c.Format)
			}
			v := reflect.New(e)
			ac := v.Interface()
			if err := c.Init(a.App, ac, e.Name(), name); err != nil {
				return err
			}
			if err := ac.(Initer).Init(c); err != nil {
				return err
			}
			if a.HasBefore {
				if err := ac.(Before).Before(); err != nil {
					return err
				}
				if c.Exit {
					return nil
				}
			}
			format := strings.ToUpper(c.Format)
			m := v.MethodByName(fn + `_` + c.Method() + format)
			if !m.IsValid() {
				m = v.MethodByName(fn + `_` + c.Method())
				if !m.IsValid() {
					m = v.MethodByName(fn + `_` + format)
					if !m.IsValid() {
						m = v.MethodByName(fn)
					}
				}
			}
			if r, err := a.SafelyCall(m, []reflect.Value{}); err != nil {
				return err
			} else if len(r) > 0 {
				if err, ok := r[0].Interface().(error); ok && err != nil {
					return c.DisplayError(err.Error())
				}
			}
			if a.HasAfter {
				if c.Exit {
					return nil
				}
				return ac.(After).After()
			}
			return nil
		})
		if len(methods) < 1 {
			a.Webx.Any(path, h)
			for strings.HasSuffix(path, `/index`) {
				path = strings.TrimSuffix(path, `/index`)
				a.Webx.Any(path+`/`, h)
			}
			continue
		}
		a.Webx.Match(methods, path, h)
		for strings.HasSuffix(path, `/index`) {
			path = strings.TrimSuffix(path, `/index`)
			a.Webx.Match(methods, path+`/`, h)
		}
	}
}
Esempio n. 19
0
//路由注册方案3:自动注册动态实例内带HTTP方法名后缀的成员函数作为路由
func (a *Wrapper) RouteMethods() {
	if _, valid := a.Controller.(Initer); !valid {
		a.Server.Core.Logger().Infof("%T is no method Init(*Context),skip.", a.Controller)
		return
	}
	t := reflect.TypeOf(a.Controller)
	e := t.Elem()
	ctlPath := e.PkgPath() + ".(*" + e.Name() + ")."
	//github.com/webx-top/{Project}/app/{App}/controller.(*Index).
	ctl := strings.ToLower(e.Name())

	for i := t.NumMethod() - 1; i >= 0; i-- {
		m := t.Method(i)
		name := m.Name
		fn := name
		h := func(u *Url) func(ctx echo.Context) error {
			return func(ctx echo.Context) error {
				c := X(ctx)
				if !u.ValidExt(c.Format) {
					return c.HTML(404, `The contents can not be displayed in this format: `+c.Format)
				}
				v := reflect.New(e)
				ac := v.Interface()
				if err := c.Init(a.App, ac, e.Name(), name); err != nil {
					return err
				}
				if err := ac.(Initer).Init(c); err != nil {
					return err
				}
				if a.HasBefore {
					if err := ac.(Before).Before(); err != nil {
						return err
					}
					if c.Exit {
						return nil
					}
				}
				format := strings.ToUpper(c.Format)
				m := v.MethodByName(fn + `_` + c.Method() + format)
				if !m.IsValid() {
					m = v.MethodByName(fn + `_` + c.Method())
					if !m.IsValid() {
						m = v.MethodByName(fn + `_` + format)
						if !m.IsValid() {
							m = v.MethodByName(fn)
						}
					}
				}
				if r, err := a.SafelyCall(m, []reflect.Value{}); err != nil {
					return err
				} else if len(r) > 0 {
					if err, ok := r[0].Interface().(error); ok && err != nil {
						return c.DisplayError(err.Error())
					}
				}
				if a.HasAfter {
					if c.Exit {
						return nil
					}
					return ac.(After).After()
				}
				return nil
			}
		}
		if strings.HasSuffix(name, `_ANY`) {
			name = strings.TrimSuffix(name, `_ANY`)
			path := "/" + ctl + "/" + strings.ToLower(name)
			u := a.App.Server.URL.SetByKey(path, ctlPath+name+"-fm")
			handler := echo.HandlerFunc(h(u))
			a.Webx.Any(path, handler)
			for strings.HasSuffix(path, `/index`) {
				path = strings.TrimSuffix(path, `/index`)
				a.Webx.Any(path+`/`, handler)
			}
			continue
		}
		matches := methodSuffixRegex.FindAllString(name, 1)
		if len(matches) < 1 {
			continue
		}
		methods := strings.Split(strings.TrimPrefix(matches[0], `_`), `_`)
		name = strings.TrimSuffix(name, matches[0])
		path := "/" + ctl + "/" + strings.ToLower(name)
		u := a.App.Server.URL.SetByKey(path, ctlPath+name+"-fm")
		handler := echo.HandlerFunc(h(u))
		a.Webx.Match(methods, path, handler)
		for strings.HasSuffix(path, `/index`) {
			path = strings.TrimSuffix(path, `/index`)
			a.Webx.Match(methods, path+`/`, handler)
		}
	}
}
Esempio n. 20
0
func Markdown(options ...*Options) echo.MiddlewareFunc {
	// Default options
	opts := new(Options)
	if len(options) > 0 {
		opts = options[0]
	}
	if opts.Index == "" {
		opts.Index = "SUMMARY.md"
	}
	if opts.MarkdownExtensions == nil {
		opts.MarkdownExtensions = []string{`.md`, `.mdown`, `.markdown`}
	}
	opts.Root, _ = filepath.Abs(opts.Root)

	if opts.Preprocessor == nil {
		opts.Preprocessor = func(c echo.Context, b []byte) []byte {
			return b
		}
	}
	if opts.Filter == nil {
		opts.Filter = func(string) bool {
			return true
		}
	}

	length := len(opts.Path)

	return func(next echo.Handler) echo.Handler {
		return echo.HandlerFunc(func(c echo.Context) error {
			file := c.Request().URL().Path()
			if len(file) < length || file[0:length] != opts.Path {
				return next.Handle(c)
			}
			if !opts.Filter(file) {
				return next.Handle(c)
			}
			file = filepath.Clean(file[length:])
			absFile := filepath.Join(opts.Root, file)
			if !strings.HasPrefix(absFile, opts.Root) {
				return next.Handle(c)
			}
			fi, err := os.Stat(absFile)
			if err != nil {
				return echo.ErrNotFound
			}
			w := c.Response()
			if fi.IsDir() {
				// Index file
				indexFile := filepath.Join(absFile, opts.Index)
				fi, err = os.Stat(indexFile)
				if err != nil || fi.IsDir() {
					if opts.Browse {
						fs := http.Dir(filepath.Dir(absFile))
						d, err := fs.Open(filepath.Base(absFile))
						if err != nil {
							return echo.ErrNotFound
						}
						defer d.Close()
						dirs, err := d.Readdir(-1)
						if err != nil {
							return echo.ErrNotFound
						}

						// Create a directory index
						w.Header().Set(echo.HeaderContentType, echo.MIMETextHTMLCharsetUTF8)
						if _, err = fmt.Fprintf(w, `<!doctype html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>`+file+`</title>
        <meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible" />
        <meta content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" name="viewport" />
        <link href="/favicon.ico" rel="shortcut icon">
    </head>
    <body>`); err != nil {
							return err
						}
						if _, err = fmt.Fprintf(w, "<ul id=\"fileList\">\n"); err != nil {
							return err
						}
						for _, d := range dirs {
							name := d.Name()
							color := "#212121"
							if d.IsDir() {
								color = "#e91e63"
								name += "/"
							}
							if !opts.Filter(name) {
								continue
							}
							if _, err = fmt.Fprintf(w, "<li><a href=\"%s\" style=\"color: %s;\">%s</a></li>\n", name, color, name); err != nil {
								return err
							}
						}
						if _, err = fmt.Fprintf(w, "</ul>\n"); err != nil {
							return err
						}
						_, err = fmt.Fprintf(w, "</body>\n</html>")
						return err
					}
					return echo.ErrNotFound
				}
				absFile = indexFile
			}
			ext := strings.ToLower(filepath.Ext(fi.Name()))
			isMarkdownDocument := false
			for _, vext := range opts.MarkdownExtensions {
				if ext == vext {
					isMarkdownDocument = true
					break
				}
			}
			if isMarkdownDocument {
				modtime := fi.ModTime()
				if t, err := time.Parse(http.TimeFormat, c.Request().Header().Get(echo.HeaderIfModifiedSince)); err == nil && modtime.Before(t.Add(1*time.Second)) {
					w.Header().Del(echo.HeaderContentType)
					w.Header().Del(echo.HeaderContentLength)
					return c.NoContent(http.StatusNotModified)
				}
				b, err := ioutil.ReadFile(absFile)
				if err != nil {
					return echo.ErrNotFound
				}
				b = opts.Preprocessor(c, b)
				b = md2html.MarkdownCommon(b)

				w.Header().Set(echo.HeaderContentType, echo.MIMETextHTMLCharsetUTF8)
				w.Header().Set(echo.HeaderLastModified, modtime.UTC().Format(http.TimeFormat))
				w.WriteHeader(http.StatusOK)
				_, err = w.Write(b)
			} else {
				w.Header().Set(echo.HeaderContentType, echo.ContentTypeByExtension(ext))
				w.ServeFile(absFile)
			}
			return err
		})
	}
}
Esempio n. 21
0
// CORSFromConfig returns a CORS middleware from config.
// See `CORS()`.
func CORSWithConfig(config CORSConfig) echo.MiddlewareFunc {
	// Defaults
	if len(config.AllowOrigins) == 0 {
		config.AllowOrigins = DefaultCORSConfig.AllowOrigins
	}
	if len(config.AllowMethods) == 0 {
		config.AllowMethods = DefaultCORSConfig.AllowMethods
	}
	allowMethods := strings.Join(config.AllowMethods, ",")
	allowHeaders := strings.Join(config.AllowHeaders, ",")
	exposeHeaders := strings.Join(config.ExposeHeaders, ",")
	maxAge := strconv.Itoa(config.MaxAge)

	return func(next echo.Handler) echo.Handler {
		return echo.HandlerFunc(func(c echo.Context) error {
			rq := c.Request()
			origin := c.Request().Header().Get(echo.HeaderOrigin)
			header := c.Response().Header()

			// Check allowed origins
			allowedOrigin := ""
			for _, o := range config.AllowOrigins {
				if o == "*" || o == origin {
					allowedOrigin = o
					break
				}
			}

			// Simple request
			if rq.Method() != echo.OPTIONS {
				header.Add(echo.HeaderVary, echo.HeaderOrigin)
				if origin == "" || allowedOrigin == "" {
					return next.Handle(c)
				}
				header.Set(echo.HeaderAccessControlAllowOrigin, allowedOrigin)
				if config.AllowCredentials {
					header.Set(echo.HeaderAccessControlAllowCredentials, "true")
				}
				if exposeHeaders != "" {
					header.Set(echo.HeaderAccessControlExposeHeaders, exposeHeaders)
				}
				return next.Handle(c)
			}

			// Preflight request
			header.Add(echo.HeaderVary, echo.HeaderOrigin)
			header.Add(echo.HeaderVary, echo.HeaderAccessControlRequestMethod)
			header.Add(echo.HeaderVary, echo.HeaderAccessControlRequestHeaders)
			if origin == "" || allowedOrigin == "" {
				return next.Handle(c)
			}
			header.Set(echo.HeaderAccessControlAllowOrigin, allowedOrigin)
			header.Set(echo.HeaderAccessControlAllowMethods, allowMethods)
			if config.AllowCredentials {
				header.Set(echo.HeaderAccessControlAllowCredentials, "true")
			}
			if allowHeaders != "" {
				header.Set(echo.HeaderAccessControlAllowHeaders, allowHeaders)
			} else {
				h := rq.Header().Get(echo.HeaderAccessControlRequestHeaders)
				if h != "" {
					header.Set(echo.HeaderAccessControlAllowHeaders, h)
				}
			}
			if config.MaxAge > 0 {
				header.Set(echo.HeaderAccessControlMaxAge, maxAge)
			}
			return c.NoContent(http.StatusNoContent)
		})
	}
}
Esempio n. 22
0
func Static(options ...*StaticOptions) echo.MiddlewareFunc {
	// Default options
	opts := new(StaticOptions)
	if len(options) > 0 {
		opts = options[0]
	}
	if opts.Index == "" {
		opts.Index = "index.html"
	}

	opts.Root, _ = filepath.Abs(opts.Root)
	length := len(opts.Path)

	return func(next echo.Handler) echo.Handler {
		return echo.HandlerFunc(func(c echo.Context) error {
			file := c.Request().URL().Path()
			if len(file) < length || file[0:length] != opts.Path {
				return next.Handle(c)
			}
			file = filepath.Clean(file[length:])
			absFile := filepath.Join(opts.Root, file)
			if !strings.HasPrefix(absFile, opts.Root) {
				return next.Handle(c)
			}
			fi, err := os.Stat(absFile)
			if err != nil {
				return next.Handle(c)
			}
			w := c.Response()
			if fi.IsDir() {
				// Index file
				indexFile := filepath.Join(absFile, opts.Index)
				fi, err = os.Stat(indexFile)
				if err != nil || fi.IsDir() {
					if opts.Browse {
						fs := http.Dir(filepath.Dir(absFile))
						d, err := fs.Open(filepath.Base(absFile))
						if err != nil {
							return echo.ErrNotFound
						}
						defer d.Close()
						dirs, err := d.Readdir(-1)
						if err != nil {
							return echo.ErrNotFound
						}

						// Create a directory index
						w.Header().Set(echo.HeaderContentType, echo.MIMETextHTMLCharsetUTF8)
						if _, err = fmt.Fprintf(w, `<!doctype html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>`+file+`</title>
        <meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible" />
        <meta content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" name="viewport" />
        <link href="/favicon.ico" rel="shortcut icon">
    </head>
    <body>`); err != nil {
							return err
						}
						if _, err = fmt.Fprintf(w, "<ul id=\"fileList\">\n"); err != nil {
							return err
						}
						for _, d := range dirs {
							name := d.Name()
							color := "#212121"
							if d.IsDir() {
								color = "#e91e63"
								name += "/"
							}
							if _, err = fmt.Fprintf(w, "<li><a href=\"%s\" style=\"color: %s;\">%s</a></li>\n", name, color, name); err != nil {
								return err
							}
						}
						if _, err = fmt.Fprintf(w, "</ul>\n"); err != nil {
							return err
						}
						_, err = fmt.Fprintf(w, "</body>\n</html>")
						return err
					}
					return next.Handle(c)
				}
				absFile = indexFile
			}
			w.ServeFile(absFile)
			return nil
		})
	}
}