kos/entry/http/context.go

136 lines
2.7 KiB
Go

package http
import (
"context"
"encoding/json"
"net"
"net/http"
"os"
"path"
"strings"
)
var (
defaultBinder = &DefaultBinder{}
)
var (
realIPHeaders = []string{
"Cf-Connecting-Ip",
"True-Client-IP",
"X-Forwarded-For",
"X-Real-Ip",
}
)
type Context struct {
ctx context.Context
req *http.Request
res http.ResponseWriter
params map[string]string
statusCode int
}
func (ctx *Context) reset(req *http.Request, res http.ResponseWriter, ps map[string]string) {
ctx.statusCode = http.StatusOK
ctx.req, ctx.res, ctx.params = req, res, ps
}
func (ctx *Context) RealIp() string {
var (
pos int
ipaddr string
)
for _, h := range realIPHeaders {
if ipaddr = ctx.Request().Header.Get(h); ipaddr != "" {
goto __end
}
}
ipaddr, _, _ = net.SplitHostPort(ctx.Request().RemoteAddr)
__end:
if pos = strings.LastIndexByte(ipaddr, ','); pos > -1 {
ipaddr = ipaddr[:pos]
}
return ipaddr
}
func (ctx *Context) Request() *http.Request {
return ctx.req
}
func (ctx *Context) Response() http.ResponseWriter {
return ctx.res
}
func (ctx *Context) Context() context.Context {
if ctx.Request().Context() != nil {
return ctx.Request().Context()
}
return ctx.ctx
}
func (ctx *Context) Bind(v any) (err error) {
return defaultBinder.Bind(v, ctx.Request())
}
func (ctx *Context) Query(k string) string {
return ctx.Request().FormValue(k)
}
func (ctx *Context) Param(k string) string {
var (
ok bool
v string
)
if v, ok = ctx.params[k]; ok {
return v
}
return ctx.Request().FormValue(k)
}
func (ctx *Context) json(res responsePayload) (err error) {
ctx.Response().Header().Set("Content-Type", "application/json")
encoder := json.NewEncoder(ctx.Response())
if strings.HasPrefix(ctx.Request().Header.Get("User-Agent"), "curl") {
encoder.SetIndent("", "\t")
}
return encoder.Encode(res)
}
func (ctx *Context) Success(v any) (err error) {
return ctx.json(responsePayload{Data: v})
}
func (ctx *Context) Status(code int) {
ctx.statusCode = code
}
func (ctx *Context) Error(code int, reason string) (err error) {
return ctx.json(responsePayload{Code: code, Reason: reason})
}
func (ctx *Context) Redirect(url string, code int) {
if code != http.StatusFound && code != http.StatusMovedPermanently {
code = http.StatusMovedPermanently
}
http.Redirect(ctx.Response(), ctx.Request(), url, code)
}
func (ctx *Context) SetCookie(cookie *http.Cookie) {
http.SetCookie(ctx.Response(), cookie)
}
func (ctx *Context) SendFile(filename string) (err error) {
var (
fi os.FileInfo
fp *os.File
)
if fi, err = os.Stat(filename); err == nil {
if fp, err = os.Open(filename); err == nil {
http.ServeContent(ctx.Response(), ctx.Request(), path.Base(filename), fi.ModTime(), fp)
err = fp.Close()
}
}
return
}