diff --git a/context/context.go b/context/context.go index e2a82652..ee308476 100644 --- a/context/context.go +++ b/context/context.go @@ -6,6 +6,8 @@ import ( "github.com/astaxie/beego/middleware" ) +// Http request context struct including BeegoInput, BeegoOutput, http.Request and http.ResponseWriter. +// BeegoInput and BeegoOutput provides some api to operate request and response more easily. type Context struct { Input *BeegoInput Output *BeegoOutput @@ -13,11 +15,16 @@ type Context struct { ResponseWriter http.ResponseWriter } +// Redirect does redirection to localurl with http header status code. +// It sends http response header directly. func (ctx *Context) Redirect(status int, localurl string) { ctx.Output.Header("Location", localurl) ctx.Output.SetStatus(status) } +// Abort stops this request. +// if middleware.ErrorMaps exists, panic body. +// if middleware.HTTPExceptionMaps exists, panic HTTPException struct with status and body string. func (ctx *Context) Abort(status int, body string) { ctx.Output.SetStatus(status) // first panic from ErrorMaps, is is user defined error functions. @@ -35,14 +42,20 @@ func (ctx *Context) Abort(status int, body string) { panic(body) } +// Write string to response body. +// it sends response body. func (ctx *Context) WriteString(content string) { ctx.Output.Body([]byte(content)) } +// Get cookie from request by a given key. +// It's alias of BeegoInput.Cookie. func (ctx *Context) GetCookie(key string) string { return ctx.Input.Cookie(key) } +// Set cookie for response. +// It's alias of BeegoOutput.Cookie. func (ctx *Context) SetCookie(name string, value string, others ...interface{}) { ctx.Output.Cookie(name, value, others...) } diff --git a/context/input.go b/context/input.go index e9fc5295..308dd77c 100644 --- a/context/input.go +++ b/context/input.go @@ -10,14 +10,17 @@ import ( "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{} + Data map[interface{}]interface{} // store some values in this context when calling context in filter or controller. Request *http.Request RequestBody []byte } +// NewInput return BeegoInput generated by http.Request. func NewInput(req *http.Request) *BeegoInput { return &BeegoInput{ Params: make(map[string]string), @@ -26,22 +29,27 @@ func NewInput(req *http.Request) *BeegoInput { } } +// 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 @@ -52,10 +60,14 @@ func (input *BeegoInput) Scheme() string { } } +// 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, ":") @@ -67,30 +79,39 @@ func (input *BeegoInput) Host() string { 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 } +// 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.Request.MultipartForm != nil } +// 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] != "" { @@ -98,13 +119,14 @@ func (input *BeegoInput) IP() string { } ip := strings.Split(input.Request.RemoteAddr, ":") if len(ip) > 0 { - if 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, ",") @@ -112,15 +134,20 @@ func (input *BeegoInput) Proxy() []string { 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 { @@ -130,10 +157,12 @@ func (input *BeegoInput) Port() int { 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 @@ -141,15 +170,19 @@ func (input *BeegoInput) Param(key string) string { return "" } +// Query returns input data item string by a given string. func (input *BeegoInput) Query(key string) string { 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 { @@ -158,10 +191,12 @@ func (input *BeegoInput) Cookie(key string) string { 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) Body() []byte { requestbody, _ := ioutil.ReadAll(input.Request.Body) input.Request.Body.Close() @@ -171,6 +206,7 @@ func (input *BeegoInput) Body() []byte { 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 @@ -178,6 +214,8 @@ func (input *BeegoInput) GetData(key interface{}) interface{} { 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 } diff --git a/context/output.go b/context/output.go index 60e04ebe..43948e15 100644 --- a/context/output.go +++ b/context/output.go @@ -17,20 +17,27 @@ import ( "strings" ) +// BeegoOutput does work for sending response header. type BeegoOutput struct { Context *Context Status int EnableGzip bool } +// NewOutput returns new BeegoOutput. +// it contains nothing now. func NewOutput() *BeegoOutput { return &BeegoOutput{} } +// Header sets response header item string via given key. func (output *BeegoOutput) Header(key, val string) { output.Context.ResponseWriter.Header().Set(key, val) } +// Body sets response body content. +// if EnableGzip, compress content string. +// it sends out response body directly. func (output *BeegoOutput) Body(content []byte) { output_writer := output.Context.ResponseWriter.(io.Writer) if output.EnableGzip == true && output.Context.Input.Header("Accept-Encoding") != "" { @@ -64,6 +71,8 @@ func (output *BeegoOutput) Body(content []byte) { } } +// Cookie sets cookie value via given key. +// others are ordered as cookie's max age time, path,domain, secure and httponly. func (output *BeegoOutput) Cookie(name string, value string, others ...interface{}) { var b bytes.Buffer fmt.Fprintf(&b, "%s=%s", sanitizeName(name), sanitizeValue(value)) @@ -116,6 +125,8 @@ func sanitizeValue(v string) string { return cookieValueSanitizer.Replace(v) } +// Json writes json to response body. +// if coding is true, it converts utf-8 to \u0000 type. func (output *BeegoOutput) Json(data interface{}, hasIndent bool, coding bool) error { output.Header("Content-Type", "application/json;charset=UTF-8") var content []byte @@ -136,6 +147,7 @@ func (output *BeegoOutput) Json(data interface{}, hasIndent bool, coding bool) e return nil } +// Jsonp writes jsonp to response body. func (output *BeegoOutput) Jsonp(data interface{}, hasIndent bool) error { output.Header("Content-Type", "application/javascript;charset=UTF-8") var content []byte @@ -161,6 +173,7 @@ func (output *BeegoOutput) Jsonp(data interface{}, hasIndent bool) error { return nil } +// Xml writes xml string to response body. func (output *BeegoOutput) Xml(data interface{}, hasIndent bool) error { output.Header("Content-Type", "application/xml;charset=UTF-8") var content []byte @@ -178,6 +191,8 @@ func (output *BeegoOutput) Xml(data interface{}, hasIndent bool) error { return nil } +// Download forces response for download file. +// it prepares the download response header automatically. func (output *BeegoOutput) Download(file string) { output.Header("Content-Description", "File Transfer") output.Header("Content-Type", "application/octet-stream") @@ -189,6 +204,8 @@ func (output *BeegoOutput) Download(file string) { http.ServeFile(output.Context.ResponseWriter, output.Context.Request, file) } +// ContentType sets the content type from ext string. +// MIME type is given in mime package. func (output *BeegoOutput) ContentType(ext string) { if !strings.HasPrefix(ext, ".") { ext = "." + ext @@ -199,43 +216,63 @@ func (output *BeegoOutput) ContentType(ext string) { } } +// SetStatus sets response status code. +// It writes response header directly. func (output *BeegoOutput) SetStatus(status int) { output.Context.ResponseWriter.WriteHeader(status) output.Status = status } +// IsCachable returns boolean of this request is cached. +// HTTP 304 means cached. func (output *BeegoOutput) IsCachable(status int) bool { return output.Status >= 200 && output.Status < 300 || output.Status == 304 } +// IsEmpty returns boolean of this request is empty. +// HTTP 201,204 and 304 means empty. func (output *BeegoOutput) IsEmpty(status int) bool { return output.Status == 201 || output.Status == 204 || output.Status == 304 } +// IsOk returns boolean of this request runs well. +// HTTP 200 means ok. func (output *BeegoOutput) IsOk(status int) bool { return output.Status == 200 } +// IsSuccessful returns boolean of this request runs successfully. +// HTTP 2xx means ok. func (output *BeegoOutput) IsSuccessful(status int) bool { return output.Status >= 200 && output.Status < 300 } +// IsRedirect returns boolean of this request is redirection header. +// HTTP 301,302,307 means redirection. func (output *BeegoOutput) IsRedirect(status int) bool { return output.Status == 301 || output.Status == 302 || output.Status == 303 || output.Status == 307 } +// IsForbidden returns boolean of this request is forbidden. +// HTTP 403 means forbidden. func (output *BeegoOutput) IsForbidden(status int) bool { return output.Status == 403 } +// IsNotFound returns boolean of this request is not found. +// HTTP 404 means forbidden. func (output *BeegoOutput) IsNotFound(status int) bool { return output.Status == 404 } +// IsClient returns boolean of this request client sends error data. +// HTTP 4xx means forbidden. func (output *BeegoOutput) IsClientError(status int) bool { return output.Status >= 400 && output.Status < 500 } +// IsServerError returns boolean of this server handler errors. +// HTTP 5xx means server internal error. func (output *BeegoOutput) IsServerError(status int) bool { return output.Status >= 500 && output.Status < 600 } @@ -254,6 +291,7 @@ func stringsToJson(str string) string { return jsons } +// Sessions sets session item value with given key. func (output *BeegoOutput) Session(name interface{}, value interface{}) { output.Context.Input.CruSession.Set(name, value) }