Skip to content

Commit

Permalink
chore: Add X-Goog-Api-Client metric header to outgoing requests (#655)
Browse files Browse the repository at this point in the history
* chore: Add `X-Goog-Api-Client` metric header to outgoing requests

* Fix lint and test

* Remove App Check headers
  • Loading branch information
jonathanedey authored Nov 21, 2024
1 parent 4d55c62 commit 4ff0812
Show file tree
Hide file tree
Showing 14 changed files with 58 additions and 23 deletions.
4 changes: 1 addition & 3 deletions auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (
"errors"
"fmt"
"os"
"runtime"
"strings"
"time"

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

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

baseURL := defaultAuthURL
Expand Down
9 changes: 3 additions & 6 deletions auth/auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import (
"log"
"net/http"
"os"
"runtime"
"strings"
"syscall"
"testing"
Expand Down Expand Up @@ -1452,11 +1451,9 @@ func checkBaseClient(client *Client, wantProjectID string) error {
return fmt.Errorf("version = %q; want = %q", version, wantVersion)
}

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

return nil
Expand Down
3 changes: 3 additions & 0 deletions auth/token_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,9 @@ func newIAMSigner(ctx context.Context, config *internal.AuthConfig) (*iamSigner,
if err != nil {
return nil, err
}
hc.Opts = []internal.HTTPOption{
internal.WithHeader("x-goog-api-client", internal.GetMetricsHeader(config.Version)),
}

return &iamSigner{
mutex: &sync.Mutex{},
Expand Down
13 changes: 11 additions & 2 deletions auth/token_generator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ func TestIAMSigner(t *testing.T) {
conf := &internal.AuthConfig{
Opts: optsWithTokenSource,
ServiceAccountID: "test-service-account",
Version: testVersion,
}
signer, err := newIAMSigner(ctx, conf)
if err != nil {
Expand Down Expand Up @@ -155,6 +156,7 @@ func TestIAMSignerHTTPError(t *testing.T) {
conf := &internal.AuthConfig{
Opts: optsWithTokenSource,
ServiceAccountID: "test-service-account",
Version: testVersion,
}
signer, err := newIAMSigner(context.Background(), conf)
if err != nil {
Expand Down Expand Up @@ -182,6 +184,7 @@ func TestIAMSignerUnknownHTTPError(t *testing.T) {
conf := &internal.AuthConfig{
Opts: optsWithTokenSource,
ServiceAccountID: "test-service-account",
Version: testVersion,
}
signer, err := newIAMSigner(context.Background(), conf)
if err != nil {
Expand All @@ -208,7 +211,8 @@ func TestIAMSignerUnknownHTTPError(t *testing.T) {
func TestIAMSignerWithMetadataService(t *testing.T) {
ctx := context.Background()
conf := &internal.AuthConfig{
Opts: optsWithTokenSource,
Opts: optsWithTokenSource,
Version: testVersion,
}

signer, err := newIAMSigner(ctx, conf)
Expand Down Expand Up @@ -253,7 +257,8 @@ func TestIAMSignerWithMetadataService(t *testing.T) {
func TestIAMSignerNoMetadataService(t *testing.T) {
ctx := context.Background()
conf := &internal.AuthConfig{
Opts: optsWithTokenSource,
Opts: optsWithTokenSource,
Version: testVersion,
}

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

w.Header().Set("Content-Type", "application/json")
b, err := json.Marshal(resp)
Expand Down
3 changes: 1 addition & 2 deletions auth/user_mgt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import (
"net/http"
"net/http/httptest"
"reflect"
"runtime"
"sort"
"strconv"
"strings"
Expand Down Expand Up @@ -2317,7 +2316,7 @@ func echoServer(resp interface{}, t *testing.T) *mockAuthServer {
}

gh = r.Header.Get("x-goog-api-client")
wh = fmt.Sprintf("gl-go/%s fire-admin/%s", strings.TrimPrefix(runtime.Version(), "go"), testVersion)
wh = internal.GetMetricsHeader(testVersion)
if gh != wh {
t.Errorf("x-goog-api-client header = %q; want: %q", gh, wh)
}
Expand Down
1 change: 1 addition & 0 deletions firebase.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ func (a *App) InstanceID(ctx context.Context) (*iid.Client, error) {
conf := &internal.InstanceIDConfig{
ProjectID: a.projectID,
Opts: a.opts,
Version: Version,
}
return iid.NewClient(ctx, conf)
}
Expand Down
3 changes: 3 additions & 0 deletions iid/iid.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,9 @@ func NewClient(ctx context.Context, c *internal.InstanceIDConfig) (*Client, erro
if err != nil {
return nil, err
}
hc.Opts = []internal.HTTPOption{
internal.WithHeader("x-goog-api-client", internal.GetMetricsHeader(c.Version)),
}

hc.CreateErrFn = createError
return &Client{
Expand Down
13 changes: 13 additions & 0 deletions iid/iid_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ var testIIDConfig = &internal.InstanceIDConfig{
Opts: []option.ClientOption{
option.WithTokenSource(&internal.MockTokenSource{AccessToken: "test-token"}),
},
Version: "test-version",
}

func TestNoProjectID(t *testing.T) {
Expand Down Expand Up @@ -83,6 +84,10 @@ func TestDeleteInstanceID(t *testing.T) {
if h := tr.Header.Get("Authorization"); h != "Bearer test-token" {
t.Errorf("Authorization = %q; want = %q", h, "Bearer test-token")
}
xGoogAPIClientHeader := internal.GetMetricsHeader(testIIDConfig.Version)
if h := tr.Header.Get("x-goog-api-client"); h != xGoogAPIClientHeader {
t.Errorf("x-goog-api-client header = %q; want = %q", h, xGoogAPIClientHeader)
}
}

func TestDeleteInstanceIDError(t *testing.T) {
Expand Down Expand Up @@ -156,6 +161,10 @@ func TestDeleteInstanceIDError(t *testing.T) {
if h := tr.Header.Get("Authorization"); h != "Bearer test-token" {
t.Errorf("Authorization = %q; want = %q", h, "Bearer test-token")
}
xGoogAPIClientHeader := internal.GetMetricsHeader(testIIDConfig.Version)
if h := tr.Header.Get("x-goog-api-client"); h != xGoogAPIClientHeader {
t.Errorf("x-goog-api-client header = %q; want = %q", h, xGoogAPIClientHeader)
}
tr = nil
}
}
Expand Down Expand Up @@ -201,6 +210,10 @@ func TestDeleteInstanceIDUnexpectedError(t *testing.T) {
if h := tr.Header.Get("Authorization"); h != "Bearer test-token" {
t.Errorf("Authorization = %q; want = %q", h, "Bearer test-token")
}
xGoogAPIClientHeader := internal.GetMetricsHeader(testIIDConfig.Version)
if h := tr.Header.Get("x-goog-api-client"); h != xGoogAPIClientHeader {
t.Errorf("x-goog-api-client header = %q; want = %q", h, xGoogAPIClientHeader)
}
}

func TestDeleteInstanceIDConnectionError(t *testing.T) {
Expand Down
8 changes: 8 additions & 0 deletions internal/http_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ import (
"io/ioutil"
"math"
"net/http"
"runtime"
"strconv"
"strings"
"time"

"google.golang.org/api/option"
Expand Down Expand Up @@ -441,3 +443,9 @@ func retryNetworkAndHTTPErrors(statusCodes ...int) RetryCondition {
return false
}
}

// GetMetricsHeader constructs header value for metrics attribution
func GetMetricsHeader(sdkVersion string) string {
goVersion := strings.TrimPrefix(runtime.Version(), "go")
return fmt.Sprintf("gl-go/%s fire-admin/%s", goVersion, sdkVersion)
}
1 change: 1 addition & 0 deletions internal/internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ type HashConfig map[string]interface{}
type InstanceIDConfig struct {
Opts []option.ClientOption
ProjectID string
Version string
}

// DatabaseConfig represents the configuration of Firebase Database service.
Expand Down
6 changes: 2 additions & 4 deletions messaging/messaging.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import (
"fmt"
"net/http"
"regexp"
"runtime"
"strconv"
"strings"
"time"
Expand Down Expand Up @@ -878,7 +877,7 @@ func NewClient(ctx context.Context, c *internal.MessagingConfig) (*Client, error

return &Client{
fcmClient: newFCMClient(hc, c, messagingEndpoint, batchEndpoint),
iidClient: newIIDClient(hc),
iidClient: newIIDClient(hc, c),
}, nil
}

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

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

return &fcmClient{
Expand Down
5 changes: 1 addition & 4 deletions messaging/messaging_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ import (
"net/http"
"net/http/httptest"
"reflect"
"runtime"
"strings"
"testing"
"time"

Expand Down Expand Up @@ -1396,8 +1394,7 @@ func checkFCMRequest(t *testing.T, b []byte, tr *http.Request, want map[string]i
if h := tr.Header.Get("X-FIREBASE-CLIENT"); h != clientVersion {
t.Errorf("X-FIREBASE-CLIENT = %q; want = %q", h, clientVersion)
}
goVersion := strings.TrimPrefix(runtime.Version(), "go")
xGoogAPIClientHeader := "gl-go/" + goVersion + " fire-admin/" + testMessagingConfig.Version
xGoogAPIClientHeader := internal.GetMetricsHeader(testMessagingConfig.Version)
if h := tr.Header.Get("x-goog-api-client"); h != xGoogAPIClientHeader {
t.Errorf("x-goog-api-client header = %q; want = %q", h, xGoogAPIClientHeader)
}
Expand Down
7 changes: 5 additions & 2 deletions messaging/topic_mgt.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,13 @@ type iidClient struct {
httpClient *internal.HTTPClient
}

func newIIDClient(hc *http.Client) *iidClient {
func newIIDClient(hc *http.Client, conf *internal.MessagingConfig) *iidClient {
client := internal.WithDefaultRetryConfig(hc)
client.CreateErrFn = handleIIDError
client.Opts = []internal.HTTPOption{internal.WithHeader("access_token_auth", "true")}
client.Opts = []internal.HTTPOption{
internal.WithHeader("access_token_auth", "true"),
internal.WithHeader("x-goog-api-client", internal.GetMetricsHeader(conf.Version)),
}
return &iidClient{
iidEndpoint: iidEndpoint,
httpClient: client,
Expand Down
5 changes: 5 additions & 0 deletions messaging/topic_mgt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"testing"

"firebase.google.com/go/v4/errorutils"
"firebase.google.com/go/v4/internal"
)

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

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

0 comments on commit 4ff0812

Please sign in to comment.