aboutsummaryrefslogtreecommitdiffstats
path: root/src/dma/vendor/github.com/labstack/echo
diff options
context:
space:
mode:
Diffstat (limited to 'src/dma/vendor/github.com/labstack/echo')
-rw-r--r--src/dma/vendor/github.com/labstack/echo/.editorconfig25
-rw-r--r--src/dma/vendor/github.com/labstack/echo/.gitattributes20
-rw-r--r--src/dma/vendor/github.com/labstack/echo/.gitignore7
-rw-r--r--src/dma/vendor/github.com/labstack/echo/.travis.yml16
-rw-r--r--src/dma/vendor/github.com/labstack/echo/LICENSE21
-rw-r--r--src/dma/vendor/github.com/labstack/echo/Makefile3
-rw-r--r--src/dma/vendor/github.com/labstack/echo/README.md99
-rw-r--r--src/dma/vendor/github.com/labstack/echo/bind.go277
-rw-r--r--src/dma/vendor/github.com/labstack/echo/context.go600
-rw-r--r--src/dma/vendor/github.com/labstack/echo/echo.go782
-rw-r--r--src/dma/vendor/github.com/labstack/echo/group.go121
-rw-r--r--src/dma/vendor/github.com/labstack/echo/log.go41
-rw-r--r--src/dma/vendor/github.com/labstack/echo/response.go110
-rw-r--r--src/dma/vendor/github.com/labstack/echo/router.go435
14 files changed, 2557 insertions, 0 deletions
diff --git a/src/dma/vendor/github.com/labstack/echo/.editorconfig b/src/dma/vendor/github.com/labstack/echo/.editorconfig
new file mode 100644
index 00000000..17ae50dd
--- /dev/null
+++ b/src/dma/vendor/github.com/labstack/echo/.editorconfig
@@ -0,0 +1,25 @@
+# EditorConfig coding styles definitions. For more information about the
+# properties used in this file, please see the EditorConfig documentation:
+# http://editorconfig.org/
+
+# indicate this is the root of the project
+root = true
+
+[*]
+charset = utf-8
+
+end_of_line = LF
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+indent_style = space
+indent_size = 2
+
+[Makefile]
+indent_style = tab
+
+[*.md]
+trim_trailing_whitespace = false
+
+[*.go]
+indent_style = tab
diff --git a/src/dma/vendor/github.com/labstack/echo/.gitattributes b/src/dma/vendor/github.com/labstack/echo/.gitattributes
new file mode 100644
index 00000000..49b63e52
--- /dev/null
+++ b/src/dma/vendor/github.com/labstack/echo/.gitattributes
@@ -0,0 +1,20 @@
+# Automatically normalize line endings for all text-based files
+# http://git-scm.com/docs/gitattributes#_end_of_line_conversion
+* text=auto
+
+# For the following file types, normalize line endings to LF on checking and
+# prevent conversion to CRLF when they are checked out (this is required in
+# order to prevent newline related issues)
+.* text eol=lf
+*.go text eol=lf
+*.yml text eol=lf
+*.html text eol=lf
+*.css text eol=lf
+*.js text eol=lf
+*.json text eol=lf
+LICENSE text eol=lf
+
+# Exclude `website` and `cookbook` from GitHub's language statistics
+# https://github.com/github/linguist#using-gitattributes
+cookbook/* linguist-documentation
+website/* linguist-documentation
diff --git a/src/dma/vendor/github.com/labstack/echo/.gitignore b/src/dma/vendor/github.com/labstack/echo/.gitignore
new file mode 100644
index 00000000..dd74acca
--- /dev/null
+++ b/src/dma/vendor/github.com/labstack/echo/.gitignore
@@ -0,0 +1,7 @@
+.DS_Store
+coverage.txt
+_test
+vendor
+.idea
+*.iml
+*.out
diff --git a/src/dma/vendor/github.com/labstack/echo/.travis.yml b/src/dma/vendor/github.com/labstack/echo/.travis.yml
new file mode 100644
index 00000000..30346d7f
--- /dev/null
+++ b/src/dma/vendor/github.com/labstack/echo/.travis.yml
@@ -0,0 +1,16 @@
+language: go
+go:
+ - 1.11.x
+ - tip
+env:
+ - GO111MODULE=on
+install:
+ - go get -v golang.org/x/lint/golint
+script:
+ - golint -set_exit_status ./...
+ - go test -race -coverprofile=coverage.txt -covermode=atomic ./...
+after_success:
+ - bash <(curl -s https://codecov.io/bash)
+matrix:
+ allow_failures:
+ - go: tip
diff --git a/src/dma/vendor/github.com/labstack/echo/LICENSE b/src/dma/vendor/github.com/labstack/echo/LICENSE
new file mode 100644
index 00000000..b5b006b4
--- /dev/null
+++ b/src/dma/vendor/github.com/labstack/echo/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2017 LabStack
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/src/dma/vendor/github.com/labstack/echo/Makefile b/src/dma/vendor/github.com/labstack/echo/Makefile
new file mode 100644
index 00000000..dfcb6c02
--- /dev/null
+++ b/src/dma/vendor/github.com/labstack/echo/Makefile
@@ -0,0 +1,3 @@
+tag:
+ @git tag `grep -P '^\tversion = ' echo.go|cut -f2 -d'"'`
+ @git tag|grep -v ^v
diff --git a/src/dma/vendor/github.com/labstack/echo/README.md b/src/dma/vendor/github.com/labstack/echo/README.md
new file mode 100644
index 00000000..49e4d3b1
--- /dev/null
+++ b/src/dma/vendor/github.com/labstack/echo/README.md
@@ -0,0 +1,99 @@
+<a href="https://echo.labstack.com"><img height="80" src="https://cdn.labstack.com/images/echo-logo.svg"></a>
+
+[![Sourcegraph](https://sourcegraph.com/github.com/labstack/echo/-/badge.svg?style=flat-square)](https://sourcegraph.com/github.com/labstack/echo?badge)
+[![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/labstack/echo)
+[![Go Report Card](https://goreportcard.com/badge/github.com/labstack/echo?style=flat-square)](https://goreportcard.com/report/github.com/labstack/echo)
+[![Build Status](http://img.shields.io/travis/labstack/echo.svg?style=flat-square)](https://travis-ci.org/labstack/echo)
+[![Codecov](https://img.shields.io/codecov/c/github/labstack/echo.svg?style=flat-square)](https://codecov.io/gh/labstack/echo)
+[![Join the chat at https://gitter.im/labstack/echo](https://img.shields.io/badge/gitter-join%20chat-brightgreen.svg?style=flat-square)](https://gitter.im/labstack/echo)
+[![Forum](https://img.shields.io/badge/community-forum-00afd1.svg?style=flat-square)](https://forum.labstack.com)
+[![Twitter](https://img.shields.io/badge/twitter-@labstack-55acee.svg?style=flat-square)](https://twitter.com/labstack)
+[![License](http://img.shields.io/badge/license-mit-blue.svg?style=flat-square)](https://raw.githubusercontent.com/labstack/echo/master/LICENSE)
+
+## Feature Overview
+
+- Optimized HTTP router which smartly prioritize routes
+- Build robust and scalable RESTful APIs
+- Group APIs
+- Extensible middleware framework
+- Define middleware at root, group or route level
+- Data binding for JSON, XML and form payload
+- Handy functions to send variety of HTTP responses
+- Centralized HTTP error handling
+- Template rendering with any template engine
+- Define your format for the logger
+- Highly customizable
+- Automatic TLS via Let’s Encrypt
+- HTTP/2 support
+
+## Benchmarks
+
+Date: 2018/03/15<br>
+Source: https://github.com/vishr/web-framework-benchmark<br>
+Lower is better!
+
+<img src="https://i.imgur.com/I32VdMJ.png">
+
+## [Guide](https://echo.labstack.com/guide)
+
+### Example
+
+```go
+package main
+
+import (
+ "net/http"
+
+ "github.com/labstack/echo"
+ "github.com/labstack/echo/middleware"
+)
+
+func main() {
+ // Echo instance
+ e := echo.New()
+
+ // Middleware
+ e.Use(middleware.Logger())
+ e.Use(middleware.Recover())
+
+ // Routes
+ e.GET("/", hello)
+
+ // Start server
+ e.Logger.Fatal(e.Start(":1323"))
+}
+
+// Handler
+func hello(c echo.Context) error {
+ return c.String(http.StatusOK, "Hello, World!")
+}
+```
+
+## Help
+
+- [Forum](https://forum.labstack.com)
+- [Chat](https://gitter.im/labstack/echo)
+
+## Contribute
+
+**Use issues for everything**
+
+- For a small change, just send a PR.
+- For bigger changes open an issue for discussion before sending a PR.
+- PR should have:
+ - Test case
+ - Documentation
+ - Example (If it makes sense)
+- You can also contribute by:
+ - Reporting issues
+ - Suggesting new features or enhancements
+ - Improve/fix documentation
+
+## Credits
+- [Vishal Rana](https://github.com/vishr) - Author
+- [Nitin Rana](https://github.com/nr17) - Consultant
+- [Contributors](https://github.com/labstack/echo/graphs/contributors)
+
+## License
+
+[MIT](https://github.com/labstack/echo/blob/master/LICENSE)
diff --git a/src/dma/vendor/github.com/labstack/echo/bind.go b/src/dma/vendor/github.com/labstack/echo/bind.go
new file mode 100644
index 00000000..4998e25b
--- /dev/null
+++ b/src/dma/vendor/github.com/labstack/echo/bind.go
@@ -0,0 +1,277 @@
+package echo
+
+import (
+ "encoding/json"
+ "encoding/xml"
+ "errors"
+ "fmt"
+ "net/http"
+ "reflect"
+ "strconv"
+ "strings"
+)
+
+type (
+ // Binder is the interface that wraps the Bind method.
+ Binder interface {
+ Bind(i interface{}, c Context) error
+ }
+
+ // DefaultBinder is the default implementation of the Binder interface.
+ DefaultBinder struct{}
+
+ // BindUnmarshaler is the interface used to wrap the UnmarshalParam method.
+ BindUnmarshaler interface {
+ // UnmarshalParam decodes and assigns a value from an form or query param.
+ UnmarshalParam(param string) error
+ }
+)
+
+// Bind implements the `Binder#Bind` function.
+func (b *DefaultBinder) Bind(i interface{}, c Context) (err error) {
+ req := c.Request()
+ if req.ContentLength == 0 {
+ if req.Method == http.MethodGet || req.Method == http.MethodDelete {
+ if err = b.bindData(i, c.QueryParams(), "query"); err != nil {
+ return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
+ }
+ return
+ }
+ return NewHTTPError(http.StatusBadRequest, "Request body can't be empty")
+ }
+ ctype := req.Header.Get(HeaderContentType)
+ switch {
+ case strings.HasPrefix(ctype, MIMEApplicationJSON):
+ if err = json.NewDecoder(req.Body).Decode(i); err != nil {
+ if ute, ok := err.(*json.UnmarshalTypeError); ok {
+ return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Unmarshal type error: expected=%v, got=%v, field=%v, offset=%v", ute.Type, ute.Value, ute.Field, ute.Offset)).SetInternal(err)
+ } else if se, ok := err.(*json.SyntaxError); ok {
+ return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Syntax error: offset=%v, error=%v", se.Offset, se.Error())).SetInternal(err)
+ } else {
+ return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
+ }
+ return NewHTTPError(http.StatusBadRequest, err.Error())
+ }
+ case strings.HasPrefix(ctype, MIMEApplicationXML), strings.HasPrefix(ctype, MIMETextXML):
+ if err = xml.NewDecoder(req.Body).Decode(i); err != nil {
+ if ute, ok := err.(*xml.UnsupportedTypeError); ok {
+ return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Unsupported type error: type=%v, error=%v", ute.Type, ute.Error())).SetInternal(err)
+ } else if se, ok := err.(*xml.SyntaxError); ok {
+ return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Syntax error: line=%v, error=%v", se.Line, se.Error())).SetInternal(err)
+ } else {
+ return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
+ }
+ return NewHTTPError(http.StatusBadRequest, err.Error())
+ }
+ case strings.HasPrefix(ctype, MIMEApplicationForm), strings.HasPrefix(ctype, MIMEMultipartForm):
+ params, err := c.FormParams()
+ if err != nil {
+ return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
+ }
+ if err = b.bindData(i, params, "form"); err != nil {
+ return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
+ }
+ default:
+ return ErrUnsupportedMediaType
+ }
+ return
+}
+
+func (b *DefaultBinder) bindData(ptr interface{}, data map[string][]string, tag string) error {
+ typ := reflect.TypeOf(ptr).Elem()
+ val := reflect.ValueOf(ptr).Elem()
+
+ if typ.Kind() != reflect.Struct {
+ return errors.New("binding element must be a struct")
+ }
+
+ for i := 0; i < typ.NumField(); i++ {
+ typeField := typ.Field(i)
+ structField := val.Field(i)
+ if !structField.CanSet() {
+ continue
+ }
+ structFieldKind := structField.Kind()
+ inputFieldName := typeField.Tag.Get(tag)
+
+ if inputFieldName == "" {
+ inputFieldName = typeField.Name
+ // If tag is nil, we inspect if the field is a struct.
+ if _, ok := bindUnmarshaler(structField); !ok && structFieldKind == reflect.Struct {
+ if err := b.bindData(structField.Addr().Interface(), data, tag); err != nil {
+ return err
+ }
+ continue
+ }
+ }
+
+ inputValue, exists := data[inputFieldName]
+ if !exists {
+ // Go json.Unmarshal supports case insensitive binding. However the
+ // url params are bound case sensitive which is inconsistent. To
+ // fix this we must check all of the map values in a
+ // case-insensitive search.
+ inputFieldName = strings.ToLower(inputFieldName)
+ for k, v := range data {
+ if strings.ToLower(k) == inputFieldName {
+ inputValue = v
+ exists = true
+ break
+ }
+ }
+ }
+
+ if !exists {
+ continue
+ }
+
+ // Call this first, in case we're dealing with an alias to an array type
+ if ok, err := unmarshalField(typeField.Type.Kind(), inputValue[0], structField); ok {
+ if err != nil {
+ return err
+ }
+ continue
+ }
+
+ numElems := len(inputValue)
+ if structFieldKind == reflect.Slice && numElems > 0 {
+ sliceOf := structField.Type().Elem().Kind()
+ slice := reflect.MakeSlice(structField.Type(), numElems, numElems)
+ for j := 0; j < numElems; j++ {
+ if err := setWithProperType(sliceOf, inputValue[j], slice.Index(j)); err != nil {
+ return err
+ }
+ }
+ val.Field(i).Set(slice)
+ } else if err := setWithProperType(typeField.Type.Kind(), inputValue[0], structField); err != nil {
+ return err
+
+ }
+ }
+ return nil
+}
+
+func setWithProperType(valueKind reflect.Kind, val string, structField reflect.Value) error {
+ // But also call it here, in case we're dealing with an array of BindUnmarshalers
+ if ok, err := unmarshalField(valueKind, val, structField); ok {
+ return err
+ }
+
+ switch valueKind {
+ case reflect.Ptr:
+ return setWithProperType(structField.Elem().Kind(), val, structField.Elem())
+ case reflect.Int:
+ return setIntField(val, 0, structField)
+ case reflect.Int8:
+ return setIntField(val, 8, structField)
+ case reflect.Int16:
+ return setIntField(val, 16, structField)
+ case reflect.Int32:
+ return setIntField(val, 32, structField)
+ case reflect.Int64:
+ return setIntField(val, 64, structField)
+ case reflect.Uint:
+ return setUintField(val, 0, structField)
+ case reflect.Uint8:
+ return setUintField(val, 8, structField)
+ case reflect.Uint16:
+ return setUintField(val, 16, structField)
+ case reflect.Uint32:
+ return setUintField(val, 32, structField)
+ case reflect.Uint64:
+ return setUintField(val, 64, structField)
+ case reflect.Bool:
+ return setBoolField(val, structField)
+ case reflect.Float32:
+ return setFloatField(val, 32, structField)
+ case reflect.Float64:
+ return setFloatField(val, 64, structField)
+ case reflect.String:
+ structField.SetString(val)
+ default:
+ return errors.New("unknown type")
+ }
+ return nil
+}
+
+func unmarshalField(valueKind reflect.Kind, val string, field reflect.Value) (bool, error) {
+ switch valueKind {
+ case reflect.Ptr:
+ return unmarshalFieldPtr(val, field)
+ default:
+ return unmarshalFieldNonPtr(val, field)
+ }
+}
+
+// bindUnmarshaler attempts to unmarshal a reflect.Value into a BindUnmarshaler
+func bindUnmarshaler(field reflect.Value) (BindUnmarshaler, bool) {
+ ptr := reflect.New(field.Type())
+ if ptr.CanInterface() {
+ iface := ptr.Interface()
+ if unmarshaler, ok := iface.(BindUnmarshaler); ok {
+ return unmarshaler, ok
+ }
+ }
+ return nil, false
+}
+
+func unmarshalFieldNonPtr(value string, field reflect.Value) (bool, error) {
+ if unmarshaler, ok := bindUnmarshaler(field); ok {
+ err := unmarshaler.UnmarshalParam(value)
+ field.Set(reflect.ValueOf(unmarshaler).Elem())
+ return true, err
+ }
+ return false, nil
+}
+
+func unmarshalFieldPtr(value string, field reflect.Value) (bool, error) {
+ if field.IsNil() {
+ // Initialize the pointer to a nil value
+ field.Set(reflect.New(field.Type().Elem()))
+ }
+ return unmarshalFieldNonPtr(value, field.Elem())
+}
+
+func setIntField(value string, bitSize int, field reflect.Value) error {
+ if value == "" {
+ value = "0"
+ }
+ intVal, err := strconv.ParseInt(value, 10, bitSize)
+ if err == nil {
+ field.SetInt(intVal)
+ }
+ return err
+}
+
+func setUintField(value string, bitSize int, field reflect.Value) error {
+ if value == "" {
+ value = "0"
+ }
+ uintVal, err := strconv.ParseUint(value, 10, bitSize)
+ if err == nil {
+ field.SetUint(uintVal)
+ }
+ return err
+}
+
+func setBoolField(value string, field reflect.Value) error {
+ if value == "" {
+ value = "false"
+ }
+ boolVal, err := strconv.ParseBool(value)
+ if err == nil {
+ field.SetBool(boolVal)
+ }
+ return err
+}
+
+func setFloatField(value string, bitSize int, field reflect.Value) error {
+ if value == "" {
+ value = "0.0"
+ }
+ floatVal, err := strconv.ParseFloat(value, bitSize)
+ if err == nil {
+ field.SetFloat(floatVal)
+ }
+ return err
+}
diff --git a/src/dma/vendor/github.com/labstack/echo/context.go b/src/dma/vendor/github.com/labstack/echo/context.go
new file mode 100644
index 00000000..d4722700
--- /dev/null
+++ b/src/dma/vendor/github.com/labstack/echo/context.go
@@ -0,0 +1,600 @@
+package echo
+
+import (
+ "bytes"
+ "encoding/json"
+ "encoding/xml"
+ "fmt"
+ "io"
+ "mime/multipart"
+ "net"
+ "net/http"
+ "net/url"
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+type (
+ // Context represents the context of the current HTTP request. It holds request and
+ // response objects, path, path parameters, data and registered handler.
+ Context interface {
+ // Request returns `*http.Request`.
+ Request() *http.Request
+
+ // SetRequest sets `*http.Request`.
+ SetRequest(r *http.Request)
+
+ // Response returns `*Response`.
+ Response() *Response
+
+ // IsTLS returns true if HTTP connection is TLS otherwise false.
+ IsTLS() bool
+
+ // IsWebSocket returns true if HTTP connection is WebSocket otherwise false.
+ IsWebSocket() bool
+
+ // Scheme returns the HTTP protocol scheme, `http` or `https`.
+ Scheme() string
+
+ // RealIP returns the client's network address based on `X-Forwarded-For`
+ // or `X-Real-IP` request header.
+ RealIP() string
+
+ // Path returns the registered path for the handler.
+ Path() string
+
+ // SetPath sets the registered path for the handler.
+ SetPath(p string)
+
+ // Param returns path parameter by name.
+ Param(name string) string
+
+ // ParamNames returns path parameter names.
+ ParamNames() []string
+
+ // SetParamNames sets path parameter names.
+ SetParamNames(names ...string)
+
+ // ParamValues returns path parameter values.
+ ParamValues() []string
+
+ // SetParamValues sets path parameter values.
+ SetParamValues(values ...string)
+
+ // QueryParam returns the query param for the provided name.
+ QueryParam(name string) string
+
+ // QueryParams returns the query parameters as `url.Values`.
+ QueryParams() url.Values
+
+ // QueryString returns the URL query string.
+ QueryString() string
+
+ // FormValue returns the form field value for the provided name.
+ FormValue(name string) string
+
+ // FormParams returns the form parameters as `url.Values`.
+ FormParams() (url.Values, error)
+
+ // FormFile returns the multipart form file for the provided name.
+ FormFile(name string) (*multipart.FileHeader, error)
+
+ // MultipartForm returns the multipart form.
+ MultipartForm() (*multipart.Form, error)
+
+ // Cookie returns the named cookie provided in the request.
+ Cookie(name string) (*http.Cookie, error)
+
+ // SetCookie adds a `Set-Cookie` header in HTTP response.
+ SetCookie(cookie *http.Cookie)
+
+ // Cookies returns the HTTP cookies sent with the request.
+ Cookies() []*http.Cookie
+
+ // Get retrieves data from the context.
+ Get(key string) interface{}
+
+ // Set saves data in the context.
+ Set(key string, val interface{})
+
+ // Bind binds the request body into provided type `i`. The default binder
+ // does it based on Content-Type header.
+ Bind(i interface{}) error
+
+ // Validate validates provided `i`. It is usually called after `Context#Bind()`.
+ // Validator must be registered using `Echo#Validator`.
+ Validate(i interface{}) error
+
+ // Render renders a template with data and sends a text/html response with status
+ // code. Renderer must be registered using `Echo.Renderer`.
+ Render(code int, name string, data interface{}) error
+
+ // HTML sends an HTTP response with status code.
+ HTML(code int, html string) error
+
+ // HTMLBlob sends an HTTP blob response with status code.
+ HTMLBlob(code int, b []byte) error
+
+ // String sends a string response with status code.
+ String(code int, s string) error
+
+ // JSON sends a JSON response with status code.
+ JSON(code int, i interface{}) error
+
+ // JSONPretty sends a pretty-print JSON with status code.
+ JSONPretty(code int, i interface{}, indent string) error
+
+ // JSONBlob sends a JSON blob response with status code.
+ JSONBlob(code int, b []byte) error
+
+ // JSONP sends a JSONP response with status code. It uses `callback` to construct
+ // the JSONP payload.
+ JSONP(code int, callback string, i interface{}) error
+
+ // JSONPBlob sends a JSONP blob response with status code. It uses `callback`
+ // to construct the JSONP payload.
+ JSONPBlob(code int, callback string, b []byte) error
+
+ // XML sends an XML response with status code.
+ XML(code int, i interface{}) error
+
+ // XMLPretty sends a pretty-print XML with status code.
+ XMLPretty(code int, i interface{}, indent string) error
+
+ // XMLBlob sends an XML blob response with status code.
+ XMLBlob(code int, b []byte) error
+
+ // Blob sends a blob response with status code and content type.
+ Blob(code int, contentType string, b []byte) error
+
+ // Stream sends a streaming response with status code and content type.
+ Stream(code int, contentType string, r io.Reader) error
+
+ // File sends a response with the content of the file.
+ File(file string) error
+
+ // Attachment sends a response as attachment, prompting client to save the
+ // file.
+ Attachment(file string, name string) error
+
+ // Inline sends a response as inline, opening the file in the browser.
+ Inline(file string, name string) error
+
+ // NoContent sends a response with no body and a status code.
+ NoContent(code int) error
+
+ // Redirect redirects the request to a provided URL with status code.
+ Redirect(code int, url string) error
+
+ // Error invokes the registered HTTP error handler. Generally used by middleware.
+ Error(err error)
+
+ // Handler returns the matched handler by router.
+ Handler() HandlerFunc
+
+ // SetHandler sets the matched handler by router.
+ SetHandler(h HandlerFunc)
+
+ // Logger returns the `Logger` instance.
+ Logger() Logger
+
+ // Echo returns the `Echo` instance.
+ Echo() *Echo
+
+ // Reset resets the context after request completes. It must be called along
+ // with `Echo#AcquireContext()` and `Echo#ReleaseContext()`.
+ // See `Echo#ServeHTTP()`
+ Reset(r *http.Request, w http.ResponseWriter)
+ }
+
+ context struct {
+ request *http.Request
+ response *Response
+ path string
+ pnames []string
+ pvalues []string
+ query url.Values
+ handler HandlerFunc
+ store Map
+ echo *Echo
+ }
+)
+
+const (
+ defaultMemory = 32 << 20 // 32 MB
+ indexPage = "index.html"
+ defaultIndent = " "
+)
+
+func (c *context) writeContentType(value string) {
+ header := c.Response().Header()
+ if header.Get(HeaderContentType) == "" {
+ header.Set(HeaderContentType, value)
+ }
+}
+
+func (c *context) Request() *http.Request {
+ return c.request
+}
+
+func (c *context) SetRequest(r *http.Request) {
+ c.request = r
+}
+
+func (c *context) Response() *Response {
+ return c.response
+}
+
+func (c *context) IsTLS() bool {
+ return c.request.TLS != nil
+}
+
+func (c *context) IsWebSocket() bool {
+ upgrade := c.request.Header.Get(HeaderUpgrade)
+ return upgrade == "websocket" || upgrade == "Websocket"
+}
+
+func (c *context) Scheme() string {
+ // Can't use `r.Request.URL.Scheme`
+ // See: https://groups.google.com/forum/#!topic/golang-nuts/pMUkBlQBDF0
+ if c.IsTLS() {
+ return "https"
+ }
+ if scheme := c.request.Header.Get(HeaderXForwardedProto); scheme != "" {
+ return scheme
+ }
+ if scheme := c.request.Header.Get(HeaderXForwardedProtocol); scheme != "" {
+ return scheme
+ }
+ if ssl := c.request.Header.Get(HeaderXForwardedSsl); ssl == "on" {
+ return "https"
+ }
+ if scheme := c.request.Header.Get(HeaderXUrlScheme); scheme != "" {
+ return scheme
+ }
+ return "http"
+}
+
+func (c *context) RealIP() string {
+ if ip := c.request.Header.Get(HeaderXForwardedFor); ip != "" {
+ return strings.Split(ip, ", ")[0]
+ }
+ if ip := c.request.Header.Get(HeaderXRealIP); ip != "" {
+ return ip
+ }
+ ra, _, _ := net.SplitHostPort(c.request.RemoteAddr)
+ return ra
+}
+
+func (c *context) Path() string {
+ return c.path
+}
+
+func (c *context) SetPath(p string) {
+ c.path = p
+}
+
+func (c *context) Param(name string) string {
+ for i, n := range c.pnames {
+ if i < len(c.pvalues) {
+ if n == name {
+ return c.pvalues[i]
+ }
+ }
+ }
+ return ""
+}
+
+func (c *context) ParamNames() []string {
+ return c.pnames
+}
+
+func (c *context) SetParamNames(names ...string) {
+ c.pnames = names
+}
+
+func (c *context) ParamValues() []string {
+ return c.pvalues[:len(c.pnames)]
+}
+
+func (c *context) SetParamValues(values ...string) {
+ c.pvalues = values
+}
+
+func (c *context) QueryParam(name string) string {
+ if c.query == nil {
+ c.query = c.request.URL.Query()
+ }
+ return c.query.Get(name)
+}
+
+func (c *context) QueryParams() url.Values {
+ if c.query == nil {
+ c.query = c.request.URL.Query()
+ }
+ return c.query
+}
+
+func (c *context) QueryString() string {
+ return c.request.URL.RawQuery
+}
+
+func (c *context) FormValue(name string) string {
+ return c.request.FormValue(name)
+}
+
+func (c *context) FormParams() (url.Values, error) {
+ if strings.HasPrefix(c.request.Header.Get(HeaderContentType), MIMEMultipartForm) {
+ if err := c.request.ParseMultipartForm(defaultMemory); err != nil {
+ return nil, err
+ }
+ } else {
+ if err := c.request.ParseForm(); err != nil {
+ return nil, err
+ }
+ }
+ return c.request.Form, nil
+}
+
+func (c *context) FormFile(name string) (*multipart.FileHeader, error) {
+ _, fh, err := c.request.FormFile(name)
+ return fh, err
+}
+
+func (c *context) MultipartForm() (*multipart.Form, error) {
+ err := c.request.ParseMultipartForm(defaultMemory)
+ return c.request.MultipartForm, err
+}
+
+func (c *context) Cookie(name string) (*http.Cookie, error) {
+ return c.request.Cookie(name)
+}
+
+func (c *context) SetCookie(cookie *http.Cookie) {
+ http.SetCookie(c.Response(), cookie)
+}
+
+func (c *context) Cookies() []*http.Cookie {
+ return c.request.Cookies()
+}
+
+func (c *context) Get(key string) interface{} {
+ return c.store[key]
+}
+
+func (c *context) Set(key string, val interface{}) {
+ if c.store == nil {
+ c.store = make(Map)
+ }
+ c.store[key] = val
+}
+
+func (c *context) Bind(i interface{}) error {
+ return c.echo.Binder.Bind(i, c)
+}
+
+func (c *context) Validate(i interface{}) error {
+ if c.echo.Validator == nil {
+ return ErrValidatorNotRegistered
+ }
+ return c.echo.Validator.Validate(i)
+}
+
+func (c *context) Render(code int, name string, data interface{}) (err error) {
+ if c.echo.Renderer == nil {
+ return ErrRendererNotRegistered
+ }
+ buf := new(bytes.Buffer)
+ if err = c.echo.Renderer.Render(buf, name, data, c); err != nil {
+ return
+ }
+ return c.HTMLBlob(code, buf.Bytes())
+}
+
+func (c *context) HTML(code int, html string) (err error) {
+ return c.HTMLBlob(code, []byte(html))
+}
+
+func (c *context) HTMLBlob(code int, b []byte) (err error) {
+ return c.Blob(code, MIMETextHTMLCharsetUTF8, b)
+}
+
+func (c *context) String(code int, s string) (err error) {
+ return c.Blob(code, MIMETextPlainCharsetUTF8, []byte(s))
+}
+
+func (c *context) jsonPBlob(code int, callback string, i interface{}) (err error) {
+ enc := json.NewEncoder(c.response)
+ _, pretty := c.QueryParams()["pretty"]
+ if c.echo.Debug || pretty {
+ enc.SetIndent("", " ")
+ }
+ c.writeContentType(MIMEApplicationJavaScriptCharsetUTF8)
+ c.response.WriteHeader(code)
+ if _, err = c.response.Write([]byte(callback + "(")); err != nil {
+ return
+ }
+ if err = enc.Encode(i); err != nil {
+ return
+ }
+ if _, err = c.response.Write([]byte(");")); err != nil {
+ return
+ }
+ return
+}
+
+func (c *context) json(code int, i interface{}, indent string) error {
+ enc := json.NewEncoder(c.response)
+ if indent != "" {
+ enc.SetIndent("", indent)
+ }
+ c.writeContentType(MIMEApplicationJSONCharsetUTF8)
+ c.response.WriteHeader(code)
+ return enc.Encode(i)
+}
+
+func (c *context) JSON(code int, i interface{}) (err error) {
+ indent := ""
+ if _, pretty := c.QueryParams()["pretty"]; c.echo.Debug || pretty {
+ indent = defaultIndent
+ }
+ return c.json(code, i, indent)
+}
+
+func (c *context) JSONPretty(code int, i interface{}, indent string) (err error) {
+ return c.json(code, i, indent)
+}
+
+func (c *context) JSONBlob(code int, b []byte) (err error) {
+ return c.Blob(code, MIMEApplicationJSONCharsetUTF8, b)
+}
+
+func (c *context) JSONP(code int, callback string, i interface{}) (err error) {
+ return c.jsonPBlob(code, callback, i)
+}
+
+func (c *context) JSONPBlob(code int, callback string, b []byte) (err error) {
+ c.writeContentType(MIMEApplicationJavaScriptCharsetUTF8)
+ c.response.WriteHeader(code)
+ if _, err = c.response.Write([]byte(callback + "(")); err != nil {
+ return
+ }
+ if _, err = c.response.Write(b); err != nil {
+ return
+ }
+ _, err = c.response.Write([]byte(");"))
+ return
+}
+
+func (c *context) xml(code int, i interface{}, indent string) (err error) {
+ c.writeContentType(MIMEApplicationXMLCharsetUTF8)
+ c.response.WriteHeader(code)
+ enc := xml.NewEncoder(c.response)
+ if indent != "" {
+ enc.Indent("", indent)
+ }
+ if _, err = c.response.Write([]byte(xml.Header)); err != nil {
+ return
+ }
+ return enc.Encode(i)
+}
+
+func (c *context) XML(code int, i interface{}) (err error) {
+ indent := ""
+ if _, pretty := c.QueryParams()["pretty"]; c.echo.Debug || pretty {
+ indent = defaultIndent
+ }
+ return c.xml(code, i, indent)
+}
+
+func (c *context) XMLPretty(code int, i interface{}, indent string) (err error) {
+ return c.xml(code, i, indent)
+}
+
+func (c *context) XMLBlob(code int, b []byte) (err error) {
+ c.writeContentType(MIMEApplicationXMLCharsetUTF8)
+ c.response.WriteHeader(code)
+ if _, err = c.response.Write([]byte(xml.Header)); err != nil {
+ return
+ }
+ _, err = c.response.Write(b)
+ return
+}
+
+func (c *context) Blob(code int, contentType string, b []byte) (err error) {
+ c.writeContentType(contentType)
+ c.response.WriteHeader(code)
+ _, err = c.response.Write(b)
+ return
+}
+
+func (c *context) Stream(code int, contentType string, r io.Reader) (err error) {
+ c.writeContentType(contentType)
+ c.response.WriteHeader(code)
+ _, err = io.Copy(c.response, r)
+ return
+}
+
+func (c *context) File(file string) (err error) {
+ f, err := os.Open(file)
+ if err != nil {
+ return NotFoundHandler(c)
+ }
+ defer f.Close()
+
+ fi, _ := f.Stat()
+ if fi.IsDir() {
+ file = filepath.Join(file, indexPage)
+ f, err = os.Open(file)
+ if err != nil {
+ return NotFoundHandler(c)
+ }
+ defer f.Close()
+ if fi, err = f.Stat(); err != nil {
+ return
+ }
+ }
+ http.ServeContent(c.Response(), c.Request(), fi.Name(), fi.ModTime(), f)
+ return
+}
+
+func (c *context) Attachment(file, name string) error {
+ return c.contentDisposition(file, name, "attachment")
+}
+
+func (c *context) Inline(file, name string) error {
+ return c.contentDisposition(file, name, "inline")
+}
+
+func (c *context) contentDisposition(file, name, dispositionType string) error {
+ c.response.Header().Set(HeaderContentDisposition, fmt.Sprintf("%s; filename=%q", dispositionType, name))
+ return c.File(file)
+}
+
+func (c *context) NoContent(code int) error {
+ c.response.WriteHeader(code)
+ return nil
+}
+
+func (c *context) Redirect(code int, url string) error {
+ if code < 300 || code > 308 {
+ return ErrInvalidRedirectCode
+ }
+ c.response.Header().Set(HeaderLocation, url)
+ c.response.WriteHeader(code)
+ return nil
+}
+
+func (c *context) Error(err error) {
+ c.echo.HTTPErrorHandler(err, c)
+}
+
+func (c *context) Echo() *Echo {
+ return c.echo
+}
+
+func (c *context) Handler() HandlerFunc {
+ return c.handler
+}
+
+func (c *context) SetHandler(h HandlerFunc) {
+ c.handler = h
+}
+
+func (c *context) Logger() Logger {
+ return c.echo.Logger
+}
+
+func (c *context) Reset(r *http.Request, w http.ResponseWriter) {
+ c.request = r
+ c.response.reset(w)
+ c.query = nil
+ c.handler = NotFoundHandler
+ c.store = nil
+ c.path = ""
+ c.pnames = nil
+ // NOTE: Don't reset because it has to have length c.echo.maxParam at all times
+ // c.pvalues = nil
+}
+
diff --git a/src/dma/vendor/github.com/labstack/echo/echo.go b/src/dma/vendor/github.com/labstack/echo/echo.go
new file mode 100644
index 00000000..98286515
--- /dev/null
+++ b/src/dma/vendor/github.com/labstack/echo/echo.go
@@ -0,0 +1,782 @@
+/*
+Package echo implements high performance, minimalist Go web framework.
+
+Example:
+
+ package main
+
+ import (
+ "net/http"
+
+ "github.com/labstack/echo"
+ "github.com/labstack/echo/middleware"
+ )
+
+ // Handler
+ func hello(c echo.Context) error {
+ return c.String(http.StatusOK, "Hello, World!")
+ }
+
+ func main() {
+ // Echo instance
+ e := echo.New()
+
+ // Middleware
+ e.Use(middleware.Logger())
+ e.Use(middleware.Recover())
+
+ // Routes
+ e.GET("/", hello)
+
+ // Start server
+ e.Logger.Fatal(e.Start(":1323"))
+ }
+
+Learn more at https://echo.labstack.com
+*/
+package echo
+
+import (
+ "bytes"
+ stdContext "context"
+ "crypto/tls"
+ "errors"
+ "fmt"
+ "io"
+ stdLog "log"
+ "net"
+ "net/http"
+ "net/url"
+ "path"
+ "path/filepath"
+ "reflect"
+ "runtime"
+ "sync"
+ "time"
+
+ "github.com/labstack/gommon/color"
+ "github.com/labstack/gommon/log"
+ "golang.org/x/crypto/acme/autocert"
+)
+
+type (
+ // Echo is the top-level framework instance.
+ Echo struct {
+ StdLogger *stdLog.Logger
+ colorer *color.Color
+ premiddleware []MiddlewareFunc
+ middleware []MiddlewareFunc
+ maxParam *int
+ router *Router
+ notFoundHandler HandlerFunc
+ pool sync.Pool
+ Server *http.Server
+ TLSServer *http.Server
+ Listener net.Listener
+ TLSListener net.Listener
+ AutoTLSManager autocert.Manager
+ DisableHTTP2 bool
+ Debug bool
+ HideBanner bool
+ HidePort bool
+ HTTPErrorHandler HTTPErrorHandler
+ Binder Binder
+ Validator Validator
+ Renderer Renderer
+ Logger Logger
+ }
+
+ // Route contains a handler and information for matching against requests.
+ Route struct {
+ Method string `json:"method"`
+ Path string `json:"path"`
+ Name string `json:"name"`
+ }
+
+ // HTTPError represents an error that occurred while handling a request.
+ HTTPError struct {
+ Code int
+ Message interface{}
+ Internal error // Stores the error returned by an external dependency
+ }
+
+ // MiddlewareFunc defines a function to process middleware.
+ MiddlewareFunc func(HandlerFunc) HandlerFunc
+
+ // HandlerFunc defines a function to serve HTTP requests.
+ HandlerFunc func(Context) error
+
+ // HTTPErrorHandler is a centralized HTTP error handler.
+ HTTPErrorHandler func(error, Context)
+
+ // Validator is the interface that wraps the Validate function.
+ Validator interface {
+ Validate(i interface{}) error
+ }
+
+ // Renderer is the interface that wraps the Render function.
+ Renderer interface {
+ Render(io.Writer, string, interface{}, Context) error
+ }
+
+ // Map defines a generic map of type `map[string]interface{}`.
+ Map map[string]interface{}
+
+ // i is the interface for Echo and Group.
+ i interface {
+ GET(string, HandlerFunc, ...MiddlewareFunc) *Route
+ }
+)
+
+// HTTP methods
+// NOTE: Deprecated, please use the stdlib constants directly instead.
+const (
+ CONNECT = http.MethodConnect
+ DELETE = http.MethodDelete
+ GET = http.MethodGet
+ HEAD = http.MethodHead
+ OPTIONS = http.MethodOptions
+ PATCH = http.MethodPatch
+ POST = http.MethodPost
+ // PROPFIND = "PROPFIND"
+ PUT = http.MethodPut
+ TRACE = http.MethodTrace
+)
+
+// MIME types
+const (
+ MIMEApplicationJSON = "application/json"
+ MIMEApplicationJSONCharsetUTF8 = MIMEApplicationJSON + "; " + charsetUTF8
+ MIMEApplicationJavaScript = "application/javascript"
+ MIMEApplicationJavaScriptCharsetUTF8 = MIMEApplicationJavaScript + "; " + charsetUTF8
+ MIMEApplicationXML = "application/xml"
+ MIMEApplicationXMLCharsetUTF8 = MIMEApplicationXML + "; " + charsetUTF8
+ MIMETextXML = "text/xml"
+ MIMETextXMLCharsetUTF8 = MIMETextXML + "; " + charsetUTF8
+ MIMEApplicationForm = "application/x-www-form-urlencoded"
+ MIMEApplicationProtobuf = "application/protobuf"
+ MIMEApplicationMsgpack = "application/msgpack"
+ MIMETextHTML = "text/html"
+ MIMETextHTMLCharsetUTF8 = MIMETextHTML + "; " + charsetUTF8
+ MIMETextPlain = "text/plain"
+ MIMETextPlainCharsetUTF8 = MIMETextPlain + "; " + charsetUTF8
+ MIMEMultipartForm = "multipart/form-data"
+ MIMEOctetStream = "application/octet-stream"
+)
+
+const (
+ charsetUTF8 = "charset=UTF-8"
+ // PROPFIND Method can be used on collection and property resources.
+ PROPFIND = "PROPFIND"
+)
+
+// Headers
+const (
+ HeaderAccept = "Accept"
+ HeaderAcceptEncoding = "Accept-Encoding"
+ HeaderAllow = "Allow"
+ HeaderAuthorization = "Authorization"
+ HeaderContentDisposition = "Content-Disposition"
+ HeaderContentEncoding = "Content-Encoding"
+ HeaderContentLength = "Content-Length"
+ HeaderContentType = "Content-Type"
+ HeaderCookie = "Cookie"
+ HeaderSetCookie = "Set-Cookie"
+ HeaderIfModifiedSince = "If-Modified-Since"
+ HeaderLastModified = "Last-Modified"
+ HeaderLocation = "Location"
+ HeaderUpgrade = "Upgrade"
+ HeaderVary = "Vary"
+ HeaderWWWAuthenticate = "WWW-Authenticate"
+ HeaderXForwardedFor = "X-Forwarded-For"
+ HeaderXForwardedProto = "X-Forwarded-Proto"
+ HeaderXForwardedProtocol = "X-Forwarded-Protocol"
+ HeaderXForwardedSsl = "X-Forwarded-Ssl"
+ HeaderXUrlScheme = "X-Url-Scheme"
+ HeaderXHTTPMethodOverride = "X-HTTP-Method-Override"
+ HeaderXRealIP = "X-Real-IP"
+ HeaderXRequestID = "X-Request-ID"
+ HeaderXRequestedWith = "X-Requested-With"
+ HeaderServer = "Server"
+ HeaderOrigin = "Origin"
+
+ // Access control
+ HeaderAccessControlRequestMethod = "Access-Control-Request-Method"
+ HeaderAccessControlRequestHeaders = "Access-Control-Request-Headers"
+ HeaderAccessControlAllowOrigin = "Access-Control-Allow-Origin"
+ HeaderAccessControlAllowMethods = "Access-Control-Allow-Methods"
+ HeaderAccessControlAllowHeaders = "Access-Control-Allow-Headers"
+ HeaderAccessControlAllowCredentials = "Access-Control-Allow-Credentials"
+ HeaderAccessControlExposeHeaders = "Access-Control-Expose-Headers"
+ HeaderAccessControlMaxAge = "Access-Control-Max-Age"
+
+ // Security
+ HeaderStrictTransportSecurity = "Strict-Transport-Security"
+ HeaderXContentTypeOptions = "X-Content-Type-Options"
+ HeaderXXSSProtection = "X-XSS-Protection"
+ HeaderXFrameOptions = "X-Frame-Options"
+ HeaderContentSecurityPolicy = "Content-Security-Policy"
+ HeaderXCSRFToken = "X-CSRF-Token"
+)
+
+const (
+ // Version of Echo
+ Version = "3.3.10-dev"
+ website = "https://echo.labstack.com"
+ // http://patorjk.com/software/taag/#p=display&f=Small%20Slant&t=Echo
+ banner = `
+ ____ __
+ / __/___/ / ___
+ / _// __/ _ \/ _ \
+/___/\__/_//_/\___/ %s
+High performance, minimalist Go web framework
+%s
+____________________________________O/_______
+ O\
+`
+)
+
+var (
+ methods = [...]string{
+ http.MethodConnect,
+ http.MethodDelete,
+ http.MethodGet,
+ http.MethodHead,
+ http.MethodOptions,
+ http.MethodPatch,
+ http.MethodPost,
+ PROPFIND,
+ http.MethodPut,
+ http.MethodTrace,
+ }
+)
+
+// Errors
+var (
+ ErrUnsupportedMediaType = NewHTTPError(http.StatusUnsupportedMediaType)
+ ErrNotFound = NewHTTPError(http.StatusNotFound)
+ ErrUnauthorized = NewHTTPError(http.StatusUnauthorized)
+ ErrForbidden = NewHTTPError(http.StatusForbidden)
+ ErrMethodNotAllowed = NewHTTPError(http.StatusMethodNotAllowed)
+ ErrStatusRequestEntityTooLarge = NewHTTPError(http.StatusRequestEntityTooLarge)
+ ErrTooManyRequests = NewHTTPError(http.StatusTooManyRequests)
+ ErrBadRequest = NewHTTPError(http.StatusBadRequest)
+ ErrBadGateway = NewHTTPError(http.StatusBadGateway)
+ ErrInternalServerError = NewHTTPError(http.StatusInternalServerError)
+ ErrRequestTimeout = NewHTTPError(http.StatusRequestTimeout)
+ ErrServiceUnavailable = NewHTTPError(http.StatusServiceUnavailable)
+ ErrValidatorNotRegistered = errors.New("validator not registered")
+ ErrRendererNotRegistered = errors.New("renderer not registered")
+ ErrInvalidRedirectCode = errors.New("invalid redirect status code")
+ ErrCookieNotFound = errors.New("cookie not found")
+)
+
+// Error handlers
+var (
+ NotFoundHandler = func(c Context) error {
+ return ErrNotFound
+ }
+
+ MethodNotAllowedHandler = func(c Context) error {
+ return ErrMethodNotAllowed
+ }
+)
+
+// New creates an instance of Echo.
+func New() (e *Echo) {
+ e = &Echo{
+ Server: new(http.Server),
+ TLSServer: new(http.Server),
+ AutoTLSManager: autocert.Manager{
+ Prompt: autocert.AcceptTOS,
+ },
+ Logger: log.New("echo"),
+ colorer: color.New(),
+ maxParam: new(int),
+ }
+ e.Server.Handler = e
+ e.TLSServer.Handler = e
+ e.HTTPErrorHandler = e.DefaultHTTPErrorHandler
+ e.Binder = &DefaultBinder{}
+ e.Logger.SetLevel(log.ERROR)
+ e.StdLogger = stdLog.New(e.Logger.Output(), e.Logger.Prefix()+": ", 0)
+ e.pool.New = func() interface{} {
+ return e.NewContext(nil, nil)
+ }
+ e.router = NewRouter(e)
+ return
+}
+
+// NewContext returns a Context instance.
+func (e *Echo) NewContext(r *http.Request, w http.ResponseWriter) Context {
+ return &context{
+ request: r,
+ response: NewResponse(w, e),
+ store: make(Map),
+ echo: e,
+ pvalues: make([]string, *e.maxParam),
+ handler: NotFoundHandler,
+ }
+}
+
+// Router returns router.
+func (e *Echo) Router() *Router {
+ return e.router
+}
+
+// DefaultHTTPErrorHandler is the default HTTP error handler. It sends a JSON response
+// with status code.
+func (e *Echo) DefaultHTTPErrorHandler(err error, c Context) {
+ var (
+ code = http.StatusInternalServerError
+ msg interface{}
+ )
+
+ if he, ok := err.(*HTTPError); ok {
+ code = he.Code
+ msg = he.Message
+ if he.Internal != nil {
+ err = fmt.Errorf("%v, %v", err, he.Internal)
+ }
+ } else if e.Debug {
+ msg = err.Error()
+ } else {
+ msg = http.StatusText(code)
+ }
+ if _, ok := msg.(string); ok {
+ msg = Map{"message": msg}
+ }
+
+ // Send response
+ if !c.Response().Committed {
+ if c.Request().Method == http.MethodHead { // Issue #608
+ err = c.NoContent(code)
+ } else {
+ err = c.JSON(code, msg)
+ }
+ if err != nil {
+ e.Logger.Error(err)
+ }
+ }
+}
+
+// Pre adds middleware to the chain which is run before router.
+func (e *Echo) Pre(middleware ...MiddlewareFunc) {
+ e.premiddleware = append(e.premiddleware, middleware...)
+}
+
+// Use adds middleware to the chain which is run after router.
+func (e *Echo) Use(middleware ...MiddlewareFunc) {
+ e.middleware = append(e.middleware, middleware...)
+}
+
+// CONNECT registers a new CONNECT route for a path with matching handler in the
+// router with optional route-level middleware.
+func (e *Echo) CONNECT(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+ return e.Add(http.MethodConnect, path, h, m...)
+}
+
+// DELETE registers a new DELETE route for a path with matching handler in the router
+// with optional route-level middleware.
+func (e *Echo) DELETE(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+ return e.Add(http.MethodDelete, path, h, m...)
+}
+
+// GET registers a new GET route for a path with matching handler in the router
+// with optional route-level middleware.
+func (e *Echo) GET(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+ return e.Add(http.MethodGet, path, h, m...)
+}
+
+// HEAD registers a new HEAD route for a path with matching handler in the
+// router with optional route-level middleware.
+func (e *Echo) HEAD(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+ return e.Add(http.MethodHead, path, h, m...)
+}
+
+// OPTIONS registers a new OPTIONS route for a path with matching handler in the
+// router with optional route-level middleware.
+func (e *Echo) OPTIONS(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+ return e.Add(http.MethodOptions, path, h, m...)
+}
+
+// PATCH registers a new PATCH route for a path with matching handler in the
+// router with optional route-level middleware.
+func (e *Echo) PATCH(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+ return e.Add(http.MethodPatch, path, h, m...)
+}
+
+// POST registers a new POST route for a path with matching handler in the
+// router with optional route-level middleware.
+func (e *Echo) POST(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+ return e.Add(http.MethodPost, path, h, m...)
+}
+
+// PUT registers a new PUT route for a path with matching handler in the
+// router with optional route-level middleware.
+func (e *Echo) PUT(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+ return e.Add(http.MethodPut, path, h, m...)
+}
+
+// TRACE registers a new TRACE route for a path with matching handler in the
+// router with optional route-level middleware.
+func (e *Echo) TRACE(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+ return e.Add(http.MethodTrace, path, h, m...)
+}
+
+// Any registers a new route for all HTTP methods and path with matching handler
+// in the router with optional route-level middleware.
+func (e *Echo) Any(path string, handler HandlerFunc, middleware ...MiddlewareFunc) []*Route {
+ routes := make([]*Route, len(methods))
+ for i, m := range methods {
+ routes[i] = e.Add(m, path, handler, middleware...)
+ }
+ return routes
+}
+
+// Match registers a new route for multiple HTTP methods and path with matching
+// handler in the router with optional route-level middleware.
+func (e *Echo) Match(methods []string, path string, handler HandlerFunc, middleware ...MiddlewareFunc) []*Route {
+ routes := make([]*Route, len(methods))
+ for i, m := range methods {
+ routes[i] = e.Add(m, path, handler, middleware...)
+ }
+ return routes
+}
+
+// Static registers a new route with path prefix to serve static files from the
+// provided root directory.
+func (e *Echo) Static(prefix, root string) *Route {
+ if root == "" {
+ root = "." // For security we want to restrict to CWD.
+ }
+ return static(e, prefix, root)
+}
+
+func static(i i, prefix, root string) *Route {
+ h := func(c Context) error {
+ p, err := url.PathUnescape(c.Param("*"))
+ if err != nil {
+ return err
+ }
+ name := filepath.Join(root, path.Clean("/"+p)) // "/"+ for security
+ return c.File(name)
+ }
+ i.GET(prefix, h)
+ if prefix == "/" {
+ return i.GET(prefix+"*", h)
+ }
+
+ return i.GET(prefix+"/*", h)
+}
+
+// File registers a new route with path to serve a static file with optional route-level middleware.
+func (e *Echo) File(path, file string, m ...MiddlewareFunc) *Route {
+ return e.GET(path, func(c Context) error {
+ return c.File(file)
+ }, m...)
+}
+
+// Add registers a new route for an HTTP method and path with matching handler
+// in the router with optional route-level middleware.
+func (e *Echo) Add(method, path string, handler HandlerFunc, middleware ...MiddlewareFunc) *Route {
+ name := handlerName(handler)
+ e.router.Add(method, path, func(c Context) error {
+ h := handler
+ // Chain middleware
+ for i := len(middleware) - 1; i >= 0; i-- {
+ h = middleware[i](h)
+ }
+ return h(c)
+ })
+ r := &Route{
+ Method: method,
+ Path: path,
+ Name: name,
+ }
+ e.router.routes[method+path] = r
+ return r
+}
+
+// Group creates a new router group with prefix and optional group-level middleware.
+func (e *Echo) Group(prefix string, m ...MiddlewareFunc) (g *Group) {
+ g = &Group{prefix: prefix, echo: e}
+ g.Use(m...)
+ return
+}
+
+// URI generates a URI from handler.
+func (e *Echo) URI(handler HandlerFunc, params ...interface{}) string {
+ name := handlerName(handler)
+ return e.Reverse(name, params...)
+}
+
+// URL is an alias for `URI` function.
+func (e *Echo) URL(h HandlerFunc, params ...interface{}) string {
+ return e.URI(h, params...)
+}
+
+// Reverse generates an URL from route name and provided parameters.
+func (e *Echo) Reverse(name string, params ...interface{}) string {
+ uri := new(bytes.Buffer)
+ ln := len(params)
+ n := 0
+ for _, r := range e.router.routes {
+ if r.Name == name {
+ for i, l := 0, len(r.Path); i < l; i++ {
+ if r.Path[i] == ':' && n < ln {
+ for ; i < l && r.Path[i] != '/'; i++ {
+ }
+ uri.WriteString(fmt.Sprintf("%v", params[n]))
+ n++
+ }
+ if i < l {
+ uri.WriteByte(r.Path[i])
+ }
+ }
+ break
+ }
+ }
+ return uri.String()
+}
+
+// Routes returns the registered routes.
+func (e *Echo) Routes() []*Route {
+ routes := make([]*Route, 0, len(e.router.routes))
+ for _, v := range e.router.routes {
+ routes = append(routes, v)
+ }
+ return routes
+}
+
+// AcquireContext returns an empty `Context` instance from the pool.
+// You must return the context by calling `ReleaseContext()`.
+func (e *Echo) AcquireContext() Context {
+ return e.pool.Get().(Context)
+}
+
+// ReleaseContext returns the `Context` instance back to the pool.
+// You must call it after `AcquireContext()`.
+func (e *Echo) ReleaseContext(c Context) {
+ e.pool.Put(c)
+}
+
+// ServeHTTP implements `http.Handler` interface, which serves HTTP requests.
+func (e *Echo) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ // Acquire context
+ c := e.pool.Get().(*context)
+ c.Reset(r, w)
+
+ h := NotFoundHandler
+
+ if e.premiddleware == nil {
+ e.router.Find(r.Method, getPath(r), c)
+ h = c.Handler()
+ for i := len(e.middleware) - 1; i >= 0; i-- {
+ h = e.middleware[i](h)
+ }
+ } else {
+ h = func(c Context) error {
+ e.router.Find(r.Method, getPath(r), c)
+ h := c.Handler()
+ for i := len(e.middleware) - 1; i >= 0; i-- {
+ h = e.middleware[i](h)
+ }
+ return h(c)
+ }
+ for i := len(e.premiddleware) - 1; i >= 0; i-- {
+ h = e.premiddleware[i](h)
+ }
+ }
+
+ // Execute chain
+ if err := h(c); err != nil {
+ e.HTTPErrorHandler(err, c)
+ }
+
+ // Release context
+ e.pool.Put(c)
+}
+
+// Start starts an HTTP server.
+func (e *Echo) Start(address string) error {
+ e.Server.Addr = address
+ return e.StartServer(e.Server)
+}
+
+// StartTLS starts an HTTPS server.
+func (e *Echo) StartTLS(address string, certFile, keyFile string) (err error) {
+ if certFile == "" || keyFile == "" {
+ return errors.New("invalid tls configuration")
+ }
+ s := e.TLSServer
+ s.TLSConfig = new(tls.Config)
+ s.TLSConfig.Certificates = make([]tls.Certificate, 1)
+ s.TLSConfig.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
+ if err != nil {
+ return
+ }
+ return e.startTLS(address)
+}
+
+// StartAutoTLS starts an HTTPS server using certificates automatically installed from https://letsencrypt.org.
+func (e *Echo) StartAutoTLS(address string) error {
+ s := e.TLSServer
+ s.TLSConfig = new(tls.Config)
+ s.TLSConfig.GetCertificate = e.AutoTLSManager.GetCertificate
+ return e.startTLS(address)
+}
+
+func (e *Echo) startTLS(address string) error {
+ s := e.TLSServer
+ s.Addr = address
+ if !e.DisableHTTP2 {
+ s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, "h2")
+ }
+ return e.StartServer(e.TLSServer)
+}
+
+// StartServer starts a custom http server.
+func (e *Echo) StartServer(s *http.Server) (err error) {
+ // Setup
+ e.colorer.SetOutput(e.Logger.Output())
+ s.ErrorLog = e.StdLogger
+ s.Handler = e
+ if e.Debug {
+ e.Logger.SetLevel(log.DEBUG)
+ }
+
+ if !e.HideBanner {
+ e.colorer.Printf(banner, e.colorer.Red("v"+Version), e.colorer.Blue(website))
+ }
+
+ if s.TLSConfig == nil {
+ if e.Listener == nil {
+ e.Listener, err = newListener(s.Addr)
+ if err != nil {
+ return err
+ }
+ }
+ if !e.HidePort {
+ e.colorer.Printf("⇨ http server started on %s\n", e.colorer.Green(e.Listener.Addr()))
+ }
+ return s.Serve(e.Listener)
+ }
+ if e.TLSListener == nil {
+ l, err := newListener(s.Addr)
+ if err != nil {
+ return err
+ }
+ e.TLSListener = tls.NewListener(l, s.TLSConfig)
+ }
+ if !e.HidePort {
+ e.colorer.Printf("⇨ https server started on %s\n", e.colorer.Green(e.TLSListener.Addr()))
+ }
+ return s.Serve(e.TLSListener)
+}
+
+// Close immediately stops the server.
+// It internally calls `http.Server#Close()`.
+func (e *Echo) Close() error {
+ if err := e.TLSServer.Close(); err != nil {
+ return err
+ }
+ return e.Server.Close()
+}
+
+// Shutdown stops the server gracefully.
+// It internally calls `http.Server#Shutdown()`.
+func (e *Echo) Shutdown(ctx stdContext.Context) error {
+ if err := e.TLSServer.Shutdown(ctx); err != nil {
+ return err
+ }
+ return e.Server.Shutdown(ctx)
+}
+
+// NewHTTPError creates a new HTTPError instance.
+func NewHTTPError(code int, message ...interface{}) *HTTPError {
+ he := &HTTPError{Code: code, Message: http.StatusText(code)}
+ if len(message) > 0 {
+ he.Message = message[0]
+ }
+ return he
+}
+
+// Error makes it compatible with `error` interface.
+func (he *HTTPError) Error() string {
+ return fmt.Sprintf("code=%d, message=%v", he.Code, he.Message)
+}
+
+// SetInternal sets error to HTTPError.Internal
+func (he *HTTPError) SetInternal(err error) *HTTPError {
+ he.Internal = err
+ return he
+}
+
+// WrapHandler wraps `http.Handler` into `echo.HandlerFunc`.
+func WrapHandler(h http.Handler) HandlerFunc {
+ return func(c Context) error {
+ h.ServeHTTP(c.Response(), c.Request())
+ return nil
+ }
+}
+
+// WrapMiddleware wraps `func(http.Handler) http.Handler` into `echo.MiddlewareFunc`
+func WrapMiddleware(m func(http.Handler) http.Handler) MiddlewareFunc {
+ return func(next HandlerFunc) HandlerFunc {
+ return func(c Context) (err error) {
+ m(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ c.SetRequest(r)
+ err = next(c)
+ })).ServeHTTP(c.Response(), c.Request())
+ return
+ }
+ }
+}
+
+func getPath(r *http.Request) string {
+ path := r.URL.RawPath
+ if path == "" {
+ path = r.URL.Path
+ }
+ return path
+}
+
+func handlerName(h HandlerFunc) string {
+ t := reflect.ValueOf(h).Type()
+ if t.Kind() == reflect.Func {
+ return runtime.FuncForPC(reflect.ValueOf(h).Pointer()).Name()
+ }
+ return t.String()
+}
+
+// // PathUnescape is wraps `url.PathUnescape`
+// func PathUnescape(s string) (string, error) {
+// return url.PathUnescape(s)
+// }
+
+// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
+// connections. It's used by ListenAndServe and ListenAndServeTLS so
+// dead TCP connections (e.g. closing laptop mid-download) eventually
+// go away.
+type tcpKeepAliveListener struct {
+ *net.TCPListener
+}
+
+func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
+ tc, err := ln.AcceptTCP()
+ if err != nil {
+ return
+ }
+ tc.SetKeepAlive(true)
+ tc.SetKeepAlivePeriod(3 * time.Minute)
+ return tc, nil
+}
+
+func newListener(address string) (*tcpKeepAliveListener, error) {
+ l, err := net.Listen("tcp", address)
+ if err != nil {
+ return nil, err
+ }
+ return &tcpKeepAliveListener{l.(*net.TCPListener)}, nil
+}
diff --git a/src/dma/vendor/github.com/labstack/echo/group.go b/src/dma/vendor/github.com/labstack/echo/group.go
new file mode 100644
index 00000000..3e3732b6
--- /dev/null
+++ b/src/dma/vendor/github.com/labstack/echo/group.go
@@ -0,0 +1,121 @@
+package echo
+
+import (
+ "net/http"
+ "path"
+)
+
+type (
+ // Group is a set of sub-routes for a specified route. It can be used for inner
+ // routes that share a common middleware or functionality that should be separate
+ // from the parent echo instance while still inheriting from it.
+ Group struct {
+ prefix string
+ middleware []MiddlewareFunc
+ echo *Echo
+ }
+)
+
+// Use implements `Echo#Use()` for sub-routes within the Group.
+func (g *Group) Use(middleware ...MiddlewareFunc) {
+ g.middleware = append(g.middleware, middleware...)
+ // Allow all requests to reach the group as they might get dropped if router
+ // doesn't find a match, making none of the group middleware process.
+ for _, p := range []string{"", "/*"} {
+ g.echo.Any(path.Clean(g.prefix+p), func(c Context) error {
+ return NotFoundHandler(c)
+ }, g.middleware...)
+ }
+}
+
+// CONNECT implements `Echo#CONNECT()` for sub-routes within the Group.
+func (g *Group) CONNECT(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+ return g.Add(http.MethodConnect, path, h, m...)
+}
+
+// DELETE implements `Echo#DELETE()` for sub-routes within the Group.
+func (g *Group) DELETE(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+ return g.Add(http.MethodDelete, path, h, m...)
+}
+
+// GET implements `Echo#GET()` for sub-routes within the Group.
+func (g *Group) GET(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+ return g.Add(http.MethodGet, path, h, m...)
+}
+
+// HEAD implements `Echo#HEAD()` for sub-routes within the Group.
+func (g *Group) HEAD(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+ return g.Add(http.MethodHead, path, h, m...)
+}
+
+// OPTIONS implements `Echo#OPTIONS()` for sub-routes within the Group.
+func (g *Group) OPTIONS(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+ return g.Add(http.MethodOptions, path, h, m...)
+}
+
+// PATCH implements `Echo#PATCH()` for sub-routes within the Group.
+func (g *Group) PATCH(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+ return g.Add(http.MethodPatch, path, h, m...)
+}
+
+// POST implements `Echo#POST()` for sub-routes within the Group.
+func (g *Group) POST(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+ return g.Add(http.MethodPost, path, h, m...)
+}
+
+// PUT implements `Echo#PUT()` for sub-routes within the Group.
+func (g *Group) PUT(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+ return g.Add(http.MethodPut, path, h, m...)
+}
+
+// TRACE implements `Echo#TRACE()` for sub-routes within the Group.
+func (g *Group) TRACE(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
+ return g.Add(http.MethodTrace, path, h, m...)
+}
+
+// Any implements `Echo#Any()` for sub-routes within the Group.
+func (g *Group) Any(path string, handler HandlerFunc, middleware ...MiddlewareFunc) []*Route {
+ routes := make([]*Route, len(methods))
+ for i, m := range methods {
+ routes[i] = g.Add(m, path, handler, middleware...)
+ }
+ return routes
+}
+
+// Match implements `Echo#Match()` for sub-routes within the Group.
+func (g *Group) Match(methods []string, path string, handler HandlerFunc, middleware ...MiddlewareFunc) []*Route {
+ routes := make([]*Route, len(methods))
+ for i, m := range methods {
+ routes[i] = g.Add(m, path, handler, middleware...)
+ }
+ return routes
+}
+
+// Group creates a new sub-group with prefix and optional sub-group-level middleware.
+func (g *Group) Group(prefix string, middleware ...MiddlewareFunc) *Group {
+ m := make([]MiddlewareFunc, 0, len(g.middleware)+len(middleware))
+ m = append(m, g.middleware...)
+ m = append(m, middleware...)
+ return g.echo.Group(g.prefix+prefix, m...)
+}
+
+// Static implements `Echo#Static()` for sub-routes within the Group.
+func (g *Group) Static(prefix, root string) {
+ static(g, prefix, root)
+}
+
+// File implements `Echo#File()` for sub-routes within the Group.
+func (g *Group) File(path, file string) {
+ g.echo.File(g.prefix+path, file)
+}
+
+// Add implements `Echo#Add()` for sub-routes within the Group.
+func (g *Group) Add(method, path string, handler HandlerFunc, middleware ...MiddlewareFunc) *Route {
+ // Combine into a new slice to avoid accidentally passing the same slice for
+ // multiple routes, which would lead to later add() calls overwriting the
+ // middleware from earlier calls.
+ m := make([]MiddlewareFunc, 0, len(g.middleware)+len(middleware))
+ m = append(m, g.middleware...)
+ m = append(m, middleware...)
+ return g.echo.Add(method, g.prefix+path, handler, m...)
+}
diff --git a/src/dma/vendor/github.com/labstack/echo/log.go b/src/dma/vendor/github.com/labstack/echo/log.go
new file mode 100644
index 00000000..3f8de590
--- /dev/null
+++ b/src/dma/vendor/github.com/labstack/echo/log.go
@@ -0,0 +1,41 @@
+package echo
+
+import (
+ "io"
+
+ "github.com/labstack/gommon/log"
+)
+
+type (
+ // Logger defines the logging interface.
+ Logger interface {
+ Output() io.Writer
+ SetOutput(w io.Writer)
+ Prefix() string
+ SetPrefix(p string)
+ Level() log.Lvl
+ SetLevel(v log.Lvl)
+ SetHeader(h string)
+ Print(i ...interface{})
+ Printf(format string, args ...interface{})
+ Printj(j log.JSON)
+ Debug(i ...interface{})
+ Debugf(format string, args ...interface{})
+ Debugj(j log.JSON)
+ Info(i ...interface{})
+ Infof(format string, args ...interface{})
+ Infoj(j log.JSON)
+ Warn(i ...interface{})
+ Warnf(format string, args ...interface{})
+ Warnj(j log.JSON)
+ Error(i ...interface{})
+ Errorf(format string, args ...interface{})
+ Errorj(j log.JSON)
+ Fatal(i ...interface{})
+ Fatalj(j log.JSON)
+ Fatalf(format string, args ...interface{})
+ Panic(i ...interface{})
+ Panicj(j log.JSON)
+ Panicf(format string, args ...interface{})
+ }
+)
diff --git a/src/dma/vendor/github.com/labstack/echo/response.go b/src/dma/vendor/github.com/labstack/echo/response.go
new file mode 100644
index 00000000..6244783b
--- /dev/null
+++ b/src/dma/vendor/github.com/labstack/echo/response.go
@@ -0,0 +1,110 @@
+package echo
+
+import (
+ "bufio"
+ "net"
+ "net/http"
+)
+
+type (
+ // Response wraps an http.ResponseWriter and implements its interface to be used
+ // by an HTTP handler to construct an HTTP response.
+ // See: https://golang.org/pkg/net/http/#ResponseWriter
+ Response struct {
+ echo *Echo
+ beforeFuncs []func()
+ afterFuncs []func()
+ Writer http.ResponseWriter
+ Status int
+ Size int64
+ Committed bool
+ }
+)
+
+// NewResponse creates a new instance of Response.
+func NewResponse(w http.ResponseWriter, e *Echo) (r *Response) {
+ return &Response{Writer: w, echo: e}
+}
+
+// Header returns the header map for the writer that will be sent by
+// WriteHeader. Changing the header after a call to WriteHeader (or Write) has
+// no effect unless the modified headers were declared as trailers by setting
+// the "Trailer" header before the call to WriteHeader (see example)
+// To suppress implicit response headers, set their value to nil.
+// Example: https://golang.org/pkg/net/http/#example_ResponseWriter_trailers
+func (r *Response) Header() http.Header {
+ return r.Writer.Header()
+}
+
+// Before registers a function which is called just before the response is written.
+func (r *Response) Before(fn func()) {
+ r.beforeFuncs = append(r.beforeFuncs, fn)
+}
+
+// After registers a function which is called just after the response is written.
+// If the `Content-Length` is unknown, none of the after function is executed.
+func (r *Response) After(fn func()) {
+ r.afterFuncs = append(r.afterFuncs, fn)
+}
+
+// WriteHeader sends an HTTP response header with status code. If WriteHeader is
+// not called explicitly, the first call to Write will trigger an implicit
+// WriteHeader(http.StatusOK). Thus explicit calls to WriteHeader are mainly
+// used to send error codes.
+func (r *Response) WriteHeader(code int) {
+ if r.Committed {
+ r.echo.Logger.Warn("response already committed")
+ return
+ }
+ for _, fn := range r.beforeFuncs {
+ fn()
+ }
+ r.Status = code
+ r.Writer.WriteHeader(code)
+ r.Committed = true
+}
+
+// Write writes the data to the connection as part of an HTTP reply.
+func (r *Response) Write(b []byte) (n int, err error) {
+ if !r.Committed {
+ r.WriteHeader(http.StatusOK)
+ }
+ n, err = r.Writer.Write(b)
+ r.Size += int64(n)
+ for _, fn := range r.afterFuncs {
+ fn()
+ }
+ return
+}
+
+// Flush implements the http.Flusher interface to allow an HTTP handler to flush
+// buffered data to the client.
+// See [http.Flusher](https://golang.org/pkg/net/http/#Flusher)
+func (r *Response) Flush() {
+ r.Writer.(http.Flusher).Flush()
+}
+
+// Hijack implements the http.Hijacker interface to allow an HTTP handler to
+// take over the connection.
+// See [http.Hijacker](https://golang.org/pkg/net/http/#Hijacker)
+func (r *Response) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return r.Writer.(http.Hijacker).Hijack()
+}
+
+// CloseNotify implements the http.CloseNotifier interface to allow detecting
+// when the underlying connection has gone away.
+// This mechanism can be used to cancel long operations on the server if the
+// client has disconnected before the response is ready.
+// See [http.CloseNotifier](https://golang.org/pkg/net/http/#CloseNotifier)
+func (r *Response) CloseNotify() <-chan bool {
+ return r.Writer.(http.CloseNotifier).CloseNotify()
+}
+
+func (r *Response) reset(w http.ResponseWriter) {
+ r.beforeFuncs = nil
+ r.afterFuncs = nil
+ r.Writer = w
+ r.Size = 0
+ r.Status = http.StatusOK
+ r.Committed = false
+}
diff --git a/src/dma/vendor/github.com/labstack/echo/router.go b/src/dma/vendor/github.com/labstack/echo/router.go
new file mode 100644
index 00000000..73f0b68b
--- /dev/null
+++ b/src/dma/vendor/github.com/labstack/echo/router.go
@@ -0,0 +1,435 @@
+package echo
+
+import "net/http"
+
+type (
+ // Router is the registry of all registered routes for an `Echo` instance for
+ // request matching and URL path parameter parsing.
+ Router struct {
+ tree *node
+ routes map[string]*Route
+ echo *Echo
+ }
+ node struct {
+ kind kind
+ label byte
+ prefix string
+ parent *node
+ children children
+ ppath string
+ pnames []string
+ methodHandler *methodHandler
+ }
+ kind uint8
+ children []*node
+ methodHandler struct {
+ connect HandlerFunc
+ delete HandlerFunc
+ get HandlerFunc
+ head HandlerFunc
+ options HandlerFunc
+ patch HandlerFunc
+ post HandlerFunc
+ propfind HandlerFunc
+ put HandlerFunc
+ trace HandlerFunc
+ }
+)
+
+const (
+ skind kind = iota
+ pkind
+ akind
+)
+
+// NewRouter returns a new Router instance.
+func NewRouter(e *Echo) *Router {
+ return &Router{
+ tree: &node{
+ methodHandler: new(methodHandler),
+ },
+ routes: map[string]*Route{},
+ echo: e,
+ }
+}
+
+// Add registers a new route for method and path with matching handler.
+func (r *Router) Add(method, path string, h HandlerFunc) {
+ // Validate path
+ if path == "" {
+ panic("echo: path cannot be empty")
+ }
+ if path[0] != '/' {
+ path = "/" + path
+ }
+ pnames := []string{} // Param names
+ ppath := path // Pristine path
+
+ for i, l := 0, len(path); i < l; i++ {
+ if path[i] == ':' {
+ j := i + 1
+
+ r.insert(method, path[:i], nil, skind, "", nil)
+ for ; i < l && path[i] != '/'; i++ {
+ }
+
+ pnames = append(pnames, path[j:i])
+ path = path[:j] + path[i:]
+ i, l = j, len(path)
+
+ if i == l {
+ r.insert(method, path[:i], h, pkind, ppath, pnames)
+ return
+ }
+ r.insert(method, path[:i], nil, pkind, "", nil)
+ } else if path[i] == '*' {
+ r.insert(method, path[:i], nil, skind, "", nil)
+ pnames = append(pnames, "*")
+ r.insert(method, path[:i+1], h, akind, ppath, pnames)
+ return
+ }
+ }
+
+ r.insert(method, path, h, skind, ppath, pnames)
+}
+
+func (r *Router) insert(method, path string, h HandlerFunc, t kind, ppath string, pnames []string) {
+ // Adjust max param
+ l := len(pnames)
+ if *r.echo.maxParam < l {
+ *r.echo.maxParam = l
+ }
+
+ cn := r.tree // Current node as root
+ if cn == nil {
+ panic("echo: invalid method")
+ }
+ search := path
+
+ for {
+ sl := len(search)
+ pl := len(cn.prefix)
+ l := 0
+
+ // LCP
+ max := pl
+ if sl < max {
+ max = sl
+ }
+ for ; l < max && search[l] == cn.prefix[l]; l++ {
+ }
+
+ if l == 0 {
+ // At root node
+ cn.label = search[0]
+ cn.prefix = search
+ if h != nil {
+ cn.kind = t
+ cn.addHandler(method, h)
+ cn.ppath = ppath
+ cn.pnames = pnames
+ }
+ } else if l < pl {
+ // Split node
+ n := newNode(cn.kind, cn.prefix[l:], cn, cn.children, cn.methodHandler, cn.ppath, cn.pnames)
+
+ // Reset parent node
+ cn.kind = skind
+ cn.label = cn.prefix[0]
+ cn.prefix = cn.prefix[:l]
+ cn.children = nil
+ cn.methodHandler = new(methodHandler)
+ cn.ppath = ""
+ cn.pnames = nil
+
+ cn.addChild(n)
+
+ if l == sl {
+ // At parent node
+ cn.kind = t
+ cn.addHandler(method, h)
+ cn.ppath = ppath
+ cn.pnames = pnames
+ } else {
+ // Create child node
+ n = newNode(t, search[l:], cn, nil, new(methodHandler), ppath, pnames)
+ n.addHandler(method, h)
+ cn.addChild(n)
+ }
+ } else if l < sl {
+ search = search[l:]
+ c := cn.findChildWithLabel(search[0])
+ if c != nil {
+ // Go deeper
+ cn = c
+ continue
+ }
+ // Create child node
+ n := newNode(t, search, cn, nil, new(methodHandler), ppath, pnames)
+ n.addHandler(method, h)
+ cn.addChild(n)
+ } else {
+ // Node already exists
+ if h != nil {
+ cn.addHandler(method, h)
+ cn.ppath = ppath
+ if len(cn.pnames) == 0 { // Issue #729
+ cn.pnames = pnames
+ }
+ }
+ }
+ return
+ }
+}
+
+func newNode(t kind, pre string, p *node, c children, mh *methodHandler, ppath string, pnames []string) *node {
+ return &node{
+ kind: t,
+ label: pre[0],
+ prefix: pre,
+ parent: p,
+ children: c,
+ ppath: ppath,
+ pnames: pnames,
+ methodHandler: mh,
+ }
+}
+
+func (n *node) addChild(c *node) {
+ n.children = append(n.children, c)
+}
+
+func (n *node) findChild(l byte, t kind) *node {
+ for _, c := range n.children {
+ if c.label == l && c.kind == t {
+ return c
+ }
+ }
+ return nil
+}
+
+func (n *node) findChildWithLabel(l byte) *node {
+ for _, c := range n.children {
+ if c.label == l {
+ return c
+ }
+ }
+ return nil
+}
+
+func (n *node) findChildByKind(t kind) *node {
+ for _, c := range n.children {
+ if c.kind == t {
+ return c
+ }
+ }
+ return nil
+}
+
+func (n *node) addHandler(method string, h HandlerFunc) {
+ switch method {
+ case http.MethodConnect:
+ n.methodHandler.connect = h
+ case http.MethodDelete:
+ n.methodHandler.delete = h
+ case http.MethodGet:
+ n.methodHandler.get = h
+ case http.MethodHead:
+ n.methodHandler.head = h
+ case http.MethodOptions:
+ n.methodHandler.options = h
+ case http.MethodPatch:
+ n.methodHandler.patch = h
+ case http.MethodPost:
+ n.methodHandler.post = h
+ case PROPFIND:
+ n.methodHandler.propfind = h
+ case http.MethodPut:
+ n.methodHandler.put = h
+ case http.MethodTrace:
+ n.methodHandler.trace = h
+ }
+}
+
+func (n *node) findHandler(method string) HandlerFunc {
+ switch method {
+ case http.MethodConnect:
+ return n.methodHandler.connect
+ case http.MethodDelete:
+ return n.methodHandler.delete
+ case http.MethodGet:
+ return n.methodHandler.get
+ case http.MethodHead:
+ return n.methodHandler.head
+ case http.MethodOptions:
+ return n.methodHandler.options
+ case http.MethodPatch:
+ return n.methodHandler.patch
+ case http.MethodPost:
+ return n.methodHandler.post
+ case PROPFIND:
+ return n.methodHandler.propfind
+ case http.MethodPut:
+ return n.methodHandler.put
+ case http.MethodTrace:
+ return n.methodHandler.trace
+ default:
+ return nil
+ }
+}
+
+func (n *node) checkMethodNotAllowed() HandlerFunc {
+ for _, m := range methods {
+ if h := n.findHandler(m); h != nil {
+ return MethodNotAllowedHandler
+ }
+ }
+ return NotFoundHandler
+}
+
+// Find lookup a handler registered for method and path. It also parses URL for path
+// parameters and load them into context.
+//
+// For performance:
+//
+// - Get context from `Echo#AcquireContext()`
+// - Reset it `Context#Reset()`
+// - Return it `Echo#ReleaseContext()`.
+func (r *Router) Find(method, path string, c Context) {
+ ctx := c.(*context)
+ ctx.path = path
+ cn := r.tree // Current node as root
+
+ var (
+ search = path
+ child *node // Child node
+ n int // Param counter
+ nk kind // Next kind
+ nn *node // Next node
+ ns string // Next search
+ pvalues = ctx.pvalues // Use the internal slice so the interface can keep the illusion of a dynamic slice
+ )
+
+ // Search order static > param > any
+ for {
+ if search == "" {
+ break
+ }
+
+ pl := 0 // Prefix length
+ l := 0 // LCP length
+
+ if cn.label != ':' {
+ sl := len(search)
+ pl = len(cn.prefix)
+
+ // LCP
+ max := pl
+ if sl < max {
+ max = sl
+ }
+ for ; l < max && search[l] == cn.prefix[l]; l++ {
+ }
+ }
+
+ if l == pl {
+ // Continue search
+ search = search[l:]
+ } else {
+ cn = nn
+ search = ns
+ if nk == pkind {
+ goto Param
+ } else if nk == akind {
+ goto Any
+ }
+ // Not found
+ return
+ }
+
+ if search == "" {
+ break
+ }
+
+ // Static node
+ if child = cn.findChild(search[0], skind); child != nil {
+ // Save next
+ if cn.prefix[len(cn.prefix)-1] == '/' { // Issue #623
+ nk = pkind
+ nn = cn
+ ns = search
+ }
+ cn = child
+ continue
+ }
+
+ // Param node
+ Param:
+ if child = cn.findChildByKind(pkind); child != nil {
+ // Issue #378
+ if len(pvalues) == n {
+ continue
+ }
+
+ // Save next
+ if cn.prefix[len(cn.prefix)-1] == '/' { // Issue #623
+ nk = akind
+ nn = cn
+ ns = search
+ }
+
+ cn = child
+ i, l := 0, len(search)
+ for ; i < l && search[i] != '/'; i++ {
+ }
+ pvalues[n] = search[:i]
+ n++
+ search = search[i:]
+ continue
+ }
+
+ // Any node
+ Any:
+ if cn = cn.findChildByKind(akind); cn == nil {
+ if nn != nil {
+ cn = nn
+ nn = cn.parent // Next (Issue #954)
+ search = ns
+ if nk == pkind {
+ goto Param
+ } else if nk == akind {
+ goto Any
+ }
+ }
+ // Not found
+ return
+ }
+ pvalues[len(cn.pnames)-1] = search
+ break
+ }
+
+ ctx.handler = cn.findHandler(method)
+ ctx.path = cn.ppath
+ ctx.pnames = cn.pnames
+
+ // NOTE: Slow zone...
+ if ctx.handler == nil {
+ ctx.handler = cn.checkMethodNotAllowed()
+
+ // Dig further for any, might have an empty value for *, e.g.
+ // serving a directory. Issue #207.
+ if cn = cn.findChildByKind(akind); cn == nil {
+ return
+ }
+ if h := cn.findHandler(method); h != nil {
+ ctx.handler = h
+ } else {
+ ctx.handler = cn.checkMethodNotAllowed()
+ }
+ ctx.path = cn.ppath
+ ctx.pnames = cn.pnames
+ pvalues[len(cn.pnames)-1] = ""
+ }
+
+ return
+}