This repository has been archived by the owner on Apr 18, 2024. It is now read-only.
/
marshal_httpbody.go
88 lines (77 loc) · 2.51 KB
/
marshal_httpbody.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
package runtime
import (
"io"
"reflect"
"github.com/golang/protobuf/proto"
hb "google.golang.org/genproto/googleapis/api/httpbody"
)
var (
backupMarshaler = &JSONPb{OrigName: true}
)
// HttpBodyMarshaler is a Marshaler which supports marshaling of a
// google.api.HttpBody message as the full response body if it is
// the actual message used as the response. If not, then this will
// simply fallback to the JSONPb marshaler.
type HttpBodyMarshaler struct{}
// ContentType returns the type specified in the google.api.HttpBody
// proto if "v" is a google.api.HttpBody proto, otherwise returns
// "application/json".
func (*HttpBodyMarshaler) ContentType(v interface{}) string {
if h := tryHttpBody(v); h != nil {
return h.GetContentType()
}
return "application/json"
}
// Marshal marshals "v" by returning the body bytes if v is a
// google.api.HttpBody message, or it marshals to JSON.
func (*HttpBodyMarshaler) Marshal(v interface{}) ([]byte, error) {
if h := tryHttpBody(v); h != nil {
return h.GetData(), nil
}
return backupMarshaler.Marshal(v)
}
// Unmarshal unmarshals JSON data into "v".
// google.api.HttpBody messages are not supported on the request.
func (*HttpBodyMarshaler) Unmarshal(data []byte, v interface{}) error {
return backupMarshaler.Unmarshal(data, v)
}
// NewDecoder returns a Decoder which reads JSON stream from "r".
func (*HttpBodyMarshaler) NewDecoder(r io.Reader) Decoder {
return backupMarshaler.NewDecoder(r)
}
// NewEncoder returns an Encoder which writes JSON stream into "w".
func (*HttpBodyMarshaler) NewEncoder(w io.Writer) Encoder {
return backupMarshaler.NewEncoder(w)
}
// Delimiter for encoded multi-part streams.
func (j *HttpBodyMarshaler) Delimiter() []byte {
return []byte("")
}
func tryHttpBody(v interface{}) *hb.HttpBody {
rv := reflect.ValueOf(v)
// The handler wraps streamed chunks in a map.
// If we're sending an HTTP body as a chunk, we need to unpack it.
if rv.Kind() == reflect.Map && rv.Type().ConvertibleTo(reflect.TypeOf(map[string]proto.Message{})) {
m := v.(map[string]proto.Message)
if r, ok := m["result"]; ok && proto.MessageName(r) == "google.api.HttpBody" {
return r.(*hb.HttpBody)
}
return nil
}
if rv.Kind() != reflect.Ptr {
return nil
}
for rv.Kind() == reflect.Ptr {
if rv.IsNil() {
rv.Set(reflect.New(rv.Type().Elem()))
}
if rv.Type().ConvertibleTo(typeProtoMessage) {
pb := rv.Interface().(proto.Message)
if proto.MessageName(pb) == "google.api.HttpBody" {
return v.(*hb.HttpBody)
}
}
rv = rv.Elem()
}
return nil
}