diff --git a/runtime/marshal_urlencode.go b/runtime/marshal_urlencode.go new file mode 100644 index 00000000000..b6bcbadb128 --- /dev/null +++ b/runtime/marshal_urlencode.go @@ -0,0 +1,56 @@ +package runtime + +import ( + "fmt" + "io" + "io/ioutil" + "net/url" + + "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" + "google.golang.org/protobuf/proto" +) + +type UrlEncodeMarshal struct { + Marshaler +} + +// ContentType means the content type of the response +func (u UrlEncodeMarshal) ContentType(_ interface{}) string { + return "application/json" +} + +func (u UrlEncodeMarshal) Marshal(v interface{}) ([]byte, error) { + // can marshal the response in proto message format + j := JSONPb{} + return j.Marshal(v) +} + +// NewDecoder indicates how to decode the request +func (u UrlEncodeMarshal) NewDecoder(r io.Reader) Decoder { + return DecoderFunc(func(p interface{}) error { + msg, ok := p.(proto.Message) + if !ok { + return fmt.Errorf("not proto message") + } + + formData, err := ioutil.ReadAll(r) + if err != nil { + return err + } + + values, err := url.ParseQuery(string(formData)) + if err != nil { + return err + } + + filter := &utilities.DoubleArray{} + + err = PopulateQueryParameters(msg, values, filter) + + if err != nil { + return err + } + + return nil + }) +} diff --git a/runtime/marshaler_registry.go b/runtime/marshaler_registry.go index a714de02406..311d6fec9fe 100644 --- a/runtime/marshaler_registry.go +++ b/runtime/marshaler_registry.go @@ -11,7 +11,10 @@ import ( // MIMEWildcard is the fallback MIME type used for requests which do not match // a registered MIME type. -const MIMEWildcard = "*" +const ( + MIMEWildcard = "*" + MIMEFormURLEncoded = "application/x-www-form-urlencoded" +) var ( acceptHeader = http.CanonicalHeaderKey("Accept") @@ -27,6 +30,8 @@ var ( }, }, } + + defaultFormMarshaler = &UrlEncodeMarshal{} ) // MarshalerForRequest returns the inbound/outbound marshalers for this request. @@ -93,7 +98,8 @@ func (m marshalerRegistry) add(mime string, marshaler Marshaler) error { func makeMarshalerMIMERegistry() marshalerRegistry { return marshalerRegistry{ mimeMap: map[string]Marshaler{ - MIMEWildcard: defaultMarshaler, + MIMEWildcard: defaultMarshaler, + MIMEFormURLEncoded: defaultFormMarshaler, }, } }