func Decode(r *http.Request, qp httpext.QueryParamsOption, maxMemory int64, v interface{}) (err error) {
	typ := r.Header.Get(httpext.ContentType)
	if idx := strings.Index(typ, ";"); idx != -1 {
		typ = typ[:idx]
	}
	switch typ {
	case httpext.ApplicationForm:
		err = DecodeForm(r, qp, v)
	case httpext.MultipartForm:
		err = DecodeMultipartForm(r, qp, maxMemory, v)
	default:
		if qp == httpext.QueryParams {
			if err = DecodeSEOQueryParams(r, v); err != nil {
				return
			}
		}
		err = httpext.Decode(r, qp, maxMemory, v)
	}
	return
}
Decode takes the request and attempts to discover it's content type via
the http headers and then decode the request body into the provided struct.
Example if header was "application/json" would decode using
json.NewDecoder(ioext.LimitReader(r.Body, maxMemory)).Decode(v).

NOTE: when qp=QueryParams both query params and SEO query params will be parsed and
included eg. route /user/:id?test=true both 'id' and 'test' are treated as query params and added
to the request.Form prior to decoding or added to parsed JSON or XML; in short SEO query params are
treated just like normal query params.
package pure
import (
	"io"
	"net/http"
	"net/url"
	"strings"
	httpext "github.com/go-playground/pkg/v5/net/http"
	urlext "github.com/go-playground/pkg/v5/net/url"
)
func RequestVars(r *http.Request) ReqVars {
	rv := r.Context().Value(defaultContextIdentifier)
	if rv == nil {
		return new(requestVars)
	}
	return rv.(*requestVars)
}
func AcceptedLanguages(r *http.Request) (languages []string) {
	return httpext.AcceptedLanguages(r)
}
func Attachment(w http.ResponseWriter, r io.Reader, filename string) (err error) {
	return httpext.Attachment(w, r, filename)
}
func Inline(w http.ResponseWriter, r io.Reader, filename string) (err error) {
	return httpext.Inline(w, r, filename)
}
func ClientIP(r *http.Request) (clientIP string) {
	return httpext.ClientIP(r)
}
func JSONStream(w http.ResponseWriter, status int, i interface{}) error {
	return httpext.JSONStream(w, status, i)
}
func JSON(w http.ResponseWriter, status int, i interface{}) error {
	return httpext.JSON(w, status, i)
}
func JSONBytes(w http.ResponseWriter, status int, b []byte) (err error) {
	return httpext.JSONBytes(w, status, b)
}
func JSONP(w http.ResponseWriter, status int, i interface{}, callback string) error {
	return httpext.JSONP(w, status, i, callback)
}
func XML(w http.ResponseWriter, status int, i interface{}) error {
	return httpext.XML(w, status, i)
}
func XMLBytes(w http.ResponseWriter, status int, b []byte) (err error) {
	return httpext.XMLBytes(w, status, b)
}
func ParseForm(r *http.Request) error {
	if err := r.ParseForm(); err != nil {
		return err
	}
	if rvi := r.Context().Value(defaultContextIdentifier); rvi != nil {
		rv := rvi.(*requestVars)
		if !rv.formParsed {
			for _, p := range rv.params {
				r.Form.Add(p.key, p.value)
			}
			rv.formParsed = true
		}
	}
	return nil
}
func ParseMultipartForm(r *http.Request, maxMemory int64) error {
	if err := r.ParseMultipartForm(maxMemory); err != nil {
		return err
	}
	if rvi := r.Context().Value(defaultContextIdentifier); rvi != nil {
		rv := rvi.(*requestVars)
		if !rv.formParsed {
			for _, p := range rv.params {
				r.Form.Add(p.key, p.value)
			}
			rv.formParsed = true
		}
	}
	return nil
}