Moved to google.golang.org/genproto/googleapis/api/annotations
Fixes #52
This commit is contained in:
187
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/context.go
generated
vendored
Normal file
187
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/context.go
generated
vendored
Normal file
@@ -0,0 +1,187 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
"google.golang.org/grpc/metadata"
|
||||
)
|
||||
|
||||
// MetadataHeaderPrefix is the http prefix that represents custom metadata
|
||||
// parameters to or from a gRPC call.
|
||||
const MetadataHeaderPrefix = "Grpc-Metadata-"
|
||||
|
||||
// MetadataPrefix is the prefix for grpc-gateway supplied custom metadata fields.
|
||||
const MetadataPrefix = "grpcgateway-"
|
||||
|
||||
// MetadataTrailerPrefix is prepended to gRPC metadata as it is converted to
|
||||
// HTTP headers in a response handled by grpc-gateway
|
||||
const MetadataTrailerPrefix = "Grpc-Trailer-"
|
||||
|
||||
const metadataGrpcTimeout = "Grpc-Timeout"
|
||||
|
||||
const xForwardedFor = "X-Forwarded-For"
|
||||
const xForwardedHost = "X-Forwarded-Host"
|
||||
|
||||
var (
|
||||
// DefaultContextTimeout is used for gRPC call context.WithTimeout whenever a Grpc-Timeout inbound
|
||||
// header isn't present. If the value is 0 the sent `context` will not have a timeout.
|
||||
DefaultContextTimeout = 0 * time.Second
|
||||
)
|
||||
|
||||
/*
|
||||
AnnotateContext adds context information such as metadata from the request.
|
||||
|
||||
At a minimum, the RemoteAddr is included in the fashion of "X-Forwarded-For",
|
||||
except that the forwarded destination is not another HTTP service but rather
|
||||
a gRPC service.
|
||||
*/
|
||||
func AnnotateContext(ctx context.Context, req *http.Request) (context.Context, error) {
|
||||
var pairs []string
|
||||
timeout := DefaultContextTimeout
|
||||
if tm := req.Header.Get(metadataGrpcTimeout); tm != "" {
|
||||
var err error
|
||||
timeout, err = timeoutDecode(tm)
|
||||
if err != nil {
|
||||
return nil, grpc.Errorf(codes.InvalidArgument, "invalid grpc-timeout: %s", tm)
|
||||
}
|
||||
}
|
||||
|
||||
for key, vals := range req.Header {
|
||||
for _, val := range vals {
|
||||
// For backwards-compatibility, pass through 'authorization' header with no prefix.
|
||||
if strings.ToLower(key) == "authorization" {
|
||||
pairs = append(pairs, "authorization", val)
|
||||
}
|
||||
if isPermanentHTTPHeader(key) {
|
||||
pairs = append(pairs, strings.ToLower(fmt.Sprintf("%s%s", MetadataPrefix, key)), val)
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(key, MetadataHeaderPrefix) {
|
||||
pairs = append(pairs, key[len(MetadataHeaderPrefix):], val)
|
||||
}
|
||||
}
|
||||
}
|
||||
if host := req.Header.Get(xForwardedHost); host != "" {
|
||||
pairs = append(pairs, strings.ToLower(xForwardedHost), host)
|
||||
} else if req.Host != "" {
|
||||
pairs = append(pairs, strings.ToLower(xForwardedHost), req.Host)
|
||||
}
|
||||
|
||||
if addr := req.RemoteAddr; addr != "" {
|
||||
if remoteIP, _, err := net.SplitHostPort(addr); err == nil {
|
||||
if fwd := req.Header.Get(xForwardedFor); fwd == "" {
|
||||
pairs = append(pairs, strings.ToLower(xForwardedFor), remoteIP)
|
||||
} else {
|
||||
pairs = append(pairs, strings.ToLower(xForwardedFor), fmt.Sprintf("%s, %s", fwd, remoteIP))
|
||||
}
|
||||
} else {
|
||||
grpclog.Printf("invalid remote addr: %s", addr)
|
||||
}
|
||||
}
|
||||
|
||||
if timeout != 0 {
|
||||
ctx, _ = context.WithTimeout(ctx, timeout)
|
||||
}
|
||||
if len(pairs) == 0 {
|
||||
return ctx, nil
|
||||
}
|
||||
return metadata.NewContext(ctx, metadata.Pairs(pairs...)), nil
|
||||
}
|
||||
|
||||
// ServerMetadata consists of metadata sent from gRPC server.
|
||||
type ServerMetadata struct {
|
||||
HeaderMD metadata.MD
|
||||
TrailerMD metadata.MD
|
||||
}
|
||||
|
||||
type serverMetadataKey struct{}
|
||||
|
||||
// NewServerMetadataContext creates a new context with ServerMetadata
|
||||
func NewServerMetadataContext(ctx context.Context, md ServerMetadata) context.Context {
|
||||
return context.WithValue(ctx, serverMetadataKey{}, md)
|
||||
}
|
||||
|
||||
// ServerMetadataFromContext returns the ServerMetadata in ctx
|
||||
func ServerMetadataFromContext(ctx context.Context) (md ServerMetadata, ok bool) {
|
||||
md, ok = ctx.Value(serverMetadataKey{}).(ServerMetadata)
|
||||
return
|
||||
}
|
||||
|
||||
func timeoutDecode(s string) (time.Duration, error) {
|
||||
size := len(s)
|
||||
if size < 2 {
|
||||
return 0, fmt.Errorf("timeout string is too short: %q", s)
|
||||
}
|
||||
d, ok := timeoutUnitToDuration(s[size-1])
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("timeout unit is not recognized: %q", s)
|
||||
}
|
||||
t, err := strconv.ParseInt(s[:size-1], 10, 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return d * time.Duration(t), nil
|
||||
}
|
||||
|
||||
func timeoutUnitToDuration(u uint8) (d time.Duration, ok bool) {
|
||||
switch u {
|
||||
case 'H':
|
||||
return time.Hour, true
|
||||
case 'M':
|
||||
return time.Minute, true
|
||||
case 'S':
|
||||
return time.Second, true
|
||||
case 'm':
|
||||
return time.Millisecond, true
|
||||
case 'u':
|
||||
return time.Microsecond, true
|
||||
case 'n':
|
||||
return time.Nanosecond, true
|
||||
default:
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// isPermanentHTTPHeader checks whether hdr belongs to the list of
|
||||
// permenant request headers maintained by IANA.
|
||||
// http://www.iana.org/assignments/message-headers/message-headers.xml
|
||||
func isPermanentHTTPHeader(hdr string) bool {
|
||||
switch hdr {
|
||||
case
|
||||
"Accept",
|
||||
"Accept-Charset",
|
||||
"Accept-Language",
|
||||
"Accept-Ranges",
|
||||
"Authorization",
|
||||
"Cache-Control",
|
||||
"Content-Type",
|
||||
"Cookie",
|
||||
"Date",
|
||||
"Expect",
|
||||
"From",
|
||||
"Host",
|
||||
"If-Match",
|
||||
"If-Modified-Since",
|
||||
"If-None-Match",
|
||||
"If-Schedule-Tag-Match",
|
||||
"If-Unmodified-Since",
|
||||
"Max-Forwards",
|
||||
"Origin",
|
||||
"Pragma",
|
||||
"Referer",
|
||||
"User-Agent",
|
||||
"Via",
|
||||
"Warning":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
172
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/context_test.go
generated
vendored
Normal file
172
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/context_test.go
generated
vendored
Normal file
@@ -0,0 +1,172 @@
|
||||
package runtime_test
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/grpc-ecosystem/grpc-gateway/runtime"
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/grpc/metadata"
|
||||
)
|
||||
|
||||
const (
|
||||
emptyForwardMetaCount = 1
|
||||
)
|
||||
|
||||
func TestAnnotateContext_WorksWithEmpty(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
request, err := http.NewRequest("GET", "http://www.example.com", nil)
|
||||
if err != nil {
|
||||
t.Fatalf("http.NewRequest(%q, %q, nil) failed with %v; want success", "GET", "http://www.example.com", err)
|
||||
}
|
||||
request.Header.Add("Some-Irrelevant-Header", "some value")
|
||||
annotated, err := runtime.AnnotateContext(ctx, request)
|
||||
if err != nil {
|
||||
t.Errorf("runtime.AnnotateContext(ctx, %#v) failed with %v; want success", request, err)
|
||||
return
|
||||
}
|
||||
md, ok := metadata.FromContext(annotated)
|
||||
if !ok || len(md) != emptyForwardMetaCount {
|
||||
t.Errorf("Expected %d metadata items in context; got %v", emptyForwardMetaCount, md)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAnnotateContext_ForwardsGrpcMetadata(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
request, err := http.NewRequest("GET", "http://www.example.com", nil)
|
||||
if err != nil {
|
||||
t.Fatalf("http.NewRequest(%q, %q, nil) failed with %v; want success", "GET", "http://www.example.com", err)
|
||||
}
|
||||
request.Header.Add("Some-Irrelevant-Header", "some value")
|
||||
request.Header.Add("Grpc-Metadata-FooBar", "Value1")
|
||||
request.Header.Add("Grpc-Metadata-Foo-BAZ", "Value2")
|
||||
request.Header.Add("Grpc-Metadata-foo-bAz", "Value3")
|
||||
request.Header.Add("Authorization", "Token 1234567890")
|
||||
annotated, err := runtime.AnnotateContext(ctx, request)
|
||||
if err != nil {
|
||||
t.Errorf("runtime.AnnotateContext(ctx, %#v) failed with %v; want success", request, err)
|
||||
return
|
||||
}
|
||||
md, ok := metadata.FromContext(annotated)
|
||||
if got, want := len(md), emptyForwardMetaCount+4; !ok || got != want {
|
||||
t.Errorf("metadata items in context = %d want %d: %v", got, want, md)
|
||||
}
|
||||
if got, want := md["foobar"], []string{"Value1"}; !reflect.DeepEqual(got, want) {
|
||||
t.Errorf(`md["grpcgateway-foobar"] = %q; want %q`, got, want)
|
||||
}
|
||||
if got, want := md["foo-baz"], []string{"Value2", "Value3"}; !reflect.DeepEqual(got, want) {
|
||||
t.Errorf(`md["grpcgateway-foo-baz"] = %q want %q`, got, want)
|
||||
}
|
||||
if got, want := md["grpcgateway-authorization"], []string{"Token 1234567890"}; !reflect.DeepEqual(got, want) {
|
||||
t.Errorf(`md["grpcgateway-authorization"] = %q want %q`, got, want)
|
||||
}
|
||||
if got, want := md["authorization"], []string{"Token 1234567890"}; !reflect.DeepEqual(got, want) {
|
||||
t.Errorf(`md["authorization"] = %q want %q`, got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAnnotateContext_XForwardedFor(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
request, err := http.NewRequest("GET", "http://bar.foo.example.com", nil)
|
||||
if err != nil {
|
||||
t.Fatalf("http.NewRequest(%q, %q, nil) failed with %v; want success", "GET", "http://bar.foo.example.com", err)
|
||||
}
|
||||
request.Header.Add("X-Forwarded-For", "192.0.2.100") // client
|
||||
request.RemoteAddr = "192.0.2.200:12345" // proxy
|
||||
|
||||
annotated, err := runtime.AnnotateContext(ctx, request)
|
||||
if err != nil {
|
||||
t.Errorf("runtime.AnnotateContext(ctx, %#v) failed with %v; want success", request, err)
|
||||
return
|
||||
}
|
||||
md, ok := metadata.FromContext(annotated)
|
||||
if !ok || len(md) != emptyForwardMetaCount+1 {
|
||||
t.Errorf("Expected %d metadata items in context; got %v", emptyForwardMetaCount+1, md)
|
||||
}
|
||||
if got, want := md["x-forwarded-host"], []string{"bar.foo.example.com"}; !reflect.DeepEqual(got, want) {
|
||||
t.Errorf(`md["host"] = %v; want %v`, got, want)
|
||||
}
|
||||
// Note: it must be in order client, proxy1, proxy2
|
||||
if got, want := md["x-forwarded-for"], []string{"192.0.2.100, 192.0.2.200"}; !reflect.DeepEqual(got, want) {
|
||||
t.Errorf(`md["x-forwarded-for"] = %v want %v`, got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAnnotateContext_SupportsTimeouts(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
request, err := http.NewRequest("GET", "http://example.com", nil)
|
||||
if err != nil {
|
||||
t.Fatalf(`http.NewRequest("GET", "http://example.com", nil failed with %v; want success`, err)
|
||||
}
|
||||
annotated, err := runtime.AnnotateContext(ctx, request)
|
||||
if err != nil {
|
||||
t.Errorf("runtime.AnnotateContext(ctx, %#v) failed with %v; want success", request, err)
|
||||
return
|
||||
}
|
||||
if _, ok := annotated.Deadline(); ok {
|
||||
// no deadline by default
|
||||
t.Errorf("annotated.Deadline() = _, true; want _, false")
|
||||
}
|
||||
|
||||
const acceptableError = 50 * time.Millisecond
|
||||
runtime.DefaultContextTimeout = 10 * time.Second
|
||||
annotated, err = runtime.AnnotateContext(ctx, request)
|
||||
if err != nil {
|
||||
t.Errorf("runtime.AnnotateContext(ctx, %#v) failed with %v; want success", request, err)
|
||||
return
|
||||
}
|
||||
deadline, ok := annotated.Deadline()
|
||||
if !ok {
|
||||
t.Errorf("annotated.Deadline() = _, false; want _, true")
|
||||
}
|
||||
if got, want := deadline.Sub(time.Now()), runtime.DefaultContextTimeout; got-want > acceptableError || got-want < -acceptableError {
|
||||
t.Errorf("deadline.Sub(time.Now()) = %v; want %v; with error %v", got, want, acceptableError)
|
||||
}
|
||||
|
||||
for _, spec := range []struct {
|
||||
timeout string
|
||||
want time.Duration
|
||||
}{
|
||||
{
|
||||
timeout: "17H",
|
||||
want: 17 * time.Hour,
|
||||
},
|
||||
{
|
||||
timeout: "19M",
|
||||
want: 19 * time.Minute,
|
||||
},
|
||||
{
|
||||
timeout: "23S",
|
||||
want: 23 * time.Second,
|
||||
},
|
||||
{
|
||||
timeout: "1009m",
|
||||
want: 1009 * time.Millisecond,
|
||||
},
|
||||
{
|
||||
timeout: "1000003u",
|
||||
want: 1000003 * time.Microsecond,
|
||||
},
|
||||
{
|
||||
timeout: "100000007n",
|
||||
want: 100000007 * time.Nanosecond,
|
||||
},
|
||||
} {
|
||||
request.Header.Set("Grpc-Timeout", spec.timeout)
|
||||
annotated, err = runtime.AnnotateContext(ctx, request)
|
||||
if err != nil {
|
||||
t.Errorf("runtime.AnnotateContext(ctx, %#v) failed with %v; want success", request, err)
|
||||
return
|
||||
}
|
||||
deadline, ok := annotated.Deadline()
|
||||
if !ok {
|
||||
t.Errorf("annotated.Deadline() = _, false; want _, true; timeout = %q", spec.timeout)
|
||||
}
|
||||
if got, want := deadline.Sub(time.Now()), spec.want; got-want > acceptableError || got-want < -acceptableError {
|
||||
t.Errorf("deadline.Sub(time.Now()) = %v; want %v; with error %v; timeout= %q", got, want, acceptableError, spec.timeout)
|
||||
}
|
||||
}
|
||||
}
|
58
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/convert.go
generated
vendored
Normal file
58
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/convert.go
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// String just returns the given string.
|
||||
// It is just for compatibility to other types.
|
||||
func String(val string) (string, error) {
|
||||
return val, nil
|
||||
}
|
||||
|
||||
// Bool converts the given string representation of a boolean value into bool.
|
||||
func Bool(val string) (bool, error) {
|
||||
return strconv.ParseBool(val)
|
||||
}
|
||||
|
||||
// Float64 converts the given string representation into representation of a floating point number into float64.
|
||||
func Float64(val string) (float64, error) {
|
||||
return strconv.ParseFloat(val, 64)
|
||||
}
|
||||
|
||||
// Float32 converts the given string representation of a floating point number into float32.
|
||||
func Float32(val string) (float32, error) {
|
||||
f, err := strconv.ParseFloat(val, 32)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return float32(f), nil
|
||||
}
|
||||
|
||||
// Int64 converts the given string representation of an integer into int64.
|
||||
func Int64(val string) (int64, error) {
|
||||
return strconv.ParseInt(val, 0, 64)
|
||||
}
|
||||
|
||||
// Int32 converts the given string representation of an integer into int32.
|
||||
func Int32(val string) (int32, error) {
|
||||
i, err := strconv.ParseInt(val, 0, 32)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int32(i), nil
|
||||
}
|
||||
|
||||
// Uint64 converts the given string representation of an integer into uint64.
|
||||
func Uint64(val string) (uint64, error) {
|
||||
return strconv.ParseUint(val, 0, 64)
|
||||
}
|
||||
|
||||
// Uint32 converts the given string representation of an integer into uint32.
|
||||
func Uint32(val string) (uint32, error) {
|
||||
i, err := strconv.ParseUint(val, 0, 32)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uint32(i), nil
|
||||
}
|
5
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/doc.go
generated
vendored
Normal file
5
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/doc.go
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
/*
|
||||
Package runtime contains runtime helper functions used by
|
||||
servers which protoc-gen-grpc-gateway generates.
|
||||
*/
|
||||
package runtime
|
121
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/errors.go
generated
vendored
Normal file
121
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/errors.go
generated
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
)
|
||||
|
||||
// HTTPStatusFromCode converts a gRPC error code into the corresponding HTTP response status.
|
||||
func HTTPStatusFromCode(code codes.Code) int {
|
||||
switch code {
|
||||
case codes.OK:
|
||||
return http.StatusOK
|
||||
case codes.Canceled:
|
||||
return http.StatusRequestTimeout
|
||||
case codes.Unknown:
|
||||
return http.StatusInternalServerError
|
||||
case codes.InvalidArgument:
|
||||
return http.StatusBadRequest
|
||||
case codes.DeadlineExceeded:
|
||||
return http.StatusRequestTimeout
|
||||
case codes.NotFound:
|
||||
return http.StatusNotFound
|
||||
case codes.AlreadyExists:
|
||||
return http.StatusConflict
|
||||
case codes.PermissionDenied:
|
||||
return http.StatusForbidden
|
||||
case codes.Unauthenticated:
|
||||
return http.StatusUnauthorized
|
||||
case codes.ResourceExhausted:
|
||||
return http.StatusForbidden
|
||||
case codes.FailedPrecondition:
|
||||
return http.StatusPreconditionFailed
|
||||
case codes.Aborted:
|
||||
return http.StatusConflict
|
||||
case codes.OutOfRange:
|
||||
return http.StatusBadRequest
|
||||
case codes.Unimplemented:
|
||||
return http.StatusNotImplemented
|
||||
case codes.Internal:
|
||||
return http.StatusInternalServerError
|
||||
case codes.Unavailable:
|
||||
return http.StatusServiceUnavailable
|
||||
case codes.DataLoss:
|
||||
return http.StatusInternalServerError
|
||||
}
|
||||
|
||||
grpclog.Printf("Unknown gRPC error code: %v", code)
|
||||
return http.StatusInternalServerError
|
||||
}
|
||||
|
||||
var (
|
||||
// HTTPError replies to the request with the error.
|
||||
// You can set a custom function to this variable to customize error format.
|
||||
HTTPError = DefaultHTTPError
|
||||
// OtherErrorHandler handles the following error used by the gateway: StatusMethodNotAllowed StatusNotFound and StatusBadRequest
|
||||
OtherErrorHandler = DefaultOtherErrorHandler
|
||||
)
|
||||
|
||||
type errorBody struct {
|
||||
Error string `protobuf:"bytes,1,name=error" json:"error"`
|
||||
Code int32 `protobuf:"varint,2,name=code" json:"code"`
|
||||
}
|
||||
|
||||
//Make this also conform to proto.Message for builtin JSONPb Marshaler
|
||||
func (e *errorBody) Reset() { *e = errorBody{} }
|
||||
func (e *errorBody) String() string { return proto.CompactTextString(e) }
|
||||
func (*errorBody) ProtoMessage() {}
|
||||
|
||||
// DefaultHTTPError is the default implementation of HTTPError.
|
||||
// If "err" is an error from gRPC system, the function replies with the status code mapped by HTTPStatusFromCode.
|
||||
// If otherwise, it replies with http.StatusInternalServerError.
|
||||
//
|
||||
// The response body returned by this function is a JSON object,
|
||||
// which contains a member whose key is "error" and whose value is err.Error().
|
||||
func DefaultHTTPError(ctx context.Context, marshaler Marshaler, w http.ResponseWriter, _ *http.Request, err error) {
|
||||
const fallback = `{"error": "failed to marshal error message"}`
|
||||
|
||||
w.Header().Del("Trailer")
|
||||
w.Header().Set("Content-Type", marshaler.ContentType())
|
||||
body := &errorBody{
|
||||
Error: grpc.ErrorDesc(err),
|
||||
Code: int32(grpc.Code(err)),
|
||||
}
|
||||
|
||||
buf, merr := marshaler.Marshal(body)
|
||||
if merr != nil {
|
||||
grpclog.Printf("Failed to marshal error message %q: %v", body, merr)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
if _, err := io.WriteString(w, fallback); err != nil {
|
||||
grpclog.Printf("Failed to write response: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
md, ok := ServerMetadataFromContext(ctx)
|
||||
if !ok {
|
||||
grpclog.Printf("Failed to extract ServerMetadata from context")
|
||||
}
|
||||
|
||||
handleForwardResponseServerMetadata(w, md)
|
||||
handleForwardResponseTrailerHeader(w, md)
|
||||
st := HTTPStatusFromCode(grpc.Code(err))
|
||||
w.WriteHeader(st)
|
||||
if _, err := w.Write(buf); err != nil {
|
||||
grpclog.Printf("Failed to write response: %v", err)
|
||||
}
|
||||
|
||||
handleForwardResponseTrailer(w, md)
|
||||
}
|
||||
|
||||
// DefaultOtherErrorHandler is the default implementation of OtherErrorHandler.
|
||||
// It simply writes a string representation of the given error into "w".
|
||||
func DefaultOtherErrorHandler(w http.ResponseWriter, _ *http.Request, msg string, code int) {
|
||||
http.Error(w, msg, code)
|
||||
}
|
56
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/errors_test.go
generated
vendored
Normal file
56
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/errors_test.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
package runtime_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/grpc-ecosystem/grpc-gateway/runtime"
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
)
|
||||
|
||||
func TestDefaultHTTPError(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
for _, spec := range []struct {
|
||||
err error
|
||||
status int
|
||||
msg string
|
||||
}{
|
||||
{
|
||||
err: fmt.Errorf("example error"),
|
||||
status: http.StatusInternalServerError,
|
||||
msg: "example error",
|
||||
},
|
||||
{
|
||||
err: grpc.Errorf(codes.NotFound, "no such resource"),
|
||||
status: http.StatusNotFound,
|
||||
msg: "no such resource",
|
||||
},
|
||||
} {
|
||||
w := httptest.NewRecorder()
|
||||
req, _ := http.NewRequest("", "", nil) // Pass in an empty request to match the signature
|
||||
runtime.DefaultHTTPError(ctx, &runtime.JSONBuiltin{}, w, req, spec.err)
|
||||
|
||||
if got, want := w.Header().Get("Content-Type"), "application/json"; got != want {
|
||||
t.Errorf(`w.Header().Get("Content-Type") = %q; want %q; on spec.err=%v`, got, want, spec.err)
|
||||
}
|
||||
if got, want := w.Code, spec.status; got != want {
|
||||
t.Errorf("w.Code = %d; want %d", got, want)
|
||||
}
|
||||
|
||||
body := make(map[string]interface{})
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &body); err != nil {
|
||||
t.Errorf("json.Unmarshal(%q, &body) failed with %v; want success", w.Body.Bytes(), err)
|
||||
continue
|
||||
}
|
||||
if got, want := body["error"].(string), spec.msg; !strings.Contains(got, want) {
|
||||
t.Errorf(`body["error"] = %q; want %q; on spec.err=%v`, got, want, spec.err)
|
||||
}
|
||||
}
|
||||
}
|
164
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/handler.go
generated
vendored
Normal file
164
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/handler.go
generated
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/textproto"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/runtime/internal"
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
)
|
||||
|
||||
// ForwardResponseStream forwards the stream from gRPC server to REST client.
|
||||
func ForwardResponseStream(ctx context.Context, marshaler Marshaler, w http.ResponseWriter, req *http.Request, recv func() (proto.Message, error), opts ...func(context.Context, http.ResponseWriter, proto.Message) error) {
|
||||
f, ok := w.(http.Flusher)
|
||||
if !ok {
|
||||
grpclog.Printf("Flush not supported in %T", w)
|
||||
http.Error(w, "unexpected type of web server", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
md, ok := ServerMetadataFromContext(ctx)
|
||||
if !ok {
|
||||
grpclog.Printf("Failed to extract ServerMetadata from context")
|
||||
http.Error(w, "unexpected error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
handleForwardResponseServerMetadata(w, md)
|
||||
|
||||
w.Header().Set("Transfer-Encoding", "chunked")
|
||||
w.Header().Set("Content-Type", marshaler.ContentType())
|
||||
if err := handleForwardResponseOptions(ctx, w, nil, opts); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
f.Flush()
|
||||
for {
|
||||
resp, err := recv()
|
||||
if err == io.EOF {
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
handleForwardResponseStreamError(marshaler, w, err)
|
||||
return
|
||||
}
|
||||
if err := handleForwardResponseOptions(ctx, w, resp, opts); err != nil {
|
||||
handleForwardResponseStreamError(marshaler, w, err)
|
||||
return
|
||||
}
|
||||
|
||||
buf, err := marshaler.Marshal(streamChunk(resp, nil))
|
||||
if err != nil {
|
||||
grpclog.Printf("Failed to marshal response chunk: %v", err)
|
||||
return
|
||||
}
|
||||
if _, err = fmt.Fprintf(w, "%s\n", buf); err != nil {
|
||||
grpclog.Printf("Failed to send response chunk: %v", err)
|
||||
return
|
||||
}
|
||||
f.Flush()
|
||||
}
|
||||
}
|
||||
|
||||
func handleForwardResponseServerMetadata(w http.ResponseWriter, md ServerMetadata) {
|
||||
for k, vs := range md.HeaderMD {
|
||||
hKey := fmt.Sprintf("%s%s", MetadataHeaderPrefix, k)
|
||||
for i := range vs {
|
||||
w.Header().Add(hKey, vs[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func handleForwardResponseTrailerHeader(w http.ResponseWriter, md ServerMetadata) {
|
||||
for k := range md.TrailerMD {
|
||||
tKey := textproto.CanonicalMIMEHeaderKey(fmt.Sprintf("%s%s", MetadataTrailerPrefix, k))
|
||||
w.Header().Add("Trailer", tKey)
|
||||
}
|
||||
}
|
||||
|
||||
func handleForwardResponseTrailer(w http.ResponseWriter, md ServerMetadata) {
|
||||
for k, vs := range md.TrailerMD {
|
||||
tKey := fmt.Sprintf("%s%s", MetadataTrailerPrefix, k)
|
||||
for i := range vs {
|
||||
w.Header().Add(tKey, vs[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ForwardResponseMessage forwards the message "resp" from gRPC server to REST client.
|
||||
func ForwardResponseMessage(ctx context.Context, marshaler Marshaler, w http.ResponseWriter, req *http.Request, resp proto.Message, opts ...func(context.Context, http.ResponseWriter, proto.Message) error) {
|
||||
md, ok := ServerMetadataFromContext(ctx)
|
||||
if !ok {
|
||||
grpclog.Printf("Failed to extract ServerMetadata from context")
|
||||
}
|
||||
|
||||
handleForwardResponseServerMetadata(w, md)
|
||||
handleForwardResponseTrailerHeader(w, md)
|
||||
w.Header().Set("Content-Type", marshaler.ContentType())
|
||||
if err := handleForwardResponseOptions(ctx, w, resp, opts); err != nil {
|
||||
HTTPError(ctx, marshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
buf, err := marshaler.Marshal(resp)
|
||||
if err != nil {
|
||||
grpclog.Printf("Marshal error: %v", err)
|
||||
HTTPError(ctx, marshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
if _, err = w.Write(buf); err != nil {
|
||||
grpclog.Printf("Failed to write response: %v", err)
|
||||
}
|
||||
|
||||
handleForwardResponseTrailer(w, md)
|
||||
}
|
||||
|
||||
func handleForwardResponseOptions(ctx context.Context, w http.ResponseWriter, resp proto.Message, opts []func(context.Context, http.ResponseWriter, proto.Message) error) error {
|
||||
if len(opts) == 0 {
|
||||
return nil
|
||||
}
|
||||
for _, opt := range opts {
|
||||
if err := opt(ctx, w, resp); err != nil {
|
||||
grpclog.Printf("Error handling ForwardResponseOptions: %v", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleForwardResponseStreamError(marshaler Marshaler, w http.ResponseWriter, err error) {
|
||||
buf, merr := marshaler.Marshal(streamChunk(nil, err))
|
||||
if merr != nil {
|
||||
grpclog.Printf("Failed to marshal an error: %v", merr)
|
||||
return
|
||||
}
|
||||
if _, werr := fmt.Fprintf(w, "%s\n", buf); werr != nil {
|
||||
grpclog.Printf("Failed to notify error to client: %v", werr)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func streamChunk(result proto.Message, err error) map[string]proto.Message {
|
||||
if err != nil {
|
||||
grpcCode := grpc.Code(err)
|
||||
httpCode := HTTPStatusFromCode(grpcCode)
|
||||
return map[string]proto.Message{
|
||||
"error": &internal.StreamError{
|
||||
GrpcCode: int32(grpcCode),
|
||||
HttpCode: int32(httpCode),
|
||||
Message: err.Error(),
|
||||
HttpStatus: http.StatusText(httpCode),
|
||||
},
|
||||
}
|
||||
}
|
||||
if result == nil {
|
||||
return streamChunk(nil, fmt.Errorf("empty response"))
|
||||
}
|
||||
return map[string]proto.Message{"result": result}
|
||||
}
|
93
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/internal/stream_chunk.pb.go
generated
vendored
Normal file
93
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/internal/stream_chunk.pb.go
generated
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
// Code generated by protoc-gen-go.
|
||||
// source: runtime/internal/stream_chunk.proto
|
||||
// DO NOT EDIT!
|
||||
|
||||
/*
|
||||
Package internal is a generated protocol buffer package.
|
||||
|
||||
It is generated from these files:
|
||||
runtime/internal/stream_chunk.proto
|
||||
|
||||
It has these top-level messages:
|
||||
StreamError
|
||||
*/
|
||||
package internal
|
||||
|
||||
import proto "github.com/golang/protobuf/proto"
|
||||
import fmt "fmt"
|
||||
import math "math"
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||
|
||||
// StreamError is a response type which is returned when
|
||||
// streaming rpc returns an error.
|
||||
type StreamError struct {
|
||||
GrpcCode int32 `protobuf:"varint,1,opt,name=grpc_code,json=grpcCode" json:"grpc_code,omitempty"`
|
||||
HttpCode int32 `protobuf:"varint,2,opt,name=http_code,json=httpCode" json:"http_code,omitempty"`
|
||||
Message string `protobuf:"bytes,3,opt,name=message" json:"message,omitempty"`
|
||||
HttpStatus string `protobuf:"bytes,4,opt,name=http_status,json=httpStatus" json:"http_status,omitempty"`
|
||||
}
|
||||
|
||||
func (m *StreamError) Reset() { *m = StreamError{} }
|
||||
func (m *StreamError) String() string { return proto.CompactTextString(m) }
|
||||
func (*StreamError) ProtoMessage() {}
|
||||
func (*StreamError) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
|
||||
|
||||
func (m *StreamError) GetGrpcCode() int32 {
|
||||
if m != nil {
|
||||
return m.GrpcCode
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *StreamError) GetHttpCode() int32 {
|
||||
if m != nil {
|
||||
return m.HttpCode
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *StreamError) GetMessage() string {
|
||||
if m != nil {
|
||||
return m.Message
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *StreamError) GetHttpStatus() string {
|
||||
if m != nil {
|
||||
return m.HttpStatus
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*StreamError)(nil), "grpc.gateway.runtime.StreamError")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("runtime/internal/stream_chunk.proto", fileDescriptor0) }
|
||||
|
||||
var fileDescriptor0 = []byte{
|
||||
// 181 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x34, 0x8e, 0xbf, 0xee, 0x82, 0x30,
|
||||
0x14, 0x85, 0xd3, 0xdf, 0x1f, 0x85, 0xcb, 0x46, 0x1c, 0x9a, 0x38, 0x48, 0x74, 0x61, 0x82, 0xc1,
|
||||
0x37, 0xd0, 0xf8, 0x02, 0xb0, 0xb9, 0x90, 0x0a, 0x37, 0x40, 0x94, 0x96, 0xdc, 0x5e, 0x62, 0x5c,
|
||||
0x7d, 0x72, 0xd3, 0x22, 0xe3, 0xf9, 0xbe, 0x73, 0x92, 0x03, 0x07, 0x9a, 0x34, 0xf7, 0x03, 0xe6,
|
||||
0xbd, 0x66, 0x24, 0xad, 0x1e, 0xb9, 0x65, 0x42, 0x35, 0x54, 0x75, 0x37, 0xe9, 0x7b, 0x36, 0x92,
|
||||
0x61, 0x13, 0x6f, 0x5a, 0x1a, 0xeb, 0xac, 0x55, 0x8c, 0x4f, 0xf5, 0xca, 0xbe, 0x8b, 0xfd, 0x5b,
|
||||
0x40, 0x54, 0xfa, 0xf2, 0x85, 0xc8, 0x50, 0xbc, 0x85, 0xd0, 0xf5, 0xaa, 0xda, 0x34, 0x28, 0x45,
|
||||
0x22, 0xd2, 0xff, 0x22, 0x70, 0xe0, 0x6c, 0x1a, 0x74, 0xb2, 0x63, 0x1e, 0x67, 0xf9, 0x33, 0x4b,
|
||||
0x07, 0xbc, 0x94, 0xb0, 0x1e, 0xd0, 0x5a, 0xd5, 0xa2, 0xfc, 0x4d, 0x44, 0x1a, 0x16, 0x4b, 0x8c,
|
||||
0x77, 0x10, 0xf9, 0x99, 0x65, 0xc5, 0x93, 0x95, 0x7f, 0xde, 0x82, 0x43, 0xa5, 0x27, 0x27, 0xb8,
|
||||
0x06, 0xcb, 0xf3, 0xdb, 0xca, 0xbf, 0x3d, 0x7e, 0x02, 0x00, 0x00, 0xff, 0xff, 0xa9, 0x07, 0x92,
|
||||
0xb6, 0xd4, 0x00, 0x00, 0x00,
|
||||
}
|
12
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/internal/stream_chunk.proto
generated
vendored
Normal file
12
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/internal/stream_chunk.proto
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
syntax = "proto3";
|
||||
package grpc.gateway.runtime;
|
||||
option go_package = "internal";
|
||||
|
||||
// StreamError is a response type which is returned when
|
||||
// streaming rpc returns an error.
|
||||
message StreamError {
|
||||
int32 grpc_code = 1;
|
||||
int32 http_code = 2;
|
||||
string message = 3;
|
||||
string http_status = 4;
|
||||
}
|
37
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/marshal_json.go
generated
vendored
Normal file
37
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/marshal_json.go
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
)
|
||||
|
||||
// JSONBuiltin is a Marshaler which marshals/unmarshals into/from JSON
|
||||
// with the standard "encoding/json" package of Golang.
|
||||
// Although it is generally faster for simple proto messages than JSONPb,
|
||||
// it does not support advanced features of protobuf, e.g. map, oneof, ....
|
||||
type JSONBuiltin struct{}
|
||||
|
||||
// ContentType always Returns "application/json".
|
||||
func (*JSONBuiltin) ContentType() string {
|
||||
return "application/json"
|
||||
}
|
||||
|
||||
// Marshal marshals "v" into JSON
|
||||
func (j *JSONBuiltin) Marshal(v interface{}) ([]byte, error) {
|
||||
return json.Marshal(v)
|
||||
}
|
||||
|
||||
// Unmarshal unmarshals JSON data into "v".
|
||||
func (j *JSONBuiltin) Unmarshal(data []byte, v interface{}) error {
|
||||
return json.Unmarshal(data, v)
|
||||
}
|
||||
|
||||
// NewDecoder returns a Decoder which reads JSON stream from "r".
|
||||
func (j *JSONBuiltin) NewDecoder(r io.Reader) Decoder {
|
||||
return json.NewDecoder(r)
|
||||
}
|
||||
|
||||
// NewEncoder returns an Encoder which writes JSON stream into "w".
|
||||
func (j *JSONBuiltin) NewEncoder(w io.Writer) Encoder {
|
||||
return json.NewEncoder(w)
|
||||
}
|
245
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/marshal_json_test.go
generated
vendored
Normal file
245
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/marshal_json_test.go
generated
vendored
Normal file
@@ -0,0 +1,245 @@
|
||||
package runtime_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/golang/protobuf/ptypes/empty"
|
||||
structpb "github.com/golang/protobuf/ptypes/struct"
|
||||
"github.com/golang/protobuf/ptypes/timestamp"
|
||||
"github.com/golang/protobuf/ptypes/wrappers"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/examples/examplepb"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/runtime"
|
||||
)
|
||||
|
||||
func TestJSONBuiltinMarshal(t *testing.T) {
|
||||
var m runtime.JSONBuiltin
|
||||
msg := examplepb.SimpleMessage{
|
||||
Id: "foo",
|
||||
}
|
||||
|
||||
buf, err := m.Marshal(&msg)
|
||||
if err != nil {
|
||||
t.Errorf("m.Marshal(%v) failed with %v; want success", &msg, err)
|
||||
}
|
||||
|
||||
var got examplepb.SimpleMessage
|
||||
if err := json.Unmarshal(buf, &got); err != nil {
|
||||
t.Errorf("json.Unmarshal(%q, &got) failed with %v; want success", buf, err)
|
||||
}
|
||||
if want := msg; !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("got = %v; want %v", &got, &want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONBuiltinMarshalField(t *testing.T) {
|
||||
var m runtime.JSONBuiltin
|
||||
for _, fixt := range builtinFieldFixtures {
|
||||
buf, err := m.Marshal(fixt.data)
|
||||
if err != nil {
|
||||
t.Errorf("m.Marshal(%v) failed with %v; want success", fixt.data, err)
|
||||
}
|
||||
if got, want := string(buf), fixt.json; got != want {
|
||||
t.Errorf("got = %q; want %q; data = %#v", got, want, fixt.data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONBuiltinMarshalFieldKnownErrors(t *testing.T) {
|
||||
var m runtime.JSONBuiltin
|
||||
for _, fixt := range builtinKnownErrors {
|
||||
buf, err := m.Marshal(fixt.data)
|
||||
if err != nil {
|
||||
t.Errorf("m.Marshal(%v) failed with %v; want success", fixt.data, err)
|
||||
}
|
||||
if got, want := string(buf), fixt.json; got == want {
|
||||
t.Errorf("surprisingly got = %q; as want %q; data = %#v", got, want, fixt.data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONBuiltinsnmarshal(t *testing.T) {
|
||||
var (
|
||||
m runtime.JSONBuiltin
|
||||
got examplepb.SimpleMessage
|
||||
|
||||
data = []byte(`{"id": "foo"}`)
|
||||
)
|
||||
if err := m.Unmarshal(data, &got); err != nil {
|
||||
t.Errorf("m.Unmarshal(%q, &got) failed with %v; want success", data, err)
|
||||
}
|
||||
|
||||
want := examplepb.SimpleMessage{
|
||||
Id: "foo",
|
||||
}
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("got = %v; want = %v", &got, &want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONBuiltinUnmarshalField(t *testing.T) {
|
||||
var m runtime.JSONBuiltin
|
||||
for _, fixt := range builtinFieldFixtures {
|
||||
dest := reflect.New(reflect.TypeOf(fixt.data))
|
||||
if err := m.Unmarshal([]byte(fixt.json), dest.Interface()); err != nil {
|
||||
t.Errorf("m.Unmarshal(%q, dest) failed with %v; want success", fixt.json, err)
|
||||
}
|
||||
|
||||
if got, want := dest.Elem().Interface(), fixt.data; !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("got = %#v; want = %#v; input = %q", got, want, fixt.json)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONBuiltinUnmarshalFieldKnownErrors(t *testing.T) {
|
||||
var m runtime.JSONBuiltin
|
||||
for _, fixt := range builtinKnownErrors {
|
||||
dest := reflect.New(reflect.TypeOf(fixt.data))
|
||||
if err := m.Unmarshal([]byte(fixt.json), dest.Interface()); err == nil {
|
||||
t.Errorf("m.Unmarshal(%q, dest) succeeded; want ane error", fixt.json)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONBuiltinEncoder(t *testing.T) {
|
||||
var m runtime.JSONBuiltin
|
||||
msg := examplepb.SimpleMessage{
|
||||
Id: "foo",
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
enc := m.NewEncoder(&buf)
|
||||
if err := enc.Encode(&msg); err != nil {
|
||||
t.Errorf("enc.Encode(%v) failed with %v; want success", &msg, err)
|
||||
}
|
||||
|
||||
var got examplepb.SimpleMessage
|
||||
if err := json.Unmarshal(buf.Bytes(), &got); err != nil {
|
||||
t.Errorf("json.Unmarshal(%q, &got) failed with %v; want success", buf.String(), err)
|
||||
}
|
||||
if want := msg; !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("got = %v; want %v", &got, &want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONBuiltinEncoderFields(t *testing.T) {
|
||||
var m runtime.JSONBuiltin
|
||||
for _, fixt := range builtinFieldFixtures {
|
||||
var buf bytes.Buffer
|
||||
enc := m.NewEncoder(&buf)
|
||||
if err := enc.Encode(fixt.data); err != nil {
|
||||
t.Errorf("enc.Encode(%#v) failed with %v; want success", fixt.data, err)
|
||||
}
|
||||
|
||||
if got, want := buf.String(), fixt.json+"\n"; got != want {
|
||||
t.Errorf("got = %q; want %q; data = %#v", got, want, fixt.data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONBuiltinDecoder(t *testing.T) {
|
||||
var (
|
||||
m runtime.JSONBuiltin
|
||||
got examplepb.SimpleMessage
|
||||
|
||||
data = `{"id": "foo"}`
|
||||
)
|
||||
r := strings.NewReader(data)
|
||||
dec := m.NewDecoder(r)
|
||||
if err := dec.Decode(&got); err != nil {
|
||||
t.Errorf("m.Unmarshal(&got) failed with %v; want success", err)
|
||||
}
|
||||
|
||||
want := examplepb.SimpleMessage{
|
||||
Id: "foo",
|
||||
}
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("got = %v; want = %v", &got, &want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONBuiltinDecoderFields(t *testing.T) {
|
||||
var m runtime.JSONBuiltin
|
||||
for _, fixt := range builtinFieldFixtures {
|
||||
r := strings.NewReader(fixt.json)
|
||||
dec := m.NewDecoder(r)
|
||||
dest := reflect.New(reflect.TypeOf(fixt.data))
|
||||
if err := dec.Decode(dest.Interface()); err != nil {
|
||||
t.Errorf("dec.Decode(dest) failed with %v; want success; data = %q", err, fixt.json)
|
||||
}
|
||||
|
||||
if got, want := dest.Elem().Interface(), fixt.data; !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("got = %v; want = %v; input = %q", got, want, fixt.json)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
builtinFieldFixtures = []struct {
|
||||
data interface{}
|
||||
json string
|
||||
}{
|
||||
{data: "", json: `""`},
|
||||
{data: proto.String(""), json: `""`},
|
||||
{data: "foo", json: `"foo"`},
|
||||
{data: proto.String("foo"), json: `"foo"`},
|
||||
{data: int32(-1), json: "-1"},
|
||||
{data: proto.Int32(-1), json: "-1"},
|
||||
{data: int64(-1), json: "-1"},
|
||||
{data: proto.Int64(-1), json: "-1"},
|
||||
{data: uint32(123), json: "123"},
|
||||
{data: proto.Uint32(123), json: "123"},
|
||||
{data: uint64(123), json: "123"},
|
||||
{data: proto.Uint64(123), json: "123"},
|
||||
{data: float32(-1.5), json: "-1.5"},
|
||||
{data: proto.Float32(-1.5), json: "-1.5"},
|
||||
{data: float64(-1.5), json: "-1.5"},
|
||||
{data: proto.Float64(-1.5), json: "-1.5"},
|
||||
{data: true, json: "true"},
|
||||
{data: proto.Bool(true), json: "true"},
|
||||
{data: (*string)(nil), json: "null"},
|
||||
{data: new(empty.Empty), json: "{}"},
|
||||
{data: examplepb.NumericEnum_ONE, json: "1"},
|
||||
{
|
||||
data: (*examplepb.NumericEnum)(proto.Int32(int32(examplepb.NumericEnum_ONE))),
|
||||
json: "1",
|
||||
},
|
||||
}
|
||||
builtinKnownErrors = []struct {
|
||||
data interface{}
|
||||
json string
|
||||
}{
|
||||
{data: examplepb.NumericEnum_ONE, json: "ONE"},
|
||||
{
|
||||
data: (*examplepb.NumericEnum)(proto.Int32(int32(examplepb.NumericEnum_ONE))),
|
||||
json: "ONE",
|
||||
},
|
||||
{
|
||||
data: &examplepb.ABitOfEverything_OneofString{OneofString: "abc"},
|
||||
json: `"abc"`,
|
||||
},
|
||||
{
|
||||
data: ×tamp.Timestamp{
|
||||
Seconds: 1462875553,
|
||||
Nanos: 123000000,
|
||||
},
|
||||
json: `"2016-05-10T10:19:13.123Z"`,
|
||||
},
|
||||
{
|
||||
data: &wrappers.Int32Value{Value: 123},
|
||||
json: "123",
|
||||
},
|
||||
{
|
||||
data: &structpb.Value{
|
||||
Kind: &structpb.Value_StringValue{
|
||||
StringValue: "abc",
|
||||
},
|
||||
},
|
||||
json: `"abc"`,
|
||||
},
|
||||
}
|
||||
)
|
184
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/marshal_jsonpb.go
generated
vendored
Normal file
184
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/marshal_jsonpb.go
generated
vendored
Normal file
@@ -0,0 +1,184 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
|
||||
"github.com/golang/protobuf/jsonpb"
|
||||
"github.com/golang/protobuf/proto"
|
||||
)
|
||||
|
||||
// JSONPb is a Marshaler which marshals/unmarshals into/from JSON
|
||||
// with the "github.com/golang/protobuf/jsonpb".
|
||||
// It supports fully functionality of protobuf unlike JSONBuiltin.
|
||||
type JSONPb jsonpb.Marshaler
|
||||
|
||||
// ContentType always returns "application/json".
|
||||
func (*JSONPb) ContentType() string {
|
||||
return "application/json"
|
||||
}
|
||||
|
||||
// Marshal marshals "v" into JSON
|
||||
// Currently it can marshal only proto.Message.
|
||||
// TODO(yugui) Support fields of primitive types in a message.
|
||||
func (j *JSONPb) Marshal(v interface{}) ([]byte, error) {
|
||||
if _, ok := v.(proto.Message); !ok {
|
||||
return j.marshalNonProtoField(v)
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := j.marshalTo(&buf, v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func (j *JSONPb) marshalTo(w io.Writer, v interface{}) error {
|
||||
p, ok := v.(proto.Message)
|
||||
if !ok {
|
||||
buf, err := j.marshalNonProtoField(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = w.Write(buf)
|
||||
return err
|
||||
}
|
||||
return (*jsonpb.Marshaler)(j).Marshal(w, p)
|
||||
}
|
||||
|
||||
// marshalNonProto marshals a non-message field of a protobuf message.
|
||||
// This function does not correctly marshals arbitary data structure into JSON,
|
||||
// but it is only capable of marshaling non-message field values of protobuf,
|
||||
// i.e. primitive types, enums; pointers to primitives or enums; maps from
|
||||
// integer/string types to primitives/enums/pointers to messages.
|
||||
func (j *JSONPb) marshalNonProtoField(v interface{}) ([]byte, error) {
|
||||
rv := reflect.ValueOf(v)
|
||||
for rv.Kind() == reflect.Ptr {
|
||||
if rv.IsNil() {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
rv = rv.Elem()
|
||||
}
|
||||
|
||||
if rv.Kind() == reflect.Map {
|
||||
m := make(map[string]*json.RawMessage)
|
||||
for _, k := range rv.MapKeys() {
|
||||
buf, err := j.Marshal(rv.MapIndex(k).Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m[fmt.Sprintf("%v", k.Interface())] = (*json.RawMessage)(&buf)
|
||||
}
|
||||
if j.Indent != "" {
|
||||
return json.MarshalIndent(m, "", j.Indent)
|
||||
}
|
||||
return json.Marshal(m)
|
||||
}
|
||||
if enum, ok := rv.Interface().(protoEnum); ok && !j.EnumsAsInts {
|
||||
return json.Marshal(enum.String())
|
||||
}
|
||||
return json.Marshal(rv.Interface())
|
||||
}
|
||||
|
||||
// Unmarshal unmarshals JSON "data" into "v"
|
||||
// Currently it can marshal only proto.Message.
|
||||
// TODO(yugui) Support fields of primitive types in a message.
|
||||
func (j *JSONPb) Unmarshal(data []byte, v interface{}) error {
|
||||
return unmarshalJSONPb(data, v)
|
||||
}
|
||||
|
||||
// NewDecoder returns a Decoder which reads JSON stream from "r".
|
||||
func (j *JSONPb) NewDecoder(r io.Reader) Decoder {
|
||||
d := json.NewDecoder(r)
|
||||
return DecoderFunc(func(v interface{}) error { return decodeJSONPb(d, v) })
|
||||
}
|
||||
|
||||
// NewEncoder returns an Encoder which writes JSON stream into "w".
|
||||
func (j *JSONPb) NewEncoder(w io.Writer) Encoder {
|
||||
return EncoderFunc(func(v interface{}) error { return j.marshalTo(w, v) })
|
||||
}
|
||||
|
||||
func unmarshalJSONPb(data []byte, v interface{}) error {
|
||||
d := json.NewDecoder(bytes.NewReader(data))
|
||||
return decodeJSONPb(d, v)
|
||||
}
|
||||
|
||||
func decodeJSONPb(d *json.Decoder, v interface{}) error {
|
||||
p, ok := v.(proto.Message)
|
||||
if !ok {
|
||||
return decodeNonProtoField(d, v)
|
||||
}
|
||||
unmarshaler := &jsonpb.Unmarshaler{AllowUnknownFields: true}
|
||||
return unmarshaler.UnmarshalNext(d, p)
|
||||
}
|
||||
|
||||
func decodeNonProtoField(d *json.Decoder, v interface{}) error {
|
||||
rv := reflect.ValueOf(v)
|
||||
if rv.Kind() != reflect.Ptr {
|
||||
return fmt.Errorf("%T is not a pointer", v)
|
||||
}
|
||||
for rv.Kind() == reflect.Ptr {
|
||||
if rv.IsNil() {
|
||||
rv.Set(reflect.New(rv.Type().Elem()))
|
||||
}
|
||||
if rv.Type().ConvertibleTo(typeProtoMessage) {
|
||||
unmarshaler := &jsonpb.Unmarshaler{AllowUnknownFields: true}
|
||||
return unmarshaler.UnmarshalNext(d, rv.Interface().(proto.Message))
|
||||
}
|
||||
rv = rv.Elem()
|
||||
}
|
||||
if rv.Kind() == reflect.Map {
|
||||
if rv.IsNil() {
|
||||
rv.Set(reflect.MakeMap(rv.Type()))
|
||||
}
|
||||
conv, ok := convFromType[rv.Type().Key().Kind()]
|
||||
if !ok {
|
||||
return fmt.Errorf("unsupported type of map field key: %v", rv.Type().Key())
|
||||
}
|
||||
|
||||
m := make(map[string]*json.RawMessage)
|
||||
if err := d.Decode(&m); err != nil {
|
||||
return err
|
||||
}
|
||||
for k, v := range m {
|
||||
result := conv.Call([]reflect.Value{reflect.ValueOf(k)})
|
||||
if err := result[1].Interface(); err != nil {
|
||||
return err.(error)
|
||||
}
|
||||
bk := result[0]
|
||||
bv := reflect.New(rv.Type().Elem())
|
||||
if err := unmarshalJSONPb([]byte(*v), bv.Interface()); err != nil {
|
||||
return err
|
||||
}
|
||||
rv.SetMapIndex(bk, bv.Elem())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if _, ok := rv.Interface().(protoEnum); ok {
|
||||
var repr interface{}
|
||||
if err := d.Decode(&repr); err != nil {
|
||||
return err
|
||||
}
|
||||
switch repr.(type) {
|
||||
case string:
|
||||
// TODO(yugui) Should use proto.StructProperties?
|
||||
return fmt.Errorf("unmarshaling of symbolic enum %q not supported: %T", repr, rv.Interface())
|
||||
case float64:
|
||||
rv.Set(reflect.ValueOf(int32(repr.(float64))).Convert(rv.Type()))
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("cannot assign %#v into Go type %T", repr, rv.Interface())
|
||||
}
|
||||
}
|
||||
return d.Decode(v)
|
||||
}
|
||||
|
||||
type protoEnum interface {
|
||||
fmt.Stringer
|
||||
EnumDescriptor() ([]byte, []int)
|
||||
}
|
||||
|
||||
var typeProtoMessage = reflect.TypeOf((*proto.Message)(nil)).Elem()
|
606
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/marshal_jsonpb_test.go
generated
vendored
Normal file
606
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/marshal_jsonpb_test.go
generated
vendored
Normal file
@@ -0,0 +1,606 @@
|
||||
package runtime_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/protobuf/jsonpb"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/golang/protobuf/ptypes/duration"
|
||||
"github.com/golang/protobuf/ptypes/empty"
|
||||
structpb "github.com/golang/protobuf/ptypes/struct"
|
||||
"github.com/golang/protobuf/ptypes/timestamp"
|
||||
"github.com/golang/protobuf/ptypes/wrappers"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/examples/examplepb"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/runtime"
|
||||
)
|
||||
|
||||
func TestJSONPbMarshal(t *testing.T) {
|
||||
msg := examplepb.ABitOfEverything{
|
||||
Uuid: "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7",
|
||||
Nested: []*examplepb.ABitOfEverything_Nested{
|
||||
{
|
||||
Name: "foo",
|
||||
Amount: 12345,
|
||||
},
|
||||
},
|
||||
Uint64Value: 0xFFFFFFFFFFFFFFFF,
|
||||
EnumValue: examplepb.NumericEnum_ONE,
|
||||
OneofValue: &examplepb.ABitOfEverything_OneofString{
|
||||
OneofString: "bar",
|
||||
},
|
||||
MapValue: map[string]examplepb.NumericEnum{
|
||||
"a": examplepb.NumericEnum_ONE,
|
||||
"b": examplepb.NumericEnum_ZERO,
|
||||
},
|
||||
}
|
||||
|
||||
for _, spec := range []struct {
|
||||
enumsAsInts, emitDefaults bool
|
||||
indent string
|
||||
origName bool
|
||||
verifier func(json string)
|
||||
}{
|
||||
{
|
||||
verifier: func(json string) {
|
||||
if strings.ContainsAny(json, " \t\r\n") {
|
||||
t.Errorf("strings.ContainsAny(%q, %q) = true; want false", json, " \t\r\n")
|
||||
}
|
||||
if !strings.Contains(json, "ONE") {
|
||||
t.Errorf(`strings.Contains(%q, "ONE") = false; want true`, json)
|
||||
}
|
||||
if want := "uint64Value"; !strings.Contains(json, want) {
|
||||
t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
enumsAsInts: true,
|
||||
verifier: func(json string) {
|
||||
if strings.Contains(json, "ONE") {
|
||||
t.Errorf(`strings.Contains(%q, "ONE") = true; want false`, json)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
emitDefaults: true,
|
||||
verifier: func(json string) {
|
||||
if want := `"sfixed32Value"`; !strings.Contains(json, want) {
|
||||
t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
indent: "\t\t",
|
||||
verifier: func(json string) {
|
||||
if want := "\t\t\"amount\":"; !strings.Contains(json, want) {
|
||||
t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
origName: true,
|
||||
verifier: func(json string) {
|
||||
if want := "uint64_value"; !strings.Contains(json, want) {
|
||||
t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want)
|
||||
}
|
||||
},
|
||||
},
|
||||
} {
|
||||
m := runtime.JSONPb{
|
||||
EnumsAsInts: spec.enumsAsInts,
|
||||
EmitDefaults: spec.emitDefaults,
|
||||
Indent: spec.indent,
|
||||
OrigName: spec.origName,
|
||||
}
|
||||
buf, err := m.Marshal(&msg)
|
||||
if err != nil {
|
||||
t.Errorf("m.Marshal(%v) failed with %v; want success; spec=%v", &msg, err, spec)
|
||||
}
|
||||
|
||||
var got examplepb.ABitOfEverything
|
||||
if err := jsonpb.UnmarshalString(string(buf), &got); err != nil {
|
||||
t.Errorf("jsonpb.UnmarshalString(%q, &got) failed with %v; want success; spec=%v", string(buf), err, spec)
|
||||
}
|
||||
if want := msg; !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("got = %v; want %v; spec=%v", &got, &want, spec)
|
||||
}
|
||||
if spec.verifier != nil {
|
||||
spec.verifier(string(buf))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONPbMarshalFields(t *testing.T) {
|
||||
var m runtime.JSONPb
|
||||
for _, spec := range []struct {
|
||||
val interface{}
|
||||
want string
|
||||
}{} {
|
||||
buf, err := m.Marshal(spec.val)
|
||||
if err != nil {
|
||||
t.Errorf("m.Marshal(%#v) failed with %v; want success", spec.val, err)
|
||||
}
|
||||
if got, want := string(buf), spec.want; got != want {
|
||||
t.Errorf("m.Marshal(%#v) = %q; want %q", spec.val, got, want)
|
||||
}
|
||||
}
|
||||
|
||||
m.EnumsAsInts = true
|
||||
buf, err := m.Marshal(examplepb.NumericEnum_ONE)
|
||||
if err != nil {
|
||||
t.Errorf("m.Marshal(%#v) failed with %v; want success", examplepb.NumericEnum_ONE, err)
|
||||
}
|
||||
if got, want := string(buf), "1"; got != want {
|
||||
t.Errorf("m.Marshal(%#v) = %q; want %q", examplepb.NumericEnum_ONE, got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONPbUnmarshal(t *testing.T) {
|
||||
var (
|
||||
m runtime.JSONPb
|
||||
got examplepb.ABitOfEverything
|
||||
)
|
||||
for _, data := range []string{
|
||||
`{
|
||||
"uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7",
|
||||
"nested": [
|
||||
{"name": "foo", "amount": 12345}
|
||||
],
|
||||
"uint64Value": 18446744073709551615,
|
||||
"enumValue": "ONE",
|
||||
"oneofString": "bar",
|
||||
"mapValue": {
|
||||
"a": 1,
|
||||
"b": 0
|
||||
}
|
||||
}`,
|
||||
`{
|
||||
"uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7",
|
||||
"nested": [
|
||||
{"name": "foo", "amount": 12345}
|
||||
],
|
||||
"uint64Value": "18446744073709551615",
|
||||
"enumValue": "ONE",
|
||||
"oneofString": "bar",
|
||||
"mapValue": {
|
||||
"a": 1,
|
||||
"b": 0
|
||||
}
|
||||
}`,
|
||||
`{
|
||||
"uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7",
|
||||
"nested": [
|
||||
{"name": "foo", "amount": 12345}
|
||||
],
|
||||
"uint64Value": 18446744073709551615,
|
||||
"enumValue": 1,
|
||||
"oneofString": "bar",
|
||||
"mapValue": {
|
||||
"a": 1,
|
||||
"b": 0
|
||||
}
|
||||
}`,
|
||||
} {
|
||||
if err := m.Unmarshal([]byte(data), &got); err != nil {
|
||||
t.Errorf("m.Unmarshal(%q, &got) failed with %v; want success", data, err)
|
||||
}
|
||||
|
||||
want := examplepb.ABitOfEverything{
|
||||
Uuid: "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7",
|
||||
Nested: []*examplepb.ABitOfEverything_Nested{
|
||||
{
|
||||
Name: "foo",
|
||||
Amount: 12345,
|
||||
},
|
||||
},
|
||||
Uint64Value: 0xFFFFFFFFFFFFFFFF,
|
||||
EnumValue: examplepb.NumericEnum_ONE,
|
||||
OneofValue: &examplepb.ABitOfEverything_OneofString{
|
||||
OneofString: "bar",
|
||||
},
|
||||
MapValue: map[string]examplepb.NumericEnum{
|
||||
"a": examplepb.NumericEnum_ONE,
|
||||
"b": examplepb.NumericEnum_ZERO,
|
||||
},
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("got = %v; want = %v", &got, &want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONPbUnmarshalFields(t *testing.T) {
|
||||
var m runtime.JSONPb
|
||||
for _, fixt := range fieldFixtures {
|
||||
if fixt.skipUnmarshal {
|
||||
continue
|
||||
}
|
||||
|
||||
dest := reflect.New(reflect.TypeOf(fixt.data))
|
||||
if err := m.Unmarshal([]byte(fixt.json), dest.Interface()); err != nil {
|
||||
t.Errorf("m.Unmarshal(%q, %T) failed with %v; want success", fixt.json, dest.Interface(), err)
|
||||
}
|
||||
if got, want := dest.Elem().Interface(), fixt.data; !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("dest = %#v; want %#v; input = %v", got, want, fixt.json)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONPbEncoder(t *testing.T) {
|
||||
msg := examplepb.ABitOfEverything{
|
||||
Uuid: "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7",
|
||||
Nested: []*examplepb.ABitOfEverything_Nested{
|
||||
{
|
||||
Name: "foo",
|
||||
Amount: 12345,
|
||||
},
|
||||
},
|
||||
Uint64Value: 0xFFFFFFFFFFFFFFFF,
|
||||
OneofValue: &examplepb.ABitOfEverything_OneofString{
|
||||
OneofString: "bar",
|
||||
},
|
||||
MapValue: map[string]examplepb.NumericEnum{
|
||||
"a": examplepb.NumericEnum_ONE,
|
||||
"b": examplepb.NumericEnum_ZERO,
|
||||
},
|
||||
}
|
||||
|
||||
for _, spec := range []struct {
|
||||
enumsAsInts, emitDefaults bool
|
||||
indent string
|
||||
origName bool
|
||||
verifier func(json string)
|
||||
}{
|
||||
{
|
||||
verifier: func(json string) {
|
||||
if strings.ContainsAny(json, " \t\r\n") {
|
||||
t.Errorf("strings.ContainsAny(%q, %q) = true; want false", json, " \t\r\n")
|
||||
}
|
||||
if strings.Contains(json, "ONE") {
|
||||
t.Errorf(`strings.Contains(%q, "ONE") = true; want false`, json)
|
||||
}
|
||||
if want := "uint64Value"; !strings.Contains(json, want) {
|
||||
t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
enumsAsInts: true,
|
||||
verifier: func(json string) {
|
||||
if strings.Contains(json, "ONE") {
|
||||
t.Errorf(`strings.Contains(%q, "ONE") = true; want false`, json)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
emitDefaults: true,
|
||||
verifier: func(json string) {
|
||||
if want := `"sfixed32Value"`; !strings.Contains(json, want) {
|
||||
t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
indent: "\t\t",
|
||||
verifier: func(json string) {
|
||||
if want := "\t\t\"amount\":"; !strings.Contains(json, want) {
|
||||
t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
origName: true,
|
||||
verifier: func(json string) {
|
||||
if want := "uint64_value"; !strings.Contains(json, want) {
|
||||
t.Errorf(`strings.Contains(%q, %q) = false; want true`, json, want)
|
||||
}
|
||||
},
|
||||
},
|
||||
} {
|
||||
m := runtime.JSONPb{
|
||||
EnumsAsInts: spec.enumsAsInts,
|
||||
EmitDefaults: spec.emitDefaults,
|
||||
Indent: spec.indent,
|
||||
OrigName: spec.origName,
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
enc := m.NewEncoder(&buf)
|
||||
if err := enc.Encode(&msg); err != nil {
|
||||
t.Errorf("enc.Encode(%v) failed with %v; want success; spec=%v", &msg, err, spec)
|
||||
}
|
||||
|
||||
var got examplepb.ABitOfEverything
|
||||
if err := jsonpb.UnmarshalString(buf.String(), &got); err != nil {
|
||||
t.Errorf("jsonpb.UnmarshalString(%q, &got) failed with %v; want success; spec=%v", buf.String(), err, spec)
|
||||
}
|
||||
if want := msg; !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("got = %v; want %v; spec=%v", &got, &want, spec)
|
||||
}
|
||||
if spec.verifier != nil {
|
||||
spec.verifier(buf.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONPbEncoderFields(t *testing.T) {
|
||||
var m runtime.JSONPb
|
||||
for _, fixt := range fieldFixtures {
|
||||
var buf bytes.Buffer
|
||||
enc := m.NewEncoder(&buf)
|
||||
if err := enc.Encode(fixt.data); err != nil {
|
||||
t.Errorf("enc.Encode(%#v) failed with %v; want success", fixt.data, err)
|
||||
}
|
||||
if got, want := buf.String(), fixt.json; got != want {
|
||||
t.Errorf("enc.Encode(%#v) = %q; want %q", fixt.data, got, want)
|
||||
}
|
||||
}
|
||||
|
||||
m.EnumsAsInts = true
|
||||
buf, err := m.Marshal(examplepb.NumericEnum_ONE)
|
||||
if err != nil {
|
||||
t.Errorf("m.Marshal(%#v) failed with %v; want success", examplepb.NumericEnum_ONE, err)
|
||||
}
|
||||
if got, want := string(buf), "1"; got != want {
|
||||
t.Errorf("m.Marshal(%#v) = %q; want %q", examplepb.NumericEnum_ONE, got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONPbDecoder(t *testing.T) {
|
||||
var (
|
||||
m runtime.JSONPb
|
||||
got examplepb.ABitOfEverything
|
||||
)
|
||||
for _, data := range []string{
|
||||
`{
|
||||
"uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7",
|
||||
"nested": [
|
||||
{"name": "foo", "amount": 12345}
|
||||
],
|
||||
"uint64Value": 18446744073709551615,
|
||||
"enumValue": "ONE",
|
||||
"oneofString": "bar",
|
||||
"mapValue": {
|
||||
"a": 1,
|
||||
"b": 0
|
||||
}
|
||||
}`,
|
||||
`{
|
||||
"uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7",
|
||||
"nested": [
|
||||
{"name": "foo", "amount": 12345}
|
||||
],
|
||||
"uint64Value": "18446744073709551615",
|
||||
"enumValue": "ONE",
|
||||
"oneofString": "bar",
|
||||
"mapValue": {
|
||||
"a": 1,
|
||||
"b": 0
|
||||
}
|
||||
}`,
|
||||
`{
|
||||
"uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7",
|
||||
"nested": [
|
||||
{"name": "foo", "amount": 12345}
|
||||
],
|
||||
"uint64Value": 18446744073709551615,
|
||||
"enumValue": 1,
|
||||
"oneofString": "bar",
|
||||
"mapValue": {
|
||||
"a": 1,
|
||||
"b": 0
|
||||
}
|
||||
}`,
|
||||
} {
|
||||
r := strings.NewReader(data)
|
||||
dec := m.NewDecoder(r)
|
||||
if err := dec.Decode(&got); err != nil {
|
||||
t.Errorf("m.Unmarshal(&got) failed with %v; want success; data=%q", err, data)
|
||||
}
|
||||
|
||||
want := examplepb.ABitOfEverything{
|
||||
Uuid: "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7",
|
||||
Nested: []*examplepb.ABitOfEverything_Nested{
|
||||
{
|
||||
Name: "foo",
|
||||
Amount: 12345,
|
||||
},
|
||||
},
|
||||
Uint64Value: 0xFFFFFFFFFFFFFFFF,
|
||||
EnumValue: examplepb.NumericEnum_ONE,
|
||||
OneofValue: &examplepb.ABitOfEverything_OneofString{
|
||||
OneofString: "bar",
|
||||
},
|
||||
MapValue: map[string]examplepb.NumericEnum{
|
||||
"a": examplepb.NumericEnum_ONE,
|
||||
"b": examplepb.NumericEnum_ZERO,
|
||||
},
|
||||
}
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("got = %v; want = %v; data = %v", &got, &want, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONPbDecoderFields(t *testing.T) {
|
||||
var m runtime.JSONPb
|
||||
for _, fixt := range fieldFixtures {
|
||||
if fixt.skipUnmarshal {
|
||||
continue
|
||||
}
|
||||
|
||||
dest := reflect.New(reflect.TypeOf(fixt.data))
|
||||
dec := m.NewDecoder(strings.NewReader(fixt.json))
|
||||
if err := dec.Decode(dest.Interface()); err != nil {
|
||||
t.Errorf("dec.Decode(%T) failed with %v; want success; input = %q", dest.Interface(), err, fixt.json)
|
||||
}
|
||||
if got, want := dest.Elem().Interface(), fixt.data; !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("dest = %#v; want %#v; input = %v", got, want, fixt.json)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
fieldFixtures = []struct {
|
||||
data interface{}
|
||||
json string
|
||||
skipUnmarshal bool
|
||||
}{
|
||||
{data: int32(1), json: "1"},
|
||||
{data: proto.Int32(1), json: "1"},
|
||||
{data: int64(1), json: "1"},
|
||||
{data: proto.Int64(1), json: "1"},
|
||||
{data: uint32(1), json: "1"},
|
||||
{data: proto.Uint32(1), json: "1"},
|
||||
{data: uint64(1), json: "1"},
|
||||
{data: proto.Uint64(1), json: "1"},
|
||||
{data: "abc", json: `"abc"`},
|
||||
{data: proto.String("abc"), json: `"abc"`},
|
||||
{data: float32(1.5), json: "1.5"},
|
||||
{data: proto.Float32(1.5), json: "1.5"},
|
||||
{data: float64(1.5), json: "1.5"},
|
||||
{data: proto.Float64(1.5), json: "1.5"},
|
||||
{data: true, json: "true"},
|
||||
{data: false, json: "false"},
|
||||
{data: (*string)(nil), json: "null"},
|
||||
{
|
||||
data: examplepb.NumericEnum_ONE,
|
||||
json: `"ONE"`,
|
||||
// TODO(yugui) support unmarshaling of symbolic enum
|
||||
skipUnmarshal: true,
|
||||
},
|
||||
{
|
||||
data: (*examplepb.NumericEnum)(proto.Int32(int32(examplepb.NumericEnum_ONE))),
|
||||
json: `"ONE"`,
|
||||
// TODO(yugui) support unmarshaling of symbolic enum
|
||||
skipUnmarshal: true,
|
||||
},
|
||||
|
||||
{
|
||||
data: map[string]int32{
|
||||
"foo": 1,
|
||||
},
|
||||
json: `{"foo":1}`,
|
||||
},
|
||||
{
|
||||
data: map[string]*examplepb.SimpleMessage{
|
||||
"foo": {Id: "bar"},
|
||||
},
|
||||
json: `{"foo":{"id":"bar"}}`,
|
||||
},
|
||||
{
|
||||
data: map[int32]*examplepb.SimpleMessage{
|
||||
1: {Id: "foo"},
|
||||
},
|
||||
json: `{"1":{"id":"foo"}}`,
|
||||
},
|
||||
{
|
||||
data: map[bool]*examplepb.SimpleMessage{
|
||||
true: {Id: "foo"},
|
||||
},
|
||||
json: `{"true":{"id":"foo"}}`,
|
||||
},
|
||||
{
|
||||
data: &duration.Duration{
|
||||
Seconds: 123,
|
||||
Nanos: 456000000,
|
||||
},
|
||||
json: `"123.456s"`,
|
||||
},
|
||||
{
|
||||
data: ×tamp.Timestamp{
|
||||
Seconds: 1462875553,
|
||||
Nanos: 123000000,
|
||||
},
|
||||
json: `"2016-05-10T10:19:13.123Z"`,
|
||||
},
|
||||
{
|
||||
data: new(empty.Empty),
|
||||
json: "{}",
|
||||
},
|
||||
|
||||
// TODO(yugui) Enable unmarshaling of the following examples
|
||||
// once jsonpb supports them.
|
||||
{
|
||||
data: &structpb.Value{
|
||||
Kind: new(structpb.Value_NullValue),
|
||||
},
|
||||
json: "null",
|
||||
skipUnmarshal: true,
|
||||
},
|
||||
{
|
||||
data: &structpb.Value{
|
||||
Kind: &structpb.Value_NumberValue{
|
||||
NumberValue: 123.4,
|
||||
},
|
||||
},
|
||||
json: "123.4",
|
||||
skipUnmarshal: true,
|
||||
},
|
||||
{
|
||||
data: &structpb.Value{
|
||||
Kind: &structpb.Value_StringValue{
|
||||
StringValue: "abc",
|
||||
},
|
||||
},
|
||||
json: `"abc"`,
|
||||
skipUnmarshal: true,
|
||||
},
|
||||
{
|
||||
data: &structpb.Value{
|
||||
Kind: &structpb.Value_BoolValue{
|
||||
BoolValue: true,
|
||||
},
|
||||
},
|
||||
json: "true",
|
||||
skipUnmarshal: true,
|
||||
},
|
||||
{
|
||||
data: &structpb.Struct{
|
||||
Fields: map[string]*structpb.Value{
|
||||
"foo_bar": {
|
||||
Kind: &structpb.Value_BoolValue{
|
||||
BoolValue: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
json: `{"foo_bar":true}`,
|
||||
skipUnmarshal: true,
|
||||
},
|
||||
|
||||
{
|
||||
data: &wrappers.BoolValue{Value: true},
|
||||
json: "true",
|
||||
},
|
||||
{
|
||||
data: &wrappers.DoubleValue{Value: 123.456},
|
||||
json: "123.456",
|
||||
},
|
||||
{
|
||||
data: &wrappers.FloatValue{Value: 123.456},
|
||||
json: "123.456",
|
||||
},
|
||||
{
|
||||
data: &wrappers.Int32Value{Value: -123},
|
||||
json: "-123",
|
||||
},
|
||||
{
|
||||
data: &wrappers.Int64Value{Value: -123},
|
||||
json: `"-123"`,
|
||||
},
|
||||
{
|
||||
data: &wrappers.UInt32Value{Value: 123},
|
||||
json: "123",
|
||||
},
|
||||
{
|
||||
data: &wrappers.UInt64Value{Value: 123},
|
||||
json: `"123"`,
|
||||
},
|
||||
// TODO(yugui) Add other well-known types once jsonpb supports them
|
||||
}
|
||||
)
|
42
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/marshaler.go
generated
vendored
Normal file
42
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/marshaler.go
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// Marshaler defines a conversion between byte sequence and gRPC payloads / fields.
|
||||
type Marshaler interface {
|
||||
// Marshal marshals "v" into byte sequence.
|
||||
Marshal(v interface{}) ([]byte, error)
|
||||
// Unmarshal unmarshals "data" into "v".
|
||||
// "v" must be a pointer value.
|
||||
Unmarshal(data []byte, v interface{}) error
|
||||
// NewDecoder returns a Decoder which reads byte sequence from "r".
|
||||
NewDecoder(r io.Reader) Decoder
|
||||
// NewEncoder returns an Encoder which writes bytes sequence into "w".
|
||||
NewEncoder(w io.Writer) Encoder
|
||||
// ContentType returns the Content-Type which this marshaler is responsible for.
|
||||
ContentType() string
|
||||
}
|
||||
|
||||
// Decoder decodes a byte sequence
|
||||
type Decoder interface {
|
||||
Decode(v interface{}) error
|
||||
}
|
||||
|
||||
// Encoder encodes gRPC payloads / fields into byte sequence.
|
||||
type Encoder interface {
|
||||
Encode(v interface{}) error
|
||||
}
|
||||
|
||||
// DecoderFunc adapts an decoder function into Decoder.
|
||||
type DecoderFunc func(v interface{}) error
|
||||
|
||||
// Decode delegates invocations to the underlying function itself.
|
||||
func (f DecoderFunc) Decode(v interface{}) error { return f(v) }
|
||||
|
||||
// EncoderFunc adapts an encoder function into Encoder
|
||||
type EncoderFunc func(v interface{}) error
|
||||
|
||||
// Encode delegates invocations to the underlying function itself.
|
||||
func (f EncoderFunc) Encode(v interface{}) error { return f(v) }
|
91
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/marshaler_registry.go
generated
vendored
Normal file
91
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/marshaler_registry.go
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// MIMEWildcard is the fallback MIME type used for requests which do not match
|
||||
// a registered MIME type.
|
||||
const MIMEWildcard = "*"
|
||||
|
||||
var (
|
||||
acceptHeader = http.CanonicalHeaderKey("Accept")
|
||||
contentTypeHeader = http.CanonicalHeaderKey("Content-Type")
|
||||
|
||||
defaultMarshaler = &JSONPb{OrigName: true}
|
||||
)
|
||||
|
||||
// MarshalerForRequest returns the inbound/outbound marshalers for this request.
|
||||
// It checks the registry on the ServeMux for the MIME type set by the Content-Type header.
|
||||
// If it isn't set (or the request Content-Type is empty), checks for "*".
|
||||
// If there are multiple Content-Type headers set, choose the first one that it can
|
||||
// exactly match in the registry.
|
||||
// Otherwise, it follows the above logic for "*"/InboundMarshaler/OutboundMarshaler.
|
||||
func MarshalerForRequest(mux *ServeMux, r *http.Request) (inbound Marshaler, outbound Marshaler) {
|
||||
for _, acceptVal := range r.Header[acceptHeader] {
|
||||
if m, ok := mux.marshalers.mimeMap[acceptVal]; ok {
|
||||
outbound = m
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for _, contentTypeVal := range r.Header[contentTypeHeader] {
|
||||
if m, ok := mux.marshalers.mimeMap[contentTypeVal]; ok {
|
||||
inbound = m
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if inbound == nil {
|
||||
inbound = mux.marshalers.mimeMap[MIMEWildcard]
|
||||
}
|
||||
if outbound == nil {
|
||||
outbound = inbound
|
||||
}
|
||||
|
||||
return inbound, outbound
|
||||
}
|
||||
|
||||
// marshalerRegistry is a mapping from MIME types to Marshalers.
|
||||
type marshalerRegistry struct {
|
||||
mimeMap map[string]Marshaler
|
||||
}
|
||||
|
||||
// add adds a marshaler for a case-sensitive MIME type string ("*" to match any
|
||||
// MIME type).
|
||||
func (m marshalerRegistry) add(mime string, marshaler Marshaler) error {
|
||||
if len(mime) == 0 {
|
||||
return errors.New("empty MIME type")
|
||||
}
|
||||
|
||||
m.mimeMap[mime] = marshaler
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// makeMarshalerMIMERegistry returns a new registry of marshalers.
|
||||
// It allows for a mapping of case-sensitive Content-Type MIME type string to runtime.Marshaler interfaces.
|
||||
//
|
||||
// For example, you could allow the client to specify the use of the runtime.JSONPb marshaler
|
||||
// with a "applicaton/jsonpb" Content-Type and the use of the runtime.JSONBuiltin marshaler
|
||||
// with a "application/json" Content-Type.
|
||||
// "*" can be used to match any Content-Type.
|
||||
// This can be attached to a ServerMux with the marshaler option.
|
||||
func makeMarshalerMIMERegistry() marshalerRegistry {
|
||||
return marshalerRegistry{
|
||||
mimeMap: map[string]Marshaler{
|
||||
MIMEWildcard: defaultMarshaler,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// WithMarshalerOption returns a ServeMuxOption which associates inbound and outbound
|
||||
// Marshalers to a MIME type in mux.
|
||||
func WithMarshalerOption(mime string, marshaler Marshaler) ServeMuxOption {
|
||||
return func(mux *ServeMux) {
|
||||
if err := mux.marshalers.add(mime, marshaler); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
107
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/marshaler_registry_test.go
generated
vendored
Normal file
107
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/marshaler_registry_test.go
generated
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
package runtime_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/grpc-ecosystem/grpc-gateway/runtime"
|
||||
)
|
||||
|
||||
func TestMarshalerForRequest(t *testing.T) {
|
||||
r, err := http.NewRequest("GET", "http://example.com", nil)
|
||||
if err != nil {
|
||||
t.Fatalf(`http.NewRequest("GET", "http://example.com", nil) failed with %v; want success`, err)
|
||||
}
|
||||
r.Header.Set("Accept", "application/x-out")
|
||||
r.Header.Set("Content-Type", "application/x-in")
|
||||
|
||||
mux := runtime.NewServeMux()
|
||||
|
||||
in, out := runtime.MarshalerForRequest(mux, r)
|
||||
if _, ok := in.(*runtime.JSONPb); !ok {
|
||||
t.Errorf("in = %#v; want a runtime.JSONPb", in)
|
||||
}
|
||||
if _, ok := out.(*runtime.JSONPb); !ok {
|
||||
t.Errorf("out = %#v; want a runtime.JSONPb", in)
|
||||
}
|
||||
|
||||
var marshalers [3]dummyMarshaler
|
||||
specs := []struct {
|
||||
opt runtime.ServeMuxOption
|
||||
|
||||
wantIn runtime.Marshaler
|
||||
wantOut runtime.Marshaler
|
||||
}{
|
||||
{
|
||||
opt: runtime.WithMarshalerOption(runtime.MIMEWildcard, &marshalers[0]),
|
||||
wantIn: &marshalers[0],
|
||||
wantOut: &marshalers[0],
|
||||
},
|
||||
{
|
||||
opt: runtime.WithMarshalerOption("application/x-in", &marshalers[1]),
|
||||
wantIn: &marshalers[1],
|
||||
wantOut: &marshalers[0],
|
||||
},
|
||||
{
|
||||
opt: runtime.WithMarshalerOption("application/x-out", &marshalers[2]),
|
||||
wantIn: &marshalers[1],
|
||||
wantOut: &marshalers[2],
|
||||
},
|
||||
}
|
||||
for i, spec := range specs {
|
||||
var opts []runtime.ServeMuxOption
|
||||
for _, s := range specs[:i+1] {
|
||||
opts = append(opts, s.opt)
|
||||
}
|
||||
mux = runtime.NewServeMux(opts...)
|
||||
|
||||
in, out = runtime.MarshalerForRequest(mux, r)
|
||||
if got, want := in, spec.wantIn; got != want {
|
||||
t.Errorf("in = %#v; want %#v", got, want)
|
||||
}
|
||||
if got, want := out, spec.wantOut; got != want {
|
||||
t.Errorf("out = %#v; want %#v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
r.Header.Set("Content-Type", "application/x-another")
|
||||
in, out = runtime.MarshalerForRequest(mux, r)
|
||||
if got, want := in, &marshalers[1]; got != want {
|
||||
t.Errorf("in = %#v; want %#v", got, want)
|
||||
}
|
||||
if got, want := out, &marshalers[0]; got != want {
|
||||
t.Errorf("out = %#v; want %#v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
type dummyMarshaler struct{}
|
||||
|
||||
func (dummyMarshaler) ContentType() string { return "" }
|
||||
func (dummyMarshaler) Marshal(interface{}) ([]byte, error) {
|
||||
return nil, errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (dummyMarshaler) Unmarshal([]byte, interface{}) error {
|
||||
return errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (dummyMarshaler) NewDecoder(r io.Reader) runtime.Decoder {
|
||||
return dummyDecoder{}
|
||||
}
|
||||
func (dummyMarshaler) NewEncoder(w io.Writer) runtime.Encoder {
|
||||
return dummyEncoder{}
|
||||
}
|
||||
|
||||
type dummyDecoder struct{}
|
||||
|
||||
func (dummyDecoder) Decode(interface{}) error {
|
||||
return errors.New("not implemented")
|
||||
}
|
||||
|
||||
type dummyEncoder struct{}
|
||||
|
||||
func (dummyEncoder) Encode(interface{}) error {
|
||||
return errors.New("not implemented")
|
||||
}
|
132
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/mux.go
generated
vendored
Normal file
132
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/mux.go
generated
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
)
|
||||
|
||||
// A HandlerFunc handles a specific pair of path pattern and HTTP method.
|
||||
type HandlerFunc func(w http.ResponseWriter, r *http.Request, pathParams map[string]string)
|
||||
|
||||
// ServeMux is a request multiplexer for grpc-gateway.
|
||||
// It matches http requests to patterns and invokes the corresponding handler.
|
||||
type ServeMux struct {
|
||||
// handlers maps HTTP method to a list of handlers.
|
||||
handlers map[string][]handler
|
||||
forwardResponseOptions []func(context.Context, http.ResponseWriter, proto.Message) error
|
||||
marshalers marshalerRegistry
|
||||
}
|
||||
|
||||
// ServeMuxOption is an option that can be given to a ServeMux on construction.
|
||||
type ServeMuxOption func(*ServeMux)
|
||||
|
||||
// WithForwardResponseOption returns a ServeMuxOption representing the forwardResponseOption.
|
||||
//
|
||||
// forwardResponseOption is an option that will be called on the relevant context.Context,
|
||||
// http.ResponseWriter, and proto.Message before every forwarded response.
|
||||
//
|
||||
// The message may be nil in the case where just a header is being sent.
|
||||
func WithForwardResponseOption(forwardResponseOption func(context.Context, http.ResponseWriter, proto.Message) error) ServeMuxOption {
|
||||
return func(serveMux *ServeMux) {
|
||||
serveMux.forwardResponseOptions = append(serveMux.forwardResponseOptions, forwardResponseOption)
|
||||
}
|
||||
}
|
||||
|
||||
// NewServeMux returns a new ServeMux whose internal mapping is empty.
|
||||
func NewServeMux(opts ...ServeMuxOption) *ServeMux {
|
||||
serveMux := &ServeMux{
|
||||
handlers: make(map[string][]handler),
|
||||
forwardResponseOptions: make([]func(context.Context, http.ResponseWriter, proto.Message) error, 0),
|
||||
marshalers: makeMarshalerMIMERegistry(),
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(serveMux)
|
||||
}
|
||||
return serveMux
|
||||
}
|
||||
|
||||
// Handle associates "h" to the pair of HTTP method and path pattern.
|
||||
func (s *ServeMux) Handle(meth string, pat Pattern, h HandlerFunc) {
|
||||
s.handlers[meth] = append(s.handlers[meth], handler{pat: pat, h: h})
|
||||
}
|
||||
|
||||
// ServeHTTP dispatches the request to the first handler whose pattern matches to r.Method and r.Path.
|
||||
func (s *ServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
path := r.URL.Path
|
||||
if !strings.HasPrefix(path, "/") {
|
||||
OtherErrorHandler(w, r, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
components := strings.Split(path[1:], "/")
|
||||
l := len(components)
|
||||
var verb string
|
||||
if idx := strings.LastIndex(components[l-1], ":"); idx == 0 {
|
||||
OtherErrorHandler(w, r, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
||||
return
|
||||
} else if idx > 0 {
|
||||
c := components[l-1]
|
||||
components[l-1], verb = c[:idx], c[idx+1:]
|
||||
}
|
||||
|
||||
if override := r.Header.Get("X-HTTP-Method-Override"); override != "" && isPathLengthFallback(r) {
|
||||
r.Method = strings.ToUpper(override)
|
||||
if err := r.ParseForm(); err != nil {
|
||||
OtherErrorHandler(w, r, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
for _, h := range s.handlers[r.Method] {
|
||||
pathParams, err := h.pat.Match(components, verb)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
h.h(w, r, pathParams)
|
||||
return
|
||||
}
|
||||
|
||||
// lookup other methods to handle fallback from GET to POST and
|
||||
// to determine if it is MethodNotAllowed or NotFound.
|
||||
for m, handlers := range s.handlers {
|
||||
if m == r.Method {
|
||||
continue
|
||||
}
|
||||
for _, h := range handlers {
|
||||
pathParams, err := h.pat.Match(components, verb)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
// X-HTTP-Method-Override is optional. Always allow fallback to POST.
|
||||
if isPathLengthFallback(r) {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
OtherErrorHandler(w, r, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
h.h(w, r, pathParams)
|
||||
return
|
||||
}
|
||||
OtherErrorHandler(w, r, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
}
|
||||
OtherErrorHandler(w, r, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
||||
}
|
||||
|
||||
// GetForwardResponseOptions returns the ForwardResponseOptions associated with this ServeMux.
|
||||
func (s *ServeMux) GetForwardResponseOptions() []func(context.Context, http.ResponseWriter, proto.Message) error {
|
||||
return s.forwardResponseOptions
|
||||
}
|
||||
|
||||
func isPathLengthFallback(r *http.Request) bool {
|
||||
return r.Method == "POST" && r.Header.Get("Content-Type") == "application/x-www-form-urlencoded"
|
||||
}
|
||||
|
||||
type handler struct {
|
||||
pat Pattern
|
||||
h HandlerFunc
|
||||
}
|
213
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/mux_test.go
generated
vendored
Normal file
213
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/mux_test.go
generated
vendored
Normal file
@@ -0,0 +1,213 @@
|
||||
package runtime_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/grpc-ecosystem/grpc-gateway/runtime"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/utilities"
|
||||
)
|
||||
|
||||
func TestMuxServeHTTP(t *testing.T) {
|
||||
type stubPattern struct {
|
||||
method string
|
||||
ops []int
|
||||
pool []string
|
||||
verb string
|
||||
}
|
||||
for _, spec := range []struct {
|
||||
patterns []stubPattern
|
||||
|
||||
reqMethod string
|
||||
reqPath string
|
||||
headers map[string]string
|
||||
|
||||
respStatus int
|
||||
respContent string
|
||||
}{
|
||||
{
|
||||
patterns: nil,
|
||||
reqMethod: "GET",
|
||||
reqPath: "/",
|
||||
respStatus: http.StatusNotFound,
|
||||
},
|
||||
{
|
||||
patterns: []stubPattern{
|
||||
{
|
||||
method: "GET",
|
||||
ops: []int{int(utilities.OpLitPush), 0},
|
||||
pool: []string{"foo"},
|
||||
},
|
||||
},
|
||||
reqMethod: "GET",
|
||||
reqPath: "/foo",
|
||||
respStatus: http.StatusOK,
|
||||
respContent: "GET /foo",
|
||||
},
|
||||
{
|
||||
patterns: []stubPattern{
|
||||
{
|
||||
method: "GET",
|
||||
ops: []int{int(utilities.OpLitPush), 0},
|
||||
pool: []string{"foo"},
|
||||
},
|
||||
},
|
||||
reqMethod: "GET",
|
||||
reqPath: "/bar",
|
||||
respStatus: http.StatusNotFound,
|
||||
},
|
||||
{
|
||||
patterns: []stubPattern{
|
||||
{
|
||||
method: "GET",
|
||||
ops: []int{int(utilities.OpLitPush), 0},
|
||||
pool: []string{"foo"},
|
||||
},
|
||||
{
|
||||
method: "GET",
|
||||
ops: []int{int(utilities.OpPush), 0},
|
||||
},
|
||||
},
|
||||
reqMethod: "GET",
|
||||
reqPath: "/foo",
|
||||
respStatus: http.StatusOK,
|
||||
respContent: "GET /foo",
|
||||
},
|
||||
{
|
||||
patterns: []stubPattern{
|
||||
{
|
||||
method: "GET",
|
||||
ops: []int{int(utilities.OpLitPush), 0},
|
||||
pool: []string{"foo"},
|
||||
},
|
||||
{
|
||||
method: "POST",
|
||||
ops: []int{int(utilities.OpLitPush), 0},
|
||||
pool: []string{"foo"},
|
||||
},
|
||||
},
|
||||
reqMethod: "POST",
|
||||
reqPath: "/foo",
|
||||
respStatus: http.StatusOK,
|
||||
respContent: "POST /foo",
|
||||
},
|
||||
{
|
||||
patterns: []stubPattern{
|
||||
{
|
||||
method: "GET",
|
||||
ops: []int{int(utilities.OpLitPush), 0},
|
||||
pool: []string{"foo"},
|
||||
},
|
||||
},
|
||||
reqMethod: "DELETE",
|
||||
reqPath: "/foo",
|
||||
respStatus: http.StatusMethodNotAllowed,
|
||||
},
|
||||
{
|
||||
patterns: []stubPattern{
|
||||
{
|
||||
method: "GET",
|
||||
ops: []int{int(utilities.OpLitPush), 0},
|
||||
pool: []string{"foo"},
|
||||
},
|
||||
},
|
||||
reqMethod: "POST",
|
||||
reqPath: "/foo",
|
||||
headers: map[string]string{
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
},
|
||||
respStatus: http.StatusOK,
|
||||
respContent: "GET /foo",
|
||||
},
|
||||
{
|
||||
patterns: []stubPattern{
|
||||
{
|
||||
method: "GET",
|
||||
ops: []int{int(utilities.OpLitPush), 0},
|
||||
pool: []string{"foo"},
|
||||
},
|
||||
{
|
||||
method: "POST",
|
||||
ops: []int{int(utilities.OpLitPush), 0},
|
||||
pool: []string{"foo"},
|
||||
},
|
||||
},
|
||||
reqMethod: "POST",
|
||||
reqPath: "/foo",
|
||||
headers: map[string]string{
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
"X-HTTP-Method-Override": "GET",
|
||||
},
|
||||
respStatus: http.StatusOK,
|
||||
respContent: "GET /foo",
|
||||
},
|
||||
{
|
||||
patterns: []stubPattern{
|
||||
{
|
||||
method: "GET",
|
||||
ops: []int{int(utilities.OpLitPush), 0},
|
||||
pool: []string{"foo"},
|
||||
},
|
||||
},
|
||||
reqMethod: "POST",
|
||||
reqPath: "/foo",
|
||||
headers: map[string]string{
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
respStatus: http.StatusMethodNotAllowed,
|
||||
},
|
||||
{
|
||||
patterns: []stubPattern{
|
||||
{
|
||||
method: "POST",
|
||||
ops: []int{int(utilities.OpLitPush), 0},
|
||||
pool: []string{"foo"},
|
||||
verb: "bar",
|
||||
},
|
||||
},
|
||||
reqMethod: "POST",
|
||||
reqPath: "/foo:bar",
|
||||
headers: map[string]string{
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
respStatus: http.StatusOK,
|
||||
respContent: "POST /foo:bar",
|
||||
},
|
||||
} {
|
||||
mux := runtime.NewServeMux()
|
||||
for _, p := range spec.patterns {
|
||||
func(p stubPattern) {
|
||||
pat, err := runtime.NewPattern(1, p.ops, p.pool, p.verb)
|
||||
if err != nil {
|
||||
t.Fatalf("runtime.NewPattern(1, %#v, %#v, %q) failed with %v; want success", p.ops, p.pool, p.verb, err)
|
||||
}
|
||||
mux.Handle(p.method, pat, func(w http.ResponseWriter, r *http.Request, pathParams map[string]string) {
|
||||
fmt.Fprintf(w, "%s %s", p.method, pat.String())
|
||||
})
|
||||
}(p)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("http://host.example%s", spec.reqPath)
|
||||
r, err := http.NewRequest(spec.reqMethod, url, bytes.NewReader(nil))
|
||||
if err != nil {
|
||||
t.Fatalf("http.NewRequest(%q, %q, nil) failed with %v; want success", spec.reqMethod, url, err)
|
||||
}
|
||||
for name, value := range spec.headers {
|
||||
r.Header.Set(name, value)
|
||||
}
|
||||
w := httptest.NewRecorder()
|
||||
mux.ServeHTTP(w, r)
|
||||
|
||||
if got, want := w.Code, spec.respStatus; got != want {
|
||||
t.Errorf("w.Code = %d; want %d; patterns=%v; req=%v", got, want, spec.patterns, r)
|
||||
}
|
||||
if spec.respContent != "" {
|
||||
if got, want := w.Body.String(), spec.respContent; got != want {
|
||||
t.Errorf("w.Body = %q; want %q; patterns=%v; req=%v", got, want, spec.patterns, r)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
227
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/pattern.go
generated
vendored
Normal file
227
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/pattern.go
generated
vendored
Normal file
@@ -0,0 +1,227 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/grpc-ecosystem/grpc-gateway/utilities"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNotMatch indicates that the given HTTP request path does not match to the pattern.
|
||||
ErrNotMatch = errors.New("not match to the path pattern")
|
||||
// ErrInvalidPattern indicates that the given definition of Pattern is not valid.
|
||||
ErrInvalidPattern = errors.New("invalid pattern")
|
||||
)
|
||||
|
||||
type op struct {
|
||||
code utilities.OpCode
|
||||
operand int
|
||||
}
|
||||
|
||||
// Pattern is a template pattern of http request paths defined in github.com/googleapis/googleapis/google/api/http.proto.
|
||||
type Pattern struct {
|
||||
// ops is a list of operations
|
||||
ops []op
|
||||
// pool is a constant pool indexed by the operands or vars.
|
||||
pool []string
|
||||
// vars is a list of variables names to be bound by this pattern
|
||||
vars []string
|
||||
// stacksize is the max depth of the stack
|
||||
stacksize int
|
||||
// tailLen is the length of the fixed-size segments after a deep wildcard
|
||||
tailLen int
|
||||
// verb is the VERB part of the path pattern. It is empty if the pattern does not have VERB part.
|
||||
verb string
|
||||
}
|
||||
|
||||
// NewPattern returns a new Pattern from the given definition values.
|
||||
// "ops" is a sequence of op codes. "pool" is a constant pool.
|
||||
// "verb" is the verb part of the pattern. It is empty if the pattern does not have the part.
|
||||
// "version" must be 1 for now.
|
||||
// It returns an error if the given definition is invalid.
|
||||
func NewPattern(version int, ops []int, pool []string, verb string) (Pattern, error) {
|
||||
if version != 1 {
|
||||
grpclog.Printf("unsupported version: %d", version)
|
||||
return Pattern{}, ErrInvalidPattern
|
||||
}
|
||||
|
||||
l := len(ops)
|
||||
if l%2 != 0 {
|
||||
grpclog.Printf("odd number of ops codes: %d", l)
|
||||
return Pattern{}, ErrInvalidPattern
|
||||
}
|
||||
|
||||
var (
|
||||
typedOps []op
|
||||
stack, maxstack int
|
||||
tailLen int
|
||||
pushMSeen bool
|
||||
vars []string
|
||||
)
|
||||
for i := 0; i < l; i += 2 {
|
||||
op := op{code: utilities.OpCode(ops[i]), operand: ops[i+1]}
|
||||
switch op.code {
|
||||
case utilities.OpNop:
|
||||
continue
|
||||
case utilities.OpPush:
|
||||
if pushMSeen {
|
||||
tailLen++
|
||||
}
|
||||
stack++
|
||||
case utilities.OpPushM:
|
||||
if pushMSeen {
|
||||
grpclog.Printf("pushM appears twice")
|
||||
return Pattern{}, ErrInvalidPattern
|
||||
}
|
||||
pushMSeen = true
|
||||
stack++
|
||||
case utilities.OpLitPush:
|
||||
if op.operand < 0 || len(pool) <= op.operand {
|
||||
grpclog.Printf("negative literal index: %d", op.operand)
|
||||
return Pattern{}, ErrInvalidPattern
|
||||
}
|
||||
if pushMSeen {
|
||||
tailLen++
|
||||
}
|
||||
stack++
|
||||
case utilities.OpConcatN:
|
||||
if op.operand <= 0 {
|
||||
grpclog.Printf("negative concat size: %d", op.operand)
|
||||
return Pattern{}, ErrInvalidPattern
|
||||
}
|
||||
stack -= op.operand
|
||||
if stack < 0 {
|
||||
grpclog.Print("stack underflow")
|
||||
return Pattern{}, ErrInvalidPattern
|
||||
}
|
||||
stack++
|
||||
case utilities.OpCapture:
|
||||
if op.operand < 0 || len(pool) <= op.operand {
|
||||
grpclog.Printf("variable name index out of bound: %d", op.operand)
|
||||
return Pattern{}, ErrInvalidPattern
|
||||
}
|
||||
v := pool[op.operand]
|
||||
op.operand = len(vars)
|
||||
vars = append(vars, v)
|
||||
stack--
|
||||
if stack < 0 {
|
||||
grpclog.Printf("stack underflow")
|
||||
return Pattern{}, ErrInvalidPattern
|
||||
}
|
||||
default:
|
||||
grpclog.Printf("invalid opcode: %d", op.code)
|
||||
return Pattern{}, ErrInvalidPattern
|
||||
}
|
||||
|
||||
if maxstack < stack {
|
||||
maxstack = stack
|
||||
}
|
||||
typedOps = append(typedOps, op)
|
||||
}
|
||||
return Pattern{
|
||||
ops: typedOps,
|
||||
pool: pool,
|
||||
vars: vars,
|
||||
stacksize: maxstack,
|
||||
tailLen: tailLen,
|
||||
verb: verb,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// MustPattern is a helper function which makes it easier to call NewPattern in variable initialization.
|
||||
func MustPattern(p Pattern, err error) Pattern {
|
||||
if err != nil {
|
||||
grpclog.Fatalf("Pattern initialization failed: %v", err)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// Match examines components if it matches to the Pattern.
|
||||
// If it matches, the function returns a mapping from field paths to their captured values.
|
||||
// If otherwise, the function returns an error.
|
||||
func (p Pattern) Match(components []string, verb string) (map[string]string, error) {
|
||||
if p.verb != verb {
|
||||
return nil, ErrNotMatch
|
||||
}
|
||||
|
||||
var pos int
|
||||
stack := make([]string, 0, p.stacksize)
|
||||
captured := make([]string, len(p.vars))
|
||||
l := len(components)
|
||||
for _, op := range p.ops {
|
||||
switch op.code {
|
||||
case utilities.OpNop:
|
||||
continue
|
||||
case utilities.OpPush, utilities.OpLitPush:
|
||||
if pos >= l {
|
||||
return nil, ErrNotMatch
|
||||
}
|
||||
c := components[pos]
|
||||
if op.code == utilities.OpLitPush {
|
||||
if lit := p.pool[op.operand]; c != lit {
|
||||
return nil, ErrNotMatch
|
||||
}
|
||||
}
|
||||
stack = append(stack, c)
|
||||
pos++
|
||||
case utilities.OpPushM:
|
||||
end := len(components)
|
||||
if end < pos+p.tailLen {
|
||||
return nil, ErrNotMatch
|
||||
}
|
||||
end -= p.tailLen
|
||||
stack = append(stack, strings.Join(components[pos:end], "/"))
|
||||
pos = end
|
||||
case utilities.OpConcatN:
|
||||
n := op.operand
|
||||
l := len(stack) - n
|
||||
stack = append(stack[:l], strings.Join(stack[l:], "/"))
|
||||
case utilities.OpCapture:
|
||||
n := len(stack) - 1
|
||||
captured[op.operand] = stack[n]
|
||||
stack = stack[:n]
|
||||
}
|
||||
}
|
||||
if pos < l {
|
||||
return nil, ErrNotMatch
|
||||
}
|
||||
bindings := make(map[string]string)
|
||||
for i, val := range captured {
|
||||
bindings[p.vars[i]] = val
|
||||
}
|
||||
return bindings, nil
|
||||
}
|
||||
|
||||
// Verb returns the verb part of the Pattern.
|
||||
func (p Pattern) Verb() string { return p.verb }
|
||||
|
||||
func (p Pattern) String() string {
|
||||
var stack []string
|
||||
for _, op := range p.ops {
|
||||
switch op.code {
|
||||
case utilities.OpNop:
|
||||
continue
|
||||
case utilities.OpPush:
|
||||
stack = append(stack, "*")
|
||||
case utilities.OpLitPush:
|
||||
stack = append(stack, p.pool[op.operand])
|
||||
case utilities.OpPushM:
|
||||
stack = append(stack, "**")
|
||||
case utilities.OpConcatN:
|
||||
n := op.operand
|
||||
l := len(stack) - n
|
||||
stack = append(stack[:l], strings.Join(stack[l:], "/"))
|
||||
case utilities.OpCapture:
|
||||
n := len(stack) - 1
|
||||
stack[n] = fmt.Sprintf("{%s=%s}", p.vars[op.operand], stack[n])
|
||||
}
|
||||
}
|
||||
segs := strings.Join(stack, "/")
|
||||
if p.verb != "" {
|
||||
return fmt.Sprintf("/%s:%s", segs, p.verb)
|
||||
}
|
||||
return "/" + segs
|
||||
}
|
590
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/pattern_test.go
generated
vendored
Normal file
590
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/pattern_test.go
generated
vendored
Normal file
@@ -0,0 +1,590 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/grpc-ecosystem/grpc-gateway/utilities"
|
||||
)
|
||||
|
||||
const (
|
||||
validVersion = 1
|
||||
anything = 0
|
||||
)
|
||||
|
||||
func TestNewPattern(t *testing.T) {
|
||||
for _, spec := range []struct {
|
||||
ops []int
|
||||
pool []string
|
||||
verb string
|
||||
|
||||
stackSizeWant, tailLenWant int
|
||||
}{
|
||||
{},
|
||||
{
|
||||
ops: []int{int(utilities.OpNop), anything},
|
||||
stackSizeWant: 0,
|
||||
tailLenWant: 0,
|
||||
},
|
||||
{
|
||||
ops: []int{int(utilities.OpPush), anything},
|
||||
stackSizeWant: 1,
|
||||
tailLenWant: 0,
|
||||
},
|
||||
{
|
||||
ops: []int{int(utilities.OpLitPush), 0},
|
||||
pool: []string{"abc"},
|
||||
stackSizeWant: 1,
|
||||
tailLenWant: 0,
|
||||
},
|
||||
{
|
||||
ops: []int{int(utilities.OpPushM), anything},
|
||||
stackSizeWant: 1,
|
||||
tailLenWant: 0,
|
||||
},
|
||||
{
|
||||
ops: []int{
|
||||
int(utilities.OpPush), anything,
|
||||
int(utilities.OpConcatN), 1,
|
||||
},
|
||||
stackSizeWant: 1,
|
||||
tailLenWant: 0,
|
||||
},
|
||||
{
|
||||
ops: []int{
|
||||
int(utilities.OpPush), anything,
|
||||
int(utilities.OpConcatN), 1,
|
||||
int(utilities.OpCapture), 0,
|
||||
},
|
||||
pool: []string{"abc"},
|
||||
stackSizeWant: 1,
|
||||
tailLenWant: 0,
|
||||
},
|
||||
{
|
||||
ops: []int{
|
||||
int(utilities.OpPush), anything,
|
||||
int(utilities.OpLitPush), 0,
|
||||
int(utilities.OpLitPush), 1,
|
||||
int(utilities.OpPushM), anything,
|
||||
int(utilities.OpConcatN), 2,
|
||||
int(utilities.OpCapture), 2,
|
||||
},
|
||||
pool: []string{"lit1", "lit2", "var1"},
|
||||
stackSizeWant: 4,
|
||||
tailLenWant: 0,
|
||||
},
|
||||
{
|
||||
ops: []int{
|
||||
int(utilities.OpPushM), anything,
|
||||
int(utilities.OpConcatN), 1,
|
||||
int(utilities.OpCapture), 2,
|
||||
int(utilities.OpLitPush), 0,
|
||||
int(utilities.OpLitPush), 1,
|
||||
},
|
||||
pool: []string{"lit1", "lit2", "var1"},
|
||||
stackSizeWant: 2,
|
||||
tailLenWant: 2,
|
||||
},
|
||||
{
|
||||
ops: []int{
|
||||
int(utilities.OpLitPush), 0,
|
||||
int(utilities.OpLitPush), 1,
|
||||
int(utilities.OpPushM), anything,
|
||||
int(utilities.OpLitPush), 2,
|
||||
int(utilities.OpConcatN), 3,
|
||||
int(utilities.OpLitPush), 3,
|
||||
int(utilities.OpCapture), 4,
|
||||
},
|
||||
pool: []string{"lit1", "lit2", "lit3", "lit4", "var1"},
|
||||
stackSizeWant: 4,
|
||||
tailLenWant: 2,
|
||||
},
|
||||
{
|
||||
ops: []int{int(utilities.OpLitPush), 0},
|
||||
pool: []string{"abc"},
|
||||
verb: "LOCK",
|
||||
stackSizeWant: 1,
|
||||
tailLenWant: 0,
|
||||
},
|
||||
} {
|
||||
pat, err := NewPattern(validVersion, spec.ops, spec.pool, spec.verb)
|
||||
if err != nil {
|
||||
t.Errorf("NewPattern(%d, %v, %q, %q) failed with %v; want success", validVersion, spec.ops, spec.pool, spec.verb, err)
|
||||
continue
|
||||
}
|
||||
if got, want := pat.stacksize, spec.stackSizeWant; got != want {
|
||||
t.Errorf("pat.stacksize = %d; want %d", got, want)
|
||||
}
|
||||
if got, want := pat.tailLen, spec.tailLenWant; got != want {
|
||||
t.Errorf("pat.stacksize = %d; want %d", got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewPatternWithWrongOp(t *testing.T) {
|
||||
for _, spec := range []struct {
|
||||
ops []int
|
||||
pool []string
|
||||
verb string
|
||||
}{
|
||||
{
|
||||
// op code out of bound
|
||||
ops: []int{-1, anything},
|
||||
},
|
||||
{
|
||||
// op code out of bound
|
||||
ops: []int{int(utilities.OpEnd), 0},
|
||||
},
|
||||
{
|
||||
// odd number of items
|
||||
ops: []int{int(utilities.OpPush)},
|
||||
},
|
||||
{
|
||||
// negative index
|
||||
ops: []int{int(utilities.OpLitPush), -1},
|
||||
pool: []string{"abc"},
|
||||
},
|
||||
{
|
||||
// index out of bound
|
||||
ops: []int{int(utilities.OpLitPush), 1},
|
||||
pool: []string{"abc"},
|
||||
},
|
||||
{
|
||||
// negative # of segments
|
||||
ops: []int{int(utilities.OpConcatN), -1},
|
||||
pool: []string{"abc"},
|
||||
},
|
||||
{
|
||||
// negative index
|
||||
ops: []int{int(utilities.OpCapture), -1},
|
||||
pool: []string{"abc"},
|
||||
},
|
||||
{
|
||||
// index out of bound
|
||||
ops: []int{int(utilities.OpCapture), 1},
|
||||
pool: []string{"abc"},
|
||||
},
|
||||
{
|
||||
// pushM appears twice
|
||||
ops: []int{
|
||||
int(utilities.OpPushM), anything,
|
||||
int(utilities.OpLitPush), 0,
|
||||
int(utilities.OpPushM), anything,
|
||||
},
|
||||
pool: []string{"abc"},
|
||||
},
|
||||
} {
|
||||
_, err := NewPattern(validVersion, spec.ops, spec.pool, spec.verb)
|
||||
if err == nil {
|
||||
t.Errorf("NewPattern(%d, %v, %q, %q) succeeded; want failure with %v", validVersion, spec.ops, spec.pool, spec.verb, ErrInvalidPattern)
|
||||
continue
|
||||
}
|
||||
if err != ErrInvalidPattern {
|
||||
t.Errorf("NewPattern(%d, %v, %q, %q) failed with %v; want failure with %v", validVersion, spec.ops, spec.pool, spec.verb, err, ErrInvalidPattern)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewPatternWithStackUnderflow(t *testing.T) {
|
||||
for _, spec := range []struct {
|
||||
ops []int
|
||||
pool []string
|
||||
verb string
|
||||
}{
|
||||
{
|
||||
ops: []int{int(utilities.OpConcatN), 1},
|
||||
},
|
||||
{
|
||||
ops: []int{int(utilities.OpCapture), 0},
|
||||
pool: []string{"abc"},
|
||||
},
|
||||
} {
|
||||
_, err := NewPattern(validVersion, spec.ops, spec.pool, spec.verb)
|
||||
if err == nil {
|
||||
t.Errorf("NewPattern(%d, %v, %q, %q) succeeded; want failure with %v", validVersion, spec.ops, spec.pool, spec.verb, ErrInvalidPattern)
|
||||
continue
|
||||
}
|
||||
if err != ErrInvalidPattern {
|
||||
t.Errorf("NewPattern(%d, %v, %q, %q) failed with %v; want failure with %v", validVersion, spec.ops, spec.pool, spec.verb, err, ErrInvalidPattern)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMatch(t *testing.T) {
|
||||
for _, spec := range []struct {
|
||||
ops []int
|
||||
pool []string
|
||||
verb string
|
||||
|
||||
match []string
|
||||
notMatch []string
|
||||
}{
|
||||
{
|
||||
match: []string{""},
|
||||
notMatch: []string{"example"},
|
||||
},
|
||||
{
|
||||
ops: []int{int(utilities.OpNop), anything},
|
||||
match: []string{""},
|
||||
notMatch: []string{"example", "path/to/example"},
|
||||
},
|
||||
{
|
||||
ops: []int{int(utilities.OpPush), anything},
|
||||
match: []string{"abc", "def"},
|
||||
notMatch: []string{"", "abc/def"},
|
||||
},
|
||||
{
|
||||
ops: []int{int(utilities.OpLitPush), 0},
|
||||
pool: []string{"v1"},
|
||||
match: []string{"v1"},
|
||||
notMatch: []string{"", "v2"},
|
||||
},
|
||||
{
|
||||
ops: []int{int(utilities.OpPushM), anything},
|
||||
match: []string{"", "abc", "abc/def", "abc/def/ghi"},
|
||||
},
|
||||
{
|
||||
ops: []int{
|
||||
int(utilities.OpPushM), anything,
|
||||
int(utilities.OpLitPush), 0,
|
||||
},
|
||||
pool: []string{"tail"},
|
||||
match: []string{"tail", "abc/tail", "abc/def/tail"},
|
||||
notMatch: []string{
|
||||
"", "abc", "abc/def",
|
||||
"tail/extra", "abc/tail/extra", "abc/def/tail/extra",
|
||||
},
|
||||
},
|
||||
{
|
||||
ops: []int{
|
||||
int(utilities.OpLitPush), 0,
|
||||
int(utilities.OpLitPush), 1,
|
||||
int(utilities.OpPush), anything,
|
||||
int(utilities.OpConcatN), 1,
|
||||
int(utilities.OpCapture), 2,
|
||||
},
|
||||
pool: []string{"v1", "bucket", "name"},
|
||||
match: []string{"v1/bucket/my-bucket", "v1/bucket/our-bucket"},
|
||||
notMatch: []string{
|
||||
"",
|
||||
"v1",
|
||||
"v1/bucket",
|
||||
"v2/bucket/my-bucket",
|
||||
"v1/pubsub/my-topic",
|
||||
},
|
||||
},
|
||||
{
|
||||
ops: []int{
|
||||
int(utilities.OpLitPush), 0,
|
||||
int(utilities.OpLitPush), 1,
|
||||
int(utilities.OpPushM), anything,
|
||||
int(utilities.OpConcatN), 2,
|
||||
int(utilities.OpCapture), 2,
|
||||
},
|
||||
pool: []string{"v1", "o", "name"},
|
||||
match: []string{
|
||||
"v1/o",
|
||||
"v1/o/my-bucket",
|
||||
"v1/o/our-bucket",
|
||||
"v1/o/my-bucket/dir",
|
||||
"v1/o/my-bucket/dir/dir2",
|
||||
"v1/o/my-bucket/dir/dir2/obj",
|
||||
},
|
||||
notMatch: []string{
|
||||
"",
|
||||
"v1",
|
||||
"v2/o/my-bucket",
|
||||
"v1/b/my-bucket",
|
||||
},
|
||||
},
|
||||
{
|
||||
ops: []int{
|
||||
int(utilities.OpLitPush), 0,
|
||||
int(utilities.OpLitPush), 1,
|
||||
int(utilities.OpPush), anything,
|
||||
int(utilities.OpConcatN), 2,
|
||||
int(utilities.OpCapture), 2,
|
||||
int(utilities.OpLitPush), 3,
|
||||
int(utilities.OpPush), anything,
|
||||
int(utilities.OpConcatN), 1,
|
||||
int(utilities.OpCapture), 4,
|
||||
},
|
||||
pool: []string{"v2", "b", "name", "o", "oname"},
|
||||
match: []string{
|
||||
"v2/b/my-bucket/o/obj",
|
||||
"v2/b/our-bucket/o/obj",
|
||||
"v2/b/my-bucket/o/dir",
|
||||
},
|
||||
notMatch: []string{
|
||||
"",
|
||||
"v2",
|
||||
"v2/b",
|
||||
"v2/b/my-bucket",
|
||||
"v2/b/my-bucket/o",
|
||||
},
|
||||
},
|
||||
{
|
||||
ops: []int{int(utilities.OpLitPush), 0},
|
||||
pool: []string{"v1"},
|
||||
verb: "LOCK",
|
||||
match: []string{"v1:LOCK"},
|
||||
notMatch: []string{"v1", "LOCK"},
|
||||
},
|
||||
} {
|
||||
pat, err := NewPattern(validVersion, spec.ops, spec.pool, spec.verb)
|
||||
if err != nil {
|
||||
t.Errorf("NewPattern(%d, %v, %q, %q) failed with %v; want success", validVersion, spec.ops, spec.pool, spec.verb, err)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, path := range spec.match {
|
||||
_, err = pat.Match(segments(path))
|
||||
if err != nil {
|
||||
t.Errorf("pat.Match(%q) failed with %v; want success; pattern = (%v, %q)", path, err, spec.ops, spec.pool)
|
||||
}
|
||||
}
|
||||
|
||||
for _, path := range spec.notMatch {
|
||||
_, err = pat.Match(segments(path))
|
||||
if err == nil {
|
||||
t.Errorf("pat.Match(%q) succeeded; want failure with %v; pattern = (%v, %q)", path, ErrNotMatch, spec.ops, spec.pool)
|
||||
continue
|
||||
}
|
||||
if err != ErrNotMatch {
|
||||
t.Errorf("pat.Match(%q) failed with %v; want failure with %v; pattern = (%v, %q)", spec.notMatch, err, ErrNotMatch, spec.ops, spec.pool)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMatchWithBinding(t *testing.T) {
|
||||
for _, spec := range []struct {
|
||||
ops []int
|
||||
pool []string
|
||||
path string
|
||||
verb string
|
||||
|
||||
want map[string]string
|
||||
}{
|
||||
{
|
||||
want: make(map[string]string),
|
||||
},
|
||||
{
|
||||
ops: []int{int(utilities.OpNop), anything},
|
||||
want: make(map[string]string),
|
||||
},
|
||||
{
|
||||
ops: []int{int(utilities.OpPush), anything},
|
||||
path: "abc",
|
||||
want: make(map[string]string),
|
||||
},
|
||||
{
|
||||
ops: []int{int(utilities.OpPush), anything},
|
||||
verb: "LOCK",
|
||||
path: "abc:LOCK",
|
||||
want: make(map[string]string),
|
||||
},
|
||||
{
|
||||
ops: []int{int(utilities.OpLitPush), 0},
|
||||
pool: []string{"endpoint"},
|
||||
path: "endpoint",
|
||||
want: make(map[string]string),
|
||||
},
|
||||
{
|
||||
ops: []int{int(utilities.OpPushM), anything},
|
||||
path: "abc/def/ghi",
|
||||
want: make(map[string]string),
|
||||
},
|
||||
{
|
||||
ops: []int{
|
||||
int(utilities.OpLitPush), 0,
|
||||
int(utilities.OpLitPush), 1,
|
||||
int(utilities.OpPush), anything,
|
||||
int(utilities.OpConcatN), 1,
|
||||
int(utilities.OpCapture), 2,
|
||||
},
|
||||
pool: []string{"v1", "bucket", "name"},
|
||||
path: "v1/bucket/my-bucket",
|
||||
want: map[string]string{
|
||||
"name": "my-bucket",
|
||||
},
|
||||
},
|
||||
{
|
||||
ops: []int{
|
||||
int(utilities.OpLitPush), 0,
|
||||
int(utilities.OpLitPush), 1,
|
||||
int(utilities.OpPush), anything,
|
||||
int(utilities.OpConcatN), 1,
|
||||
int(utilities.OpCapture), 2,
|
||||
},
|
||||
pool: []string{"v1", "bucket", "name"},
|
||||
verb: "LOCK",
|
||||
path: "v1/bucket/my-bucket:LOCK",
|
||||
want: map[string]string{
|
||||
"name": "my-bucket",
|
||||
},
|
||||
},
|
||||
{
|
||||
ops: []int{
|
||||
int(utilities.OpLitPush), 0,
|
||||
int(utilities.OpLitPush), 1,
|
||||
int(utilities.OpPushM), anything,
|
||||
int(utilities.OpConcatN), 2,
|
||||
int(utilities.OpCapture), 2,
|
||||
},
|
||||
pool: []string{"v1", "o", "name"},
|
||||
path: "v1/o/my-bucket/dir/dir2/obj",
|
||||
want: map[string]string{
|
||||
"name": "o/my-bucket/dir/dir2/obj",
|
||||
},
|
||||
},
|
||||
{
|
||||
ops: []int{
|
||||
int(utilities.OpLitPush), 0,
|
||||
int(utilities.OpLitPush), 1,
|
||||
int(utilities.OpPushM), anything,
|
||||
int(utilities.OpLitPush), 2,
|
||||
int(utilities.OpConcatN), 3,
|
||||
int(utilities.OpCapture), 4,
|
||||
int(utilities.OpLitPush), 3,
|
||||
},
|
||||
pool: []string{"v1", "o", ".ext", "tail", "name"},
|
||||
path: "v1/o/my-bucket/dir/dir2/obj/.ext/tail",
|
||||
want: map[string]string{
|
||||
"name": "o/my-bucket/dir/dir2/obj/.ext",
|
||||
},
|
||||
},
|
||||
{
|
||||
ops: []int{
|
||||
int(utilities.OpLitPush), 0,
|
||||
int(utilities.OpLitPush), 1,
|
||||
int(utilities.OpPush), anything,
|
||||
int(utilities.OpConcatN), 2,
|
||||
int(utilities.OpCapture), 2,
|
||||
int(utilities.OpLitPush), 3,
|
||||
int(utilities.OpPush), anything,
|
||||
int(utilities.OpConcatN), 1,
|
||||
int(utilities.OpCapture), 4,
|
||||
},
|
||||
pool: []string{"v2", "b", "name", "o", "oname"},
|
||||
path: "v2/b/my-bucket/o/obj",
|
||||
want: map[string]string{
|
||||
"name": "b/my-bucket",
|
||||
"oname": "obj",
|
||||
},
|
||||
},
|
||||
} {
|
||||
pat, err := NewPattern(validVersion, spec.ops, spec.pool, spec.verb)
|
||||
if err != nil {
|
||||
t.Errorf("NewPattern(%d, %v, %q, %q) failed with %v; want success", validVersion, spec.ops, spec.pool, spec.verb, err)
|
||||
continue
|
||||
}
|
||||
|
||||
got, err := pat.Match(segments(spec.path))
|
||||
if err != nil {
|
||||
t.Errorf("pat.Match(%q) failed with %v; want success; pattern = (%v, %q)", spec.path, err, spec.ops, spec.pool)
|
||||
}
|
||||
if !reflect.DeepEqual(got, spec.want) {
|
||||
t.Errorf("pat.Match(%q) = %q; want %q; pattern = (%v, %q)", spec.path, got, spec.want, spec.ops, spec.pool)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func segments(path string) (components []string, verb string) {
|
||||
if path == "" {
|
||||
return nil, ""
|
||||
}
|
||||
components = strings.Split(path, "/")
|
||||
l := len(components)
|
||||
c := components[l-1]
|
||||
if idx := strings.LastIndex(c, ":"); idx >= 0 {
|
||||
components[l-1], verb = c[:idx], c[idx+1:]
|
||||
}
|
||||
return components, verb
|
||||
}
|
||||
|
||||
func TestPatternString(t *testing.T) {
|
||||
for _, spec := range []struct {
|
||||
ops []int
|
||||
pool []string
|
||||
|
||||
want string
|
||||
}{
|
||||
{
|
||||
want: "/",
|
||||
},
|
||||
{
|
||||
ops: []int{int(utilities.OpNop), anything},
|
||||
want: "/",
|
||||
},
|
||||
{
|
||||
ops: []int{int(utilities.OpPush), anything},
|
||||
want: "/*",
|
||||
},
|
||||
{
|
||||
ops: []int{int(utilities.OpLitPush), 0},
|
||||
pool: []string{"endpoint"},
|
||||
want: "/endpoint",
|
||||
},
|
||||
{
|
||||
ops: []int{int(utilities.OpPushM), anything},
|
||||
want: "/**",
|
||||
},
|
||||
{
|
||||
ops: []int{
|
||||
int(utilities.OpPush), anything,
|
||||
int(utilities.OpConcatN), 1,
|
||||
},
|
||||
want: "/*",
|
||||
},
|
||||
{
|
||||
ops: []int{
|
||||
int(utilities.OpPush), anything,
|
||||
int(utilities.OpConcatN), 1,
|
||||
int(utilities.OpCapture), 0,
|
||||
},
|
||||
pool: []string{"name"},
|
||||
want: "/{name=*}",
|
||||
},
|
||||
{
|
||||
ops: []int{
|
||||
int(utilities.OpLitPush), 0,
|
||||
int(utilities.OpLitPush), 1,
|
||||
int(utilities.OpPush), anything,
|
||||
int(utilities.OpConcatN), 2,
|
||||
int(utilities.OpCapture), 2,
|
||||
int(utilities.OpLitPush), 3,
|
||||
int(utilities.OpPushM), anything,
|
||||
int(utilities.OpLitPush), 4,
|
||||
int(utilities.OpConcatN), 3,
|
||||
int(utilities.OpCapture), 6,
|
||||
int(utilities.OpLitPush), 5,
|
||||
},
|
||||
pool: []string{"v1", "buckets", "bucket_name", "objects", ".ext", "tail", "name"},
|
||||
want: "/v1/{bucket_name=buckets/*}/{name=objects/**/.ext}/tail",
|
||||
},
|
||||
} {
|
||||
p, err := NewPattern(validVersion, spec.ops, spec.pool, "")
|
||||
if err != nil {
|
||||
t.Errorf("NewPattern(%d, %v, %q, %q) failed with %v; want success", validVersion, spec.ops, spec.pool, "", err)
|
||||
continue
|
||||
}
|
||||
if got, want := p.String(), spec.want; got != want {
|
||||
t.Errorf("%#v.String() = %q; want %q", p, got, want)
|
||||
}
|
||||
|
||||
verb := "LOCK"
|
||||
p, err = NewPattern(validVersion, spec.ops, spec.pool, verb)
|
||||
if err != nil {
|
||||
t.Errorf("NewPattern(%d, %v, %q, %q) failed with %v; want success", validVersion, spec.ops, spec.pool, verb, err)
|
||||
continue
|
||||
}
|
||||
if got, want := p.String(), fmt.Sprintf("%s:%s", spec.want, verb); got != want {
|
||||
t.Errorf("%#v.String() = %q; want %q", p, got, want)
|
||||
}
|
||||
}
|
||||
}
|
80
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/proto2_convert.go
generated
vendored
Normal file
80
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/proto2_convert.go
generated
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"github.com/golang/protobuf/proto"
|
||||
)
|
||||
|
||||
// StringP returns a pointer to a string whose pointee is same as the given string value.
|
||||
func StringP(val string) (*string, error) {
|
||||
return proto.String(val), nil
|
||||
}
|
||||
|
||||
// BoolP parses the given string representation of a boolean value,
|
||||
// and returns a pointer to a bool whose value is same as the parsed value.
|
||||
func BoolP(val string) (*bool, error) {
|
||||
b, err := Bool(val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return proto.Bool(b), nil
|
||||
}
|
||||
|
||||
// Float64P parses the given string representation of a floating point number,
|
||||
// and returns a pointer to a float64 whose value is same as the parsed number.
|
||||
func Float64P(val string) (*float64, error) {
|
||||
f, err := Float64(val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return proto.Float64(f), nil
|
||||
}
|
||||
|
||||
// Float32P parses the given string representation of a floating point number,
|
||||
// and returns a pointer to a float32 whose value is same as the parsed number.
|
||||
func Float32P(val string) (*float32, error) {
|
||||
f, err := Float32(val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return proto.Float32(f), nil
|
||||
}
|
||||
|
||||
// Int64P parses the given string representation of an integer
|
||||
// and returns a pointer to a int64 whose value is same as the parsed integer.
|
||||
func Int64P(val string) (*int64, error) {
|
||||
i, err := Int64(val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return proto.Int64(i), nil
|
||||
}
|
||||
|
||||
// Int32P parses the given string representation of an integer
|
||||
// and returns a pointer to a int32 whose value is same as the parsed integer.
|
||||
func Int32P(val string) (*int32, error) {
|
||||
i, err := Int32(val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return proto.Int32(i), err
|
||||
}
|
||||
|
||||
// Uint64P parses the given string representation of an integer
|
||||
// and returns a pointer to a uint64 whose value is same as the parsed integer.
|
||||
func Uint64P(val string) (*uint64, error) {
|
||||
i, err := Uint64(val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return proto.Uint64(i), err
|
||||
}
|
||||
|
||||
// Uint32P parses the given string representation of an integer
|
||||
// and returns a pointer to a uint32 whose value is same as the parsed integer.
|
||||
func Uint32P(val string) (*uint32, error) {
|
||||
i, err := Uint32(val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return proto.Uint32(i), err
|
||||
}
|
222
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/query.go
generated
vendored
Normal file
222
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/query.go
generated
vendored
Normal file
@@ -0,0 +1,222 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/utilities"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
)
|
||||
|
||||
// PopulateQueryParameters populates "values" into "msg".
|
||||
// A value is ignored if its key starts with one of the elements in "filter".
|
||||
func PopulateQueryParameters(msg proto.Message, values url.Values, filter *utilities.DoubleArray) error {
|
||||
for key, values := range values {
|
||||
fieldPath := strings.Split(key, ".")
|
||||
if filter.HasCommonPrefix(fieldPath) {
|
||||
continue
|
||||
}
|
||||
if err := populateFieldValueFromPath(msg, fieldPath, values); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// PopulateFieldFromPath sets a value in a nested Protobuf structure.
|
||||
// It instantiates missing protobuf fields as it goes.
|
||||
func PopulateFieldFromPath(msg proto.Message, fieldPathString string, value string) error {
|
||||
fieldPath := strings.Split(fieldPathString, ".")
|
||||
return populateFieldValueFromPath(msg, fieldPath, []string{value})
|
||||
}
|
||||
|
||||
func populateFieldValueFromPath(msg proto.Message, fieldPath []string, values []string) error {
|
||||
m := reflect.ValueOf(msg)
|
||||
if m.Kind() != reflect.Ptr {
|
||||
return fmt.Errorf("unexpected type %T: %v", msg, msg)
|
||||
}
|
||||
var props *proto.Properties
|
||||
m = m.Elem()
|
||||
for i, fieldName := range fieldPath {
|
||||
isLast := i == len(fieldPath)-1
|
||||
if !isLast && m.Kind() != reflect.Struct {
|
||||
return fmt.Errorf("non-aggregate type in the mid of path: %s", strings.Join(fieldPath, "."))
|
||||
}
|
||||
var f reflect.Value
|
||||
f, props = fieldByProtoName(m, fieldName)
|
||||
if !f.IsValid() {
|
||||
grpclog.Printf("field not found in %T: %s", msg, strings.Join(fieldPath, "."))
|
||||
return nil
|
||||
}
|
||||
|
||||
switch f.Kind() {
|
||||
case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, reflect.String, reflect.Uint32, reflect.Uint64:
|
||||
if !isLast {
|
||||
return fmt.Errorf("unexpected nested field %s in %s", fieldPath[i+1], strings.Join(fieldPath[:i+1], "."))
|
||||
}
|
||||
m = f
|
||||
case reflect.Slice:
|
||||
// TODO(yugui) Support []byte
|
||||
if !isLast {
|
||||
return fmt.Errorf("unexpected repeated field in %s", strings.Join(fieldPath, "."))
|
||||
}
|
||||
return populateRepeatedField(f, values, props)
|
||||
case reflect.Ptr:
|
||||
if f.IsNil() {
|
||||
m = reflect.New(f.Type().Elem())
|
||||
f.Set(m.Convert(f.Type()))
|
||||
}
|
||||
m = f.Elem()
|
||||
continue
|
||||
case reflect.Struct:
|
||||
m = f
|
||||
continue
|
||||
default:
|
||||
return fmt.Errorf("unexpected type %s in %T", f.Type(), msg)
|
||||
}
|
||||
}
|
||||
switch len(values) {
|
||||
case 0:
|
||||
return fmt.Errorf("no value of field: %s", strings.Join(fieldPath, "."))
|
||||
case 1:
|
||||
default:
|
||||
grpclog.Printf("too many field values: %s", strings.Join(fieldPath, "."))
|
||||
}
|
||||
return populateField(m, values[0], props)
|
||||
}
|
||||
|
||||
// fieldByProtoName looks up a field whose corresponding protobuf field name is "name".
|
||||
// "m" must be a struct value. It returns zero reflect.Value if no such field found.
|
||||
func fieldByProtoName(m reflect.Value, name string) (reflect.Value, *proto.Properties) {
|
||||
props := proto.GetProperties(m.Type())
|
||||
for _, p := range props.Prop {
|
||||
if p.OrigName == name {
|
||||
return m.FieldByName(p.Name), p
|
||||
}
|
||||
}
|
||||
return reflect.Value{}, nil
|
||||
}
|
||||
|
||||
func populateRepeatedField(f reflect.Value, values []string, props *proto.Properties) error {
|
||||
elemType := f.Type().Elem()
|
||||
|
||||
// is the destination field a slice of an enumeration type?
|
||||
if enumValMap := proto.EnumValueMap(props.Enum); enumValMap != nil {
|
||||
return populateFieldEnumRepeated(f, values, enumValMap)
|
||||
}
|
||||
|
||||
conv, ok := convFromType[elemType.Kind()]
|
||||
if !ok {
|
||||
return fmt.Errorf("unsupported field type %s", elemType)
|
||||
}
|
||||
f.Set(reflect.MakeSlice(f.Type(), len(values), len(values)).Convert(f.Type()))
|
||||
for i, v := range values {
|
||||
result := conv.Call([]reflect.Value{reflect.ValueOf(v)})
|
||||
if err := result[1].Interface(); err != nil {
|
||||
return err.(error)
|
||||
}
|
||||
f.Index(i).Set(result[0].Convert(f.Index(i).Type()))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func populateField(f reflect.Value, value string, props *proto.Properties) error {
|
||||
// Handle well known type
|
||||
type wkt interface {
|
||||
XXX_WellKnownType() string
|
||||
}
|
||||
if wkt, ok := f.Addr().Interface().(wkt); ok {
|
||||
switch wkt.XXX_WellKnownType() {
|
||||
case "Timestamp":
|
||||
if value == "null" {
|
||||
f.Field(0).SetInt(0)
|
||||
f.Field(1).SetInt(0)
|
||||
return nil
|
||||
}
|
||||
|
||||
t, err := time.Parse(time.RFC3339Nano, value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("bad Timestamp: %v", err)
|
||||
}
|
||||
f.Field(0).SetInt(int64(t.Unix()))
|
||||
f.Field(1).SetInt(int64(t.Nanosecond()))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// is the destination field an enumeration type?
|
||||
if enumValMap := proto.EnumValueMap(props.Enum); enumValMap != nil {
|
||||
return populateFieldEnum(f, value, enumValMap)
|
||||
}
|
||||
|
||||
conv, ok := convFromType[f.Kind()]
|
||||
if !ok {
|
||||
return fmt.Errorf("unsupported field type %T", f)
|
||||
}
|
||||
result := conv.Call([]reflect.Value{reflect.ValueOf(value)})
|
||||
if err := result[1].Interface(); err != nil {
|
||||
return err.(error)
|
||||
}
|
||||
f.Set(result[0].Convert(f.Type()))
|
||||
return nil
|
||||
}
|
||||
|
||||
func convertEnum(value string, t reflect.Type, enumValMap map[string]int32) (reflect.Value, error) {
|
||||
// see if it's an enumeration string
|
||||
if enumVal, ok := enumValMap[value]; ok {
|
||||
return reflect.ValueOf(enumVal).Convert(t), nil
|
||||
}
|
||||
|
||||
// check for an integer that matches an enumeration value
|
||||
eVal, err := strconv.Atoi(value)
|
||||
if err != nil {
|
||||
return reflect.Value{}, fmt.Errorf("%s is not a valid %s", value, t)
|
||||
}
|
||||
for _, v := range enumValMap {
|
||||
if v == int32(eVal) {
|
||||
return reflect.ValueOf(eVal).Convert(t), nil
|
||||
}
|
||||
}
|
||||
return reflect.Value{}, fmt.Errorf("%s is not a valid %s", value, t)
|
||||
}
|
||||
|
||||
func populateFieldEnum(f reflect.Value, value string, enumValMap map[string]int32) error {
|
||||
cval, err := convertEnum(value, f.Type(), enumValMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.Set(cval)
|
||||
return nil
|
||||
}
|
||||
|
||||
func populateFieldEnumRepeated(f reflect.Value, values []string, enumValMap map[string]int32) error {
|
||||
elemType := f.Type().Elem()
|
||||
f.Set(reflect.MakeSlice(f.Type(), len(values), len(values)).Convert(f.Type()))
|
||||
for i, v := range values {
|
||||
result, err := convertEnum(v, elemType, enumValMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.Index(i).Set(result)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
convFromType = map[reflect.Kind]reflect.Value{
|
||||
reflect.String: reflect.ValueOf(String),
|
||||
reflect.Bool: reflect.ValueOf(Bool),
|
||||
reflect.Float64: reflect.ValueOf(Float64),
|
||||
reflect.Float32: reflect.ValueOf(Float32),
|
||||
reflect.Int64: reflect.ValueOf(Int64),
|
||||
reflect.Int32: reflect.ValueOf(Int32),
|
||||
reflect.Uint64: reflect.ValueOf(Uint64),
|
||||
reflect.Uint32: reflect.ValueOf(Uint32),
|
||||
// TODO(yugui) Support []byte
|
||||
}
|
||||
)
|
470
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/query_test.go
generated
vendored
Normal file
470
vendor/github.com/grpc-ecosystem/grpc-gateway/runtime/query_test.go
generated
vendored
Normal file
@@ -0,0 +1,470 @@
|
||||
package runtime_test
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"time"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/golang/protobuf/ptypes"
|
||||
"github.com/golang/protobuf/ptypes/timestamp"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/runtime"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/utilities"
|
||||
)
|
||||
|
||||
func TestPopulateParameters(t *testing.T) {
|
||||
timeT := time.Date(2016, time.December, 15, 12, 23, 32, 49, time.UTC)
|
||||
timeStr := timeT.Format(time.RFC3339Nano)
|
||||
timePb, err := ptypes.TimestampProto(timeT)
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't setup timestamp in Protobuf format: %v", err)
|
||||
}
|
||||
|
||||
for _, spec := range []struct {
|
||||
values url.Values
|
||||
filter *utilities.DoubleArray
|
||||
want proto.Message
|
||||
}{
|
||||
{
|
||||
values: url.Values{
|
||||
"float_value": {"1.5"},
|
||||
"double_value": {"2.5"},
|
||||
"int64_value": {"-1"},
|
||||
"int32_value": {"-2"},
|
||||
"uint64_value": {"3"},
|
||||
"uint32_value": {"4"},
|
||||
"bool_value": {"true"},
|
||||
"string_value": {"str"},
|
||||
"repeated_value": {"a", "b", "c"},
|
||||
"enum_value": {"1"},
|
||||
"repeated_enum": {"1", "2", "0"},
|
||||
"timestamp_value": {timeStr},
|
||||
},
|
||||
filter: utilities.NewDoubleArray(nil),
|
||||
want: &proto3Message{
|
||||
FloatValue: 1.5,
|
||||
DoubleValue: 2.5,
|
||||
Int64Value: -1,
|
||||
Int32Value: -2,
|
||||
Uint64Value: 3,
|
||||
Uint32Value: 4,
|
||||
BoolValue: true,
|
||||
StringValue: "str",
|
||||
RepeatedValue: []string{"a", "b", "c"},
|
||||
EnumValue: EnumValue_Y,
|
||||
RepeatedEnum: []EnumValue{EnumValue_Y, EnumValue_Z, EnumValue_X},
|
||||
TimestampValue: timePb,
|
||||
},
|
||||
},
|
||||
{
|
||||
values: url.Values{
|
||||
"enum_value": {"EnumValue_Z"},
|
||||
"repeated_enum": {"EnumValue_X", "2", "0"},
|
||||
},
|
||||
filter: utilities.NewDoubleArray(nil),
|
||||
want: &proto3Message{
|
||||
EnumValue: EnumValue_Z,
|
||||
RepeatedEnum: []EnumValue{EnumValue_X, EnumValue_Z, EnumValue_X},
|
||||
},
|
||||
},
|
||||
{
|
||||
values: url.Values{
|
||||
"float_value": {"1.5"},
|
||||
"double_value": {"2.5"},
|
||||
"int64_value": {"-1"},
|
||||
"int32_value": {"-2"},
|
||||
"uint64_value": {"3"},
|
||||
"uint32_value": {"4"},
|
||||
"bool_value": {"true"},
|
||||
"string_value": {"str"},
|
||||
"repeated_value": {"a", "b", "c"},
|
||||
"enum_value": {"1"},
|
||||
"repeated_enum": {"1", "2", "0"},
|
||||
},
|
||||
filter: utilities.NewDoubleArray(nil),
|
||||
want: &proto2Message{
|
||||
FloatValue: proto.Float32(1.5),
|
||||
DoubleValue: proto.Float64(2.5),
|
||||
Int64Value: proto.Int64(-1),
|
||||
Int32Value: proto.Int32(-2),
|
||||
Uint64Value: proto.Uint64(3),
|
||||
Uint32Value: proto.Uint32(4),
|
||||
BoolValue: proto.Bool(true),
|
||||
StringValue: proto.String("str"),
|
||||
RepeatedValue: []string{"a", "b", "c"},
|
||||
EnumValue: EnumValue_Y,
|
||||
RepeatedEnum: []EnumValue{EnumValue_Y, EnumValue_Z, EnumValue_X},
|
||||
},
|
||||
},
|
||||
{
|
||||
values: url.Values{
|
||||
"nested.nested.nested.repeated_value": {"a", "b", "c"},
|
||||
"nested.nested.nested.string_value": {"s"},
|
||||
"nested.nested.string_value": {"t"},
|
||||
"nested.string_value": {"u"},
|
||||
"nested_non_null.string_value": {"v"},
|
||||
},
|
||||
filter: utilities.NewDoubleArray(nil),
|
||||
want: &proto3Message{
|
||||
Nested: &proto2Message{
|
||||
Nested: &proto3Message{
|
||||
Nested: &proto2Message{
|
||||
RepeatedValue: []string{"a", "b", "c"},
|
||||
StringValue: proto.String("s"),
|
||||
},
|
||||
StringValue: "t",
|
||||
},
|
||||
StringValue: proto.String("u"),
|
||||
},
|
||||
NestedNonNull: proto2Message{
|
||||
StringValue: proto.String("v"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
values: url.Values{
|
||||
"uint64_value": {"1", "2", "3", "4", "5"},
|
||||
},
|
||||
filter: utilities.NewDoubleArray(nil),
|
||||
want: &proto3Message{
|
||||
Uint64Value: 1,
|
||||
},
|
||||
},
|
||||
} {
|
||||
msg := proto.Clone(spec.want)
|
||||
msg.Reset()
|
||||
err := runtime.PopulateQueryParameters(msg, spec.values, spec.filter)
|
||||
if err != nil {
|
||||
t.Errorf("runtime.PopulateQueryParameters(msg, %v, %v) failed with %v; want success", spec.values, spec.filter, err)
|
||||
continue
|
||||
}
|
||||
if got, want := msg, spec.want; !proto.Equal(got, want) {
|
||||
t.Errorf("runtime.PopulateQueryParameters(msg, %v, %v = %v; want %v", spec.values, spec.filter, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPopulateParametersWithFilters(t *testing.T) {
|
||||
for _, spec := range []struct {
|
||||
values url.Values
|
||||
filter *utilities.DoubleArray
|
||||
want proto.Message
|
||||
}{
|
||||
{
|
||||
values: url.Values{
|
||||
"bool_value": {"true"},
|
||||
"string_value": {"str"},
|
||||
"repeated_value": {"a", "b", "c"},
|
||||
},
|
||||
filter: utilities.NewDoubleArray([][]string{
|
||||
{"bool_value"}, {"repeated_value"},
|
||||
}),
|
||||
want: &proto3Message{
|
||||
StringValue: "str",
|
||||
},
|
||||
},
|
||||
{
|
||||
values: url.Values{
|
||||
"nested.nested.bool_value": {"true"},
|
||||
"nested.nested.string_value": {"str"},
|
||||
"nested.string_value": {"str"},
|
||||
"string_value": {"str"},
|
||||
},
|
||||
filter: utilities.NewDoubleArray([][]string{
|
||||
{"nested"},
|
||||
}),
|
||||
want: &proto3Message{
|
||||
StringValue: "str",
|
||||
},
|
||||
},
|
||||
{
|
||||
values: url.Values{
|
||||
"nested.nested.bool_value": {"true"},
|
||||
"nested.nested.string_value": {"str"},
|
||||
"nested.string_value": {"str"},
|
||||
"string_value": {"str"},
|
||||
},
|
||||
filter: utilities.NewDoubleArray([][]string{
|
||||
{"nested", "nested"},
|
||||
}),
|
||||
want: &proto3Message{
|
||||
Nested: &proto2Message{
|
||||
StringValue: proto.String("str"),
|
||||
},
|
||||
StringValue: "str",
|
||||
},
|
||||
},
|
||||
{
|
||||
values: url.Values{
|
||||
"nested.nested.bool_value": {"true"},
|
||||
"nested.nested.string_value": {"str"},
|
||||
"nested.string_value": {"str"},
|
||||
"string_value": {"str"},
|
||||
},
|
||||
filter: utilities.NewDoubleArray([][]string{
|
||||
{"nested", "nested", "string_value"},
|
||||
}),
|
||||
want: &proto3Message{
|
||||
Nested: &proto2Message{
|
||||
StringValue: proto.String("str"),
|
||||
Nested: &proto3Message{
|
||||
BoolValue: true,
|
||||
},
|
||||
},
|
||||
StringValue: "str",
|
||||
},
|
||||
},
|
||||
} {
|
||||
msg := proto.Clone(spec.want)
|
||||
msg.Reset()
|
||||
err := runtime.PopulateQueryParameters(msg, spec.values, spec.filter)
|
||||
if err != nil {
|
||||
t.Errorf("runtime.PoplateQueryParameters(msg, %v, %v) failed with %v; want success", spec.values, spec.filter, err)
|
||||
continue
|
||||
}
|
||||
if got, want := msg, spec.want; !proto.Equal(got, want) {
|
||||
t.Errorf("runtime.PopulateQueryParameters(msg, %v, %v = %v; want %v", spec.values, spec.filter, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPopulateQueryParametersWithInvalidNestedParameters(t *testing.T) {
|
||||
for _, spec := range []struct {
|
||||
msg proto.Message
|
||||
values url.Values
|
||||
filter *utilities.DoubleArray
|
||||
}{
|
||||
{
|
||||
msg: &proto3Message{},
|
||||
values: url.Values{
|
||||
"float_value.nested": {"test"},
|
||||
},
|
||||
filter: utilities.NewDoubleArray(nil),
|
||||
},
|
||||
{
|
||||
msg: &proto3Message{},
|
||||
values: url.Values{
|
||||
"double_value.nested": {"test"},
|
||||
},
|
||||
filter: utilities.NewDoubleArray(nil),
|
||||
},
|
||||
{
|
||||
msg: &proto3Message{},
|
||||
values: url.Values{
|
||||
"int64_value.nested": {"test"},
|
||||
},
|
||||
filter: utilities.NewDoubleArray(nil),
|
||||
},
|
||||
{
|
||||
msg: &proto3Message{},
|
||||
values: url.Values{
|
||||
"int32_value.nested": {"test"},
|
||||
},
|
||||
filter: utilities.NewDoubleArray(nil),
|
||||
},
|
||||
{
|
||||
msg: &proto3Message{},
|
||||
values: url.Values{
|
||||
"uint64_value.nested": {"test"},
|
||||
},
|
||||
filter: utilities.NewDoubleArray(nil),
|
||||
},
|
||||
{
|
||||
msg: &proto3Message{},
|
||||
values: url.Values{
|
||||
"uint32_value.nested": {"test"},
|
||||
},
|
||||
filter: utilities.NewDoubleArray(nil),
|
||||
},
|
||||
{
|
||||
msg: &proto3Message{},
|
||||
values: url.Values{
|
||||
"bool_value.nested": {"test"},
|
||||
},
|
||||
filter: utilities.NewDoubleArray(nil),
|
||||
},
|
||||
{
|
||||
msg: &proto3Message{},
|
||||
values: url.Values{
|
||||
"string_value.nested": {"test"},
|
||||
},
|
||||
filter: utilities.NewDoubleArray(nil),
|
||||
},
|
||||
{
|
||||
msg: &proto3Message{},
|
||||
values: url.Values{
|
||||
"repeated_value.nested": {"test"},
|
||||
},
|
||||
filter: utilities.NewDoubleArray(nil),
|
||||
},
|
||||
{
|
||||
msg: &proto3Message{},
|
||||
values: url.Values{
|
||||
"enum_value.nested": {"test"},
|
||||
},
|
||||
filter: utilities.NewDoubleArray(nil),
|
||||
},
|
||||
{
|
||||
msg: &proto3Message{},
|
||||
values: url.Values{
|
||||
"enum_value.nested": {"test"},
|
||||
},
|
||||
filter: utilities.NewDoubleArray(nil),
|
||||
},
|
||||
{
|
||||
msg: &proto3Message{},
|
||||
values: url.Values{
|
||||
"repeated_enum.nested": {"test"},
|
||||
},
|
||||
filter: utilities.NewDoubleArray(nil),
|
||||
},
|
||||
} {
|
||||
spec.msg.Reset()
|
||||
err := runtime.PopulateQueryParameters(spec.msg, spec.values, spec.filter)
|
||||
if err == nil {
|
||||
t.Errorf("runtime.PopulateQueryParameters(msg, %v, %v) did not fail; want error", spec.values, spec.filter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type proto3Message struct {
|
||||
Nested *proto2Message `protobuf:"bytes,1,opt,name=nested" json:"nested,omitempty"`
|
||||
NestedNonNull proto2Message `protobuf:"bytes,11,opt,name=nested_non_null" json:"nested_non_null,omitempty"`
|
||||
FloatValue float32 `protobuf:"fixed32,2,opt,name=float_value" json:"float_value,omitempty"`
|
||||
DoubleValue float64 `protobuf:"fixed64,3,opt,name=double_value" json:"double_value,omitempty"`
|
||||
Int64Value int64 `protobuf:"varint,4,opt,name=int64_value" json:"int64_value,omitempty"`
|
||||
Int32Value int32 `protobuf:"varint,5,opt,name=int32_value" json:"int32_value,omitempty"`
|
||||
Uint64Value uint64 `protobuf:"varint,6,opt,name=uint64_value" json:"uint64_value,omitempty"`
|
||||
Uint32Value uint32 `protobuf:"varint,7,opt,name=uint32_value" json:"uint32_value,omitempty"`
|
||||
BoolValue bool `protobuf:"varint,8,opt,name=bool_value" json:"bool_value,omitempty"`
|
||||
StringValue string `protobuf:"bytes,9,opt,name=string_value" json:"string_value,omitempty"`
|
||||
RepeatedValue []string `protobuf:"bytes,10,rep,name=repeated_value" json:"repeated_value,omitempty"`
|
||||
EnumValue EnumValue `protobuf:"varint,11,opt,name=enum_value,json=enumValue,enum=runtime_test_api.EnumValue" json:"enum_value,omitempty"`
|
||||
RepeatedEnum []EnumValue `protobuf:"varint,12,rep,packed,name=repeated_enum,json=repeated_enum,enum=runtime_test_api.EnumValue" json:"repeated_enum,omitempty"`
|
||||
TimestampValue *timestamp.Timestamp `protobuf:"bytes,11,opt,name=timestamp_value" json:"timestamp_value,omitempty"`
|
||||
}
|
||||
|
||||
func (m *proto3Message) Reset() { *m = proto3Message{} }
|
||||
func (m *proto3Message) String() string { return proto.CompactTextString(m) }
|
||||
func (*proto3Message) ProtoMessage() {}
|
||||
|
||||
func (m *proto3Message) GetNested() *proto2Message {
|
||||
if m != nil {
|
||||
return m.Nested
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type proto2Message struct {
|
||||
Nested *proto3Message `protobuf:"bytes,1,opt,name=nested" json:"nested,omitempty"`
|
||||
FloatValue *float32 `protobuf:"fixed32,2,opt,name=float_value" json:"float_value,omitempty"`
|
||||
DoubleValue *float64 `protobuf:"fixed64,3,opt,name=double_value" json:"double_value,omitempty"`
|
||||
Int64Value *int64 `protobuf:"varint,4,opt,name=int64_value" json:"int64_value,omitempty"`
|
||||
Int32Value *int32 `protobuf:"varint,5,opt,name=int32_value" json:"int32_value,omitempty"`
|
||||
Uint64Value *uint64 `protobuf:"varint,6,opt,name=uint64_value" json:"uint64_value,omitempty"`
|
||||
Uint32Value *uint32 `protobuf:"varint,7,opt,name=uint32_value" json:"uint32_value,omitempty"`
|
||||
BoolValue *bool `protobuf:"varint,8,opt,name=bool_value" json:"bool_value,omitempty"`
|
||||
StringValue *string `protobuf:"bytes,9,opt,name=string_value" json:"string_value,omitempty"`
|
||||
RepeatedValue []string `protobuf:"bytes,10,rep,name=repeated_value" json:"repeated_value,omitempty"`
|
||||
EnumValue EnumValue `protobuf:"varint,11,opt,name=enum_value,json=enumValue,enum=runtime_test_api.EnumValue" json:"enum_value,omitempty"`
|
||||
RepeatedEnum []EnumValue `protobuf:"varint,12,rep,packed,name=repeated_enum,json=repeated_enum,enum=runtime_test_api.EnumValue" json:"repeated_enum,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
}
|
||||
|
||||
func (m *proto2Message) Reset() { *m = proto2Message{} }
|
||||
func (m *proto2Message) String() string { return proto.CompactTextString(m) }
|
||||
func (*proto2Message) ProtoMessage() {}
|
||||
|
||||
func (m *proto2Message) GetNested() *proto3Message {
|
||||
if m != nil {
|
||||
return m.Nested
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *proto2Message) GetFloatValue() float32 {
|
||||
if m != nil && m.FloatValue != nil {
|
||||
return *m.FloatValue
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *proto2Message) GetDoubleValue() float64 {
|
||||
if m != nil && m.DoubleValue != nil {
|
||||
return *m.DoubleValue
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *proto2Message) GetInt64Value() int64 {
|
||||
if m != nil && m.Int64Value != nil {
|
||||
return *m.Int64Value
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *proto2Message) GetInt32Value() int32 {
|
||||
if m != nil && m.Int32Value != nil {
|
||||
return *m.Int32Value
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *proto2Message) GetUint64Value() uint64 {
|
||||
if m != nil && m.Uint64Value != nil {
|
||||
return *m.Uint64Value
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *proto2Message) GetUint32Value() uint32 {
|
||||
if m != nil && m.Uint32Value != nil {
|
||||
return *m.Uint32Value
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *proto2Message) GetBoolValue() bool {
|
||||
if m != nil && m.BoolValue != nil {
|
||||
return *m.BoolValue
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *proto2Message) GetStringValue() string {
|
||||
if m != nil && m.StringValue != nil {
|
||||
return *m.StringValue
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *proto2Message) GetRepeatedValue() []string {
|
||||
if m != nil {
|
||||
return m.RepeatedValue
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type EnumValue int32
|
||||
|
||||
const (
|
||||
EnumValue_X EnumValue = 0
|
||||
EnumValue_Y EnumValue = 1
|
||||
EnumValue_Z EnumValue = 2
|
||||
)
|
||||
|
||||
var EnumValue_name = map[int32]string{
|
||||
0: "EnumValue_X",
|
||||
1: "EnumValue_Y",
|
||||
2: "EnumValue_Z",
|
||||
}
|
||||
var EnumValue_value = map[string]int32{
|
||||
"EnumValue_X": 0,
|
||||
"EnumValue_Y": 1,
|
||||
"EnumValue_Z": 2,
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterEnum("runtime_test_api.EnumValue", EnumValue_name, EnumValue_value)
|
||||
}
|
Reference in New Issue
Block a user