func (c *Context) Redirect(location string) {
	c.Abort()
	status := c.Response.Status()
	switch status {
	case http.StatusMovedPermanently, http.StatusSeeOther, http.StatusTemporaryRedirect:
	default:
		status = http.StatusFound
	}
	c.SetHeader("Location", location)
	http.Redirect(c.Response, c.Request, location, status)
}
Redirect returns a HTTP redirect to the specific location.
package gogo
import (
	"crypto"
	"math"
	"net/http"
	"net/url"
	"strings"
	"sync"
	"time"
	"github.com/dolab/gogo/internal/params"
	"github.com/dolab/gogo/internal/render"
	"github.com/dolab/gogo/pkgs/hooks"
)
var (
	contextPool = sync.Pool{
		New: func() interface{} {
			return NewContext()
		},
	}
	contextNew = func(w http.ResponseWriter, r *http.Request, ps *params.Params, pkg, ctrl, action string) *Context {
		ctx := contextPool.Get().(*Context)
		ctx.Response.Hijack(w)
		ctx.Request = r
		ctx.Params = ps
		ctx.Logger = NewRequestLogger(r)
		ctx.pkg = pkg
		ctx.ctrl = ctrl
		ctx.action = action
		return ctx
	}
	contextReuse = func(ctx *Context) {
		contextPool.Put(ctx)
	}
)
type Context struct {
	Response Responser
	Request  *http.Request
	Params   *params.Params
	Logger   Logger
	mux            sync.RWMutex
	settings       map[string]interface{}
	frozenSettings map[string]interface{}
	cursor         int8
	pkg           string
	ctrl          string
	action        string
	filters       []Middleware
	responseReady *hooks.HookList
	issuedAt      time.Time
}
func NewContext() *Context {
	return &Context{
		Response: NewResponse(nil),
		cursor:   -1,
	}
}
func (c *Context) Package() string {
	return c.pkg
}
func (c *Context) Controller() string {
	return c.ctrl
}
func (c *Context) Action() string {
	return c.action
}
func (c *Context) ContentType() string {
	s := c.Header("Content-Type")
	i := strings.Index(s, ";")
	if i == -1 {
		i = len(s)
	}
	return strings.TrimSpace(strings.ToLower(s[:i]))
}
func (c *Context) Set(key string, value interface{}) {
	if c.settings == nil {
		c.settings = make(map[string]interface{})
	}
	c.settings[key] = value
}
func (c *Context) Get(key string) (v interface{}, ok bool) {
	if c.settings == nil {
		return
	}
	v, ok = c.settings[key]
	return
}
func (c *Context) MustGet(key string) interface{} {
	v, ok := c.Get(key)
	if !ok {
		c.Logger.Panicf("Key %s doesn't exist", key)
	}
	return v
}
func (c *Context) SetFinal(key string, value interface{}) error {
	if c.frozenSettings == nil {
		c.frozenSettings = make(map[string]interface{})
	}
	if _, ok := c.frozenSettings[key]; ok {
		return ErrSettingsKey
	}
	c.frozenSettings[key] = value
	return nil
}
func (c *Context) GetFinal(key string) (v interface{}, ok bool) {
	if c.frozenSettings == nil {
		return
	}
	v, ok = c.frozenSettings[key]
	return
}
func (c *Context) MustSetFinal(key string, value interface{}) {
	err := c.SetFinal(key, value)
	if err != nil {
		c.Logger.Panicf("Freeze key %s duplicated!", key)
	}
}
func (c *Context) MustGetFinal(key string) interface{} {
	v, ok := c.GetFinal(key)
	if !ok {
		c.Logger.Panicf("Freeze key %s doesn't exist", key)
	}
	return v
}
func (c *Context) RequestID() string {
	if c.Logger == nil {
		return ""
	}
	return c.Logger.RequestID()
}
func (c *Context) RequestURI() string {
	if c.Request.RequestURI != "" {
		return c.Request.RequestURI
	}
	uri, _ := url.QueryUnescape(c.Request.URL.EscapedPath())
	return uri
}
func (c *Context) HasRawHeader(key string) bool {
	for yek := range c.Request.Header {
		if key == yek {
			return true
		}
	}
	return false
}
func (c *Context) RawHeader(key string) []string {
	for yek, vals := range c.Request.Header {
		if key == yek {
			return vals
		}
	}
	return nil
}
func (c *Context) HasHeader(key string) bool {
	_, ok := c.Request.Header[http.CanonicalHeaderKey(key)]
	return ok
}
func (c *Context) Header(key string) string {
	return c.Request.Header.Get(key)
}
func (c *Context) SetStatus(code int) {
	c.Response.WriteHeader(code)
}
func (c *Context) AddHeader(key, value string) {
	c.Response.Header().Add(key, value)
}
func (c *Context) SetHeader(key, value string) {
	c.Response.Header().Set(key, value)
}