cmd/grpcurl: add -allow-unknown-fields option (#147)
This commit is contained in:
parent
8376c2f7bb
commit
8e51c5e2d3
|
|
@ -100,6 +100,10 @@ var (
|
|||
ASCII character: 0x1E. The stream should not end in a record separator.
|
||||
If it does, it will be interpreted as a final, blank message after the
|
||||
separator.`))
|
||||
allowUnknownFields = flags.Bool("allow-unknown-fields", false, prettify(`
|
||||
When true, the request contents, if 'json' format is used, allows
|
||||
unkown fields to be present. They will be ignored when parsing
|
||||
the request.`))
|
||||
connectTimeout = flags.Float64("connect-timeout", 0, prettify(`
|
||||
The maximum time, in seconds, to wait for connection to be established.
|
||||
Defaults to 10 seconds.`))
|
||||
|
|
@ -615,7 +619,8 @@ func main() {
|
|||
// for messages, also show a template in JSON, to make it easier to
|
||||
// create a request to invoke an RPC
|
||||
tmpl := grpcurl.MakeTemplate(dsc)
|
||||
_, formatter, err := grpcurl.RequestParserAndFormatterFor(grpcurl.Format(*format), descSource, true, false, nil)
|
||||
options := grpcurl.FormatOptions{EmitJSONDefaultFields: true}
|
||||
_, formatter, err := grpcurl.RequestParserAndFormatter(grpcurl.Format(*format), descSource, nil, options)
|
||||
if err != nil {
|
||||
fail(err, "Failed to construct formatter for %q", *format)
|
||||
}
|
||||
|
|
@ -647,7 +652,12 @@ func main() {
|
|||
// between each message, so output could potentially be piped
|
||||
// to another grpcurl process
|
||||
includeSeparators := !*verbose
|
||||
rf, formatter, err := grpcurl.RequestParserAndFormatterFor(grpcurl.Format(*format), descSource, *emitDefaults, includeSeparators, in)
|
||||
options := grpcurl.FormatOptions{
|
||||
EmitJSONDefaultFields: *emitDefaults,
|
||||
IncludeTextSeparator: includeSeparators,
|
||||
AllowUnknownFields: *allowUnknownFields,
|
||||
}
|
||||
rf, formatter, err := grpcurl.RequestParserAndFormatter(grpcurl.Format(*format), descSource, in, options)
|
||||
if err != nil {
|
||||
fail(err, "Failed to construct request parser and formatter for %q", *format)
|
||||
}
|
||||
|
|
|
|||
64
format.go
64
format.go
|
|
@ -55,6 +55,15 @@ func NewJSONRequestParser(in io.Reader, resolver jsonpb.AnyResolver) RequestPars
|
|||
}
|
||||
}
|
||||
|
||||
// NewJSONRequestParserWithUnmarshaler is like NewJSONRequestParser but
|
||||
// accepts a protobuf jsonpb.Unmarshaler instead of jsonpb.AnyResolver.
|
||||
func NewJSONRequestParserWithUnmarshaler(in io.Reader, unmarshaler jsonpb.Unmarshaler) RequestParser {
|
||||
return &jsonRequestParser{
|
||||
dec: json.NewDecoder(in),
|
||||
unmarshaler: unmarshaler,
|
||||
}
|
||||
}
|
||||
|
||||
func (f *jsonRequestParser) Next(m proto.Message) error {
|
||||
var msg json.RawMessage
|
||||
if err := f.dec.Decode(&msg); err != nil {
|
||||
|
|
@ -342,21 +351,58 @@ func (a *unknownAny) ProtoMessage() {
|
|||
|
||||
var _ proto.Message = (*unknownAny)(nil)
|
||||
|
||||
// FormatOptions is a set of flags that are passed to a JSON or text formatter.
|
||||
type FormatOptions struct {
|
||||
// EmitJSONDefaultFields flag, when true, includes empty/default values in the output.
|
||||
// FormatJSON only flag.
|
||||
EmitJSONDefaultFields bool
|
||||
|
||||
// AllowUnknownFields is an option for the parser. When true,
|
||||
// it accepts input which includes unknown fields. These unknown fields
|
||||
// are skipped instead of returning an error.
|
||||
// FormatJSON only flag.
|
||||
AllowUnknownFields bool
|
||||
|
||||
// IncludeTextSeparator is true then, when invoked to format multiple messages,
|
||||
// all messages after the first one will be prefixed with the
|
||||
// ASCII 'Record Separator' character (0x1E).
|
||||
// It might be useful when the output is piped to another grpcurl process.
|
||||
// FormatText only flag.
|
||||
IncludeTextSeparator bool
|
||||
}
|
||||
|
||||
// RequestParserAndFormatter returns a request parser and formatter for the
|
||||
// given format. The given descriptor source may be used for parsing message
|
||||
// data (if needed by the format).
|
||||
// It accepts a set of options. The field EmitJSONDefaultFields and IncludeTextSeparator
|
||||
// are options for JSON and protobuf text formats, respectively. The AllowUnknownFields field
|
||||
// is a JSON-only format flag.
|
||||
// Requests will be parsed from the given in.
|
||||
func RequestParserAndFormatter(format Format, descSource DescriptorSource, in io.Reader, opts FormatOptions) (RequestParser, Formatter, error) {
|
||||
switch format {
|
||||
case FormatJSON:
|
||||
resolver := AnyResolverFromDescriptorSource(descSource)
|
||||
unmarshaler := jsonpb.Unmarshaler{AnyResolver: resolver, AllowUnknownFields: opts.AllowUnknownFields}
|
||||
return NewJSONRequestParserWithUnmarshaler(in, unmarshaler), NewJSONFormatter(opts.EmitJSONDefaultFields, anyResolverWithFallback{AnyResolver: resolver}), nil
|
||||
case FormatText:
|
||||
return NewTextRequestParser(in), NewTextFormatter(opts.IncludeTextSeparator), nil
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("unknown format: %s", format)
|
||||
}
|
||||
}
|
||||
|
||||
// RequestParserAndFormatterFor returns a request parser and formatter for the
|
||||
// given format. The given descriptor source may be used for parsing message
|
||||
// data (if needed by the format). The flags emitJSONDefaultFields and
|
||||
// includeTextSeparator are options for JSON and protobuf text formats,
|
||||
// respectively. Requests will be parsed from the given in.
|
||||
// This function is deprecated. Please use RequestParserAndFormatter instead.
|
||||
// DEPRECATED
|
||||
func RequestParserAndFormatterFor(format Format, descSource DescriptorSource, emitJSONDefaultFields, includeTextSeparator bool, in io.Reader) (RequestParser, Formatter, error) {
|
||||
switch format {
|
||||
case FormatJSON:
|
||||
resolver := AnyResolverFromDescriptorSource(descSource)
|
||||
return NewJSONRequestParser(in, resolver), NewJSONFormatter(emitJSONDefaultFields, anyResolverWithFallback{AnyResolver: resolver}), nil
|
||||
case FormatText:
|
||||
return NewTextRequestParser(in), NewTextFormatter(includeTextSeparator), nil
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("unknown format: %s", format)
|
||||
}
|
||||
return RequestParserAndFormatter(format, descSource, in, FormatOptions{
|
||||
EmitJSONDefaultFields: emitJSONDefaultFields,
|
||||
IncludeTextSeparator: includeTextSeparator,
|
||||
})
|
||||
}
|
||||
|
||||
// DefaultEventHandler logs events to a writer. This is not thread-safe, but is
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ func TestRequestParser(t *testing.T) {
|
|||
|
||||
for i, tc := range testCases {
|
||||
name := fmt.Sprintf("#%d, %s, %d message(s)", i+1, tc.format, len(tc.expectedOutput))
|
||||
rf, _, err := RequestParserAndFormatterFor(tc.format, source, false, false, strings.NewReader(tc.input))
|
||||
rf, _, err := RequestParserAndFormatter(tc.format, source, strings.NewReader(tc.input), FormatOptions{})
|
||||
if err != nil {
|
||||
t.Errorf("Failed to create parser and formatter: %v", err)
|
||||
continue
|
||||
|
|
@ -126,7 +126,7 @@ func TestHandler(t *testing.T) {
|
|||
name += ", verbose"
|
||||
}
|
||||
|
||||
_, formatter, err := RequestParserAndFormatterFor(format, source, false, !verbose, nil)
|
||||
_, formatter, err := RequestParserAndFormatter(format, source, nil, FormatOptions{IncludeTextSeparator: !verbose})
|
||||
if err != nil {
|
||||
t.Errorf("Failed to create parser and formatter: %v", err)
|
||||
continue
|
||||
|
|
|
|||
Loading…
Reference in New Issue