|
- // Copyright 2015 go-swagger maintainers
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
-
- package middleware
-
- import (
- "mime"
- "net/http"
- "strings"
-
- "github.com/go-openapi/errors"
- "github.com/go-openapi/runtime"
- "github.com/go-openapi/swag"
- )
-
- type validation struct {
- context *Context
- result []error
- request *http.Request
- route *MatchedRoute
- bound map[string]interface{}
- }
-
- // ContentType validates the content type of a request
- func validateContentType(allowed []string, actual string) error {
- debugLog("validating content type for %q against [%s]", actual, strings.Join(allowed, ", "))
- if len(allowed) == 0 {
- return nil
- }
- mt, _, err := mime.ParseMediaType(actual)
- if err != nil {
- return errors.InvalidContentType(actual, allowed)
- }
- if swag.ContainsStringsCI(allowed, mt) {
- return nil
- }
- if swag.ContainsStringsCI(allowed, "*/*") {
- return nil
- }
- parts := strings.Split(actual, "/")
- if len(parts) == 2 && swag.ContainsStringsCI(allowed, parts[0]+"/*") {
- return nil
- }
- return errors.InvalidContentType(actual, allowed)
- }
-
- func validateRequest(ctx *Context, request *http.Request, route *MatchedRoute) *validation {
- debugLog("validating request %s %s", request.Method, request.URL.EscapedPath())
- validate := &validation{
- context: ctx,
- request: request,
- route: route,
- bound: make(map[string]interface{}),
- }
-
- validate.contentType()
- if len(validate.result) == 0 {
- validate.responseFormat()
- }
- if len(validate.result) == 0 {
- validate.parameters()
- }
-
- return validate
- }
-
- func (v *validation) parameters() {
- debugLog("validating request parameters for %s %s", v.request.Method, v.request.URL.EscapedPath())
- if result := v.route.Binder.Bind(v.request, v.route.Params, v.route.Consumer, v.bound); result != nil {
- if result.Error() == "validation failure list" {
- for _, e := range result.(*errors.Validation).Value.([]interface{}) {
- v.result = append(v.result, e.(error))
- }
- return
- }
- v.result = append(v.result, result)
- }
- }
-
- func (v *validation) contentType() {
- if len(v.result) == 0 && runtime.HasBody(v.request) {
- debugLog("validating body content type for %s %s", v.request.Method, v.request.URL.EscapedPath())
- ct, _, req, err := v.context.ContentType(v.request)
- if err != nil {
- v.result = append(v.result, err)
- } else {
- v.request = req
- }
-
- if len(v.result) == 0 {
- if err := validateContentType(v.route.Consumes, ct); err != nil {
- v.result = append(v.result, err)
- }
- }
- if ct != "" && v.route.Consumer == nil {
- cons, ok := v.route.Consumers[ct]
- if !ok {
- v.result = append(v.result, errors.New(500, "no consumer registered for %s", ct))
- } else {
- v.route.Consumer = cons
- }
- }
- }
- }
-
- func (v *validation) responseFormat() {
- if str, rCtx := v.context.ResponseFormat(v.request, v.route.Produces); str == "" && runtime.HasBody(v.request) {
- v.request = rCtx
- v.result = append(v.result, errors.InvalidResponseFormat(v.request.Header.Get(runtime.HeaderAccept), v.route.Produces))
- }
- }
|