trpc.group/trpc-go/trpc-go@v1.0.3/restful/serialize_form.go (about)

     1  //
     2  //
     3  // Tencent is pleased to support the open source community by making tRPC available.
     4  //
     5  // Copyright (C) 2023 THL A29 Limited, a Tencent company.
     6  // All rights reserved.
     7  //
     8  // If you have downloaded a copy of the tRPC source code from Tencent,
     9  // please note that tRPC source code is licensed under the  Apache 2.0 License,
    10  // A copy of the Apache 2.0 License is included in this file.
    11  //
    12  //
    13  
    14  package restful
    15  
    16  import (
    17  	"errors"
    18  	"net/url"
    19  	"strings"
    20  
    21  	"google.golang.org/protobuf/proto"
    22  )
    23  
    24  func init() {
    25  	RegisterSerializer(&FormSerializer{})
    26  }
    27  
    28  // FormSerializer is used for Content-Type: application/x-www-form-urlencoded.
    29  type FormSerializer struct {
    30  	// If DiscardUnknown is set, unknown fields are ignored.
    31  	DiscardUnknown bool
    32  }
    33  
    34  // Marshal implements Serializer.
    35  // It does the same thing as the jsonpb marshaler's Marshal method.
    36  func (*FormSerializer) Marshal(v interface{}) ([]byte, error) {
    37  	msg, ok := v.(proto.Message)
    38  	if !ok { // marshal a field of tRPC message
    39  		return marshal(v)
    40  	}
    41  	// marshal tRPC message
    42  	return Marshaller.Marshal(msg)
    43  }
    44  
    45  // Unmarshal implements Serializer
    46  func (f *FormSerializer) Unmarshal(data []byte, v interface{}) error {
    47  	msg, ok := assertProtoMessage(v)
    48  	if !ok {
    49  		return errNotProtoMessageType
    50  	}
    51  
    52  	// get url.Values
    53  	vs, err := url.ParseQuery(string(data))
    54  	if err != nil {
    55  		return err
    56  	}
    57  	// populate proto message
    58  	for key, values := range vs {
    59  		fieldPath := strings.Split(key, ".")
    60  		if err := PopulateMessage(msg, fieldPath, values); err != nil {
    61  			if !f.DiscardUnknown || !errors.Is(err, ErrTraverseNotFound) {
    62  				return err
    63  			}
    64  		}
    65  	}
    66  
    67  	return nil
    68  }
    69  
    70  // Name implements Serializer.
    71  func (*FormSerializer) Name() string {
    72  	return "application/x-www-form-urlencoded"
    73  }
    74  
    75  // ContentType implements Serializer.
    76  // Does the same thing as jsonpb marshaler.
    77  func (*FormSerializer) ContentType() string {
    78  	return "application/json"
    79  }