From 96d611ac2433034692c10e074684d95847576daf Mon Sep 17 00:00:00 2001 From: Roman Azami Date: Tue, 13 Nov 2018 14:45:17 -0800 Subject: [PATCH 1/7] Updated Patch behavior --- Gopkg.lock | 63 ++- Makefile | 2 +- .../abe/a_bit_of_everything_service_api.go | 231 ++++++++ .../abe/examplepb_update_v2_request.go | 18 + examples/clients/abe/protobuf_field_mask.go | 18 + examples/integration/integration_test.go | 188 +++++++ .../proto/examplepb/a_bit_of_everything.pb.go | 493 +++++++++++------- .../examplepb/a_bit_of_everything.pb.gw.go | 241 ++++++++- .../proto/examplepb/a_bit_of_everything.proto | 23 + .../a_bit_of_everything.swagger.json | 168 ++++++ .../proto/examplepb/echo_service.pb.gw.go | 6 +- .../proto/examplepb/flow_combination.pb.gw.go | 84 ++- examples/proto/examplepb/stream.pb.gw.go | 12 +- .../unannotated_echo_service.pb.gw.go | 6 +- examples/proto/examplepb/wrappers.pb.gw.go | 6 +- examples/server/a_bit_of_everything.go | 38 +- examples/server/fieldmask_helper.go | 55 ++ examples/server/fieldmask_helper_test.go | 92 ++++ .../gengateway/template.go | 58 ++- .../gengateway/template_test.go | 4 +- runtime/fieldmask.go | 70 +++ runtime/fieldmask_test.go | 87 ++++ utilities/readerfactory.go | 20 + 23 files changed, 1760 insertions(+), 223 deletions(-) create mode 100644 examples/clients/abe/examplepb_update_v2_request.go create mode 100644 examples/clients/abe/protobuf_field_mask.go create mode 100644 examples/server/fieldmask_helper.go create mode 100644 examples/server/fieldmask_helper_test.go create mode 100644 runtime/fieldmask.go create mode 100644 runtime/fieldmask_test.go create mode 100644 utilities/readerfactory.go diff --git a/Gopkg.lock b/Gopkg.lock index ca212aeaa81..1bbc8d61516 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -2,21 +2,28 @@ [[projects]] + digest = "1:2cd7915ab26ede7d95b8749e6b1f933f1c6d5398030684e6505940a10f31cfda" name = "github.com/ghodss/yaml" packages = ["."] + pruneopts = "UT" revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7" [[projects]] + digest = "1:5cae6c173646d9230aecf8074c171edb4fb9a37f074c5c89ba2fece20b6703b6" name = "github.com/go-resty/resty" packages = ["."] + pruneopts = "UT" revision = "f8815663de1e64d57cdd4ee9e2b2fa96977a030e" [[projects]] + digest = "1:1ba1d79f2810270045c328ae5d674321db34e3aae468eb4233883b473c5c0467" name = "github.com/golang/glog" packages = ["."] + pruneopts = "UT" revision = "23def4e6c14b4da8ac2ed8007337bc5eb5007998" [[projects]] + digest = "1:77303a120dcd145972685b3465e58e1a0910544fcb323ca24755e073c1ea6d2c" name = "github.com/golang/protobuf" packages = [ "jsonpb", @@ -33,16 +40,20 @@ "ptypes/empty", "ptypes/struct", "ptypes/timestamp", - "ptypes/wrappers" + "ptypes/wrappers", ] + pruneopts = "UT" revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5" [[projects]] + digest = "1:d673e95129a1107bfd04e093751a5e1267faabc27d218d824fb013f57ac08f55" name = "github.com/rogpeppe/fastuuid" packages = ["."] + pruneopts = "UT" revision = "6724a57986aff9bff1a1770e9347036def7c89f6" [[projects]] + digest = "1:c0b7af9789502fec69b7ab40035a2180e43b9663c32101084ba51c844ea416e9" name = "golang.org/x/net" packages = [ "context", @@ -52,17 +63,21 @@ "idna", "internal/timeseries", "publicsuffix", - "trace" + "trace", ] + pruneopts = "UT" revision = "4dfa2610cdf3b287375bbba5b8f2a14d3b01d8de" [[projects]] branch = "master" + digest = "1:7ba061af4131fb44b30448572acd0d6fefbf63a61b97b7ef1dea0be5871c2742" name = "golang.org/x/sys" packages = ["unix"] + pruneopts = "UT" revision = "66b7b1311ac80bbafcd2daeef9a5e6e2cd1e2399" [[projects]] + digest = "1:a2ab62866c75542dd18d2b069fec854577a20211d7c0ea6ae746072a1dccdd18" name = "golang.org/x/text" packages = [ "collate", @@ -78,22 +93,26 @@ "unicode/bidi", "unicode/cldr", "unicode/norm", - "unicode/rangetable" + "unicode/rangetable", ] + pruneopts = "UT" revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" version = "v0.3.0" [[projects]] + digest = "1:46be2f6b4d4e4b89f8102668902e68013234da1684fc78da602da95e745f285d" name = "google.golang.org/genproto" packages = [ "googleapis/api/annotations", "googleapis/rpc/errdetails", "googleapis/rpc/status", - "protobuf/field_mask" + "protobuf/field_mask", ] + pruneopts = "UT" revision = "383e8b2c3b9e36c4076b235b32537292176bae20" [[projects]] + digest = "1:c3ad9841823db6da420a5625b367913b4ff54bbe60e8e3c98bd20e243e62e2d2" name = "google.golang.org/grpc" packages = [ ".", @@ -121,19 +140,51 @@ "resolver/passthrough", "stats", "status", - "tap" + "tap", ] + pruneopts = "UT" revision = "2e463a05d100327ca47ac218281906921038fd95" version = "v1.16.0" [[projects]] + digest = "1:6570992c02a2137a20be83990a979b6fe892e20ecdc6b756449989b2a7efb8ae" name = "gopkg.in/yaml.v2" packages = ["."] + pruneopts = "UT" revision = "eb3733d160e74a9c7e442f435eb3bea458e1d19f" [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "869b43d6e47c7434098120dae9352bde379feae8504ece065ee51b78c6aca0fa" + input-imports = [ + "github.com/ghodss/yaml", + "github.com/go-resty/resty", + "github.com/golang/glog", + "github.com/golang/protobuf/jsonpb", + "github.com/golang/protobuf/proto", + "github.com/golang/protobuf/protoc-gen-go", + "github.com/golang/protobuf/protoc-gen-go/descriptor", + "github.com/golang/protobuf/protoc-gen-go/generator", + "github.com/golang/protobuf/protoc-gen-go/plugin", + "github.com/golang/protobuf/ptypes", + "github.com/golang/protobuf/ptypes/any", + "github.com/golang/protobuf/ptypes/duration", + "github.com/golang/protobuf/ptypes/empty", + "github.com/golang/protobuf/ptypes/struct", + "github.com/golang/protobuf/ptypes/timestamp", + "github.com/golang/protobuf/ptypes/wrappers", + "github.com/rogpeppe/fastuuid", + "golang.org/x/net/context", + "google.golang.org/genproto/googleapis/api/annotations", + "google.golang.org/genproto/googleapis/rpc/errdetails", + "google.golang.org/genproto/googleapis/rpc/status", + "google.golang.org/genproto/protobuf/field_mask", + "google.golang.org/grpc", + "google.golang.org/grpc/codes", + "google.golang.org/grpc/connectivity", + "google.golang.org/grpc/grpclog", + "google.golang.org/grpc/metadata", + "google.golang.org/grpc/status", + ] solver-name = "gps-cdcl" solver-version = 1 diff --git a/Makefile b/Makefile index 5cd992cd635..865058628ef 100644 --- a/Makefile +++ b/Makefile @@ -51,7 +51,7 @@ RUNTIME_GO=$(RUNTIME_PROTO:.proto=.pb.go) OPENAPIV2_PROTO=protoc-gen-swagger/options/openapiv2.proto protoc-gen-swagger/options/annotations.proto OPENAPIV2_GO=$(OPENAPIV2_PROTO:.proto=.pb.go) -PKGMAP=Mgoogle/protobuf/descriptor.proto=$(GO_PLUGIN_PKG)/descriptor,Mexamples/proto/sub/message.proto=$(PKG)/examples/proto/sub +PKGMAP=Mgoogle/protobuf/field_mask.proto=google.golang.org/genproto/protobuf/field_mask,Mgoogle/protobuf/descriptor.proto=$(GO_PLUGIN_PKG)/descriptor,Mexamples/proto/sub/message.proto=$(PKG)/examples/proto/sub ADDITIONAL_GW_FLAGS= ifneq "$(GATEWAY_PLUGIN_FLAGS)" "" ADDITIONAL_GW_FLAGS=,$(GATEWAY_PLUGIN_FLAGS) diff --git a/examples/clients/abe/a_bit_of_everything_service_api.go b/examples/clients/abe/a_bit_of_everything_service_api.go index d1f2a1f95e9..5e8d72779c3 100644 --- a/examples/clients/abe/a_bit_of_everything_service_api.go +++ b/examples/clients/abe/a_bit_of_everything_service_api.go @@ -812,6 +812,83 @@ func (a ABitOfEverythingServiceApi) Lookup(uuid string) (*ExamplepbABitOfEveryth return successPayload, localVarAPIResponse, err } +/** + * + * + * @param abeUuid + * @param body + * @return *ProtobufEmpty + */ +func (a ABitOfEverythingServiceApi) PatchWithFieldMaskInBody(abeUuid string, body ExamplepbUpdateV2Request) (*ProtobufEmpty, *APIResponse, error) { + + var localVarHttpMethod = strings.ToUpper("Patch") + // create path and map variables + localVarPath := a.Configuration.BasePath + "/v2a/example/a_bit_of_everything/{abe.uuid}" + localVarPath = strings.Replace(localVarPath, "{"+"abe.uuid"+"}", fmt.Sprintf("%v", abeUuid), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := make(map[string]string) + var localVarPostBody interface{} + var localVarFileName string + var localVarFileBytes []byte + // authentication '(OAuth2)' required + // oauth required + if a.Configuration.AccessToken != ""{ + localVarHeaderParams["Authorization"] = "Bearer " + a.Configuration.AccessToken + } + // authentication '(BasicAuth)' required + // http basic authentication required + if a.Configuration.Username != "" || a.Configuration.Password != ""{ + localVarHeaderParams["Authorization"] = "Basic " + a.Configuration.GetBasicAuthEncodedString() + } + // authentication '(ApiKeyAuth)' required + // set key with prefix in header + localVarHeaderParams["X-API-Key"] = a.Configuration.GetAPIKeyWithPrefix("X-API-Key") + // add default headers if any + for key := range a.Configuration.DefaultHeader { + localVarHeaderParams[key] = a.Configuration.DefaultHeader[key] + } + + // to determine the Content-Type header + localVarHttpContentTypes := []string{ "application/json", "application/x-foo-mime", } + + // set Content-Type header + localVarHttpContentType := a.Configuration.APIClient.SelectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + // to determine the Accept header + localVarHttpHeaderAccepts := []string{ + "application/json", + "application/x-foo-mime", + } + + // set Accept header + localVarHttpHeaderAccept := a.Configuration.APIClient.SelectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &body + var successPayload = new(ProtobufEmpty) + localVarHttpResponse, err := a.Configuration.APIClient.CallAPI(localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + + var localVarURL, _ = url.Parse(localVarPath) + localVarURL.RawQuery = localVarQueryParams.Encode() + var localVarAPIResponse = &APIResponse{Operation: "PatchWithFieldMaskInBody", Method: localVarHttpMethod, RequestURL: localVarURL.String()} + if localVarHttpResponse != nil { + localVarAPIResponse.Response = localVarHttpResponse.RawResponse + localVarAPIResponse.Payload = localVarHttpResponse.Body() + } + + if err != nil { + return successPayload, localVarAPIResponse, err + } + err = json.Unmarshal(localVarHttpResponse.Body(), &successPayload) + return successPayload, localVarAPIResponse, err +} + /** * * @@ -1038,3 +1115,157 @@ func (a ABitOfEverythingServiceApi) Update(uuid string, body ExamplepbABitOfEver return successPayload, localVarAPIResponse, err } +/** + * + * + * @param abeUuid + * @param body + * @return *ProtobufEmpty + */ +func (a ABitOfEverythingServiceApi) UpdateV2(abeUuid string, body ExamplepbABitOfEverything) (*ProtobufEmpty, *APIResponse, error) { + + var localVarHttpMethod = strings.ToUpper("Put") + // create path and map variables + localVarPath := a.Configuration.BasePath + "/v2/example/a_bit_of_everything/{abe.uuid}" + localVarPath = strings.Replace(localVarPath, "{"+"abe.uuid"+"}", fmt.Sprintf("%v", abeUuid), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := make(map[string]string) + var localVarPostBody interface{} + var localVarFileName string + var localVarFileBytes []byte + // authentication '(OAuth2)' required + // oauth required + if a.Configuration.AccessToken != ""{ + localVarHeaderParams["Authorization"] = "Bearer " + a.Configuration.AccessToken + } + // authentication '(BasicAuth)' required + // http basic authentication required + if a.Configuration.Username != "" || a.Configuration.Password != ""{ + localVarHeaderParams["Authorization"] = "Basic " + a.Configuration.GetBasicAuthEncodedString() + } + // authentication '(ApiKeyAuth)' required + // set key with prefix in header + localVarHeaderParams["X-API-Key"] = a.Configuration.GetAPIKeyWithPrefix("X-API-Key") + // add default headers if any + for key := range a.Configuration.DefaultHeader { + localVarHeaderParams[key] = a.Configuration.DefaultHeader[key] + } + + // to determine the Content-Type header + localVarHttpContentTypes := []string{ "application/json", "application/x-foo-mime", } + + // set Content-Type header + localVarHttpContentType := a.Configuration.APIClient.SelectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + // to determine the Accept header + localVarHttpHeaderAccepts := []string{ + "application/json", + "application/x-foo-mime", + } + + // set Accept header + localVarHttpHeaderAccept := a.Configuration.APIClient.SelectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &body + var successPayload = new(ProtobufEmpty) + localVarHttpResponse, err := a.Configuration.APIClient.CallAPI(localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + + var localVarURL, _ = url.Parse(localVarPath) + localVarURL.RawQuery = localVarQueryParams.Encode() + var localVarAPIResponse = &APIResponse{Operation: "UpdateV2", Method: localVarHttpMethod, RequestURL: localVarURL.String()} + if localVarHttpResponse != nil { + localVarAPIResponse.Response = localVarHttpResponse.RawResponse + localVarAPIResponse.Payload = localVarHttpResponse.Body() + } + + if err != nil { + return successPayload, localVarAPIResponse, err + } + err = json.Unmarshal(localVarHttpResponse.Body(), &successPayload) + return successPayload, localVarAPIResponse, err +} + +/** + * + * + * @param abeUuid + * @param body + * @return *ProtobufEmpty + */ +func (a ABitOfEverythingServiceApi) UpdateV22(abeUuid string, body ExamplepbABitOfEverything) (*ProtobufEmpty, *APIResponse, error) { + + var localVarHttpMethod = strings.ToUpper("Patch") + // create path and map variables + localVarPath := a.Configuration.BasePath + "/v2/example/a_bit_of_everything/{abe.uuid}" + localVarPath = strings.Replace(localVarPath, "{"+"abe.uuid"+"}", fmt.Sprintf("%v", abeUuid), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := make(map[string]string) + var localVarPostBody interface{} + var localVarFileName string + var localVarFileBytes []byte + // authentication '(OAuth2)' required + // oauth required + if a.Configuration.AccessToken != ""{ + localVarHeaderParams["Authorization"] = "Bearer " + a.Configuration.AccessToken + } + // authentication '(BasicAuth)' required + // http basic authentication required + if a.Configuration.Username != "" || a.Configuration.Password != ""{ + localVarHeaderParams["Authorization"] = "Basic " + a.Configuration.GetBasicAuthEncodedString() + } + // authentication '(ApiKeyAuth)' required + // set key with prefix in header + localVarHeaderParams["X-API-Key"] = a.Configuration.GetAPIKeyWithPrefix("X-API-Key") + // add default headers if any + for key := range a.Configuration.DefaultHeader { + localVarHeaderParams[key] = a.Configuration.DefaultHeader[key] + } + + // to determine the Content-Type header + localVarHttpContentTypes := []string{ "application/json", "application/x-foo-mime", } + + // set Content-Type header + localVarHttpContentType := a.Configuration.APIClient.SelectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + // to determine the Accept header + localVarHttpHeaderAccepts := []string{ + "application/json", + "application/x-foo-mime", + } + + // set Accept header + localVarHttpHeaderAccept := a.Configuration.APIClient.SelectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &body + var successPayload = new(ProtobufEmpty) + localVarHttpResponse, err := a.Configuration.APIClient.CallAPI(localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + + var localVarURL, _ = url.Parse(localVarPath) + localVarURL.RawQuery = localVarQueryParams.Encode() + var localVarAPIResponse = &APIResponse{Operation: "UpdateV22", Method: localVarHttpMethod, RequestURL: localVarURL.String()} + if localVarHttpResponse != nil { + localVarAPIResponse.Response = localVarHttpResponse.RawResponse + localVarAPIResponse.Payload = localVarHttpResponse.Body() + } + + if err != nil { + return successPayload, localVarAPIResponse, err + } + err = json.Unmarshal(localVarHttpResponse.Body(), &successPayload) + return successPayload, localVarAPIResponse, err +} + diff --git a/examples/clients/abe/examplepb_update_v2_request.go b/examples/clients/abe/examplepb_update_v2_request.go new file mode 100644 index 00000000000..9d021f8241c --- /dev/null +++ b/examples/clients/abe/examplepb_update_v2_request.go @@ -0,0 +1,18 @@ +/* + * A Bit of Everything + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * OpenAPI spec version: 1.0 + * Contact: none@example.com + * Generated by: https://github.com/swagger-api/swagger-codegen.git + */ + +package abe + +type ExamplepbUpdateV2Request struct { + + Abe ExamplepbABitOfEverything `json:"abe,omitempty"` + + UpdateMask ProtobufFieldMask `json:"update_mask,omitempty"` +} diff --git a/examples/clients/abe/protobuf_field_mask.go b/examples/clients/abe/protobuf_field_mask.go new file mode 100644 index 00000000000..f30f2531765 --- /dev/null +++ b/examples/clients/abe/protobuf_field_mask.go @@ -0,0 +1,18 @@ +/* + * A Bit of Everything + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * OpenAPI spec version: 1.0 + * Contact: none@example.com + * Generated by: https://github.com/swagger-api/swagger-codegen.git + */ + +package abe + +// paths: \"f.a\" paths: \"f.b.d\" Here `f` represents a field in some root message, `a` and `b` fields in the message found in `f`, and `d` a field found in the message in `f.b`. Field masks are used to specify a subset of fields that should be returned by a get operation or modified by an update operation. Field masks also have a custom JSON encoding (see below). # Field Masks in Projections When used in the context of a projection, a response message or sub-message is filtered by the API to only contain those fields as specified in the mask. For example, if the mask in the previous example is applied to a response message as follows: f { a : 22 b { d : 1 x : 2 } y : 13 } z: 8 The result will not contain specific values for fields x,y and z (their value will be set to the default, and omitted in proto text output): f { a : 22 b { d : 1 } } A repeated field is not allowed except at the last position of a paths string. If a FieldMask object is not present in a get operation, the operation applies to all fields (as if a FieldMask of all fields had been specified). Note that a field mask does not necessarily apply to the top-level response message. In case of a REST get operation, the field mask applies directly to the response, but in case of a REST list operation, the mask instead applies to each individual message in the returned resource list. In case of a REST custom method, other definitions may be used. Where the mask applies will be clearly documented together with its declaration in the API. In any case, the effect on the returned resource/resources is required behavior for APIs. # Field Masks in Update Operations A field mask in update operations specifies which fields of the targeted resource are going to be updated. The API is required to only change the values of the fields as specified in the mask and leave the others untouched. If a resource is passed in to describe the updated values, the API ignores the values of all fields not covered by the mask. If a repeated field is specified for an update operation, the existing repeated values in the target resource will be overwritten by the new values. Note that a repeated field is only allowed in the last position of a `paths` string. If a sub-message is specified in the last position of the field mask for an update operation, then the existing sub-message in the target resource is overwritten. Given the target message: f { b { d : 1 x : 2 } c : 1 } And an update message: f { b { d : 10 } } then if the field mask is: paths: \"f.b\" then the result will be: f { b { d : 10 } c : 1 } However, if the update mask was: paths: \"f.b.d\" then the result would be: f { b { d : 10 x : 2 } c : 1 } In order to reset a field's value to the default, the field must be in the mask and set to the default value in the provided resource. Hence, in order to reset all fields of a resource, provide a default instance of the resource and set all fields in the mask, or do not provide a mask as described below. If a field mask is not present on update, the operation applies to all fields (as if a field mask of all fields has been specified). Note that in the presence of schema evolution, this may mean that fields the client does not know and has therefore not filled into the request will be reset to their default. If this is unwanted behavior, a specific service may require a client to always specify a field mask, producing an error if not. As with get operations, the location of the resource which describes the updated values in the request message depends on the operation kind. In any case, the effect of the field mask is required to be honored by the API. ## Considerations for HTTP REST The HTTP kind of an update operation which uses a field mask must be set to PATCH instead of PUT in order to satisfy HTTP semantics (PUT must only be used for full updates). # JSON Encoding of Field Masks In JSON, a field mask is encoded as a single string where paths are separated by a comma. Fields name in each path are converted to/from lower-camel naming conventions. As an example, consider the following message declarations: message Profile { User user = 1; Photo photo = 2; } message User { string display_name = 1; string address = 2; } In proto a field mask for `Profile` may look as such: mask { paths: \"user.display_name\" paths: \"photo\" } In JSON, the same mask is represented as below: { mask: \"user.displayName,photo\" } # Field Masks and Oneof Fields Field masks treat fields in oneofs just as regular fields. Consider the following message: message SampleMessage { oneof test_oneof { string name = 4; SubMessage sub_message = 9; } } The field mask can be: mask { paths: \"name\" } Or: mask { paths: \"sub_message\" } Note that oneof type names (\"test_oneof\" in this case) cannot be used in paths. +type ProtobufFieldMask struct { + + // The set of field mask paths. + Paths []string `json:"paths,omitempty"` +} diff --git a/examples/integration/integration_test.go b/examples/integration/integration_test.go index b488be6ad2f..96b36d04b58 100644 --- a/examples/integration/integration_test.go +++ b/examples/integration/integration_test.go @@ -22,6 +22,7 @@ import ( "github.com/grpc-ecosystem/grpc-gateway/examples/proto/pathenum" "github.com/grpc-ecosystem/grpc-gateway/examples/proto/sub" "github.com/grpc-ecosystem/grpc-gateway/runtime" + "google.golang.org/genproto/protobuf/field_mask" "google.golang.org/grpc/codes" ) @@ -555,6 +556,193 @@ func testABELookup(t *testing.T, port int) { } } +// TestABEPatch demonstrates partially updating a resource. +// First, we'll create an ABE resource with known values for string_value and int32_value +// Then, issue a PATCH request updating only the string_value +// Then, GET the resource and verify that string_value is changed, but int32_value isn't +func TestABEPatch(t *testing.T) { + port := 8080 + + // create a record with a known string_value and int32_value + uuid := postABE(t, port, gw.ABitOfEverything{StringValue: "strprefix/bar", Int32Value: 32}) + + // issue PATCH request, only updating string_value + req, err := http.NewRequest( + http.MethodPatch, + fmt.Sprintf("http://localhost:%d/v2/example/a_bit_of_everything/%s", port, uuid), + strings.NewReader(`{"string_value": "strprefix/foo"}`), + ) + if err != nil { + t.Fatalf("http.NewRequest(PATCH) failed with %v; want success", err) + } + patchResp, err := http.DefaultClient.Do(req) + if err != nil { + t.Fatalf("failed to issue PATCH request: %v", err) + } + if got, want := patchResp.StatusCode, http.StatusOK; got != want { + if body, err := ioutil.ReadAll(patchResp.Body); err != nil { + t.Errorf("patchResp body couldn't be read: %v", err) + } else { + t.Errorf("patchResp.StatusCode= %d; want %d resp: %v", got, want, string(body)) + } + } + + // issue GET request, verifying that string_value is changed and int32_value is not + getRespBody := getABE(t, port, uuid) + if got, want := getRespBody.StringValue, "strprefix/foo"; got != want { + t.Errorf("string_value= %q; want %q", got, want) + } + if got, want := getRespBody.Int32Value, int32(32); got != want { + t.Errorf("int_32_value= %d; want %d", got, want) + } +} + +// TestABEPatchBody demonstrates the ability to specify an update mask within the request body. +func TestABEPatchBody(t *testing.T) { + port := 8080 + + for _, tc := range []struct { + name string + originalValue gw.ABitOfEverything + input gw.UpdateV2Request + want gw.ABitOfEverything + }{ + { + name: "with fieldmask provided", + originalValue: gw.ABitOfEverything{ + StringValue: "rabbit", + SingleNested: &gw.ABitOfEverything_Nested{Name: "some value that will get overwritten", Amount: 345}, + }, + input: gw.UpdateV2Request{Abe: &gw.ABitOfEverything{ + StringValue: "some value that won't get updated because it's not in the field mask", + SingleNested: &gw.ABitOfEverything_Nested{Amount: 456}, + }, UpdateMask: &field_mask.FieldMask{Paths: []string{"single_nested"}}}, + want: gw.ABitOfEverything{StringValue: "rabbit", SingleNested: &gw.ABitOfEverything_Nested{Amount: 456}}, + }, + { + name: "with empty fieldmask", + originalValue: gw.ABitOfEverything{ + StringValue: "some value that will get overwritten", + SingleNested: &gw.ABitOfEverything_Nested{Name: "value that will get empty", Amount: 345}, + }, + input: gw.UpdateV2Request{Abe: &gw.ABitOfEverything{ + StringValue: "some updated value because the fieldMask is nil", + SingleNested: &gw.ABitOfEverything_Nested{Amount: 456}, + }, UpdateMask: &field_mask.FieldMask{}}, + want: gw.ABitOfEverything{ + StringValue: "some updated value because the fieldMask is nil", + SingleNested: &gw.ABitOfEverything_Nested{Amount: 456}, + }, + }, + { + name: "with nil fieldmask", + originalValue: gw.ABitOfEverything{ + StringValue: "some value that will get overwritten", + SingleNested: &gw.ABitOfEverything_Nested{Name: "value that will get empty", Amount: 123}, + }, + input: gw.UpdateV2Request{Abe: &gw.ABitOfEverything{ + StringValue: "some updated value because the fieldMask is nil", + SingleNested: &gw.ABitOfEverything_Nested{Amount: 657}, + }, UpdateMask: nil}, + want: gw.ABitOfEverything{ + StringValue: "some updated value because the fieldMask is nil", + SingleNested: &gw.ABitOfEverything_Nested{Amount: 657}, + }, + }, + } { + t.Run(tc.name, func(t *testing.T) { + originalABE := tc.originalValue + uuid := postABE(t, port, originalABE) + + patchBody := tc.input + patchReq, err := http.NewRequest( + http.MethodPatch, + fmt.Sprintf("http://localhost:%d/v2a/example/a_bit_of_everything/%s", port, uuid), + strings.NewReader(mustMarshal(t, patchBody)), + ) + if err != nil { + t.Fatalf("http.NewRequest(PATCH) failed with %v; want success", err) + } + patchResp, err := http.DefaultClient.Do(patchReq) + if err != nil { + t.Fatalf("failed to issue PATCH request: %v", err) + } + if got, want := patchResp.StatusCode, http.StatusOK; got != want { + if body, err := ioutil.ReadAll(patchResp.Body); err != nil { + t.Errorf("patchResp body couldn't be read: %v", err) + } else { + t.Errorf("patchResp.StatusCode= %d; want %d resp: %v", got, want, string(body)) + } + } + + want, got := tc.want, getABE(t, port, uuid) + got.Uuid = "" // empty out uuid so we don't need to worry about it in comparisons + if !reflect.DeepEqual(want, got) { + t.Errorf("want %v\ngot %v", want, got) + } + }) + } +} + +// mustMarshal marshals the given object into a json string, calling t.Fatal if an error occurs. Useful in testing to +// inline marshalling whenever you don't expect the marshalling to return an error +func mustMarshal(t *testing.T, i interface{}) string { + b, err := json.Marshal(i) + if err != nil { + t.Fatalf("failed to marshal %#v: %v", i, err) + } + + return string(b) +} + +// postABE conveniently creates a new ABE record for ease in testing +func postABE(t *testing.T, port int, abe gw.ABitOfEverything) (uuid string) { + url := fmt.Sprintf("http://localhost:%d/v1/example/a_bit_of_everything", port) + postResp, err := http.Post(url, "application/json", strings.NewReader(mustMarshal(t, abe))) + if err != nil { + t.Fatalf("http.Post(%q) failed with %v; want success", url, err) + return + } + body, err := ioutil.ReadAll(postResp.Body) + if err != nil { + t.Fatalf("postResp body couldn't be read: %v", err) + } + var f struct { + UUID string `json:"uuid"` + } + if err := json.Unmarshal(body, &f); err != nil { + t.Fatalf("postResp body couldn't be unmarshalled: %v. body: %s", err, string(body)) + } + if f.UUID == "" { + t.Fatalf("want uuid from postResp, but got none. body: %s", string(body)) + } + return f.UUID +} + +// getABE conveniently fetches an ABE record for ease in testing +func getABE(t *testing.T, port int, uuid string) gw.ABitOfEverything { + gURL := fmt.Sprintf("http://localhost:%d/v1/example/a_bit_of_everything/%s", port, uuid) + getResp, err := http.Get(gURL) + if err != nil { + t.Fatalf("http.Get(%s) failed with %v; want success", gURL, err) + } + defer getResp.Body.Close() + + if got, want := getResp.StatusCode, http.StatusOK; got != want { + t.Fatalf("getResp.StatusCode= %d, want %d. resp: %v", got, want, getResp) + } + var getRespBody gw.ABitOfEverything + body, err := ioutil.ReadAll(getResp.Body) + if err != nil { + t.Fatalf("getResp body couldn't be read: %v", err) + } + if err := json.Unmarshal(body, &getRespBody); err != nil { + t.Fatalf("getResp body couldn't be unmarshalled: %v body: %s", err, string(body)) + } + + return getRespBody +} + func testABELookupNotFound(t *testing.T, port int) { url := fmt.Sprintf("http://localhost:%d/v1/example/a_bit_of_everything", port) uuid := "not_exist" diff --git a/examples/proto/examplepb/a_bit_of_everything.pb.go b/examples/proto/examplepb/a_bit_of_everything.pb.go index 4ba9b36f349..4f29c98d99c 100644 --- a/examples/proto/examplepb/a_bit_of_everything.pb.go +++ b/examples/proto/examplepb/a_bit_of_everything.pb.go @@ -14,6 +14,7 @@ import sub "github.com/grpc-ecosystem/grpc-gateway/examples/proto/sub" import sub2 "github.com/grpc-ecosystem/grpc-gateway/examples/proto/sub2" import _ "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger/options" import _ "google.golang.org/genproto/googleapis/api/annotations" +import field_mask "google.golang.org/genproto/protobuf/field_mask" import ( context "golang.org/x/net/context" @@ -54,7 +55,7 @@ func (x NumericEnum) String() string { return proto.EnumName(NumericEnum_name, int32(x)) } func (NumericEnum) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_a_bit_of_everything_dc9cebfa7968115c, []int{0} + return fileDescriptor_a_bit_of_everything_7494e8194e1b43f3, []int{0} } // DeepEnum is one or zero. @@ -80,7 +81,7 @@ func (x ABitOfEverything_Nested_DeepEnum) String() string { return proto.EnumName(ABitOfEverything_Nested_DeepEnum_name, int32(x)) } func (ABitOfEverything_Nested_DeepEnum) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_a_bit_of_everything_dc9cebfa7968115c, []int{0, 0, 0} + return fileDescriptor_a_bit_of_everything_7494e8194e1b43f3, []int{0, 0, 0} } // Intentionaly complicated message type to cover many features of Protobuf. @@ -128,7 +129,7 @@ func (m *ABitOfEverything) Reset() { *m = ABitOfEverything{} } func (m *ABitOfEverything) String() string { return proto.CompactTextString(m) } func (*ABitOfEverything) ProtoMessage() {} func (*ABitOfEverything) Descriptor() ([]byte, []int) { - return fileDescriptor_a_bit_of_everything_dc9cebfa7968115c, []int{0} + return fileDescriptor_a_bit_of_everything_7494e8194e1b43f3, []int{0} } func (m *ABitOfEverything) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ABitOfEverything.Unmarshal(m, b) @@ -466,7 +467,7 @@ func (m *ABitOfEverything_Nested) Reset() { *m = ABitOfEverything_Nested func (m *ABitOfEverything_Nested) String() string { return proto.CompactTextString(m) } func (*ABitOfEverything_Nested) ProtoMessage() {} func (*ABitOfEverything_Nested) Descriptor() ([]byte, []int) { - return fileDescriptor_a_bit_of_everything_dc9cebfa7968115c, []int{0, 0} + return fileDescriptor_a_bit_of_everything_7494e8194e1b43f3, []int{0, 0} } func (m *ABitOfEverything_Nested) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ABitOfEverything_Nested.Unmarshal(m, b) @@ -535,7 +536,7 @@ func (m *ABitOfEverythingRepeated) Reset() { *m = ABitOfEverythingRepeat func (m *ABitOfEverythingRepeated) String() string { return proto.CompactTextString(m) } func (*ABitOfEverythingRepeated) ProtoMessage() {} func (*ABitOfEverythingRepeated) Descriptor() ([]byte, []int) { - return fileDescriptor_a_bit_of_everything_dc9cebfa7968115c, []int{1} + return fileDescriptor_a_bit_of_everything_7494e8194e1b43f3, []int{1} } func (m *ABitOfEverythingRepeated) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ABitOfEverythingRepeated.Unmarshal(m, b) @@ -678,7 +679,7 @@ func (m *Body) Reset() { *m = Body{} } func (m *Body) String() string { return proto.CompactTextString(m) } func (*Body) ProtoMessage() {} func (*Body) Descriptor() ([]byte, []int) { - return fileDescriptor_a_bit_of_everything_dc9cebfa7968115c, []int{2} + return fileDescriptor_a_bit_of_everything_7494e8194e1b43f3, []int{2} } func (m *Body) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Body.Unmarshal(m, b) @@ -717,7 +718,7 @@ func (m *MessageWithBody) Reset() { *m = MessageWithBody{} } func (m *MessageWithBody) String() string { return proto.CompactTextString(m) } func (*MessageWithBody) ProtoMessage() {} func (*MessageWithBody) Descriptor() ([]byte, []int) { - return fileDescriptor_a_bit_of_everything_dc9cebfa7968115c, []int{3} + return fileDescriptor_a_bit_of_everything_7494e8194e1b43f3, []int{3} } func (m *MessageWithBody) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_MessageWithBody.Unmarshal(m, b) @@ -751,6 +752,53 @@ func (m *MessageWithBody) GetData() *Body { return nil } +// UpdateV2Request request for update includes the message and the update mask +type UpdateV2Request struct { + Abe *ABitOfEverything `protobuf:"bytes,1,opt,name=abe,proto3" json:"abe,omitempty"` + UpdateMask *field_mask.FieldMask `protobuf:"bytes,2,opt,name=update_mask,json=updateMask,proto3" json:"update_mask,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UpdateV2Request) Reset() { *m = UpdateV2Request{} } +func (m *UpdateV2Request) String() string { return proto.CompactTextString(m) } +func (*UpdateV2Request) ProtoMessage() {} +func (*UpdateV2Request) Descriptor() ([]byte, []int) { + return fileDescriptor_a_bit_of_everything_7494e8194e1b43f3, []int{4} +} +func (m *UpdateV2Request) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UpdateV2Request.Unmarshal(m, b) +} +func (m *UpdateV2Request) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UpdateV2Request.Marshal(b, m, deterministic) +} +func (dst *UpdateV2Request) XXX_Merge(src proto.Message) { + xxx_messageInfo_UpdateV2Request.Merge(dst, src) +} +func (m *UpdateV2Request) XXX_Size() int { + return xxx_messageInfo_UpdateV2Request.Size(m) +} +func (m *UpdateV2Request) XXX_DiscardUnknown() { + xxx_messageInfo_UpdateV2Request.DiscardUnknown(m) +} + +var xxx_messageInfo_UpdateV2Request proto.InternalMessageInfo + +func (m *UpdateV2Request) GetAbe() *ABitOfEverything { + if m != nil { + return m.Abe + } + return nil +} + +func (m *UpdateV2Request) GetUpdateMask() *field_mask.FieldMask { + if m != nil { + return m.UpdateMask + } + return nil +} + func init() { proto.RegisterType((*ABitOfEverything)(nil), "grpc.gateway.examples.examplepb.ABitOfEverything") proto.RegisterMapType((map[string]NumericEnum)(nil), "grpc.gateway.examples.examplepb.ABitOfEverything.MapValueEntry") @@ -760,6 +808,7 @@ func init() { proto.RegisterType((*ABitOfEverythingRepeated)(nil), "grpc.gateway.examples.examplepb.ABitOfEverythingRepeated") proto.RegisterType((*Body)(nil), "grpc.gateway.examples.examplepb.Body") proto.RegisterType((*MessageWithBody)(nil), "grpc.gateway.examples.examplepb.MessageWithBody") + proto.RegisterType((*UpdateV2Request)(nil), "grpc.gateway.examples.examplepb.UpdateV2Request") proto.RegisterEnum("grpc.gateway.examples.examplepb.NumericEnum", NumericEnum_name, NumericEnum_value) proto.RegisterEnum("grpc.gateway.examples.examplepb.ABitOfEverything_Nested_DeepEnum", ABitOfEverything_Nested_DeepEnum_name, ABitOfEverything_Nested_DeepEnum_value) } @@ -783,6 +832,8 @@ type ABitOfEverythingServiceClient interface { CreateBody(ctx context.Context, in *ABitOfEverything, opts ...grpc.CallOption) (*ABitOfEverything, error) Lookup(ctx context.Context, in *sub2.IdMessage, opts ...grpc.CallOption) (*ABitOfEverything, error) Update(ctx context.Context, in *ABitOfEverything, opts ...grpc.CallOption) (*empty.Empty, error) + UpdateV2(ctx context.Context, in *UpdateV2Request, opts ...grpc.CallOption) (*empty.Empty, error) + PatchWithFieldMaskInBody(ctx context.Context, in *UpdateV2Request, opts ...grpc.CallOption) (*empty.Empty, error) Delete(ctx context.Context, in *sub2.IdMessage, opts ...grpc.CallOption) (*empty.Empty, error) GetQuery(ctx context.Context, in *ABitOfEverything, opts ...grpc.CallOption) (*empty.Empty, error) GetRepeatedQuery(ctx context.Context, in *ABitOfEverythingRepeated, opts ...grpc.CallOption) (*ABitOfEverythingRepeated, error) @@ -846,6 +897,24 @@ func (c *aBitOfEverythingServiceClient) Update(ctx context.Context, in *ABitOfEv return out, nil } +func (c *aBitOfEverythingServiceClient) UpdateV2(ctx context.Context, in *UpdateV2Request, opts ...grpc.CallOption) (*empty.Empty, error) { + out := new(empty.Empty) + err := c.cc.Invoke(ctx, "/grpc.gateway.examples.examplepb.ABitOfEverythingService/UpdateV2", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *aBitOfEverythingServiceClient) PatchWithFieldMaskInBody(ctx context.Context, in *UpdateV2Request, opts ...grpc.CallOption) (*empty.Empty, error) { + out := new(empty.Empty) + err := c.cc.Invoke(ctx, "/grpc.gateway.examples.examplepb.ABitOfEverythingService/PatchWithFieldMaskInBody", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *aBitOfEverythingServiceClient) Delete(ctx context.Context, in *sub2.IdMessage, opts ...grpc.CallOption) (*empty.Empty, error) { out := new(empty.Empty) err := c.cc.Invoke(ctx, "/grpc.gateway.examples.examplepb.ABitOfEverythingService/Delete", in, out, opts...) @@ -945,6 +1014,8 @@ type ABitOfEverythingServiceServer interface { CreateBody(context.Context, *ABitOfEverything) (*ABitOfEverything, error) Lookup(context.Context, *sub2.IdMessage) (*ABitOfEverything, error) Update(context.Context, *ABitOfEverything) (*empty.Empty, error) + UpdateV2(context.Context, *UpdateV2Request) (*empty.Empty, error) + PatchWithFieldMaskInBody(context.Context, *UpdateV2Request) (*empty.Empty, error) Delete(context.Context, *sub2.IdMessage) (*empty.Empty, error) GetQuery(context.Context, *ABitOfEverything) (*empty.Empty, error) GetRepeatedQuery(context.Context, *ABitOfEverythingRepeated) (*ABitOfEverythingRepeated, error) @@ -1040,6 +1111,42 @@ func _ABitOfEverythingService_Update_Handler(srv interface{}, ctx context.Contex return interceptor(ctx, in, info, handler) } +func _ABitOfEverythingService_UpdateV2_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateV2Request) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ABitOfEverythingServiceServer).UpdateV2(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.gateway.examples.examplepb.ABitOfEverythingService/UpdateV2", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ABitOfEverythingServiceServer).UpdateV2(ctx, req.(*UpdateV2Request)) + } + return interceptor(ctx, in, info, handler) +} + +func _ABitOfEverythingService_PatchWithFieldMaskInBody_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateV2Request) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ABitOfEverythingServiceServer).PatchWithFieldMaskInBody(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.gateway.examples.examplepb.ABitOfEverythingService/PatchWithFieldMaskInBody", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ABitOfEverythingServiceServer).PatchWithFieldMaskInBody(ctx, req.(*UpdateV2Request)) + } + return interceptor(ctx, in, info, handler) +} + func _ABitOfEverythingService_Delete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(sub2.IdMessage) if err := dec(in); err != nil { @@ -1240,6 +1347,14 @@ var _ABitOfEverythingService_serviceDesc = grpc.ServiceDesc{ MethodName: "Update", Handler: _ABitOfEverythingService_Update_Handler, }, + { + MethodName: "UpdateV2", + Handler: _ABitOfEverythingService_UpdateV2_Handler, + }, + { + MethodName: "PatchWithFieldMaskInBody", + Handler: _ABitOfEverythingService_PatchWithFieldMaskInBody_Handler, + }, { MethodName: "Delete", Handler: _ABitOfEverythingService_Delete_Handler, @@ -1414,181 +1529,191 @@ var _AnotherServiceWithNoBindings_serviceDesc = grpc.ServiceDesc{ } func init() { - proto.RegisterFile("examples/proto/examplepb/a_bit_of_everything.proto", fileDescriptor_a_bit_of_everything_dc9cebfa7968115c) -} - -var fileDescriptor_a_bit_of_everything_dc9cebfa7968115c = []byte{ - // 2750 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x19, 0xcd, 0x73, 0x1b, 0x57, - 0xdd, 0xab, 0x95, 0x65, 0xfb, 0xe7, 0x2f, 0xf9, 0x39, 0x71, 0x6c, 0xc5, 0xad, 0x5f, 0xd4, 0x94, - 0x6e, 0xdd, 0x6a, 0x37, 0x51, 0x4c, 0x49, 0xdc, 0x69, 0x83, 0xfc, 0x91, 0xc4, 0x4d, 0xea, 0x38, - 0x9b, 0xb4, 0x74, 0x42, 0x5a, 0xcf, 0x4a, 0x7a, 0x96, 0xb6, 0xd1, 0xee, 0x5b, 0x76, 0xdf, 0x3a, - 0x16, 0x46, 0x50, 0x60, 0x06, 0x06, 0x7a, 0x60, 0xc6, 0x70, 0xe2, 0xc0, 0x99, 0x03, 0x57, 0x4e, - 0x3d, 0x30, 0x1c, 0xca, 0x85, 0x1b, 0x30, 0xbd, 0x30, 0xc3, 0x05, 0x98, 0xe1, 0x2f, 0x80, 0xe1, - 0xc6, 0xec, 0xdb, 0x0f, 0xef, 0xae, 0xa4, 0x38, 0x72, 0x98, 0x5e, 0xec, 0x7d, 0xef, 0xfd, 0xbe, - 0xbf, 0xdf, 0x13, 0x94, 0xc9, 0x81, 0x66, 0x58, 0x2d, 0xe2, 0x28, 0x96, 0x4d, 0x19, 0x55, 0x82, - 0xa5, 0x55, 0x55, 0xb4, 0xdd, 0xaa, 0xce, 0x76, 0xe9, 0xde, 0x2e, 0xd9, 0x27, 0x76, 0x9b, 0x35, - 0x75, 0xb3, 0x21, 0x73, 0x18, 0xb4, 0xd4, 0xb0, 0xad, 0x9a, 0xdc, 0xd0, 0x18, 0x79, 0xa2, 0xb5, - 0xe5, 0x90, 0x80, 0x1c, 0xa1, 0x16, 0x16, 0x1b, 0x94, 0x36, 0x5a, 0x44, 0xd1, 0x2c, 0x5d, 0xd1, - 0x4c, 0x93, 0x32, 0x8d, 0xe9, 0xd4, 0x74, 0x7c, 0xf4, 0xc2, 0xf9, 0xe0, 0x94, 0xaf, 0xaa, 0xee, - 0x9e, 0x42, 0x0c, 0x8b, 0xb5, 0x83, 0xc3, 0x17, 0xd3, 0x87, 0x75, 0xd7, 0xe6, 0xd8, 0xc1, 0xf9, - 0x2b, 0x29, 0x79, 0x2d, 0x8d, 0x35, 0x89, 0xe9, 0x1a, 0xfc, 0x63, 0xd7, 0xfb, 0x0a, 0x00, 0x71, - 0x0a, 0xd0, 0x71, 0xab, 0x8a, 0x41, 0x1c, 0x47, 0x6b, 0x90, 0x00, 0xe2, 0x42, 0x37, 0x44, 0x39, - 0x05, 0xb2, 0x94, 0x96, 0x86, 0xe9, 0x06, 0x71, 0x98, 0x66, 0x58, 0x01, 0xc0, 0xeb, 0xfc, 0x5f, - 0xad, 0xd4, 0x20, 0x66, 0xc9, 0x79, 0xa2, 0x35, 0x1a, 0xc4, 0x56, 0xa8, 0xc5, 0xb5, 0xed, 0xd6, - 0xbc, 0xf8, 0x87, 0x59, 0xc8, 0x57, 0xd6, 0x74, 0x76, 0x77, 0x6f, 0x33, 0xb2, 0x29, 0xfa, 0x10, - 0x26, 0x1d, 0xdd, 0x6c, 0xb4, 0xc8, 0xae, 0x49, 0x1c, 0x46, 0xea, 0xf3, 0x0b, 0x58, 0x90, 0xc6, - 0xcb, 0x57, 0xe5, 0x13, 0xac, 0x2c, 0xa7, 0x29, 0xc9, 0xdb, 0x1c, 0x5f, 0x9d, 0xf0, 0xc9, 0xf9, - 0x2b, 0xd4, 0x84, 0xac, 0xeb, 0xea, 0xf5, 0x79, 0x01, 0x0b, 0xd2, 0xd8, 0xda, 0x83, 0xa3, 0xca, - 0xbd, 0x4f, 0x04, 0xe1, 0xa7, 0xc2, 0xed, 0x6f, 0x6a, 0xa5, 0xbd, 0x4a, 0xe9, 0xc6, 0xa5, 0xd2, - 0xb5, 0x0f, 0x0f, 0xaf, 0x76, 0x4a, 0xf1, 0xe5, 0xca, 0x20, 0xcb, 0xcb, 0xe5, 0x8e, 0xca, 0x39, - 0xa0, 0x1d, 0xc8, 0x05, 0x1a, 0x64, 0xb0, 0xf8, 0x5c, 0x1a, 0x04, 0x74, 0xd0, 0x12, 0x8c, 0xef, - 0xb5, 0xa8, 0xc6, 0x76, 0xf7, 0xb5, 0x96, 0x4b, 0xe6, 0x45, 0x2c, 0x48, 0x19, 0x15, 0xf8, 0xd6, - 0xfb, 0xde, 0x0e, 0xba, 0x00, 0x13, 0x75, 0xea, 0x56, 0x5b, 0x24, 0x80, 0xc8, 0x62, 0x41, 0x12, - 0xd4, 0x71, 0x7f, 0xcf, 0x07, 0x59, 0x82, 0x71, 0xdd, 0x64, 0x6f, 0xac, 0x04, 0x10, 0xc3, 0x58, - 0x90, 0x44, 0x15, 0xf8, 0x56, 0x44, 0xc3, 0x8d, 0x43, 0xe4, 0xb0, 0x20, 0x65, 0xd5, 0x71, 0x37, - 0x06, 0xe2, 0xd3, 0xb8, 0x52, 0x0e, 0x20, 0x46, 0xb0, 0x20, 0x0d, 0x73, 0x1a, 0x57, 0xca, 0x3e, - 0xc0, 0x4b, 0x30, 0xb9, 0xa7, 0x1f, 0x90, 0x7a, 0x44, 0x64, 0x14, 0x0b, 0x52, 0x4e, 0x9d, 0x08, - 0x36, 0x93, 0x40, 0x11, 0x9d, 0x31, 0x2c, 0x48, 0x23, 0x01, 0x50, 0x48, 0xe9, 0x05, 0x80, 0x2a, - 0xa5, 0xad, 0x00, 0x02, 0xb0, 0x20, 0x8d, 0xaa, 0x63, 0xde, 0x4e, 0x24, 0xac, 0xc3, 0x6c, 0xdd, - 0x6c, 0x04, 0x00, 0xe3, 0x9e, 0x57, 0xd5, 0x71, 0x7f, 0x2f, 0x12, 0xb6, 0xda, 0x66, 0xc4, 0x09, - 0x20, 0x5e, 0xc0, 0x82, 0x34, 0xa1, 0x02, 0xdf, 0x4a, 0x28, 0x1c, 0x89, 0x31, 0x89, 0x05, 0x69, - 0xd2, 0x57, 0x38, 0x94, 0xe2, 0x36, 0x80, 0x97, 0x4a, 0x01, 0xc0, 0x14, 0x16, 0xa4, 0xa9, 0xf2, - 0xeb, 0x27, 0xba, 0x73, 0xdb, 0x35, 0x88, 0xad, 0xd7, 0x36, 0x4d, 0xd7, 0x50, 0xc7, 0x3c, 0x7c, - 0x9f, 0xd8, 0x0e, 0x4c, 0x47, 0xc9, 0x19, 0x50, 0x7c, 0x91, 0x53, 0x94, 0xfa, 0x50, 0x0c, 0x73, - 0x5a, 0xde, 0xd1, 0x58, 0x93, 0x53, 0x9b, 0xb4, 0x82, 0x2f, 0x9f, 0xa2, 0x03, 0x73, 0x7e, 0x84, - 0xec, 0xa6, 0x09, 0x2f, 0x71, 0xc2, 0x6f, 0x9f, 0x44, 0xf8, 0x5d, 0x3f, 0xcb, 0x43, 0xfa, 0x41, - 0xdc, 0x45, 0xec, 0x66, 0xcd, 0xc4, 0xda, 0x67, 0xfa, 0x32, 0x4c, 0x39, 0x49, 0xff, 0x4d, 0x63, - 0x41, 0x9a, 0x56, 0x27, 0x9d, 0x84, 0x03, 0x23, 0xb0, 0x28, 0x16, 0xf2, 0x58, 0x90, 0xf2, 0x21, - 0x58, 0x2c, 0xea, 0x9c, 0xb8, 0x13, 0x66, 0xb0, 0x20, 0xcd, 0xa8, 0xe3, 0x4e, 0xcc, 0x09, 0x01, - 0x48, 0x44, 0x07, 0x61, 0x41, 0x42, 0x3e, 0x48, 0x48, 0xa5, 0x0c, 0x67, 0x6d, 0x62, 0x11, 0xcd, - 0x33, 0x45, 0x22, 0x2e, 0x66, 0xb1, 0x28, 0x8d, 0xa9, 0xb3, 0xe1, 0xe1, 0xfd, 0x58, 0x7c, 0x5c, - 0x83, 0x71, 0x6a, 0x12, 0xaf, 0xae, 0x7b, 0x65, 0x77, 0xfe, 0x0c, 0xaf, 0x36, 0x73, 0xb2, 0x5f, - 0xe9, 0xe4, 0xb0, 0xd2, 0xc9, 0x9b, 0xde, 0xe9, 0xad, 0x21, 0x15, 0x38, 0x30, 0x5f, 0xa1, 0x97, - 0x60, 0xc2, 0x47, 0xf5, 0x79, 0xcd, 0x9f, 0xf5, 0xa2, 0xef, 0xd6, 0x90, 0xea, 0x13, 0xf4, 0x99, - 0xa0, 0x47, 0x30, 0x66, 0x68, 0x56, 0x20, 0xc7, 0x1c, 0xaf, 0x04, 0xd7, 0x07, 0xaf, 0x04, 0xef, - 0x6a, 0x16, 0x17, 0x77, 0xd3, 0x64, 0x76, 0x5b, 0x1d, 0x35, 0x82, 0x25, 0x3a, 0x80, 0x59, 0x43, - 0xb3, 0xac, 0xb4, 0xbe, 0xe7, 0x38, 0x9f, 0x5b, 0xa7, 0xe2, 0x63, 0x25, 0xec, 0xe3, 0x33, 0x9c, - 0x31, 0xd2, 0xfb, 0x31, 0xce, 0x41, 0xec, 0xf9, 0x9c, 0xe7, 0x9f, 0x8f, 0xb3, 0x1f, 0x79, 0xdd, - 0x9c, 0x63, 0xfb, 0x68, 0x15, 0xe6, 0x4d, 0x6a, 0xae, 0x53, 0x73, 0x9f, 0x98, 0x5e, 0x3b, 0xd1, - 0x5a, 0xdb, 0x9a, 0xe1, 0x97, 0xb7, 0xf9, 0x02, 0x2f, 0x00, 0x7d, 0xcf, 0xd1, 0x3a, 0x4c, 0x47, - 0x3d, 0x2b, 0x90, 0xf8, 0x3c, 0xf7, 0x78, 0xa1, 0xcb, 0xe3, 0x0f, 0x42, 0x38, 0x75, 0x2a, 0x42, - 0xf1, 0x89, 0x3c, 0x82, 0x28, 0x92, 0xe2, 0xc9, 0xb6, 0x88, 0xc5, 0x81, 0xeb, 0xc2, 0x4c, 0x48, - 0x28, 0x4a, 0xac, 0xc2, 0xaf, 0x05, 0xc8, 0x05, 0xcd, 0x0a, 0x41, 0xd6, 0xd4, 0x0c, 0xe2, 0x37, - 0x2b, 0x95, 0x7f, 0xa3, 0x39, 0xc8, 0x69, 0x06, 0x75, 0x4d, 0x36, 0x9f, 0xe1, 0x85, 0x2a, 0x58, - 0xa1, 0x7b, 0x90, 0xa1, 0x8f, 0x79, 0x4f, 0x98, 0x2a, 0x57, 0x4e, 0xdb, 0x6a, 0xe4, 0x0d, 0x42, - 0x2c, 0x2e, 0x58, 0x86, 0x3e, 0x2e, 0x2e, 0xc1, 0x68, 0xb8, 0x46, 0x63, 0x30, 0x7c, 0xa3, 0x72, - 0xe7, 0xfe, 0x66, 0x7e, 0x08, 0x8d, 0x42, 0xf6, 0x81, 0xfa, 0xde, 0x66, 0x5e, 0x28, 0xe8, 0x30, - 0x99, 0x08, 0x4c, 0x94, 0x07, 0xf1, 0x31, 0x69, 0x07, 0xf2, 0x7a, 0x9f, 0x68, 0x0d, 0x86, 0x7d, - 0xeb, 0x64, 0x4e, 0x51, 0x35, 0x7d, 0xd4, 0xd5, 0xcc, 0x55, 0xa1, 0xb0, 0x01, 0x73, 0xbd, 0x63, - 0xb3, 0x07, 0xcf, 0x33, 0x71, 0x9e, 0x63, 0x71, 0x2a, 0xdf, 0x0d, 0xa9, 0xa4, 0xe3, 0xac, 0x07, - 0x95, 0xed, 0x38, 0x95, 0xe7, 0x69, 0xdf, 0xc7, 0xfc, 0x57, 0x3f, 0x17, 0x8e, 0x2a, 0xbf, 0x17, - 0xa0, 0xb1, 0x3c, 0x5b, 0xc1, 0x55, 0x9d, 0x61, 0xba, 0x87, 0x8f, 0xc7, 0xc9, 0xf2, 0xd6, 0x96, - 0xc9, 0xc2, 0x90, 0x6d, 0xe3, 0x1a, 0x35, 0xac, 0x96, 0x5e, 0xf3, 0x82, 0x03, 0x07, 0x63, 0x18, - 0x66, 0x6d, 0x8b, 0x60, 0x46, 0x71, 0x8d, 0xee, 0x13, 0x1b, 0x1b, 0x9a, 0xd9, 0xc6, 0x7b, 0x44, - 0x63, 0xae, 0x4d, 0x1c, 0x8f, 0xd6, 0x4e, 0x18, 0xbb, 0x7f, 0x12, 0xf8, 0x0c, 0xb2, 0xfc, 0x3e, - 0x5c, 0xbc, 0xa1, 0x9b, 0x75, 0x4c, 0x5d, 0x86, 0x0d, 0x6a, 0x13, 0xac, 0x55, 0xbd, 0xcf, 0xae, - 0xa1, 0x4b, 0x6e, 0x32, 0x66, 0x39, 0xab, 0x8a, 0xd2, 0xd0, 0x59, 0xd3, 0xad, 0xca, 0x35, 0x6a, - 0x28, 0x9e, 0xba, 0x25, 0x52, 0xa3, 0x4e, 0xdb, 0x61, 0x24, 0x58, 0x06, 0xda, 0xaf, 0x4d, 0x86, - 0x45, 0x93, 0xab, 0x56, 0xfc, 0xc5, 0x28, 0xcc, 0xa7, 0x69, 0xaa, 0x41, 0x60, 0xa3, 0x6b, 0xb0, - 0xc0, 0xdb, 0x52, 0x94, 0x32, 0xf1, 0x19, 0x46, 0xc0, 0xa2, 0x94, 0x51, 0xe7, 0x3c, 0x80, 0x10, - 0xe1, 0xc6, 0xf1, 0x3c, 0xf3, 0x26, 0x14, 0x92, 0xa8, 0x89, 0xe9, 0xc6, 0x1b, 0xab, 0x04, 0xf5, - 0x5c, 0x1c, 0x77, 0x23, 0x36, 0xe9, 0x74, 0xf1, 0x8d, 0x37, 0x0f, 0x11, 0x8b, 0x92, 0x98, 0xe4, - 0xbb, 0x75, 0xdc, 0x47, 0xba, 0xf8, 0x26, 0x26, 0xa2, 0x2c, 0x16, 0xa5, 0x6c, 0x92, 0xef, 0x7b, - 0xb1, 0x26, 0xd4, 0x8b, 0x6f, 0xd4, 0xd7, 0x86, 0xb1, 0x28, 0x0d, 0x77, 0xf1, 0x0d, 0x5b, 0xdc, - 0x5b, 0x70, 0x3e, 0x65, 0xaa, 0x44, 0xe7, 0xcc, 0x61, 0x51, 0xca, 0xa9, 0xf3, 0x09, 0x63, 0xc5, - 0x9b, 0x68, 0x6f, 0xf4, 0xd8, 0x9c, 0x26, 0x4a, 0x23, 0x3d, 0xd0, 0x43, 0xee, 0x5f, 0x83, 0xf9, - 0x24, 0x7a, 0x6c, 0xf2, 0x1a, 0xc5, 0xa2, 0x34, 0xaa, 0x9e, 0x8d, 0xe3, 0xae, 0x45, 0x53, 0x58, - 0x97, 0xb9, 0x12, 0xbd, 0x68, 0x8c, 0xf7, 0xde, 0x84, 0xb9, 0x92, 0xfd, 0x37, 0x65, 0xae, 0xf8, - 0xb4, 0x06, 0x58, 0x94, 0x26, 0x92, 0xe6, 0x5a, 0x3b, 0x9e, 0xdc, 0x7a, 0xba, 0x29, 0x52, 0x77, - 0x1c, 0x8b, 0xd2, 0x64, 0xb7, 0x9b, 0x42, 0x6d, 0x49, 0x5a, 0xdb, 0x58, 0x25, 0x9f, 0x38, 0x45, - 0x25, 0x4f, 0xd8, 0xe6, 0x78, 0x4c, 0xba, 0x0e, 0x8b, 0x29, 0xdb, 0x24, 0x9d, 0x32, 0x89, 0x45, - 0x69, 0x5a, 0x5d, 0x48, 0x58, 0x27, 0x31, 0x40, 0xf5, 0x21, 0x10, 0x05, 0xc5, 0x14, 0x16, 0xa5, - 0x7c, 0x2f, 0x02, 0x7d, 0x83, 0x39, 0x31, 0x68, 0x4d, 0x63, 0x51, 0x9a, 0x49, 0x79, 0x27, 0x66, - 0xa5, 0x9e, 0xc8, 0xb1, 0x51, 0x4e, 0x94, 0x50, 0x37, 0x72, 0xc0, 0xb9, 0x58, 0x80, 0xec, 0x1a, - 0xad, 0xb7, 0x7b, 0xb5, 0xb1, 0xe2, 0x23, 0x98, 0x0e, 0xa6, 0xce, 0x6f, 0xe8, 0xac, 0xc9, 0xc1, - 0xa6, 0x20, 0x13, 0x5e, 0xcc, 0xd4, 0x8c, 0xee, 0x15, 0x8e, 0x6c, 0x5d, 0x63, 0x5a, 0x50, 0x7f, - 0x5f, 0x3e, 0xd1, 0x1b, 0x1e, 0x11, 0x95, 0xa3, 0x2c, 0x63, 0x18, 0x8f, 0xf9, 0xc6, 0xeb, 0x58, - 0x0f, 0x37, 0xd5, 0xbb, 0xf9, 0x21, 0x34, 0x02, 0xe2, 0xdd, 0xed, 0xcd, 0xbc, 0x50, 0xfe, 0xcf, - 0x02, 0x9c, 0x4b, 0x97, 0xac, 0xfb, 0xc4, 0xde, 0xd7, 0x6b, 0x04, 0x7d, 0x21, 0x42, 0x6e, 0xdd, - 0xf6, 0xd4, 0x41, 0x97, 0x07, 0xae, 0xfa, 0x85, 0xc1, 0x51, 0x8a, 0xff, 0xcc, 0xfc, 0xe0, 0xcf, - 0xff, 0xf8, 0x79, 0xe6, 0x6f, 0x99, 0xe2, 0x5f, 0x33, 0xca, 0xfe, 0xe5, 0xf0, 0xd5, 0xa1, 0xd7, - 0x9b, 0x83, 0x72, 0x18, 0x2b, 0x9f, 0x1d, 0xe5, 0x30, 0x5e, 0x11, 0x3b, 0xca, 0x61, 0xcc, 0x3b, - 0x1d, 0xc5, 0x21, 0x96, 0x66, 0x6b, 0x8c, 0xda, 0xca, 0xa1, 0x9b, 0x38, 0x38, 0x8c, 0x45, 0x40, - 0x47, 0x39, 0x4c, 0x04, 0x54, 0xb8, 0x8e, 0x9d, 0x1f, 0xd7, 0x81, 0x8e, 0x72, 0x18, 0xcf, 0xed, - 0xb7, 0x1c, 0x66, 0x5b, 0x36, 0xd9, 0xd3, 0x0f, 0x94, 0xe5, 0x8e, 0xcf, 0x24, 0x86, 0xe6, 0xa4, - 0xe9, 0x38, 0x69, 0x46, 0x4e, 0x0a, 0x21, 0x29, 0x64, 0xbf, 0x21, 0xae, 0xa3, 0x1c, 0x1e, 0xe7, - 0x6a, 0x47, 0x39, 0x4c, 0x5d, 0x7a, 0x3c, 0xcc, 0x9e, 0xb7, 0xa1, 0x0e, 0xfa, 0x95, 0x00, 0xe0, - 0x3b, 0x96, 0x07, 0xdc, 0x97, 0xe3, 0xdc, 0x65, 0xee, 0xdb, 0x8b, 0xc5, 0xa5, 0x13, 0x3c, 0xbb, - 0x2a, 0x2c, 0xa3, 0xef, 0x40, 0xee, 0x0e, 0xa5, 0x8f, 0x5d, 0x0b, 0x4d, 0xcb, 0x8e, 0x5b, 0x2d, - 0xcb, 0x5b, 0xf5, 0x20, 0x4b, 0x4e, 0xc3, 0x59, 0xe6, 0x9c, 0x25, 0xf4, 0x95, 0x13, 0x63, 0xca, - 0x1b, 0x16, 0x3a, 0xe8, 0x47, 0x02, 0xe4, 0xde, 0xb3, 0xea, 0xa7, 0x8c, 0xfb, 0x3e, 0x77, 0xa6, - 0xe2, 0x65, 0x2e, 0xc5, 0x6b, 0x85, 0x67, 0x94, 0xc2, 0x33, 0xc3, 0xcf, 0x04, 0xc8, 0x6d, 0x90, - 0x16, 0x61, 0xa4, 0xdb, 0x0e, 0xfd, 0xd8, 0x3c, 0x3a, 0xaa, 0xbc, 0x56, 0x7d, 0x15, 0xa6, 0x00, - 0x2a, 0x96, 0x7e, 0x9b, 0xb4, 0x2b, 0x2e, 0x6b, 0xa2, 0x21, 0x38, 0x07, 0xb9, 0xbb, 0xde, 0x67, - 0x19, 0x4d, 0x42, 0xd6, 0x26, 0x5a, 0x1d, 0x86, 0x9f, 0xd8, 0x3a, 0x23, 0xbe, 0x69, 0x96, 0x9f, - 0xd5, 0x34, 0x7f, 0x17, 0x60, 0xf4, 0x26, 0x61, 0xf7, 0x5c, 0x62, 0xb7, 0xff, 0x9f, 0xc6, 0xf9, - 0x54, 0x38, 0xaa, 0x3c, 0x28, 0x6e, 0xc3, 0x62, 0xaf, 0x31, 0x2d, 0x62, 0x38, 0xe0, 0x78, 0xf6, - 0x81, 0x50, 0x1d, 0xe2, 0xfa, 0xc9, 0xe8, 0xf5, 0x93, 0xf4, 0xfb, 0x96, 0xc7, 0x20, 0xd4, 0xf2, - 0xd3, 0x61, 0xc8, 0xdf, 0x24, 0x2c, 0xac, 0xe5, 0x3e, 0xf3, 0x6b, 0x03, 0x6b, 0x1b, 0xe2, 0x17, - 0x4e, 0x8f, 0x5a, 0xfc, 0x24, 0xcb, 0x35, 0xf8, 0xaf, 0x88, 0xfe, 0x2d, 0x9e, 0xa0, 0x43, 0xd4, - 0x9c, 0x82, 0x52, 0xd0, 0x6b, 0xd0, 0xec, 0xa4, 0xcf, 0x52, 0x75, 0xb3, 0xef, 0xa4, 0xd8, 0x75, - 0xe6, 0x3e, 0xed, 0x30, 0x59, 0xcf, 0x9e, 0x32, 0xcb, 0xf5, 0x3e, 0xed, 0x8b, 0x9b, 0xa8, 0xc0, - 0xfd, 0x67, 0xad, 0x6e, 0xbc, 0xe3, 0x59, 0xaa, 0xa7, 0x22, 0x7d, 0x19, 0x76, 0x17, 0xd8, 0x3e, - 0x03, 0x4c, 0x9f, 0xe3, 0xbe, 0x7a, 0x3a, 0x4f, 0xe3, 0x9a, 0x68, 0x00, 0xe8, 0x73, 0x11, 0xb2, - 0x9b, 0xb5, 0x26, 0x45, 0xfd, 0x1e, 0xc6, 0x1c, 0xb7, 0x2a, 0xfb, 0xa3, 0x64, 0x58, 0x1c, 0x9e, - 0x19, 0xb2, 0xf8, 0xaf, 0xcc, 0x51, 0xe5, 0xfb, 0x19, 0x98, 0x20, 0xb5, 0x26, 0xc5, 0x8e, 0xdf, - 0xf8, 0x61, 0x94, 0xaf, 0x6c, 0xab, 0x86, 0x66, 0xee, 0xbb, 0x86, 0xa1, 0xd9, 0xed, 0x55, 0xbc, - 0x19, 0x6c, 0x15, 0xf2, 0x1b, 0xc4, 0xa9, 0xd9, 0x3a, 0x7f, 0xcd, 0xe6, 0xbb, 0xc5, 0x0d, 0x40, - 0xc9, 0xb4, 0xe5, 0xd2, 0x0e, 0x98, 0xac, 0xef, 0x5c, 0x07, 0xf1, 0xab, 0x97, 0xae, 0xa0, 0xab, - 0xf0, 0x86, 0x4a, 0x98, 0x6b, 0x9b, 0xa4, 0x8e, 0x9f, 0x34, 0x89, 0x89, 0x59, 0x93, 0x60, 0x9b, - 0x38, 0xd4, 0xb5, 0x6b, 0x04, 0xeb, 0x0e, 0x66, 0xc4, 0xb0, 0xa8, 0xad, 0xd9, 0x7a, 0xab, 0x8d, - 0x5d, 0x53, 0xdb, 0xd7, 0xf4, 0x96, 0x56, 0x6d, 0x11, 0xf9, 0x9d, 0x37, 0x41, 0x5c, 0xb9, 0xb4, - 0x82, 0x56, 0x60, 0xf9, 0x29, 0x04, 0xea, 0x94, 0x38, 0xd8, 0xa4, 0x0c, 0x93, 0x03, 0xdd, 0x61, - 0x32, 0xca, 0x41, 0xf6, 0x97, 0x19, 0x41, 0xe4, 0x49, 0xf6, 0xe1, 0xc9, 0x65, 0xc2, 0x33, 0x8c, - 0x72, 0xe8, 0x3b, 0xe6, 0xe1, 0x42, 0x31, 0xaf, 0xec, 0x97, 0x23, 0x78, 0xef, 0x6c, 0xd5, 0xbf, - 0xe4, 0x3e, 0x44, 0xa8, 0xeb, 0x08, 0xfd, 0x56, 0x80, 0x89, 0x0d, 0x42, 0x2c, 0xfe, 0x7e, 0xe8, - 0x6d, 0x7c, 0x39, 0x7d, 0xf7, 0x3a, 0xd7, 0xed, 0x5a, 0x71, 0xe5, 0xc4, 0x12, 0x9f, 0xf8, 0xbd, - 0x41, 0xf6, 0xc6, 0x53, 0xde, 0x85, 0x2a, 0x00, 0xdb, 0x74, 0x4d, 0x37, 0xeb, 0xba, 0xd9, 0x70, - 0xd0, 0x42, 0x57, 0x05, 0xdf, 0x08, 0x7e, 0x8a, 0xe9, 0x5b, 0xdc, 0x87, 0xd0, 0xfb, 0x30, 0xf2, - 0x40, 0x37, 0x08, 0x75, 0x19, 0xea, 0x03, 0xd4, 0x17, 0xf9, 0x3c, 0x17, 0xff, 0x2c, 0x9a, 0x8d, - 0xdb, 0x93, 0x05, 0xc4, 0x9a, 0x90, 0xdf, 0xb4, 0x6d, 0x6a, 0x7b, 0xb3, 0xf3, 0x06, 0x61, 0x9a, - 0xde, 0x72, 0x06, 0x66, 0x70, 0x91, 0x33, 0x78, 0x11, 0x2d, 0x26, 0x1c, 0xe6, 0x51, 0x7d, 0xa2, - 0xb3, 0x66, 0x3d, 0xa0, 0xfa, 0x63, 0x01, 0xd0, 0x4d, 0xc2, 0xd2, 0xb3, 0xfa, 0xa5, 0x13, 0xfd, - 0x91, 0xc2, 0xe8, 0x2b, 0xc6, 0x2b, 0x5c, 0x8c, 0x0b, 0xc5, 0x85, 0xb8, 0x18, 0x9e, 0x04, 0x55, - 0x5a, 0x6f, 0x2b, 0x87, 0xde, 0x44, 0xc0, 0x67, 0x7a, 0xf4, 0x43, 0x01, 0x66, 0x76, 0xa8, 0xc3, - 0x3c, 0x8a, 0x1c, 0x95, 0x0b, 0xf2, 0x6c, 0xd7, 0x82, 0xbe, 0xdc, 0x15, 0xce, 0xfd, 0xd5, 0xe2, - 0xc5, 0x38, 0x77, 0x8b, 0x3a, 0xcc, 0x93, 0x80, 0xbf, 0x08, 0xfb, 0x62, 0x84, 0x41, 0x51, 0xf8, - 0x9d, 0x70, 0x54, 0xf9, 0x4c, 0x40, 0x7b, 0x7d, 0xee, 0x0e, 0xb8, 0x1e, 0x2b, 0x12, 0xa5, 0x12, - 0x7e, 0xd2, 0xd4, 0x6b, 0x4d, 0xec, 0x34, 0xa9, 0xdb, 0xaa, 0xf3, 0xf4, 0xab, 0x12, 0xec, 0x3a, - 0xa4, 0x8e, 0x75, 0x13, 0x5b, 0x2d, 0xad, 0x46, 0x30, 0xdd, 0xe3, 0x89, 0x5a, 0xa7, 0x35, 0xd7, - 0x20, 0xa6, 0xff, 0x03, 0x19, 0xae, 0x51, 0xc3, 0x5b, 0x5c, 0x28, 0xdc, 0x83, 0xa5, 0x5e, 0x93, - 0x81, 0x97, 0x46, 0xe1, 0x6d, 0x65, 0xc0, 0x7a, 0x53, 0xfe, 0x18, 0xce, 0xd4, 0x34, 0x83, 0xb4, - 0xd6, 0x35, 0x87, 0x04, 0x34, 0xbc, 0xd1, 0x1a, 0xa9, 0x30, 0xec, 0x3f, 0x6b, 0x0f, 0x1a, 0x48, - 0x0b, 0xdc, 0x86, 0xb3, 0x68, 0x26, 0x11, 0x48, 0xde, 0x51, 0xf9, 0x23, 0x58, 0xac, 0x98, 0x94, - 0x35, 0x89, 0x1d, 0x70, 0xf2, 0x9c, 0x17, 0x4b, 0xaa, 0xb7, 0x13, 0x29, 0x36, 0x28, 0xe3, 0xa1, - 0xb5, 0xcf, 0x46, 0x8e, 0x2a, 0xbf, 0x19, 0x41, 0x7f, 0x11, 0x60, 0xb6, 0x82, 0xd7, 0xfc, 0x07, - 0xb5, 0x58, 0x09, 0xf8, 0x00, 0xce, 0x34, 0xd4, 0x9d, 0xf5, 0xd2, 0x4d, 0x5f, 0x75, 0x6c, 0xd9, - 0xf4, 0x63, 0x52, 0x63, 0x83, 0x9a, 0xac, 0x90, 0x37, 0xa9, 0x49, 0xbe, 0x1e, 0xa8, 0xe6, 0x41, - 0x2f, 0x7f, 0x04, 0x67, 0xd6, 0xee, 0x6f, 0xe0, 0x2b, 0xa5, 0xf5, 0x96, 0xe6, 0x3a, 0x04, 0xdf, - 0xd1, 0x6b, 0xc4, 0x74, 0x08, 0xba, 0x31, 0x18, 0x65, 0xa5, 0xda, 0xa2, 0x55, 0xc5, 0xd0, 0x1c, - 0x46, 0x6c, 0xe5, 0xce, 0xd6, 0xfa, 0xe6, 0xf6, 0xfd, 0x4d, 0x99, 0x1d, 0xb0, 0xb2, 0x78, 0x59, - 0xbe, 0xb4, 0x2c, 0x0a, 0x99, 0x6c, 0x39, 0xaf, 0x59, 0xfe, 0x33, 0xa0, 0x4e, 0x4d, 0xe5, 0x63, - 0x87, 0x9a, 0xe5, 0xb9, 0xf8, 0xce, 0x41, 0x69, 0x8f, 0xd2, 0x92, 0xa1, 0x1b, 0x64, 0xb5, 0x0b, - 0x72, 0xb5, 0x0f, 0xa4, 0xba, 0xe3, 0x75, 0x8c, 0x2b, 0x68, 0x0b, 0x6e, 0x76, 0x77, 0x0c, 0xd7, - 0x21, 0xf6, 0x71, 0xb7, 0x68, 0x6a, 0xfb, 0x04, 0x5b, 0xc4, 0x36, 0x74, 0xc7, 0xf1, 0x02, 0x93, - 0x51, 0xac, 0xd5, 0x6a, 0xc4, 0x71, 0x12, 0xdd, 0x45, 0x56, 0x9f, 0xa3, 0x07, 0x8d, 0xa8, 0xb7, - 0x40, 0x5c, 0xb9, 0x7c, 0x15, 0x55, 0x60, 0x72, 0xeb, 0x15, 0x03, 0x6b, 0x98, 0x11, 0xcd, 0xa2, - 0x4c, 0x46, 0x97, 0x40, 0x2e, 0x0c, 0xf4, 0x08, 0xf3, 0xf0, 0x27, 0x19, 0x98, 0x86, 0xb1, 0x35, - 0xcd, 0xd1, 0x6b, 0x7c, 0xfe, 0xcf, 0x8c, 0x0a, 0xf0, 0x42, 0xe2, 0x46, 0x30, 0x3d, 0x9a, 0x29, - 0x8c, 0x7d, 0x50, 0xaa, 0xec, 0x6c, 0x95, 0x6e, 0x93, 0x36, 0xce, 0xc0, 0x17, 0x42, 0x74, 0x43, - 0xf8, 0xa3, 0x30, 0x2a, 0x4a, 0xd9, 0xf2, 0x4b, 0xa1, 0x0f, 0x63, 0x0e, 0x57, 0xa8, 0xe6, 0xb2, - 0xa6, 0xe2, 0xfd, 0xa1, 0xb6, 0xfe, 0x6d, 0xb2, 0xba, 0xd4, 0x1f, 0x88, 0xd1, 0xc7, 0xc4, 0x5c, - 0xfb, 0x1e, 0x14, 0xfc, 0x0b, 0x07, 0x42, 0x37, 0x6d, 0xcd, 0x64, 0x0e, 0xf6, 0x16, 0x81, 0xf5, - 0x60, 0x31, 0xb8, 0x86, 0xa0, 0xd9, 0xe0, 0x90, 0xaf, 0xc2, 0xd3, 0x75, 0x18, 0xd6, 0xea, 0x86, - 0x6e, 0xa2, 0xd5, 0x04, 0xaa, 0x59, 0x4f, 0x80, 0x71, 0x67, 0x78, 0x60, 0xba, 0xc3, 0xbc, 0x4e, - 0xb4, 0x4f, 0xb0, 0x6e, 0xee, 0x51, 0xdb, 0xe0, 0xfe, 0xae, 0x2e, 0xc1, 0x64, 0xdc, 0x14, 0x43, - 0xe9, 0xab, 0x51, 0xf5, 0xd5, 0xbe, 0x97, 0xa3, 0x34, 0xa8, 0xbd, 0x05, 0xe7, 0xde, 0x3d, 0xae, - 0x3e, 0xf1, 0x9c, 0x1a, 0x34, 0x97, 0x1e, 0x8e, 0x45, 0x9e, 0xab, 0xe6, 0x78, 0x3e, 0x5f, 0xf9, - 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x16, 0x9f, 0xcc, 0xe3, 0x75, 0x21, 0x00, 0x00, + proto.RegisterFile("examples/proto/examplepb/a_bit_of_everything.proto", fileDescriptor_a_bit_of_everything_7494e8194e1b43f3) +} + +var fileDescriptor_a_bit_of_everything_7494e8194e1b43f3 = []byte{ + // 2901 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x59, 0xcd, 0x6f, 0x1b, 0xd7, + 0xb5, 0xd7, 0x70, 0xa8, 0xaf, 0xa3, 0x2f, 0xea, 0xca, 0x1f, 0x32, 0xad, 0x44, 0xd7, 0x8c, 0xf3, + 0x32, 0x51, 0x42, 0x8e, 0x4d, 0xfb, 0xe5, 0xd9, 0x0a, 0x12, 0x3f, 0xea, 0xc3, 0xb6, 0x62, 0x5b, + 0x96, 0xc7, 0x8e, 0x5f, 0xe0, 0xe7, 0x44, 0xb8, 0x24, 0xaf, 0xc8, 0xb1, 0x39, 0x73, 0x27, 0x73, + 0xef, 0xc8, 0x66, 0x55, 0xb5, 0x69, 0x0b, 0xb4, 0x68, 0xb3, 0x28, 0xe0, 0x74, 0x55, 0x14, 0x5d, + 0x77, 0xd1, 0x6d, 0x57, 0x59, 0xb4, 0x5d, 0xa4, 0x9b, 0xee, 0xda, 0x22, 0x40, 0x51, 0xa0, 0x9b, + 0xb6, 0x40, 0xff, 0x82, 0x02, 0xdd, 0x15, 0x73, 0x67, 0x86, 0x9a, 0x19, 0x92, 0x96, 0x69, 0x07, + 0xd9, 0x48, 0x73, 0xe7, 0x9e, 0xf3, 0x3b, 0x9f, 0xf7, 0x9c, 0x73, 0x87, 0x50, 0xa6, 0x8f, 0x89, + 0xe5, 0xb4, 0x28, 0xd7, 0x1d, 0x97, 0x09, 0xa6, 0x87, 0x4b, 0xa7, 0xaa, 0x93, 0xed, 0xaa, 0x29, + 0xb6, 0xd9, 0xce, 0x36, 0xdd, 0xa5, 0x6e, 0x5b, 0x34, 0x4d, 0xbb, 0x51, 0x92, 0x34, 0x68, 0xb1, + 0xe1, 0x3a, 0xb5, 0x52, 0x83, 0x08, 0xfa, 0x88, 0xb4, 0x4b, 0x11, 0x40, 0xa9, 0xc3, 0x9a, 0x5f, + 0x68, 0x30, 0xd6, 0x68, 0x51, 0x9d, 0x38, 0xa6, 0x4e, 0x6c, 0x9b, 0x09, 0x22, 0x4c, 0x66, 0xf3, + 0x80, 0x3d, 0x8f, 0xc3, 0x5d, 0xb9, 0xaa, 0x7a, 0x3b, 0xfa, 0x8e, 0x49, 0x5b, 0xf5, 0x6d, 0x8b, + 0xf0, 0x87, 0x21, 0xc5, 0xc9, 0x34, 0x05, 0xb5, 0x1c, 0xd1, 0x0e, 0x37, 0x5f, 0x4e, 0x6f, 0xd6, + 0x3d, 0x57, 0xe2, 0x87, 0xfb, 0xaf, 0xa5, 0x2c, 0x72, 0x88, 0x68, 0x52, 0xdb, 0xb3, 0xe4, 0xc3, + 0xb6, 0xff, 0x14, 0xe9, 0x91, 0x22, 0xe4, 0x5e, 0x55, 0xb7, 0x28, 0xe7, 0xa4, 0x41, 0x43, 0x8a, + 0x53, 0xdd, 0x14, 0xe5, 0x14, 0xc9, 0x62, 0x5a, 0x1b, 0x61, 0x5a, 0x94, 0x0b, 0x62, 0x39, 0x21, + 0xc1, 0x9b, 0xf2, 0x5f, 0xad, 0xd8, 0xa0, 0x76, 0x91, 0x3f, 0x22, 0x8d, 0x06, 0x75, 0x75, 0xe6, + 0x48, 0x7f, 0x74, 0xfb, 0xa6, 0xf0, 0xbb, 0x39, 0xc8, 0x55, 0x56, 0x4c, 0x71, 0x73, 0x67, 0xbd, + 0xe3, 0x75, 0xf4, 0x21, 0x4c, 0x71, 0xd3, 0x6e, 0xb4, 0xe8, 0xb6, 0x4d, 0xb9, 0xa0, 0xf5, 0xf9, + 0x13, 0x58, 0xd1, 0x26, 0xca, 0x17, 0x4a, 0x87, 0xc4, 0xa1, 0x94, 0x46, 0x2a, 0x6d, 0x4a, 0x7e, + 0x63, 0x32, 0x80, 0x0b, 0x56, 0xa8, 0x09, 0x59, 0xcf, 0x33, 0xeb, 0xf3, 0x0a, 0x56, 0xb4, 0xf1, + 0x95, 0x3b, 0x4f, 0x2a, 0xb7, 0x3e, 0x51, 0x94, 0x1f, 0x29, 0xd7, 0xfe, 0x9f, 0x14, 0x77, 0x2a, + 0xc5, 0xcb, 0x67, 0x8a, 0x17, 0x3f, 0xdc, 0xbb, 0xb0, 0x5f, 0x8c, 0x2f, 0xcf, 0x0f, 0xb2, 0x3c, + 0x5b, 0xde, 0x37, 0xa4, 0x04, 0xb4, 0x05, 0x23, 0xa1, 0x05, 0x19, 0xac, 0xbe, 0x90, 0x05, 0x21, + 0x0e, 0x5a, 0x84, 0x89, 0x9d, 0x16, 0x23, 0x62, 0x7b, 0x97, 0xb4, 0x3c, 0x3a, 0xaf, 0x62, 0x45, + 0xcb, 0x18, 0x20, 0x5f, 0xdd, 0xf5, 0xdf, 0xa0, 0x53, 0x30, 0x59, 0x67, 0x5e, 0xb5, 0x45, 0x43, + 0x8a, 0x2c, 0x56, 0x34, 0xc5, 0x98, 0x08, 0xde, 0x05, 0x24, 0x8b, 0x30, 0x61, 0xda, 0xe2, 0xad, + 0xf3, 0x21, 0xc5, 0x30, 0x56, 0x34, 0xd5, 0x00, 0xf9, 0xaa, 0x83, 0xe1, 0xc5, 0x29, 0x46, 0xb0, + 0xa2, 0x65, 0x8d, 0x09, 0x2f, 0x46, 0x12, 0x60, 0x9c, 0x2b, 0x87, 0x14, 0xa3, 0x58, 0xd1, 0x86, + 0x25, 0xc6, 0xb9, 0x72, 0x40, 0xf0, 0x0a, 0x4c, 0xed, 0x98, 0x8f, 0x69, 0xbd, 0x03, 0x32, 0x86, + 0x15, 0x6d, 0xc4, 0x98, 0x0c, 0x5f, 0x26, 0x89, 0x3a, 0x38, 0xe3, 0x58, 0xd1, 0x46, 0x43, 0xa2, + 0x08, 0xe9, 0x25, 0x80, 0x2a, 0x63, 0xad, 0x90, 0x02, 0xb0, 0xa2, 0x8d, 0x19, 0xe3, 0xfe, 0x9b, + 0x8e, 0xb2, 0x5c, 0xb8, 0xa6, 0xdd, 0x08, 0x09, 0x26, 0xfc, 0xa8, 0x1a, 0x13, 0xc1, 0xbb, 0x8e, + 0xb2, 0xd5, 0xb6, 0xa0, 0x3c, 0xa4, 0x78, 0x09, 0x2b, 0xda, 0xa4, 0x01, 0xf2, 0x55, 0xc2, 0xe0, + 0x8e, 0x1a, 0x53, 0x58, 0xd1, 0xa6, 0x02, 0x83, 0x23, 0x2d, 0xae, 0x01, 0xf8, 0x47, 0x29, 0x24, + 0x98, 0xc6, 0x8a, 0x36, 0x5d, 0x7e, 0xf3, 0xd0, 0x70, 0x6e, 0x7a, 0x16, 0x75, 0xcd, 0xda, 0xba, + 0xed, 0x59, 0xc6, 0xb8, 0xcf, 0x1f, 0x80, 0x6d, 0xc1, 0x4c, 0xe7, 0x70, 0x86, 0x88, 0x2f, 0x4b, + 0x44, 0xad, 0x0f, 0x62, 0x74, 0xa6, 0x4b, 0x5b, 0x44, 0x34, 0x25, 0xda, 0x94, 0x13, 0x3e, 0x05, + 0x88, 0x1c, 0x8e, 0x05, 0x19, 0xb2, 0x9d, 0x06, 0x5e, 0x94, 0xc0, 0xef, 0x1e, 0x06, 0x7c, 0x23, + 0x38, 0xe5, 0x11, 0x7e, 0x98, 0x77, 0x1d, 0x71, 0x73, 0x76, 0x62, 0x1d, 0x08, 0x7d, 0x15, 0xa6, + 0x79, 0x32, 0x7e, 0x33, 0x58, 0xd1, 0x66, 0x8c, 0x29, 0x9e, 0x08, 0x60, 0x87, 0xac, 0x93, 0x0b, + 0x39, 0xac, 0x68, 0xb9, 0x88, 0x2c, 0x96, 0x75, 0x3c, 0x1e, 0x84, 0x59, 0xac, 0x68, 0xb3, 0xc6, + 0x04, 0x8f, 0x05, 0x21, 0x24, 0xe9, 0xe0, 0x20, 0xac, 0x68, 0x28, 0x20, 0x89, 0x50, 0xca, 0x70, + 0xd4, 0xa5, 0x0e, 0x25, 0xbe, 0x2b, 0x12, 0x79, 0x31, 0x87, 0x55, 0x6d, 0xdc, 0x98, 0x8b, 0x36, + 0x6f, 0xc7, 0xf2, 0xe3, 0x22, 0x4c, 0x30, 0x9b, 0xfa, 0x95, 0xdf, 0x2f, 0xbb, 0xf3, 0x47, 0x64, + 0xb5, 0x39, 0x56, 0x0a, 0x2a, 0x5d, 0x29, 0xaa, 0x74, 0xa5, 0x75, 0x7f, 0xf7, 0xea, 0x90, 0x01, + 0x92, 0x58, 0xae, 0xd0, 0x2b, 0x30, 0x19, 0xb0, 0x06, 0xb2, 0xe6, 0x8f, 0xfa, 0xd9, 0x77, 0x75, + 0xc8, 0x08, 0x00, 0x03, 0x21, 0xe8, 0x3e, 0x8c, 0x5b, 0xc4, 0x09, 0xf5, 0x38, 0x26, 0x2b, 0xc1, + 0xa5, 0xc1, 0x2b, 0xc1, 0x0d, 0xe2, 0x48, 0x75, 0xd7, 0x6d, 0xe1, 0xb6, 0x8d, 0x31, 0x2b, 0x5c, + 0xa2, 0xc7, 0x30, 0x67, 0x11, 0xc7, 0x49, 0xdb, 0x7b, 0x5c, 0xca, 0xb9, 0xfa, 0x5c, 0x72, 0x9c, + 0x84, 0x7f, 0x02, 0x81, 0xb3, 0x56, 0xfa, 0x7d, 0x4c, 0x72, 0x98, 0x7b, 0x81, 0xe4, 0xf9, 0x17, + 0x93, 0x1c, 0x64, 0x5e, 0xb7, 0xe4, 0xd8, 0x7b, 0xb4, 0x0c, 0xf3, 0x36, 0xb3, 0x57, 0x99, 0xbd, + 0x4b, 0x6d, 0xbf, 0x9d, 0x90, 0xd6, 0x26, 0xb1, 0x82, 0xf2, 0x36, 0x9f, 0x97, 0x05, 0xa0, 0xef, + 0x3e, 0x5a, 0x85, 0x99, 0x4e, 0xcf, 0x0a, 0x35, 0x3e, 0x29, 0x23, 0x9e, 0xef, 0x8a, 0xf8, 0x9d, + 0x88, 0xce, 0x98, 0xee, 0xb0, 0x04, 0x20, 0xf7, 0xa1, 0x93, 0x49, 0xf1, 0xc3, 0xb6, 0x80, 0xd5, + 0x81, 0xeb, 0xc2, 0x6c, 0x04, 0xd4, 0x39, 0x58, 0xf9, 0x5f, 0x28, 0x30, 0x12, 0x36, 0x2b, 0x04, + 0x59, 0x9b, 0x58, 0x34, 0x68, 0x56, 0x86, 0x7c, 0x46, 0xc7, 0x60, 0x84, 0x58, 0xcc, 0xb3, 0xc5, + 0x7c, 0x46, 0x16, 0xaa, 0x70, 0x85, 0x6e, 0x41, 0x86, 0x3d, 0x94, 0x3d, 0x61, 0xba, 0x5c, 0x79, + 0xde, 0x56, 0x53, 0x5a, 0xa3, 0xd4, 0x91, 0x8a, 0x65, 0xd8, 0xc3, 0xc2, 0x22, 0x8c, 0x45, 0x6b, + 0x34, 0x0e, 0xc3, 0x97, 0x2b, 0xd7, 0x6f, 0xaf, 0xe7, 0x86, 0xd0, 0x18, 0x64, 0xef, 0x18, 0xef, + 0xaf, 0xe7, 0x94, 0xbc, 0x09, 0x53, 0x89, 0xc4, 0x44, 0x39, 0x50, 0x1f, 0xd2, 0x76, 0xa8, 0xaf, + 0xff, 0x88, 0x56, 0x60, 0x38, 0xf0, 0x4e, 0xe6, 0x39, 0xaa, 0x66, 0xc0, 0xba, 0x9c, 0xb9, 0xa0, + 0xe4, 0xd7, 0xe0, 0x58, 0xef, 0xdc, 0xec, 0x21, 0xf3, 0x48, 0x5c, 0xe6, 0x78, 0x1c, 0xe5, 0x5b, + 0x11, 0x4a, 0x3a, 0xcf, 0x7a, 0xa0, 0x6c, 0xc6, 0x51, 0x5e, 0xa4, 0x7d, 0x1f, 0xc8, 0x5f, 0xfe, + 0x42, 0x79, 0x52, 0xf9, 0xad, 0x02, 0x8d, 0xa5, 0xb9, 0x0a, 0xae, 0x9a, 0x02, 0xb3, 0x1d, 0x7c, + 0x30, 0x70, 0x96, 0x37, 0x36, 0x6c, 0x11, 0xa5, 0x6c, 0x1b, 0xd7, 0x98, 0xe5, 0xb4, 0xcc, 0x9a, + 0x9f, 0x1c, 0x38, 0x1c, 0xc3, 0xb0, 0x68, 0x3b, 0x14, 0x0b, 0x86, 0x6b, 0x6c, 0x97, 0xba, 0xd8, + 0x22, 0x76, 0x1b, 0xef, 0x50, 0x22, 0x3c, 0x97, 0x72, 0x1f, 0x6b, 0x2b, 0xca, 0xdd, 0x3f, 0x28, + 0x72, 0x06, 0x59, 0xba, 0x0b, 0xa7, 0x2f, 0x9b, 0x76, 0x1d, 0x33, 0x4f, 0x60, 0x8b, 0xb9, 0x14, + 0x93, 0xaa, 0xff, 0xd8, 0x35, 0x74, 0x95, 0x9a, 0x42, 0x38, 0x7c, 0x59, 0xd7, 0x1b, 0xa6, 0x68, + 0x7a, 0xd5, 0x52, 0x8d, 0x59, 0xba, 0x6f, 0x6e, 0x91, 0xd6, 0x18, 0x6f, 0x73, 0x41, 0xc3, 0x65, + 0x68, 0xfd, 0xca, 0x54, 0x54, 0x34, 0xa5, 0x69, 0x85, 0x9f, 0x8c, 0xc1, 0x7c, 0x1a, 0xd3, 0x08, + 0x13, 0x1b, 0x5d, 0x84, 0x13, 0xb2, 0x2d, 0x75, 0x8e, 0x4c, 0x7c, 0x86, 0x51, 0xb0, 0xaa, 0x65, + 0x8c, 0x63, 0x3e, 0x41, 0xc4, 0x70, 0xf9, 0x60, 0x9e, 0x79, 0x1b, 0xf2, 0x49, 0xd6, 0xc4, 0x74, + 0xe3, 0x8f, 0x55, 0x8a, 0x71, 0x3c, 0xce, 0xbb, 0x16, 0x9b, 0x74, 0xba, 0xe4, 0xc6, 0x9b, 0x87, + 0x8a, 0x55, 0x4d, 0x4d, 0xca, 0xdd, 0x38, 0xe8, 0x23, 0x5d, 0x72, 0x13, 0x13, 0x51, 0x16, 0xab, + 0x5a, 0x36, 0x29, 0xf7, 0xfd, 0x58, 0x13, 0xea, 0x25, 0xb7, 0xd3, 0xd7, 0x86, 0xb1, 0xaa, 0x0d, + 0x77, 0xc9, 0x8d, 0x5a, 0xdc, 0x3b, 0x70, 0x32, 0xe5, 0xaa, 0x44, 0xe7, 0x1c, 0xc1, 0xaa, 0x36, + 0x62, 0xcc, 0x27, 0x9c, 0x15, 0x6f, 0xa2, 0xbd, 0xd9, 0x63, 0x73, 0x9a, 0xaa, 0x8d, 0xf6, 0x60, + 0x8f, 0xa4, 0xff, 0x0f, 0xcc, 0x27, 0xd9, 0x63, 0x93, 0xd7, 0x18, 0x56, 0xb5, 0x31, 0xe3, 0x68, + 0x9c, 0x77, 0xa5, 0x33, 0x85, 0x75, 0xb9, 0x2b, 0xd1, 0x8b, 0xc6, 0x65, 0xef, 0x4d, 0xb8, 0x2b, + 0xd9, 0x7f, 0x53, 0xee, 0x8a, 0x4f, 0x6b, 0x80, 0x55, 0x6d, 0x32, 0xe9, 0xae, 0x95, 0x83, 0xc9, + 0xad, 0x67, 0x98, 0x3a, 0xe6, 0x4e, 0x60, 0x55, 0x9b, 0xea, 0x0e, 0x53, 0x64, 0x2d, 0x4d, 0x5b, + 0x1b, 0xab, 0xe4, 0x93, 0xcf, 0x51, 0xc9, 0x13, 0xbe, 0x39, 0x18, 0x93, 0x2e, 0xc1, 0x42, 0xca, + 0x37, 0xc9, 0xa0, 0x4c, 0x61, 0x55, 0x9b, 0x31, 0x4e, 0x24, 0xbc, 0x93, 0x18, 0xa0, 0xfa, 0x00, + 0x74, 0x92, 0x62, 0x1a, 0xab, 0x5a, 0xae, 0x17, 0x40, 0xdf, 0x64, 0x4e, 0x0c, 0x5a, 0x33, 0x58, + 0xd5, 0x66, 0x53, 0xd1, 0x89, 0x79, 0xa9, 0x27, 0x73, 0x6c, 0x94, 0x53, 0x35, 0xd4, 0xcd, 0x1c, + 0x4a, 0x2e, 0xe4, 0x21, 0xbb, 0xc2, 0xea, 0xed, 0x5e, 0x6d, 0xac, 0x70, 0x1f, 0x66, 0xc2, 0xa9, + 0xf3, 0xff, 0x4c, 0xd1, 0x94, 0x64, 0xd3, 0x90, 0x89, 0x2e, 0x66, 0x46, 0xc6, 0xf4, 0x0b, 0x47, + 0xb6, 0x4e, 0x04, 0x09, 0xeb, 0xef, 0xab, 0x87, 0x46, 0xc3, 0x07, 0x31, 0x24, 0x4b, 0xe1, 0x33, + 0x05, 0x66, 0xde, 0x77, 0xea, 0x44, 0xd0, 0xbb, 0x65, 0x83, 0x7e, 0xec, 0x51, 0x2e, 0xd0, 0x2a, + 0xa8, 0xa4, 0x1a, 0x28, 0x31, 0x51, 0x3e, 0x3b, 0x70, 0x35, 0x37, 0x7c, 0x6e, 0xf4, 0x36, 0x4c, + 0x78, 0x12, 0x57, 0xde, 0xe0, 0x43, 0xd5, 0xba, 0x67, 0x87, 0xcb, 0xfe, 0x25, 0xff, 0x06, 0xe1, + 0x0f, 0x0d, 0x08, 0xc8, 0xfd, 0xe7, 0x25, 0x0c, 0x13, 0xb1, 0x8c, 0xf1, 0xfb, 0xe8, 0xbd, 0x75, + 0xe3, 0x66, 0x6e, 0x08, 0x8d, 0x82, 0x7a, 0x73, 0x73, 0x3d, 0xa7, 0x94, 0xff, 0xbc, 0x00, 0xc7, + 0xd3, 0x82, 0x6f, 0x53, 0x77, 0xd7, 0xac, 0x51, 0xf4, 0xa5, 0x0a, 0x23, 0xab, 0xae, 0xef, 0x64, + 0x34, 0xb8, 0xf6, 0xf9, 0xc1, 0x59, 0x0a, 0xff, 0xc8, 0x7c, 0xf7, 0x8f, 0x7f, 0xff, 0x2c, 0xf3, + 0xd7, 0x4c, 0xe1, 0x2f, 0x19, 0x7d, 0xf7, 0x6c, 0xf4, 0xb5, 0xa4, 0xd7, 0xb7, 0x12, 0x7d, 0x2f, + 0x56, 0xd4, 0xf7, 0xf5, 0xbd, 0x78, 0x9d, 0xde, 0xd7, 0xf7, 0x62, 0x39, 0xb3, 0xaf, 0x73, 0xea, + 0x10, 0x97, 0x08, 0xe6, 0xea, 0x7b, 0x5e, 0x62, 0x63, 0x2f, 0x96, 0x97, 0xfb, 0xfa, 0x5e, 0x22, + 0xcd, 0xa3, 0x75, 0x6c, 0xff, 0xa0, 0x3a, 0xed, 0xeb, 0x7b, 0xf1, 0x8a, 0xf3, 0x0e, 0x17, 0xae, + 0xe3, 0xd2, 0x1d, 0xf3, 0xb1, 0xbe, 0xb4, 0x1f, 0x08, 0x89, 0xb1, 0xf1, 0x34, 0x0e, 0x4f, 0x0b, + 0xe2, 0x29, 0x86, 0xa4, 0x92, 0xfd, 0x46, 0xcb, 0x7d, 0x7d, 0xef, 0xa0, 0x82, 0xec, 0xeb, 0x7b, + 0xa9, 0xab, 0x98, 0xcf, 0xd9, 0xf3, 0x8e, 0xb6, 0x8f, 0x7e, 0xae, 0x00, 0x04, 0x81, 0x95, 0xc7, + 0xe0, 0xeb, 0x09, 0xee, 0x92, 0x8c, 0xed, 0xe9, 0xc2, 0xe2, 0x21, 0x91, 0x5d, 0x56, 0x96, 0xd0, + 0x37, 0x61, 0xe4, 0x3a, 0x63, 0x0f, 0x3d, 0x07, 0xcd, 0x94, 0xb8, 0x57, 0x2d, 0x97, 0x36, 0xea, + 0xe1, 0xd9, 0x7d, 0x1e, 0xc9, 0x25, 0x29, 0x59, 0x43, 0xff, 0x75, 0x68, 0x4e, 0xf9, 0x23, 0xcc, + 0x3e, 0xfa, 0xbe, 0x02, 0x23, 0xc1, 0x59, 0x7e, 0x1e, 0xd7, 0xf4, 0xb9, 0xc9, 0x15, 0xce, 0x4a, + 0x2d, 0xde, 0xc8, 0x3f, 0xa3, 0x16, 0xbe, 0x1b, 0x7e, 0xa3, 0xc0, 0x58, 0x54, 0x54, 0xd0, 0x99, + 0x43, 0x55, 0x49, 0xd5, 0x9f, 0xbe, 0x9a, 0x3c, 0x90, 0x9a, 0xd4, 0xf3, 0x4b, 0xfa, 0x6e, 0xf9, + 0xe9, 0x9a, 0x90, 0x2a, 0x2d, 0x05, 0xda, 0xf8, 0xb5, 0xe8, 0xde, 0xd9, 0xf2, 0xa0, 0x2c, 0xe8, + 0x67, 0x0a, 0xcc, 0x6f, 0x11, 0x51, 0x6b, 0xfa, 0x45, 0xb7, 0x53, 0xa4, 0x36, 0x6c, 0x99, 0x78, + 0x5f, 0x9d, 0x49, 0x6f, 0x49, 0x93, 0xce, 0x94, 0xdf, 0xd0, 0x77, 0xcb, 0xe4, 0x59, 0x15, 0x54, + 0x96, 0xd0, 0x8f, 0x15, 0x18, 0x59, 0xa3, 0x2d, 0x2a, 0x68, 0x77, 0xa6, 0xf5, 0x93, 0x75, 0xff, + 0x49, 0xe5, 0x8d, 0xea, 0xeb, 0x30, 0x0d, 0x50, 0x71, 0xcc, 0x6b, 0xb4, 0x5d, 0xf1, 0x44, 0x13, + 0x0d, 0xc1, 0x71, 0x18, 0xb9, 0xe9, 0x3f, 0x96, 0xd1, 0x14, 0x64, 0x5d, 0x4a, 0xea, 0x30, 0xfc, + 0xc8, 0x35, 0x05, 0x0d, 0x92, 0x6f, 0xe9, 0x59, 0x93, 0xef, 0x6f, 0x0a, 0x8c, 0x5d, 0xa1, 0xe2, + 0x96, 0x47, 0xdd, 0xf6, 0x57, 0x99, 0x7e, 0x9f, 0x2a, 0x4f, 0x2a, 0x77, 0x0a, 0x9b, 0xb0, 0xd0, + 0x6b, 0x3c, 0xef, 0x08, 0x1c, 0x70, 0x2c, 0xff, 0x40, 0xa9, 0x0e, 0x49, 0xfb, 0x4a, 0xe8, 0xcd, + 0xc3, 0xec, 0xfb, 0xd8, 0x17, 0x10, 0x59, 0xf9, 0xe9, 0x30, 0xe4, 0xae, 0x50, 0x11, 0xf5, 0xf0, + 0x40, 0xf8, 0xc5, 0xc1, 0x5b, 0x64, 0xc8, 0x9f, 0x7f, 0x7e, 0xd6, 0xc2, 0x27, 0x59, 0x69, 0xc1, + 0xbf, 0x55, 0xf4, 0x2f, 0xf5, 0x10, 0x1b, 0x3a, 0x43, 0x49, 0x58, 0x6c, 0x7b, 0x5d, 0x30, 0xf6, + 0xd3, 0x7b, 0xa9, 0xce, 0xd4, 0xf7, 0x86, 0xd0, 0xb5, 0xe7, 0x3d, 0x6d, 0x33, 0xd9, 0x31, 0x9e, + 0x32, 0xc3, 0xf7, 0xde, 0xed, 0xcb, 0x9b, 0xe8, 0x71, 0xfd, 0x67, 0xec, 0x6e, 0xbe, 0x83, 0x19, + 0xba, 0xa7, 0x21, 0x7d, 0x05, 0x76, 0xb7, 0xb0, 0x3e, 0x83, 0x6b, 0x9f, 0xed, 0xbe, 0x76, 0xf2, + 0xa7, 0x49, 0x4d, 0xb4, 0x58, 0xf4, 0x85, 0x0a, 0xd9, 0xf5, 0x5a, 0x93, 0xa1, 0x7e, 0x1f, 0x44, + 0xb9, 0x57, 0x2d, 0x05, 0x57, 0x88, 0xa8, 0x38, 0x3c, 0x33, 0x65, 0xe1, 0x9f, 0x99, 0x27, 0x95, + 0xef, 0x64, 0x60, 0x92, 0xd6, 0x9a, 0x0c, 0xf3, 0x60, 0xb4, 0x82, 0x31, 0xb9, 0x72, 0x9d, 0x1a, + 0x9a, 0xbd, 0xed, 0x59, 0x16, 0x71, 0xdb, 0xcb, 0x78, 0x3d, 0x7c, 0x95, 0xcf, 0xad, 0x51, 0x5e, + 0x73, 0x4d, 0xf9, 0x2b, 0x86, 0x7c, 0x5b, 0x58, 0x03, 0x94, 0x3c, 0xb6, 0x52, 0xdb, 0x01, 0x0f, + 0xeb, 0x7b, 0x97, 0x40, 0xfd, 0xef, 0x33, 0xe7, 0xd0, 0x05, 0x78, 0xcb, 0xa0, 0xc2, 0x73, 0x6d, + 0x5a, 0xc7, 0x8f, 0x9a, 0xd4, 0xc6, 0xa2, 0x49, 0xb1, 0x4b, 0x39, 0xf3, 0xdc, 0x1a, 0xc5, 0x26, + 0xc7, 0x82, 0x5a, 0x0e, 0x73, 0x89, 0x6b, 0xb6, 0xda, 0xd8, 0xb3, 0xc9, 0x2e, 0x31, 0x5b, 0xa4, + 0xda, 0xa2, 0xa5, 0xf7, 0xde, 0x06, 0xf5, 0xfc, 0x99, 0xf3, 0xe8, 0x3c, 0x2c, 0x3d, 0x05, 0xa0, + 0xce, 0x28, 0xc7, 0x36, 0x13, 0x98, 0x3e, 0x36, 0xb9, 0x28, 0xa1, 0x11, 0xc8, 0xfe, 0x34, 0xa3, + 0xa8, 0xf2, 0x90, 0x7d, 0x78, 0x78, 0x99, 0xf0, 0x1d, 0xa3, 0xef, 0x05, 0x81, 0xb9, 0x77, 0xa2, + 0x90, 0x8b, 0x37, 0x1c, 0x7f, 0x6f, 0x39, 0xf8, 0xb8, 0x71, 0x0f, 0xa1, 0xae, 0x2d, 0xf4, 0x2b, + 0x05, 0x26, 0xd7, 0x28, 0x75, 0xe4, 0x77, 0x63, 0xff, 0xc5, 0xd7, 0x33, 0xd9, 0x5c, 0x92, 0xb6, + 0x5d, 0x2c, 0x9c, 0x3f, 0xb4, 0xc4, 0x27, 0x7e, 0x67, 0x2a, 0xf9, 0xd7, 0x12, 0xd9, 0x85, 0x2a, + 0x00, 0x9b, 0x6c, 0xc5, 0xb4, 0xeb, 0xa6, 0xdd, 0xe0, 0xe8, 0x44, 0x57, 0x05, 0x5f, 0x0b, 0x7f, + 0x82, 0xeb, 0x5b, 0xdc, 0x87, 0xd0, 0x5d, 0x18, 0xbd, 0x63, 0x5a, 0x94, 0x79, 0x02, 0xf5, 0x21, + 0xea, 0xcb, 0x7c, 0x52, 0xaa, 0x7f, 0x14, 0xcd, 0xc5, 0xfd, 0x29, 0x42, 0xb0, 0x26, 0xe4, 0xd6, + 0x5d, 0x97, 0xb9, 0x7e, 0xfb, 0x5e, 0xa3, 0x82, 0x98, 0x2d, 0x3e, 0xb0, 0x80, 0xd3, 0x52, 0xc0, + 0xcb, 0x68, 0x21, 0x11, 0x30, 0x1f, 0xf5, 0x91, 0x29, 0x9a, 0xf5, 0x10, 0xf5, 0x07, 0x0a, 0xa0, + 0x2b, 0x54, 0xa4, 0xef, 0x68, 0x87, 0xcf, 0x08, 0x29, 0x8e, 0xbe, 0x6a, 0xbc, 0x26, 0xd5, 0x38, + 0x55, 0x38, 0x11, 0x57, 0xc3, 0xd7, 0xa0, 0xca, 0xea, 0x6d, 0x7d, 0xcf, 0x9f, 0x08, 0xe4, 0x5d, + 0x0e, 0x7d, 0x4f, 0x81, 0xd9, 0x2d, 0xc6, 0x85, 0x8f, 0x28, 0x59, 0xa5, 0x22, 0xcf, 0x76, 0x1d, + 0xec, 0x2b, 0x5d, 0x97, 0xd2, 0x5f, 0x2f, 0x9c, 0x8e, 0x4b, 0x77, 0x18, 0x17, 0xbe, 0x06, 0xf2, + 0x97, 0x80, 0x40, 0x8d, 0x28, 0x29, 0xf2, 0xbf, 0x56, 0x9e, 0x54, 0x3e, 0x57, 0xd0, 0x4e, 0x9f, + 0xdb, 0x19, 0xae, 0xc7, 0x8a, 0x44, 0xb1, 0x88, 0x1f, 0x35, 0xcd, 0x5a, 0x13, 0xf3, 0x26, 0xf3, + 0x5a, 0x75, 0x79, 0xfc, 0xaa, 0x14, 0x7b, 0x9c, 0xd6, 0xb1, 0x69, 0x63, 0xa7, 0x45, 0x6a, 0x14, + 0xb3, 0x1d, 0x79, 0x50, 0xeb, 0xac, 0xe6, 0x59, 0xd4, 0x0e, 0x7e, 0x18, 0xc5, 0x35, 0x66, 0xf9, + 0x8b, 0x53, 0xf9, 0x5b, 0xb0, 0xd8, 0x6b, 0x32, 0xf0, 0x8f, 0x51, 0x74, 0x1f, 0x1c, 0xb0, 0xde, + 0x94, 0x1f, 0xc0, 0x91, 0x1a, 0xb1, 0x68, 0x6b, 0x95, 0x70, 0x1a, 0x62, 0xf8, 0x97, 0x17, 0x64, + 0xc0, 0x70, 0xf0, 0x73, 0xc6, 0xa0, 0x89, 0x74, 0x42, 0xfa, 0x70, 0x0e, 0xcd, 0x26, 0x12, 0xc9, + 0xdf, 0x2a, 0x7f, 0x04, 0x0b, 0x15, 0x9b, 0x89, 0x26, 0x75, 0x43, 0x49, 0x7e, 0xf0, 0x62, 0x87, + 0xea, 0xdd, 0xc4, 0x11, 0x1b, 0x54, 0xf0, 0xd0, 0xca, 0xe7, 0xa3, 0x4f, 0x2a, 0xbf, 0x1c, 0x45, + 0x7f, 0x52, 0x60, 0xae, 0x82, 0x57, 0x82, 0x0f, 0xa9, 0xb1, 0x12, 0xf0, 0x01, 0x1c, 0x69, 0x18, + 0x5b, 0xab, 0xc5, 0x2b, 0x81, 0xe9, 0xd8, 0x71, 0xd9, 0x03, 0x5a, 0x13, 0x83, 0xba, 0x2c, 0x9f, + 0xb3, 0x99, 0x4d, 0xff, 0x37, 0x34, 0xcd, 0xa7, 0x5e, 0xfa, 0x08, 0x8e, 0xac, 0xdc, 0x5e, 0xc3, + 0xe7, 0x8a, 0xab, 0x2d, 0xe2, 0x71, 0x8a, 0xaf, 0x9b, 0x35, 0x6a, 0x73, 0x8a, 0x2e, 0x0f, 0x86, + 0xac, 0x57, 0x5b, 0xac, 0xaa, 0x5b, 0x84, 0x0b, 0xea, 0xea, 0xd7, 0x37, 0x56, 0xd7, 0x37, 0x6f, + 0xaf, 0x97, 0xc4, 0x63, 0x51, 0x56, 0xcf, 0x96, 0xce, 0x2c, 0xa9, 0x4a, 0x26, 0x5b, 0xce, 0x11, + 0x27, 0xf8, 0xfc, 0x6b, 0x32, 0x5b, 0x7f, 0xc0, 0x99, 0x5d, 0x3e, 0x16, 0x7f, 0xf3, 0xb8, 0xb8, + 0xc3, 0x58, 0xd1, 0x32, 0x2d, 0xba, 0xdc, 0x45, 0xb9, 0xdc, 0x87, 0xd2, 0xd8, 0xf2, 0x3b, 0xc6, + 0x39, 0xb4, 0x01, 0x57, 0xba, 0x3b, 0x86, 0xc7, 0xa9, 0x7b, 0xd0, 0x2d, 0x9a, 0x64, 0x97, 0x62, + 0x87, 0xba, 0x96, 0xc9, 0xb9, 0x9f, 0x98, 0x82, 0x61, 0x52, 0xab, 0x51, 0xce, 0x13, 0xdd, 0xa5, + 0x64, 0xbc, 0x40, 0x0f, 0x1a, 0x35, 0xae, 0x82, 0x7a, 0xfe, 0xec, 0x05, 0x54, 0x81, 0xa9, 0x8d, + 0xd7, 0x2c, 0x4c, 0xb0, 0xa0, 0xc4, 0x61, 0xa2, 0x84, 0xce, 0x40, 0x29, 0x3f, 0xd0, 0xc7, 0xb7, + 0x7b, 0x3f, 0xcc, 0xc0, 0x0c, 0x8c, 0xaf, 0x10, 0x6e, 0xd6, 0xe4, 0xfc, 0x9f, 0x19, 0x53, 0xe0, + 0xa5, 0xc4, 0x8d, 0x60, 0x66, 0x2c, 0x93, 0x1f, 0xff, 0xa0, 0x58, 0xd9, 0xda, 0x28, 0x5e, 0xa3, + 0x6d, 0x9c, 0x81, 0x2f, 0x95, 0xce, 0x0d, 0xe1, 0xf7, 0xca, 0x98, 0xaa, 0x65, 0xcb, 0xaf, 0x44, + 0x31, 0x8c, 0x05, 0x5c, 0x67, 0xc4, 0x13, 0x4d, 0xdd, 0xff, 0xc3, 0x5c, 0xf3, 0x1b, 0x74, 0x79, + 0xb1, 0x3f, 0x91, 0x60, 0x0f, 0xa9, 0xbd, 0xf2, 0x6d, 0xc8, 0x07, 0x17, 0x0e, 0x84, 0xae, 0xb8, + 0xc4, 0x16, 0x1c, 0xfb, 0x8b, 0xd0, 0x7b, 0xb0, 0x10, 0x5e, 0x43, 0xd0, 0x5c, 0xb8, 0x29, 0x57, + 0xd1, 0xee, 0x2a, 0x0c, 0x93, 0xba, 0x65, 0xda, 0x68, 0x39, 0xc1, 0x6a, 0xd7, 0x13, 0x64, 0x32, + 0x18, 0x3e, 0x99, 0xc9, 0x85, 0xdf, 0x89, 0x76, 0x29, 0x36, 0xed, 0x1d, 0xe6, 0x5a, 0x32, 0xde, + 0xd5, 0x45, 0x98, 0x8a, 0xbb, 0x62, 0x28, 0x7d, 0x35, 0xaa, 0xbe, 0xde, 0xf7, 0x72, 0x94, 0x26, + 0x75, 0x37, 0xe0, 0xf8, 0x8d, 0x83, 0xea, 0x13, 0x3f, 0x53, 0x83, 0x9e, 0xa5, 0x7b, 0xe3, 0x9d, + 0xc8, 0x55, 0x47, 0xe4, 0x79, 0x3e, 0xf7, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x52, 0x42, 0x5e, + 0xa6, 0x8f, 0x23, 0x00, 0x00, } diff --git a/examples/proto/examplepb/a_bit_of_everything.pb.gw.go b/examples/proto/examplepb/a_bit_of_everything.pb.gw.go index c506569c47d..2d9070eef8d 100644 --- a/examples/proto/examplepb/a_bit_of_everything.pb.gw.go +++ b/examples/proto/examplepb/a_bit_of_everything.pb.gw.go @@ -265,7 +265,11 @@ func request_ABitOfEverythingService_CreateBody_0(ctx context.Context, marshaler var protoReq ABitOfEverything var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -305,7 +309,11 @@ func request_ABitOfEverythingService_Update_0(ctx context.Context, marshaler run var protoReq ABitOfEverything var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -332,6 +340,139 @@ func request_ABitOfEverythingService_Update_0(ctx context.Context, marshaler run } +var ( + filter_ABitOfEverythingService_UpdateV2_0 = &utilities.DoubleArray{Encoding: map[string]int{"abe": 0, "uuid": 1}, Base: []int{1, 2, 1, 0, 0}, Check: []int{0, 1, 2, 3, 2}} +) + +func request_ABitOfEverythingService_UpdateV2_0(ctx context.Context, marshaler runtime.Marshaler, client ABitOfEverythingServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq UpdateV2Request + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.Abe); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["abe.uuid"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "abe.uuid") + } + + err = runtime.PopulateFieldFromPath(&protoReq, "abe.uuid", val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "abe.uuid", err) + } + + if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_ABitOfEverythingService_UpdateV2_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.UpdateV2(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +var ( + filter_ABitOfEverythingService_UpdateV2_1 = &utilities.DoubleArray{Encoding: map[string]int{"abe": 0, "uuid": 1}, Base: []int{1, 2, 1, 0, 0}, Check: []int{0, 1, 2, 3, 2}} +) + +func request_ABitOfEverythingService_UpdateV2_1(ctx context.Context, marshaler runtime.Marshaler, client ABitOfEverythingServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq UpdateV2Request + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.Abe); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if protoReq.UpdateMask != nil && len(protoReq.UpdateMask.GetPaths()) > 0 { + runtime.CamelCaseFieldMask(protoReq.UpdateMask) + } else { + if fieldMask, err := runtime.FieldMaskFromRequestBody(newReader()); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } else { + protoReq.UpdateMask = fieldMask + } + } + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["abe.uuid"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "abe.uuid") + } + + err = runtime.PopulateFieldFromPath(&protoReq, "abe.uuid", val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "abe.uuid", err) + } + + if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_ABitOfEverythingService_UpdateV2_1); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.UpdateV2(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func request_ABitOfEverythingService_PatchWithFieldMaskInBody_0(ctx context.Context, marshaler runtime.Marshaler, client ABitOfEverythingServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq UpdateV2Request + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if protoReq.UpdateMask != nil && len(protoReq.UpdateMask.GetPaths()) > 0 { + runtime.CamelCaseFieldMask(protoReq.UpdateMask) + } + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["abe.uuid"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "abe.uuid") + } + + err = runtime.PopulateFieldFromPath(&protoReq, "abe.uuid", val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "abe.uuid", err) + } + + msg, err := client.PatchWithFieldMaskInBody(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + func request_ABitOfEverythingService_Delete_0(ctx context.Context, marshaler runtime.Marshaler, client ABitOfEverythingServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq sub2.IdMessage var metadata runtime.ServerMetadata @@ -624,7 +765,11 @@ func request_ABitOfEverythingService_Echo_1(ctx context.Context, marshaler runti var protoReq sub.StringMessage var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.Value); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.Value); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -654,7 +799,11 @@ func request_ABitOfEverythingService_DeepPathEcho_0(ctx context.Context, marshal var protoReq ABitOfEverything var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -703,7 +852,11 @@ func request_ABitOfEverythingService_GetMessageWithBody_0(ctx context.Context, m var protoReq MessageWithBody var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.Data); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.Data); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -734,7 +887,11 @@ func request_ABitOfEverythingService_PostWithEmptyBody_0(ctx context.Context, ma var protoReq Body var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -888,6 +1045,66 @@ func RegisterABitOfEverythingServiceHandlerClient(ctx context.Context, mux *runt }) + mux.Handle("PUT", pattern_ABitOfEverythingService_UpdateV2_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_ABitOfEverythingService_UpdateV2_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_ABitOfEverythingService_UpdateV2_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("PATCH", pattern_ABitOfEverythingService_UpdateV2_1, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_ABitOfEverythingService_UpdateV2_1(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_ABitOfEverythingService_UpdateV2_1(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("PATCH", pattern_ABitOfEverythingService_PatchWithFieldMaskInBody_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_ABitOfEverythingService_PatchWithFieldMaskInBody_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_ABitOfEverythingService_PatchWithFieldMaskInBody_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("DELETE", pattern_ABitOfEverythingService_Delete_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -1120,6 +1337,12 @@ var ( pattern_ABitOfEverythingService_Update_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "example", "a_bit_of_everything", "uuid"}, "")) + pattern_ABitOfEverythingService_UpdateV2_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v2", "example", "a_bit_of_everything", "abe.uuid"}, "")) + + pattern_ABitOfEverythingService_UpdateV2_1 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v2", "example", "a_bit_of_everything", "abe.uuid"}, "")) + + pattern_ABitOfEverythingService_PatchWithFieldMaskInBody_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v2a", "example", "a_bit_of_everything", "abe.uuid"}, "")) + pattern_ABitOfEverythingService_Delete_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "example", "a_bit_of_everything", "uuid"}, "")) pattern_ABitOfEverythingService_GetQuery_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"v1", "example", "a_bit_of_everything", "query", "uuid"}, "")) @@ -1152,6 +1375,12 @@ var ( forward_ABitOfEverythingService_Update_0 = runtime.ForwardResponseMessage + forward_ABitOfEverythingService_UpdateV2_0 = runtime.ForwardResponseMessage + + forward_ABitOfEverythingService_UpdateV2_1 = runtime.ForwardResponseMessage + + forward_ABitOfEverythingService_PatchWithFieldMaskInBody_0 = runtime.ForwardResponseMessage + forward_ABitOfEverythingService_Delete_0 = runtime.ForwardResponseMessage forward_ABitOfEverythingService_GetQuery_0 = runtime.ForwardResponseMessage diff --git a/examples/proto/examplepb/a_bit_of_everything.proto b/examples/proto/examplepb/a_bit_of_everything.proto index d7a91bf4d8e..e07b09789d5 100644 --- a/examples/proto/examplepb/a_bit_of_everything.proto +++ b/examples/proto/examplepb/a_bit_of_everything.proto @@ -3,6 +3,7 @@ option go_package = "examplepb"; package grpc.gateway.examples.examplepb; import "google/api/annotations.proto"; +import "google/protobuf/field_mask.proto"; import "google/protobuf/empty.proto"; import "google/protobuf/duration.proto"; import "examples/proto/pathenum/path_enum.proto"; @@ -239,6 +240,12 @@ enum NumericEnum { ONE = 1; } +// UpdateV2Request request for update includes the message and the update mask +message UpdateV2Request { + ABitOfEverything abe = 1; + google.protobuf.FieldMask update_mask = 2; +} + // ABitOfEverything service is used to validate that APIs with complicated // proto messages and URL templates are still processed correctly. service ABitOfEverythingService { @@ -276,6 +283,22 @@ service ABitOfEverythingService { body: "*" }; } + rpc UpdateV2(UpdateV2Request) returns (google.protobuf.Empty) { + option (google.api.http) = { + put: "/v2/example/a_bit_of_everything/{abe.uuid}" + body: "abe" + additional_bindings { + patch: "/v2/example/a_bit_of_everything/{abe.uuid}" + body: "abe" + } + }; + } + rpc PatchWithFieldMaskInBody(UpdateV2Request) returns (google.protobuf.Empty) { + option (google.api.http) = { + patch: "/v2a/example/a_bit_of_everything/{abe.uuid}" + body: "*" + }; + } rpc Delete(sub2.IdMessage) returns (google.protobuf.Empty) { option (google.api.http) = { delete: "/v1/example/a_bit_of_everything/{uuid}" diff --git a/examples/proto/examplepb/a_bit_of_everything.swagger.json b/examples/proto/examplepb/a_bit_of_everything.swagger.json index 61c1023786e..b3249e62612 100644 --- a/examples/proto/examplepb/a_bit_of_everything.swagger.json +++ b/examples/proto/examplepb/a_bit_of_everything.swagger.json @@ -953,6 +953,100 @@ ] } }, + "/v2/example/a_bit_of_everything/{abe.uuid}": { + "put": { + "operationId": "UpdateV2", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/protobufEmpty" + } + }, + "403": { + "description": "Returned when the user does not have permission to access the resource.", + "schema": {} + }, + "404": { + "description": "Returned when the resource does not exist.", + "schema": { + "format": "string" + } + }, + "418": { + "description": "I'm a teapot.", + "schema": { + "$ref": "#/definitions/examplepbNumericEnum" + } + } + }, + "parameters": [ + { + "name": "abe.uuid", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/examplepbABitOfEverything" + } + } + ], + "tags": [ + "ABitOfEverythingService" + ] + }, + "patch": { + "operationId": "UpdateV22", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/protobufEmpty" + } + }, + "403": { + "description": "Returned when the user does not have permission to access the resource.", + "schema": {} + }, + "404": { + "description": "Returned when the resource does not exist.", + "schema": { + "format": "string" + } + }, + "418": { + "description": "I'm a teapot.", + "schema": { + "$ref": "#/definitions/examplepbNumericEnum" + } + } + }, + "parameters": [ + { + "name": "abe.uuid", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/examplepbABitOfEverything" + } + } + ], + "tags": [ + "ABitOfEverythingService" + ] + } + }, "/v2/example/echo": { "get": { "summary": "Summary: Echo rpc", @@ -1250,6 +1344,54 @@ "ABitOfEverythingService" ] } + }, + "/v2a/example/a_bit_of_everything/{abe.uuid}": { + "patch": { + "operationId": "PatchWithFieldMaskInBody", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/protobufEmpty" + } + }, + "403": { + "description": "Returned when the user does not have permission to access the resource.", + "schema": {} + }, + "404": { + "description": "Returned when the resource does not exist.", + "schema": { + "format": "string" + } + }, + "418": { + "description": "I'm a teapot.", + "schema": { + "$ref": "#/definitions/examplepbNumericEnum" + } + } + }, + "parameters": [ + { + "name": "abe.uuid", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/examplepbUpdateV2Request" + } + } + ], + "tags": [ + "ABitOfEverythingService" + ] + } } }, "definitions": { @@ -1561,6 +1703,18 @@ "default": "ZERO", "description": "NumericEnum is one or zero.\n\n - ZERO: ZERO means 0\n - ONE: ONE means 1" }, + "examplepbUpdateV2Request": { + "type": "object", + "properties": { + "abe": { + "$ref": "#/definitions/examplepbABitOfEverything" + }, + "update_mask": { + "$ref": "#/definitions/protobufFieldMask" + } + }, + "title": "UpdateV2Request request for update includes the message and the update mask" + }, "pathenumPathEnum": { "type": "string", "enum": [ @@ -1574,6 +1728,20 @@ "description": "service Foo {\n rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);\n }\n\nThe JSON representation for `Empty` is empty JSON object `{}`.", "title": "A generic empty message that you can re-use to avoid defining duplicated\nempty messages in your APIs. A typical example is to use it as the request\nor the response type of an API method. For instance:" }, + "protobufFieldMask": { + "type": "object", + "properties": { + "paths": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The set of field mask paths." + } + }, + "description": "paths: \"f.a\"\n paths: \"f.b.d\"\n\nHere `f` represents a field in some root message, `a` and `b`\nfields in the message found in `f`, and `d` a field found in the\nmessage in `f.b`.\n\nField masks are used to specify a subset of fields that should be\nreturned by a get operation or modified by an update operation.\nField masks also have a custom JSON encoding (see below).\n\n# Field Masks in Projections\n\nWhen used in the context of a projection, a response message or\nsub-message is filtered by the API to only contain those fields as\nspecified in the mask. For example, if the mask in the previous\nexample is applied to a response message as follows:\n\n f {\n a : 22\n b {\n d : 1\n x : 2\n }\n y : 13\n }\n z: 8\n\nThe result will not contain specific values for fields x,y and z\n(their value will be set to the default, and omitted in proto text\noutput):\n\n\n f {\n a : 22\n b {\n d : 1\n }\n }\n\nA repeated field is not allowed except at the last position of a\npaths string.\n\nIf a FieldMask object is not present in a get operation, the\noperation applies to all fields (as if a FieldMask of all fields\nhad been specified).\n\nNote that a field mask does not necessarily apply to the\ntop-level response message. In case of a REST get operation, the\nfield mask applies directly to the response, but in case of a REST\nlist operation, the mask instead applies to each individual message\nin the returned resource list. In case of a REST custom method,\nother definitions may be used. Where the mask applies will be\nclearly documented together with its declaration in the API. In\nany case, the effect on the returned resource/resources is required\nbehavior for APIs.\n\n# Field Masks in Update Operations\n\nA field mask in update operations specifies which fields of the\ntargeted resource are going to be updated. The API is required\nto only change the values of the fields as specified in the mask\nand leave the others untouched. If a resource is passed in to\ndescribe the updated values, the API ignores the values of all\nfields not covered by the mask.\n\nIf a repeated field is specified for an update operation, the existing\nrepeated values in the target resource will be overwritten by the new values.\nNote that a repeated field is only allowed in the last position of a `paths`\nstring.\n\nIf a sub-message is specified in the last position of the field mask for an\nupdate operation, then the existing sub-message in the target resource is\noverwritten. Given the target message:\n\n f {\n b {\n d : 1\n x : 2\n }\n c : 1\n }\n\nAnd an update message:\n\n f {\n b {\n d : 10\n }\n }\n\nthen if the field mask is:\n\n paths: \"f.b\"\n\nthen the result will be:\n\n f {\n b {\n d : 10\n }\n c : 1\n }\n\nHowever, if the update mask was:\n\n paths: \"f.b.d\"\n\nthen the result would be:\n\n f {\n b {\n d : 10\n x : 2\n }\n c : 1\n }\n\nIn order to reset a field's value to the default, the field must\nbe in the mask and set to the default value in the provided resource.\nHence, in order to reset all fields of a resource, provide a default\ninstance of the resource and set all fields in the mask, or do\nnot provide a mask as described below.\n\nIf a field mask is not present on update, the operation applies to\nall fields (as if a field mask of all fields has been specified).\nNote that in the presence of schema evolution, this may mean that\nfields the client does not know and has therefore not filled into\nthe request will be reset to their default. If this is unwanted\nbehavior, a specific service may require a client to always specify\na field mask, producing an error if not.\n\nAs with get operations, the location of the resource which\ndescribes the updated values in the request message depends on the\noperation kind. In any case, the effect of the field mask is\nrequired to be honored by the API.\n\n## Considerations for HTTP REST\n\nThe HTTP kind of an update operation which uses a field mask must\nbe set to PATCH instead of PUT in order to satisfy HTTP semantics\n(PUT must only be used for full updates).\n\n# JSON Encoding of Field Masks\n\nIn JSON, a field mask is encoded as a single string where paths are\nseparated by a comma. Fields name in each path are converted\nto/from lower-camel naming conventions.\n\nAs an example, consider the following message declarations:\n\n message Profile {\n User user = 1;\n Photo photo = 2;\n }\n message User {\n string display_name = 1;\n string address = 2;\n }\n\nIn proto a field mask for `Profile` may look as such:\n\n mask {\n paths: \"user.display_name\"\n paths: \"photo\"\n }\n\nIn JSON, the same mask is represented as below:\n\n {\n mask: \"user.displayName,photo\"\n }\n\n# Field Masks and Oneof Fields\n\nField masks treat fields in oneofs just as regular fields. Consider the\nfollowing message:\n\n message SampleMessage {\n oneof test_oneof {\n string name = 4;\n SubMessage sub_message = 9;\n }\n }\n\nThe field mask can be:\n\n mask {\n paths: \"name\"\n }\n\nOr:\n\n mask {\n paths: \"sub_message\"\n }\n\nNote that oneof type names (\"test_oneof\" in this case) cannot be used in\npaths.", + "title": "`FieldMask` represents a set of symbolic field paths, for example:" + }, "subStringMessage": { "type": "object", "properties": { diff --git a/examples/proto/examplepb/echo_service.pb.gw.go b/examples/proto/examplepb/echo_service.pb.gw.go index ca6579265e0..5e9efc9beac 100644 --- a/examples/proto/examplepb/echo_service.pb.gw.go +++ b/examples/proto/examplepb/echo_service.pb.gw.go @@ -272,7 +272,11 @@ func request_EchoService_EchoBody_0(ctx context.Context, marshaler runtime.Marsh var protoReq SimpleMessage var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } diff --git a/examples/proto/examplepb/flow_combination.pb.gw.go b/examples/proto/examplepb/flow_combination.pb.gw.go index a20cf605711..b4ae06a19d7 100644 --- a/examples/proto/examplepb/flow_combination.pb.gw.go +++ b/examples/proto/examplepb/flow_combination.pb.gw.go @@ -61,7 +61,11 @@ func request_FlowCombination_StreamEmptyRpc_0(ctx context.Context, marshaler run grpclog.Infof("Failed to start streaming: %v", err) return nil, metadata, err } - dec := marshaler.NewDecoder(req.Body) + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + dec := marshaler.NewDecoder(newReader()) for { var protoReq EmptyProto err = dec.Decode(&protoReq) @@ -102,7 +106,11 @@ func request_FlowCombination_StreamEmptyStream_0(ctx context.Context, marshaler grpclog.Infof("Failed to start streaming: %v", err) return nil, metadata, err } - dec := marshaler.NewDecoder(req.Body) + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, berr + } + dec := marshaler.NewDecoder(newReader()) handleSend := func() error { var protoReq EmptyProto err := dec.Decode(&protoReq) @@ -151,7 +159,11 @@ func request_FlowCombination_RpcBodyRpc_0(ctx context.Context, marshaler runtime var protoReq NonEmptyProto var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -230,7 +242,11 @@ func request_FlowCombination_RpcBodyRpc_3(ctx context.Context, marshaler runtime var protoReq NonEmptyProto var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.C); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.C); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -276,7 +292,11 @@ func request_FlowCombination_RpcBodyRpc_4(ctx context.Context, marshaler runtime var protoReq NonEmptyProto var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.C); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.C); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -297,7 +317,11 @@ func request_FlowCombination_RpcBodyRpc_5(ctx context.Context, marshaler runtime var protoReq NonEmptyProto var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.C); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.C); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -406,7 +430,11 @@ func request_FlowCombination_RpcPathNestedRpc_0(ctx context.Context, marshaler r var protoReq NestedProto var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.C); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.C); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -491,7 +519,11 @@ func request_FlowCombination_RpcPathNestedRpc_2(ctx context.Context, marshaler r var protoReq NestedProto var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.C); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.C); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -526,7 +558,11 @@ func request_FlowCombination_RpcBodyStream_0(ctx context.Context, marshaler runt var protoReq NonEmptyProto var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -629,7 +665,11 @@ func request_FlowCombination_RpcBodyStream_3(ctx context.Context, marshaler runt var protoReq NonEmptyProto var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.C); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.C); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -683,7 +723,11 @@ func request_FlowCombination_RpcBodyStream_4(ctx context.Context, marshaler runt var protoReq NonEmptyProto var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.C); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.C); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -712,7 +756,11 @@ func request_FlowCombination_RpcBodyStream_5(ctx context.Context, marshaler runt var protoReq NonEmptyProto var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.C); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.C); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -845,7 +893,11 @@ func request_FlowCombination_RpcPathNestedStream_0(ctx context.Context, marshale var protoReq NestedProto var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.C); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.C); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -946,7 +998,11 @@ func request_FlowCombination_RpcPathNestedStream_2(ctx context.Context, marshale var protoReq NestedProto var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.C); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.C); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } diff --git a/examples/proto/examplepb/stream.pb.gw.go b/examples/proto/examplepb/stream.pb.gw.go index a62da50e2a0..f43c517b17e 100644 --- a/examples/proto/examplepb/stream.pb.gw.go +++ b/examples/proto/examplepb/stream.pb.gw.go @@ -37,7 +37,11 @@ func request_StreamService_BulkCreate_0(ctx context.Context, marshaler runtime.M grpclog.Infof("Failed to start streaming: %v", err) return nil, metadata, err } - dec := marshaler.NewDecoder(req.Body) + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + dec := marshaler.NewDecoder(newReader()) for { var protoReq ABitOfEverything err = dec.Decode(&protoReq) @@ -95,7 +99,11 @@ func request_StreamService_BulkEcho_0(ctx context.Context, marshaler runtime.Mar grpclog.Infof("Failed to start streaming: %v", err) return nil, metadata, err } - dec := marshaler.NewDecoder(req.Body) + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, berr + } + dec := marshaler.NewDecoder(newReader()) handleSend := func() error { var protoReq sub.StringMessage err := dec.Decode(&protoReq) diff --git a/examples/proto/examplepb/unannotated_echo_service.pb.gw.go b/examples/proto/examplepb/unannotated_echo_service.pb.gw.go index 90bcbbd39f0..01764c0f9e6 100644 --- a/examples/proto/examplepb/unannotated_echo_service.pb.gw.go +++ b/examples/proto/examplepb/unannotated_echo_service.pb.gw.go @@ -113,7 +113,11 @@ func request_UnannotatedEchoService_EchoBody_0(ctx context.Context, marshaler ru var protoReq UnannotatedSimpleMessage var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } diff --git a/examples/proto/examplepb/wrappers.pb.gw.go b/examples/proto/examplepb/wrappers.pb.gw.go index f603e0283a2..7e95a4c6163 100644 --- a/examples/proto/examplepb/wrappers.pb.gw.go +++ b/examples/proto/examplepb/wrappers.pb.gw.go @@ -32,7 +32,11 @@ func request_WrappersService_Create_0(ctx context.Context, marshaler runtime.Mar var protoReq Wrappers var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } diff --git a/examples/server/a_bit_of_everything.go b/examples/server/a_bit_of_everything.go index 4f433654749..384638cab31 100644 --- a/examples/server/a_bit_of_everything.go +++ b/examples/server/a_bit_of_everything.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "io" + "strings" "sync" "github.com/golang/glog" @@ -11,8 +12,8 @@ import ( "github.com/golang/protobuf/ptypes/duration" "github.com/golang/protobuf/ptypes/empty" examples "github.com/grpc-ecosystem/grpc-gateway/examples/proto/examplepb" - sub "github.com/grpc-ecosystem/grpc-gateway/examples/proto/sub" - sub2 "github.com/grpc-ecosystem/grpc-gateway/examples/proto/sub2" + "github.com/grpc-ecosystem/grpc-gateway/examples/proto/sub" + "github.com/grpc-ecosystem/grpc-gateway/examples/proto/sub2" "github.com/rogpeppe/fastuuid" "google.golang.org/genproto/googleapis/rpc/errdetails" "google.golang.org/grpc" @@ -161,6 +162,39 @@ func (s *_ABitOfEverythingServer) Update(ctx context.Context, msg *examples.ABit return new(empty.Empty), nil } +func (s *_ABitOfEverythingServer) UpdateV2(ctx context.Context, msg *examples.UpdateV2Request) (*empty.Empty, error) { + glog.Info(msg) + // If there is no update mask do a regular update + if msg.UpdateMask == nil || len(msg.UpdateMask.GetPaths()) == 0 { + return s.Update(ctx, msg.Abe) + } + + s.m.Lock() + defer s.m.Unlock() + if a, ok := s.v[msg.Abe.Uuid]; ok { + applyFieldMask(a, msg.Abe, msg.UpdateMask) + } else { + return nil, status.Errorf(codes.NotFound, "not found") + } + return new(empty.Empty), nil +} + +// PatchWithFieldMaskInBody differs from UpdateV2 only in that this method exposes the field mask in the request body, +// so that clients can specify their mask explicitly +func (s *_ABitOfEverythingServer) PatchWithFieldMaskInBody(ctx context.Context, request *examples.UpdateV2Request) (*empty.Empty, error) { + // low-effort attempt to modify the field mask to only include paths for the ABE struct. Since this is only for the + // integration tests, this narrow implementaion is fine. + if request.UpdateMask != nil { + var shifted []string + for _, path := range request.UpdateMask.GetPaths() { + shifted = append(shifted, strings.TrimPrefix(path, "Abe.")) + } + request.UpdateMask.Paths = shifted + } + + return s.UpdateV2(ctx, request) +} + func (s *_ABitOfEverythingServer) Delete(ctx context.Context, msg *sub2.IdMessage) (*empty.Empty, error) { s.m.Lock() defer s.m.Unlock() diff --git a/examples/server/fieldmask_helper.go b/examples/server/fieldmask_helper.go new file mode 100644 index 00000000000..d0cac43c58f --- /dev/null +++ b/examples/server/fieldmask_helper.go @@ -0,0 +1,55 @@ +package server + +import ( + "log" + "reflect" + "strings" + + "google.golang.org/genproto/protobuf/field_mask" +) + +func applyFieldMask(patchee, patcher interface{}, mask *field_mask.FieldMask) { + if mask == nil { + return + } + + for _, path := range mask.GetPaths() { + val := getField(patcher, path) + if val.IsValid() { + setValue(patchee, val, path) + } + } +} + +func getField(obj interface{}, path string) (val reflect.Value) { + // this func is lazy -- if anything bad happens just return nil + defer func() { + if r := recover(); r != nil { + log.Printf("failed to get field:\npath: %q\nobj: %#v\nerr: %v", path, obj, r) + val = reflect.Value{} + } + }() + + v := reflect.ValueOf(obj) + if len(path) == 0 { + return v + } + + for _, s := range strings.Split(path, ".") { + if v.Kind() == reflect.Ptr { + v = reflect.Indirect(v) + } + v = v.FieldByName(s) + } + + return v +} + +func setValue(obj interface{}, newValue reflect.Value, path string) { + defer func() { + if r := recover(); r != nil { + log.Printf("failed to set value:\nnewValue: %#v\npath: %q\nobj: %#v\nerr: %v", newValue, path, obj, r) + } + }() + getField(obj, path).Set(newValue) +} diff --git a/examples/server/fieldmask_helper_test.go b/examples/server/fieldmask_helper_test.go new file mode 100644 index 00000000000..c735fdd7aca --- /dev/null +++ b/examples/server/fieldmask_helper_test.go @@ -0,0 +1,92 @@ +package server + +import ( + "reflect" + "testing" + + "google.golang.org/genproto/protobuf/field_mask" +) + +func TestApplyFieldMask(t *testing.T) { + for _, test := range []struct { + name string + patchee interface{} + patcher interface{} + fieldMask *field_mask.FieldMask + expected interface{} + }{ + {"nil fieldMask", &a{E: 64}, &a{E: 42}, nil, &a{E: 64}}, + {"empty paths", &a{E: 63}, &a{E: 42}, &field_mask.FieldMask{}, &a{E: 63}}, + {"simple path", &a{E: 23, F: "test"}, &a{B: &b{}, E: 42}, &field_mask.FieldMask{Paths: []string{"E"}}, &a{E: 42, F: "test"}}, + {"nested", &a{B: &b{C: 85}}, &a{B: &b{C: 58, D: nil}}, &field_mask.FieldMask{Paths: []string{"B.C"}}, &a{B: &b{C: 58}}}, + {"multiple paths", &a{B: &b{C: 40, D: []int{1, 2, 3}}, E: 34, F: "catapult"}, &a{B: &b{C: 56}, F: "lettuce"}, &field_mask.FieldMask{Paths: []string{"B.C", "F"}}, &a{B: &b{C: 56, D: []int{1, 2, 3}}, E: 34, F: "lettuce"}}, + } { + t.Run(test.name, func(t *testing.T) { + applyFieldMask(test.patchee, test.patcher, test.fieldMask) + if !reflect.DeepEqual(test.patchee, test.expected) { + t.Errorf("expected %v, but was %v", test.expected, test.patchee) + } + }) + } +} + +func TestGetValue(t *testing.T) { + for _, test := range []struct { + name string + input interface{} + path string + expected interface{} + }{ + {"empty", &a{E: 45, F: "test"}, "", &a{E: 45, F: "test"}}, + {"pointer-simple", &a{E: 45}, "E", 45}, + {"pointer-nested", &a{B: &b{C: 42}}, "B.C", 42}, + {"pointer-complex type", &a{B: &b{D: []int{1, 2}}}, "B.D", []int{1, 2}}, + {"pointer-invalid path", &a{F: "test"}, "X.Y", nil}, + {"simple", a{E: 45}, "E", 45}, + {"nested", a{B: &b{C: 42}}, "B.C", 42}, + {"complex type", a{B: &b{D: []int{1, 2}}}, "B.D", []int{1, 2}}, + {"invalid path", a{F: "test"}, "X.Y", nil}, + } { + t.Run(test.name, func(t *testing.T) { + if actual := getField(test.input, test.path); actual.IsValid() { + if !reflect.DeepEqual(test.expected, actual.Interface()) { + t.Errorf("expected %v, but got %v", test.expected, actual) + } + } else if test.expected != nil { + t.Errorf("expected nil, but was %v", actual) + } + }) + } +} + +func TestSetValue(t *testing.T) { + for _, test := range []struct { + name string + obj interface{} + newValue interface{} + path string + expected interface{} + }{ + {"simple", &a{E: 45}, 34, "E", 34}, + {"nested", &a{B: &b{C: 54}}, 43, "B.C", 43}, + {"complex type", &a{B: &b{D: []int{1, 2}}}, []int{3, 4}, "B.D", []int{3, 4}}, + } { + t.Run(test.name, func(t *testing.T) { + setValue(test.obj, reflect.ValueOf(test.newValue), test.path) + if actual := getField(test.obj, test.path).Interface(); !reflect.DeepEqual(actual, test.expected) { + t.Errorf("expected %v, but got %v", test.newValue, actual) + } + }) + } +} + +type a struct { + B *b + E int + F string +} + +type b struct { + C int + D []int +} diff --git a/protoc-gen-grpc-gateway/gengateway/template.go b/protoc-gen-grpc-gateway/gengateway/template.go index 7db03cca64e..fad1392c0c0 100644 --- a/protoc-gen-grpc-gateway/gengateway/template.go +++ b/protoc-gen-grpc-gateway/gengateway/template.go @@ -7,6 +7,7 @@ import ( "text/template" "github.com/golang/glog" + generator2 "github.com/golang/protobuf/protoc-gen-go/generator" "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor" "github.com/grpc-ecosystem/grpc-gateway/utilities" ) @@ -23,6 +24,14 @@ type binding struct { Registry *descriptor.Registry } +// GetBodyFieldPath returns the binding body's fieldpath. +func (b binding) GetBodyFieldPath() string { + if b.Body != nil && len(b.Body.FieldPath) != 0 { + return b.Body.FieldPath.String() + } + return "*" +} + // HasQueryParam determines if the binding needs parameters in query string. // // It sometimes returns true even though actually the binding does not need. @@ -88,6 +97,26 @@ func (b binding) LookupEnum(p descriptor.Parameter) *descriptor.Enum { return e } +// FieldMaskField returns the golang-style name of the variable for a FieldMask, if there is exactly one of that type in +// the message. Otherwise, it returns an empty string. +func (b binding) FieldMaskField() string { + var fieldMaskField *descriptor.Field + for _, f := range b.Method.RequestType.Fields { + if f.GetTypeName() == ".google.protobuf.FieldMask" { + // if there is more than 1 FieldMask for this request, then return none + if fieldMaskField != nil { + return "" + } + fieldMaskField = f + } + } + + if fieldMaskField != nil { + return generator2.CamelCase(fieldMaskField.GetName()) + } + return "" +} + // queryParamFilter is a wrapper of utilities.DoubleArray which provides String() to output DoubleArray.Encoding in a stable and predictable format. type queryParamFilter struct { *utilities.DoubleArray @@ -197,7 +226,11 @@ func request_{{.Method.Service.GetName}}_{{.Method.GetName}}_{{.Index}}(ctx cont grpclog.Infof("Failed to start streaming: %v", err) return nil, metadata, err } - dec := marshaler.NewDecoder(req.Body) + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + dec := marshaler.NewDecoder(newReader()) for { var protoReq {{.Method.RequestType.GoType .Method.Service.File.GoPkg.Path}} err = dec.Decode(&protoReq) @@ -244,9 +277,24 @@ var ( var protoReq {{.Method.RequestType.GoType .Method.Service.File.GoPkg.Path}} var metadata runtime.ServerMetadata {{if .Body}} - if err := marshaler.NewDecoder(req.Body).Decode(&{{.Body.AssignableExpr "protoReq"}}); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&{{.Body.AssignableExpr "protoReq"}}); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + {{- if and (eq (.HTTPMethod) "PATCH") (.FieldMaskField)}} + if protoReq.{{.FieldMaskField}} != nil && len(protoReq.{{.FieldMaskField}}.GetPaths()) > 0 { + runtime.CamelCaseFieldMask(protoReq.{{.FieldMaskField}}) + } {{if not (eq "*" .GetBodyFieldPath)}} else { + if fieldMask, err := runtime.FieldMaskFromRequestBody(newReader()); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } else { + protoReq.{{.FieldMaskField}} = fieldMask + } + } {{end}} + {{end}} {{end}} {{if .PathParams}} var ( @@ -319,7 +367,11 @@ var ( grpclog.Infof("Failed to start streaming: %v", err) return nil, metadata, err } - dec := marshaler.NewDecoder(req.Body) + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, berr + } + dec := marshaler.NewDecoder(newReader()) handleSend := func() error { var protoReq {{.Method.RequestType.GoType .Method.Service.File.GoPkg.Path}} err := dec.Decode(&protoReq) diff --git a/protoc-gen-grpc-gateway/gengateway/template_test.go b/protoc-gen-grpc-gateway/gengateway/template_test.go index 3f1313a7ddc..ca9e587a69d 100644 --- a/protoc-gen-grpc-gateway/gengateway/template_test.go +++ b/protoc-gen-grpc-gateway/gengateway/template_test.go @@ -230,7 +230,7 @@ func TestApplyTemplateRequestWithoutClientStreaming(t *testing.T) { if want := spec.sigWant; !strings.Contains(got, want) { t.Errorf("applyTemplate(%#v) = %s; want to contain %s", file, got, want) } - if want := `marshaler.NewDecoder(req.Body).Decode(&protoReq.GetNested().Bool)`; !strings.Contains(got, want) { + if want := `marshaler.NewDecoder(newReader()).Decode(&protoReq.GetNested().Bool)`; !strings.Contains(got, want) { t.Errorf("applyTemplate(%#v) = %s; want to contain %s", file, got, want) } if want := `val, ok = pathParams["nested.int32"]`; !strings.Contains(got, want) { @@ -391,7 +391,7 @@ func TestApplyTemplateRequestWithClientStreaming(t *testing.T) { if want := spec.sigWant; !strings.Contains(got, want) { t.Errorf("applyTemplate(%#v) = %s; want to contain %s", file, got, want) } - if want := `marshaler.NewDecoder(req.Body)`; !strings.Contains(got, want) { + if want := `marshaler.NewDecoder(newReader()`; !strings.Contains(got, want) { t.Errorf("applyTemplate(%#v) = %s; want to contain %s", file, got, want) } if want := `func RegisterExampleServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {`; !strings.Contains(got, want) { diff --git a/runtime/fieldmask.go b/runtime/fieldmask.go new file mode 100644 index 00000000000..e1cf7a91461 --- /dev/null +++ b/runtime/fieldmask.go @@ -0,0 +1,70 @@ +package runtime + +import ( + "encoding/json" + "io" + "strings" + + "github.com/golang/protobuf/protoc-gen-go/generator" + "google.golang.org/genproto/protobuf/field_mask" +) + +// FieldMaskFromRequestBody creates a FieldMask printing all complete paths from the JSON body. +func FieldMaskFromRequestBody(r io.Reader) (*field_mask.FieldMask, error) { + fm := &field_mask.FieldMask{} + var root interface{} + if err := json.NewDecoder(r).Decode(&root); err != nil { + if err == io.EOF { + return fm, nil + } + return nil, err + } + + queue := []fieldMaskPathItem{{node: root}} + for len(queue) > 0 { + // dequeue an item + item := queue[0] + queue = queue[1:] + + if m, ok := item.node.(map[string]interface{}); ok { + // if the item is an object, then enqueue all of its children + for k, v := range m { + queue = append(queue, fieldMaskPathItem{path: append(item.path, generator.CamelCase(k)), node: v}) + } + } else if len(item.path) > 0 { + // otherwise, it's a leaf node so print its path + fm.Paths = append(fm.Paths, strings.Join(item.path, ".")) + } + } + + return fm, nil +} + +// fieldMaskPathItem stores a in-progress deconstruction of a path for a fieldmask +type fieldMaskPathItem struct { + // the list of prior fields leading up to node + path []string + + // a generic decoded json object the current item to inspect for further path extraction + node interface{} +} + +// CamelCaseFieldMask updates the given FieldMask by converting all of its paths to CamelCase, using the same heuristic +// that's used for naming protobuf fields in Go. +func CamelCaseFieldMask(mask *field_mask.FieldMask) { + if mask == nil || mask.Paths == nil { + return + } + + var newPaths []string + for _, path := range mask.Paths { + lowerCasedParts := strings.Split(path, ".") + var camelCasedParts []string + for _, part := range lowerCasedParts { + camelCasedParts = append(camelCasedParts, generator.CamelCase(part)) + } + newPaths = append(newPaths, strings.Join(camelCasedParts, ".")) + } + + mask.Paths = newPaths +} diff --git a/runtime/fieldmask_test.go b/runtime/fieldmask_test.go new file mode 100644 index 00000000000..3c097878aa0 --- /dev/null +++ b/runtime/fieldmask_test.go @@ -0,0 +1,87 @@ +package runtime + +import ( + "bytes" + "fmt" + "testing" + + "google.golang.org/genproto/protobuf/field_mask" +) + +func fieldMasksEqual(fm1, fm2 *field_mask.FieldMask) bool { + if fm1 == nil && fm2 == nil { + return true + } + if fm1 == nil || fm2 == nil { + return false + } + if len(fm1.GetPaths()) != len(fm2.GetPaths()) { + return false + } + + paths := make(map[string]bool) + for _, path := range fm1.GetPaths() { + paths[path] = true + } + for _, path := range fm2.GetPaths() { + if _, ok := paths[path]; !ok { + return false + } + } + + return true +} + +func newFieldMask(paths ...string) *field_mask.FieldMask { + return &field_mask.FieldMask{Paths: paths} +} + +func fieldMaskString(fm *field_mask.FieldMask) string { + if fm == nil { + return "" + } + return fmt.Sprintf("%v", fm.GetPaths()) +} + +func TestFieldMaskFromRequestBody(t *testing.T) { + for _, tc := range []struct { + name string + input string + expected *field_mask.FieldMask + expectedErr error + }{ + {name: "empty", expected: newFieldMask()}, + {name: "simple", input: `{"foo":1, "bar":"baz"}`, expected: newFieldMask("Foo", "Bar")}, + {name: "nested", input: `{"foo": {"bar":1, "baz": 2}, "qux": 3}`, expected: newFieldMask("Foo.Bar", "Foo.Baz", "Qux")}, + {name: "canonical", input: `{"f": {"b": {"d": 1, "x": 2}, "c": 1}}`, expected: newFieldMask("F.B.D", "F.B.X", "F.C")}, + } { + t.Run(tc.name, func(t *testing.T) { + actual, err := FieldMaskFromRequestBody(bytes.NewReader([]byte(tc.input))) + if !fieldMasksEqual(actual, tc.expected) { + t.Errorf("want %v; got %v", fieldMaskString(tc.expected), fieldMaskString(actual)) + } + if err != tc.expectedErr { + t.Errorf("want %v; got %v", tc.expectedErr, err) + } + }) + } +} + +func TestCamelCaseFieldMask(t *testing.T) { + for _, tc := range []struct { + name string + input *field_mask.FieldMask + expected *field_mask.FieldMask + }{ + {"nil", nil, nil}, + {"empty", &field_mask.FieldMask{Paths: nil}, &field_mask.FieldMask{Paths: nil}}, + {"main usage", newFieldMask("a", "a.b", "some_field.some_sub_field"), newFieldMask("A", "A.B", "SomeField.SomeSubField")}, + } { + t.Run(tc.name, func(t *testing.T) { + CamelCaseFieldMask(tc.input) + if expected, actual := tc.expected, tc.input; !fieldMasksEqual(expected, actual) { + t.Errorf("want %v; got %v", fieldMaskString(expected), fieldMaskString(actual)) + } + }) + } +} diff --git a/utilities/readerfactory.go b/utilities/readerfactory.go new file mode 100644 index 00000000000..6dd3854665f --- /dev/null +++ b/utilities/readerfactory.go @@ -0,0 +1,20 @@ +package utilities + +import ( + "bytes" + "io" + "io/ioutil" +) + +// IOReaderFactory takes in an io.Reader and returns a function that will allow you to create a new reader that begins +// at the start of the stream +func IOReaderFactory(r io.Reader) (func() io.Reader, error) { + b, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + + return func() io.Reader { + return bytes.NewReader(b) + }, nil +} From 73373e5bf2362d891afcaa78ee9201b6dc92df96 Mon Sep 17 00:00:00 2001 From: Rodrigo Queiro Date: Wed, 14 Nov 2018 14:51:26 +0100 Subject: [PATCH 2/7] Make Bazel CI failures clearer (#807) * Make Bazel CI failures clearer - don't try to run tests if the BUILD files are out-of-date - run buildifier even if the tests fail, as it may still be useful - use a parameter to hold Bazel config to simplify config.yml - ignore the vendor/ directory when running Gazelle (otherwise it will fail if you've used `dep` to create vendor/) * Add Bazel invocation to CONTRIBUTING.md --- .circleci/config.yml | 36 ++++++++++++++++++++++-------------- BUILD | 1 + CONTRIBUTING.md | 4 +++- 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 150455b5c21..b4189cd4638 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -50,23 +50,32 @@ jobs: - run: dep ensure --vendor-only - run: go get golang.org/x/lint/golint - run: make lint - bazel_lint: + bazel: docker: - image: l.gcr.io/google/bazel:latest working_directory: /go/src/github.com/grpc-ecosystem/grpc-gateway steps: - checkout - - run: 'bazel --output_base=$HOME/.cache/_grpc_gateway_bazel run //:buildifier_check || - (echo "Bazel files not formatted, please run \`bazel run :buildifier\`"; exit 1)' - - run: 'test -z "$(bazel --output_base=$HOME/.cache/_grpc_gateway_bazel run //:gazelle_diff)" || - (echo "Bazel files out-of-date, please run \`bazel run :gazelle_diff\`"; exit 1)' - bazel_test: - docker: - - image: l.gcr.io/google/bazel:latest - working_directory: /go/src/github.com/grpc-ecosystem/grpc-gateway - steps: - - checkout - - run: bazel --output_base=$HOME/.cache/_grpc_gateway_bazel test --test_output=errors --features=race //... + - run: + name: Create Bazel config file (.bazelrc) + command: | + cat > .bazelrc << EOF + startup --output_base $HOME/.cache/_grpc_gateway_bazel + build --test_output errors + build --features race + EOF + - run: + name: Check that Bazel BUILD files are up-to-date + command: 'test -z "$(bazel run //:gazelle_diff)" || + (echo "ERROR: Bazel files out-of-date, please run \`bazel run :gazelle_fix\`" >&2; exit 1)' + - run: + name: Run tests with Bazel + command: bazel test //... + - run: + name: Check formatting of Bazel BUILD files + command: 'bazel run //:buildifier_check || + (echo "ERROR: Bazel files not formatted, please run \`bazel run :buildifier\`" >&2; exit 1)' + when: always build_linux_release: docker: - image: jfbrandhorst/grpc-gateway-build-env @@ -153,8 +162,7 @@ workflows: - node_test - generate - lint - - bazel_lint - - bazel_test + - bazel - build_linux_release: filters: branches: diff --git a/BUILD b/BUILD index b72e9743bd8..a9997cb5a0e 100644 --- a/BUILD +++ b/BUILD @@ -11,6 +11,7 @@ buildifier( ) # gazelle:exclude third_party +# gazelle:exclude vendor gazelle( name = "gazelle_diff", diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8bcfb2794ca..a7d09ce6cb0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -24,10 +24,12 @@ All submissions, including submissions by project members, require review. Great, it should be as simple as thus (run from the root of the directory): ```bash -$ docker run -v $(pwd):/go/src/github.com/grpc-ecosystem/grpc-gateway --rm jfbrandhorst/grpc-gateway-build-env \ +docker run -v $(pwd):/go/src/github.com/grpc-ecosystem/grpc-gateway --rm jfbrandhorst/grpc-gateway-build-env \ /bin/bash -c 'cd /go/src/github.com/grpc-ecosystem/grpc-gateway && \ make realclean && \ make examples SWAGGER_CODEGEN="${SWAGGER_CODEGEN}"' +docker run -itv $(pwd):/grpc-gateway -w /grpc-gateway --entrypoint /bin/bash --rm \ + l.gcr.io/google/bazel -c 'bazel run :gazelle_fix; bazel run :buildifier' ``` If this has resulted in some file changes in the repo, please ensure you check those in with your merge request. From 165983158a39a3d3f7518f633e6260caba5194e8 Mon Sep 17 00:00:00 2001 From: Mayank Date: Wed, 14 Nov 2018 19:23:00 +0530 Subject: [PATCH 3/7] Adding support for more well known types in descriptor (#809) --- protoc-gen-grpc-gateway/descriptor/types.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/protoc-gen-grpc-gateway/descriptor/types.go b/protoc-gen-grpc-gateway/descriptor/types.go index 5cf9d597fb0..ada554b53a8 100644 --- a/protoc-gen-grpc-gateway/descriptor/types.go +++ b/protoc-gen-grpc-gateway/descriptor/types.go @@ -451,7 +451,16 @@ var ( } wellKnownTypeConv = map[string]string{ - ".google.protobuf.Timestamp": "runtime.Timestamp", - ".google.protobuf.Duration": "runtime.Duration", + ".google.protobuf.Timestamp": "runtime.Timestamp", + ".google.protobuf.Duration": "runtime.Duration", + ".google.protobuf.StringValue": "runtime.StringValue", + ".google.protobuf.BytesValue": "runtime.BytesValue", + ".google.protobuf.Int32Value": "runtime.Int32Value", + ".google.protobuf.UInt32Value": "runtime.UInt32Value", + ".google.protobuf.Int64Value": "runtime.Int64Value", + ".google.protobuf.UInt64Value": "runtime.UInt64Value", + ".google.protobuf.FloatValue": "runtime.FloatValue", + ".google.protobuf.DoubleValue": "runtime.DoubleValue", + ".google.protobuf.BoolValue": "runtime.BoolValue", } ) From db12ed14c78970feba2310b7dc2ac91f59b846b6 Mon Sep 17 00:00:00 2001 From: Roman Azami Date: Wed, 14 Nov 2018 22:03:50 -0800 Subject: [PATCH 4/7] Updated bazel builds to support field_mask dependencies --- codegenerator/BUILD.bazel | 4 ++-- examples/clients/abe/BUILD.bazel | 4 +++- examples/clients/echo/BUILD.bazel | 2 +- examples/clients/responsebody/BUILD.bazel | 2 +- examples/clients/unannotatedecho/BUILD.bazel | 2 +- .../cmd/example-gateway-server/BUILD.bazel | 2 +- examples/cmd/example-grpc-server/BUILD.bazel | 2 +- examples/gateway/BUILD.bazel | 4 ++-- examples/integration/BUILD.bazel | 7 +++--- examples/proto/examplepb/BUILD.bazel | 11 +++++---- examples/server/BUILD.bazel | 23 +++++++++++++------ protoc-gen-grpc-gateway/BUILD.bazel | 4 ++-- .../descriptor/BUILD.bazel | 8 +++---- .../gengateway/BUILD.bazel | 7 +++--- protoc-gen-grpc-gateway/httprule/BUILD.bazel | 4 ++-- protoc-gen-swagger/BUILD.bazel | 4 ++-- protoc-gen-swagger/genswagger/BUILD.bazel | 6 ++--- runtime/BUILD.bazel | 22 ++++++++++-------- utilities/BUILD.bazel | 1 + 19 files changed, 69 insertions(+), 50 deletions(-) diff --git a/codegenerator/BUILD.bazel b/codegenerator/BUILD.bazel index 651177fa157..d14983dcf4a 100644 --- a/codegenerator/BUILD.bazel +++ b/codegenerator/BUILD.bazel @@ -10,7 +10,7 @@ go_library( ], importpath = "github.com/grpc-ecosystem/grpc-gateway/codegenerator", deps = [ - "@com_github_golang_protobuf//proto:go_default_library", + "//vendor/github.com/golang/protobuf/proto:go_default_library", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", ], ) @@ -20,7 +20,7 @@ go_test( srcs = ["parse_req_test.go"], embed = [":go_default_library"], deps = [ - "@com_github_golang_protobuf//proto:go_default_library", + "//vendor/github.com/golang/protobuf/proto:go_default_library", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", ], ) diff --git a/examples/clients/abe/BUILD.bazel b/examples/clients/abe/BUILD.bazel index 6b61fa1b3fa..c9f40633f64 100644 --- a/examples/clients/abe/BUILD.bazel +++ b/examples/clients/abe/BUILD.bazel @@ -18,10 +18,12 @@ go_library( "examplepb_a_bit_of_everything_repeated.go", "examplepb_body.go", "examplepb_numeric_enum.go", + "examplepb_update_v2_request.go", "message_path_enum_nested_path_enum.go", "nested_deep_enum.go", "pathenum_path_enum.go", "protobuf_empty.go", + "protobuf_field_mask.go", "sub_string_message.go", ], importpath = "github.com/grpc-ecosystem/grpc-gateway/examples/clients/abe", @@ -29,6 +31,6 @@ go_library( "//examples/proto/examplepb:go_default_library", "//examples/proto/pathenum:go_default_library", "//runtime:go_default_library", - "@com_github_go_resty_resty//:go_default_library", + "//vendor/github.com/go-resty/resty:go_default_library", ], ) diff --git a/examples/clients/echo/BUILD.bazel b/examples/clients/echo/BUILD.bazel index 090b56aafab..3d220ab7292 100644 --- a/examples/clients/echo/BUILD.bazel +++ b/examples/clients/echo/BUILD.bazel @@ -13,5 +13,5 @@ go_library( "examplepb_simple_message.go", ], importpath = "github.com/grpc-ecosystem/grpc-gateway/examples/clients/echo", - deps = ["@com_github_go_resty_resty//:go_default_library"], + deps = ["//vendor/github.com/go-resty/resty:go_default_library"], ) diff --git a/examples/clients/responsebody/BUILD.bazel b/examples/clients/responsebody/BUILD.bazel index bdbc237a815..e9f45b174a8 100644 --- a/examples/clients/responsebody/BUILD.bazel +++ b/examples/clients/responsebody/BUILD.bazel @@ -15,5 +15,5 @@ go_library( ], importpath = "github.com/grpc-ecosystem/grpc-gateway/examples/clients/responsebody", visibility = ["//visibility:public"], - deps = ["@com_github_go_resty_resty//:go_default_library"], + deps = ["//vendor/github.com/go-resty/resty:go_default_library"], ) diff --git a/examples/clients/unannotatedecho/BUILD.bazel b/examples/clients/unannotatedecho/BUILD.bazel index 611c6c7052d..f0749ef59b1 100644 --- a/examples/clients/unannotatedecho/BUILD.bazel +++ b/examples/clients/unannotatedecho/BUILD.bazel @@ -12,5 +12,5 @@ go_library( "unannotated_echo_service_api.go", ], importpath = "github.com/grpc-ecosystem/grpc-gateway/examples/clients/unannotatedecho", - deps = ["@com_github_go_resty_resty//:go_default_library"], + deps = ["//vendor/github.com/go-resty/resty:go_default_library"], ) diff --git a/examples/cmd/example-gateway-server/BUILD.bazel b/examples/cmd/example-gateway-server/BUILD.bazel index 0f7c5052e7e..9f649f711f1 100644 --- a/examples/cmd/example-gateway-server/BUILD.bazel +++ b/examples/cmd/example-gateway-server/BUILD.bazel @@ -7,7 +7,7 @@ go_library( visibility = ["//visibility:private"], deps = [ "//examples/gateway:go_default_library", - "@com_github_golang_glog//:go_default_library", + "//vendor/github.com/golang/glog:go_default_library", ], ) diff --git a/examples/cmd/example-grpc-server/BUILD.bazel b/examples/cmd/example-grpc-server/BUILD.bazel index 1c66416c6ba..5a0a9fa11a3 100644 --- a/examples/cmd/example-grpc-server/BUILD.bazel +++ b/examples/cmd/example-grpc-server/BUILD.bazel @@ -8,7 +8,7 @@ go_library( importpath = "github.com/grpc-ecosystem/grpc-gateway/examples/cmd/example-grpc-server", deps = [ "//examples/server:go_default_library", - "@com_github_golang_glog//:go_default_library", + "//vendor/github.com/golang/glog:go_default_library", ], ) diff --git a/examples/gateway/BUILD.bazel b/examples/gateway/BUILD.bazel index 393a7c41f9c..4b091e3d8f4 100644 --- a/examples/gateway/BUILD.bazel +++ b/examples/gateway/BUILD.bazel @@ -13,8 +13,8 @@ go_library( deps = [ "//examples/proto/examplepb:go_default_library", "//runtime:go_default_library", - "@com_github_golang_glog//:go_default_library", + "//vendor/github.com/golang/glog:go_default_library", + "//vendor/google.golang.org/grpc/connectivity:go_default_library", "@org_golang_google_grpc//:go_default_library", - "@org_golang_google_grpc//connectivity:go_default_library", ], ) diff --git a/examples/integration/BUILD.bazel b/examples/integration/BUILD.bazel index 287de4b324a..7897846fb68 100644 --- a/examples/integration/BUILD.bazel +++ b/examples/integration/BUILD.bazel @@ -18,11 +18,12 @@ go_test( "//examples/proto/sub:go_default_library", "//examples/server:go_default_library", "//runtime:go_default_library", - "@com_github_golang_glog//:go_default_library", + "//vendor/github.com/golang/glog:go_default_library", + "//vendor/github.com/golang/protobuf/proto:go_default_library", + "//vendor/google.golang.org/grpc/codes:go_default_library", "@com_github_golang_protobuf//jsonpb:go_default_library_gen", - "@com_github_golang_protobuf//proto:go_default_library", "@go_googleapis//google/rpc:status_go_proto", "@io_bazel_rules_go//proto/wkt:empty_go_proto", - "@org_golang_google_grpc//codes:go_default_library", + "@io_bazel_rules_go//proto/wkt:field_mask_go_proto", ], ) diff --git a/examples/proto/examplepb/BUILD.bazel b/examples/proto/examplepb/BUILD.bazel index 20009954efc..b275a86aa99 100644 --- a/examples/proto/examplepb/BUILD.bazel +++ b/examples/proto/examplepb/BUILD.bazel @@ -29,6 +29,7 @@ proto_library( "//protoc-gen-swagger/options:options_proto", "@com_google_protobuf//:duration_proto", "@com_google_protobuf//:empty_proto", + "@com_google_protobuf//:field_mask_proto", "@com_google_protobuf//:timestamp_proto", "@com_google_protobuf//:wrappers_proto", "@go_googleapis//google/api:annotations_proto", @@ -60,12 +61,12 @@ go_library( deps = [ "//runtime:go_default_library", "//utilities:go_default_library", - "@com_github_golang_protobuf//proto:go_default_library", + "//vendor/github.com/golang/protobuf/proto:go_default_library", + "//vendor/golang.org/x/net/context:go_default_library", + "//vendor/google.golang.org/grpc/codes:go_default_library", + "//vendor/google.golang.org/grpc/grpclog:go_default_library", + "//vendor/google.golang.org/grpc/status:go_default_library", "@org_golang_google_grpc//:go_default_library", - "@org_golang_google_grpc//codes:go_default_library", - "@org_golang_google_grpc//grpclog:go_default_library", - "@org_golang_google_grpc//status:go_default_library", - "@org_golang_x_net//context:go_default_library", ], ) diff --git a/examples/server/BUILD.bazel b/examples/server/BUILD.bazel index 29d44cfb4d1..3ca0092b51a 100644 --- a/examples/server/BUILD.bazel +++ b/examples/server/BUILD.bazel @@ -1,4 +1,4 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") package(default_visibility = ["//visibility:public"]) @@ -7,6 +7,7 @@ go_library( srcs = [ "a_bit_of_everything.go", "echo.go", + "fieldmask_helper.go", "flow_combination.go", "main.go", "responsebody.go", @@ -17,15 +18,23 @@ go_library( "//examples/proto/examplepb:go_default_library", "//examples/proto/sub:go_default_library", "//examples/proto/sub2:go_default_library", - "@com_github_golang_glog//:go_default_library", - "@com_github_golang_protobuf//proto:go_default_library", - "@com_github_rogpeppe_fastuuid//:go_default_library", + "//vendor/github.com/golang/glog:go_default_library", + "//vendor/github.com/golang/protobuf/proto:go_default_library", + "//vendor/github.com/rogpeppe/fastuuid:go_default_library", + "//vendor/google.golang.org/grpc/codes:go_default_library", + "//vendor/google.golang.org/grpc/metadata:go_default_library", + "//vendor/google.golang.org/grpc/status:go_default_library", "@go_googleapis//google/rpc:errdetails_go_proto", "@io_bazel_rules_go//proto/wkt:duration_go_proto", "@io_bazel_rules_go//proto/wkt:empty_go_proto", + "@io_bazel_rules_go//proto/wkt:field_mask_go_proto", "@org_golang_google_grpc//:go_default_library", - "@org_golang_google_grpc//codes:go_default_library", - "@org_golang_google_grpc//metadata:go_default_library", - "@org_golang_google_grpc//status:go_default_library", ], ) + +go_test( + name = "go_default_test", + srcs = ["fieldmask_helper_test.go"], + embed = [":go_default_library"], + deps = ["@io_bazel_rules_go//proto/wkt:field_mask_go_proto"], +) diff --git a/protoc-gen-grpc-gateway/BUILD.bazel b/protoc-gen-grpc-gateway/BUILD.bazel index 1af07f27f79..d11de3bc524 100644 --- a/protoc-gen-grpc-gateway/BUILD.bazel +++ b/protoc-gen-grpc-gateway/BUILD.bazel @@ -11,8 +11,8 @@ go_library( "//codegenerator:go_default_library", "//protoc-gen-grpc-gateway/descriptor:go_default_library", "//protoc-gen-grpc-gateway/gengateway:go_default_library", - "@com_github_golang_glog//:go_default_library", - "@com_github_golang_protobuf//proto:go_default_library", + "//vendor/github.com/golang/glog:go_default_library", + "//vendor/github.com/golang/protobuf/proto:go_default_library", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", ], ) diff --git a/protoc-gen-grpc-gateway/descriptor/BUILD.bazel b/protoc-gen-grpc-gateway/descriptor/BUILD.bazel index cfbdc277a8c..bff70b933ce 100644 --- a/protoc-gen-grpc-gateway/descriptor/BUILD.bazel +++ b/protoc-gen-grpc-gateway/descriptor/BUILD.bazel @@ -14,10 +14,10 @@ go_library( importpath = "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor", deps = [ "//protoc-gen-grpc-gateway/httprule:go_default_library", - "@com_github_ghodss_yaml//:go_default_library", - "@com_github_golang_glog//:go_default_library", + "//vendor/github.com/ghodss/yaml:go_default_library", + "//vendor/github.com/golang/glog:go_default_library", + "//vendor/github.com/golang/protobuf/proto:go_default_library", "@com_github_golang_protobuf//jsonpb:go_default_library_gen", - "@com_github_golang_protobuf//proto:go_default_library", "@com_github_golang_protobuf//protoc-gen-go/generator:go_default_library_gen", "@go_googleapis//google/api:annotations_go_proto", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", @@ -37,7 +37,7 @@ go_test( embed = [":go_default_library"], deps = [ "//protoc-gen-grpc-gateway/httprule:go_default_library", - "@com_github_golang_protobuf//proto:go_default_library", + "//vendor/github.com/golang/protobuf/proto:go_default_library", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", "@io_bazel_rules_go//proto/wkt:descriptor_go_proto", ], diff --git a/protoc-gen-grpc-gateway/gengateway/BUILD.bazel b/protoc-gen-grpc-gateway/gengateway/BUILD.bazel index fcd9cfc3209..cc3fd3b4d72 100644 --- a/protoc-gen-grpc-gateway/gengateway/BUILD.bazel +++ b/protoc-gen-grpc-gateway/gengateway/BUILD.bazel @@ -14,8 +14,9 @@ go_library( "//protoc-gen-grpc-gateway/descriptor:go_default_library", "//protoc-gen-grpc-gateway/generator:go_default_library", "//utilities:go_default_library", - "@com_github_golang_glog//:go_default_library", - "@com_github_golang_protobuf//proto:go_default_library", + "//vendor/github.com/golang/glog:go_default_library", + "//vendor/github.com/golang/protobuf/proto:go_default_library", + "@com_github_golang_protobuf//protoc-gen-go/generator:go_default_library_gen", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", ], ) @@ -31,7 +32,7 @@ go_test( deps = [ "//protoc-gen-grpc-gateway/descriptor:go_default_library", "//protoc-gen-grpc-gateway/httprule:go_default_library", - "@com_github_golang_protobuf//proto:go_default_library", + "//vendor/github.com/golang/protobuf/proto:go_default_library", "@io_bazel_rules_go//proto/wkt:descriptor_go_proto", ], ) diff --git a/protoc-gen-grpc-gateway/httprule/BUILD.bazel b/protoc-gen-grpc-gateway/httprule/BUILD.bazel index 89f94a14b45..68f4f2929df 100644 --- a/protoc-gen-grpc-gateway/httprule/BUILD.bazel +++ b/protoc-gen-grpc-gateway/httprule/BUILD.bazel @@ -12,7 +12,7 @@ go_library( importpath = "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/httprule", deps = [ "//utilities:go_default_library", - "@com_github_golang_glog//:go_default_library", + "//vendor/github.com/golang/glog:go_default_library", ], ) @@ -27,6 +27,6 @@ go_test( embed = [":go_default_library"], deps = [ "//utilities:go_default_library", - "@com_github_golang_glog//:go_default_library", + "//vendor/github.com/golang/glog:go_default_library", ], ) diff --git a/protoc-gen-swagger/BUILD.bazel b/protoc-gen-swagger/BUILD.bazel index d5a1d05fcc7..bd7d3e3668c 100644 --- a/protoc-gen-swagger/BUILD.bazel +++ b/protoc-gen-swagger/BUILD.bazel @@ -10,8 +10,8 @@ go_library( "//codegenerator:go_default_library", "//protoc-gen-grpc-gateway/descriptor:go_default_library", "//protoc-gen-swagger/genswagger:go_default_library", - "@com_github_golang_glog//:go_default_library", - "@com_github_golang_protobuf//proto:go_default_library", + "//vendor/github.com/golang/glog:go_default_library", + "//vendor/github.com/golang/protobuf/proto:go_default_library", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", ], ) diff --git a/protoc-gen-swagger/genswagger/BUILD.bazel b/protoc-gen-swagger/genswagger/BUILD.bazel index 172330ad88f..3faa83a593c 100644 --- a/protoc-gen-swagger/genswagger/BUILD.bazel +++ b/protoc-gen-swagger/genswagger/BUILD.bazel @@ -15,8 +15,8 @@ go_library( "//protoc-gen-grpc-gateway/descriptor:go_default_library", "//protoc-gen-grpc-gateway/generator:go_default_library", "//protoc-gen-swagger/options:go_default_library", - "@com_github_golang_glog//:go_default_library", - "@com_github_golang_protobuf//proto:go_default_library", + "//vendor/github.com/golang/glog:go_default_library", + "//vendor/github.com/golang/protobuf/proto:go_default_library", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", "@io_bazel_rules_go//proto/wkt:descriptor_go_proto", ], @@ -30,7 +30,7 @@ go_test( deps = [ "//protoc-gen-grpc-gateway/descriptor:go_default_library", "//protoc-gen-grpc-gateway/httprule:go_default_library", - "@com_github_golang_protobuf//proto:go_default_library", + "//vendor/github.com/golang/protobuf/proto:go_default_library", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", "@io_bazel_rules_go//proto/wkt:descriptor_go_proto", ], diff --git a/runtime/BUILD.bazel b/runtime/BUILD.bazel index 66a8999f2a2..c8a4dd83d3a 100644 --- a/runtime/BUILD.bazel +++ b/runtime/BUILD.bazel @@ -9,6 +9,7 @@ go_library( "convert.go", "doc.go", "errors.go", + "fieldmask.go", "handler.go", "marshal_json.go", "marshal_jsonpb.go", @@ -25,15 +26,17 @@ go_library( deps = [ "//runtime/internal:go_default_library", "//utilities:go_default_library", + "//vendor/github.com/golang/protobuf/proto:go_default_library", + "//vendor/google.golang.org/grpc/codes:go_default_library", + "//vendor/google.golang.org/grpc/grpclog:go_default_library", + "//vendor/google.golang.org/grpc/metadata:go_default_library", + "//vendor/google.golang.org/grpc/status:go_default_library", "@com_github_golang_protobuf//jsonpb:go_default_library_gen", - "@com_github_golang_protobuf//proto:go_default_library", + "@com_github_golang_protobuf//protoc-gen-go/generator:go_default_library_gen", "@io_bazel_rules_go//proto/wkt:any_go_proto", "@io_bazel_rules_go//proto/wkt:duration_go_proto", + "@io_bazel_rules_go//proto/wkt:field_mask_go_proto", "@io_bazel_rules_go//proto/wkt:timestamp_go_proto", - "@org_golang_google_grpc//codes:go_default_library", - "@org_golang_google_grpc//grpclog:go_default_library", - "@org_golang_google_grpc//metadata:go_default_library", - "@org_golang_google_grpc//status:go_default_library", ], ) @@ -43,6 +46,7 @@ go_test( srcs = [ "context_test.go", "errors_test.go", + "fieldmask_test.go", "handler_test.go", "marshal_json_test.go", "marshal_jsonpb_test.go", @@ -57,8 +61,11 @@ go_test( "//examples/proto/examplepb:go_default_library", "//runtime/internal:go_default_library", "//utilities:go_default_library", + "//vendor/github.com/golang/protobuf/proto:go_default_library", + "//vendor/google.golang.org/grpc/codes:go_default_library", + "//vendor/google.golang.org/grpc/metadata:go_default_library", + "//vendor/google.golang.org/grpc/status:go_default_library", "@com_github_golang_protobuf//jsonpb:go_default_library_gen", - "@com_github_golang_protobuf//proto:go_default_library", "@com_github_golang_protobuf//ptypes:go_default_library_gen", "@go_googleapis//google/rpc:errdetails_go_proto", "@io_bazel_rules_go//proto/wkt:duration_go_proto", @@ -68,8 +75,5 @@ go_test( "@io_bazel_rules_go//proto/wkt:timestamp_go_proto", "@io_bazel_rules_go//proto/wkt:wrappers_go_proto", "@org_golang_google_grpc//:go_default_library", - "@org_golang_google_grpc//codes:go_default_library", - "@org_golang_google_grpc//metadata:go_default_library", - "@org_golang_google_grpc//status:go_default_library", ], ) diff --git a/utilities/BUILD.bazel b/utilities/BUILD.bazel index 151f6864d92..7109d793231 100644 --- a/utilities/BUILD.bazel +++ b/utilities/BUILD.bazel @@ -7,6 +7,7 @@ go_library( srcs = [ "doc.go", "pattern.go", + "readerfactory.go", "trie.go", ], importpath = "github.com/grpc-ecosystem/grpc-gateway/utilities", From 398e4356300c19959d4cc65668975b2254b06b51 Mon Sep 17 00:00:00 2001 From: Roman Azami Date: Tue, 13 Nov 2018 14:45:17 -0800 Subject: [PATCH 5/7] Updated Patch behavior --- Gopkg.lock | 63 ++- Makefile | 2 +- .../abe/a_bit_of_everything_service_api.go | 231 ++++++++ .../abe/examplepb_update_v2_request.go | 18 + examples/clients/abe/protobuf_field_mask.go | 18 + examples/integration/integration_test.go | 188 +++++++ .../proto/examplepb/a_bit_of_everything.pb.go | 493 +++++++++++------- .../examplepb/a_bit_of_everything.pb.gw.go | 241 ++++++++- .../proto/examplepb/a_bit_of_everything.proto | 23 + .../a_bit_of_everything.swagger.json | 168 ++++++ .../proto/examplepb/echo_service.pb.gw.go | 6 +- .../proto/examplepb/flow_combination.pb.gw.go | 84 ++- examples/proto/examplepb/stream.pb.gw.go | 12 +- .../unannotated_echo_service.pb.gw.go | 6 +- examples/proto/examplepb/wrappers.pb.gw.go | 6 +- examples/server/a_bit_of_everything.go | 38 +- examples/server/fieldmask_helper.go | 55 ++ examples/server/fieldmask_helper_test.go | 92 ++++ .../gengateway/template.go | 58 ++- .../gengateway/template_test.go | 4 +- runtime/fieldmask.go | 70 +++ runtime/fieldmask_test.go | 87 ++++ utilities/readerfactory.go | 20 + 23 files changed, 1760 insertions(+), 223 deletions(-) create mode 100644 examples/clients/abe/examplepb_update_v2_request.go create mode 100644 examples/clients/abe/protobuf_field_mask.go create mode 100644 examples/server/fieldmask_helper.go create mode 100644 examples/server/fieldmask_helper_test.go create mode 100644 runtime/fieldmask.go create mode 100644 runtime/fieldmask_test.go create mode 100644 utilities/readerfactory.go diff --git a/Gopkg.lock b/Gopkg.lock index ca212aeaa81..1bbc8d61516 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -2,21 +2,28 @@ [[projects]] + digest = "1:2cd7915ab26ede7d95b8749e6b1f933f1c6d5398030684e6505940a10f31cfda" name = "github.com/ghodss/yaml" packages = ["."] + pruneopts = "UT" revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7" [[projects]] + digest = "1:5cae6c173646d9230aecf8074c171edb4fb9a37f074c5c89ba2fece20b6703b6" name = "github.com/go-resty/resty" packages = ["."] + pruneopts = "UT" revision = "f8815663de1e64d57cdd4ee9e2b2fa96977a030e" [[projects]] + digest = "1:1ba1d79f2810270045c328ae5d674321db34e3aae468eb4233883b473c5c0467" name = "github.com/golang/glog" packages = ["."] + pruneopts = "UT" revision = "23def4e6c14b4da8ac2ed8007337bc5eb5007998" [[projects]] + digest = "1:77303a120dcd145972685b3465e58e1a0910544fcb323ca24755e073c1ea6d2c" name = "github.com/golang/protobuf" packages = [ "jsonpb", @@ -33,16 +40,20 @@ "ptypes/empty", "ptypes/struct", "ptypes/timestamp", - "ptypes/wrappers" + "ptypes/wrappers", ] + pruneopts = "UT" revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5" [[projects]] + digest = "1:d673e95129a1107bfd04e093751a5e1267faabc27d218d824fb013f57ac08f55" name = "github.com/rogpeppe/fastuuid" packages = ["."] + pruneopts = "UT" revision = "6724a57986aff9bff1a1770e9347036def7c89f6" [[projects]] + digest = "1:c0b7af9789502fec69b7ab40035a2180e43b9663c32101084ba51c844ea416e9" name = "golang.org/x/net" packages = [ "context", @@ -52,17 +63,21 @@ "idna", "internal/timeseries", "publicsuffix", - "trace" + "trace", ] + pruneopts = "UT" revision = "4dfa2610cdf3b287375bbba5b8f2a14d3b01d8de" [[projects]] branch = "master" + digest = "1:7ba061af4131fb44b30448572acd0d6fefbf63a61b97b7ef1dea0be5871c2742" name = "golang.org/x/sys" packages = ["unix"] + pruneopts = "UT" revision = "66b7b1311ac80bbafcd2daeef9a5e6e2cd1e2399" [[projects]] + digest = "1:a2ab62866c75542dd18d2b069fec854577a20211d7c0ea6ae746072a1dccdd18" name = "golang.org/x/text" packages = [ "collate", @@ -78,22 +93,26 @@ "unicode/bidi", "unicode/cldr", "unicode/norm", - "unicode/rangetable" + "unicode/rangetable", ] + pruneopts = "UT" revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" version = "v0.3.0" [[projects]] + digest = "1:46be2f6b4d4e4b89f8102668902e68013234da1684fc78da602da95e745f285d" name = "google.golang.org/genproto" packages = [ "googleapis/api/annotations", "googleapis/rpc/errdetails", "googleapis/rpc/status", - "protobuf/field_mask" + "protobuf/field_mask", ] + pruneopts = "UT" revision = "383e8b2c3b9e36c4076b235b32537292176bae20" [[projects]] + digest = "1:c3ad9841823db6da420a5625b367913b4ff54bbe60e8e3c98bd20e243e62e2d2" name = "google.golang.org/grpc" packages = [ ".", @@ -121,19 +140,51 @@ "resolver/passthrough", "stats", "status", - "tap" + "tap", ] + pruneopts = "UT" revision = "2e463a05d100327ca47ac218281906921038fd95" version = "v1.16.0" [[projects]] + digest = "1:6570992c02a2137a20be83990a979b6fe892e20ecdc6b756449989b2a7efb8ae" name = "gopkg.in/yaml.v2" packages = ["."] + pruneopts = "UT" revision = "eb3733d160e74a9c7e442f435eb3bea458e1d19f" [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "869b43d6e47c7434098120dae9352bde379feae8504ece065ee51b78c6aca0fa" + input-imports = [ + "github.com/ghodss/yaml", + "github.com/go-resty/resty", + "github.com/golang/glog", + "github.com/golang/protobuf/jsonpb", + "github.com/golang/protobuf/proto", + "github.com/golang/protobuf/protoc-gen-go", + "github.com/golang/protobuf/protoc-gen-go/descriptor", + "github.com/golang/protobuf/protoc-gen-go/generator", + "github.com/golang/protobuf/protoc-gen-go/plugin", + "github.com/golang/protobuf/ptypes", + "github.com/golang/protobuf/ptypes/any", + "github.com/golang/protobuf/ptypes/duration", + "github.com/golang/protobuf/ptypes/empty", + "github.com/golang/protobuf/ptypes/struct", + "github.com/golang/protobuf/ptypes/timestamp", + "github.com/golang/protobuf/ptypes/wrappers", + "github.com/rogpeppe/fastuuid", + "golang.org/x/net/context", + "google.golang.org/genproto/googleapis/api/annotations", + "google.golang.org/genproto/googleapis/rpc/errdetails", + "google.golang.org/genproto/googleapis/rpc/status", + "google.golang.org/genproto/protobuf/field_mask", + "google.golang.org/grpc", + "google.golang.org/grpc/codes", + "google.golang.org/grpc/connectivity", + "google.golang.org/grpc/grpclog", + "google.golang.org/grpc/metadata", + "google.golang.org/grpc/status", + ] solver-name = "gps-cdcl" solver-version = 1 diff --git a/Makefile b/Makefile index 5cd992cd635..865058628ef 100644 --- a/Makefile +++ b/Makefile @@ -51,7 +51,7 @@ RUNTIME_GO=$(RUNTIME_PROTO:.proto=.pb.go) OPENAPIV2_PROTO=protoc-gen-swagger/options/openapiv2.proto protoc-gen-swagger/options/annotations.proto OPENAPIV2_GO=$(OPENAPIV2_PROTO:.proto=.pb.go) -PKGMAP=Mgoogle/protobuf/descriptor.proto=$(GO_PLUGIN_PKG)/descriptor,Mexamples/proto/sub/message.proto=$(PKG)/examples/proto/sub +PKGMAP=Mgoogle/protobuf/field_mask.proto=google.golang.org/genproto/protobuf/field_mask,Mgoogle/protobuf/descriptor.proto=$(GO_PLUGIN_PKG)/descriptor,Mexamples/proto/sub/message.proto=$(PKG)/examples/proto/sub ADDITIONAL_GW_FLAGS= ifneq "$(GATEWAY_PLUGIN_FLAGS)" "" ADDITIONAL_GW_FLAGS=,$(GATEWAY_PLUGIN_FLAGS) diff --git a/examples/clients/abe/a_bit_of_everything_service_api.go b/examples/clients/abe/a_bit_of_everything_service_api.go index d1f2a1f95e9..5e8d72779c3 100644 --- a/examples/clients/abe/a_bit_of_everything_service_api.go +++ b/examples/clients/abe/a_bit_of_everything_service_api.go @@ -812,6 +812,83 @@ func (a ABitOfEverythingServiceApi) Lookup(uuid string) (*ExamplepbABitOfEveryth return successPayload, localVarAPIResponse, err } +/** + * + * + * @param abeUuid + * @param body + * @return *ProtobufEmpty + */ +func (a ABitOfEverythingServiceApi) PatchWithFieldMaskInBody(abeUuid string, body ExamplepbUpdateV2Request) (*ProtobufEmpty, *APIResponse, error) { + + var localVarHttpMethod = strings.ToUpper("Patch") + // create path and map variables + localVarPath := a.Configuration.BasePath + "/v2a/example/a_bit_of_everything/{abe.uuid}" + localVarPath = strings.Replace(localVarPath, "{"+"abe.uuid"+"}", fmt.Sprintf("%v", abeUuid), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := make(map[string]string) + var localVarPostBody interface{} + var localVarFileName string + var localVarFileBytes []byte + // authentication '(OAuth2)' required + // oauth required + if a.Configuration.AccessToken != ""{ + localVarHeaderParams["Authorization"] = "Bearer " + a.Configuration.AccessToken + } + // authentication '(BasicAuth)' required + // http basic authentication required + if a.Configuration.Username != "" || a.Configuration.Password != ""{ + localVarHeaderParams["Authorization"] = "Basic " + a.Configuration.GetBasicAuthEncodedString() + } + // authentication '(ApiKeyAuth)' required + // set key with prefix in header + localVarHeaderParams["X-API-Key"] = a.Configuration.GetAPIKeyWithPrefix("X-API-Key") + // add default headers if any + for key := range a.Configuration.DefaultHeader { + localVarHeaderParams[key] = a.Configuration.DefaultHeader[key] + } + + // to determine the Content-Type header + localVarHttpContentTypes := []string{ "application/json", "application/x-foo-mime", } + + // set Content-Type header + localVarHttpContentType := a.Configuration.APIClient.SelectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + // to determine the Accept header + localVarHttpHeaderAccepts := []string{ + "application/json", + "application/x-foo-mime", + } + + // set Accept header + localVarHttpHeaderAccept := a.Configuration.APIClient.SelectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &body + var successPayload = new(ProtobufEmpty) + localVarHttpResponse, err := a.Configuration.APIClient.CallAPI(localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + + var localVarURL, _ = url.Parse(localVarPath) + localVarURL.RawQuery = localVarQueryParams.Encode() + var localVarAPIResponse = &APIResponse{Operation: "PatchWithFieldMaskInBody", Method: localVarHttpMethod, RequestURL: localVarURL.String()} + if localVarHttpResponse != nil { + localVarAPIResponse.Response = localVarHttpResponse.RawResponse + localVarAPIResponse.Payload = localVarHttpResponse.Body() + } + + if err != nil { + return successPayload, localVarAPIResponse, err + } + err = json.Unmarshal(localVarHttpResponse.Body(), &successPayload) + return successPayload, localVarAPIResponse, err +} + /** * * @@ -1038,3 +1115,157 @@ func (a ABitOfEverythingServiceApi) Update(uuid string, body ExamplepbABitOfEver return successPayload, localVarAPIResponse, err } +/** + * + * + * @param abeUuid + * @param body + * @return *ProtobufEmpty + */ +func (a ABitOfEverythingServiceApi) UpdateV2(abeUuid string, body ExamplepbABitOfEverything) (*ProtobufEmpty, *APIResponse, error) { + + var localVarHttpMethod = strings.ToUpper("Put") + // create path and map variables + localVarPath := a.Configuration.BasePath + "/v2/example/a_bit_of_everything/{abe.uuid}" + localVarPath = strings.Replace(localVarPath, "{"+"abe.uuid"+"}", fmt.Sprintf("%v", abeUuid), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := make(map[string]string) + var localVarPostBody interface{} + var localVarFileName string + var localVarFileBytes []byte + // authentication '(OAuth2)' required + // oauth required + if a.Configuration.AccessToken != ""{ + localVarHeaderParams["Authorization"] = "Bearer " + a.Configuration.AccessToken + } + // authentication '(BasicAuth)' required + // http basic authentication required + if a.Configuration.Username != "" || a.Configuration.Password != ""{ + localVarHeaderParams["Authorization"] = "Basic " + a.Configuration.GetBasicAuthEncodedString() + } + // authentication '(ApiKeyAuth)' required + // set key with prefix in header + localVarHeaderParams["X-API-Key"] = a.Configuration.GetAPIKeyWithPrefix("X-API-Key") + // add default headers if any + for key := range a.Configuration.DefaultHeader { + localVarHeaderParams[key] = a.Configuration.DefaultHeader[key] + } + + // to determine the Content-Type header + localVarHttpContentTypes := []string{ "application/json", "application/x-foo-mime", } + + // set Content-Type header + localVarHttpContentType := a.Configuration.APIClient.SelectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + // to determine the Accept header + localVarHttpHeaderAccepts := []string{ + "application/json", + "application/x-foo-mime", + } + + // set Accept header + localVarHttpHeaderAccept := a.Configuration.APIClient.SelectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &body + var successPayload = new(ProtobufEmpty) + localVarHttpResponse, err := a.Configuration.APIClient.CallAPI(localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + + var localVarURL, _ = url.Parse(localVarPath) + localVarURL.RawQuery = localVarQueryParams.Encode() + var localVarAPIResponse = &APIResponse{Operation: "UpdateV2", Method: localVarHttpMethod, RequestURL: localVarURL.String()} + if localVarHttpResponse != nil { + localVarAPIResponse.Response = localVarHttpResponse.RawResponse + localVarAPIResponse.Payload = localVarHttpResponse.Body() + } + + if err != nil { + return successPayload, localVarAPIResponse, err + } + err = json.Unmarshal(localVarHttpResponse.Body(), &successPayload) + return successPayload, localVarAPIResponse, err +} + +/** + * + * + * @param abeUuid + * @param body + * @return *ProtobufEmpty + */ +func (a ABitOfEverythingServiceApi) UpdateV22(abeUuid string, body ExamplepbABitOfEverything) (*ProtobufEmpty, *APIResponse, error) { + + var localVarHttpMethod = strings.ToUpper("Patch") + // create path and map variables + localVarPath := a.Configuration.BasePath + "/v2/example/a_bit_of_everything/{abe.uuid}" + localVarPath = strings.Replace(localVarPath, "{"+"abe.uuid"+"}", fmt.Sprintf("%v", abeUuid), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := make(map[string]string) + var localVarPostBody interface{} + var localVarFileName string + var localVarFileBytes []byte + // authentication '(OAuth2)' required + // oauth required + if a.Configuration.AccessToken != ""{ + localVarHeaderParams["Authorization"] = "Bearer " + a.Configuration.AccessToken + } + // authentication '(BasicAuth)' required + // http basic authentication required + if a.Configuration.Username != "" || a.Configuration.Password != ""{ + localVarHeaderParams["Authorization"] = "Basic " + a.Configuration.GetBasicAuthEncodedString() + } + // authentication '(ApiKeyAuth)' required + // set key with prefix in header + localVarHeaderParams["X-API-Key"] = a.Configuration.GetAPIKeyWithPrefix("X-API-Key") + // add default headers if any + for key := range a.Configuration.DefaultHeader { + localVarHeaderParams[key] = a.Configuration.DefaultHeader[key] + } + + // to determine the Content-Type header + localVarHttpContentTypes := []string{ "application/json", "application/x-foo-mime", } + + // set Content-Type header + localVarHttpContentType := a.Configuration.APIClient.SelectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + // to determine the Accept header + localVarHttpHeaderAccepts := []string{ + "application/json", + "application/x-foo-mime", + } + + // set Accept header + localVarHttpHeaderAccept := a.Configuration.APIClient.SelectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &body + var successPayload = new(ProtobufEmpty) + localVarHttpResponse, err := a.Configuration.APIClient.CallAPI(localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + + var localVarURL, _ = url.Parse(localVarPath) + localVarURL.RawQuery = localVarQueryParams.Encode() + var localVarAPIResponse = &APIResponse{Operation: "UpdateV22", Method: localVarHttpMethod, RequestURL: localVarURL.String()} + if localVarHttpResponse != nil { + localVarAPIResponse.Response = localVarHttpResponse.RawResponse + localVarAPIResponse.Payload = localVarHttpResponse.Body() + } + + if err != nil { + return successPayload, localVarAPIResponse, err + } + err = json.Unmarshal(localVarHttpResponse.Body(), &successPayload) + return successPayload, localVarAPIResponse, err +} + diff --git a/examples/clients/abe/examplepb_update_v2_request.go b/examples/clients/abe/examplepb_update_v2_request.go new file mode 100644 index 00000000000..9d021f8241c --- /dev/null +++ b/examples/clients/abe/examplepb_update_v2_request.go @@ -0,0 +1,18 @@ +/* + * A Bit of Everything + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * OpenAPI spec version: 1.0 + * Contact: none@example.com + * Generated by: https://github.com/swagger-api/swagger-codegen.git + */ + +package abe + +type ExamplepbUpdateV2Request struct { + + Abe ExamplepbABitOfEverything `json:"abe,omitempty"` + + UpdateMask ProtobufFieldMask `json:"update_mask,omitempty"` +} diff --git a/examples/clients/abe/protobuf_field_mask.go b/examples/clients/abe/protobuf_field_mask.go new file mode 100644 index 00000000000..f30f2531765 --- /dev/null +++ b/examples/clients/abe/protobuf_field_mask.go @@ -0,0 +1,18 @@ +/* + * A Bit of Everything + * + * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + * + * OpenAPI spec version: 1.0 + * Contact: none@example.com + * Generated by: https://github.com/swagger-api/swagger-codegen.git + */ + +package abe + +// paths: \"f.a\" paths: \"f.b.d\" Here `f` represents a field in some root message, `a` and `b` fields in the message found in `f`, and `d` a field found in the message in `f.b`. Field masks are used to specify a subset of fields that should be returned by a get operation or modified by an update operation. Field masks also have a custom JSON encoding (see below). # Field Masks in Projections When used in the context of a projection, a response message or sub-message is filtered by the API to only contain those fields as specified in the mask. For example, if the mask in the previous example is applied to a response message as follows: f { a : 22 b { d : 1 x : 2 } y : 13 } z: 8 The result will not contain specific values for fields x,y and z (their value will be set to the default, and omitted in proto text output): f { a : 22 b { d : 1 } } A repeated field is not allowed except at the last position of a paths string. If a FieldMask object is not present in a get operation, the operation applies to all fields (as if a FieldMask of all fields had been specified). Note that a field mask does not necessarily apply to the top-level response message. In case of a REST get operation, the field mask applies directly to the response, but in case of a REST list operation, the mask instead applies to each individual message in the returned resource list. In case of a REST custom method, other definitions may be used. Where the mask applies will be clearly documented together with its declaration in the API. In any case, the effect on the returned resource/resources is required behavior for APIs. # Field Masks in Update Operations A field mask in update operations specifies which fields of the targeted resource are going to be updated. The API is required to only change the values of the fields as specified in the mask and leave the others untouched. If a resource is passed in to describe the updated values, the API ignores the values of all fields not covered by the mask. If a repeated field is specified for an update operation, the existing repeated values in the target resource will be overwritten by the new values. Note that a repeated field is only allowed in the last position of a `paths` string. If a sub-message is specified in the last position of the field mask for an update operation, then the existing sub-message in the target resource is overwritten. Given the target message: f { b { d : 1 x : 2 } c : 1 } And an update message: f { b { d : 10 } } then if the field mask is: paths: \"f.b\" then the result will be: f { b { d : 10 } c : 1 } However, if the update mask was: paths: \"f.b.d\" then the result would be: f { b { d : 10 x : 2 } c : 1 } In order to reset a field's value to the default, the field must be in the mask and set to the default value in the provided resource. Hence, in order to reset all fields of a resource, provide a default instance of the resource and set all fields in the mask, or do not provide a mask as described below. If a field mask is not present on update, the operation applies to all fields (as if a field mask of all fields has been specified). Note that in the presence of schema evolution, this may mean that fields the client does not know and has therefore not filled into the request will be reset to their default. If this is unwanted behavior, a specific service may require a client to always specify a field mask, producing an error if not. As with get operations, the location of the resource which describes the updated values in the request message depends on the operation kind. In any case, the effect of the field mask is required to be honored by the API. ## Considerations for HTTP REST The HTTP kind of an update operation which uses a field mask must be set to PATCH instead of PUT in order to satisfy HTTP semantics (PUT must only be used for full updates). # JSON Encoding of Field Masks In JSON, a field mask is encoded as a single string where paths are separated by a comma. Fields name in each path are converted to/from lower-camel naming conventions. As an example, consider the following message declarations: message Profile { User user = 1; Photo photo = 2; } message User { string display_name = 1; string address = 2; } In proto a field mask for `Profile` may look as such: mask { paths: \"user.display_name\" paths: \"photo\" } In JSON, the same mask is represented as below: { mask: \"user.displayName,photo\" } # Field Masks and Oneof Fields Field masks treat fields in oneofs just as regular fields. Consider the following message: message SampleMessage { oneof test_oneof { string name = 4; SubMessage sub_message = 9; } } The field mask can be: mask { paths: \"name\" } Or: mask { paths: \"sub_message\" } Note that oneof type names (\"test_oneof\" in this case) cannot be used in paths. +type ProtobufFieldMask struct { + + // The set of field mask paths. + Paths []string `json:"paths,omitempty"` +} diff --git a/examples/integration/integration_test.go b/examples/integration/integration_test.go index b488be6ad2f..96b36d04b58 100644 --- a/examples/integration/integration_test.go +++ b/examples/integration/integration_test.go @@ -22,6 +22,7 @@ import ( "github.com/grpc-ecosystem/grpc-gateway/examples/proto/pathenum" "github.com/grpc-ecosystem/grpc-gateway/examples/proto/sub" "github.com/grpc-ecosystem/grpc-gateway/runtime" + "google.golang.org/genproto/protobuf/field_mask" "google.golang.org/grpc/codes" ) @@ -555,6 +556,193 @@ func testABELookup(t *testing.T, port int) { } } +// TestABEPatch demonstrates partially updating a resource. +// First, we'll create an ABE resource with known values for string_value and int32_value +// Then, issue a PATCH request updating only the string_value +// Then, GET the resource and verify that string_value is changed, but int32_value isn't +func TestABEPatch(t *testing.T) { + port := 8080 + + // create a record with a known string_value and int32_value + uuid := postABE(t, port, gw.ABitOfEverything{StringValue: "strprefix/bar", Int32Value: 32}) + + // issue PATCH request, only updating string_value + req, err := http.NewRequest( + http.MethodPatch, + fmt.Sprintf("http://localhost:%d/v2/example/a_bit_of_everything/%s", port, uuid), + strings.NewReader(`{"string_value": "strprefix/foo"}`), + ) + if err != nil { + t.Fatalf("http.NewRequest(PATCH) failed with %v; want success", err) + } + patchResp, err := http.DefaultClient.Do(req) + if err != nil { + t.Fatalf("failed to issue PATCH request: %v", err) + } + if got, want := patchResp.StatusCode, http.StatusOK; got != want { + if body, err := ioutil.ReadAll(patchResp.Body); err != nil { + t.Errorf("patchResp body couldn't be read: %v", err) + } else { + t.Errorf("patchResp.StatusCode= %d; want %d resp: %v", got, want, string(body)) + } + } + + // issue GET request, verifying that string_value is changed and int32_value is not + getRespBody := getABE(t, port, uuid) + if got, want := getRespBody.StringValue, "strprefix/foo"; got != want { + t.Errorf("string_value= %q; want %q", got, want) + } + if got, want := getRespBody.Int32Value, int32(32); got != want { + t.Errorf("int_32_value= %d; want %d", got, want) + } +} + +// TestABEPatchBody demonstrates the ability to specify an update mask within the request body. +func TestABEPatchBody(t *testing.T) { + port := 8080 + + for _, tc := range []struct { + name string + originalValue gw.ABitOfEverything + input gw.UpdateV2Request + want gw.ABitOfEverything + }{ + { + name: "with fieldmask provided", + originalValue: gw.ABitOfEverything{ + StringValue: "rabbit", + SingleNested: &gw.ABitOfEverything_Nested{Name: "some value that will get overwritten", Amount: 345}, + }, + input: gw.UpdateV2Request{Abe: &gw.ABitOfEverything{ + StringValue: "some value that won't get updated because it's not in the field mask", + SingleNested: &gw.ABitOfEverything_Nested{Amount: 456}, + }, UpdateMask: &field_mask.FieldMask{Paths: []string{"single_nested"}}}, + want: gw.ABitOfEverything{StringValue: "rabbit", SingleNested: &gw.ABitOfEverything_Nested{Amount: 456}}, + }, + { + name: "with empty fieldmask", + originalValue: gw.ABitOfEverything{ + StringValue: "some value that will get overwritten", + SingleNested: &gw.ABitOfEverything_Nested{Name: "value that will get empty", Amount: 345}, + }, + input: gw.UpdateV2Request{Abe: &gw.ABitOfEverything{ + StringValue: "some updated value because the fieldMask is nil", + SingleNested: &gw.ABitOfEverything_Nested{Amount: 456}, + }, UpdateMask: &field_mask.FieldMask{}}, + want: gw.ABitOfEverything{ + StringValue: "some updated value because the fieldMask is nil", + SingleNested: &gw.ABitOfEverything_Nested{Amount: 456}, + }, + }, + { + name: "with nil fieldmask", + originalValue: gw.ABitOfEverything{ + StringValue: "some value that will get overwritten", + SingleNested: &gw.ABitOfEverything_Nested{Name: "value that will get empty", Amount: 123}, + }, + input: gw.UpdateV2Request{Abe: &gw.ABitOfEverything{ + StringValue: "some updated value because the fieldMask is nil", + SingleNested: &gw.ABitOfEverything_Nested{Amount: 657}, + }, UpdateMask: nil}, + want: gw.ABitOfEverything{ + StringValue: "some updated value because the fieldMask is nil", + SingleNested: &gw.ABitOfEverything_Nested{Amount: 657}, + }, + }, + } { + t.Run(tc.name, func(t *testing.T) { + originalABE := tc.originalValue + uuid := postABE(t, port, originalABE) + + patchBody := tc.input + patchReq, err := http.NewRequest( + http.MethodPatch, + fmt.Sprintf("http://localhost:%d/v2a/example/a_bit_of_everything/%s", port, uuid), + strings.NewReader(mustMarshal(t, patchBody)), + ) + if err != nil { + t.Fatalf("http.NewRequest(PATCH) failed with %v; want success", err) + } + patchResp, err := http.DefaultClient.Do(patchReq) + if err != nil { + t.Fatalf("failed to issue PATCH request: %v", err) + } + if got, want := patchResp.StatusCode, http.StatusOK; got != want { + if body, err := ioutil.ReadAll(patchResp.Body); err != nil { + t.Errorf("patchResp body couldn't be read: %v", err) + } else { + t.Errorf("patchResp.StatusCode= %d; want %d resp: %v", got, want, string(body)) + } + } + + want, got := tc.want, getABE(t, port, uuid) + got.Uuid = "" // empty out uuid so we don't need to worry about it in comparisons + if !reflect.DeepEqual(want, got) { + t.Errorf("want %v\ngot %v", want, got) + } + }) + } +} + +// mustMarshal marshals the given object into a json string, calling t.Fatal if an error occurs. Useful in testing to +// inline marshalling whenever you don't expect the marshalling to return an error +func mustMarshal(t *testing.T, i interface{}) string { + b, err := json.Marshal(i) + if err != nil { + t.Fatalf("failed to marshal %#v: %v", i, err) + } + + return string(b) +} + +// postABE conveniently creates a new ABE record for ease in testing +func postABE(t *testing.T, port int, abe gw.ABitOfEverything) (uuid string) { + url := fmt.Sprintf("http://localhost:%d/v1/example/a_bit_of_everything", port) + postResp, err := http.Post(url, "application/json", strings.NewReader(mustMarshal(t, abe))) + if err != nil { + t.Fatalf("http.Post(%q) failed with %v; want success", url, err) + return + } + body, err := ioutil.ReadAll(postResp.Body) + if err != nil { + t.Fatalf("postResp body couldn't be read: %v", err) + } + var f struct { + UUID string `json:"uuid"` + } + if err := json.Unmarshal(body, &f); err != nil { + t.Fatalf("postResp body couldn't be unmarshalled: %v. body: %s", err, string(body)) + } + if f.UUID == "" { + t.Fatalf("want uuid from postResp, but got none. body: %s", string(body)) + } + return f.UUID +} + +// getABE conveniently fetches an ABE record for ease in testing +func getABE(t *testing.T, port int, uuid string) gw.ABitOfEverything { + gURL := fmt.Sprintf("http://localhost:%d/v1/example/a_bit_of_everything/%s", port, uuid) + getResp, err := http.Get(gURL) + if err != nil { + t.Fatalf("http.Get(%s) failed with %v; want success", gURL, err) + } + defer getResp.Body.Close() + + if got, want := getResp.StatusCode, http.StatusOK; got != want { + t.Fatalf("getResp.StatusCode= %d, want %d. resp: %v", got, want, getResp) + } + var getRespBody gw.ABitOfEverything + body, err := ioutil.ReadAll(getResp.Body) + if err != nil { + t.Fatalf("getResp body couldn't be read: %v", err) + } + if err := json.Unmarshal(body, &getRespBody); err != nil { + t.Fatalf("getResp body couldn't be unmarshalled: %v body: %s", err, string(body)) + } + + return getRespBody +} + func testABELookupNotFound(t *testing.T, port int) { url := fmt.Sprintf("http://localhost:%d/v1/example/a_bit_of_everything", port) uuid := "not_exist" diff --git a/examples/proto/examplepb/a_bit_of_everything.pb.go b/examples/proto/examplepb/a_bit_of_everything.pb.go index 4ba9b36f349..4f29c98d99c 100644 --- a/examples/proto/examplepb/a_bit_of_everything.pb.go +++ b/examples/proto/examplepb/a_bit_of_everything.pb.go @@ -14,6 +14,7 @@ import sub "github.com/grpc-ecosystem/grpc-gateway/examples/proto/sub" import sub2 "github.com/grpc-ecosystem/grpc-gateway/examples/proto/sub2" import _ "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger/options" import _ "google.golang.org/genproto/googleapis/api/annotations" +import field_mask "google.golang.org/genproto/protobuf/field_mask" import ( context "golang.org/x/net/context" @@ -54,7 +55,7 @@ func (x NumericEnum) String() string { return proto.EnumName(NumericEnum_name, int32(x)) } func (NumericEnum) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_a_bit_of_everything_dc9cebfa7968115c, []int{0} + return fileDescriptor_a_bit_of_everything_7494e8194e1b43f3, []int{0} } // DeepEnum is one or zero. @@ -80,7 +81,7 @@ func (x ABitOfEverything_Nested_DeepEnum) String() string { return proto.EnumName(ABitOfEverything_Nested_DeepEnum_name, int32(x)) } func (ABitOfEverything_Nested_DeepEnum) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_a_bit_of_everything_dc9cebfa7968115c, []int{0, 0, 0} + return fileDescriptor_a_bit_of_everything_7494e8194e1b43f3, []int{0, 0, 0} } // Intentionaly complicated message type to cover many features of Protobuf. @@ -128,7 +129,7 @@ func (m *ABitOfEverything) Reset() { *m = ABitOfEverything{} } func (m *ABitOfEverything) String() string { return proto.CompactTextString(m) } func (*ABitOfEverything) ProtoMessage() {} func (*ABitOfEverything) Descriptor() ([]byte, []int) { - return fileDescriptor_a_bit_of_everything_dc9cebfa7968115c, []int{0} + return fileDescriptor_a_bit_of_everything_7494e8194e1b43f3, []int{0} } func (m *ABitOfEverything) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ABitOfEverything.Unmarshal(m, b) @@ -466,7 +467,7 @@ func (m *ABitOfEverything_Nested) Reset() { *m = ABitOfEverything_Nested func (m *ABitOfEverything_Nested) String() string { return proto.CompactTextString(m) } func (*ABitOfEverything_Nested) ProtoMessage() {} func (*ABitOfEverything_Nested) Descriptor() ([]byte, []int) { - return fileDescriptor_a_bit_of_everything_dc9cebfa7968115c, []int{0, 0} + return fileDescriptor_a_bit_of_everything_7494e8194e1b43f3, []int{0, 0} } func (m *ABitOfEverything_Nested) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ABitOfEverything_Nested.Unmarshal(m, b) @@ -535,7 +536,7 @@ func (m *ABitOfEverythingRepeated) Reset() { *m = ABitOfEverythingRepeat func (m *ABitOfEverythingRepeated) String() string { return proto.CompactTextString(m) } func (*ABitOfEverythingRepeated) ProtoMessage() {} func (*ABitOfEverythingRepeated) Descriptor() ([]byte, []int) { - return fileDescriptor_a_bit_of_everything_dc9cebfa7968115c, []int{1} + return fileDescriptor_a_bit_of_everything_7494e8194e1b43f3, []int{1} } func (m *ABitOfEverythingRepeated) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ABitOfEverythingRepeated.Unmarshal(m, b) @@ -678,7 +679,7 @@ func (m *Body) Reset() { *m = Body{} } func (m *Body) String() string { return proto.CompactTextString(m) } func (*Body) ProtoMessage() {} func (*Body) Descriptor() ([]byte, []int) { - return fileDescriptor_a_bit_of_everything_dc9cebfa7968115c, []int{2} + return fileDescriptor_a_bit_of_everything_7494e8194e1b43f3, []int{2} } func (m *Body) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Body.Unmarshal(m, b) @@ -717,7 +718,7 @@ func (m *MessageWithBody) Reset() { *m = MessageWithBody{} } func (m *MessageWithBody) String() string { return proto.CompactTextString(m) } func (*MessageWithBody) ProtoMessage() {} func (*MessageWithBody) Descriptor() ([]byte, []int) { - return fileDescriptor_a_bit_of_everything_dc9cebfa7968115c, []int{3} + return fileDescriptor_a_bit_of_everything_7494e8194e1b43f3, []int{3} } func (m *MessageWithBody) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_MessageWithBody.Unmarshal(m, b) @@ -751,6 +752,53 @@ func (m *MessageWithBody) GetData() *Body { return nil } +// UpdateV2Request request for update includes the message and the update mask +type UpdateV2Request struct { + Abe *ABitOfEverything `protobuf:"bytes,1,opt,name=abe,proto3" json:"abe,omitempty"` + UpdateMask *field_mask.FieldMask `protobuf:"bytes,2,opt,name=update_mask,json=updateMask,proto3" json:"update_mask,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UpdateV2Request) Reset() { *m = UpdateV2Request{} } +func (m *UpdateV2Request) String() string { return proto.CompactTextString(m) } +func (*UpdateV2Request) ProtoMessage() {} +func (*UpdateV2Request) Descriptor() ([]byte, []int) { + return fileDescriptor_a_bit_of_everything_7494e8194e1b43f3, []int{4} +} +func (m *UpdateV2Request) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UpdateV2Request.Unmarshal(m, b) +} +func (m *UpdateV2Request) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UpdateV2Request.Marshal(b, m, deterministic) +} +func (dst *UpdateV2Request) XXX_Merge(src proto.Message) { + xxx_messageInfo_UpdateV2Request.Merge(dst, src) +} +func (m *UpdateV2Request) XXX_Size() int { + return xxx_messageInfo_UpdateV2Request.Size(m) +} +func (m *UpdateV2Request) XXX_DiscardUnknown() { + xxx_messageInfo_UpdateV2Request.DiscardUnknown(m) +} + +var xxx_messageInfo_UpdateV2Request proto.InternalMessageInfo + +func (m *UpdateV2Request) GetAbe() *ABitOfEverything { + if m != nil { + return m.Abe + } + return nil +} + +func (m *UpdateV2Request) GetUpdateMask() *field_mask.FieldMask { + if m != nil { + return m.UpdateMask + } + return nil +} + func init() { proto.RegisterType((*ABitOfEverything)(nil), "grpc.gateway.examples.examplepb.ABitOfEverything") proto.RegisterMapType((map[string]NumericEnum)(nil), "grpc.gateway.examples.examplepb.ABitOfEverything.MapValueEntry") @@ -760,6 +808,7 @@ func init() { proto.RegisterType((*ABitOfEverythingRepeated)(nil), "grpc.gateway.examples.examplepb.ABitOfEverythingRepeated") proto.RegisterType((*Body)(nil), "grpc.gateway.examples.examplepb.Body") proto.RegisterType((*MessageWithBody)(nil), "grpc.gateway.examples.examplepb.MessageWithBody") + proto.RegisterType((*UpdateV2Request)(nil), "grpc.gateway.examples.examplepb.UpdateV2Request") proto.RegisterEnum("grpc.gateway.examples.examplepb.NumericEnum", NumericEnum_name, NumericEnum_value) proto.RegisterEnum("grpc.gateway.examples.examplepb.ABitOfEverything_Nested_DeepEnum", ABitOfEverything_Nested_DeepEnum_name, ABitOfEverything_Nested_DeepEnum_value) } @@ -783,6 +832,8 @@ type ABitOfEverythingServiceClient interface { CreateBody(ctx context.Context, in *ABitOfEverything, opts ...grpc.CallOption) (*ABitOfEverything, error) Lookup(ctx context.Context, in *sub2.IdMessage, opts ...grpc.CallOption) (*ABitOfEverything, error) Update(ctx context.Context, in *ABitOfEverything, opts ...grpc.CallOption) (*empty.Empty, error) + UpdateV2(ctx context.Context, in *UpdateV2Request, opts ...grpc.CallOption) (*empty.Empty, error) + PatchWithFieldMaskInBody(ctx context.Context, in *UpdateV2Request, opts ...grpc.CallOption) (*empty.Empty, error) Delete(ctx context.Context, in *sub2.IdMessage, opts ...grpc.CallOption) (*empty.Empty, error) GetQuery(ctx context.Context, in *ABitOfEverything, opts ...grpc.CallOption) (*empty.Empty, error) GetRepeatedQuery(ctx context.Context, in *ABitOfEverythingRepeated, opts ...grpc.CallOption) (*ABitOfEverythingRepeated, error) @@ -846,6 +897,24 @@ func (c *aBitOfEverythingServiceClient) Update(ctx context.Context, in *ABitOfEv return out, nil } +func (c *aBitOfEverythingServiceClient) UpdateV2(ctx context.Context, in *UpdateV2Request, opts ...grpc.CallOption) (*empty.Empty, error) { + out := new(empty.Empty) + err := c.cc.Invoke(ctx, "/grpc.gateway.examples.examplepb.ABitOfEverythingService/UpdateV2", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *aBitOfEverythingServiceClient) PatchWithFieldMaskInBody(ctx context.Context, in *UpdateV2Request, opts ...grpc.CallOption) (*empty.Empty, error) { + out := new(empty.Empty) + err := c.cc.Invoke(ctx, "/grpc.gateway.examples.examplepb.ABitOfEverythingService/PatchWithFieldMaskInBody", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *aBitOfEverythingServiceClient) Delete(ctx context.Context, in *sub2.IdMessage, opts ...grpc.CallOption) (*empty.Empty, error) { out := new(empty.Empty) err := c.cc.Invoke(ctx, "/grpc.gateway.examples.examplepb.ABitOfEverythingService/Delete", in, out, opts...) @@ -945,6 +1014,8 @@ type ABitOfEverythingServiceServer interface { CreateBody(context.Context, *ABitOfEverything) (*ABitOfEverything, error) Lookup(context.Context, *sub2.IdMessage) (*ABitOfEverything, error) Update(context.Context, *ABitOfEverything) (*empty.Empty, error) + UpdateV2(context.Context, *UpdateV2Request) (*empty.Empty, error) + PatchWithFieldMaskInBody(context.Context, *UpdateV2Request) (*empty.Empty, error) Delete(context.Context, *sub2.IdMessage) (*empty.Empty, error) GetQuery(context.Context, *ABitOfEverything) (*empty.Empty, error) GetRepeatedQuery(context.Context, *ABitOfEverythingRepeated) (*ABitOfEverythingRepeated, error) @@ -1040,6 +1111,42 @@ func _ABitOfEverythingService_Update_Handler(srv interface{}, ctx context.Contex return interceptor(ctx, in, info, handler) } +func _ABitOfEverythingService_UpdateV2_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateV2Request) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ABitOfEverythingServiceServer).UpdateV2(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.gateway.examples.examplepb.ABitOfEverythingService/UpdateV2", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ABitOfEverythingServiceServer).UpdateV2(ctx, req.(*UpdateV2Request)) + } + return interceptor(ctx, in, info, handler) +} + +func _ABitOfEverythingService_PatchWithFieldMaskInBody_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateV2Request) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ABitOfEverythingServiceServer).PatchWithFieldMaskInBody(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.gateway.examples.examplepb.ABitOfEverythingService/PatchWithFieldMaskInBody", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ABitOfEverythingServiceServer).PatchWithFieldMaskInBody(ctx, req.(*UpdateV2Request)) + } + return interceptor(ctx, in, info, handler) +} + func _ABitOfEverythingService_Delete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(sub2.IdMessage) if err := dec(in); err != nil { @@ -1240,6 +1347,14 @@ var _ABitOfEverythingService_serviceDesc = grpc.ServiceDesc{ MethodName: "Update", Handler: _ABitOfEverythingService_Update_Handler, }, + { + MethodName: "UpdateV2", + Handler: _ABitOfEverythingService_UpdateV2_Handler, + }, + { + MethodName: "PatchWithFieldMaskInBody", + Handler: _ABitOfEverythingService_PatchWithFieldMaskInBody_Handler, + }, { MethodName: "Delete", Handler: _ABitOfEverythingService_Delete_Handler, @@ -1414,181 +1529,191 @@ var _AnotherServiceWithNoBindings_serviceDesc = grpc.ServiceDesc{ } func init() { - proto.RegisterFile("examples/proto/examplepb/a_bit_of_everything.proto", fileDescriptor_a_bit_of_everything_dc9cebfa7968115c) -} - -var fileDescriptor_a_bit_of_everything_dc9cebfa7968115c = []byte{ - // 2750 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x19, 0xcd, 0x73, 0x1b, 0x57, - 0xdd, 0xab, 0x95, 0x65, 0xfb, 0xe7, 0x2f, 0xf9, 0x39, 0x71, 0x6c, 0xc5, 0xad, 0x5f, 0xd4, 0x94, - 0x6e, 0xdd, 0x6a, 0x37, 0x51, 0x4c, 0x49, 0xdc, 0x69, 0x83, 0xfc, 0x91, 0xc4, 0x4d, 0xea, 0x38, - 0x9b, 0xb4, 0x74, 0x42, 0x5a, 0xcf, 0x4a, 0x7a, 0x96, 0xb6, 0xd1, 0xee, 0x5b, 0x76, 0xdf, 0x3a, - 0x16, 0x46, 0x50, 0x60, 0x06, 0x06, 0x7a, 0x60, 0xc6, 0x70, 0xe2, 0xc0, 0x99, 0x03, 0x57, 0x4e, - 0x3d, 0x30, 0x1c, 0xca, 0x85, 0x1b, 0x30, 0xbd, 0x30, 0xc3, 0x05, 0x98, 0xe1, 0x2f, 0x80, 0xe1, - 0xc6, 0xec, 0xdb, 0x0f, 0xef, 0xae, 0xa4, 0x38, 0x72, 0x98, 0x5e, 0xec, 0x7d, 0xef, 0xfd, 0xbe, - 0xbf, 0xdf, 0x13, 0x94, 0xc9, 0x81, 0x66, 0x58, 0x2d, 0xe2, 0x28, 0x96, 0x4d, 0x19, 0x55, 0x82, - 0xa5, 0x55, 0x55, 0xb4, 0xdd, 0xaa, 0xce, 0x76, 0xe9, 0xde, 0x2e, 0xd9, 0x27, 0x76, 0x9b, 0x35, - 0x75, 0xb3, 0x21, 0x73, 0x18, 0xb4, 0xd4, 0xb0, 0xad, 0x9a, 0xdc, 0xd0, 0x18, 0x79, 0xa2, 0xb5, - 0xe5, 0x90, 0x80, 0x1c, 0xa1, 0x16, 0x16, 0x1b, 0x94, 0x36, 0x5a, 0x44, 0xd1, 0x2c, 0x5d, 0xd1, - 0x4c, 0x93, 0x32, 0x8d, 0xe9, 0xd4, 0x74, 0x7c, 0xf4, 0xc2, 0xf9, 0xe0, 0x94, 0xaf, 0xaa, 0xee, - 0x9e, 0x42, 0x0c, 0x8b, 0xb5, 0x83, 0xc3, 0x17, 0xd3, 0x87, 0x75, 0xd7, 0xe6, 0xd8, 0xc1, 0xf9, - 0x2b, 0x29, 0x79, 0x2d, 0x8d, 0x35, 0x89, 0xe9, 0x1a, 0xfc, 0x63, 0xd7, 0xfb, 0x0a, 0x00, 0x71, - 0x0a, 0xd0, 0x71, 0xab, 0x8a, 0x41, 0x1c, 0x47, 0x6b, 0x90, 0x00, 0xe2, 0x42, 0x37, 0x44, 0x39, - 0x05, 0xb2, 0x94, 0x96, 0x86, 0xe9, 0x06, 0x71, 0x98, 0x66, 0x58, 0x01, 0xc0, 0xeb, 0xfc, 0x5f, - 0xad, 0xd4, 0x20, 0x66, 0xc9, 0x79, 0xa2, 0x35, 0x1a, 0xc4, 0x56, 0xa8, 0xc5, 0xb5, 0xed, 0xd6, - 0xbc, 0xf8, 0x87, 0x59, 0xc8, 0x57, 0xd6, 0x74, 0x76, 0x77, 0x6f, 0x33, 0xb2, 0x29, 0xfa, 0x10, - 0x26, 0x1d, 0xdd, 0x6c, 0xb4, 0xc8, 0xae, 0x49, 0x1c, 0x46, 0xea, 0xf3, 0x0b, 0x58, 0x90, 0xc6, - 0xcb, 0x57, 0xe5, 0x13, 0xac, 0x2c, 0xa7, 0x29, 0xc9, 0xdb, 0x1c, 0x5f, 0x9d, 0xf0, 0xc9, 0xf9, - 0x2b, 0xd4, 0x84, 0xac, 0xeb, 0xea, 0xf5, 0x79, 0x01, 0x0b, 0xd2, 0xd8, 0xda, 0x83, 0xa3, 0xca, - 0xbd, 0x4f, 0x04, 0xe1, 0xa7, 0xc2, 0xed, 0x6f, 0x6a, 0xa5, 0xbd, 0x4a, 0xe9, 0xc6, 0xa5, 0xd2, - 0xb5, 0x0f, 0x0f, 0xaf, 0x76, 0x4a, 0xf1, 0xe5, 0xca, 0x20, 0xcb, 0xcb, 0xe5, 0x8e, 0xca, 0x39, - 0xa0, 0x1d, 0xc8, 0x05, 0x1a, 0x64, 0xb0, 0xf8, 0x5c, 0x1a, 0x04, 0x74, 0xd0, 0x12, 0x8c, 0xef, - 0xb5, 0xa8, 0xc6, 0x76, 0xf7, 0xb5, 0x96, 0x4b, 0xe6, 0x45, 0x2c, 0x48, 0x19, 0x15, 0xf8, 0xd6, - 0xfb, 0xde, 0x0e, 0xba, 0x00, 0x13, 0x75, 0xea, 0x56, 0x5b, 0x24, 0x80, 0xc8, 0x62, 0x41, 0x12, - 0xd4, 0x71, 0x7f, 0xcf, 0x07, 0x59, 0x82, 0x71, 0xdd, 0x64, 0x6f, 0xac, 0x04, 0x10, 0xc3, 0x58, - 0x90, 0x44, 0x15, 0xf8, 0x56, 0x44, 0xc3, 0x8d, 0x43, 0xe4, 0xb0, 0x20, 0x65, 0xd5, 0x71, 0x37, - 0x06, 0xe2, 0xd3, 0xb8, 0x52, 0x0e, 0x20, 0x46, 0xb0, 0x20, 0x0d, 0x73, 0x1a, 0x57, 0xca, 0x3e, - 0xc0, 0x4b, 0x30, 0xb9, 0xa7, 0x1f, 0x90, 0x7a, 0x44, 0x64, 0x14, 0x0b, 0x52, 0x4e, 0x9d, 0x08, - 0x36, 0x93, 0x40, 0x11, 0x9d, 0x31, 0x2c, 0x48, 0x23, 0x01, 0x50, 0x48, 0xe9, 0x05, 0x80, 0x2a, - 0xa5, 0xad, 0x00, 0x02, 0xb0, 0x20, 0x8d, 0xaa, 0x63, 0xde, 0x4e, 0x24, 0xac, 0xc3, 0x6c, 0xdd, - 0x6c, 0x04, 0x00, 0xe3, 0x9e, 0x57, 0xd5, 0x71, 0x7f, 0x2f, 0x12, 0xb6, 0xda, 0x66, 0xc4, 0x09, - 0x20, 0x5e, 0xc0, 0x82, 0x34, 0xa1, 0x02, 0xdf, 0x4a, 0x28, 0x1c, 0x89, 0x31, 0x89, 0x05, 0x69, - 0xd2, 0x57, 0x38, 0x94, 0xe2, 0x36, 0x80, 0x97, 0x4a, 0x01, 0xc0, 0x14, 0x16, 0xa4, 0xa9, 0xf2, - 0xeb, 0x27, 0xba, 0x73, 0xdb, 0x35, 0x88, 0xad, 0xd7, 0x36, 0x4d, 0xd7, 0x50, 0xc7, 0x3c, 0x7c, - 0x9f, 0xd8, 0x0e, 0x4c, 0x47, 0xc9, 0x19, 0x50, 0x7c, 0x91, 0x53, 0x94, 0xfa, 0x50, 0x0c, 0x73, - 0x5a, 0xde, 0xd1, 0x58, 0x93, 0x53, 0x9b, 0xb4, 0x82, 0x2f, 0x9f, 0xa2, 0x03, 0x73, 0x7e, 0x84, - 0xec, 0xa6, 0x09, 0x2f, 0x71, 0xc2, 0x6f, 0x9f, 0x44, 0xf8, 0x5d, 0x3f, 0xcb, 0x43, 0xfa, 0x41, - 0xdc, 0x45, 0xec, 0x66, 0xcd, 0xc4, 0xda, 0x67, 0xfa, 0x32, 0x4c, 0x39, 0x49, 0xff, 0x4d, 0x63, - 0x41, 0x9a, 0x56, 0x27, 0x9d, 0x84, 0x03, 0x23, 0xb0, 0x28, 0x16, 0xf2, 0x58, 0x90, 0xf2, 0x21, - 0x58, 0x2c, 0xea, 0x9c, 0xb8, 0x13, 0x66, 0xb0, 0x20, 0xcd, 0xa8, 0xe3, 0x4e, 0xcc, 0x09, 0x01, - 0x48, 0x44, 0x07, 0x61, 0x41, 0x42, 0x3e, 0x48, 0x48, 0xa5, 0x0c, 0x67, 0x6d, 0x62, 0x11, 0xcd, - 0x33, 0x45, 0x22, 0x2e, 0x66, 0xb1, 0x28, 0x8d, 0xa9, 0xb3, 0xe1, 0xe1, 0xfd, 0x58, 0x7c, 0x5c, - 0x83, 0x71, 0x6a, 0x12, 0xaf, 0xae, 0x7b, 0x65, 0x77, 0xfe, 0x0c, 0xaf, 0x36, 0x73, 0xb2, 0x5f, - 0xe9, 0xe4, 0xb0, 0xd2, 0xc9, 0x9b, 0xde, 0xe9, 0xad, 0x21, 0x15, 0x38, 0x30, 0x5f, 0xa1, 0x97, - 0x60, 0xc2, 0x47, 0xf5, 0x79, 0xcd, 0x9f, 0xf5, 0xa2, 0xef, 0xd6, 0x90, 0xea, 0x13, 0xf4, 0x99, - 0xa0, 0x47, 0x30, 0x66, 0x68, 0x56, 0x20, 0xc7, 0x1c, 0xaf, 0x04, 0xd7, 0x07, 0xaf, 0x04, 0xef, - 0x6a, 0x16, 0x17, 0x77, 0xd3, 0x64, 0x76, 0x5b, 0x1d, 0x35, 0x82, 0x25, 0x3a, 0x80, 0x59, 0x43, - 0xb3, 0xac, 0xb4, 0xbe, 0xe7, 0x38, 0x9f, 0x5b, 0xa7, 0xe2, 0x63, 0x25, 0xec, 0xe3, 0x33, 0x9c, - 0x31, 0xd2, 0xfb, 0x31, 0xce, 0x41, 0xec, 0xf9, 0x9c, 0xe7, 0x9f, 0x8f, 0xb3, 0x1f, 0x79, 0xdd, - 0x9c, 0x63, 0xfb, 0x68, 0x15, 0xe6, 0x4d, 0x6a, 0xae, 0x53, 0x73, 0x9f, 0x98, 0x5e, 0x3b, 0xd1, - 0x5a, 0xdb, 0x9a, 0xe1, 0x97, 0xb7, 0xf9, 0x02, 0x2f, 0x00, 0x7d, 0xcf, 0xd1, 0x3a, 0x4c, 0x47, - 0x3d, 0x2b, 0x90, 0xf8, 0x3c, 0xf7, 0x78, 0xa1, 0xcb, 0xe3, 0x0f, 0x42, 0x38, 0x75, 0x2a, 0x42, - 0xf1, 0x89, 0x3c, 0x82, 0x28, 0x92, 0xe2, 0xc9, 0xb6, 0x88, 0xc5, 0x81, 0xeb, 0xc2, 0x4c, 0x48, - 0x28, 0x4a, 0xac, 0xc2, 0xaf, 0x05, 0xc8, 0x05, 0xcd, 0x0a, 0x41, 0xd6, 0xd4, 0x0c, 0xe2, 0x37, - 0x2b, 0x95, 0x7f, 0xa3, 0x39, 0xc8, 0x69, 0x06, 0x75, 0x4d, 0x36, 0x9f, 0xe1, 0x85, 0x2a, 0x58, - 0xa1, 0x7b, 0x90, 0xa1, 0x8f, 0x79, 0x4f, 0x98, 0x2a, 0x57, 0x4e, 0xdb, 0x6a, 0xe4, 0x0d, 0x42, - 0x2c, 0x2e, 0x58, 0x86, 0x3e, 0x2e, 0x2e, 0xc1, 0x68, 0xb8, 0x46, 0x63, 0x30, 0x7c, 0xa3, 0x72, - 0xe7, 0xfe, 0x66, 0x7e, 0x08, 0x8d, 0x42, 0xf6, 0x81, 0xfa, 0xde, 0x66, 0x5e, 0x28, 0xe8, 0x30, - 0x99, 0x08, 0x4c, 0x94, 0x07, 0xf1, 0x31, 0x69, 0x07, 0xf2, 0x7a, 0x9f, 0x68, 0x0d, 0x86, 0x7d, - 0xeb, 0x64, 0x4e, 0x51, 0x35, 0x7d, 0xd4, 0xd5, 0xcc, 0x55, 0xa1, 0xb0, 0x01, 0x73, 0xbd, 0x63, - 0xb3, 0x07, 0xcf, 0x33, 0x71, 0x9e, 0x63, 0x71, 0x2a, 0xdf, 0x0d, 0xa9, 0xa4, 0xe3, 0xac, 0x07, - 0x95, 0xed, 0x38, 0x95, 0xe7, 0x69, 0xdf, 0xc7, 0xfc, 0x57, 0x3f, 0x17, 0x8e, 0x2a, 0xbf, 0x17, - 0xa0, 0xb1, 0x3c, 0x5b, 0xc1, 0x55, 0x9d, 0x61, 0xba, 0x87, 0x8f, 0xc7, 0xc9, 0xf2, 0xd6, 0x96, - 0xc9, 0xc2, 0x90, 0x6d, 0xe3, 0x1a, 0x35, 0xac, 0x96, 0x5e, 0xf3, 0x82, 0x03, 0x07, 0x63, 0x18, - 0x66, 0x6d, 0x8b, 0x60, 0x46, 0x71, 0x8d, 0xee, 0x13, 0x1b, 0x1b, 0x9a, 0xd9, 0xc6, 0x7b, 0x44, - 0x63, 0xae, 0x4d, 0x1c, 0x8f, 0xd6, 0x4e, 0x18, 0xbb, 0x7f, 0x12, 0xf8, 0x0c, 0xb2, 0xfc, 0x3e, - 0x5c, 0xbc, 0xa1, 0x9b, 0x75, 0x4c, 0x5d, 0x86, 0x0d, 0x6a, 0x13, 0xac, 0x55, 0xbd, 0xcf, 0xae, - 0xa1, 0x4b, 0x6e, 0x32, 0x66, 0x39, 0xab, 0x8a, 0xd2, 0xd0, 0x59, 0xd3, 0xad, 0xca, 0x35, 0x6a, - 0x28, 0x9e, 0xba, 0x25, 0x52, 0xa3, 0x4e, 0xdb, 0x61, 0x24, 0x58, 0x06, 0xda, 0xaf, 0x4d, 0x86, - 0x45, 0x93, 0xab, 0x56, 0xfc, 0xc5, 0x28, 0xcc, 0xa7, 0x69, 0xaa, 0x41, 0x60, 0xa3, 0x6b, 0xb0, - 0xc0, 0xdb, 0x52, 0x94, 0x32, 0xf1, 0x19, 0x46, 0xc0, 0xa2, 0x94, 0x51, 0xe7, 0x3c, 0x80, 0x10, - 0xe1, 0xc6, 0xf1, 0x3c, 0xf3, 0x26, 0x14, 0x92, 0xa8, 0x89, 0xe9, 0xc6, 0x1b, 0xab, 0x04, 0xf5, - 0x5c, 0x1c, 0x77, 0x23, 0x36, 0xe9, 0x74, 0xf1, 0x8d, 0x37, 0x0f, 0x11, 0x8b, 0x92, 0x98, 0xe4, - 0xbb, 0x75, 0xdc, 0x47, 0xba, 0xf8, 0x26, 0x26, 0xa2, 0x2c, 0x16, 0xa5, 0x6c, 0x92, 0xef, 0x7b, - 0xb1, 0x26, 0xd4, 0x8b, 0x6f, 0xd4, 0xd7, 0x86, 0xb1, 0x28, 0x0d, 0x77, 0xf1, 0x0d, 0x5b, 0xdc, - 0x5b, 0x70, 0x3e, 0x65, 0xaa, 0x44, 0xe7, 0xcc, 0x61, 0x51, 0xca, 0xa9, 0xf3, 0x09, 0x63, 0xc5, - 0x9b, 0x68, 0x6f, 0xf4, 0xd8, 0x9c, 0x26, 0x4a, 0x23, 0x3d, 0xd0, 0x43, 0xee, 0x5f, 0x83, 0xf9, - 0x24, 0x7a, 0x6c, 0xf2, 0x1a, 0xc5, 0xa2, 0x34, 0xaa, 0x9e, 0x8d, 0xe3, 0xae, 0x45, 0x53, 0x58, - 0x97, 0xb9, 0x12, 0xbd, 0x68, 0x8c, 0xf7, 0xde, 0x84, 0xb9, 0x92, 0xfd, 0x37, 0x65, 0xae, 0xf8, - 0xb4, 0x06, 0x58, 0x94, 0x26, 0x92, 0xe6, 0x5a, 0x3b, 0x9e, 0xdc, 0x7a, 0xba, 0x29, 0x52, 0x77, - 0x1c, 0x8b, 0xd2, 0x64, 0xb7, 0x9b, 0x42, 0x6d, 0x49, 0x5a, 0xdb, 0x58, 0x25, 0x9f, 0x38, 0x45, - 0x25, 0x4f, 0xd8, 0xe6, 0x78, 0x4c, 0xba, 0x0e, 0x8b, 0x29, 0xdb, 0x24, 0x9d, 0x32, 0x89, 0x45, - 0x69, 0x5a, 0x5d, 0x48, 0x58, 0x27, 0x31, 0x40, 0xf5, 0x21, 0x10, 0x05, 0xc5, 0x14, 0x16, 0xa5, - 0x7c, 0x2f, 0x02, 0x7d, 0x83, 0x39, 0x31, 0x68, 0x4d, 0x63, 0x51, 0x9a, 0x49, 0x79, 0x27, 0x66, - 0xa5, 0x9e, 0xc8, 0xb1, 0x51, 0x4e, 0x94, 0x50, 0x37, 0x72, 0xc0, 0xb9, 0x58, 0x80, 0xec, 0x1a, - 0xad, 0xb7, 0x7b, 0xb5, 0xb1, 0xe2, 0x23, 0x98, 0x0e, 0xa6, 0xce, 0x6f, 0xe8, 0xac, 0xc9, 0xc1, - 0xa6, 0x20, 0x13, 0x5e, 0xcc, 0xd4, 0x8c, 0xee, 0x15, 0x8e, 0x6c, 0x5d, 0x63, 0x5a, 0x50, 0x7f, - 0x5f, 0x3e, 0xd1, 0x1b, 0x1e, 0x11, 0x95, 0xa3, 0x2c, 0x63, 0x18, 0x8f, 0xf9, 0xc6, 0xeb, 0x58, - 0x0f, 0x37, 0xd5, 0xbb, 0xf9, 0x21, 0x34, 0x02, 0xe2, 0xdd, 0xed, 0xcd, 0xbc, 0x50, 0xfe, 0xcf, - 0x02, 0x9c, 0x4b, 0x97, 0xac, 0xfb, 0xc4, 0xde, 0xd7, 0x6b, 0x04, 0x7d, 0x21, 0x42, 0x6e, 0xdd, - 0xf6, 0xd4, 0x41, 0x97, 0x07, 0xae, 0xfa, 0x85, 0xc1, 0x51, 0x8a, 0xff, 0xcc, 0xfc, 0xe0, 0xcf, - 0xff, 0xf8, 0x79, 0xe6, 0x6f, 0x99, 0xe2, 0x5f, 0x33, 0xca, 0xfe, 0xe5, 0xf0, 0xd5, 0xa1, 0xd7, - 0x9b, 0x83, 0x72, 0x18, 0x2b, 0x9f, 0x1d, 0xe5, 0x30, 0x5e, 0x11, 0x3b, 0xca, 0x61, 0xcc, 0x3b, - 0x1d, 0xc5, 0x21, 0x96, 0x66, 0x6b, 0x8c, 0xda, 0xca, 0xa1, 0x9b, 0x38, 0x38, 0x8c, 0x45, 0x40, - 0x47, 0x39, 0x4c, 0x04, 0x54, 0xb8, 0x8e, 0x9d, 0x1f, 0xd7, 0x81, 0x8e, 0x72, 0x18, 0xcf, 0xed, - 0xb7, 0x1c, 0x66, 0x5b, 0x36, 0xd9, 0xd3, 0x0f, 0x94, 0xe5, 0x8e, 0xcf, 0x24, 0x86, 0xe6, 0xa4, - 0xe9, 0x38, 0x69, 0x46, 0x4e, 0x0a, 0x21, 0x29, 0x64, 0xbf, 0x21, 0xae, 0xa3, 0x1c, 0x1e, 0xe7, - 0x6a, 0x47, 0x39, 0x4c, 0x5d, 0x7a, 0x3c, 0xcc, 0x9e, 0xb7, 0xa1, 0x0e, 0xfa, 0x95, 0x00, 0xe0, - 0x3b, 0x96, 0x07, 0xdc, 0x97, 0xe3, 0xdc, 0x65, 0xee, 0xdb, 0x8b, 0xc5, 0xa5, 0x13, 0x3c, 0xbb, - 0x2a, 0x2c, 0xa3, 0xef, 0x40, 0xee, 0x0e, 0xa5, 0x8f, 0x5d, 0x0b, 0x4d, 0xcb, 0x8e, 0x5b, 0x2d, - 0xcb, 0x5b, 0xf5, 0x20, 0x4b, 0x4e, 0xc3, 0x59, 0xe6, 0x9c, 0x25, 0xf4, 0x95, 0x13, 0x63, 0xca, - 0x1b, 0x16, 0x3a, 0xe8, 0x47, 0x02, 0xe4, 0xde, 0xb3, 0xea, 0xa7, 0x8c, 0xfb, 0x3e, 0x77, 0xa6, - 0xe2, 0x65, 0x2e, 0xc5, 0x6b, 0x85, 0x67, 0x94, 0xc2, 0x33, 0xc3, 0xcf, 0x04, 0xc8, 0x6d, 0x90, - 0x16, 0x61, 0xa4, 0xdb, 0x0e, 0xfd, 0xd8, 0x3c, 0x3a, 0xaa, 0xbc, 0x56, 0x7d, 0x15, 0xa6, 0x00, - 0x2a, 0x96, 0x7e, 0x9b, 0xb4, 0x2b, 0x2e, 0x6b, 0xa2, 0x21, 0x38, 0x07, 0xb9, 0xbb, 0xde, 0x67, - 0x19, 0x4d, 0x42, 0xd6, 0x26, 0x5a, 0x1d, 0x86, 0x9f, 0xd8, 0x3a, 0x23, 0xbe, 0x69, 0x96, 0x9f, - 0xd5, 0x34, 0x7f, 0x17, 0x60, 0xf4, 0x26, 0x61, 0xf7, 0x5c, 0x62, 0xb7, 0xff, 0x9f, 0xc6, 0xf9, - 0x54, 0x38, 0xaa, 0x3c, 0x28, 0x6e, 0xc3, 0x62, 0xaf, 0x31, 0x2d, 0x62, 0x38, 0xe0, 0x78, 0xf6, - 0x81, 0x50, 0x1d, 0xe2, 0xfa, 0xc9, 0xe8, 0xf5, 0x93, 0xf4, 0xfb, 0x96, 0xc7, 0x20, 0xd4, 0xf2, - 0xd3, 0x61, 0xc8, 0xdf, 0x24, 0x2c, 0xac, 0xe5, 0x3e, 0xf3, 0x6b, 0x03, 0x6b, 0x1b, 0xe2, 0x17, - 0x4e, 0x8f, 0x5a, 0xfc, 0x24, 0xcb, 0x35, 0xf8, 0xaf, 0x88, 0xfe, 0x2d, 0x9e, 0xa0, 0x43, 0xd4, - 0x9c, 0x82, 0x52, 0xd0, 0x6b, 0xd0, 0xec, 0xa4, 0xcf, 0x52, 0x75, 0xb3, 0xef, 0xa4, 0xd8, 0x75, - 0xe6, 0x3e, 0xed, 0x30, 0x59, 0xcf, 0x9e, 0x32, 0xcb, 0xf5, 0x3e, 0xed, 0x8b, 0x9b, 0xa8, 0xc0, - 0xfd, 0x67, 0xad, 0x6e, 0xbc, 0xe3, 0x59, 0xaa, 0xa7, 0x22, 0x7d, 0x19, 0x76, 0x17, 0xd8, 0x3e, - 0x03, 0x4c, 0x9f, 0xe3, 0xbe, 0x7a, 0x3a, 0x4f, 0xe3, 0x9a, 0x68, 0x00, 0xe8, 0x73, 0x11, 0xb2, - 0x9b, 0xb5, 0x26, 0x45, 0xfd, 0x1e, 0xc6, 0x1c, 0xb7, 0x2a, 0xfb, 0xa3, 0x64, 0x58, 0x1c, 0x9e, - 0x19, 0xb2, 0xf8, 0xaf, 0xcc, 0x51, 0xe5, 0xfb, 0x19, 0x98, 0x20, 0xb5, 0x26, 0xc5, 0x8e, 0xdf, - 0xf8, 0x61, 0x94, 0xaf, 0x6c, 0xab, 0x86, 0x66, 0xee, 0xbb, 0x86, 0xa1, 0xd9, 0xed, 0x55, 0xbc, - 0x19, 0x6c, 0x15, 0xf2, 0x1b, 0xc4, 0xa9, 0xd9, 0x3a, 0x7f, 0xcd, 0xe6, 0xbb, 0xc5, 0x0d, 0x40, - 0xc9, 0xb4, 0xe5, 0xd2, 0x0e, 0x98, 0xac, 0xef, 0x5c, 0x07, 0xf1, 0xab, 0x97, 0xae, 0xa0, 0xab, - 0xf0, 0x86, 0x4a, 0x98, 0x6b, 0x9b, 0xa4, 0x8e, 0x9f, 0x34, 0x89, 0x89, 0x59, 0x93, 0x60, 0x9b, - 0x38, 0xd4, 0xb5, 0x6b, 0x04, 0xeb, 0x0e, 0x66, 0xc4, 0xb0, 0xa8, 0xad, 0xd9, 0x7a, 0xab, 0x8d, - 0x5d, 0x53, 0xdb, 0xd7, 0xf4, 0x96, 0x56, 0x6d, 0x11, 0xf9, 0x9d, 0x37, 0x41, 0x5c, 0xb9, 0xb4, - 0x82, 0x56, 0x60, 0xf9, 0x29, 0x04, 0xea, 0x94, 0x38, 0xd8, 0xa4, 0x0c, 0x93, 0x03, 0xdd, 0x61, - 0x32, 0xca, 0x41, 0xf6, 0x97, 0x19, 0x41, 0xe4, 0x49, 0xf6, 0xe1, 0xc9, 0x65, 0xc2, 0x33, 0x8c, - 0x72, 0xe8, 0x3b, 0xe6, 0xe1, 0x42, 0x31, 0xaf, 0xec, 0x97, 0x23, 0x78, 0xef, 0x6c, 0xd5, 0xbf, - 0xe4, 0x3e, 0x44, 0xa8, 0xeb, 0x08, 0xfd, 0x56, 0x80, 0x89, 0x0d, 0x42, 0x2c, 0xfe, 0x7e, 0xe8, - 0x6d, 0x7c, 0x39, 0x7d, 0xf7, 0x3a, 0xd7, 0xed, 0x5a, 0x71, 0xe5, 0xc4, 0x12, 0x9f, 0xf8, 0xbd, - 0x41, 0xf6, 0xc6, 0x53, 0xde, 0x85, 0x2a, 0x00, 0xdb, 0x74, 0x4d, 0x37, 0xeb, 0xba, 0xd9, 0x70, - 0xd0, 0x42, 0x57, 0x05, 0xdf, 0x08, 0x7e, 0x8a, 0xe9, 0x5b, 0xdc, 0x87, 0xd0, 0xfb, 0x30, 0xf2, - 0x40, 0x37, 0x08, 0x75, 0x19, 0xea, 0x03, 0xd4, 0x17, 0xf9, 0x3c, 0x17, 0xff, 0x2c, 0x9a, 0x8d, - 0xdb, 0x93, 0x05, 0xc4, 0x9a, 0x90, 0xdf, 0xb4, 0x6d, 0x6a, 0x7b, 0xb3, 0xf3, 0x06, 0x61, 0x9a, - 0xde, 0x72, 0x06, 0x66, 0x70, 0x91, 0x33, 0x78, 0x11, 0x2d, 0x26, 0x1c, 0xe6, 0x51, 0x7d, 0xa2, - 0xb3, 0x66, 0x3d, 0xa0, 0xfa, 0x63, 0x01, 0xd0, 0x4d, 0xc2, 0xd2, 0xb3, 0xfa, 0xa5, 0x13, 0xfd, - 0x91, 0xc2, 0xe8, 0x2b, 0xc6, 0x2b, 0x5c, 0x8c, 0x0b, 0xc5, 0x85, 0xb8, 0x18, 0x9e, 0x04, 0x55, - 0x5a, 0x6f, 0x2b, 0x87, 0xde, 0x44, 0xc0, 0x67, 0x7a, 0xf4, 0x43, 0x01, 0x66, 0x76, 0xa8, 0xc3, - 0x3c, 0x8a, 0x1c, 0x95, 0x0b, 0xf2, 0x6c, 0xd7, 0x82, 0xbe, 0xdc, 0x15, 0xce, 0xfd, 0xd5, 0xe2, - 0xc5, 0x38, 0x77, 0x8b, 0x3a, 0xcc, 0x93, 0x80, 0xbf, 0x08, 0xfb, 0x62, 0x84, 0x41, 0x51, 0xf8, - 0x9d, 0x70, 0x54, 0xf9, 0x4c, 0x40, 0x7b, 0x7d, 0xee, 0x0e, 0xb8, 0x1e, 0x2b, 0x12, 0xa5, 0x12, - 0x7e, 0xd2, 0xd4, 0x6b, 0x4d, 0xec, 0x34, 0xa9, 0xdb, 0xaa, 0xf3, 0xf4, 0xab, 0x12, 0xec, 0x3a, - 0xa4, 0x8e, 0x75, 0x13, 0x5b, 0x2d, 0xad, 0x46, 0x30, 0xdd, 0xe3, 0x89, 0x5a, 0xa7, 0x35, 0xd7, - 0x20, 0xa6, 0xff, 0x03, 0x19, 0xae, 0x51, 0xc3, 0x5b, 0x5c, 0x28, 0xdc, 0x83, 0xa5, 0x5e, 0x93, - 0x81, 0x97, 0x46, 0xe1, 0x6d, 0x65, 0xc0, 0x7a, 0x53, 0xfe, 0x18, 0xce, 0xd4, 0x34, 0x83, 0xb4, - 0xd6, 0x35, 0x87, 0x04, 0x34, 0xbc, 0xd1, 0x1a, 0xa9, 0x30, 0xec, 0x3f, 0x6b, 0x0f, 0x1a, 0x48, - 0x0b, 0xdc, 0x86, 0xb3, 0x68, 0x26, 0x11, 0x48, 0xde, 0x51, 0xf9, 0x23, 0x58, 0xac, 0x98, 0x94, - 0x35, 0x89, 0x1d, 0x70, 0xf2, 0x9c, 0x17, 0x4b, 0xaa, 0xb7, 0x13, 0x29, 0x36, 0x28, 0xe3, 0xa1, - 0xb5, 0xcf, 0x46, 0x8e, 0x2a, 0xbf, 0x19, 0x41, 0x7f, 0x11, 0x60, 0xb6, 0x82, 0xd7, 0xfc, 0x07, - 0xb5, 0x58, 0x09, 0xf8, 0x00, 0xce, 0x34, 0xd4, 0x9d, 0xf5, 0xd2, 0x4d, 0x5f, 0x75, 0x6c, 0xd9, - 0xf4, 0x63, 0x52, 0x63, 0x83, 0x9a, 0xac, 0x90, 0x37, 0xa9, 0x49, 0xbe, 0x1e, 0xa8, 0xe6, 0x41, - 0x2f, 0x7f, 0x04, 0x67, 0xd6, 0xee, 0x6f, 0xe0, 0x2b, 0xa5, 0xf5, 0x96, 0xe6, 0x3a, 0x04, 0xdf, - 0xd1, 0x6b, 0xc4, 0x74, 0x08, 0xba, 0x31, 0x18, 0x65, 0xa5, 0xda, 0xa2, 0x55, 0xc5, 0xd0, 0x1c, - 0x46, 0x6c, 0xe5, 0xce, 0xd6, 0xfa, 0xe6, 0xf6, 0xfd, 0x4d, 0x99, 0x1d, 0xb0, 0xb2, 0x78, 0x59, - 0xbe, 0xb4, 0x2c, 0x0a, 0x99, 0x6c, 0x39, 0xaf, 0x59, 0xfe, 0x33, 0xa0, 0x4e, 0x4d, 0xe5, 0x63, - 0x87, 0x9a, 0xe5, 0xb9, 0xf8, 0xce, 0x41, 0x69, 0x8f, 0xd2, 0x92, 0xa1, 0x1b, 0x64, 0xb5, 0x0b, - 0x72, 0xb5, 0x0f, 0xa4, 0xba, 0xe3, 0x75, 0x8c, 0x2b, 0x68, 0x0b, 0x6e, 0x76, 0x77, 0x0c, 0xd7, - 0x21, 0xf6, 0x71, 0xb7, 0x68, 0x6a, 0xfb, 0x04, 0x5b, 0xc4, 0x36, 0x74, 0xc7, 0xf1, 0x02, 0x93, - 0x51, 0xac, 0xd5, 0x6a, 0xc4, 0x71, 0x12, 0xdd, 0x45, 0x56, 0x9f, 0xa3, 0x07, 0x8d, 0xa8, 0xb7, - 0x40, 0x5c, 0xb9, 0x7c, 0x15, 0x55, 0x60, 0x72, 0xeb, 0x15, 0x03, 0x6b, 0x98, 0x11, 0xcd, 0xa2, - 0x4c, 0x46, 0x97, 0x40, 0x2e, 0x0c, 0xf4, 0x08, 0xf3, 0xf0, 0x27, 0x19, 0x98, 0x86, 0xb1, 0x35, - 0xcd, 0xd1, 0x6b, 0x7c, 0xfe, 0xcf, 0x8c, 0x0a, 0xf0, 0x42, 0xe2, 0x46, 0x30, 0x3d, 0x9a, 0x29, - 0x8c, 0x7d, 0x50, 0xaa, 0xec, 0x6c, 0x95, 0x6e, 0x93, 0x36, 0xce, 0xc0, 0x17, 0x42, 0x74, 0x43, - 0xf8, 0xa3, 0x30, 0x2a, 0x4a, 0xd9, 0xf2, 0x4b, 0xa1, 0x0f, 0x63, 0x0e, 0x57, 0xa8, 0xe6, 0xb2, - 0xa6, 0xe2, 0xfd, 0xa1, 0xb6, 0xfe, 0x6d, 0xb2, 0xba, 0xd4, 0x1f, 0x88, 0xd1, 0xc7, 0xc4, 0x5c, - 0xfb, 0x1e, 0x14, 0xfc, 0x0b, 0x07, 0x42, 0x37, 0x6d, 0xcd, 0x64, 0x0e, 0xf6, 0x16, 0x81, 0xf5, - 0x60, 0x31, 0xb8, 0x86, 0xa0, 0xd9, 0xe0, 0x90, 0xaf, 0xc2, 0xd3, 0x75, 0x18, 0xd6, 0xea, 0x86, - 0x6e, 0xa2, 0xd5, 0x04, 0xaa, 0x59, 0x4f, 0x80, 0x71, 0x67, 0x78, 0x60, 0xba, 0xc3, 0xbc, 0x4e, - 0xb4, 0x4f, 0xb0, 0x6e, 0xee, 0x51, 0xdb, 0xe0, 0xfe, 0xae, 0x2e, 0xc1, 0x64, 0xdc, 0x14, 0x43, - 0xe9, 0xab, 0x51, 0xf5, 0xd5, 0xbe, 0x97, 0xa3, 0x34, 0xa8, 0xbd, 0x05, 0xe7, 0xde, 0x3d, 0xae, - 0x3e, 0xf1, 0x9c, 0x1a, 0x34, 0x97, 0x1e, 0x8e, 0x45, 0x9e, 0xab, 0xe6, 0x78, 0x3e, 0x5f, 0xf9, - 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x16, 0x9f, 0xcc, 0xe3, 0x75, 0x21, 0x00, 0x00, + proto.RegisterFile("examples/proto/examplepb/a_bit_of_everything.proto", fileDescriptor_a_bit_of_everything_7494e8194e1b43f3) +} + +var fileDescriptor_a_bit_of_everything_7494e8194e1b43f3 = []byte{ + // 2901 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x59, 0xcd, 0x6f, 0x1b, 0xd7, + 0xb5, 0xd7, 0x70, 0xa8, 0xaf, 0xa3, 0x2f, 0xea, 0xca, 0x1f, 0x32, 0xad, 0x44, 0xd7, 0x8c, 0xf3, + 0x32, 0x51, 0x42, 0x8e, 0x4d, 0xfb, 0xe5, 0xd9, 0x0a, 0x12, 0x3f, 0xea, 0xc3, 0xb6, 0x62, 0x5b, + 0x96, 0xc7, 0x8e, 0x5f, 0xe0, 0xe7, 0x44, 0xb8, 0x24, 0xaf, 0xc8, 0xb1, 0x39, 0x73, 0x27, 0x73, + 0xef, 0xc8, 0x66, 0x55, 0xb5, 0x69, 0x0b, 0xb4, 0x68, 0xb3, 0x28, 0xe0, 0x74, 0x55, 0x14, 0x5d, + 0x77, 0xd1, 0x6d, 0x57, 0x59, 0xb4, 0x5d, 0xa4, 0x9b, 0xee, 0xda, 0x22, 0x40, 0x51, 0xa0, 0x9b, + 0xb6, 0x40, 0xff, 0x82, 0x02, 0xdd, 0x15, 0x73, 0x67, 0x86, 0x9a, 0x19, 0x92, 0x96, 0x69, 0x07, + 0xd9, 0x48, 0x73, 0xe7, 0x9e, 0xf3, 0x3b, 0x9f, 0xf7, 0x9c, 0x73, 0x87, 0x50, 0xa6, 0x8f, 0x89, + 0xe5, 0xb4, 0x28, 0xd7, 0x1d, 0x97, 0x09, 0xa6, 0x87, 0x4b, 0xa7, 0xaa, 0x93, 0xed, 0xaa, 0x29, + 0xb6, 0xd9, 0xce, 0x36, 0xdd, 0xa5, 0x6e, 0x5b, 0x34, 0x4d, 0xbb, 0x51, 0x92, 0x34, 0x68, 0xb1, + 0xe1, 0x3a, 0xb5, 0x52, 0x83, 0x08, 0xfa, 0x88, 0xb4, 0x4b, 0x11, 0x40, 0xa9, 0xc3, 0x9a, 0x5f, + 0x68, 0x30, 0xd6, 0x68, 0x51, 0x9d, 0x38, 0xa6, 0x4e, 0x6c, 0x9b, 0x09, 0x22, 0x4c, 0x66, 0xf3, + 0x80, 0x3d, 0x8f, 0xc3, 0x5d, 0xb9, 0xaa, 0x7a, 0x3b, 0xfa, 0x8e, 0x49, 0x5b, 0xf5, 0x6d, 0x8b, + 0xf0, 0x87, 0x21, 0xc5, 0xc9, 0x34, 0x05, 0xb5, 0x1c, 0xd1, 0x0e, 0x37, 0x5f, 0x4e, 0x6f, 0xd6, + 0x3d, 0x57, 0xe2, 0x87, 0xfb, 0xaf, 0xa5, 0x2c, 0x72, 0x88, 0x68, 0x52, 0xdb, 0xb3, 0xe4, 0xc3, + 0xb6, 0xff, 0x14, 0xe9, 0x91, 0x22, 0xe4, 0x5e, 0x55, 0xb7, 0x28, 0xe7, 0xa4, 0x41, 0x43, 0x8a, + 0x53, 0xdd, 0x14, 0xe5, 0x14, 0xc9, 0x62, 0x5a, 0x1b, 0x61, 0x5a, 0x94, 0x0b, 0x62, 0x39, 0x21, + 0xc1, 0x9b, 0xf2, 0x5f, 0xad, 0xd8, 0xa0, 0x76, 0x91, 0x3f, 0x22, 0x8d, 0x06, 0x75, 0x75, 0xe6, + 0x48, 0x7f, 0x74, 0xfb, 0xa6, 0xf0, 0xbb, 0x39, 0xc8, 0x55, 0x56, 0x4c, 0x71, 0x73, 0x67, 0xbd, + 0xe3, 0x75, 0xf4, 0x21, 0x4c, 0x71, 0xd3, 0x6e, 0xb4, 0xe8, 0xb6, 0x4d, 0xb9, 0xa0, 0xf5, 0xf9, + 0x13, 0x58, 0xd1, 0x26, 0xca, 0x17, 0x4a, 0x87, 0xc4, 0xa1, 0x94, 0x46, 0x2a, 0x6d, 0x4a, 0x7e, + 0x63, 0x32, 0x80, 0x0b, 0x56, 0xa8, 0x09, 0x59, 0xcf, 0x33, 0xeb, 0xf3, 0x0a, 0x56, 0xb4, 0xf1, + 0x95, 0x3b, 0x4f, 0x2a, 0xb7, 0x3e, 0x51, 0x94, 0x1f, 0x29, 0xd7, 0xfe, 0x9f, 0x14, 0x77, 0x2a, + 0xc5, 0xcb, 0x67, 0x8a, 0x17, 0x3f, 0xdc, 0xbb, 0xb0, 0x5f, 0x8c, 0x2f, 0xcf, 0x0f, 0xb2, 0x3c, + 0x5b, 0xde, 0x37, 0xa4, 0x04, 0xb4, 0x05, 0x23, 0xa1, 0x05, 0x19, 0xac, 0xbe, 0x90, 0x05, 0x21, + 0x0e, 0x5a, 0x84, 0x89, 0x9d, 0x16, 0x23, 0x62, 0x7b, 0x97, 0xb4, 0x3c, 0x3a, 0xaf, 0x62, 0x45, + 0xcb, 0x18, 0x20, 0x5f, 0xdd, 0xf5, 0xdf, 0xa0, 0x53, 0x30, 0x59, 0x67, 0x5e, 0xb5, 0x45, 0x43, + 0x8a, 0x2c, 0x56, 0x34, 0xc5, 0x98, 0x08, 0xde, 0x05, 0x24, 0x8b, 0x30, 0x61, 0xda, 0xe2, 0xad, + 0xf3, 0x21, 0xc5, 0x30, 0x56, 0x34, 0xd5, 0x00, 0xf9, 0xaa, 0x83, 0xe1, 0xc5, 0x29, 0x46, 0xb0, + 0xa2, 0x65, 0x8d, 0x09, 0x2f, 0x46, 0x12, 0x60, 0x9c, 0x2b, 0x87, 0x14, 0xa3, 0x58, 0xd1, 0x86, + 0x25, 0xc6, 0xb9, 0x72, 0x40, 0xf0, 0x0a, 0x4c, 0xed, 0x98, 0x8f, 0x69, 0xbd, 0x03, 0x32, 0x86, + 0x15, 0x6d, 0xc4, 0x98, 0x0c, 0x5f, 0x26, 0x89, 0x3a, 0x38, 0xe3, 0x58, 0xd1, 0x46, 0x43, 0xa2, + 0x08, 0xe9, 0x25, 0x80, 0x2a, 0x63, 0xad, 0x90, 0x02, 0xb0, 0xa2, 0x8d, 0x19, 0xe3, 0xfe, 0x9b, + 0x8e, 0xb2, 0x5c, 0xb8, 0xa6, 0xdd, 0x08, 0x09, 0x26, 0xfc, 0xa8, 0x1a, 0x13, 0xc1, 0xbb, 0x8e, + 0xb2, 0xd5, 0xb6, 0xa0, 0x3c, 0xa4, 0x78, 0x09, 0x2b, 0xda, 0xa4, 0x01, 0xf2, 0x55, 0xc2, 0xe0, + 0x8e, 0x1a, 0x53, 0x58, 0xd1, 0xa6, 0x02, 0x83, 0x23, 0x2d, 0xae, 0x01, 0xf8, 0x47, 0x29, 0x24, + 0x98, 0xc6, 0x8a, 0x36, 0x5d, 0x7e, 0xf3, 0xd0, 0x70, 0x6e, 0x7a, 0x16, 0x75, 0xcd, 0xda, 0xba, + 0xed, 0x59, 0xc6, 0xb8, 0xcf, 0x1f, 0x80, 0x6d, 0xc1, 0x4c, 0xe7, 0x70, 0x86, 0x88, 0x2f, 0x4b, + 0x44, 0xad, 0x0f, 0x62, 0x74, 0xa6, 0x4b, 0x5b, 0x44, 0x34, 0x25, 0xda, 0x94, 0x13, 0x3e, 0x05, + 0x88, 0x1c, 0x8e, 0x05, 0x19, 0xb2, 0x9d, 0x06, 0x5e, 0x94, 0xc0, 0xef, 0x1e, 0x06, 0x7c, 0x23, + 0x38, 0xe5, 0x11, 0x7e, 0x98, 0x77, 0x1d, 0x71, 0x73, 0x76, 0x62, 0x1d, 0x08, 0x7d, 0x15, 0xa6, + 0x79, 0x32, 0x7e, 0x33, 0x58, 0xd1, 0x66, 0x8c, 0x29, 0x9e, 0x08, 0x60, 0x87, 0xac, 0x93, 0x0b, + 0x39, 0xac, 0x68, 0xb9, 0x88, 0x2c, 0x96, 0x75, 0x3c, 0x1e, 0x84, 0x59, 0xac, 0x68, 0xb3, 0xc6, + 0x04, 0x8f, 0x05, 0x21, 0x24, 0xe9, 0xe0, 0x20, 0xac, 0x68, 0x28, 0x20, 0x89, 0x50, 0xca, 0x70, + 0xd4, 0xa5, 0x0e, 0x25, 0xbe, 0x2b, 0x12, 0x79, 0x31, 0x87, 0x55, 0x6d, 0xdc, 0x98, 0x8b, 0x36, + 0x6f, 0xc7, 0xf2, 0xe3, 0x22, 0x4c, 0x30, 0x9b, 0xfa, 0x95, 0xdf, 0x2f, 0xbb, 0xf3, 0x47, 0x64, + 0xb5, 0x39, 0x56, 0x0a, 0x2a, 0x5d, 0x29, 0xaa, 0x74, 0xa5, 0x75, 0x7f, 0xf7, 0xea, 0x90, 0x01, + 0x92, 0x58, 0xae, 0xd0, 0x2b, 0x30, 0x19, 0xb0, 0x06, 0xb2, 0xe6, 0x8f, 0xfa, 0xd9, 0x77, 0x75, + 0xc8, 0x08, 0x00, 0x03, 0x21, 0xe8, 0x3e, 0x8c, 0x5b, 0xc4, 0x09, 0xf5, 0x38, 0x26, 0x2b, 0xc1, + 0xa5, 0xc1, 0x2b, 0xc1, 0x0d, 0xe2, 0x48, 0x75, 0xd7, 0x6d, 0xe1, 0xb6, 0x8d, 0x31, 0x2b, 0x5c, + 0xa2, 0xc7, 0x30, 0x67, 0x11, 0xc7, 0x49, 0xdb, 0x7b, 0x5c, 0xca, 0xb9, 0xfa, 0x5c, 0x72, 0x9c, + 0x84, 0x7f, 0x02, 0x81, 0xb3, 0x56, 0xfa, 0x7d, 0x4c, 0x72, 0x98, 0x7b, 0x81, 0xe4, 0xf9, 0x17, + 0x93, 0x1c, 0x64, 0x5e, 0xb7, 0xe4, 0xd8, 0x7b, 0xb4, 0x0c, 0xf3, 0x36, 0xb3, 0x57, 0x99, 0xbd, + 0x4b, 0x6d, 0xbf, 0x9d, 0x90, 0xd6, 0x26, 0xb1, 0x82, 0xf2, 0x36, 0x9f, 0x97, 0x05, 0xa0, 0xef, + 0x3e, 0x5a, 0x85, 0x99, 0x4e, 0xcf, 0x0a, 0x35, 0x3e, 0x29, 0x23, 0x9e, 0xef, 0x8a, 0xf8, 0x9d, + 0x88, 0xce, 0x98, 0xee, 0xb0, 0x04, 0x20, 0xf7, 0xa1, 0x93, 0x49, 0xf1, 0xc3, 0xb6, 0x80, 0xd5, + 0x81, 0xeb, 0xc2, 0x6c, 0x04, 0xd4, 0x39, 0x58, 0xf9, 0x5f, 0x28, 0x30, 0x12, 0x36, 0x2b, 0x04, + 0x59, 0x9b, 0x58, 0x34, 0x68, 0x56, 0x86, 0x7c, 0x46, 0xc7, 0x60, 0x84, 0x58, 0xcc, 0xb3, 0xc5, + 0x7c, 0x46, 0x16, 0xaa, 0x70, 0x85, 0x6e, 0x41, 0x86, 0x3d, 0x94, 0x3d, 0x61, 0xba, 0x5c, 0x79, + 0xde, 0x56, 0x53, 0x5a, 0xa3, 0xd4, 0x91, 0x8a, 0x65, 0xd8, 0xc3, 0xc2, 0x22, 0x8c, 0x45, 0x6b, + 0x34, 0x0e, 0xc3, 0x97, 0x2b, 0xd7, 0x6f, 0xaf, 0xe7, 0x86, 0xd0, 0x18, 0x64, 0xef, 0x18, 0xef, + 0xaf, 0xe7, 0x94, 0xbc, 0x09, 0x53, 0x89, 0xc4, 0x44, 0x39, 0x50, 0x1f, 0xd2, 0x76, 0xa8, 0xaf, + 0xff, 0x88, 0x56, 0x60, 0x38, 0xf0, 0x4e, 0xe6, 0x39, 0xaa, 0x66, 0xc0, 0xba, 0x9c, 0xb9, 0xa0, + 0xe4, 0xd7, 0xe0, 0x58, 0xef, 0xdc, 0xec, 0x21, 0xf3, 0x48, 0x5c, 0xe6, 0x78, 0x1c, 0xe5, 0x5b, + 0x11, 0x4a, 0x3a, 0xcf, 0x7a, 0xa0, 0x6c, 0xc6, 0x51, 0x5e, 0xa4, 0x7d, 0x1f, 0xc8, 0x5f, 0xfe, + 0x42, 0x79, 0x52, 0xf9, 0xad, 0x02, 0x8d, 0xa5, 0xb9, 0x0a, 0xae, 0x9a, 0x02, 0xb3, 0x1d, 0x7c, + 0x30, 0x70, 0x96, 0x37, 0x36, 0x6c, 0x11, 0xa5, 0x6c, 0x1b, 0xd7, 0x98, 0xe5, 0xb4, 0xcc, 0x9a, + 0x9f, 0x1c, 0x38, 0x1c, 0xc3, 0xb0, 0x68, 0x3b, 0x14, 0x0b, 0x86, 0x6b, 0x6c, 0x97, 0xba, 0xd8, + 0x22, 0x76, 0x1b, 0xef, 0x50, 0x22, 0x3c, 0x97, 0x72, 0x1f, 0x6b, 0x2b, 0xca, 0xdd, 0x3f, 0x28, + 0x72, 0x06, 0x59, 0xba, 0x0b, 0xa7, 0x2f, 0x9b, 0x76, 0x1d, 0x33, 0x4f, 0x60, 0x8b, 0xb9, 0x14, + 0x93, 0xaa, 0xff, 0xd8, 0x35, 0x74, 0x95, 0x9a, 0x42, 0x38, 0x7c, 0x59, 0xd7, 0x1b, 0xa6, 0x68, + 0x7a, 0xd5, 0x52, 0x8d, 0x59, 0xba, 0x6f, 0x6e, 0x91, 0xd6, 0x18, 0x6f, 0x73, 0x41, 0xc3, 0x65, + 0x68, 0xfd, 0xca, 0x54, 0x54, 0x34, 0xa5, 0x69, 0x85, 0x9f, 0x8c, 0xc1, 0x7c, 0x1a, 0xd3, 0x08, + 0x13, 0x1b, 0x5d, 0x84, 0x13, 0xb2, 0x2d, 0x75, 0x8e, 0x4c, 0x7c, 0x86, 0x51, 0xb0, 0xaa, 0x65, + 0x8c, 0x63, 0x3e, 0x41, 0xc4, 0x70, 0xf9, 0x60, 0x9e, 0x79, 0x1b, 0xf2, 0x49, 0xd6, 0xc4, 0x74, + 0xe3, 0x8f, 0x55, 0x8a, 0x71, 0x3c, 0xce, 0xbb, 0x16, 0x9b, 0x74, 0xba, 0xe4, 0xc6, 0x9b, 0x87, + 0x8a, 0x55, 0x4d, 0x4d, 0xca, 0xdd, 0x38, 0xe8, 0x23, 0x5d, 0x72, 0x13, 0x13, 0x51, 0x16, 0xab, + 0x5a, 0x36, 0x29, 0xf7, 0xfd, 0x58, 0x13, 0xea, 0x25, 0xb7, 0xd3, 0xd7, 0x86, 0xb1, 0xaa, 0x0d, + 0x77, 0xc9, 0x8d, 0x5a, 0xdc, 0x3b, 0x70, 0x32, 0xe5, 0xaa, 0x44, 0xe7, 0x1c, 0xc1, 0xaa, 0x36, + 0x62, 0xcc, 0x27, 0x9c, 0x15, 0x6f, 0xa2, 0xbd, 0xd9, 0x63, 0x73, 0x9a, 0xaa, 0x8d, 0xf6, 0x60, + 0x8f, 0xa4, 0xff, 0x0f, 0xcc, 0x27, 0xd9, 0x63, 0x93, 0xd7, 0x18, 0x56, 0xb5, 0x31, 0xe3, 0x68, + 0x9c, 0x77, 0xa5, 0x33, 0x85, 0x75, 0xb9, 0x2b, 0xd1, 0x8b, 0xc6, 0x65, 0xef, 0x4d, 0xb8, 0x2b, + 0xd9, 0x7f, 0x53, 0xee, 0x8a, 0x4f, 0x6b, 0x80, 0x55, 0x6d, 0x32, 0xe9, 0xae, 0x95, 0x83, 0xc9, + 0xad, 0x67, 0x98, 0x3a, 0xe6, 0x4e, 0x60, 0x55, 0x9b, 0xea, 0x0e, 0x53, 0x64, 0x2d, 0x4d, 0x5b, + 0x1b, 0xab, 0xe4, 0x93, 0xcf, 0x51, 0xc9, 0x13, 0xbe, 0x39, 0x18, 0x93, 0x2e, 0xc1, 0x42, 0xca, + 0x37, 0xc9, 0xa0, 0x4c, 0x61, 0x55, 0x9b, 0x31, 0x4e, 0x24, 0xbc, 0x93, 0x18, 0xa0, 0xfa, 0x00, + 0x74, 0x92, 0x62, 0x1a, 0xab, 0x5a, 0xae, 0x17, 0x40, 0xdf, 0x64, 0x4e, 0x0c, 0x5a, 0x33, 0x58, + 0xd5, 0x66, 0x53, 0xd1, 0x89, 0x79, 0xa9, 0x27, 0x73, 0x6c, 0x94, 0x53, 0x35, 0xd4, 0xcd, 0x1c, + 0x4a, 0x2e, 0xe4, 0x21, 0xbb, 0xc2, 0xea, 0xed, 0x5e, 0x6d, 0xac, 0x70, 0x1f, 0x66, 0xc2, 0xa9, + 0xf3, 0xff, 0x4c, 0xd1, 0x94, 0x64, 0xd3, 0x90, 0x89, 0x2e, 0x66, 0x46, 0xc6, 0xf4, 0x0b, 0x47, + 0xb6, 0x4e, 0x04, 0x09, 0xeb, 0xef, 0xab, 0x87, 0x46, 0xc3, 0x07, 0x31, 0x24, 0x4b, 0xe1, 0x33, + 0x05, 0x66, 0xde, 0x77, 0xea, 0x44, 0xd0, 0xbb, 0x65, 0x83, 0x7e, 0xec, 0x51, 0x2e, 0xd0, 0x2a, + 0xa8, 0xa4, 0x1a, 0x28, 0x31, 0x51, 0x3e, 0x3b, 0x70, 0x35, 0x37, 0x7c, 0x6e, 0xf4, 0x36, 0x4c, + 0x78, 0x12, 0x57, 0xde, 0xe0, 0x43, 0xd5, 0xba, 0x67, 0x87, 0xcb, 0xfe, 0x25, 0xff, 0x06, 0xe1, + 0x0f, 0x0d, 0x08, 0xc8, 0xfd, 0xe7, 0x25, 0x0c, 0x13, 0xb1, 0x8c, 0xf1, 0xfb, 0xe8, 0xbd, 0x75, + 0xe3, 0x66, 0x6e, 0x08, 0x8d, 0x82, 0x7a, 0x73, 0x73, 0x3d, 0xa7, 0x94, 0xff, 0xbc, 0x00, 0xc7, + 0xd3, 0x82, 0x6f, 0x53, 0x77, 0xd7, 0xac, 0x51, 0xf4, 0xa5, 0x0a, 0x23, 0xab, 0xae, 0xef, 0x64, + 0x34, 0xb8, 0xf6, 0xf9, 0xc1, 0x59, 0x0a, 0xff, 0xc8, 0x7c, 0xf7, 0x8f, 0x7f, 0xff, 0x2c, 0xf3, + 0xd7, 0x4c, 0xe1, 0x2f, 0x19, 0x7d, 0xf7, 0x6c, 0xf4, 0xb5, 0xa4, 0xd7, 0xb7, 0x12, 0x7d, 0x2f, + 0x56, 0xd4, 0xf7, 0xf5, 0xbd, 0x78, 0x9d, 0xde, 0xd7, 0xf7, 0x62, 0x39, 0xb3, 0xaf, 0x73, 0xea, + 0x10, 0x97, 0x08, 0xe6, 0xea, 0x7b, 0x5e, 0x62, 0x63, 0x2f, 0x96, 0x97, 0xfb, 0xfa, 0x5e, 0x22, + 0xcd, 0xa3, 0x75, 0x6c, 0xff, 0xa0, 0x3a, 0xed, 0xeb, 0x7b, 0xf1, 0x8a, 0xf3, 0x0e, 0x17, 0xae, + 0xe3, 0xd2, 0x1d, 0xf3, 0xb1, 0xbe, 0xb4, 0x1f, 0x08, 0x89, 0xb1, 0xf1, 0x34, 0x0e, 0x4f, 0x0b, + 0xe2, 0x29, 0x86, 0xa4, 0x92, 0xfd, 0x46, 0xcb, 0x7d, 0x7d, 0xef, 0xa0, 0x82, 0xec, 0xeb, 0x7b, + 0xa9, 0xab, 0x98, 0xcf, 0xd9, 0xf3, 0x8e, 0xb6, 0x8f, 0x7e, 0xae, 0x00, 0x04, 0x81, 0x95, 0xc7, + 0xe0, 0xeb, 0x09, 0xee, 0x92, 0x8c, 0xed, 0xe9, 0xc2, 0xe2, 0x21, 0x91, 0x5d, 0x56, 0x96, 0xd0, + 0x37, 0x61, 0xe4, 0x3a, 0x63, 0x0f, 0x3d, 0x07, 0xcd, 0x94, 0xb8, 0x57, 0x2d, 0x97, 0x36, 0xea, + 0xe1, 0xd9, 0x7d, 0x1e, 0xc9, 0x25, 0x29, 0x59, 0x43, 0xff, 0x75, 0x68, 0x4e, 0xf9, 0x23, 0xcc, + 0x3e, 0xfa, 0xbe, 0x02, 0x23, 0xc1, 0x59, 0x7e, 0x1e, 0xd7, 0xf4, 0xb9, 0xc9, 0x15, 0xce, 0x4a, + 0x2d, 0xde, 0xc8, 0x3f, 0xa3, 0x16, 0xbe, 0x1b, 0x7e, 0xa3, 0xc0, 0x58, 0x54, 0x54, 0xd0, 0x99, + 0x43, 0x55, 0x49, 0xd5, 0x9f, 0xbe, 0x9a, 0x3c, 0x90, 0x9a, 0xd4, 0xf3, 0x4b, 0xfa, 0x6e, 0xf9, + 0xe9, 0x9a, 0x90, 0x2a, 0x2d, 0x05, 0xda, 0xf8, 0xb5, 0xe8, 0xde, 0xd9, 0xf2, 0xa0, 0x2c, 0xe8, + 0x67, 0x0a, 0xcc, 0x6f, 0x11, 0x51, 0x6b, 0xfa, 0x45, 0xb7, 0x53, 0xa4, 0x36, 0x6c, 0x99, 0x78, + 0x5f, 0x9d, 0x49, 0x6f, 0x49, 0x93, 0xce, 0x94, 0xdf, 0xd0, 0x77, 0xcb, 0xe4, 0x59, 0x15, 0x54, + 0x96, 0xd0, 0x8f, 0x15, 0x18, 0x59, 0xa3, 0x2d, 0x2a, 0x68, 0x77, 0xa6, 0xf5, 0x93, 0x75, 0xff, + 0x49, 0xe5, 0x8d, 0xea, 0xeb, 0x30, 0x0d, 0x50, 0x71, 0xcc, 0x6b, 0xb4, 0x5d, 0xf1, 0x44, 0x13, + 0x0d, 0xc1, 0x71, 0x18, 0xb9, 0xe9, 0x3f, 0x96, 0xd1, 0x14, 0x64, 0x5d, 0x4a, 0xea, 0x30, 0xfc, + 0xc8, 0x35, 0x05, 0x0d, 0x92, 0x6f, 0xe9, 0x59, 0x93, 0xef, 0x6f, 0x0a, 0x8c, 0x5d, 0xa1, 0xe2, + 0x96, 0x47, 0xdd, 0xf6, 0x57, 0x99, 0x7e, 0x9f, 0x2a, 0x4f, 0x2a, 0x77, 0x0a, 0x9b, 0xb0, 0xd0, + 0x6b, 0x3c, 0xef, 0x08, 0x1c, 0x70, 0x2c, 0xff, 0x40, 0xa9, 0x0e, 0x49, 0xfb, 0x4a, 0xe8, 0xcd, + 0xc3, 0xec, 0xfb, 0xd8, 0x17, 0x10, 0x59, 0xf9, 0xe9, 0x30, 0xe4, 0xae, 0x50, 0x11, 0xf5, 0xf0, + 0x40, 0xf8, 0xc5, 0xc1, 0x5b, 0x64, 0xc8, 0x9f, 0x7f, 0x7e, 0xd6, 0xc2, 0x27, 0x59, 0x69, 0xc1, + 0xbf, 0x55, 0xf4, 0x2f, 0xf5, 0x10, 0x1b, 0x3a, 0x43, 0x49, 0x58, 0x6c, 0x7b, 0x5d, 0x30, 0xf6, + 0xd3, 0x7b, 0xa9, 0xce, 0xd4, 0xf7, 0x86, 0xd0, 0xb5, 0xe7, 0x3d, 0x6d, 0x33, 0xd9, 0x31, 0x9e, + 0x32, 0xc3, 0xf7, 0xde, 0xed, 0xcb, 0x9b, 0xe8, 0x71, 0xfd, 0x67, 0xec, 0x6e, 0xbe, 0x83, 0x19, + 0xba, 0xa7, 0x21, 0x7d, 0x05, 0x76, 0xb7, 0xb0, 0x3e, 0x83, 0x6b, 0x9f, 0xed, 0xbe, 0x76, 0xf2, + 0xa7, 0x49, 0x4d, 0xb4, 0x58, 0xf4, 0x85, 0x0a, 0xd9, 0xf5, 0x5a, 0x93, 0xa1, 0x7e, 0x1f, 0x44, + 0xb9, 0x57, 0x2d, 0x05, 0x57, 0x88, 0xa8, 0x38, 0x3c, 0x33, 0x65, 0xe1, 0x9f, 0x99, 0x27, 0x95, + 0xef, 0x64, 0x60, 0x92, 0xd6, 0x9a, 0x0c, 0xf3, 0x60, 0xb4, 0x82, 0x31, 0xb9, 0x72, 0x9d, 0x1a, + 0x9a, 0xbd, 0xed, 0x59, 0x16, 0x71, 0xdb, 0xcb, 0x78, 0x3d, 0x7c, 0x95, 0xcf, 0xad, 0x51, 0x5e, + 0x73, 0x4d, 0xf9, 0x2b, 0x86, 0x7c, 0x5b, 0x58, 0x03, 0x94, 0x3c, 0xb6, 0x52, 0xdb, 0x01, 0x0f, + 0xeb, 0x7b, 0x97, 0x40, 0xfd, 0xef, 0x33, 0xe7, 0xd0, 0x05, 0x78, 0xcb, 0xa0, 0xc2, 0x73, 0x6d, + 0x5a, 0xc7, 0x8f, 0x9a, 0xd4, 0xc6, 0xa2, 0x49, 0xb1, 0x4b, 0x39, 0xf3, 0xdc, 0x1a, 0xc5, 0x26, + 0xc7, 0x82, 0x5a, 0x0e, 0x73, 0x89, 0x6b, 0xb6, 0xda, 0xd8, 0xb3, 0xc9, 0x2e, 0x31, 0x5b, 0xa4, + 0xda, 0xa2, 0xa5, 0xf7, 0xde, 0x06, 0xf5, 0xfc, 0x99, 0xf3, 0xe8, 0x3c, 0x2c, 0x3d, 0x05, 0xa0, + 0xce, 0x28, 0xc7, 0x36, 0x13, 0x98, 0x3e, 0x36, 0xb9, 0x28, 0xa1, 0x11, 0xc8, 0xfe, 0x34, 0xa3, + 0xa8, 0xf2, 0x90, 0x7d, 0x78, 0x78, 0x99, 0xf0, 0x1d, 0xa3, 0xef, 0x05, 0x81, 0xb9, 0x77, 0xa2, + 0x90, 0x8b, 0x37, 0x1c, 0x7f, 0x6f, 0x39, 0xf8, 0xb8, 0x71, 0x0f, 0xa1, 0xae, 0x2d, 0xf4, 0x2b, + 0x05, 0x26, 0xd7, 0x28, 0x75, 0xe4, 0x77, 0x63, 0xff, 0xc5, 0xd7, 0x33, 0xd9, 0x5c, 0x92, 0xb6, + 0x5d, 0x2c, 0x9c, 0x3f, 0xb4, 0xc4, 0x27, 0x7e, 0x67, 0x2a, 0xf9, 0xd7, 0x12, 0xd9, 0x85, 0x2a, + 0x00, 0x9b, 0x6c, 0xc5, 0xb4, 0xeb, 0xa6, 0xdd, 0xe0, 0xe8, 0x44, 0x57, 0x05, 0x5f, 0x0b, 0x7f, + 0x82, 0xeb, 0x5b, 0xdc, 0x87, 0xd0, 0x5d, 0x18, 0xbd, 0x63, 0x5a, 0x94, 0x79, 0x02, 0xf5, 0x21, + 0xea, 0xcb, 0x7c, 0x52, 0xaa, 0x7f, 0x14, 0xcd, 0xc5, 0xfd, 0x29, 0x42, 0xb0, 0x26, 0xe4, 0xd6, + 0x5d, 0x97, 0xb9, 0x7e, 0xfb, 0x5e, 0xa3, 0x82, 0x98, 0x2d, 0x3e, 0xb0, 0x80, 0xd3, 0x52, 0xc0, + 0xcb, 0x68, 0x21, 0x11, 0x30, 0x1f, 0xf5, 0x91, 0x29, 0x9a, 0xf5, 0x10, 0xf5, 0x07, 0x0a, 0xa0, + 0x2b, 0x54, 0xa4, 0xef, 0x68, 0x87, 0xcf, 0x08, 0x29, 0x8e, 0xbe, 0x6a, 0xbc, 0x26, 0xd5, 0x38, + 0x55, 0x38, 0x11, 0x57, 0xc3, 0xd7, 0xa0, 0xca, 0xea, 0x6d, 0x7d, 0xcf, 0x9f, 0x08, 0xe4, 0x5d, + 0x0e, 0x7d, 0x4f, 0x81, 0xd9, 0x2d, 0xc6, 0x85, 0x8f, 0x28, 0x59, 0xa5, 0x22, 0xcf, 0x76, 0x1d, + 0xec, 0x2b, 0x5d, 0x97, 0xd2, 0x5f, 0x2f, 0x9c, 0x8e, 0x4b, 0x77, 0x18, 0x17, 0xbe, 0x06, 0xf2, + 0x97, 0x80, 0x40, 0x8d, 0x28, 0x29, 0xf2, 0xbf, 0x56, 0x9e, 0x54, 0x3e, 0x57, 0xd0, 0x4e, 0x9f, + 0xdb, 0x19, 0xae, 0xc7, 0x8a, 0x44, 0xb1, 0x88, 0x1f, 0x35, 0xcd, 0x5a, 0x13, 0xf3, 0x26, 0xf3, + 0x5a, 0x75, 0x79, 0xfc, 0xaa, 0x14, 0x7b, 0x9c, 0xd6, 0xb1, 0x69, 0x63, 0xa7, 0x45, 0x6a, 0x14, + 0xb3, 0x1d, 0x79, 0x50, 0xeb, 0xac, 0xe6, 0x59, 0xd4, 0x0e, 0x7e, 0x18, 0xc5, 0x35, 0x66, 0xf9, + 0x8b, 0x53, 0xf9, 0x5b, 0xb0, 0xd8, 0x6b, 0x32, 0xf0, 0x8f, 0x51, 0x74, 0x1f, 0x1c, 0xb0, 0xde, + 0x94, 0x1f, 0xc0, 0x91, 0x1a, 0xb1, 0x68, 0x6b, 0x95, 0x70, 0x1a, 0x62, 0xf8, 0x97, 0x17, 0x64, + 0xc0, 0x70, 0xf0, 0x73, 0xc6, 0xa0, 0x89, 0x74, 0x42, 0xfa, 0x70, 0x0e, 0xcd, 0x26, 0x12, 0xc9, + 0xdf, 0x2a, 0x7f, 0x04, 0x0b, 0x15, 0x9b, 0x89, 0x26, 0x75, 0x43, 0x49, 0x7e, 0xf0, 0x62, 0x87, + 0xea, 0xdd, 0xc4, 0x11, 0x1b, 0x54, 0xf0, 0xd0, 0xca, 0xe7, 0xa3, 0x4f, 0x2a, 0xbf, 0x1c, 0x45, + 0x7f, 0x52, 0x60, 0xae, 0x82, 0x57, 0x82, 0x0f, 0xa9, 0xb1, 0x12, 0xf0, 0x01, 0x1c, 0x69, 0x18, + 0x5b, 0xab, 0xc5, 0x2b, 0x81, 0xe9, 0xd8, 0x71, 0xd9, 0x03, 0x5a, 0x13, 0x83, 0xba, 0x2c, 0x9f, + 0xb3, 0x99, 0x4d, 0xff, 0x37, 0x34, 0xcd, 0xa7, 0x5e, 0xfa, 0x08, 0x8e, 0xac, 0xdc, 0x5e, 0xc3, + 0xe7, 0x8a, 0xab, 0x2d, 0xe2, 0x71, 0x8a, 0xaf, 0x9b, 0x35, 0x6a, 0x73, 0x8a, 0x2e, 0x0f, 0x86, + 0xac, 0x57, 0x5b, 0xac, 0xaa, 0x5b, 0x84, 0x0b, 0xea, 0xea, 0xd7, 0x37, 0x56, 0xd7, 0x37, 0x6f, + 0xaf, 0x97, 0xc4, 0x63, 0x51, 0x56, 0xcf, 0x96, 0xce, 0x2c, 0xa9, 0x4a, 0x26, 0x5b, 0xce, 0x11, + 0x27, 0xf8, 0xfc, 0x6b, 0x32, 0x5b, 0x7f, 0xc0, 0x99, 0x5d, 0x3e, 0x16, 0x7f, 0xf3, 0xb8, 0xb8, + 0xc3, 0x58, 0xd1, 0x32, 0x2d, 0xba, 0xdc, 0x45, 0xb9, 0xdc, 0x87, 0xd2, 0xd8, 0xf2, 0x3b, 0xc6, + 0x39, 0xb4, 0x01, 0x57, 0xba, 0x3b, 0x86, 0xc7, 0xa9, 0x7b, 0xd0, 0x2d, 0x9a, 0x64, 0x97, 0x62, + 0x87, 0xba, 0x96, 0xc9, 0xb9, 0x9f, 0x98, 0x82, 0x61, 0x52, 0xab, 0x51, 0xce, 0x13, 0xdd, 0xa5, + 0x64, 0xbc, 0x40, 0x0f, 0x1a, 0x35, 0xae, 0x82, 0x7a, 0xfe, 0xec, 0x05, 0x54, 0x81, 0xa9, 0x8d, + 0xd7, 0x2c, 0x4c, 0xb0, 0xa0, 0xc4, 0x61, 0xa2, 0x84, 0xce, 0x40, 0x29, 0x3f, 0xd0, 0xc7, 0xb7, + 0x7b, 0x3f, 0xcc, 0xc0, 0x0c, 0x8c, 0xaf, 0x10, 0x6e, 0xd6, 0xe4, 0xfc, 0x9f, 0x19, 0x53, 0xe0, + 0xa5, 0xc4, 0x8d, 0x60, 0x66, 0x2c, 0x93, 0x1f, 0xff, 0xa0, 0x58, 0xd9, 0xda, 0x28, 0x5e, 0xa3, + 0x6d, 0x9c, 0x81, 0x2f, 0x95, 0xce, 0x0d, 0xe1, 0xf7, 0xca, 0x98, 0xaa, 0x65, 0xcb, 0xaf, 0x44, + 0x31, 0x8c, 0x05, 0x5c, 0x67, 0xc4, 0x13, 0x4d, 0xdd, 0xff, 0xc3, 0x5c, 0xf3, 0x1b, 0x74, 0x79, + 0xb1, 0x3f, 0x91, 0x60, 0x0f, 0xa9, 0xbd, 0xf2, 0x6d, 0xc8, 0x07, 0x17, 0x0e, 0x84, 0xae, 0xb8, + 0xc4, 0x16, 0x1c, 0xfb, 0x8b, 0xd0, 0x7b, 0xb0, 0x10, 0x5e, 0x43, 0xd0, 0x5c, 0xb8, 0x29, 0x57, + 0xd1, 0xee, 0x2a, 0x0c, 0x93, 0xba, 0x65, 0xda, 0x68, 0x39, 0xc1, 0x6a, 0xd7, 0x13, 0x64, 0x32, + 0x18, 0x3e, 0x99, 0xc9, 0x85, 0xdf, 0x89, 0x76, 0x29, 0x36, 0xed, 0x1d, 0xe6, 0x5a, 0x32, 0xde, + 0xd5, 0x45, 0x98, 0x8a, 0xbb, 0x62, 0x28, 0x7d, 0x35, 0xaa, 0xbe, 0xde, 0xf7, 0x72, 0x94, 0x26, + 0x75, 0x37, 0xe0, 0xf8, 0x8d, 0x83, 0xea, 0x13, 0x3f, 0x53, 0x83, 0x9e, 0xa5, 0x7b, 0xe3, 0x9d, + 0xc8, 0x55, 0x47, 0xe4, 0x79, 0x3e, 0xf7, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x52, 0x42, 0x5e, + 0xa6, 0x8f, 0x23, 0x00, 0x00, } diff --git a/examples/proto/examplepb/a_bit_of_everything.pb.gw.go b/examples/proto/examplepb/a_bit_of_everything.pb.gw.go index c506569c47d..2d9070eef8d 100644 --- a/examples/proto/examplepb/a_bit_of_everything.pb.gw.go +++ b/examples/proto/examplepb/a_bit_of_everything.pb.gw.go @@ -265,7 +265,11 @@ func request_ABitOfEverythingService_CreateBody_0(ctx context.Context, marshaler var protoReq ABitOfEverything var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -305,7 +309,11 @@ func request_ABitOfEverythingService_Update_0(ctx context.Context, marshaler run var protoReq ABitOfEverything var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -332,6 +340,139 @@ func request_ABitOfEverythingService_Update_0(ctx context.Context, marshaler run } +var ( + filter_ABitOfEverythingService_UpdateV2_0 = &utilities.DoubleArray{Encoding: map[string]int{"abe": 0, "uuid": 1}, Base: []int{1, 2, 1, 0, 0}, Check: []int{0, 1, 2, 3, 2}} +) + +func request_ABitOfEverythingService_UpdateV2_0(ctx context.Context, marshaler runtime.Marshaler, client ABitOfEverythingServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq UpdateV2Request + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.Abe); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["abe.uuid"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "abe.uuid") + } + + err = runtime.PopulateFieldFromPath(&protoReq, "abe.uuid", val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "abe.uuid", err) + } + + if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_ABitOfEverythingService_UpdateV2_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.UpdateV2(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +var ( + filter_ABitOfEverythingService_UpdateV2_1 = &utilities.DoubleArray{Encoding: map[string]int{"abe": 0, "uuid": 1}, Base: []int{1, 2, 1, 0, 0}, Check: []int{0, 1, 2, 3, 2}} +) + +func request_ABitOfEverythingService_UpdateV2_1(ctx context.Context, marshaler runtime.Marshaler, client ABitOfEverythingServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq UpdateV2Request + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.Abe); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if protoReq.UpdateMask != nil && len(protoReq.UpdateMask.GetPaths()) > 0 { + runtime.CamelCaseFieldMask(protoReq.UpdateMask) + } else { + if fieldMask, err := runtime.FieldMaskFromRequestBody(newReader()); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } else { + protoReq.UpdateMask = fieldMask + } + } + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["abe.uuid"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "abe.uuid") + } + + err = runtime.PopulateFieldFromPath(&protoReq, "abe.uuid", val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "abe.uuid", err) + } + + if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_ABitOfEverythingService_UpdateV2_1); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.UpdateV2(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func request_ABitOfEverythingService_PatchWithFieldMaskInBody_0(ctx context.Context, marshaler runtime.Marshaler, client ABitOfEverythingServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq UpdateV2Request + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if protoReq.UpdateMask != nil && len(protoReq.UpdateMask.GetPaths()) > 0 { + runtime.CamelCaseFieldMask(protoReq.UpdateMask) + } + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["abe.uuid"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "abe.uuid") + } + + err = runtime.PopulateFieldFromPath(&protoReq, "abe.uuid", val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "abe.uuid", err) + } + + msg, err := client.PatchWithFieldMaskInBody(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + func request_ABitOfEverythingService_Delete_0(ctx context.Context, marshaler runtime.Marshaler, client ABitOfEverythingServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq sub2.IdMessage var metadata runtime.ServerMetadata @@ -624,7 +765,11 @@ func request_ABitOfEverythingService_Echo_1(ctx context.Context, marshaler runti var protoReq sub.StringMessage var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.Value); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.Value); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -654,7 +799,11 @@ func request_ABitOfEverythingService_DeepPathEcho_0(ctx context.Context, marshal var protoReq ABitOfEverything var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -703,7 +852,11 @@ func request_ABitOfEverythingService_GetMessageWithBody_0(ctx context.Context, m var protoReq MessageWithBody var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.Data); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.Data); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -734,7 +887,11 @@ func request_ABitOfEverythingService_PostWithEmptyBody_0(ctx context.Context, ma var protoReq Body var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -888,6 +1045,66 @@ func RegisterABitOfEverythingServiceHandlerClient(ctx context.Context, mux *runt }) + mux.Handle("PUT", pattern_ABitOfEverythingService_UpdateV2_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_ABitOfEverythingService_UpdateV2_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_ABitOfEverythingService_UpdateV2_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("PATCH", pattern_ABitOfEverythingService_UpdateV2_1, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_ABitOfEverythingService_UpdateV2_1(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_ABitOfEverythingService_UpdateV2_1(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("PATCH", pattern_ABitOfEverythingService_PatchWithFieldMaskInBody_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_ABitOfEverythingService_PatchWithFieldMaskInBody_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_ABitOfEverythingService_PatchWithFieldMaskInBody_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("DELETE", pattern_ABitOfEverythingService_Delete_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -1120,6 +1337,12 @@ var ( pattern_ABitOfEverythingService_Update_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "example", "a_bit_of_everything", "uuid"}, "")) + pattern_ABitOfEverythingService_UpdateV2_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v2", "example", "a_bit_of_everything", "abe.uuid"}, "")) + + pattern_ABitOfEverythingService_UpdateV2_1 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v2", "example", "a_bit_of_everything", "abe.uuid"}, "")) + + pattern_ABitOfEverythingService_PatchWithFieldMaskInBody_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v2a", "example", "a_bit_of_everything", "abe.uuid"}, "")) + pattern_ABitOfEverythingService_Delete_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "example", "a_bit_of_everything", "uuid"}, "")) pattern_ABitOfEverythingService_GetQuery_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"v1", "example", "a_bit_of_everything", "query", "uuid"}, "")) @@ -1152,6 +1375,12 @@ var ( forward_ABitOfEverythingService_Update_0 = runtime.ForwardResponseMessage + forward_ABitOfEverythingService_UpdateV2_0 = runtime.ForwardResponseMessage + + forward_ABitOfEverythingService_UpdateV2_1 = runtime.ForwardResponseMessage + + forward_ABitOfEverythingService_PatchWithFieldMaskInBody_0 = runtime.ForwardResponseMessage + forward_ABitOfEverythingService_Delete_0 = runtime.ForwardResponseMessage forward_ABitOfEverythingService_GetQuery_0 = runtime.ForwardResponseMessage diff --git a/examples/proto/examplepb/a_bit_of_everything.proto b/examples/proto/examplepb/a_bit_of_everything.proto index d7a91bf4d8e..e07b09789d5 100644 --- a/examples/proto/examplepb/a_bit_of_everything.proto +++ b/examples/proto/examplepb/a_bit_of_everything.proto @@ -3,6 +3,7 @@ option go_package = "examplepb"; package grpc.gateway.examples.examplepb; import "google/api/annotations.proto"; +import "google/protobuf/field_mask.proto"; import "google/protobuf/empty.proto"; import "google/protobuf/duration.proto"; import "examples/proto/pathenum/path_enum.proto"; @@ -239,6 +240,12 @@ enum NumericEnum { ONE = 1; } +// UpdateV2Request request for update includes the message and the update mask +message UpdateV2Request { + ABitOfEverything abe = 1; + google.protobuf.FieldMask update_mask = 2; +} + // ABitOfEverything service is used to validate that APIs with complicated // proto messages and URL templates are still processed correctly. service ABitOfEverythingService { @@ -276,6 +283,22 @@ service ABitOfEverythingService { body: "*" }; } + rpc UpdateV2(UpdateV2Request) returns (google.protobuf.Empty) { + option (google.api.http) = { + put: "/v2/example/a_bit_of_everything/{abe.uuid}" + body: "abe" + additional_bindings { + patch: "/v2/example/a_bit_of_everything/{abe.uuid}" + body: "abe" + } + }; + } + rpc PatchWithFieldMaskInBody(UpdateV2Request) returns (google.protobuf.Empty) { + option (google.api.http) = { + patch: "/v2a/example/a_bit_of_everything/{abe.uuid}" + body: "*" + }; + } rpc Delete(sub2.IdMessage) returns (google.protobuf.Empty) { option (google.api.http) = { delete: "/v1/example/a_bit_of_everything/{uuid}" diff --git a/examples/proto/examplepb/a_bit_of_everything.swagger.json b/examples/proto/examplepb/a_bit_of_everything.swagger.json index 61c1023786e..b3249e62612 100644 --- a/examples/proto/examplepb/a_bit_of_everything.swagger.json +++ b/examples/proto/examplepb/a_bit_of_everything.swagger.json @@ -953,6 +953,100 @@ ] } }, + "/v2/example/a_bit_of_everything/{abe.uuid}": { + "put": { + "operationId": "UpdateV2", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/protobufEmpty" + } + }, + "403": { + "description": "Returned when the user does not have permission to access the resource.", + "schema": {} + }, + "404": { + "description": "Returned when the resource does not exist.", + "schema": { + "format": "string" + } + }, + "418": { + "description": "I'm a teapot.", + "schema": { + "$ref": "#/definitions/examplepbNumericEnum" + } + } + }, + "parameters": [ + { + "name": "abe.uuid", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/examplepbABitOfEverything" + } + } + ], + "tags": [ + "ABitOfEverythingService" + ] + }, + "patch": { + "operationId": "UpdateV22", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/protobufEmpty" + } + }, + "403": { + "description": "Returned when the user does not have permission to access the resource.", + "schema": {} + }, + "404": { + "description": "Returned when the resource does not exist.", + "schema": { + "format": "string" + } + }, + "418": { + "description": "I'm a teapot.", + "schema": { + "$ref": "#/definitions/examplepbNumericEnum" + } + } + }, + "parameters": [ + { + "name": "abe.uuid", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/examplepbABitOfEverything" + } + } + ], + "tags": [ + "ABitOfEverythingService" + ] + } + }, "/v2/example/echo": { "get": { "summary": "Summary: Echo rpc", @@ -1250,6 +1344,54 @@ "ABitOfEverythingService" ] } + }, + "/v2a/example/a_bit_of_everything/{abe.uuid}": { + "patch": { + "operationId": "PatchWithFieldMaskInBody", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/protobufEmpty" + } + }, + "403": { + "description": "Returned when the user does not have permission to access the resource.", + "schema": {} + }, + "404": { + "description": "Returned when the resource does not exist.", + "schema": { + "format": "string" + } + }, + "418": { + "description": "I'm a teapot.", + "schema": { + "$ref": "#/definitions/examplepbNumericEnum" + } + } + }, + "parameters": [ + { + "name": "abe.uuid", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/examplepbUpdateV2Request" + } + } + ], + "tags": [ + "ABitOfEverythingService" + ] + } } }, "definitions": { @@ -1561,6 +1703,18 @@ "default": "ZERO", "description": "NumericEnum is one or zero.\n\n - ZERO: ZERO means 0\n - ONE: ONE means 1" }, + "examplepbUpdateV2Request": { + "type": "object", + "properties": { + "abe": { + "$ref": "#/definitions/examplepbABitOfEverything" + }, + "update_mask": { + "$ref": "#/definitions/protobufFieldMask" + } + }, + "title": "UpdateV2Request request for update includes the message and the update mask" + }, "pathenumPathEnum": { "type": "string", "enum": [ @@ -1574,6 +1728,20 @@ "description": "service Foo {\n rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);\n }\n\nThe JSON representation for `Empty` is empty JSON object `{}`.", "title": "A generic empty message that you can re-use to avoid defining duplicated\nempty messages in your APIs. A typical example is to use it as the request\nor the response type of an API method. For instance:" }, + "protobufFieldMask": { + "type": "object", + "properties": { + "paths": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The set of field mask paths." + } + }, + "description": "paths: \"f.a\"\n paths: \"f.b.d\"\n\nHere `f` represents a field in some root message, `a` and `b`\nfields in the message found in `f`, and `d` a field found in the\nmessage in `f.b`.\n\nField masks are used to specify a subset of fields that should be\nreturned by a get operation or modified by an update operation.\nField masks also have a custom JSON encoding (see below).\n\n# Field Masks in Projections\n\nWhen used in the context of a projection, a response message or\nsub-message is filtered by the API to only contain those fields as\nspecified in the mask. For example, if the mask in the previous\nexample is applied to a response message as follows:\n\n f {\n a : 22\n b {\n d : 1\n x : 2\n }\n y : 13\n }\n z: 8\n\nThe result will not contain specific values for fields x,y and z\n(their value will be set to the default, and omitted in proto text\noutput):\n\n\n f {\n a : 22\n b {\n d : 1\n }\n }\n\nA repeated field is not allowed except at the last position of a\npaths string.\n\nIf a FieldMask object is not present in a get operation, the\noperation applies to all fields (as if a FieldMask of all fields\nhad been specified).\n\nNote that a field mask does not necessarily apply to the\ntop-level response message. In case of a REST get operation, the\nfield mask applies directly to the response, but in case of a REST\nlist operation, the mask instead applies to each individual message\nin the returned resource list. In case of a REST custom method,\nother definitions may be used. Where the mask applies will be\nclearly documented together with its declaration in the API. In\nany case, the effect on the returned resource/resources is required\nbehavior for APIs.\n\n# Field Masks in Update Operations\n\nA field mask in update operations specifies which fields of the\ntargeted resource are going to be updated. The API is required\nto only change the values of the fields as specified in the mask\nand leave the others untouched. If a resource is passed in to\ndescribe the updated values, the API ignores the values of all\nfields not covered by the mask.\n\nIf a repeated field is specified for an update operation, the existing\nrepeated values in the target resource will be overwritten by the new values.\nNote that a repeated field is only allowed in the last position of a `paths`\nstring.\n\nIf a sub-message is specified in the last position of the field mask for an\nupdate operation, then the existing sub-message in the target resource is\noverwritten. Given the target message:\n\n f {\n b {\n d : 1\n x : 2\n }\n c : 1\n }\n\nAnd an update message:\n\n f {\n b {\n d : 10\n }\n }\n\nthen if the field mask is:\n\n paths: \"f.b\"\n\nthen the result will be:\n\n f {\n b {\n d : 10\n }\n c : 1\n }\n\nHowever, if the update mask was:\n\n paths: \"f.b.d\"\n\nthen the result would be:\n\n f {\n b {\n d : 10\n x : 2\n }\n c : 1\n }\n\nIn order to reset a field's value to the default, the field must\nbe in the mask and set to the default value in the provided resource.\nHence, in order to reset all fields of a resource, provide a default\ninstance of the resource and set all fields in the mask, or do\nnot provide a mask as described below.\n\nIf a field mask is not present on update, the operation applies to\nall fields (as if a field mask of all fields has been specified).\nNote that in the presence of schema evolution, this may mean that\nfields the client does not know and has therefore not filled into\nthe request will be reset to their default. If this is unwanted\nbehavior, a specific service may require a client to always specify\na field mask, producing an error if not.\n\nAs with get operations, the location of the resource which\ndescribes the updated values in the request message depends on the\noperation kind. In any case, the effect of the field mask is\nrequired to be honored by the API.\n\n## Considerations for HTTP REST\n\nThe HTTP kind of an update operation which uses a field mask must\nbe set to PATCH instead of PUT in order to satisfy HTTP semantics\n(PUT must only be used for full updates).\n\n# JSON Encoding of Field Masks\n\nIn JSON, a field mask is encoded as a single string where paths are\nseparated by a comma. Fields name in each path are converted\nto/from lower-camel naming conventions.\n\nAs an example, consider the following message declarations:\n\n message Profile {\n User user = 1;\n Photo photo = 2;\n }\n message User {\n string display_name = 1;\n string address = 2;\n }\n\nIn proto a field mask for `Profile` may look as such:\n\n mask {\n paths: \"user.display_name\"\n paths: \"photo\"\n }\n\nIn JSON, the same mask is represented as below:\n\n {\n mask: \"user.displayName,photo\"\n }\n\n# Field Masks and Oneof Fields\n\nField masks treat fields in oneofs just as regular fields. Consider the\nfollowing message:\n\n message SampleMessage {\n oneof test_oneof {\n string name = 4;\n SubMessage sub_message = 9;\n }\n }\n\nThe field mask can be:\n\n mask {\n paths: \"name\"\n }\n\nOr:\n\n mask {\n paths: \"sub_message\"\n }\n\nNote that oneof type names (\"test_oneof\" in this case) cannot be used in\npaths.", + "title": "`FieldMask` represents a set of symbolic field paths, for example:" + }, "subStringMessage": { "type": "object", "properties": { diff --git a/examples/proto/examplepb/echo_service.pb.gw.go b/examples/proto/examplepb/echo_service.pb.gw.go index ca6579265e0..5e9efc9beac 100644 --- a/examples/proto/examplepb/echo_service.pb.gw.go +++ b/examples/proto/examplepb/echo_service.pb.gw.go @@ -272,7 +272,11 @@ func request_EchoService_EchoBody_0(ctx context.Context, marshaler runtime.Marsh var protoReq SimpleMessage var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } diff --git a/examples/proto/examplepb/flow_combination.pb.gw.go b/examples/proto/examplepb/flow_combination.pb.gw.go index a20cf605711..b4ae06a19d7 100644 --- a/examples/proto/examplepb/flow_combination.pb.gw.go +++ b/examples/proto/examplepb/flow_combination.pb.gw.go @@ -61,7 +61,11 @@ func request_FlowCombination_StreamEmptyRpc_0(ctx context.Context, marshaler run grpclog.Infof("Failed to start streaming: %v", err) return nil, metadata, err } - dec := marshaler.NewDecoder(req.Body) + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + dec := marshaler.NewDecoder(newReader()) for { var protoReq EmptyProto err = dec.Decode(&protoReq) @@ -102,7 +106,11 @@ func request_FlowCombination_StreamEmptyStream_0(ctx context.Context, marshaler grpclog.Infof("Failed to start streaming: %v", err) return nil, metadata, err } - dec := marshaler.NewDecoder(req.Body) + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, berr + } + dec := marshaler.NewDecoder(newReader()) handleSend := func() error { var protoReq EmptyProto err := dec.Decode(&protoReq) @@ -151,7 +159,11 @@ func request_FlowCombination_RpcBodyRpc_0(ctx context.Context, marshaler runtime var protoReq NonEmptyProto var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -230,7 +242,11 @@ func request_FlowCombination_RpcBodyRpc_3(ctx context.Context, marshaler runtime var protoReq NonEmptyProto var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.C); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.C); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -276,7 +292,11 @@ func request_FlowCombination_RpcBodyRpc_4(ctx context.Context, marshaler runtime var protoReq NonEmptyProto var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.C); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.C); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -297,7 +317,11 @@ func request_FlowCombination_RpcBodyRpc_5(ctx context.Context, marshaler runtime var protoReq NonEmptyProto var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.C); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.C); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -406,7 +430,11 @@ func request_FlowCombination_RpcPathNestedRpc_0(ctx context.Context, marshaler r var protoReq NestedProto var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.C); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.C); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -491,7 +519,11 @@ func request_FlowCombination_RpcPathNestedRpc_2(ctx context.Context, marshaler r var protoReq NestedProto var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.C); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.C); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -526,7 +558,11 @@ func request_FlowCombination_RpcBodyStream_0(ctx context.Context, marshaler runt var protoReq NonEmptyProto var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -629,7 +665,11 @@ func request_FlowCombination_RpcBodyStream_3(ctx context.Context, marshaler runt var protoReq NonEmptyProto var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.C); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.C); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -683,7 +723,11 @@ func request_FlowCombination_RpcBodyStream_4(ctx context.Context, marshaler runt var protoReq NonEmptyProto var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.C); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.C); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -712,7 +756,11 @@ func request_FlowCombination_RpcBodyStream_5(ctx context.Context, marshaler runt var protoReq NonEmptyProto var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.C); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.C); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -845,7 +893,11 @@ func request_FlowCombination_RpcPathNestedStream_0(ctx context.Context, marshale var protoReq NestedProto var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.C); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.C); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -946,7 +998,11 @@ func request_FlowCombination_RpcPathNestedStream_2(ctx context.Context, marshale var protoReq NestedProto var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.C); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.C); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } diff --git a/examples/proto/examplepb/stream.pb.gw.go b/examples/proto/examplepb/stream.pb.gw.go index a62da50e2a0..f43c517b17e 100644 --- a/examples/proto/examplepb/stream.pb.gw.go +++ b/examples/proto/examplepb/stream.pb.gw.go @@ -37,7 +37,11 @@ func request_StreamService_BulkCreate_0(ctx context.Context, marshaler runtime.M grpclog.Infof("Failed to start streaming: %v", err) return nil, metadata, err } - dec := marshaler.NewDecoder(req.Body) + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + dec := marshaler.NewDecoder(newReader()) for { var protoReq ABitOfEverything err = dec.Decode(&protoReq) @@ -95,7 +99,11 @@ func request_StreamService_BulkEcho_0(ctx context.Context, marshaler runtime.Mar grpclog.Infof("Failed to start streaming: %v", err) return nil, metadata, err } - dec := marshaler.NewDecoder(req.Body) + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, berr + } + dec := marshaler.NewDecoder(newReader()) handleSend := func() error { var protoReq sub.StringMessage err := dec.Decode(&protoReq) diff --git a/examples/proto/examplepb/unannotated_echo_service.pb.gw.go b/examples/proto/examplepb/unannotated_echo_service.pb.gw.go index 90bcbbd39f0..01764c0f9e6 100644 --- a/examples/proto/examplepb/unannotated_echo_service.pb.gw.go +++ b/examples/proto/examplepb/unannotated_echo_service.pb.gw.go @@ -113,7 +113,11 @@ func request_UnannotatedEchoService_EchoBody_0(ctx context.Context, marshaler ru var protoReq UnannotatedSimpleMessage var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } diff --git a/examples/proto/examplepb/wrappers.pb.gw.go b/examples/proto/examplepb/wrappers.pb.gw.go index f603e0283a2..7e95a4c6163 100644 --- a/examples/proto/examplepb/wrappers.pb.gw.go +++ b/examples/proto/examplepb/wrappers.pb.gw.go @@ -32,7 +32,11 @@ func request_WrappersService_Create_0(ctx context.Context, marshaler runtime.Mar var protoReq Wrappers var metadata runtime.ServerMetadata - if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } diff --git a/examples/server/a_bit_of_everything.go b/examples/server/a_bit_of_everything.go index 4f433654749..384638cab31 100644 --- a/examples/server/a_bit_of_everything.go +++ b/examples/server/a_bit_of_everything.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "io" + "strings" "sync" "github.com/golang/glog" @@ -11,8 +12,8 @@ import ( "github.com/golang/protobuf/ptypes/duration" "github.com/golang/protobuf/ptypes/empty" examples "github.com/grpc-ecosystem/grpc-gateway/examples/proto/examplepb" - sub "github.com/grpc-ecosystem/grpc-gateway/examples/proto/sub" - sub2 "github.com/grpc-ecosystem/grpc-gateway/examples/proto/sub2" + "github.com/grpc-ecosystem/grpc-gateway/examples/proto/sub" + "github.com/grpc-ecosystem/grpc-gateway/examples/proto/sub2" "github.com/rogpeppe/fastuuid" "google.golang.org/genproto/googleapis/rpc/errdetails" "google.golang.org/grpc" @@ -161,6 +162,39 @@ func (s *_ABitOfEverythingServer) Update(ctx context.Context, msg *examples.ABit return new(empty.Empty), nil } +func (s *_ABitOfEverythingServer) UpdateV2(ctx context.Context, msg *examples.UpdateV2Request) (*empty.Empty, error) { + glog.Info(msg) + // If there is no update mask do a regular update + if msg.UpdateMask == nil || len(msg.UpdateMask.GetPaths()) == 0 { + return s.Update(ctx, msg.Abe) + } + + s.m.Lock() + defer s.m.Unlock() + if a, ok := s.v[msg.Abe.Uuid]; ok { + applyFieldMask(a, msg.Abe, msg.UpdateMask) + } else { + return nil, status.Errorf(codes.NotFound, "not found") + } + return new(empty.Empty), nil +} + +// PatchWithFieldMaskInBody differs from UpdateV2 only in that this method exposes the field mask in the request body, +// so that clients can specify their mask explicitly +func (s *_ABitOfEverythingServer) PatchWithFieldMaskInBody(ctx context.Context, request *examples.UpdateV2Request) (*empty.Empty, error) { + // low-effort attempt to modify the field mask to only include paths for the ABE struct. Since this is only for the + // integration tests, this narrow implementaion is fine. + if request.UpdateMask != nil { + var shifted []string + for _, path := range request.UpdateMask.GetPaths() { + shifted = append(shifted, strings.TrimPrefix(path, "Abe.")) + } + request.UpdateMask.Paths = shifted + } + + return s.UpdateV2(ctx, request) +} + func (s *_ABitOfEverythingServer) Delete(ctx context.Context, msg *sub2.IdMessage) (*empty.Empty, error) { s.m.Lock() defer s.m.Unlock() diff --git a/examples/server/fieldmask_helper.go b/examples/server/fieldmask_helper.go new file mode 100644 index 00000000000..d0cac43c58f --- /dev/null +++ b/examples/server/fieldmask_helper.go @@ -0,0 +1,55 @@ +package server + +import ( + "log" + "reflect" + "strings" + + "google.golang.org/genproto/protobuf/field_mask" +) + +func applyFieldMask(patchee, patcher interface{}, mask *field_mask.FieldMask) { + if mask == nil { + return + } + + for _, path := range mask.GetPaths() { + val := getField(patcher, path) + if val.IsValid() { + setValue(patchee, val, path) + } + } +} + +func getField(obj interface{}, path string) (val reflect.Value) { + // this func is lazy -- if anything bad happens just return nil + defer func() { + if r := recover(); r != nil { + log.Printf("failed to get field:\npath: %q\nobj: %#v\nerr: %v", path, obj, r) + val = reflect.Value{} + } + }() + + v := reflect.ValueOf(obj) + if len(path) == 0 { + return v + } + + for _, s := range strings.Split(path, ".") { + if v.Kind() == reflect.Ptr { + v = reflect.Indirect(v) + } + v = v.FieldByName(s) + } + + return v +} + +func setValue(obj interface{}, newValue reflect.Value, path string) { + defer func() { + if r := recover(); r != nil { + log.Printf("failed to set value:\nnewValue: %#v\npath: %q\nobj: %#v\nerr: %v", newValue, path, obj, r) + } + }() + getField(obj, path).Set(newValue) +} diff --git a/examples/server/fieldmask_helper_test.go b/examples/server/fieldmask_helper_test.go new file mode 100644 index 00000000000..c735fdd7aca --- /dev/null +++ b/examples/server/fieldmask_helper_test.go @@ -0,0 +1,92 @@ +package server + +import ( + "reflect" + "testing" + + "google.golang.org/genproto/protobuf/field_mask" +) + +func TestApplyFieldMask(t *testing.T) { + for _, test := range []struct { + name string + patchee interface{} + patcher interface{} + fieldMask *field_mask.FieldMask + expected interface{} + }{ + {"nil fieldMask", &a{E: 64}, &a{E: 42}, nil, &a{E: 64}}, + {"empty paths", &a{E: 63}, &a{E: 42}, &field_mask.FieldMask{}, &a{E: 63}}, + {"simple path", &a{E: 23, F: "test"}, &a{B: &b{}, E: 42}, &field_mask.FieldMask{Paths: []string{"E"}}, &a{E: 42, F: "test"}}, + {"nested", &a{B: &b{C: 85}}, &a{B: &b{C: 58, D: nil}}, &field_mask.FieldMask{Paths: []string{"B.C"}}, &a{B: &b{C: 58}}}, + {"multiple paths", &a{B: &b{C: 40, D: []int{1, 2, 3}}, E: 34, F: "catapult"}, &a{B: &b{C: 56}, F: "lettuce"}, &field_mask.FieldMask{Paths: []string{"B.C", "F"}}, &a{B: &b{C: 56, D: []int{1, 2, 3}}, E: 34, F: "lettuce"}}, + } { + t.Run(test.name, func(t *testing.T) { + applyFieldMask(test.patchee, test.patcher, test.fieldMask) + if !reflect.DeepEqual(test.patchee, test.expected) { + t.Errorf("expected %v, but was %v", test.expected, test.patchee) + } + }) + } +} + +func TestGetValue(t *testing.T) { + for _, test := range []struct { + name string + input interface{} + path string + expected interface{} + }{ + {"empty", &a{E: 45, F: "test"}, "", &a{E: 45, F: "test"}}, + {"pointer-simple", &a{E: 45}, "E", 45}, + {"pointer-nested", &a{B: &b{C: 42}}, "B.C", 42}, + {"pointer-complex type", &a{B: &b{D: []int{1, 2}}}, "B.D", []int{1, 2}}, + {"pointer-invalid path", &a{F: "test"}, "X.Y", nil}, + {"simple", a{E: 45}, "E", 45}, + {"nested", a{B: &b{C: 42}}, "B.C", 42}, + {"complex type", a{B: &b{D: []int{1, 2}}}, "B.D", []int{1, 2}}, + {"invalid path", a{F: "test"}, "X.Y", nil}, + } { + t.Run(test.name, func(t *testing.T) { + if actual := getField(test.input, test.path); actual.IsValid() { + if !reflect.DeepEqual(test.expected, actual.Interface()) { + t.Errorf("expected %v, but got %v", test.expected, actual) + } + } else if test.expected != nil { + t.Errorf("expected nil, but was %v", actual) + } + }) + } +} + +func TestSetValue(t *testing.T) { + for _, test := range []struct { + name string + obj interface{} + newValue interface{} + path string + expected interface{} + }{ + {"simple", &a{E: 45}, 34, "E", 34}, + {"nested", &a{B: &b{C: 54}}, 43, "B.C", 43}, + {"complex type", &a{B: &b{D: []int{1, 2}}}, []int{3, 4}, "B.D", []int{3, 4}}, + } { + t.Run(test.name, func(t *testing.T) { + setValue(test.obj, reflect.ValueOf(test.newValue), test.path) + if actual := getField(test.obj, test.path).Interface(); !reflect.DeepEqual(actual, test.expected) { + t.Errorf("expected %v, but got %v", test.newValue, actual) + } + }) + } +} + +type a struct { + B *b + E int + F string +} + +type b struct { + C int + D []int +} diff --git a/protoc-gen-grpc-gateway/gengateway/template.go b/protoc-gen-grpc-gateway/gengateway/template.go index 7db03cca64e..fad1392c0c0 100644 --- a/protoc-gen-grpc-gateway/gengateway/template.go +++ b/protoc-gen-grpc-gateway/gengateway/template.go @@ -7,6 +7,7 @@ import ( "text/template" "github.com/golang/glog" + generator2 "github.com/golang/protobuf/protoc-gen-go/generator" "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor" "github.com/grpc-ecosystem/grpc-gateway/utilities" ) @@ -23,6 +24,14 @@ type binding struct { Registry *descriptor.Registry } +// GetBodyFieldPath returns the binding body's fieldpath. +func (b binding) GetBodyFieldPath() string { + if b.Body != nil && len(b.Body.FieldPath) != 0 { + return b.Body.FieldPath.String() + } + return "*" +} + // HasQueryParam determines if the binding needs parameters in query string. // // It sometimes returns true even though actually the binding does not need. @@ -88,6 +97,26 @@ func (b binding) LookupEnum(p descriptor.Parameter) *descriptor.Enum { return e } +// FieldMaskField returns the golang-style name of the variable for a FieldMask, if there is exactly one of that type in +// the message. Otherwise, it returns an empty string. +func (b binding) FieldMaskField() string { + var fieldMaskField *descriptor.Field + for _, f := range b.Method.RequestType.Fields { + if f.GetTypeName() == ".google.protobuf.FieldMask" { + // if there is more than 1 FieldMask for this request, then return none + if fieldMaskField != nil { + return "" + } + fieldMaskField = f + } + } + + if fieldMaskField != nil { + return generator2.CamelCase(fieldMaskField.GetName()) + } + return "" +} + // queryParamFilter is a wrapper of utilities.DoubleArray which provides String() to output DoubleArray.Encoding in a stable and predictable format. type queryParamFilter struct { *utilities.DoubleArray @@ -197,7 +226,11 @@ func request_{{.Method.Service.GetName}}_{{.Method.GetName}}_{{.Index}}(ctx cont grpclog.Infof("Failed to start streaming: %v", err) return nil, metadata, err } - dec := marshaler.NewDecoder(req.Body) + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + dec := marshaler.NewDecoder(newReader()) for { var protoReq {{.Method.RequestType.GoType .Method.Service.File.GoPkg.Path}} err = dec.Decode(&protoReq) @@ -244,9 +277,24 @@ var ( var protoReq {{.Method.RequestType.GoType .Method.Service.File.GoPkg.Path}} var metadata runtime.ServerMetadata {{if .Body}} - if err := marshaler.NewDecoder(req.Body).Decode(&{{.Body.AssignableExpr "protoReq"}}); err != nil && err != io.EOF { + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&{{.Body.AssignableExpr "protoReq"}}); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + {{- if and (eq (.HTTPMethod) "PATCH") (.FieldMaskField)}} + if protoReq.{{.FieldMaskField}} != nil && len(protoReq.{{.FieldMaskField}}.GetPaths()) > 0 { + runtime.CamelCaseFieldMask(protoReq.{{.FieldMaskField}}) + } {{if not (eq "*" .GetBodyFieldPath)}} else { + if fieldMask, err := runtime.FieldMaskFromRequestBody(newReader()); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } else { + protoReq.{{.FieldMaskField}} = fieldMask + } + } {{end}} + {{end}} {{end}} {{if .PathParams}} var ( @@ -319,7 +367,11 @@ var ( grpclog.Infof("Failed to start streaming: %v", err) return nil, metadata, err } - dec := marshaler.NewDecoder(req.Body) + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, berr + } + dec := marshaler.NewDecoder(newReader()) handleSend := func() error { var protoReq {{.Method.RequestType.GoType .Method.Service.File.GoPkg.Path}} err := dec.Decode(&protoReq) diff --git a/protoc-gen-grpc-gateway/gengateway/template_test.go b/protoc-gen-grpc-gateway/gengateway/template_test.go index 3f1313a7ddc..ca9e587a69d 100644 --- a/protoc-gen-grpc-gateway/gengateway/template_test.go +++ b/protoc-gen-grpc-gateway/gengateway/template_test.go @@ -230,7 +230,7 @@ func TestApplyTemplateRequestWithoutClientStreaming(t *testing.T) { if want := spec.sigWant; !strings.Contains(got, want) { t.Errorf("applyTemplate(%#v) = %s; want to contain %s", file, got, want) } - if want := `marshaler.NewDecoder(req.Body).Decode(&protoReq.GetNested().Bool)`; !strings.Contains(got, want) { + if want := `marshaler.NewDecoder(newReader()).Decode(&protoReq.GetNested().Bool)`; !strings.Contains(got, want) { t.Errorf("applyTemplate(%#v) = %s; want to contain %s", file, got, want) } if want := `val, ok = pathParams["nested.int32"]`; !strings.Contains(got, want) { @@ -391,7 +391,7 @@ func TestApplyTemplateRequestWithClientStreaming(t *testing.T) { if want := spec.sigWant; !strings.Contains(got, want) { t.Errorf("applyTemplate(%#v) = %s; want to contain %s", file, got, want) } - if want := `marshaler.NewDecoder(req.Body)`; !strings.Contains(got, want) { + if want := `marshaler.NewDecoder(newReader()`; !strings.Contains(got, want) { t.Errorf("applyTemplate(%#v) = %s; want to contain %s", file, got, want) } if want := `func RegisterExampleServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {`; !strings.Contains(got, want) { diff --git a/runtime/fieldmask.go b/runtime/fieldmask.go new file mode 100644 index 00000000000..e1cf7a91461 --- /dev/null +++ b/runtime/fieldmask.go @@ -0,0 +1,70 @@ +package runtime + +import ( + "encoding/json" + "io" + "strings" + + "github.com/golang/protobuf/protoc-gen-go/generator" + "google.golang.org/genproto/protobuf/field_mask" +) + +// FieldMaskFromRequestBody creates a FieldMask printing all complete paths from the JSON body. +func FieldMaskFromRequestBody(r io.Reader) (*field_mask.FieldMask, error) { + fm := &field_mask.FieldMask{} + var root interface{} + if err := json.NewDecoder(r).Decode(&root); err != nil { + if err == io.EOF { + return fm, nil + } + return nil, err + } + + queue := []fieldMaskPathItem{{node: root}} + for len(queue) > 0 { + // dequeue an item + item := queue[0] + queue = queue[1:] + + if m, ok := item.node.(map[string]interface{}); ok { + // if the item is an object, then enqueue all of its children + for k, v := range m { + queue = append(queue, fieldMaskPathItem{path: append(item.path, generator.CamelCase(k)), node: v}) + } + } else if len(item.path) > 0 { + // otherwise, it's a leaf node so print its path + fm.Paths = append(fm.Paths, strings.Join(item.path, ".")) + } + } + + return fm, nil +} + +// fieldMaskPathItem stores a in-progress deconstruction of a path for a fieldmask +type fieldMaskPathItem struct { + // the list of prior fields leading up to node + path []string + + // a generic decoded json object the current item to inspect for further path extraction + node interface{} +} + +// CamelCaseFieldMask updates the given FieldMask by converting all of its paths to CamelCase, using the same heuristic +// that's used for naming protobuf fields in Go. +func CamelCaseFieldMask(mask *field_mask.FieldMask) { + if mask == nil || mask.Paths == nil { + return + } + + var newPaths []string + for _, path := range mask.Paths { + lowerCasedParts := strings.Split(path, ".") + var camelCasedParts []string + for _, part := range lowerCasedParts { + camelCasedParts = append(camelCasedParts, generator.CamelCase(part)) + } + newPaths = append(newPaths, strings.Join(camelCasedParts, ".")) + } + + mask.Paths = newPaths +} diff --git a/runtime/fieldmask_test.go b/runtime/fieldmask_test.go new file mode 100644 index 00000000000..3c097878aa0 --- /dev/null +++ b/runtime/fieldmask_test.go @@ -0,0 +1,87 @@ +package runtime + +import ( + "bytes" + "fmt" + "testing" + + "google.golang.org/genproto/protobuf/field_mask" +) + +func fieldMasksEqual(fm1, fm2 *field_mask.FieldMask) bool { + if fm1 == nil && fm2 == nil { + return true + } + if fm1 == nil || fm2 == nil { + return false + } + if len(fm1.GetPaths()) != len(fm2.GetPaths()) { + return false + } + + paths := make(map[string]bool) + for _, path := range fm1.GetPaths() { + paths[path] = true + } + for _, path := range fm2.GetPaths() { + if _, ok := paths[path]; !ok { + return false + } + } + + return true +} + +func newFieldMask(paths ...string) *field_mask.FieldMask { + return &field_mask.FieldMask{Paths: paths} +} + +func fieldMaskString(fm *field_mask.FieldMask) string { + if fm == nil { + return "" + } + return fmt.Sprintf("%v", fm.GetPaths()) +} + +func TestFieldMaskFromRequestBody(t *testing.T) { + for _, tc := range []struct { + name string + input string + expected *field_mask.FieldMask + expectedErr error + }{ + {name: "empty", expected: newFieldMask()}, + {name: "simple", input: `{"foo":1, "bar":"baz"}`, expected: newFieldMask("Foo", "Bar")}, + {name: "nested", input: `{"foo": {"bar":1, "baz": 2}, "qux": 3}`, expected: newFieldMask("Foo.Bar", "Foo.Baz", "Qux")}, + {name: "canonical", input: `{"f": {"b": {"d": 1, "x": 2}, "c": 1}}`, expected: newFieldMask("F.B.D", "F.B.X", "F.C")}, + } { + t.Run(tc.name, func(t *testing.T) { + actual, err := FieldMaskFromRequestBody(bytes.NewReader([]byte(tc.input))) + if !fieldMasksEqual(actual, tc.expected) { + t.Errorf("want %v; got %v", fieldMaskString(tc.expected), fieldMaskString(actual)) + } + if err != tc.expectedErr { + t.Errorf("want %v; got %v", tc.expectedErr, err) + } + }) + } +} + +func TestCamelCaseFieldMask(t *testing.T) { + for _, tc := range []struct { + name string + input *field_mask.FieldMask + expected *field_mask.FieldMask + }{ + {"nil", nil, nil}, + {"empty", &field_mask.FieldMask{Paths: nil}, &field_mask.FieldMask{Paths: nil}}, + {"main usage", newFieldMask("a", "a.b", "some_field.some_sub_field"), newFieldMask("A", "A.B", "SomeField.SomeSubField")}, + } { + t.Run(tc.name, func(t *testing.T) { + CamelCaseFieldMask(tc.input) + if expected, actual := tc.expected, tc.input; !fieldMasksEqual(expected, actual) { + t.Errorf("want %v; got %v", fieldMaskString(expected), fieldMaskString(actual)) + } + }) + } +} diff --git a/utilities/readerfactory.go b/utilities/readerfactory.go new file mode 100644 index 00000000000..6dd3854665f --- /dev/null +++ b/utilities/readerfactory.go @@ -0,0 +1,20 @@ +package utilities + +import ( + "bytes" + "io" + "io/ioutil" +) + +// IOReaderFactory takes in an io.Reader and returns a function that will allow you to create a new reader that begins +// at the start of the stream +func IOReaderFactory(r io.Reader) (func() io.Reader, error) { + b, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + + return func() io.Reader { + return bytes.NewReader(b) + }, nil +} From 50001357839936d3eee6a7b8d7b4043f0323d641 Mon Sep 17 00:00:00 2001 From: Roman Azami Date: Wed, 14 Nov 2018 22:03:50 -0800 Subject: [PATCH 6/7] Updated bazel builds to support field_mask dependencies --- codegenerator/BUILD.bazel | 4 ++-- examples/clients/abe/BUILD.bazel | 4 +++- examples/clients/echo/BUILD.bazel | 2 +- examples/clients/responsebody/BUILD.bazel | 2 +- examples/clients/unannotatedecho/BUILD.bazel | 2 +- .../cmd/example-gateway-server/BUILD.bazel | 2 +- examples/cmd/example-grpc-server/BUILD.bazel | 2 +- examples/gateway/BUILD.bazel | 4 ++-- examples/integration/BUILD.bazel | 7 +++--- examples/proto/examplepb/BUILD.bazel | 11 +++++---- examples/server/BUILD.bazel | 23 +++++++++++++------ protoc-gen-grpc-gateway/BUILD.bazel | 4 ++-- .../descriptor/BUILD.bazel | 8 +++---- .../gengateway/BUILD.bazel | 7 +++--- protoc-gen-grpc-gateway/httprule/BUILD.bazel | 4 ++-- protoc-gen-swagger/BUILD.bazel | 4 ++-- protoc-gen-swagger/genswagger/BUILD.bazel | 6 ++--- runtime/BUILD.bazel | 22 ++++++++++-------- utilities/BUILD.bazel | 1 + 19 files changed, 69 insertions(+), 50 deletions(-) diff --git a/codegenerator/BUILD.bazel b/codegenerator/BUILD.bazel index 651177fa157..d14983dcf4a 100644 --- a/codegenerator/BUILD.bazel +++ b/codegenerator/BUILD.bazel @@ -10,7 +10,7 @@ go_library( ], importpath = "github.com/grpc-ecosystem/grpc-gateway/codegenerator", deps = [ - "@com_github_golang_protobuf//proto:go_default_library", + "//vendor/github.com/golang/protobuf/proto:go_default_library", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", ], ) @@ -20,7 +20,7 @@ go_test( srcs = ["parse_req_test.go"], embed = [":go_default_library"], deps = [ - "@com_github_golang_protobuf//proto:go_default_library", + "//vendor/github.com/golang/protobuf/proto:go_default_library", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", ], ) diff --git a/examples/clients/abe/BUILD.bazel b/examples/clients/abe/BUILD.bazel index 6b61fa1b3fa..c9f40633f64 100644 --- a/examples/clients/abe/BUILD.bazel +++ b/examples/clients/abe/BUILD.bazel @@ -18,10 +18,12 @@ go_library( "examplepb_a_bit_of_everything_repeated.go", "examplepb_body.go", "examplepb_numeric_enum.go", + "examplepb_update_v2_request.go", "message_path_enum_nested_path_enum.go", "nested_deep_enum.go", "pathenum_path_enum.go", "protobuf_empty.go", + "protobuf_field_mask.go", "sub_string_message.go", ], importpath = "github.com/grpc-ecosystem/grpc-gateway/examples/clients/abe", @@ -29,6 +31,6 @@ go_library( "//examples/proto/examplepb:go_default_library", "//examples/proto/pathenum:go_default_library", "//runtime:go_default_library", - "@com_github_go_resty_resty//:go_default_library", + "//vendor/github.com/go-resty/resty:go_default_library", ], ) diff --git a/examples/clients/echo/BUILD.bazel b/examples/clients/echo/BUILD.bazel index 090b56aafab..3d220ab7292 100644 --- a/examples/clients/echo/BUILD.bazel +++ b/examples/clients/echo/BUILD.bazel @@ -13,5 +13,5 @@ go_library( "examplepb_simple_message.go", ], importpath = "github.com/grpc-ecosystem/grpc-gateway/examples/clients/echo", - deps = ["@com_github_go_resty_resty//:go_default_library"], + deps = ["//vendor/github.com/go-resty/resty:go_default_library"], ) diff --git a/examples/clients/responsebody/BUILD.bazel b/examples/clients/responsebody/BUILD.bazel index bdbc237a815..e9f45b174a8 100644 --- a/examples/clients/responsebody/BUILD.bazel +++ b/examples/clients/responsebody/BUILD.bazel @@ -15,5 +15,5 @@ go_library( ], importpath = "github.com/grpc-ecosystem/grpc-gateway/examples/clients/responsebody", visibility = ["//visibility:public"], - deps = ["@com_github_go_resty_resty//:go_default_library"], + deps = ["//vendor/github.com/go-resty/resty:go_default_library"], ) diff --git a/examples/clients/unannotatedecho/BUILD.bazel b/examples/clients/unannotatedecho/BUILD.bazel index 611c6c7052d..f0749ef59b1 100644 --- a/examples/clients/unannotatedecho/BUILD.bazel +++ b/examples/clients/unannotatedecho/BUILD.bazel @@ -12,5 +12,5 @@ go_library( "unannotated_echo_service_api.go", ], importpath = "github.com/grpc-ecosystem/grpc-gateway/examples/clients/unannotatedecho", - deps = ["@com_github_go_resty_resty//:go_default_library"], + deps = ["//vendor/github.com/go-resty/resty:go_default_library"], ) diff --git a/examples/cmd/example-gateway-server/BUILD.bazel b/examples/cmd/example-gateway-server/BUILD.bazel index 0f7c5052e7e..9f649f711f1 100644 --- a/examples/cmd/example-gateway-server/BUILD.bazel +++ b/examples/cmd/example-gateway-server/BUILD.bazel @@ -7,7 +7,7 @@ go_library( visibility = ["//visibility:private"], deps = [ "//examples/gateway:go_default_library", - "@com_github_golang_glog//:go_default_library", + "//vendor/github.com/golang/glog:go_default_library", ], ) diff --git a/examples/cmd/example-grpc-server/BUILD.bazel b/examples/cmd/example-grpc-server/BUILD.bazel index 1c66416c6ba..5a0a9fa11a3 100644 --- a/examples/cmd/example-grpc-server/BUILD.bazel +++ b/examples/cmd/example-grpc-server/BUILD.bazel @@ -8,7 +8,7 @@ go_library( importpath = "github.com/grpc-ecosystem/grpc-gateway/examples/cmd/example-grpc-server", deps = [ "//examples/server:go_default_library", - "@com_github_golang_glog//:go_default_library", + "//vendor/github.com/golang/glog:go_default_library", ], ) diff --git a/examples/gateway/BUILD.bazel b/examples/gateway/BUILD.bazel index 393a7c41f9c..4b091e3d8f4 100644 --- a/examples/gateway/BUILD.bazel +++ b/examples/gateway/BUILD.bazel @@ -13,8 +13,8 @@ go_library( deps = [ "//examples/proto/examplepb:go_default_library", "//runtime:go_default_library", - "@com_github_golang_glog//:go_default_library", + "//vendor/github.com/golang/glog:go_default_library", + "//vendor/google.golang.org/grpc/connectivity:go_default_library", "@org_golang_google_grpc//:go_default_library", - "@org_golang_google_grpc//connectivity:go_default_library", ], ) diff --git a/examples/integration/BUILD.bazel b/examples/integration/BUILD.bazel index 287de4b324a..7897846fb68 100644 --- a/examples/integration/BUILD.bazel +++ b/examples/integration/BUILD.bazel @@ -18,11 +18,12 @@ go_test( "//examples/proto/sub:go_default_library", "//examples/server:go_default_library", "//runtime:go_default_library", - "@com_github_golang_glog//:go_default_library", + "//vendor/github.com/golang/glog:go_default_library", + "//vendor/github.com/golang/protobuf/proto:go_default_library", + "//vendor/google.golang.org/grpc/codes:go_default_library", "@com_github_golang_protobuf//jsonpb:go_default_library_gen", - "@com_github_golang_protobuf//proto:go_default_library", "@go_googleapis//google/rpc:status_go_proto", "@io_bazel_rules_go//proto/wkt:empty_go_proto", - "@org_golang_google_grpc//codes:go_default_library", + "@io_bazel_rules_go//proto/wkt:field_mask_go_proto", ], ) diff --git a/examples/proto/examplepb/BUILD.bazel b/examples/proto/examplepb/BUILD.bazel index 20009954efc..b275a86aa99 100644 --- a/examples/proto/examplepb/BUILD.bazel +++ b/examples/proto/examplepb/BUILD.bazel @@ -29,6 +29,7 @@ proto_library( "//protoc-gen-swagger/options:options_proto", "@com_google_protobuf//:duration_proto", "@com_google_protobuf//:empty_proto", + "@com_google_protobuf//:field_mask_proto", "@com_google_protobuf//:timestamp_proto", "@com_google_protobuf//:wrappers_proto", "@go_googleapis//google/api:annotations_proto", @@ -60,12 +61,12 @@ go_library( deps = [ "//runtime:go_default_library", "//utilities:go_default_library", - "@com_github_golang_protobuf//proto:go_default_library", + "//vendor/github.com/golang/protobuf/proto:go_default_library", + "//vendor/golang.org/x/net/context:go_default_library", + "//vendor/google.golang.org/grpc/codes:go_default_library", + "//vendor/google.golang.org/grpc/grpclog:go_default_library", + "//vendor/google.golang.org/grpc/status:go_default_library", "@org_golang_google_grpc//:go_default_library", - "@org_golang_google_grpc//codes:go_default_library", - "@org_golang_google_grpc//grpclog:go_default_library", - "@org_golang_google_grpc//status:go_default_library", - "@org_golang_x_net//context:go_default_library", ], ) diff --git a/examples/server/BUILD.bazel b/examples/server/BUILD.bazel index 29d44cfb4d1..3ca0092b51a 100644 --- a/examples/server/BUILD.bazel +++ b/examples/server/BUILD.bazel @@ -1,4 +1,4 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") package(default_visibility = ["//visibility:public"]) @@ -7,6 +7,7 @@ go_library( srcs = [ "a_bit_of_everything.go", "echo.go", + "fieldmask_helper.go", "flow_combination.go", "main.go", "responsebody.go", @@ -17,15 +18,23 @@ go_library( "//examples/proto/examplepb:go_default_library", "//examples/proto/sub:go_default_library", "//examples/proto/sub2:go_default_library", - "@com_github_golang_glog//:go_default_library", - "@com_github_golang_protobuf//proto:go_default_library", - "@com_github_rogpeppe_fastuuid//:go_default_library", + "//vendor/github.com/golang/glog:go_default_library", + "//vendor/github.com/golang/protobuf/proto:go_default_library", + "//vendor/github.com/rogpeppe/fastuuid:go_default_library", + "//vendor/google.golang.org/grpc/codes:go_default_library", + "//vendor/google.golang.org/grpc/metadata:go_default_library", + "//vendor/google.golang.org/grpc/status:go_default_library", "@go_googleapis//google/rpc:errdetails_go_proto", "@io_bazel_rules_go//proto/wkt:duration_go_proto", "@io_bazel_rules_go//proto/wkt:empty_go_proto", + "@io_bazel_rules_go//proto/wkt:field_mask_go_proto", "@org_golang_google_grpc//:go_default_library", - "@org_golang_google_grpc//codes:go_default_library", - "@org_golang_google_grpc//metadata:go_default_library", - "@org_golang_google_grpc//status:go_default_library", ], ) + +go_test( + name = "go_default_test", + srcs = ["fieldmask_helper_test.go"], + embed = [":go_default_library"], + deps = ["@io_bazel_rules_go//proto/wkt:field_mask_go_proto"], +) diff --git a/protoc-gen-grpc-gateway/BUILD.bazel b/protoc-gen-grpc-gateway/BUILD.bazel index 1af07f27f79..d11de3bc524 100644 --- a/protoc-gen-grpc-gateway/BUILD.bazel +++ b/protoc-gen-grpc-gateway/BUILD.bazel @@ -11,8 +11,8 @@ go_library( "//codegenerator:go_default_library", "//protoc-gen-grpc-gateway/descriptor:go_default_library", "//protoc-gen-grpc-gateway/gengateway:go_default_library", - "@com_github_golang_glog//:go_default_library", - "@com_github_golang_protobuf//proto:go_default_library", + "//vendor/github.com/golang/glog:go_default_library", + "//vendor/github.com/golang/protobuf/proto:go_default_library", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", ], ) diff --git a/protoc-gen-grpc-gateway/descriptor/BUILD.bazel b/protoc-gen-grpc-gateway/descriptor/BUILD.bazel index cfbdc277a8c..bff70b933ce 100644 --- a/protoc-gen-grpc-gateway/descriptor/BUILD.bazel +++ b/protoc-gen-grpc-gateway/descriptor/BUILD.bazel @@ -14,10 +14,10 @@ go_library( importpath = "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor", deps = [ "//protoc-gen-grpc-gateway/httprule:go_default_library", - "@com_github_ghodss_yaml//:go_default_library", - "@com_github_golang_glog//:go_default_library", + "//vendor/github.com/ghodss/yaml:go_default_library", + "//vendor/github.com/golang/glog:go_default_library", + "//vendor/github.com/golang/protobuf/proto:go_default_library", "@com_github_golang_protobuf//jsonpb:go_default_library_gen", - "@com_github_golang_protobuf//proto:go_default_library", "@com_github_golang_protobuf//protoc-gen-go/generator:go_default_library_gen", "@go_googleapis//google/api:annotations_go_proto", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", @@ -37,7 +37,7 @@ go_test( embed = [":go_default_library"], deps = [ "//protoc-gen-grpc-gateway/httprule:go_default_library", - "@com_github_golang_protobuf//proto:go_default_library", + "//vendor/github.com/golang/protobuf/proto:go_default_library", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", "@io_bazel_rules_go//proto/wkt:descriptor_go_proto", ], diff --git a/protoc-gen-grpc-gateway/gengateway/BUILD.bazel b/protoc-gen-grpc-gateway/gengateway/BUILD.bazel index fcd9cfc3209..cc3fd3b4d72 100644 --- a/protoc-gen-grpc-gateway/gengateway/BUILD.bazel +++ b/protoc-gen-grpc-gateway/gengateway/BUILD.bazel @@ -14,8 +14,9 @@ go_library( "//protoc-gen-grpc-gateway/descriptor:go_default_library", "//protoc-gen-grpc-gateway/generator:go_default_library", "//utilities:go_default_library", - "@com_github_golang_glog//:go_default_library", - "@com_github_golang_protobuf//proto:go_default_library", + "//vendor/github.com/golang/glog:go_default_library", + "//vendor/github.com/golang/protobuf/proto:go_default_library", + "@com_github_golang_protobuf//protoc-gen-go/generator:go_default_library_gen", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", ], ) @@ -31,7 +32,7 @@ go_test( deps = [ "//protoc-gen-grpc-gateway/descriptor:go_default_library", "//protoc-gen-grpc-gateway/httprule:go_default_library", - "@com_github_golang_protobuf//proto:go_default_library", + "//vendor/github.com/golang/protobuf/proto:go_default_library", "@io_bazel_rules_go//proto/wkt:descriptor_go_proto", ], ) diff --git a/protoc-gen-grpc-gateway/httprule/BUILD.bazel b/protoc-gen-grpc-gateway/httprule/BUILD.bazel index 89f94a14b45..68f4f2929df 100644 --- a/protoc-gen-grpc-gateway/httprule/BUILD.bazel +++ b/protoc-gen-grpc-gateway/httprule/BUILD.bazel @@ -12,7 +12,7 @@ go_library( importpath = "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/httprule", deps = [ "//utilities:go_default_library", - "@com_github_golang_glog//:go_default_library", + "//vendor/github.com/golang/glog:go_default_library", ], ) @@ -27,6 +27,6 @@ go_test( embed = [":go_default_library"], deps = [ "//utilities:go_default_library", - "@com_github_golang_glog//:go_default_library", + "//vendor/github.com/golang/glog:go_default_library", ], ) diff --git a/protoc-gen-swagger/BUILD.bazel b/protoc-gen-swagger/BUILD.bazel index d5a1d05fcc7..bd7d3e3668c 100644 --- a/protoc-gen-swagger/BUILD.bazel +++ b/protoc-gen-swagger/BUILD.bazel @@ -10,8 +10,8 @@ go_library( "//codegenerator:go_default_library", "//protoc-gen-grpc-gateway/descriptor:go_default_library", "//protoc-gen-swagger/genswagger:go_default_library", - "@com_github_golang_glog//:go_default_library", - "@com_github_golang_protobuf//proto:go_default_library", + "//vendor/github.com/golang/glog:go_default_library", + "//vendor/github.com/golang/protobuf/proto:go_default_library", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", ], ) diff --git a/protoc-gen-swagger/genswagger/BUILD.bazel b/protoc-gen-swagger/genswagger/BUILD.bazel index 172330ad88f..3faa83a593c 100644 --- a/protoc-gen-swagger/genswagger/BUILD.bazel +++ b/protoc-gen-swagger/genswagger/BUILD.bazel @@ -15,8 +15,8 @@ go_library( "//protoc-gen-grpc-gateway/descriptor:go_default_library", "//protoc-gen-grpc-gateway/generator:go_default_library", "//protoc-gen-swagger/options:go_default_library", - "@com_github_golang_glog//:go_default_library", - "@com_github_golang_protobuf//proto:go_default_library", + "//vendor/github.com/golang/glog:go_default_library", + "//vendor/github.com/golang/protobuf/proto:go_default_library", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", "@io_bazel_rules_go//proto/wkt:descriptor_go_proto", ], @@ -30,7 +30,7 @@ go_test( deps = [ "//protoc-gen-grpc-gateway/descriptor:go_default_library", "//protoc-gen-grpc-gateway/httprule:go_default_library", - "@com_github_golang_protobuf//proto:go_default_library", + "//vendor/github.com/golang/protobuf/proto:go_default_library", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", "@io_bazel_rules_go//proto/wkt:descriptor_go_proto", ], diff --git a/runtime/BUILD.bazel b/runtime/BUILD.bazel index 66a8999f2a2..c8a4dd83d3a 100644 --- a/runtime/BUILD.bazel +++ b/runtime/BUILD.bazel @@ -9,6 +9,7 @@ go_library( "convert.go", "doc.go", "errors.go", + "fieldmask.go", "handler.go", "marshal_json.go", "marshal_jsonpb.go", @@ -25,15 +26,17 @@ go_library( deps = [ "//runtime/internal:go_default_library", "//utilities:go_default_library", + "//vendor/github.com/golang/protobuf/proto:go_default_library", + "//vendor/google.golang.org/grpc/codes:go_default_library", + "//vendor/google.golang.org/grpc/grpclog:go_default_library", + "//vendor/google.golang.org/grpc/metadata:go_default_library", + "//vendor/google.golang.org/grpc/status:go_default_library", "@com_github_golang_protobuf//jsonpb:go_default_library_gen", - "@com_github_golang_protobuf//proto:go_default_library", + "@com_github_golang_protobuf//protoc-gen-go/generator:go_default_library_gen", "@io_bazel_rules_go//proto/wkt:any_go_proto", "@io_bazel_rules_go//proto/wkt:duration_go_proto", + "@io_bazel_rules_go//proto/wkt:field_mask_go_proto", "@io_bazel_rules_go//proto/wkt:timestamp_go_proto", - "@org_golang_google_grpc//codes:go_default_library", - "@org_golang_google_grpc//grpclog:go_default_library", - "@org_golang_google_grpc//metadata:go_default_library", - "@org_golang_google_grpc//status:go_default_library", ], ) @@ -43,6 +46,7 @@ go_test( srcs = [ "context_test.go", "errors_test.go", + "fieldmask_test.go", "handler_test.go", "marshal_json_test.go", "marshal_jsonpb_test.go", @@ -57,8 +61,11 @@ go_test( "//examples/proto/examplepb:go_default_library", "//runtime/internal:go_default_library", "//utilities:go_default_library", + "//vendor/github.com/golang/protobuf/proto:go_default_library", + "//vendor/google.golang.org/grpc/codes:go_default_library", + "//vendor/google.golang.org/grpc/metadata:go_default_library", + "//vendor/google.golang.org/grpc/status:go_default_library", "@com_github_golang_protobuf//jsonpb:go_default_library_gen", - "@com_github_golang_protobuf//proto:go_default_library", "@com_github_golang_protobuf//ptypes:go_default_library_gen", "@go_googleapis//google/rpc:errdetails_go_proto", "@io_bazel_rules_go//proto/wkt:duration_go_proto", @@ -68,8 +75,5 @@ go_test( "@io_bazel_rules_go//proto/wkt:timestamp_go_proto", "@io_bazel_rules_go//proto/wkt:wrappers_go_proto", "@org_golang_google_grpc//:go_default_library", - "@org_golang_google_grpc//codes:go_default_library", - "@org_golang_google_grpc//metadata:go_default_library", - "@org_golang_google_grpc//status:go_default_library", ], ) diff --git a/utilities/BUILD.bazel b/utilities/BUILD.bazel index 151f6864d92..7109d793231 100644 --- a/utilities/BUILD.bazel +++ b/utilities/BUILD.bazel @@ -7,6 +7,7 @@ go_library( srcs = [ "doc.go", "pattern.go", + "readerfactory.go", "trie.go", ], importpath = "github.com/grpc-ecosystem/grpc-gateway/utilities", From fc65e031d8e555a7855512acbafb43b537ab3a09 Mon Sep 17 00:00:00 2001 From: Roman Azami Date: Thu, 15 Nov 2018 08:52:44 -0800 Subject: [PATCH 7/7] Rebased with master to fix bazel tests and removed vendor dependencies --- codegenerator/BUILD.bazel | 4 ++-- examples/clients/abe/BUILD.bazel | 2 +- examples/clients/echo/BUILD.bazel | 2 +- examples/clients/responsebody/BUILD.bazel | 2 +- examples/clients/unannotatedecho/BUILD.bazel | 2 +- .../cmd/example-gateway-server/BUILD.bazel | 2 +- examples/cmd/example-grpc-server/BUILD.bazel | 2 +- examples/gateway/BUILD.bazel | 4 ++-- examples/integration/BUILD.bazel | 6 +++--- examples/proto/examplepb/BUILD.bazel | 10 +++++----- examples/server/BUILD.bazel | 12 ++++++------ protoc-gen-grpc-gateway/BUILD.bazel | 4 ++-- protoc-gen-grpc-gateway/descriptor/BUILD.bazel | 8 ++++---- protoc-gen-grpc-gateway/gengateway/BUILD.bazel | 6 +++--- protoc-gen-grpc-gateway/httprule/BUILD.bazel | 4 ++-- protoc-gen-swagger/BUILD.bazel | 4 ++-- protoc-gen-swagger/genswagger/BUILD.bazel | 6 +++--- runtime/BUILD.bazel | 18 +++++++++--------- 18 files changed, 49 insertions(+), 49 deletions(-) diff --git a/codegenerator/BUILD.bazel b/codegenerator/BUILD.bazel index d14983dcf4a..651177fa157 100644 --- a/codegenerator/BUILD.bazel +++ b/codegenerator/BUILD.bazel @@ -10,7 +10,7 @@ go_library( ], importpath = "github.com/grpc-ecosystem/grpc-gateway/codegenerator", deps = [ - "//vendor/github.com/golang/protobuf/proto:go_default_library", + "@com_github_golang_protobuf//proto:go_default_library", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", ], ) @@ -20,7 +20,7 @@ go_test( srcs = ["parse_req_test.go"], embed = [":go_default_library"], deps = [ - "//vendor/github.com/golang/protobuf/proto:go_default_library", + "@com_github_golang_protobuf//proto:go_default_library", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", ], ) diff --git a/examples/clients/abe/BUILD.bazel b/examples/clients/abe/BUILD.bazel index c9f40633f64..5df684b7f31 100644 --- a/examples/clients/abe/BUILD.bazel +++ b/examples/clients/abe/BUILD.bazel @@ -31,6 +31,6 @@ go_library( "//examples/proto/examplepb:go_default_library", "//examples/proto/pathenum:go_default_library", "//runtime:go_default_library", - "//vendor/github.com/go-resty/resty:go_default_library", + "@com_github_go_resty_resty//:go_default_library", ], ) diff --git a/examples/clients/echo/BUILD.bazel b/examples/clients/echo/BUILD.bazel index 3d220ab7292..090b56aafab 100644 --- a/examples/clients/echo/BUILD.bazel +++ b/examples/clients/echo/BUILD.bazel @@ -13,5 +13,5 @@ go_library( "examplepb_simple_message.go", ], importpath = "github.com/grpc-ecosystem/grpc-gateway/examples/clients/echo", - deps = ["//vendor/github.com/go-resty/resty:go_default_library"], + deps = ["@com_github_go_resty_resty//:go_default_library"], ) diff --git a/examples/clients/responsebody/BUILD.bazel b/examples/clients/responsebody/BUILD.bazel index e9f45b174a8..bdbc237a815 100644 --- a/examples/clients/responsebody/BUILD.bazel +++ b/examples/clients/responsebody/BUILD.bazel @@ -15,5 +15,5 @@ go_library( ], importpath = "github.com/grpc-ecosystem/grpc-gateway/examples/clients/responsebody", visibility = ["//visibility:public"], - deps = ["//vendor/github.com/go-resty/resty:go_default_library"], + deps = ["@com_github_go_resty_resty//:go_default_library"], ) diff --git a/examples/clients/unannotatedecho/BUILD.bazel b/examples/clients/unannotatedecho/BUILD.bazel index f0749ef59b1..611c6c7052d 100644 --- a/examples/clients/unannotatedecho/BUILD.bazel +++ b/examples/clients/unannotatedecho/BUILD.bazel @@ -12,5 +12,5 @@ go_library( "unannotated_echo_service_api.go", ], importpath = "github.com/grpc-ecosystem/grpc-gateway/examples/clients/unannotatedecho", - deps = ["//vendor/github.com/go-resty/resty:go_default_library"], + deps = ["@com_github_go_resty_resty//:go_default_library"], ) diff --git a/examples/cmd/example-gateway-server/BUILD.bazel b/examples/cmd/example-gateway-server/BUILD.bazel index 9f649f711f1..0f7c5052e7e 100644 --- a/examples/cmd/example-gateway-server/BUILD.bazel +++ b/examples/cmd/example-gateway-server/BUILD.bazel @@ -7,7 +7,7 @@ go_library( visibility = ["//visibility:private"], deps = [ "//examples/gateway:go_default_library", - "//vendor/github.com/golang/glog:go_default_library", + "@com_github_golang_glog//:go_default_library", ], ) diff --git a/examples/cmd/example-grpc-server/BUILD.bazel b/examples/cmd/example-grpc-server/BUILD.bazel index 5a0a9fa11a3..1c66416c6ba 100644 --- a/examples/cmd/example-grpc-server/BUILD.bazel +++ b/examples/cmd/example-grpc-server/BUILD.bazel @@ -8,7 +8,7 @@ go_library( importpath = "github.com/grpc-ecosystem/grpc-gateway/examples/cmd/example-grpc-server", deps = [ "//examples/server:go_default_library", - "//vendor/github.com/golang/glog:go_default_library", + "@com_github_golang_glog//:go_default_library", ], ) diff --git a/examples/gateway/BUILD.bazel b/examples/gateway/BUILD.bazel index 4b091e3d8f4..393a7c41f9c 100644 --- a/examples/gateway/BUILD.bazel +++ b/examples/gateway/BUILD.bazel @@ -13,8 +13,8 @@ go_library( deps = [ "//examples/proto/examplepb:go_default_library", "//runtime:go_default_library", - "//vendor/github.com/golang/glog:go_default_library", - "//vendor/google.golang.org/grpc/connectivity:go_default_library", + "@com_github_golang_glog//:go_default_library", "@org_golang_google_grpc//:go_default_library", + "@org_golang_google_grpc//connectivity:go_default_library", ], ) diff --git a/examples/integration/BUILD.bazel b/examples/integration/BUILD.bazel index 7897846fb68..b37ad78ec78 100644 --- a/examples/integration/BUILD.bazel +++ b/examples/integration/BUILD.bazel @@ -18,12 +18,12 @@ go_test( "//examples/proto/sub:go_default_library", "//examples/server:go_default_library", "//runtime:go_default_library", - "//vendor/github.com/golang/glog:go_default_library", - "//vendor/github.com/golang/protobuf/proto:go_default_library", - "//vendor/google.golang.org/grpc/codes:go_default_library", + "@com_github_golang_glog//:go_default_library", "@com_github_golang_protobuf//jsonpb:go_default_library_gen", + "@com_github_golang_protobuf//proto:go_default_library", "@go_googleapis//google/rpc:status_go_proto", "@io_bazel_rules_go//proto/wkt:empty_go_proto", "@io_bazel_rules_go//proto/wkt:field_mask_go_proto", + "@org_golang_google_grpc//codes:go_default_library", ], ) diff --git a/examples/proto/examplepb/BUILD.bazel b/examples/proto/examplepb/BUILD.bazel index b275a86aa99..f819a9472dd 100644 --- a/examples/proto/examplepb/BUILD.bazel +++ b/examples/proto/examplepb/BUILD.bazel @@ -61,12 +61,12 @@ go_library( deps = [ "//runtime:go_default_library", "//utilities:go_default_library", - "//vendor/github.com/golang/protobuf/proto:go_default_library", - "//vendor/golang.org/x/net/context:go_default_library", - "//vendor/google.golang.org/grpc/codes:go_default_library", - "//vendor/google.golang.org/grpc/grpclog:go_default_library", - "//vendor/google.golang.org/grpc/status:go_default_library", + "@com_github_golang_protobuf//proto:go_default_library", "@org_golang_google_grpc//:go_default_library", + "@org_golang_google_grpc//codes:go_default_library", + "@org_golang_google_grpc//grpclog:go_default_library", + "@org_golang_google_grpc//status:go_default_library", + "@org_golang_x_net//context:go_default_library", ], ) diff --git a/examples/server/BUILD.bazel b/examples/server/BUILD.bazel index 3ca0092b51a..6a35faff50c 100644 --- a/examples/server/BUILD.bazel +++ b/examples/server/BUILD.bazel @@ -18,17 +18,17 @@ go_library( "//examples/proto/examplepb:go_default_library", "//examples/proto/sub:go_default_library", "//examples/proto/sub2:go_default_library", - "//vendor/github.com/golang/glog:go_default_library", - "//vendor/github.com/golang/protobuf/proto:go_default_library", - "//vendor/github.com/rogpeppe/fastuuid:go_default_library", - "//vendor/google.golang.org/grpc/codes:go_default_library", - "//vendor/google.golang.org/grpc/metadata:go_default_library", - "//vendor/google.golang.org/grpc/status:go_default_library", + "@com_github_golang_glog//:go_default_library", + "@com_github_golang_protobuf//proto:go_default_library", + "@com_github_rogpeppe_fastuuid//:go_default_library", "@go_googleapis//google/rpc:errdetails_go_proto", "@io_bazel_rules_go//proto/wkt:duration_go_proto", "@io_bazel_rules_go//proto/wkt:empty_go_proto", "@io_bazel_rules_go//proto/wkt:field_mask_go_proto", "@org_golang_google_grpc//:go_default_library", + "@org_golang_google_grpc//codes:go_default_library", + "@org_golang_google_grpc//metadata:go_default_library", + "@org_golang_google_grpc//status:go_default_library", ], ) diff --git a/protoc-gen-grpc-gateway/BUILD.bazel b/protoc-gen-grpc-gateway/BUILD.bazel index d11de3bc524..1af07f27f79 100644 --- a/protoc-gen-grpc-gateway/BUILD.bazel +++ b/protoc-gen-grpc-gateway/BUILD.bazel @@ -11,8 +11,8 @@ go_library( "//codegenerator:go_default_library", "//protoc-gen-grpc-gateway/descriptor:go_default_library", "//protoc-gen-grpc-gateway/gengateway:go_default_library", - "//vendor/github.com/golang/glog:go_default_library", - "//vendor/github.com/golang/protobuf/proto:go_default_library", + "@com_github_golang_glog//:go_default_library", + "@com_github_golang_protobuf//proto:go_default_library", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", ], ) diff --git a/protoc-gen-grpc-gateway/descriptor/BUILD.bazel b/protoc-gen-grpc-gateway/descriptor/BUILD.bazel index bff70b933ce..cfbdc277a8c 100644 --- a/protoc-gen-grpc-gateway/descriptor/BUILD.bazel +++ b/protoc-gen-grpc-gateway/descriptor/BUILD.bazel @@ -14,10 +14,10 @@ go_library( importpath = "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor", deps = [ "//protoc-gen-grpc-gateway/httprule:go_default_library", - "//vendor/github.com/ghodss/yaml:go_default_library", - "//vendor/github.com/golang/glog:go_default_library", - "//vendor/github.com/golang/protobuf/proto:go_default_library", + "@com_github_ghodss_yaml//:go_default_library", + "@com_github_golang_glog//:go_default_library", "@com_github_golang_protobuf//jsonpb:go_default_library_gen", + "@com_github_golang_protobuf//proto:go_default_library", "@com_github_golang_protobuf//protoc-gen-go/generator:go_default_library_gen", "@go_googleapis//google/api:annotations_go_proto", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", @@ -37,7 +37,7 @@ go_test( embed = [":go_default_library"], deps = [ "//protoc-gen-grpc-gateway/httprule:go_default_library", - "//vendor/github.com/golang/protobuf/proto:go_default_library", + "@com_github_golang_protobuf//proto:go_default_library", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", "@io_bazel_rules_go//proto/wkt:descriptor_go_proto", ], diff --git a/protoc-gen-grpc-gateway/gengateway/BUILD.bazel b/protoc-gen-grpc-gateway/gengateway/BUILD.bazel index cc3fd3b4d72..316010f500d 100644 --- a/protoc-gen-grpc-gateway/gengateway/BUILD.bazel +++ b/protoc-gen-grpc-gateway/gengateway/BUILD.bazel @@ -14,8 +14,8 @@ go_library( "//protoc-gen-grpc-gateway/descriptor:go_default_library", "//protoc-gen-grpc-gateway/generator:go_default_library", "//utilities:go_default_library", - "//vendor/github.com/golang/glog:go_default_library", - "//vendor/github.com/golang/protobuf/proto:go_default_library", + "@com_github_golang_glog//:go_default_library", + "@com_github_golang_protobuf//proto:go_default_library", "@com_github_golang_protobuf//protoc-gen-go/generator:go_default_library_gen", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", ], @@ -32,7 +32,7 @@ go_test( deps = [ "//protoc-gen-grpc-gateway/descriptor:go_default_library", "//protoc-gen-grpc-gateway/httprule:go_default_library", - "//vendor/github.com/golang/protobuf/proto:go_default_library", + "@com_github_golang_protobuf//proto:go_default_library", "@io_bazel_rules_go//proto/wkt:descriptor_go_proto", ], ) diff --git a/protoc-gen-grpc-gateway/httprule/BUILD.bazel b/protoc-gen-grpc-gateway/httprule/BUILD.bazel index 68f4f2929df..89f94a14b45 100644 --- a/protoc-gen-grpc-gateway/httprule/BUILD.bazel +++ b/protoc-gen-grpc-gateway/httprule/BUILD.bazel @@ -12,7 +12,7 @@ go_library( importpath = "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/httprule", deps = [ "//utilities:go_default_library", - "//vendor/github.com/golang/glog:go_default_library", + "@com_github_golang_glog//:go_default_library", ], ) @@ -27,6 +27,6 @@ go_test( embed = [":go_default_library"], deps = [ "//utilities:go_default_library", - "//vendor/github.com/golang/glog:go_default_library", + "@com_github_golang_glog//:go_default_library", ], ) diff --git a/protoc-gen-swagger/BUILD.bazel b/protoc-gen-swagger/BUILD.bazel index bd7d3e3668c..d5a1d05fcc7 100644 --- a/protoc-gen-swagger/BUILD.bazel +++ b/protoc-gen-swagger/BUILD.bazel @@ -10,8 +10,8 @@ go_library( "//codegenerator:go_default_library", "//protoc-gen-grpc-gateway/descriptor:go_default_library", "//protoc-gen-swagger/genswagger:go_default_library", - "//vendor/github.com/golang/glog:go_default_library", - "//vendor/github.com/golang/protobuf/proto:go_default_library", + "@com_github_golang_glog//:go_default_library", + "@com_github_golang_protobuf//proto:go_default_library", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", ], ) diff --git a/protoc-gen-swagger/genswagger/BUILD.bazel b/protoc-gen-swagger/genswagger/BUILD.bazel index 3faa83a593c..172330ad88f 100644 --- a/protoc-gen-swagger/genswagger/BUILD.bazel +++ b/protoc-gen-swagger/genswagger/BUILD.bazel @@ -15,8 +15,8 @@ go_library( "//protoc-gen-grpc-gateway/descriptor:go_default_library", "//protoc-gen-grpc-gateway/generator:go_default_library", "//protoc-gen-swagger/options:go_default_library", - "//vendor/github.com/golang/glog:go_default_library", - "//vendor/github.com/golang/protobuf/proto:go_default_library", + "@com_github_golang_glog//:go_default_library", + "@com_github_golang_protobuf//proto:go_default_library", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", "@io_bazel_rules_go//proto/wkt:descriptor_go_proto", ], @@ -30,7 +30,7 @@ go_test( deps = [ "//protoc-gen-grpc-gateway/descriptor:go_default_library", "//protoc-gen-grpc-gateway/httprule:go_default_library", - "//vendor/github.com/golang/protobuf/proto:go_default_library", + "@com_github_golang_protobuf//proto:go_default_library", "@io_bazel_rules_go//proto/wkt:compiler_plugin_go_proto", "@io_bazel_rules_go//proto/wkt:descriptor_go_proto", ], diff --git a/runtime/BUILD.bazel b/runtime/BUILD.bazel index c8a4dd83d3a..fd2139737df 100644 --- a/runtime/BUILD.bazel +++ b/runtime/BUILD.bazel @@ -26,17 +26,17 @@ go_library( deps = [ "//runtime/internal:go_default_library", "//utilities:go_default_library", - "//vendor/github.com/golang/protobuf/proto:go_default_library", - "//vendor/google.golang.org/grpc/codes:go_default_library", - "//vendor/google.golang.org/grpc/grpclog:go_default_library", - "//vendor/google.golang.org/grpc/metadata:go_default_library", - "//vendor/google.golang.org/grpc/status:go_default_library", "@com_github_golang_protobuf//jsonpb:go_default_library_gen", + "@com_github_golang_protobuf//proto:go_default_library", "@com_github_golang_protobuf//protoc-gen-go/generator:go_default_library_gen", "@io_bazel_rules_go//proto/wkt:any_go_proto", "@io_bazel_rules_go//proto/wkt:duration_go_proto", "@io_bazel_rules_go//proto/wkt:field_mask_go_proto", "@io_bazel_rules_go//proto/wkt:timestamp_go_proto", + "@org_golang_google_grpc//codes:go_default_library", + "@org_golang_google_grpc//grpclog:go_default_library", + "@org_golang_google_grpc//metadata:go_default_library", + "@org_golang_google_grpc//status:go_default_library", ], ) @@ -61,11 +61,8 @@ go_test( "//examples/proto/examplepb:go_default_library", "//runtime/internal:go_default_library", "//utilities:go_default_library", - "//vendor/github.com/golang/protobuf/proto:go_default_library", - "//vendor/google.golang.org/grpc/codes:go_default_library", - "//vendor/google.golang.org/grpc/metadata:go_default_library", - "//vendor/google.golang.org/grpc/status:go_default_library", "@com_github_golang_protobuf//jsonpb:go_default_library_gen", + "@com_github_golang_protobuf//proto:go_default_library", "@com_github_golang_protobuf//ptypes:go_default_library_gen", "@go_googleapis//google/rpc:errdetails_go_proto", "@io_bazel_rules_go//proto/wkt:duration_go_proto", @@ -75,5 +72,8 @@ go_test( "@io_bazel_rules_go//proto/wkt:timestamp_go_proto", "@io_bazel_rules_go//proto/wkt:wrappers_go_proto", "@org_golang_google_grpc//:go_default_library", + "@org_golang_google_grpc//codes:go_default_library", + "@org_golang_google_grpc//metadata:go_default_library", + "@org_golang_google_grpc//status:go_default_library", ], )