| package validation |
| |
| import ( |
| "crypto/md5" |
| "fmt" |
| "net/http" |
| "net/url" |
| "strconv" |
| "strings" |
| |
| "go.skia.org/infra/go/util" |
| ) |
| |
| // IsValidDigest returns true if the given string is a valid digest |
| // on the string level, i.e. it does not check whether we have |
| // actually seen the given hash but whether it complies with the format |
| // that we expect for a hash. |
| func IsValidDigest(hash string) bool { |
| // Currently we expect all digests to be hex encoded MD5 hashes. |
| if len(hash) != 2*md5.Size { |
| return false |
| } |
| |
| for _, c := range []byte(hash) { |
| if ((c >= '0') && (c <= '9')) || |
| ((c >= 'a') && (c <= 'f')) || |
| ((c >= 'A') && (c <= 'F')) { |
| continue |
| } |
| return false |
| } |
| return true |
| } |
| |
| // Validation is a container to collect error messages during validation of a |
| // input with multiple fields. |
| type Validation []string |
| |
| // StrValue validates a string value against containment in a set of options. |
| // Argument: |
| // |
| // name: name of the field being validated. |
| // val: value to be validated. |
| // options: list of options, one of which value can contain. |
| // defaultVal: default value in case val is empty. Can be equal to "". |
| // |
| // If there is a problem an error message will be added to the Validation object. |
| func (v *Validation) StrValue(name string, val *string, options []string, defaultVal string) { |
| if *val == "" && defaultVal != "" { |
| *val = defaultVal |
| return |
| } |
| if !util.In(*val, options) { |
| *v = append(*v, fmt.Sprintf("Field '%s' needs to be one of '%s'", name, strings.Join(options, ","))) |
| } |
| } |
| |
| // StrFormValue does the same as StrValue but extracts the given name from |
| // the request via r.FormValue(..). |
| func (v *Validation) StrFormValue(r *http.Request, name string, val *string, options []string, defaultVal string) { |
| *val = r.FormValue(name) |
| v.StrValue(name, val, options, defaultVal) |
| } |
| |
| // Float64Value parses the value given in strVal and returns it. If strVal is empty |
| // the default value is returned. |
| func (v *Validation) Float64Value(name string, strVal string, defaultVal float64) float64 { |
| if strVal == "" { |
| return defaultVal |
| } |
| |
| tempVal, err := strconv.ParseFloat(strVal, 64) |
| if err != nil { |
| *v = append(*v, fmt.Sprintf("Field '%s' is not a valid float: %s", name, err)) |
| } |
| return tempVal |
| } |
| |
| // Int64Value parses the value given in strVal and returns it. If strVal is empty |
| // the default value is returned. |
| func (v *Validation) Int64Value(name string, strVal string, defaultVal int64) int64 { |
| if strVal == "" { |
| return defaultVal |
| } |
| |
| tempVal, err := strconv.ParseInt(strVal, 10, 64) |
| if err != nil { |
| *v = append(*v, fmt.Sprintf("Field '%s' is not a valid int: %s", name, err)) |
| } |
| return tempVal |
| } |
| |
| // Float64FormValue does the same as Float64Value but extracts the value from the request object. |
| func (v *Validation) Float64FormValue(r *http.Request, name string, defaultVal float64) float64 { |
| return v.Float64Value(name, r.FormValue(name), defaultVal) |
| } |
| |
| // Int64FormValue does the same as Int64Value but extracts the value from the request object. |
| func (v *Validation) Int64FormValue(r *http.Request, name string, defaultVal int64) int64 { |
| return v.Int64Value(name, r.FormValue(name), defaultVal) |
| } |
| |
| // Int64SliceValue parses a comma-separated list of int values and returns them. |
| func (v *Validation) Int64SliceValue(name string, strVal string, defaultVal []int64) []int64 { |
| if strVal == "" { |
| return defaultVal |
| } |
| |
| splitVals := strings.Split(strVal, ",") |
| ret := make([]int64, 0, len(splitVals)) |
| for _, oneStrVal := range splitVals { |
| tempVal, err := strconv.ParseInt(oneStrVal, 10, 64) |
| if err != nil { |
| *v = append(*v, fmt.Sprintf("Field '%s' is not a valid list of comma separated integers: %s", name, err)) |
| return nil |
| } |
| ret = append(ret, tempVal) |
| } |
| return ret |
| } |
| |
| // Int64SliceFormValue does the same as Int64SliceValue but extracts the given |
| // name from the request. |
| func (v *Validation) Int64SliceFormValue(r *http.Request, name string, defaultVal []int64) []int64 { |
| return v.Int64SliceValue(name, r.FormValue(name), defaultVal) |
| } |
| |
| // QueryFormValue extracts a URL-encoded query from the form values and decodes it. |
| // If the named field was not available in the given request an empty paramtools.ParamSet |
| // is returned. If an error occurs it will be added to the error list of the validation |
| // object. |
| func (v *Validation) QueryFormValue(r *http.Request, name string) map[string][]string { |
| if q := r.FormValue(name); q != "" { |
| ret, err := url.ParseQuery(q) |
| if err != nil { |
| *v = append(*v, fmt.Sprintf("Unable to parse query: %s. Error: %s", q, err)) |
| return nil |
| } |
| return ret |
| } |
| return map[string][]string{} |
| } |
| |
| // Errors returns a concatenation of all error values accumulated in validation or nil |
| // if there were no errors. |
| func (v *Validation) Errors() error { |
| if len(*v) == 0 { |
| return nil |
| } |
| |
| return fmt.Errorf("%s", strings.Join(*v, "\n")) |
| } |