X-Git-Url: https://gerrit.akraino.org/r/gitweb?a=blobdiff_plain;f=src%2Ffoundation%2Fapi%2Frevel%2Fparams.go;fp=src%2Ffoundation%2Fapi%2Frevel%2Fparams.go;h=3df3dde5581ea1e9449f2d924dac704ece001c10;hb=1d1ee6961c93781e1187d8c7faa868da6b2f01f4;hp=0000000000000000000000000000000000000000;hpb=56dd5e0f2164b37b40ac1daa188ccc618b4cbd19;p=iec.git diff --git a/src/foundation/api/revel/params.go b/src/foundation/api/revel/params.go new file mode 100644 index 0000000..3df3dde --- /dev/null +++ b/src/foundation/api/revel/params.go @@ -0,0 +1,180 @@ +// Copyright (c) 2012-2017 The Revel Framework Authors, All rights reserved. +// Revel Framework source code and usage is governed by a MIT style +// license that can be found in the LICENSE file. + +package revel + +import ( + "encoding/json" + "errors" + "io/ioutil" + "mime/multipart" + "net/url" + "os" + "reflect" +) + +// Params provides a unified view of the request params. +// Includes: +// - URL query string +// - Form values +// - File uploads +// +// Warning: param maps other than Values may be nil if there were none. +type Params struct { + url.Values // A unified view of all the individual param maps below. + + // Set by the router + Fixed url.Values // Fixed parameters from the route, e.g. App.Action("fixed param") + Route url.Values // Parameters extracted from the route, e.g. /customers/{id} + + // Set by the ParamsFilter + Query url.Values // Parameters from the query string, e.g. /index?limit=10 + Form url.Values // Parameters from the request body. + + Files map[string][]*multipart.FileHeader // Files uploaded in a multipart form + tmpFiles []*os.File // Temp files used during the request. + JSON []byte // JSON data from request body +} + +var paramsLogger = RevelLog.New("section", "params") + +// ParseParams parses the `http.Request` params into `revel.Controller.Params` +func ParseParams(params *Params, req *Request) { + params.Query = req.GetQuery() + + // Parse the body depending on the content type. + switch req.ContentType { + case "application/x-www-form-urlencoded": + // Typical form. + var err error + if params.Form, err = req.GetForm(); err != nil { + paramsLogger.Warn("ParseParams: Error parsing request body", "error", err) + } + + case "multipart/form-data": + // Multipart form. + if mp, err := req.GetMultipartForm(); err != nil { + paramsLogger.Warn("ParseParams: parsing request body:", "error", err) + } else { + params.Form = mp.GetValues() + params.Files = mp.GetFiles() + } + case "application/json": + fallthrough + case "text/json": + if body := req.GetBody(); body != nil { + if content, err := ioutil.ReadAll(body); err == nil { + // We wont bind it until we determine what we are binding too + params.JSON = content + } else { + paramsLogger.Error("ParseParams: Failed to ready request body bytes", "error", err) + } + } else { + paramsLogger.Info("ParseParams: Json post received with empty body") + } + } + + params.Values = params.calcValues() +} + +// Bind looks for the named parameter, converts it to the requested type, and +// writes it into "dest", which must be settable. If the value can not be +// parsed, "dest" is set to the zero value. +func (p *Params) Bind(dest interface{}, name string) { + value := reflect.ValueOf(dest) + if value.Kind() != reflect.Ptr { + paramsLogger.Panic("Bind: revel/params: non-pointer passed to Bind: " + name) + } + value = value.Elem() + if !value.CanSet() { + paramsLogger.Panic("Bind: revel/params: non-settable variable passed to Bind: " + name) + } + + // Remove the json from the Params, this will stop the binder from attempting + // to use the json data to populate the destination interface. We do not want + // to do this on a named bind directly against the param, it is ok to happen when + // the action is invoked. + jsonData := p.JSON + p.JSON = nil + value.Set(Bind(p, name, value.Type())) + p.JSON = jsonData +} + +// Bind binds the JSON data to the dest. +func (p *Params) BindJSON(dest interface{}) error { + value := reflect.ValueOf(dest) + if value.Kind() != reflect.Ptr { + paramsLogger.Warn("BindJSON: Not a pointer") + return errors.New("BindJSON not a pointer") + } + if err := json.Unmarshal(p.JSON, dest); err != nil { + paramsLogger.Warn("BindJSON: Unable to unmarshal request:", "error", err) + return err + } + return nil +} + +// calcValues returns a unified view of the component param maps. +func (p *Params) calcValues() url.Values { + numParams := len(p.Query) + len(p.Fixed) + len(p.Route) + len(p.Form) + + // If there were no params, return an empty map. + if numParams == 0 { + return make(url.Values, 0) + } + + // If only one of the param sources has anything, return that directly. + switch numParams { + case len(p.Query): + return p.Query + case len(p.Route): + return p.Route + case len(p.Fixed): + return p.Fixed + case len(p.Form): + return p.Form + } + + // Copy everything into a param map, + // order of priority is least to most trusted + values := make(url.Values, numParams) + + // ?query string parameters are first + for k, v := range p.Query { + values[k] = append(values[k], v...) + } + + // form parameters append + for k, v := range p.Form { + values[k] = append(values[k], v...) + } + + // :/path parameters overwrite + for k, v := range p.Route { + values[k] = v + } + + // fixed route parameters overwrite + for k, v := range p.Fixed { + values[k] = v + } + + return values +} + +func ParamsFilter(c *Controller, fc []Filter) { + ParseParams(c.Params, c.Request) + + // Clean up from the request. + defer func() { + for _, tmpFile := range c.Params.tmpFiles { + err := os.Remove(tmpFile.Name()) + if err != nil { + paramsLogger.Warn("ParamsFilter: Could not remove upload temp file:", err) + } + } + }() + + fc[0](c, fc[1:]) +}