diff --git a/internal/gengapic/gengapic.go b/internal/gengapic/gengapic.go index 527ed8343b8..42c7ff72e1c 100644 --- a/internal/gengapic/gengapic.go +++ b/internal/gengapic/gengapic.go @@ -441,8 +441,8 @@ func (g *generator) insertDynamicRequestHeaders(m *descriptorpb.MethodDescriptor return nil } - g.printf(`var routingHeaders []string`) - g.printf("seen := make(map[string]bool)") + g.printf(`routingHeaders := ""`) + g.printf("routingHeadersMap := make(map[string]string)") for i := range headers { namedCaptureRegex := headers[i][0] field := headers[i][1] @@ -455,14 +455,15 @@ func (g *generator) insertDynamicRequestHeaders(m *descriptorpb.MethodDescriptor } // There could be an edge case where the request field is empty and the path template is a wildcard. In that case, we still don't want to send an empty header name. g.printf("if reg := regexp.MustCompile(%q); reg.MatchString(%s) && len(%s) > 0 {", namedCaptureRegex, accessor, regexHelper) - g.printf(" if !seen[%q] {", headerName) - g.printf(" routingHeaders = append(routingHeaders, fmt.Sprintf(\"%%s=%%s\", %q, %s))", headerName, regexHelper) - g.printf(" seen[%q] = true", headerName) - g.printf(" }") + g.printf(" routingHeadersMap[%q] = %s", headerName, regexHelper) g.printf("}") } - g.printf(`hds := []string{"x-goog-request-params", strings.Join(routingHeaders, "&")}`) + g.printf("for headerName, headerValue := range routingHeadersMap {") + g.printf(` routingHeaders = fmt.Sprintf("%%s%%s=%%s&", routingHeaders, headerName, headerValue)`) + g.printf("}") + g.printf(`routingHeaders = strings.TrimSuffix(routingHeaders, "&")`) g.imports[pbinfo.ImportSpec{Path: "strings"}] = true + g.printf(`hds := []string{"x-goog-request-params", routingHeaders}`) g.imports[pbinfo.ImportSpec{Path: "regexp"}] = true return nil } diff --git a/internal/gengapic/testdata/method_GetAnotherThing.want b/internal/gengapic/testdata/method_GetAnotherThing.want index 098b5595e9d..1849b02789a 100644 --- a/internal/gengapic/testdata/method_GetAnotherThing.want +++ b/internal/gengapic/testdata/method_GetAnotherThing.want @@ -1,49 +1,32 @@ func (c *fooGRPCClient) GetAnotherThing(ctx context.Context, req *mypackagepb.InputType, opts ...gax.CallOption) (*mypackagepb.OutputType, error) { - var routingHeaders []string - seen := make(map[string]bool) + routingHeaders := "" + routingHeadersMap := make(map[string]string) if reg := regexp.MustCompile("(.*)"); reg.MatchString(req.GetOther()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetOther())[1])) > 0 { - if !seen["other"] { - routingHeaders = append(routingHeaders, fmt.Sprintf("%s=%s", "other", url.QueryEscape(reg.FindStringSubmatch(req.GetOther())[1]))) - seen["other"] = true - } + routingHeadersMap["other"] = url.QueryEscape(reg.FindStringSubmatch(req.GetOther())[1]) } if reg := regexp.MustCompile("(?Pprojects/[^/]+)/foos"); reg.MatchString(req.GetOther()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetOther())[1])) > 0 { - if !seen["name"] { - routingHeaders = append(routingHeaders, fmt.Sprintf("%s=%s", "name", url.QueryEscape(reg.FindStringSubmatch(req.GetOther())[1]))) - seen["name"] = true - } + routingHeadersMap["name"] = url.QueryEscape(reg.FindStringSubmatch(req.GetOther())[1]) } if reg := regexp.MustCompile("(?Pprojects/[^/]+)/bars/[^/]+(?:/.*)?"); reg.MatchString(req.GetAnother()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetAnother())[1])) > 0 { - if !seen["foo_name"] { - routingHeaders = append(routingHeaders, fmt.Sprintf("%s=%s", "foo_name", url.QueryEscape(reg.FindStringSubmatch(req.GetAnother())[1]))) - seen["foo_name"] = true - } + routingHeadersMap["foo_name"] = url.QueryEscape(reg.FindStringSubmatch(req.GetAnother())[1]) } if reg := regexp.MustCompile("(?Pprojects/[^/]+/foos/[^/]+)/bars/[^/]+(?:/.*)?"); reg.MatchString(req.GetAnother()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetAnother())[1])) > 0 { - if !seen["foo_name"] { - routingHeaders = append(routingHeaders, fmt.Sprintf("%s=%s", "foo_name", url.QueryEscape(reg.FindStringSubmatch(req.GetAnother())[1]))) - seen["foo_name"] = true - } + routingHeadersMap["foo_name"] = url.QueryEscape(reg.FindStringSubmatch(req.GetAnother())[1]) } if reg := regexp.MustCompile("(?P.*)"); reg.MatchString(req.GetAnother()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetAnother())[1])) > 0 { - if !seen["foo_name"] { - routingHeaders = append(routingHeaders, fmt.Sprintf("%s=%s", "foo_name", url.QueryEscape(reg.FindStringSubmatch(req.GetAnother())[1]))) - seen["foo_name"] = true - } + routingHeadersMap["foo_name"] = url.QueryEscape(reg.FindStringSubmatch(req.GetAnother())[1]) } if reg := regexp.MustCompile("(?P.*)"); reg.MatchString(req.GetFieldName().GetNested()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetFieldName().GetNested())[1])) > 0 { - if !seen["nested_name"] { - routingHeaders = append(routingHeaders, fmt.Sprintf("%s=%s", "nested_name", url.QueryEscape(reg.FindStringSubmatch(req.GetFieldName().GetNested())[1]))) - seen["nested_name"] = true - } + routingHeadersMap["nested_name"] = url.QueryEscape(reg.FindStringSubmatch(req.GetFieldName().GetNested())[1]) } if reg := regexp.MustCompile("(?Pprojects/[^/]+)/bars"); reg.MatchString(req.GetFieldName().GetNested()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetFieldName().GetNested())[1])) > 0 { - if !seen["part_of_nested"] { - routingHeaders = append(routingHeaders, fmt.Sprintf("%s=%s", "part_of_nested", url.QueryEscape(reg.FindStringSubmatch(req.GetFieldName().GetNested())[1]))) - seen["part_of_nested"] = true - } + routingHeadersMap["part_of_nested"] = url.QueryEscape(reg.FindStringSubmatch(req.GetFieldName().GetNested())[1]) } - hds := []string{"x-goog-request-params", strings.Join(routingHeaders, "&")} + for headerName, headerValue := range routingHeadersMap { + routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue) + } + routingHeaders = strings.TrimSuffix(routingHeaders, "&") + hds := []string{"x-goog-request-params", routingHeaders} hds = append(c.xGoogHeaders, hds...) ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...) diff --git a/internal/gengapic/testdata/rest_HttpBodyRPC.want b/internal/gengapic/testdata/rest_HttpBodyRPC.want index 57eba9716c6..691d0a492fc 100644 --- a/internal/gengapic/testdata/rest_HttpBodyRPC.want +++ b/internal/gengapic/testdata/rest_HttpBodyRPC.want @@ -12,15 +12,16 @@ func (c *fooRESTClient) HttpBodyRPC(ctx context.Context, req *foopb.Foo, opts .. baseUrl.Path += fmt.Sprintf("/v1/foo") // Build HTTP headers from client and context metadata. - var routingHeaders []string - seen := make(map[string]bool) + routingHeaders := "" + routingHeadersMap := make(map[string]string) if reg := regexp.MustCompile("(.*)"); reg.MatchString(req.GetOther()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetOther())[1])) > 0 { - if !seen["other"] { - routingHeaders = append(routingHeaders, fmt.Sprintf("%s=%s", "other", url.QueryEscape(reg.FindStringSubmatch(req.GetOther())[1]))) - seen["other"] = true - } + routingHeadersMap["other"] = url.QueryEscape(reg.FindStringSubmatch(req.GetOther())[1]) + } + for headerName, headerValue := range routingHeadersMap { + routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue) } - hds := []string{"x-goog-request-params", strings.Join(routingHeaders, "&")} + routingHeaders = strings.TrimSuffix(routingHeaders, "&") + hds := []string{"x-goog-request-params", routingHeaders} hds = append(c.xGoogHeaders, hds...) hds = append(hds, "Content-Type", "application/json") diff --git a/internal/gengapic/testdata/rest_ServerStreamRPC.want b/internal/gengapic/testdata/rest_ServerStreamRPC.want index 180b7f52e20..1cc8d1d668c 100644 --- a/internal/gengapic/testdata/rest_ServerStreamRPC.want +++ b/internal/gengapic/testdata/rest_ServerStreamRPC.want @@ -12,15 +12,16 @@ func (c *fooRESTClient) ServerStreamRPC(ctx context.Context, req *foopb.Foo, opt baseUrl.Path += fmt.Sprintf("/v1/foo") // Build HTTP headers from client and context metadata. - var routingHeaders []string - seen := make(map[string]bool) + routingHeaders := "" + routingHeadersMap := make(map[string]string) if reg := regexp.MustCompile("(.*)"); reg.MatchString(req.GetOther()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetOther())[1])) > 0 { - if !seen["other"] { - routingHeaders = append(routingHeaders, fmt.Sprintf("%s=%s", "other", url.QueryEscape(reg.FindStringSubmatch(req.GetOther())[1]))) - seen["other"] = true - } + routingHeadersMap["other"] = url.QueryEscape(reg.FindStringSubmatch(req.GetOther())[1]) + } + for headerName, headerValue := range routingHeadersMap { + routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue) } - hds := []string{"x-goog-request-params", strings.Join(routingHeaders, "&")} + routingHeaders = strings.TrimSuffix(routingHeaders, "&") + hds := []string{"x-goog-request-params", routingHeaders} hds = append(c.xGoogHeaders, hds...) hds = append(hds, "Content-Type", "application/json") diff --git a/internal/gengapic/testdata/rest_UnaryRPC.want b/internal/gengapic/testdata/rest_UnaryRPC.want index 92eababa2d8..dbf6297b6b9 100644 --- a/internal/gengapic/testdata/rest_UnaryRPC.want +++ b/internal/gengapic/testdata/rest_UnaryRPC.want @@ -20,15 +20,16 @@ func (c *fooRESTClient) UnaryRPC(ctx context.Context, req *foopb.Foo, opts ...ga baseUrl.RawQuery = params.Encode() // Build HTTP headers from client and context metadata. - var routingHeaders []string - seen := make(map[string]bool) + routingHeaders := "" + routingHeadersMap := make(map[string]string) if reg := regexp.MustCompile("(.*)"); reg.MatchString(req.GetOther()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetOther())[1])) > 0 { - if !seen["other"] { - routingHeaders = append(routingHeaders, fmt.Sprintf("%s=%s", "other", url.QueryEscape(reg.FindStringSubmatch(req.GetOther())[1]))) - seen["other"] = true - } + routingHeadersMap["other"] = url.QueryEscape(reg.FindStringSubmatch(req.GetOther())[1]) + } + for headerName, headerValue := range routingHeadersMap { + routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue) } - hds := []string{"x-goog-request-params", strings.Join(routingHeaders, "&")} + routingHeaders = strings.TrimSuffix(routingHeaders, "&") + hds := []string{"x-goog-request-params", routingHeaders} hds = append(c.xGoogHeaders, hds...) hds = append(hds, "Content-Type", "application/json")