From 5a5ae0d95ce72e73d7d50a0ff4a23d82e74ab2fc Mon Sep 17 00:00:00 2001 From: Eshaan Negi <11eshaansinghnegi@gmail.com> Date: Thu, 26 Mar 2026 08:31:54 +0530 Subject: [PATCH 1/2] feat: add custom User-Agent header (goperf/) to identify load test traffic --- cmd/run.go | 1 + internal/httpclient/client.go | 3 +++ 2 files changed, 4 insertions(+) diff --git a/cmd/run.go b/cmd/run.go index 1447376..08ff28c 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -107,6 +107,7 @@ Latency Percentiles: u := config.ParsedTarget httpCfg := config.ToHTTPConfig() + httpCfg.Version = cmd.Root().Version if outputFormat != "json" { httpCfg.Stderr = cmd.ErrOrStderr() } diff --git a/internal/httpclient/client.go b/internal/httpclient/client.go index 53f853d..5a02c2d 100644 --- a/internal/httpclient/client.go +++ b/internal/httpclient/client.go @@ -35,6 +35,7 @@ type Config struct { Body string Headers []string Verbose bool + Version string Stderr io.Writer } @@ -67,6 +68,8 @@ func MakeRequest(ctx context.Context, client HTTPDoer, cfg Config) (statusCode i return 0, 0, err } + req.Header.Set("User-Agent", fmt.Sprintf("goperf/%s", cfg.Version)) + for _, h := range cfg.Headers { parts := strings.SplitN(h, ":", 2) if len(parts) == 2 { From 2b633ded45dab6abfa49c9bbe11ca5831408ccf0 Mon Sep 17 00:00:00 2001 From: Eshaan Negi <11eshaansinghnegi@gmail.com> Date: Thu, 26 Mar 2026 12:29:30 +0530 Subject: [PATCH 2/2] fix: prevent duplicate User-Agent header and respect override --- internal/httpclient/client.go | 6 ++-- internal/httpclient/client_test.go | 48 ++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/internal/httpclient/client.go b/internal/httpclient/client.go index 5a02c2d..c3e363a 100644 --- a/internal/httpclient/client.go +++ b/internal/httpclient/client.go @@ -68,8 +68,6 @@ func MakeRequest(ctx context.Context, client HTTPDoer, cfg Config) (statusCode i return 0, 0, err } - req.Header.Set("User-Agent", fmt.Sprintf("goperf/%s", cfg.Version)) - for _, h := range cfg.Headers { parts := strings.SplitN(h, ":", 2) if len(parts) == 2 { @@ -77,6 +75,10 @@ func MakeRequest(ctx context.Context, client HTTPDoer, cfg Config) (statusCode i } } + if req.Header.Get("User-Agent") == "" { + req.Header.Set("User-Agent", fmt.Sprintf("goperf/%s", cfg.Version)) + } + if cfg.Body != "" && req.Header.Get("Content-Type") == "" { req.Header.Set("Content-Type", "application/json") } diff --git a/internal/httpclient/client_test.go b/internal/httpclient/client_test.go index 104b84d..caf95ab 100644 --- a/internal/httpclient/client_test.go +++ b/internal/httpclient/client_test.go @@ -57,6 +57,54 @@ func TestMakeRequestSuccess(t *testing.T) { } } +func TestMakeRequest_DefaultUserAgent(t *testing.T) { + var gotUA string + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + gotUA = r.Header.Get("User-Agent") + w.WriteHeader(http.StatusOK) + })) + defer server.Close() + + _, _, err := MakeRequest(context.Background(), &http.Client{}, Config{ + Target: server.URL, + Timeout: testTimeout, + Method: "GET", + Version: "1.2.3", + }) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + if gotUA != "goperf/1.2.3" { + t.Errorf("expected User-Agent 'goperf/1.2.3', got %q", gotUA) + } +} + +func TestMakeRequest_UserAgentOverride(t *testing.T) { + var gotUAValues []string + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + gotUAValues = r.Header.Values("User-Agent") + w.WriteHeader(http.StatusOK) + })) + defer server.Close() + + _, _, err := MakeRequest(context.Background(), &http.Client{}, Config{ + Target: server.URL, + Timeout: testTimeout, + Method: "GET", + Version: "1.2.3", + Headers: []string{"User-Agent: custom-agent/9.9"}, + }) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + if len(gotUAValues) != 1 { + t.Errorf("expected exactly 1 User-Agent value (no duplicates), got %v", gotUAValues) + } + if gotUAValues[0] != "custom-agent/9.9" { + t.Errorf("expected User-Agent 'custom-agent/9.9', got %q", gotUAValues[0]) + } +} + func TestMakeRequest_Errors(t *testing.T) { tests := []struct { name string