package context import ( "bytes" "errors" "io/ioutil" "net/http" "reflect" "strconv" "strings" "github.com/astaxie/beego/session" ) // BeegoInput operates the http request header ,data ,cookie and body. // it also contains router params and current session. type BeegoInput struct { CruSession session.SessionStore Params map[string]string Data map[interface{}]interface{} // store some values in this context when calling context in filter or controller. Request *http.Request RequestBody []byte RunController reflect.Type RunMethod string } // NewInput return BeegoInput generated by http.Request. func NewInput(req *http.Request) *BeegoInput { return &BeegoInput{ Params: make(map[string]string), Data: make(map[interface{}]interface{}), Request: req, } } // Protocol returns request protocol name, such as HTTP/1.1 . func (input *BeegoInput) Protocol() string { return input.Request.Proto } // Uri returns full request url with query string, fragment. func (input *BeegoInput) Uri() string { return input.Request.RequestURI } // Url returns request url path (without query string, fragment). func (input *BeegoInput) Url() string { return input.Request.URL.String() } // Site returns base site url as scheme://domain type. func (input *BeegoInput) Site() string { return input.Scheme() + "://" + input.Domain() } // Scheme returns request scheme as "http" or "https". func (input *BeegoInput) Scheme() string { if input.Request.URL.Scheme != "" { return input.Request.URL.Scheme } else if input.Request.TLS == nil { return "http" } else { return "https" } } // Domain returns host name. // Alias of Host method. func (input *BeegoInput) Domain() string { return input.Host() } // Host returns host name. // if no host info in request, return localhost. func (input *BeegoInput) Host() string { if input.Request.Host != "" { hostParts := strings.Split(input.Request.Host, ":") if len(hostParts) > 0 { return hostParts[0] } return input.Request.Host } return "localhost" } // Method returns http request method. func (input *BeegoInput) Method() string { return input.Request.Method } // Is returns boolean of this request is on given method, such as Is("POST"). func (input *BeegoInput) Is(method string) bool { return input.Method() == method } // Is this a GET method request? func (input *BeegoInput) IsGet() bool { return input.Is("GET") } // Is this a POST method request? func (input *BeegoInput) IsPost() bool { return input.Is("POST") } // Is this a Head method request? func (input *BeegoInput) IsHead() bool { return input.Is("HEAD") } // Is this a OPTIONS method request? func (input *BeegoInput) IsOptions() bool { return input.Is("OPTIONS") } // Is this a PUT method request? func (input *BeegoInput) IsPut() bool { return input.Is("PUT") } // Is this a DELETE method request? func (input *BeegoInput) IsDelete() bool { return input.Is("DELETE") } // Is this a PATCH method request? func (input *BeegoInput) IsPatch() bool { return input.Is("PATCH") } // IsAjax returns boolean of this request is generated by ajax. func (input *BeegoInput) IsAjax() bool { return input.Header("X-Requested-With") == "XMLHttpRequest" } // IsSecure returns boolean of this request is in https. func (input *BeegoInput) IsSecure() bool { return input.Scheme() == "https" } // IsSecure returns boolean of this request is in webSocket. func (input *BeegoInput) IsWebsocket() bool { return input.Header("Upgrade") == "websocket" } // IsSecure returns boolean of whether file uploads in this request or not.. func (input *BeegoInput) IsUpload() bool { return input.Header("Content-Type") == "multipart/form-data" } // IP returns request client ip. // if in proxy, return first proxy id. // if error, return 127.0.0.1. func (input *BeegoInput) IP() string { ips := input.Proxy() if len(ips) > 0 && ips[0] != "" { return ips[0] } ip := strings.Split(input.Request.RemoteAddr, ":") if len(ip) > 0 { if ip[0] != "[" { return ip[0] } } return "127.0.0.1" } // Proxy returns proxy client ips slice. func (input *BeegoInput) Proxy() []string { if ips := input.Header("X-Forwarded-For"); ips != "" { return strings.Split(ips, ",") } return []string{} } // Refer returns http referer header. func (input *BeegoInput) Refer() string { return input.Header("Referer") } // SubDomains returns sub domain string. // if aa.bb.domain.com, returns aa.bb . func (input *BeegoInput) SubDomains() string { parts := strings.Split(input.Host(), ".") return strings.Join(parts[len(parts)-2:], ".") } // Port returns request client port. // when error or empty, return 80. func (input *BeegoInput) Port() int { parts := strings.Split(input.Request.Host, ":") if len(parts) == 2 { port, _ := strconv.Atoi(parts[1]) return port } return 80 } // UserAgent returns request client user agent string. func (input *BeegoInput) UserAgent() string { return input.Header("User-Agent") } // Param returns router param by a given key. func (input *BeegoInput) Param(key string) string { if v, ok := input.Params[key]; ok { return v } return "" } // Query returns input data item string by a given string. func (input *BeegoInput) Query(key string) string { if val := input.Param(key); val != "" { return val } if input.Request.Form == nil { input.Request.ParseForm() } return input.Request.Form.Get(key) } // Header returns request header item string by a given string. func (input *BeegoInput) Header(key string) string { return input.Request.Header.Get(key) } // Cookie returns request cookie item string by a given key. // if non-existed, return empty string. func (input *BeegoInput) Cookie(key string) string { ck, err := input.Request.Cookie(key) if err != nil { return "" } return ck.Value } // Session returns current session item value by a given key. func (input *BeegoInput) Session(key interface{}) interface{} { return input.CruSession.Get(key) } // Body returns the raw request body data as bytes. func (input *BeegoInput) CopyBody() []byte { requestbody, _ := ioutil.ReadAll(input.Request.Body) input.Request.Body.Close() bf := bytes.NewBuffer(requestbody) input.Request.Body = ioutil.NopCloser(bf) input.RequestBody = requestbody return requestbody } // GetData returns the stored data in this context. func (input *BeegoInput) GetData(key interface{}) interface{} { if v, ok := input.Data[key]; ok { return v } return nil } // SetData stores data with given key in this context. // This data are only available in this context. func (input *BeegoInput) SetData(key, val interface{}) { input.Data[key] = val } // parseForm or parseMultiForm based on Content-type func (input *BeegoInput) ParseFormOrMulitForm(maxMemory int64) error { // Parse the body depending on the content type. if strings.Contains(input.Header("Content-Type"), "multipart/form-data") { if err := input.Request.ParseMultipartForm(maxMemory); err != nil { return errors.New("Error parsing request body:" + err.Error()) } } else if err := input.Request.ParseForm(); err != nil { return errors.New("Error parsing request body:" + err.Error()) } return nil }