@@ -40,36 +40,50 @@ func (e wrappedCallErr) Is(target error) bool {
4040 return errors .Is (e .ctxErr , target ) || errors .Is (e .wrappedErr , target )
4141}
4242
43+ // addContextHeaders adds headers set in context metadata.
44+ // x-goog-api-client and x-goog-request-params are merged properly.
45+ func addContextHeaders (ctx context.Context , req * http.Request ) {
46+ if ctx == nil {
47+ return
48+ }
49+ headers := callctx .HeadersFromContext (ctx )
50+ for k , vals := range headers {
51+ if strings .EqualFold (k , "x-goog-api-client" ) {
52+ mergeHeader (req .Header , k , vals , ' ' )
53+ } else if strings .EqualFold (k , "x-goog-request-params" ) {
54+ mergeHeader (req .Header , k , vals , '&' )
55+ } else {
56+ for _ , v := range vals {
57+ req .Header .Add (k , v )
58+ }
59+ }
60+ }
61+ }
62+
63+ // mergeHeader merges multiple values into a single header.
64+ func mergeHeader (header http.Header , key string , vals []string , separator rune ) {
65+ var mergedVal strings.Builder
66+ baseHeader := header .Get (key )
67+ if baseHeader != "" {
68+ mergedVal .WriteString (baseHeader )
69+ mergedVal .WriteRune (separator )
70+ }
71+ for _ , v := range vals {
72+ mergedVal .WriteString (v )
73+ mergedVal .WriteRune (separator )
74+ }
75+ if mergedVal .Len () > 0 {
76+ // Remove the last separator and replace the header on the request.
77+ header .Set (key , mergedVal .String ()[:mergedVal .Len ()- 1 ])
78+ }
79+ }
80+
4381// SendRequest sends a single HTTP request using the given client.
4482// If ctx is non-nil, it calls all hooks, then sends the request with
4583// req.WithContext, then calls any functions returned by the hooks in
4684// reverse order.
4785func SendRequest (ctx context.Context , client * http.Client , req * http.Request ) (* http.Response , error ) {
48- // Add headers set in context metadata.
49- if ctx != nil {
50- headers := callctx .HeadersFromContext (ctx )
51- for k , vals := range headers {
52- if k == "x-goog-api-client" {
53- // Merge all values into a single "x-goog-api-client" header.
54- var mergedVal strings.Builder
55- baseXGoogHeader := req .Header .Get ("X-Goog-Api-Client" )
56- if baseXGoogHeader != "" {
57- mergedVal .WriteString (baseXGoogHeader )
58- mergedVal .WriteRune (' ' )
59- }
60- for _ , v := range vals {
61- mergedVal .WriteString (v )
62- mergedVal .WriteRune (' ' )
63- }
64- // Remove the last space and replace the header on the request.
65- req .Header .Set (k , mergedVal .String ()[:mergedVal .Len ()- 1 ])
66- } else {
67- for _ , v := range vals {
68- req .Header .Add (k , v )
69- }
70- }
71- }
72- }
86+ addContextHeaders (ctx , req )
7387
7488 // Disallow Accept-Encoding because it interferes with the automatic gzip handling
7589 // done by the default http.Transport. See https://github.com/google/google-api-go-client/issues/219.
@@ -105,15 +119,7 @@ func send(ctx context.Context, client *http.Client, req *http.Request) (*http.Re
105119// req.WithContext, then calls any functions returned by the hooks in
106120// reverse order.
107121func SendRequestWithRetry (ctx context.Context , client * http.Client , req * http.Request , retry * RetryConfig ) (* http.Response , error ) {
108- // Add headers set in context metadata.
109- if ctx != nil {
110- headers := callctx .HeadersFromContext (ctx )
111- for k , vals := range headers {
112- for _ , v := range vals {
113- req .Header .Add (k , v )
114- }
115- }
116- }
122+ addContextHeaders (ctx , req )
117123
118124 // Disallow Accept-Encoding because it interferes with the automatic gzip handling
119125 // done by the default http.Transport. See https://github.com/google/google-api-go-client/issues/219.
0 commit comments