1 // Copyright (c) 2012-2017 The Revel Framework Authors, All rights reserved.
2 // Revel Framework source code and usage is governed by a MIT style
3 // license that can be found in the LICENSE file.
17 // Params provides a unified view of the request params.
23 // Warning: param maps other than Values may be nil if there were none.
25 url.Values // A unified view of all the individual param maps below.
28 Fixed url.Values // Fixed parameters from the route, e.g. App.Action("fixed param")
29 Route url.Values // Parameters extracted from the route, e.g. /customers/{id}
31 // Set by the ParamsFilter
32 Query url.Values // Parameters from the query string, e.g. /index?limit=10
33 Form url.Values // Parameters from the request body.
35 Files map[string][]*multipart.FileHeader // Files uploaded in a multipart form
36 tmpFiles []*os.File // Temp files used during the request.
37 JSON []byte // JSON data from request body
40 var paramsLogger = RevelLog.New("section", "params")
42 // ParseParams parses the `http.Request` params into `revel.Controller.Params`
43 func ParseParams(params *Params, req *Request) {
44 params.Query = req.GetQuery()
46 // Parse the body depending on the content type.
47 switch req.ContentType {
48 case "application/x-www-form-urlencoded":
51 if params.Form, err = req.GetForm(); err != nil {
52 paramsLogger.Warn("ParseParams: Error parsing request body", "error", err)
55 case "multipart/form-data":
57 if mp, err := req.GetMultipartForm(); err != nil {
58 paramsLogger.Warn("ParseParams: parsing request body:", "error", err)
60 params.Form = mp.GetValues()
61 params.Files = mp.GetFiles()
63 case "application/json":
66 if body := req.GetBody(); body != nil {
67 if content, err := ioutil.ReadAll(body); err == nil {
68 // We wont bind it until we determine what we are binding too
71 paramsLogger.Error("ParseParams: Failed to ready request body bytes", "error", err)
74 paramsLogger.Info("ParseParams: Json post received with empty body")
78 params.Values = params.calcValues()
81 // Bind looks for the named parameter, converts it to the requested type, and
82 // writes it into "dest", which must be settable. If the value can not be
83 // parsed, "dest" is set to the zero value.
84 func (p *Params) Bind(dest interface{}, name string) {
85 value := reflect.ValueOf(dest)
86 if value.Kind() != reflect.Ptr {
87 paramsLogger.Panic("Bind: revel/params: non-pointer passed to Bind: " + name)
91 paramsLogger.Panic("Bind: revel/params: non-settable variable passed to Bind: " + name)
94 // Remove the json from the Params, this will stop the binder from attempting
95 // to use the json data to populate the destination interface. We do not want
96 // to do this on a named bind directly against the param, it is ok to happen when
97 // the action is invoked.
100 value.Set(Bind(p, name, value.Type()))
104 // Bind binds the JSON data to the dest.
105 func (p *Params) BindJSON(dest interface{}) error {
106 value := reflect.ValueOf(dest)
107 if value.Kind() != reflect.Ptr {
108 paramsLogger.Warn("BindJSON: Not a pointer")
109 return errors.New("BindJSON not a pointer")
111 if err := json.Unmarshal(p.JSON, dest); err != nil {
112 paramsLogger.Warn("BindJSON: Unable to unmarshal request:", "error", err)
118 // calcValues returns a unified view of the component param maps.
119 func (p *Params) calcValues() url.Values {
120 numParams := len(p.Query) + len(p.Fixed) + len(p.Route) + len(p.Form)
122 // If there were no params, return an empty map.
124 return make(url.Values, 0)
127 // If only one of the param sources has anything, return that directly.
139 // Copy everything into a param map,
140 // order of priority is least to most trusted
141 values := make(url.Values, numParams)
143 // ?query string parameters are first
144 for k, v := range p.Query {
145 values[k] = append(values[k], v...)
148 // form parameters append
149 for k, v := range p.Form {
150 values[k] = append(values[k], v...)
153 // :/path parameters overwrite
154 for k, v := range p.Route {
158 // fixed route parameters overwrite
159 for k, v := range p.Fixed {
166 func ParamsFilter(c *Controller, fc []Filter) {
167 ParseParams(c.Params, c.Request)
169 // Clean up from the request.
171 for _, tmpFile := range c.Params.tmpFiles {
172 err := os.Remove(tmpFile.Name())
174 paramsLogger.Warn("ParamsFilter: Could not remove upload temp file:", err)