github.com/astaxie/beego@v1.12.3/controller.go (about)

     1  // Copyright 2014 beego Author. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package beego
    16  
    17  import (
    18  	"bytes"
    19  	"errors"
    20  	"fmt"
    21  	"html/template"
    22  	"io"
    23  	"mime/multipart"
    24  	"net/http"
    25  	"net/url"
    26  	"os"
    27  	"reflect"
    28  	"strconv"
    29  	"strings"
    30  
    31  	"github.com/astaxie/beego/context"
    32  	"github.com/astaxie/beego/context/param"
    33  	"github.com/astaxie/beego/session"
    34  )
    35  
    36  var (
    37  	// ErrAbort custom error when user stop request handler manually.
    38  	ErrAbort = errors.New("user stop run")
    39  	// GlobalControllerRouter store comments with controller. pkgpath+controller:comments
    40  	GlobalControllerRouter = make(map[string][]ControllerComments)
    41  )
    42  
    43  // ControllerFilter store the filter for controller
    44  type ControllerFilter struct {
    45  	Pattern        string
    46  	Pos            int
    47  	Filter         FilterFunc
    48  	ReturnOnOutput bool
    49  	ResetParams    bool
    50  }
    51  
    52  // ControllerFilterComments store the comment for controller level filter
    53  type ControllerFilterComments struct {
    54  	Pattern        string
    55  	Pos            int
    56  	Filter         string // NOQA
    57  	ReturnOnOutput bool
    58  	ResetParams    bool
    59  }
    60  
    61  // ControllerImportComments store the import comment for controller needed
    62  type ControllerImportComments struct {
    63  	ImportPath  string
    64  	ImportAlias string
    65  }
    66  
    67  // ControllerComments store the comment for the controller method
    68  type ControllerComments struct {
    69  	Method           string
    70  	Router           string
    71  	Filters          []*ControllerFilter
    72  	ImportComments   []*ControllerImportComments
    73  	FilterComments   []*ControllerFilterComments
    74  	AllowHTTPMethods []string
    75  	Params           []map[string]string
    76  	MethodParams     []*param.MethodParam
    77  }
    78  
    79  // ControllerCommentsSlice implements the sort interface
    80  type ControllerCommentsSlice []ControllerComments
    81  
    82  func (p ControllerCommentsSlice) Len() int           { return len(p) }
    83  func (p ControllerCommentsSlice) Less(i, j int) bool { return p[i].Router < p[j].Router }
    84  func (p ControllerCommentsSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
    85  
    86  // Controller defines some basic http request handler operations, such as
    87  // http context, template and view, session and xsrf.
    88  type Controller struct {
    89  	// context data
    90  	Ctx  *context.Context
    91  	Data map[interface{}]interface{}
    92  
    93  	// route controller info
    94  	controllerName string
    95  	actionName     string
    96  	methodMapping  map[string]func() //method:routertree
    97  	AppController  interface{}
    98  
    99  	// template data
   100  	TplName        string
   101  	ViewPath       string
   102  	Layout         string
   103  	LayoutSections map[string]string // the key is the section name and the value is the template name
   104  	TplPrefix      string
   105  	TplExt         string
   106  	EnableRender   bool
   107  
   108  	// xsrf data
   109  	_xsrfToken string
   110  	XSRFExpire int
   111  	EnableXSRF bool
   112  
   113  	// session
   114  	CruSession session.Store
   115  }
   116  
   117  // ControllerInterface is an interface to uniform all controller handler.
   118  type ControllerInterface interface {
   119  	Init(ct *context.Context, controllerName, actionName string, app interface{})
   120  	Prepare()
   121  	Get()
   122  	Post()
   123  	Delete()
   124  	Put()
   125  	Head()
   126  	Patch()
   127  	Options()
   128  	Trace()
   129  	Finish()
   130  	Render() error
   131  	XSRFToken() string
   132  	CheckXSRFCookie() bool
   133  	HandlerFunc(fn string) bool
   134  	URLMapping()
   135  }
   136  
   137  // Init generates default values of controller operations.
   138  func (c *Controller) Init(ctx *context.Context, controllerName, actionName string, app interface{}) {
   139  	c.Layout = ""
   140  	c.TplName = ""
   141  	c.controllerName = controllerName
   142  	c.actionName = actionName
   143  	c.Ctx = ctx
   144  	c.TplExt = "tpl"
   145  	c.AppController = app
   146  	c.EnableRender = true
   147  	c.EnableXSRF = true
   148  	c.Data = ctx.Input.Data()
   149  	c.methodMapping = make(map[string]func())
   150  }
   151  
   152  // Prepare runs after Init before request function execution.
   153  func (c *Controller) Prepare() {}
   154  
   155  // Finish runs after request function execution.
   156  func (c *Controller) Finish() {}
   157  
   158  // Get adds a request function to handle GET request.
   159  func (c *Controller) Get() {
   160  	http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", http.StatusMethodNotAllowed)
   161  }
   162  
   163  // Post adds a request function to handle POST request.
   164  func (c *Controller) Post() {
   165  	http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", http.StatusMethodNotAllowed)
   166  }
   167  
   168  // Delete adds a request function to handle DELETE request.
   169  func (c *Controller) Delete() {
   170  	http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", http.StatusMethodNotAllowed)
   171  }
   172  
   173  // Put adds a request function to handle PUT request.
   174  func (c *Controller) Put() {
   175  	http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", http.StatusMethodNotAllowed)
   176  }
   177  
   178  // Head adds a request function to handle HEAD request.
   179  func (c *Controller) Head() {
   180  	http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", http.StatusMethodNotAllowed)
   181  }
   182  
   183  // Patch adds a request function to handle PATCH request.
   184  func (c *Controller) Patch() {
   185  	http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", http.StatusMethodNotAllowed)
   186  }
   187  
   188  // Options adds a request function to handle OPTIONS request.
   189  func (c *Controller) Options() {
   190  	http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", http.StatusMethodNotAllowed)
   191  }
   192  
   193  // Trace adds a request function to handle Trace request.
   194  // this method SHOULD NOT be overridden.
   195  // https://tools.ietf.org/html/rfc7231#section-4.3.8
   196  // The TRACE method requests a remote, application-level loop-back of
   197  // the request message.  The final recipient of the request SHOULD
   198  // reflect the message received, excluding some fields described below,
   199  // back to the client as the message body of a 200 (OK) response with a
   200  // Content-Type of "message/http" (Section 8.3.1 of [RFC7230]).
   201  func (c *Controller) Trace() {
   202  	ts := func(h http.Header) (hs string) {
   203  		for k, v := range h {
   204  			hs += fmt.Sprintf("\r\n%s: %s", k, v)
   205  		}
   206  		return
   207  	}
   208  	hs := fmt.Sprintf("\r\nTRACE %s %s%s\r\n", c.Ctx.Request.RequestURI, c.Ctx.Request.Proto, ts(c.Ctx.Request.Header))
   209  	c.Ctx.Output.Header("Content-Type", "message/http")
   210  	c.Ctx.Output.Header("Content-Length", fmt.Sprint(len(hs)))
   211  	c.Ctx.Output.Header("Cache-Control", "no-cache, no-store, must-revalidate")
   212  	c.Ctx.WriteString(hs)
   213  }
   214  
   215  // HandlerFunc call function with the name
   216  func (c *Controller) HandlerFunc(fnname string) bool {
   217  	if v, ok := c.methodMapping[fnname]; ok {
   218  		v()
   219  		return true
   220  	}
   221  	return false
   222  }
   223  
   224  // URLMapping register the internal Controller router.
   225  func (c *Controller) URLMapping() {}
   226  
   227  // Mapping the method to function
   228  func (c *Controller) Mapping(method string, fn func()) {
   229  	c.methodMapping[method] = fn
   230  }
   231  
   232  // Render sends the response with rendered template bytes as text/html type.
   233  func (c *Controller) Render() error {
   234  	if !c.EnableRender {
   235  		return nil
   236  	}
   237  	rb, err := c.RenderBytes()
   238  	if err != nil {
   239  		return err
   240  	}
   241  
   242  	if c.Ctx.ResponseWriter.Header().Get("Content-Type") == "" {
   243  		c.Ctx.Output.Header("Content-Type", "text/html; charset=utf-8")
   244  	}
   245  
   246  	return c.Ctx.Output.Body(rb)
   247  }
   248  
   249  // RenderString returns the rendered template string. Do not send out response.
   250  func (c *Controller) RenderString() (string, error) {
   251  	b, e := c.RenderBytes()
   252  	return string(b), e
   253  }
   254  
   255  // RenderBytes returns the bytes of rendered template string. Do not send out response.
   256  func (c *Controller) RenderBytes() ([]byte, error) {
   257  	buf, err := c.renderTemplate()
   258  	//if the controller has set layout, then first get the tplName's content set the content to the layout
   259  	if err == nil && c.Layout != "" {
   260  		c.Data["LayoutContent"] = template.HTML(buf.String())
   261  
   262  		if c.LayoutSections != nil {
   263  			for sectionName, sectionTpl := range c.LayoutSections {
   264  				if sectionTpl == "" {
   265  					c.Data[sectionName] = ""
   266  					continue
   267  				}
   268  				buf.Reset()
   269  				err = ExecuteViewPathTemplate(&buf, sectionTpl, c.viewPath(), c.Data)
   270  				if err != nil {
   271  					return nil, err
   272  				}
   273  				c.Data[sectionName] = template.HTML(buf.String())
   274  			}
   275  		}
   276  
   277  		buf.Reset()
   278  		ExecuteViewPathTemplate(&buf, c.Layout, c.viewPath(), c.Data)
   279  	}
   280  	return buf.Bytes(), err
   281  }
   282  
   283  func (c *Controller) renderTemplate() (bytes.Buffer, error) {
   284  	var buf bytes.Buffer
   285  	if c.TplName == "" {
   286  		c.TplName = strings.ToLower(c.controllerName) + "/" + strings.ToLower(c.actionName) + "." + c.TplExt
   287  	}
   288  	if c.TplPrefix != "" {
   289  		c.TplName = c.TplPrefix + c.TplName
   290  	}
   291  	if BConfig.RunMode == DEV {
   292  		buildFiles := []string{c.TplName}
   293  		if c.Layout != "" {
   294  			buildFiles = append(buildFiles, c.Layout)
   295  			if c.LayoutSections != nil {
   296  				for _, sectionTpl := range c.LayoutSections {
   297  					if sectionTpl == "" {
   298  						continue
   299  					}
   300  					buildFiles = append(buildFiles, sectionTpl)
   301  				}
   302  			}
   303  		}
   304  		BuildTemplate(c.viewPath(), buildFiles...)
   305  	}
   306  	return buf, ExecuteViewPathTemplate(&buf, c.TplName, c.viewPath(), c.Data)
   307  }
   308  
   309  func (c *Controller) viewPath() string {
   310  	if c.ViewPath == "" {
   311  		return BConfig.WebConfig.ViewsPath
   312  	}
   313  	return c.ViewPath
   314  }
   315  
   316  // Redirect sends the redirection response to url with status code.
   317  func (c *Controller) Redirect(url string, code int) {
   318  	LogAccess(c.Ctx, nil, code)
   319  	c.Ctx.Redirect(code, url)
   320  }
   321  
   322  // SetData set the data depending on the accepted
   323  func (c *Controller) SetData(data interface{}) {
   324  	accept := c.Ctx.Input.Header("Accept")
   325  	switch accept {
   326  	case context.ApplicationYAML:
   327  		c.Data["yaml"] = data
   328  	case context.ApplicationXML, context.TextXML:
   329  		c.Data["xml"] = data
   330  	default:
   331  		c.Data["json"] = data
   332  	}
   333  }
   334  
   335  // Abort stops controller handler and show the error data if code is defined in ErrorMap or code string.
   336  func (c *Controller) Abort(code string) {
   337  	status, err := strconv.Atoi(code)
   338  	if err != nil {
   339  		status = 200
   340  	}
   341  	c.CustomAbort(status, code)
   342  }
   343  
   344  // CustomAbort stops controller handler and show the error data, it's similar Aborts, but support status code and body.
   345  func (c *Controller) CustomAbort(status int, body string) {
   346  	// first panic from ErrorMaps, it is user defined error functions.
   347  	if _, ok := ErrorMaps[body]; ok {
   348  		c.Ctx.Output.Status = status
   349  		panic(body)
   350  	}
   351  	// last panic user string
   352  	c.Ctx.ResponseWriter.WriteHeader(status)
   353  	c.Ctx.ResponseWriter.Write([]byte(body))
   354  	panic(ErrAbort)
   355  }
   356  
   357  // StopRun makes panic of USERSTOPRUN error and go to recover function if defined.
   358  func (c *Controller) StopRun() {
   359  	panic(ErrAbort)
   360  }
   361  
   362  // URLFor does another controller handler in this request function.
   363  // it goes to this controller method if endpoint is not clear.
   364  func (c *Controller) URLFor(endpoint string, values ...interface{}) string {
   365  	if len(endpoint) == 0 {
   366  		return ""
   367  	}
   368  	if endpoint[0] == '.' {
   369  		return URLFor(reflect.Indirect(reflect.ValueOf(c.AppController)).Type().Name()+endpoint, values...)
   370  	}
   371  	return URLFor(endpoint, values...)
   372  }
   373  
   374  // ServeJSON sends a json response with encoding charset.
   375  func (c *Controller) ServeJSON(encoding ...bool) {
   376  	var (
   377  		hasIndent   = BConfig.RunMode != PROD
   378  		hasEncoding = len(encoding) > 0 && encoding[0]
   379  	)
   380  
   381  	c.Ctx.Output.JSON(c.Data["json"], hasIndent, hasEncoding)
   382  }
   383  
   384  // ServeJSONP sends a jsonp response.
   385  func (c *Controller) ServeJSONP() {
   386  	hasIndent := BConfig.RunMode != PROD
   387  	c.Ctx.Output.JSONP(c.Data["jsonp"], hasIndent)
   388  }
   389  
   390  // ServeXML sends xml response.
   391  func (c *Controller) ServeXML() {
   392  	hasIndent := BConfig.RunMode != PROD
   393  	c.Ctx.Output.XML(c.Data["xml"], hasIndent)
   394  }
   395  
   396  // ServeYAML sends yaml response.
   397  func (c *Controller) ServeYAML() {
   398  	c.Ctx.Output.YAML(c.Data["yaml"])
   399  }
   400  
   401  // ServeFormatted serve YAML, XML OR JSON, depending on the value of the Accept header
   402  func (c *Controller) ServeFormatted(encoding ...bool) {
   403  	hasIndent := BConfig.RunMode != PROD
   404  	hasEncoding := len(encoding) > 0 && encoding[0]
   405  	c.Ctx.Output.ServeFormatted(c.Data, hasIndent, hasEncoding)
   406  }
   407  
   408  // Input returns the input data map from POST or PUT request body and query string.
   409  func (c *Controller) Input() url.Values {
   410  	if c.Ctx.Request.Form == nil {
   411  		c.Ctx.Request.ParseForm()
   412  	}
   413  	return c.Ctx.Request.Form
   414  }
   415  
   416  // ParseForm maps input data map to obj struct.
   417  func (c *Controller) ParseForm(obj interface{}) error {
   418  	return ParseForm(c.Input(), obj)
   419  }
   420  
   421  // GetString returns the input value by key string or the default value while it's present and input is blank
   422  func (c *Controller) GetString(key string, def ...string) string {
   423  	if v := c.Ctx.Input.Query(key); v != "" {
   424  		return v
   425  	}
   426  	if len(def) > 0 {
   427  		return def[0]
   428  	}
   429  	return ""
   430  }
   431  
   432  // GetStrings returns the input string slice by key string or the default value while it's present and input is blank
   433  // it's designed for multi-value input field such as checkbox(input[type=checkbox]), multi-selection.
   434  func (c *Controller) GetStrings(key string, def ...[]string) []string {
   435  	var defv []string
   436  	if len(def) > 0 {
   437  		defv = def[0]
   438  	}
   439  
   440  	if f := c.Input(); f == nil {
   441  		return defv
   442  	} else if vs := f[key]; len(vs) > 0 {
   443  		return vs
   444  	}
   445  
   446  	return defv
   447  }
   448  
   449  // GetInt returns input as an int or the default value while it's present and input is blank
   450  func (c *Controller) GetInt(key string, def ...int) (int, error) {
   451  	strv := c.Ctx.Input.Query(key)
   452  	if len(strv) == 0 && len(def) > 0 {
   453  		return def[0], nil
   454  	}
   455  	return strconv.Atoi(strv)
   456  }
   457  
   458  // GetInt8 return input as an int8 or the default value while it's present and input is blank
   459  func (c *Controller) GetInt8(key string, def ...int8) (int8, error) {
   460  	strv := c.Ctx.Input.Query(key)
   461  	if len(strv) == 0 && len(def) > 0 {
   462  		return def[0], nil
   463  	}
   464  	i64, err := strconv.ParseInt(strv, 10, 8)
   465  	return int8(i64), err
   466  }
   467  
   468  // GetUint8 return input as an uint8 or the default value while it's present and input is blank
   469  func (c *Controller) GetUint8(key string, def ...uint8) (uint8, error) {
   470  	strv := c.Ctx.Input.Query(key)
   471  	if len(strv) == 0 && len(def) > 0 {
   472  		return def[0], nil
   473  	}
   474  	u64, err := strconv.ParseUint(strv, 10, 8)
   475  	return uint8(u64), err
   476  }
   477  
   478  // GetInt16 returns input as an int16 or the default value while it's present and input is blank
   479  func (c *Controller) GetInt16(key string, def ...int16) (int16, error) {
   480  	strv := c.Ctx.Input.Query(key)
   481  	if len(strv) == 0 && len(def) > 0 {
   482  		return def[0], nil
   483  	}
   484  	i64, err := strconv.ParseInt(strv, 10, 16)
   485  	return int16(i64), err
   486  }
   487  
   488  // GetUint16 returns input as an uint16 or the default value while it's present and input is blank
   489  func (c *Controller) GetUint16(key string, def ...uint16) (uint16, error) {
   490  	strv := c.Ctx.Input.Query(key)
   491  	if len(strv) == 0 && len(def) > 0 {
   492  		return def[0], nil
   493  	}
   494  	u64, err := strconv.ParseUint(strv, 10, 16)
   495  	return uint16(u64), err
   496  }
   497  
   498  // GetInt32 returns input as an int32 or the default value while it's present and input is blank
   499  func (c *Controller) GetInt32(key string, def ...int32) (int32, error) {
   500  	strv := c.Ctx.Input.Query(key)
   501  	if len(strv) == 0 && len(def) > 0 {
   502  		return def[0], nil
   503  	}
   504  	i64, err := strconv.ParseInt(strv, 10, 32)
   505  	return int32(i64), err
   506  }
   507  
   508  // GetUint32 returns input as an uint32 or the default value while it's present and input is blank
   509  func (c *Controller) GetUint32(key string, def ...uint32) (uint32, error) {
   510  	strv := c.Ctx.Input.Query(key)
   511  	if len(strv) == 0 && len(def) > 0 {
   512  		return def[0], nil
   513  	}
   514  	u64, err := strconv.ParseUint(strv, 10, 32)
   515  	return uint32(u64), err
   516  }
   517  
   518  // GetInt64 returns input value as int64 or the default value while it's present and input is blank.
   519  func (c *Controller) GetInt64(key string, def ...int64) (int64, error) {
   520  	strv := c.Ctx.Input.Query(key)
   521  	if len(strv) == 0 && len(def) > 0 {
   522  		return def[0], nil
   523  	}
   524  	return strconv.ParseInt(strv, 10, 64)
   525  }
   526  
   527  // GetUint64 returns input value as uint64 or the default value while it's present and input is blank.
   528  func (c *Controller) GetUint64(key string, def ...uint64) (uint64, error) {
   529  	strv := c.Ctx.Input.Query(key)
   530  	if len(strv) == 0 && len(def) > 0 {
   531  		return def[0], nil
   532  	}
   533  	return strconv.ParseUint(strv, 10, 64)
   534  }
   535  
   536  // GetBool returns input value as bool or the default value while it's present and input is blank.
   537  func (c *Controller) GetBool(key string, def ...bool) (bool, error) {
   538  	strv := c.Ctx.Input.Query(key)
   539  	if len(strv) == 0 && len(def) > 0 {
   540  		return def[0], nil
   541  	}
   542  	return strconv.ParseBool(strv)
   543  }
   544  
   545  // GetFloat returns input value as float64 or the default value while it's present and input is blank.
   546  func (c *Controller) GetFloat(key string, def ...float64) (float64, error) {
   547  	strv := c.Ctx.Input.Query(key)
   548  	if len(strv) == 0 && len(def) > 0 {
   549  		return def[0], nil
   550  	}
   551  	return strconv.ParseFloat(strv, 64)
   552  }
   553  
   554  // GetFile returns the file data in file upload field named as key.
   555  // it returns the first one of multi-uploaded files.
   556  func (c *Controller) GetFile(key string) (multipart.File, *multipart.FileHeader, error) {
   557  	return c.Ctx.Request.FormFile(key)
   558  }
   559  
   560  // GetFiles return multi-upload files
   561  // files, err:=c.GetFiles("myfiles")
   562  //	if err != nil {
   563  //		http.Error(w, err.Error(), http.StatusNoContent)
   564  //		return
   565  //	}
   566  // for i, _ := range files {
   567  //	//for each fileheader, get a handle to the actual file
   568  //	file, err := files[i].Open()
   569  //	defer file.Close()
   570  //	if err != nil {
   571  //		http.Error(w, err.Error(), http.StatusInternalServerError)
   572  //		return
   573  //	}
   574  //	//create destination file making sure the path is writeable.
   575  //	dst, err := os.Create("upload/" + files[i].Filename)
   576  //	defer dst.Close()
   577  //	if err != nil {
   578  //		http.Error(w, err.Error(), http.StatusInternalServerError)
   579  //		return
   580  //	}
   581  //	//copy the uploaded file to the destination file
   582  //	if _, err := io.Copy(dst, file); err != nil {
   583  //		http.Error(w, err.Error(), http.StatusInternalServerError)
   584  //		return
   585  //	}
   586  // }
   587  func (c *Controller) GetFiles(key string) ([]*multipart.FileHeader, error) {
   588  	if files, ok := c.Ctx.Request.MultipartForm.File[key]; ok {
   589  		return files, nil
   590  	}
   591  	return nil, http.ErrMissingFile
   592  }
   593  
   594  // SaveToFile saves uploaded file to new path.
   595  // it only operates the first one of mutil-upload form file field.
   596  func (c *Controller) SaveToFile(fromfile, tofile string) error {
   597  	file, _, err := c.Ctx.Request.FormFile(fromfile)
   598  	if err != nil {
   599  		return err
   600  	}
   601  	defer file.Close()
   602  	f, err := os.OpenFile(tofile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
   603  	if err != nil {
   604  		return err
   605  	}
   606  	defer f.Close()
   607  	io.Copy(f, file)
   608  	return nil
   609  }
   610  
   611  // StartSession starts session and load old session data info this controller.
   612  func (c *Controller) StartSession() session.Store {
   613  	if c.CruSession == nil {
   614  		c.CruSession = c.Ctx.Input.CruSession
   615  	}
   616  	return c.CruSession
   617  }
   618  
   619  // SetSession puts value into session.
   620  func (c *Controller) SetSession(name interface{}, value interface{}) {
   621  	if c.CruSession == nil {
   622  		c.StartSession()
   623  	}
   624  	c.CruSession.Set(name, value)
   625  }
   626  
   627  // GetSession gets value from session.
   628  func (c *Controller) GetSession(name interface{}) interface{} {
   629  	if c.CruSession == nil {
   630  		c.StartSession()
   631  	}
   632  	return c.CruSession.Get(name)
   633  }
   634  
   635  // DelSession removes value from session.
   636  func (c *Controller) DelSession(name interface{}) {
   637  	if c.CruSession == nil {
   638  		c.StartSession()
   639  	}
   640  	c.CruSession.Delete(name)
   641  }
   642  
   643  // SessionRegenerateID regenerates session id for this session.
   644  // the session data have no changes.
   645  func (c *Controller) SessionRegenerateID() {
   646  	if c.CruSession != nil {
   647  		c.CruSession.SessionRelease(c.Ctx.ResponseWriter)
   648  	}
   649  	c.CruSession = GlobalSessions.SessionRegenerateID(c.Ctx.ResponseWriter, c.Ctx.Request)
   650  	c.Ctx.Input.CruSession = c.CruSession
   651  }
   652  
   653  // DestroySession cleans session data and session cookie.
   654  func (c *Controller) DestroySession() {
   655  	c.Ctx.Input.CruSession.Flush()
   656  	c.Ctx.Input.CruSession = nil
   657  	GlobalSessions.SessionDestroy(c.Ctx.ResponseWriter, c.Ctx.Request)
   658  }
   659  
   660  // IsAjax returns this request is ajax or not.
   661  func (c *Controller) IsAjax() bool {
   662  	return c.Ctx.Input.IsAjax()
   663  }
   664  
   665  // GetSecureCookie returns decoded cookie value from encoded browser cookie values.
   666  func (c *Controller) GetSecureCookie(Secret, key string) (string, bool) {
   667  	return c.Ctx.GetSecureCookie(Secret, key)
   668  }
   669  
   670  // SetSecureCookie puts value into cookie after encoded the value.
   671  func (c *Controller) SetSecureCookie(Secret, name, value string, others ...interface{}) {
   672  	c.Ctx.SetSecureCookie(Secret, name, value, others...)
   673  }
   674  
   675  // XSRFToken creates a CSRF token string and returns.
   676  func (c *Controller) XSRFToken() string {
   677  	if c._xsrfToken == "" {
   678  		expire := int64(BConfig.WebConfig.XSRFExpire)
   679  		if c.XSRFExpire > 0 {
   680  			expire = int64(c.XSRFExpire)
   681  		}
   682  		c._xsrfToken = c.Ctx.XSRFToken(BConfig.WebConfig.XSRFKey, expire)
   683  	}
   684  	return c._xsrfToken
   685  }
   686  
   687  // CheckXSRFCookie checks xsrf token in this request is valid or not.
   688  // the token can provided in request header "X-Xsrftoken" and "X-CsrfToken"
   689  // or in form field value named as "_xsrf".
   690  func (c *Controller) CheckXSRFCookie() bool {
   691  	if !c.EnableXSRF {
   692  		return true
   693  	}
   694  	return c.Ctx.CheckXSRFCookie()
   695  }
   696  
   697  // XSRFFormHTML writes an input field contains xsrf token value.
   698  func (c *Controller) XSRFFormHTML() string {
   699  	return `<input type="hidden" name="_xsrf" value="` +
   700  		c.XSRFToken() + `" />`
   701  }
   702  
   703  // GetControllerAndAction gets the executing controller name and action name.
   704  func (c *Controller) GetControllerAndAction() (string, string) {
   705  	return c.controllerName, c.actionName
   706  }