chore: set User-Agent on all outgoing HTTP requests (#10867)

It's only polite, and it enables better troubleshooting in situations
like weird-ass requests to the upgrades download service.

---------

Signed-off-by: Jakob Borg <jakob@kastelo.net>
This commit is contained in:
Jakob Borg
2026-08-24 18:26:23 +00:00
committed by GitHub
parent e009ec07ff
commit 9af3c75f37
11 changed files with 31 additions and 8 deletions
+1 -1
View File
@@ -224,7 +224,7 @@ func filterForLatest(rels []upgrade.Release) []upgrade.Release {
return filtered
}
var userAgentOSArchExp = regexp.MustCompile(`^syncthing.*\(.+ (\w+)-(\w+)\)$`)
var userAgentOSArchExp = regexp.MustCompile(`^[Ss]yncthing.*\(.+ (\w+)-(\w+)\)$`)
func filterForCompatibility(rels []upgrade.Release, ua, osv string) []upgrade.Release {
osArch := userAgentOSArchExp.FindStringSubmatch(ua)
+2
View File
@@ -18,6 +18,7 @@ import (
"net/http"
"strings"
"github.com/syncthing/syncthing/lib/build"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/events"
"github.com/syncthing/syncthing/lib/locations"
@@ -115,6 +116,7 @@ func (c *apiClient) Endpoint() string {
func (c *apiClient) Do(req *http.Request) (*http.Response, error) {
req.Header.Set("X-Api-Key", c.apikey)
req.Header.Set("User-Agent", build.UserAgent())
resp, err := c.Client.Do(req)
if err != nil {
return nil, err
+3
View File
@@ -20,6 +20,7 @@ import (
"time"
"github.com/syncthing/syncthing/internal/slogutil"
"github.com/syncthing/syncthing/lib/build"
)
const (
@@ -81,6 +82,7 @@ func uploadPanicLog(ctx context.Context, urlBase, file string) error {
if err != nil {
return err
}
headReq.Header.Set("User-Agent", build.UserAgent())
// Set a reasonable timeout on the HEAD request
headCtx, headCancel := context.WithTimeout(ctx, headRequestTimeout)
@@ -101,6 +103,7 @@ func uploadPanicLog(ctx context.Context, urlBase, file string) error {
if err != nil {
return err
}
putReq.Header.Set("User-Agent", build.UserAgent())
// Set a reasonable timeout on the PUT request
putCtx, putCancel := context.WithTimeout(ctx, putRequestTimeout)
+2
View File
@@ -374,6 +374,7 @@ func upgradeViaRest() error {
target := u.String()
r, _ := http.NewRequest(http.MethodPost, target, nil)
r.Header.Set("X-Api-Key", cfg.GUI().APIKey)
r.Header.Set("User-Agent", build.UserAgent())
tr := &http.Transport{
DialContext: dialer.DialContext,
@@ -955,6 +956,7 @@ func (c browserCmd) Run() error {
if err != nil {
return err
}
req.Header.Set("User-Agent", build.UserAgent())
_, err = http.DefaultClient.Do(req) //nolint:bodyclose // we're exiting in a millisecond
if err != nil {
slog.Error("GUI not available", slogutil.Error(err))
+4
View File
@@ -127,6 +127,10 @@ func LongVersionFor(program string) string {
return v
}
func UserAgent() string {
return fmt.Sprintf(`Syncthing/%s (%s %s-%s)`, strings.TrimPrefix(Version, "v"), runtime.Version(), runtime.GOOS, runtime.GOARCH)
}
func TagsList() []string {
tags := strings.Split(Tags, ",")
if len(tags) == 1 && tags[0] == "" {
+3
View File
@@ -25,6 +25,7 @@ import (
"golang.org/x/net/http2"
"github.com/syncthing/syncthing/internal/slogutil"
"github.com/syncthing/syncthing/lib/build"
"github.com/syncthing/syncthing/lib/connections/registry"
"github.com/syncthing/syncthing/lib/dialer"
"github.com/syncthing/syncthing/lib/events"
@@ -454,6 +455,7 @@ func (c *contextClient) Get(ctx context.Context, url string) (*http.Response, er
if err != nil {
return nil, err
}
req.Header.Set("User-Agent", build.UserAgent())
return c.Client.Do(req)
}
@@ -463,6 +465,7 @@ func (c *contextClient) Post(ctx context.Context, url, ctype string, data io.Rea
return nil, err
}
req.Header.Set("Content-Type", ctype)
req.Header.Set("User-Agent", build.UserAgent())
return c.Client.Do(req)
}
+2
View File
@@ -14,6 +14,7 @@ import (
"sync"
"time"
"github.com/syncthing/syncthing/lib/build"
"github.com/syncthing/syncthing/lib/osutil"
"github.com/syncthing/syncthing/lib/rand"
"github.com/syncthing/syncthing/lib/relay/protocol"
@@ -53,6 +54,7 @@ func (c *dynamicClient) serve(ctx context.Context) error {
l.Debugln(c, "failed to lookup dynamic relays", err)
return err
}
req.Header.Set("User-Agent", build.UserAgent())
data, err := http.DefaultClient.Do(req)
if err != nil {
l.Debugln(c, "failed to lookup dynamic relays", err)
+5 -5
View File
@@ -15,20 +15,19 @@ import (
"compress/gzip"
"encoding/json"
"errors"
"fmt"
"io"
"log/slog"
"net/http"
"os"
"path"
"path/filepath"
"runtime"
"sort"
"strings"
"time"
"github.com/shirou/gopsutil/v4/host"
"github.com/syncthing/syncthing/internal/slogutil"
"github.com/syncthing/syncthing/lib/build"
"github.com/syncthing/syncthing/lib/dialer"
"github.com/syncthing/syncthing/lib/signature"
"github.com/syncthing/syncthing/lib/tlsutil"
@@ -79,13 +78,13 @@ func init() {
osVersion = strings.TrimSpace(osVersion)
}
func upgradeClientGet(url, version string) (*http.Response, error) {
func upgradeClientGet(url string) (*http.Response, error) {
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return nil, err
}
req.Header.Set("User-Agent", fmt.Sprintf(`syncthing %s (%s %s-%s)`, version, runtime.Version(), runtime.GOOS, runtime.GOARCH))
req.Header.Set("User-Agent", build.UserAgent())
if osVersion != "" {
req.Header.Set("Syncthing-Os-Version", osVersion)
}
@@ -95,7 +94,7 @@ func upgradeClientGet(url, version string) (*http.Response, error) {
// FetchLatestReleases returns the latest releases. The "current" parameter
// is used for setting the User-Agent only.
func FetchLatestReleases(releasesURL, current string) []Release {
resp, err := upgradeClientGet(releasesURL, current)
resp, err := upgradeClientGet(releasesURL)
if err != nil {
slog.Warn("Failed to fetch latest release information", slogutil.Error(err))
return nil
@@ -227,6 +226,7 @@ func readRelease(archiveName, dir, url string) (string, error) {
}
req.Header.Add("Accept", "application/octet-stream")
req.Header.Set("User-Agent", build.UserAgent())
resp, err := upgradeClient.Do(req)
if err != nil {
return "", err
+7 -2
View File
@@ -337,7 +337,12 @@ func parseResponse(ctx context.Context, deviceType string, addr *net.UDPAddr, re
}
deviceUUID := strings.TrimPrefix(strings.Split(deviceUSN, "::")[0], "uuid:")
response, err = http.Get(deviceDescriptionLocation)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, deviceDescriptionLocation, nil)
if err != nil {
return nil, err
}
req.Header.Set("User-Agent", build.UserAgent())
response, err = http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
@@ -582,7 +587,7 @@ func soapRequestWithIP(ctx context.Context, url, service, function, message stri
}
req.Close = true
req.Header.Set("Content-Type", `text/xml; charset="utf-8"`)
req.Header.Set("User-Agent", "syncthing/1.0")
req.Header.Set("User-Agent", build.UserAgent())
req.Header["SOAPAction"] = []string{fmt.Sprintf(`"%s#%s"`, service, function)} // Enforce capitalization in header-entry for sensitive routers. See issue #1696
req.Header.Set("Connection", "Close")
req.Header.Set("Cache-Control", "no-cache")
+1
View File
@@ -214,6 +214,7 @@ func sendFailureReports(ctx context.Context, reports []contract.FailureReport, u
return
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("User-Agent", build.UserAgent())
resp, err := client.Do(req)
if err != nil {
+1
View File
@@ -373,6 +373,7 @@ func (s *Service) sendUsageReport(ctx context.Context) error {
return err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("User-Agent", build.UserAgent())
resp, err := client.Do(req)
if err != nil {
return err