Skip to content

Commit 4ff0812

Browse files
authored
chore: Add X-Goog-Api-Client metric header to outgoing requests (#655)
* chore: Add `X-Goog-Api-Client` metric header to outgoing requests * Fix lint and test * Remove App Check headers
1 parent 4d55c62 commit 4ff0812

14 files changed

+58
-23
lines changed

auth/auth.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import (
2121
"errors"
2222
"fmt"
2323
"os"
24-
"runtime"
2524
"strings"
2625
"time"
2726

@@ -134,12 +133,11 @@ func NewClient(ctx context.Context, conf *internal.AuthConfig) (*Client, error)
134133
return nil, err
135134
}
136135

137-
goVersion := strings.TrimPrefix(runtime.Version(), "go")
138136
hc := internal.WithDefaultRetryConfig(transport)
139137
hc.CreateErrFn = handleHTTPError
140138
hc.Opts = []internal.HTTPOption{
141139
internal.WithHeader("X-Client-Version", fmt.Sprintf("Go/Admin/%s", conf.Version)),
142-
internal.WithHeader("x-goog-api-client", fmt.Sprintf("gl-go/%s fire-admin/%s", goVersion, conf.Version)),
140+
internal.WithHeader("x-goog-api-client", internal.GetMetricsHeader(conf.Version)),
143141
}
144142

145143
baseURL := defaultAuthURL

auth/auth_test.go

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import (
2323
"log"
2424
"net/http"
2525
"os"
26-
"runtime"
2726
"strings"
2827
"syscall"
2928
"testing"
@@ -1452,11 +1451,9 @@ func checkBaseClient(client *Client, wantProjectID string) error {
14521451
return fmt.Errorf("version = %q; want = %q", version, wantVersion)
14531452
}
14541453

1455-
goVersion := strings.TrimPrefix(runtime.Version(), "go")
1456-
xGoogAPIClientHeader := req.Header.Get("x-goog-api-client")
1457-
wantXGoogAPIClientHeader := fmt.Sprintf("gl-go/%s fire-admin/%s", goVersion, testVersion)
1458-
if xGoogAPIClientHeader != wantXGoogAPIClientHeader {
1459-
return fmt.Errorf("x-goog-api-client header = %q; want = %q", xGoogAPIClientHeader, wantXGoogAPIClientHeader)
1454+
xGoogAPIClientHeader := internal.GetMetricsHeader(testVersion)
1455+
if h := req.Header.Get("x-goog-api-client"); h != xGoogAPIClientHeader {
1456+
return fmt.Errorf("x-goog-api-client header = %q; want = %q", h, xGoogAPIClientHeader)
14601457
}
14611458

14621459
return nil

auth/token_generator.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,9 @@ func newIAMSigner(ctx context.Context, config *internal.AuthConfig) (*iamSigner,
175175
if err != nil {
176176
return nil, err
177177
}
178+
hc.Opts = []internal.HTTPOption{
179+
internal.WithHeader("x-goog-api-client", internal.GetMetricsHeader(config.Version)),
180+
}
178181

179182
return &iamSigner{
180183
mutex: &sync.Mutex{},

auth/token_generator_test.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ func TestIAMSigner(t *testing.T) {
122122
conf := &internal.AuthConfig{
123123
Opts: optsWithTokenSource,
124124
ServiceAccountID: "test-service-account",
125+
Version: testVersion,
125126
}
126127
signer, err := newIAMSigner(ctx, conf)
127128
if err != nil {
@@ -155,6 +156,7 @@ func TestIAMSignerHTTPError(t *testing.T) {
155156
conf := &internal.AuthConfig{
156157
Opts: optsWithTokenSource,
157158
ServiceAccountID: "test-service-account",
159+
Version: testVersion,
158160
}
159161
signer, err := newIAMSigner(context.Background(), conf)
160162
if err != nil {
@@ -182,6 +184,7 @@ func TestIAMSignerUnknownHTTPError(t *testing.T) {
182184
conf := &internal.AuthConfig{
183185
Opts: optsWithTokenSource,
184186
ServiceAccountID: "test-service-account",
187+
Version: testVersion,
185188
}
186189
signer, err := newIAMSigner(context.Background(), conf)
187190
if err != nil {
@@ -208,7 +211,8 @@ func TestIAMSignerUnknownHTTPError(t *testing.T) {
208211
func TestIAMSignerWithMetadataService(t *testing.T) {
209212
ctx := context.Background()
210213
conf := &internal.AuthConfig{
211-
Opts: optsWithTokenSource,
214+
Opts: optsWithTokenSource,
215+
Version: testVersion,
212216
}
213217

214218
signer, err := newIAMSigner(ctx, conf)
@@ -253,7 +257,8 @@ func TestIAMSignerWithMetadataService(t *testing.T) {
253257
func TestIAMSignerNoMetadataService(t *testing.T) {
254258
ctx := context.Background()
255259
conf := &internal.AuthConfig{
256-
Opts: optsWithTokenSource,
260+
Opts: optsWithTokenSource,
261+
Version: testVersion,
257262
}
258263

259264
signer, err := newIAMSigner(ctx, conf)
@@ -340,6 +345,10 @@ func iamServer(t *testing.T, serviceAcct, signature string) *httptest.Server {
340345
if r.URL.Path != wantPath {
341346
t.Errorf("Path = %q; want = %q", r.URL.Path, wantPath)
342347
}
348+
xGoogAPIClientHeader := internal.GetMetricsHeader(testVersion)
349+
if h := r.Header.Get("x-goog-api-client"); h != xGoogAPIClientHeader {
350+
t.Errorf("x-goog-api-client header = %q; want = %q", h, xGoogAPIClientHeader)
351+
}
343352

344353
w.Header().Set("Content-Type", "application/json")
345354
b, err := json.Marshal(resp)

auth/user_mgt_test.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import (
2424
"net/http"
2525
"net/http/httptest"
2626
"reflect"
27-
"runtime"
2827
"sort"
2928
"strconv"
3029
"strings"
@@ -2317,7 +2316,7 @@ func echoServer(resp interface{}, t *testing.T) *mockAuthServer {
23172316
}
23182317

23192318
gh = r.Header.Get("x-goog-api-client")
2320-
wh = fmt.Sprintf("gl-go/%s fire-admin/%s", strings.TrimPrefix(runtime.Version(), "go"), testVersion)
2319+
wh = internal.GetMetricsHeader(testVersion)
23212320
if gh != wh {
23222321
t.Errorf("x-goog-api-client header = %q; want: %q", gh, wh)
23232322
}

firebase.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ func (a *App) InstanceID(ctx context.Context) (*iid.Client, error) {
115115
conf := &internal.InstanceIDConfig{
116116
ProjectID: a.projectID,
117117
Opts: a.opts,
118+
Version: Version,
118119
}
119120
return iid.NewClient(ctx, conf)
120121
}

iid/iid.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,9 @@ func NewClient(ctx context.Context, c *internal.InstanceIDConfig) (*Client, erro
119119
if err != nil {
120120
return nil, err
121121
}
122+
hc.Opts = []internal.HTTPOption{
123+
internal.WithHeader("x-goog-api-client", internal.GetMetricsHeader(c.Version)),
124+
}
122125

123126
hc.CreateErrFn = createError
124127
return &Client{

iid/iid_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ var testIIDConfig = &internal.InstanceIDConfig{
3131
Opts: []option.ClientOption{
3232
option.WithTokenSource(&internal.MockTokenSource{AccessToken: "test-token"}),
3333
},
34+
Version: "test-version",
3435
}
3536

3637
func TestNoProjectID(t *testing.T) {
@@ -83,6 +84,10 @@ func TestDeleteInstanceID(t *testing.T) {
8384
if h := tr.Header.Get("Authorization"); h != "Bearer test-token" {
8485
t.Errorf("Authorization = %q; want = %q", h, "Bearer test-token")
8586
}
87+
xGoogAPIClientHeader := internal.GetMetricsHeader(testIIDConfig.Version)
88+
if h := tr.Header.Get("x-goog-api-client"); h != xGoogAPIClientHeader {
89+
t.Errorf("x-goog-api-client header = %q; want = %q", h, xGoogAPIClientHeader)
90+
}
8691
}
8792

8893
func TestDeleteInstanceIDError(t *testing.T) {
@@ -156,6 +161,10 @@ func TestDeleteInstanceIDError(t *testing.T) {
156161
if h := tr.Header.Get("Authorization"); h != "Bearer test-token" {
157162
t.Errorf("Authorization = %q; want = %q", h, "Bearer test-token")
158163
}
164+
xGoogAPIClientHeader := internal.GetMetricsHeader(testIIDConfig.Version)
165+
if h := tr.Header.Get("x-goog-api-client"); h != xGoogAPIClientHeader {
166+
t.Errorf("x-goog-api-client header = %q; want = %q", h, xGoogAPIClientHeader)
167+
}
159168
tr = nil
160169
}
161170
}
@@ -201,6 +210,10 @@ func TestDeleteInstanceIDUnexpectedError(t *testing.T) {
201210
if h := tr.Header.Get("Authorization"); h != "Bearer test-token" {
202211
t.Errorf("Authorization = %q; want = %q", h, "Bearer test-token")
203212
}
213+
xGoogAPIClientHeader := internal.GetMetricsHeader(testIIDConfig.Version)
214+
if h := tr.Header.Get("x-goog-api-client"); h != xGoogAPIClientHeader {
215+
t.Errorf("x-goog-api-client header = %q; want = %q", h, xGoogAPIClientHeader)
216+
}
204217
}
205218

206219
func TestDeleteInstanceIDConnectionError(t *testing.T) {

internal/http_client.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ import (
2323
"io/ioutil"
2424
"math"
2525
"net/http"
26+
"runtime"
2627
"strconv"
28+
"strings"
2729
"time"
2830

2931
"google.golang.org/api/option"
@@ -441,3 +443,9 @@ func retryNetworkAndHTTPErrors(statusCodes ...int) RetryCondition {
441443
return false
442444
}
443445
}
446+
447+
// GetMetricsHeader constructs header value for metrics attribution
448+
func GetMetricsHeader(sdkVersion string) string {
449+
goVersion := strings.TrimPrefix(runtime.Version(), "go")
450+
return fmt.Sprintf("gl-go/%s fire-admin/%s", goVersion, sdkVersion)
451+
}

internal/internal.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ type HashConfig map[string]interface{}
5050
type InstanceIDConfig struct {
5151
Opts []option.ClientOption
5252
ProjectID string
53+
Version string
5354
}
5455

5556
// DatabaseConfig represents the configuration of Firebase Database service.

messaging/messaging.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import (
2323
"fmt"
2424
"net/http"
2525
"regexp"
26-
"runtime"
2726
"strconv"
2827
"strings"
2928
"time"
@@ -878,7 +877,7 @@ func NewClient(ctx context.Context, c *internal.MessagingConfig) (*Client, error
878877

879878
return &Client{
880879
fcmClient: newFCMClient(hc, c, messagingEndpoint, batchEndpoint),
881-
iidClient: newIIDClient(hc),
880+
iidClient: newIIDClient(hc, c),
882881
}, nil
883882
}
884883

@@ -894,12 +893,11 @@ func newFCMClient(hc *http.Client, conf *internal.MessagingConfig, messagingEndp
894893
client := internal.WithDefaultRetryConfig(hc)
895894
client.CreateErrFn = handleFCMError
896895

897-
goVersion := strings.TrimPrefix(runtime.Version(), "go")
898896
version := fmt.Sprintf("fire-admin-go/%s", conf.Version)
899897
client.Opts = []internal.HTTPOption{
900898
internal.WithHeader(apiFormatVersionHeader, apiFormatVersion),
901899
internal.WithHeader(firebaseClientHeader, version),
902-
internal.WithHeader("x-goog-api-client", fmt.Sprintf("gl-go/%s fire-admin/%s", goVersion, conf.Version)),
900+
internal.WithHeader("x-goog-api-client", internal.GetMetricsHeader(conf.Version)),
903901
}
904902

905903
return &fcmClient{

messaging/messaging_test.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ import (
2121
"net/http"
2222
"net/http/httptest"
2323
"reflect"
24-
"runtime"
25-
"strings"
2624
"testing"
2725
"time"
2826

@@ -1396,8 +1394,7 @@ func checkFCMRequest(t *testing.T, b []byte, tr *http.Request, want map[string]i
13961394
if h := tr.Header.Get("X-FIREBASE-CLIENT"); h != clientVersion {
13971395
t.Errorf("X-FIREBASE-CLIENT = %q; want = %q", h, clientVersion)
13981396
}
1399-
goVersion := strings.TrimPrefix(runtime.Version(), "go")
1400-
xGoogAPIClientHeader := "gl-go/" + goVersion + " fire-admin/" + testMessagingConfig.Version
1397+
xGoogAPIClientHeader := internal.GetMetricsHeader(testMessagingConfig.Version)
14011398
if h := tr.Header.Get("x-goog-api-client"); h != xGoogAPIClientHeader {
14021399
t.Errorf("x-goog-api-client header = %q; want = %q", h, xGoogAPIClientHeader)
14031400
}

messaging/topic_mgt.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,13 @@ type iidClient struct {
6363
httpClient *internal.HTTPClient
6464
}
6565

66-
func newIIDClient(hc *http.Client) *iidClient {
66+
func newIIDClient(hc *http.Client, conf *internal.MessagingConfig) *iidClient {
6767
client := internal.WithDefaultRetryConfig(hc)
6868
client.CreateErrFn = handleIIDError
69-
client.Opts = []internal.HTTPOption{internal.WithHeader("access_token_auth", "true")}
69+
client.Opts = []internal.HTTPOption{
70+
internal.WithHeader("access_token_auth", "true"),
71+
internal.WithHeader("x-goog-api-client", internal.GetMetricsHeader(conf.Version)),
72+
}
7073
return &iidClient{
7174
iidEndpoint: iidEndpoint,
7275
httpClient: client,

messaging/topic_mgt_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"testing"
2626

2727
"firebase.google.com/go/v4/errorutils"
28+
"firebase.google.com/go/v4/internal"
2829
)
2930

3031
func TestSubscribe(t *testing.T) {
@@ -198,6 +199,10 @@ func checkIIDRequest(t *testing.T, b []byte, tr *http.Request, op string) {
198199
if h := tr.Header.Get("Authorization"); h != "Bearer test-token" {
199200
t.Errorf("Authorization = %q; want = %q", h, "Bearer test-token")
200201
}
202+
xGoogAPIClientHeader := internal.GetMetricsHeader(testMessagingConfig.Version)
203+
if h := tr.Header.Get("x-goog-api-client"); h != xGoogAPIClientHeader {
204+
t.Errorf("x-goog-api-client header = %q; want = %q", h, xGoogAPIClientHeader)
205+
}
201206
}
202207

203208
func checkTopicMgtResponse(t *testing.T, resp *TopicManagementResponse) {

0 commit comments

Comments
 (0)