1// Package httpheaders provides shared User-Agent resolution for all HTTP-based providers.
2package httpheaders
3
4import (
5 "fmt"
6 "strings"
7)
8
9// DefaultUserAgent returns the default User-Agent string for the SDK.
10// The result is "Charm Fantasy/<version>".
11func DefaultUserAgent(version string) string {
12 return fmt.Sprintf("Charm-Fantasy/%s (https://charm.land/fantasy)", version)
13}
14
15// ResolveHeaders returns a new header map, with a User-Agent field.
16//
17// Setting the value via WithUserAgent() takes precedence, however the user
18// agent can also be set via HTTP headers (i.e. WithHeaders()). Otherwise, the
19// default user agent will be used, i.e. Charm Fantasy/0.11.0.
20//
21// Also note that the input map is never mutated.
22func ResolveHeaders(headers map[string]string, explicitUA, defaultUA string) map[string]string {
23 out := make(map[string]string, len(headers)+1)
24 var uaKeys []string
25
26 for k, v := range headers {
27 out[k] = v
28 if strings.EqualFold(k, "User-Agent") {
29 uaKeys = append(uaKeys, k)
30 }
31 }
32
33 switch {
34 case explicitUA != "":
35 for _, k := range uaKeys {
36 delete(out, k)
37 }
38 out["User-Agent"] = explicitUA
39 case len(uaKeys) > 0:
40 val := out[uaKeys[0]]
41 for _, k := range uaKeys {
42 delete(out, k)
43 }
44 out["User-Agent"] = val
45 default:
46 out["User-Agent"] = defaultUA
47 }
48
49 return out
50}
51
52// CallUserAgent resolves the User-Agent for a single API call. It returns the
53// resolved UA string and true if a per-call override should be applied, or
54// empty string and false if the client-level UA should be used as-is.
55func CallUserAgent(callUA string) (string, bool) {
56 if callUA != "" {
57 return callUA, true
58 }
59 return "", false
60}