github.com/cloudwego/hertz@v0.9.3/pkg/app/server/binding/internal/decoder/decoder.go (about)

     1  /*
     2   * Copyright 2023 CloudWeGo Authors
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   * MIT License
    16   *
    17   * Copyright (c) 2019-present Fenny and Contributors
    18   *
    19   * Permission is hereby granted, free of charge, to any person obtaining a copy
    20   * of this software and associated documentation files (the "Software"), to deal
    21   * in the Software without restriction, including without limitation the rights
    22   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    23   * copies of the Software, and to permit persons to whom the Software is
    24   * furnished to do so, subject to the following conditions:
    25   *
    26   * The above copyright notice and this permission notice shall be included in all
    27   * copies or substantial portions of the Software.
    28   *
    29   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    30   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    31   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    32   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    33   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    34   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    35   * SOFTWARE.
    36   *
    37   * This file may have been modified by CloudWeGo authors. All CloudWeGo
    38   * Modifications are Copyright 2023 CloudWeGo Authors
    39   */
    40  
    41  package decoder
    42  
    43  import (
    44  	"fmt"
    45  	"mime/multipart"
    46  	"reflect"
    47  
    48  	"github.com/cloudwego/hertz/pkg/protocol"
    49  	"github.com/cloudwego/hertz/pkg/route/param"
    50  )
    51  
    52  type fieldDecoder interface {
    53  	Decode(req *protocol.Request, params param.Params, reqValue reflect.Value) error
    54  }
    55  
    56  type Decoder func(req *protocol.Request, params param.Params, rv reflect.Value) error
    57  
    58  type DecodeConfig struct {
    59  	LooseZeroMode                      bool
    60  	DisableDefaultTag                  bool
    61  	DisableStructFieldResolve          bool
    62  	EnableDecoderUseNumber             bool
    63  	EnableDecoderDisallowUnknownFields bool
    64  	ValidateTag                        string
    65  	TypeUnmarshalFuncs                 map[reflect.Type]CustomizeDecodeFunc
    66  }
    67  
    68  func GetReqDecoder(rt reflect.Type, byTag string, config *DecodeConfig) (Decoder, bool, error) {
    69  	var decoders []fieldDecoder
    70  	var needValidate bool
    71  
    72  	el := rt.Elem()
    73  	if el.Kind() != reflect.Struct {
    74  		return nil, false, fmt.Errorf("unsupported \"%s\" type binding", rt.String())
    75  	}
    76  
    77  	for i := 0; i < el.NumField(); i++ {
    78  		if el.Field(i).PkgPath != "" && !el.Field(i).Anonymous {
    79  			// ignore unexported field
    80  			continue
    81  		}
    82  
    83  		dec, needValidate2, err := getFieldDecoder(parentInfos{[]reflect.Type{el}, []int{}, ""}, el.Field(i), i, byTag, config)
    84  		if err != nil {
    85  			return nil, false, err
    86  		}
    87  		needValidate = needValidate || needValidate2
    88  
    89  		if dec != nil {
    90  			decoders = append(decoders, dec...)
    91  		}
    92  	}
    93  
    94  	return func(req *protocol.Request, params param.Params, rv reflect.Value) error {
    95  		for _, decoder := range decoders {
    96  			err := decoder.Decode(req, params, rv)
    97  			if err != nil {
    98  				return err
    99  			}
   100  		}
   101  
   102  		return nil
   103  	}, needValidate, nil
   104  }
   105  
   106  type parentInfos struct {
   107  	Types    []reflect.Type
   108  	Indexes  []int
   109  	JSONName string
   110  }
   111  
   112  func getFieldDecoder(pInfo parentInfos, field reflect.StructField, index int, byTag string, config *DecodeConfig) ([]fieldDecoder, bool, error) {
   113  	for field.Type.Kind() == reflect.Ptr {
   114  		field.Type = field.Type.Elem()
   115  	}
   116  	// skip anonymous definitions, like:
   117  	// type A struct {
   118  	// 		string
   119  	// }
   120  	if field.Type.Kind() != reflect.Struct && field.Anonymous {
   121  		return nil, false, nil
   122  	}
   123  
   124  	// JSONName is like 'a.b.c' for 'required validate'
   125  	fieldTagInfos, newParentJSONName, needValidate := lookupFieldTags(field, pInfo.JSONName, config)
   126  	if len(fieldTagInfos) == 0 && !config.DisableDefaultTag {
   127  		fieldTagInfos, newParentJSONName = getDefaultFieldTags(field, pInfo.JSONName)
   128  	}
   129  	if len(byTag) != 0 {
   130  		fieldTagInfos = getFieldTagInfoByTag(field, byTag)
   131  	}
   132  
   133  	// customized type decoder has the highest priority
   134  	if customizedFunc, exist := config.TypeUnmarshalFuncs[field.Type]; exist {
   135  		dec, err := getCustomizedFieldDecoder(field, index, fieldTagInfos, pInfo.Indexes, customizedFunc, config)
   136  		return dec, needValidate, err
   137  	}
   138  
   139  	// slice/array field decoder
   140  	if field.Type.Kind() == reflect.Slice || field.Type.Kind() == reflect.Array {
   141  		dec, err := getSliceFieldDecoder(field, index, fieldTagInfos, pInfo.Indexes, config)
   142  		return dec, needValidate, err
   143  	}
   144  
   145  	// map filed decoder
   146  	if field.Type.Kind() == reflect.Map {
   147  		dec, err := getMapTypeTextDecoder(field, index, fieldTagInfos, pInfo.Indexes, config)
   148  		return dec, needValidate, err
   149  	}
   150  
   151  	// struct field will be resolved recursively
   152  	if field.Type.Kind() == reflect.Struct {
   153  		var decoders []fieldDecoder
   154  		el := field.Type
   155  		// todo: more built-in common struct binding, ex. time...
   156  		switch el {
   157  		case reflect.TypeOf(multipart.FileHeader{}): // file binding
   158  			dec, err := getMultipartFileDecoder(field, index, fieldTagInfos, pInfo.Indexes, config)
   159  			return dec, needValidate, err
   160  		}
   161  		if !config.DisableStructFieldResolve { // decode struct type separately
   162  			structFieldDecoder, err := getStructTypeFieldDecoder(field, index, fieldTagInfos, pInfo.Indexes, config)
   163  			if err != nil {
   164  				return nil, needValidate, err
   165  			}
   166  			if structFieldDecoder != nil {
   167  				decoders = append(decoders, structFieldDecoder...)
   168  			}
   169  		}
   170  
   171  		// prevent infinite recursion when struct field with the same name as a struct
   172  		if hasSameType(pInfo.Types, el) {
   173  			return decoders, needValidate, nil
   174  		}
   175  
   176  		pIdx := pInfo.Indexes
   177  		for i := 0; i < el.NumField(); i++ {
   178  			if el.Field(i).PkgPath != "" && !el.Field(i).Anonymous {
   179  				// ignore unexported field
   180  				continue
   181  			}
   182  			var idxes []int
   183  			if len(pInfo.Indexes) > 0 {
   184  				idxes = append(idxes, pIdx...)
   185  			}
   186  			idxes = append(idxes, index)
   187  			pInfo.Indexes = idxes
   188  			pInfo.Types = append(pInfo.Types, el)
   189  			pInfo.JSONName = newParentJSONName
   190  			dec, needValidate2, err := getFieldDecoder(pInfo, el.Field(i), i, byTag, config)
   191  			needValidate = needValidate || needValidate2
   192  			if err != nil {
   193  				return nil, false, err
   194  			}
   195  			if dec != nil {
   196  				decoders = append(decoders, dec...)
   197  			}
   198  		}
   199  
   200  		return decoders, needValidate, nil
   201  	}
   202  
   203  	// base type decoder
   204  	dec, err := getBaseTypeTextDecoder(field, index, fieldTagInfos, pInfo.Indexes, config)
   205  	return dec, needValidate, err
   206  }
   207  
   208  // hasSameType determine if the same type is present in the parent-child relationship
   209  func hasSameType(pts []reflect.Type, ft reflect.Type) bool {
   210  	for _, pt := range pts {
   211  		if reflect.DeepEqual(getElemType(pt), getElemType(ft)) {
   212  			return true
   213  		}
   214  	}
   215  	return false
   216  }