Skip to content

Commit c827ea7

Browse files
committed
Add User-Agent header derived from Go BuildInfo
1 parent 815637d commit c827ea7

5 files changed

Lines changed: 69 additions & 3 deletions

File tree

go/auth.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,8 @@ func generateAuthHeaders(h http.Header, method string, path string, body []byte,
3030
h.Add(authzTSHeader, strconv.FormatInt(timestamp, 10))
3131
h.Add(authzSigHeader, hmacString)
3232
}
33+
34+
func setRequestHeaders(h http.Header, method string, path string, body []byte, clientId string, userSecret string, timestamp int64) {
35+
h.Set("User-Agent", userAgent())
36+
generateAuthHeaders(h, method, path, body, clientId, userSecret, timestamp)
37+
}

go/client.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ func (c *client) rest(ctx context.Context, d *request, dst interface{}) (err err
285285
return err
286286
}
287287

288-
generateAuthHeaders(req.Header, req.Method, reqURL.RequestURI(), d.body,
288+
setRequestHeaders(req.Header, req.Method, reqURL.RequestURI(), d.body,
289289
c.config.ApiKey, c.config.ApiSecret, time.Now().UnixMilli())
290290

291291
if value := ctx.Value(CustomHeadersCtxKey); value != nil {
@@ -357,7 +357,7 @@ func (c *client) serverHeaders(ctx context.Context, u *url.URL) (h http.Header,
357357
return nil, err
358358
}
359359

360-
generateAuthHeaders(req.Header, req.Method, reqURL.RequestURI(), nil,
360+
setRequestHeaders(req.Header, req.Method, reqURL.RequestURI(), nil,
361361
c.config.ApiKey, c.config.ApiSecret, time.Now().UnixMilli())
362362

363363
c.config.logDebug(

go/client_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"net/http/httptest"
99
"reflect"
1010
"strconv"
11+
"strings"
1112
"testing"
1213

1314
"github.com/ethereum/go-ethereum/common/hexutil"
@@ -466,6 +467,37 @@ func Test_extractOrigins(t *testing.T) {
466467
}
467468
}
468469

470+
func TestUserAgent(t *testing.T) {
471+
ua := userAgent()
472+
t.Logf("User-Agent: %s", ua)
473+
if ua == "" {
474+
t.Fatal("userAgent() returned empty string")
475+
}
476+
if !strings.HasPrefix(ua, "data-streams-sdk-go/") {
477+
t.Errorf("userAgent() = %q, want prefix %q", ua, "data-streams-sdk-go/")
478+
}
479+
}
480+
481+
func TestUserAgentSentInRequests(t *testing.T) {
482+
ms := newMockServer(func(w http.ResponseWriter, r *http.Request) {
483+
got := r.Header.Get("User-Agent")
484+
if !strings.HasPrefix(got, "data-streams-sdk-go/") {
485+
t.Errorf("User-Agent header = %q, want prefix %q", got, "data-streams-sdk-go/")
486+
}
487+
w.Header().Set("Content-Type", "application/json")
488+
json.NewEncoder(w).Encode(feedsResponse{Feeds: []*feed.Feed{}}) //nolint:errcheck
489+
})
490+
defer ms.Close()
491+
492+
client, err := ms.Client()
493+
if err != nil {
494+
t.Fatalf("error creating client: %s", err)
495+
}
496+
497+
_, _ = client.GetFeeds(context.Background())
498+
}
499+
500+
469501
type mockServer struct {
470502
server *httptest.Server
471503
}

go/stream.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,7 @@ func (s *stream) newWSconn(ctx context.Context, origin string) (ws *wsConn, err
424424
reqURL.RawQuery = url.Values{"feedIDs": {strings.Join(feedIdsToStringList(s.feedIDs), ",")}}.Encode()
425425

426426
headers := http.Header{}
427-
generateAuthHeaders(headers, http.MethodGet, reqURL.RequestURI(), nil,
427+
setRequestHeaders(headers, http.MethodGet, reqURL.RequestURI(), nil,
428428
s.config.ApiKey, s.config.ApiSecret, time.Now().UnixMilli())
429429

430430
if origin != "" {

go/version.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package streams
2+
3+
import (
4+
"runtime/debug"
5+
"strings"
6+
"sync"
7+
)
8+
9+
const modulePath = "github.com/smartcontractkit/data-streams-sdk/go"
10+
11+
func matchesModule(path string) bool {
12+
return path == modulePath || strings.HasPrefix(path, modulePath+"/v")
13+
}
14+
15+
// userAgent returns this Go SDK version and is appended to the User-Agent header for all requests.
16+
// this is wrapped in sync.OnceValue to avoid repeated expensive calls to debug.ReadBuildInfo.
17+
var userAgent = sync.OnceValue(func() string {
18+
version := "unknown"
19+
bi, ok := debug.ReadBuildInfo()
20+
if ok {
21+
for _, dep := range bi.Deps {
22+
if matchesModule(dep.Path) {
23+
version = dep.Version
24+
break
25+
}
26+
}
27+
}
28+
return "data-streams-sdk-go/" + version
29+
})

0 commit comments

Comments
 (0)