412 lines
8.9 KiB
Go
412 lines
8.9 KiB
Go
package framework
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"encoding/xml"
|
|
"errors"
|
|
"io"
|
|
"mime/multipart"
|
|
"net/url"
|
|
|
|
"github.com/spf13/cast"
|
|
)
|
|
|
|
type IRequest interface {
|
|
// url query
|
|
// e.g. foo.com?a=1&b=bar&c[]=bar
|
|
QueryAll(key string) url.Values
|
|
QueryInt(key string, defval int) (int, bool)
|
|
QueryInt64(key string, defval int64) (int64, bool)
|
|
QueryFloat32(key string, defval float32) (float32, bool)
|
|
QueryFloat64(key string, defval float64) (float64, bool)
|
|
QueryBool(key string, defval bool) (bool, bool)
|
|
QueryString(key string, defval string) (string, bool)
|
|
QueryStringSlice(key string, defval []string) ([]string, bool)
|
|
|
|
// url params
|
|
// e.g. /book/:id
|
|
Param(key string) any
|
|
ParamInt(key string, defval int) (int, bool)
|
|
ParamInt64(key string, defval int64) (int64, bool)
|
|
ParamFloat32(key string, defval float32) (float32, bool)
|
|
ParamFloat64(key string, defval float64) (float64, bool)
|
|
ParamBool(key string, defval bool) (bool, bool)
|
|
ParamString(key string, defval string) (string, bool)
|
|
|
|
// form
|
|
FormAll(key string) url.Values
|
|
FormInt(key string, defval int) (int, bool)
|
|
FormInt64(key string, defval int64) (int64, bool)
|
|
FormFloat32(key string, defval float32) (float32, bool)
|
|
FormFloat64(key string, defval float64) (float64, bool)
|
|
FormBool(key string, defval bool) (bool, bool)
|
|
FormString(key string, defval string) (string, bool)
|
|
FormStringSlice(key string, defval []string) ([]string, bool)
|
|
FormFile(key string) (*multipart.FileHeader, error)
|
|
|
|
// JSON body
|
|
BindJSON(obj any) error
|
|
|
|
// XML body
|
|
BindXML(obj any) error
|
|
|
|
// RAW body
|
|
GetRawData() ([]byte, error)
|
|
|
|
// Basic informations
|
|
Uri() string
|
|
Method() string
|
|
Host() string
|
|
ClientIP() string
|
|
|
|
// Header
|
|
Headers() map[string][]string
|
|
Header(key string) (string, bool)
|
|
|
|
// Cookie
|
|
Cookies() map[string]string
|
|
Cookie(key string) (string, bool)
|
|
}
|
|
|
|
// {{{ url query
|
|
|
|
// QueryAll returns all queries in a request URL
|
|
func (ctx *Context) QueryAll() url.Values {
|
|
if ctx.request != nil {
|
|
return map[string][]string(ctx.request.URL.Query())
|
|
}
|
|
return url.Values{}
|
|
}
|
|
|
|
// QueryInt gets an int value from the query request
|
|
func (ctx *Context) QueryInt(key string, defval int) (int, bool) {
|
|
params := ctx.QueryAll()
|
|
if vals, ok := params[key]; ok {
|
|
if len(vals) > 0 {
|
|
return cast.ToInt(vals[0]), true
|
|
}
|
|
}
|
|
return defval, false
|
|
}
|
|
|
|
func (ctx *Context) QueryInt64(key string, defval int64) (int64, bool) {
|
|
params := ctx.QueryAll()
|
|
if vals, ok := params[key]; ok {
|
|
if len(vals) > 0 {
|
|
return cast.ToInt64(vals[0]), true
|
|
}
|
|
}
|
|
return defval, false
|
|
}
|
|
|
|
func (ctx *Context) QueryBool(key string, defval bool) (bool, bool) {
|
|
params := ctx.QueryAll()
|
|
if vals, ok := params[key]; ok {
|
|
if len(vals) > 0 {
|
|
return cast.ToBool(vals[0]), true
|
|
}
|
|
}
|
|
return defval, false
|
|
}
|
|
|
|
func (ctx *Context) QueryFloat32(key string, defval float32) (float32, bool) {
|
|
params := ctx.QueryAll()
|
|
if vals, ok := params[key]; ok {
|
|
if len(vals) > 0 {
|
|
return cast.ToFloat32(vals[0]), true
|
|
}
|
|
}
|
|
return defval, false
|
|
}
|
|
|
|
func (ctx *Context) QueryFloat64(key string, defval float64) (float64, bool) {
|
|
params := ctx.QueryAll()
|
|
if vals, ok := params[key]; ok {
|
|
if len(vals) > 0 {
|
|
return cast.ToFloat64(vals[0]), true
|
|
}
|
|
}
|
|
return defval, false
|
|
}
|
|
|
|
// QueryString gets a string value from the query request
|
|
func (ctx *Context) QueryString(key string, defval string) (string, bool) {
|
|
params := ctx.QueryAll()
|
|
if vals, ok := params[key]; ok {
|
|
if len(vals) > 0 {
|
|
return cast.ToString(vals[0]), true
|
|
}
|
|
}
|
|
return defval, false
|
|
}
|
|
|
|
// QueryArray gets an array of string values from the query request
|
|
func (ctx *Context) QueryStringSlice(key string, defval []string) ([]string, bool) {
|
|
params := ctx.QueryAll()
|
|
if vals, ok := params[key]; ok {
|
|
return cast.ToStringSlice(vals[0]), true
|
|
}
|
|
return defval, false
|
|
}
|
|
|
|
// }}}
|
|
// {{{ url params
|
|
|
|
func (ctx *Context) Param(key string) any {
|
|
if ctx.params != nil {
|
|
if val, ok := ctx.params[key]; ok {
|
|
return val
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (ctx *Context) ParamInt(key string, def int) (int, bool) {
|
|
if val := ctx.Param(key); val != nil {
|
|
return cast.ToInt(val), true
|
|
}
|
|
return def, false
|
|
}
|
|
|
|
func (ctx *Context) ParamInt64(key string, def int64) (int64, bool) {
|
|
if val := ctx.Param(key); val != nil {
|
|
return cast.ToInt64(val), true
|
|
}
|
|
return def, false
|
|
}
|
|
|
|
func (ctx *Context) ParamFloat64(key string, def float64) (float64, bool) {
|
|
if val := ctx.Param(key); val != nil {
|
|
return cast.ToFloat64(val), true
|
|
}
|
|
return def, false
|
|
}
|
|
|
|
func (ctx *Context) ParamFloat32(key string, def float32) (float32, bool) {
|
|
if val := ctx.Param(key); val != nil {
|
|
return cast.ToFloat32(val), true
|
|
}
|
|
return def, false
|
|
}
|
|
|
|
func (ctx *Context) ParamBool(key string, def bool) (bool, bool) {
|
|
if val := ctx.Param(key); val != nil {
|
|
return cast.ToBool(val), true
|
|
}
|
|
return def, false
|
|
}
|
|
|
|
func (ctx *Context) ParamString(key string, def string) (string, bool) {
|
|
if val := ctx.Param(key); val != nil {
|
|
return cast.ToString(val), true
|
|
}
|
|
return def, false
|
|
}
|
|
|
|
// }}}
|
|
// {{{ Post form
|
|
|
|
// FormAll gets everything from the submitted form
|
|
func (ctx *Context) FormAll() url.Values {
|
|
if ctx.request != nil {
|
|
_ = ctx.request.ParseForm()
|
|
return ctx.request.PostForm
|
|
}
|
|
return url.Values{}
|
|
}
|
|
|
|
// FormInt gets an int value from the submitted form
|
|
func (ctx *Context) FormInt(key string, defval int) (int, bool) {
|
|
params := ctx.FormAll()
|
|
if vals, ok := params[key]; ok {
|
|
if len(vals) > 0 {
|
|
return cast.ToInt(vals[0]), true
|
|
}
|
|
}
|
|
return defval, false
|
|
}
|
|
|
|
func (ctx *Context) FormInt64(key string, defval int64) (int64, bool) {
|
|
params := ctx.FormAll()
|
|
if vals, ok := params[key]; ok {
|
|
if len(vals) > 0 {
|
|
return cast.ToInt64(vals[0]), true
|
|
}
|
|
}
|
|
return defval, false
|
|
}
|
|
|
|
func (ctx *Context) FormBool(key string, defval bool) (bool, bool) {
|
|
params := ctx.FormAll()
|
|
if vals, ok := params[key]; ok {
|
|
if len(vals) > 0 {
|
|
return cast.ToBool(vals[0]), true
|
|
}
|
|
}
|
|
return defval, false
|
|
}
|
|
|
|
func (ctx *Context) FormFloat32(key string, defval float32) (float32, bool) {
|
|
params := ctx.FormAll()
|
|
if vals, ok := params[key]; ok {
|
|
if len(vals) > 0 {
|
|
return cast.ToFloat32(vals[0]), true
|
|
}
|
|
}
|
|
return defval, false
|
|
}
|
|
|
|
func (ctx *Context) FormFloat64(key string, defval float64) (float64, bool) {
|
|
params := ctx.FormAll()
|
|
if vals, ok := params[key]; ok {
|
|
if len(vals) > 0 {
|
|
return cast.ToFloat64(vals[0]), true
|
|
}
|
|
}
|
|
return defval, false
|
|
}
|
|
|
|
func (ctx *Context) FormString(key string, defval string) (string, bool) {
|
|
params := ctx.FormAll()
|
|
if vals, ok := params[key]; ok {
|
|
if len(vals) > 0 {
|
|
return cast.ToString(vals[0]), true
|
|
}
|
|
}
|
|
return defval, false
|
|
}
|
|
|
|
func (ctx *Context) FormStringSlice(key string, defval []string) ([]string, bool) {
|
|
params := ctx.FormAll()
|
|
if vals, ok := params[key]; ok {
|
|
return cast.ToStringSlice(vals[0]), true
|
|
}
|
|
return defval, false
|
|
}
|
|
|
|
// }}}
|
|
// {{{ type binder
|
|
|
|
var (
|
|
ErrNoRequest = errors.New("missing request in the context")
|
|
ErrNotSingleObj = errors.New("body must have only a single value")
|
|
)
|
|
|
|
// JSON body
|
|
func (ctx *Context) BindJSON(obj any) error {
|
|
if ctx.request == nil {
|
|
return ErrNoRequest
|
|
}
|
|
dec := json.NewDecoder(ctx.request.Body)
|
|
err := dec.Decode(obj)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = dec.Decode(&struct{}{})
|
|
if err != io.EOF {
|
|
return ErrNotSingleObj
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// XML body
|
|
func (ctx *Context) BindXML(obj any) error {
|
|
if ctx.request == nil {
|
|
return ErrNoRequest
|
|
}
|
|
dec := xml.NewDecoder(ctx.request.Body)
|
|
err := dec.Decode(obj)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = dec.Decode(&struct{}{})
|
|
if err != io.EOF {
|
|
return ErrNotSingleObj
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// RAW body
|
|
func (ctx *Context) GetRawData() ([]byte, error) {
|
|
if ctx.request == nil {
|
|
return []byte{}, ErrNoRequest
|
|
}
|
|
body, err := io.ReadAll(ctx.request.Body)
|
|
if err != nil {
|
|
return []byte{}, err
|
|
}
|
|
/* Restore the body (io.ReadCloser) to it's original state */
|
|
ctx.request.Body = io.NopCloser(bytes.NewBuffer(body))
|
|
|
|
return body, nil
|
|
}
|
|
|
|
// }}}
|
|
// {{{ Basic informations
|
|
|
|
func (ctx *Context) Uri() string {
|
|
return ctx.request.RequestURI
|
|
}
|
|
|
|
func (ctx *Context) Method() string {
|
|
return ctx.request.Method
|
|
}
|
|
|
|
func (ctx *Context) Host() string {
|
|
return ctx.request.Host
|
|
}
|
|
|
|
func (ctx *Context) ClientIP() string {
|
|
r := ctx.request
|
|
ipAddress := r.Header.Get("X-Real-Ip")
|
|
if ipAddress == "" {
|
|
ipAddress = r.Header.Get("X-Forwarded-For")
|
|
}
|
|
if ipAddress == "" {
|
|
ipAddress = r.RemoteAddr
|
|
}
|
|
return ipAddress
|
|
}
|
|
|
|
// }}}
|
|
// {{{ Headers
|
|
|
|
// Header
|
|
func (ctx *Context) Headers() map[string][]string {
|
|
return ctx.request.Header
|
|
}
|
|
|
|
func (ctx *Context) Header(key string) (string, bool) {
|
|
vals := ctx.request.Header.Values(key)
|
|
if vals == nil || len(vals) <= 0 {
|
|
return "", false
|
|
}
|
|
return vals[0], true
|
|
}
|
|
|
|
// }}}
|
|
// {{{ Cookies
|
|
|
|
// Cookies gets cookie key-value pairs
|
|
func (ctx *Context) Cookies() map[string]string {
|
|
cookies := ctx.request.Cookies()
|
|
ret := map[string]string{}
|
|
for _, c := range cookies {
|
|
ret[c.Name] = c.Value
|
|
}
|
|
return ret
|
|
}
|
|
|
|
func (ctx *Context) Cookie(key string) (string, bool) {
|
|
cookies := ctx.Cookies()
|
|
if val, ok := cookies[key]; ok {
|
|
return val, true
|
|
}
|
|
return "", false
|
|
}
|
|
|
|
// }}}
|