123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230 |
- package context
- import (
- "bufio"
- "crypto/hmac"
- "crypto/sha1"
- "encoding/base64"
- "errors"
- "fmt"
- "net"
- "net/http"
- "strconv"
- "strings"
- "time"
- "github.com/astaxie/beego/utils"
- )
- func NewContext() *Context {
- return &Context{
- Input: NewInput(),
- Output: NewOutput(),
- }
- }
- type Context struct {
- Input *BeegoInput
- Output *BeegoOutput
- Request *http.Request
- ResponseWriter *Response
- _xsrfToken string
- }
- func (ctx *Context) Reset(rw http.ResponseWriter, r *http.Request) {
- ctx.Request = r
- if ctx.ResponseWriter == nil {
- ctx.ResponseWriter = &Response{}
- }
- ctx.ResponseWriter.reset(rw)
- ctx.Input.Reset(ctx)
- ctx.Output.Reset(ctx)
- ctx._xsrfToken = ""
- }
- func (ctx *Context) Redirect(status int, localurl string) {
- http.Redirect(ctx.ResponseWriter, ctx.Request, localurl, status)
- }
- func (ctx *Context) Abort(status int, body string) {
- ctx.Output.SetStatus(status)
- panic(body)
- }
- func (ctx *Context) WriteString(content string) {
- ctx.ResponseWriter.Write([]byte(content))
- }
- func (ctx *Context) GetCookie(key string) string {
- return ctx.Input.Cookie(key)
- }
- func (ctx *Context) SetCookie(name string, value string, others ...interface{}) {
- ctx.Output.Cookie(name, value, others...)
- }
- func (ctx *Context) GetSecureCookie(Secret, key string) (string, bool) {
- val := ctx.Input.Cookie(key)
- if val == "" {
- return "", false
- }
- parts := strings.SplitN(val, "|", 3)
- if len(parts) != 3 {
- return "", false
- }
- vs := parts[0]
- timestamp := parts[1]
- sig := parts[2]
- h := hmac.New(sha1.New, []byte(Secret))
- fmt.Fprintf(h, "%s%s", vs, timestamp)
- if fmt.Sprintf("%02x", h.Sum(nil)) != sig {
- return "", false
- }
- res, _ := base64.URLEncoding.DecodeString(vs)
- return string(res), true
- }
- func (ctx *Context) SetSecureCookie(Secret, name, value string, others ...interface{}) {
- vs := base64.URLEncoding.EncodeToString([]byte(value))
- timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
- h := hmac.New(sha1.New, []byte(Secret))
- fmt.Fprintf(h, "%s%s", vs, timestamp)
- sig := fmt.Sprintf("%02x", h.Sum(nil))
- cookie := strings.Join([]string{vs, timestamp, sig}, "|")
- ctx.Output.Cookie(name, cookie, others...)
- }
- func (ctx *Context) XSRFToken(key string, expire int64) string {
- if ctx._xsrfToken == "" {
- token, ok := ctx.GetSecureCookie(key, "_xsrf")
- if !ok {
- token = string(utils.RandomCreateBytes(32))
- ctx.SetSecureCookie(key, "_xsrf", token, expire)
- }
- ctx._xsrfToken = token
- }
- return ctx._xsrfToken
- }
- func (ctx *Context) CheckXSRFCookie() bool {
- token := ctx.Input.Query("_xsrf")
- if token == "" {
- token = ctx.Request.Header.Get("X-Xsrftoken")
- }
- if token == "" {
- token = ctx.Request.Header.Get("X-Csrftoken")
- }
- if token == "" {
- ctx.Abort(403, "'_xsrf' argument missing from POST")
- return false
- }
- if ctx._xsrfToken != token {
- ctx.Abort(403, "XSRF cookie does not match POST argument")
- return false
- }
- return true
- }
- type Response struct {
- http.ResponseWriter
- Started bool
- Status int
- }
- func (r *Response) reset(rw http.ResponseWriter) {
- r.ResponseWriter = rw
- r.Status = 0
- r.Started = false
- }
- func (r *Response) Write(p []byte) (int, error) {
- r.Started = true
- return r.ResponseWriter.Write(p)
- }
- func (r *Response) WriteHeader(code int) {
- if r.Status > 0 {
-
- return
- }
- r.Status = code
- r.Started = true
- r.ResponseWriter.WriteHeader(code)
- }
- func (r *Response) Hijack() (net.Conn, *bufio.ReadWriter, error) {
- hj, ok := r.ResponseWriter.(http.Hijacker)
- if !ok {
- return nil, nil, errors.New("webserver doesn't support hijacking")
- }
- return hj.Hijack()
- }
- func (r *Response) Flush() {
- if f, ok := r.ResponseWriter.(http.Flusher); ok {
- f.Flush()
- }
- }
- func (r *Response) CloseNotify() <-chan bool {
- if cn, ok := r.ResponseWriter.(http.CloseNotifier); ok {
- return cn.CloseNotify()
- }
- return nil
- }
|