From 83ce925a26e4f5b833fbf1276ece78dab6624d14 Mon Sep 17 00:00:00 2001 From: Seth Hoenig Date: Mon, 2 Mar 2026 12:40:08 -0600 Subject: [PATCH] useragent: include function for getting the real upstream requester --- README.md | 12 ++++++++++++ useragent.go | 13 +++++++++++-- useragent_test.go | 25 ++++++++++++++++++++++++- 3 files changed, 47 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b659071..5cd736d 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,18 @@ u := webtools.CreateURL("example.org", "/some/path", map[string]string { }) ``` +There is also the `Origins` convenience function for parsing the user-agent +of an `http.Request` and creating a struct of interesting values regarding the +request. + +```go +ua := webtools.Origins(r) + +fmt.Println(ua.String()) # e.g. curl/unknown +fmt.Println(ua.Anchor()) # e.g. example.org/path/to/page +fmt.Println(ua.From()) # e.g. 10.0.0.1 +``` + #### package webtools/middles Provides a generic sessions `http.Handler` which can be used to set and validate diff --git a/useragent.go b/useragent.go index 10031de..8424afd 100644 --- a/useragent.go +++ b/useragent.go @@ -17,9 +17,18 @@ type Origin struct { UserAgent useragent.UserAgent } -// From returns a parsed version of the Referer headers, including the domain -// and path without the protocol or query. +// From returns the value of the X-Forwarded-For if set, otherwise defaulting +// to the Host header. func (o *Origin) From() string { + if o.Forward != "" { + return o.Forward + } + return o.Host +} + +// Anchor returns a parsed version of the Referer headers, including the domain +// and path without the protocol or query. +func (o *Origin) Anchor() string { if o.Reference == "" { return "-" } diff --git a/useragent_test.go b/useragent_test.go index 5c57607..8fdca73 100644 --- a/useragent_test.go +++ b/useragent_test.go @@ -12,6 +12,29 @@ import ( func TestOrigin_From(t *testing.T) { t.Parallel() + t.Run("forward set", func(t *testing.T) { + o := &Origin{ + Host: "10.0.0.1", + Forward: "example.com", + } + + s := o.From() + must.Eq(t, "example.com", s) + }) + + t.Run("not set", func(t *testing.T) { + o := &Origin{ + Host: "10.0.0.1", + } + + s := o.From() + must.Eq(t, "10.0.0.1", s) + }) +} + +func TestOrigin_Anchor(t *testing.T) { + t.Parallel() + cases := []struct { name string reference string @@ -26,7 +49,7 @@ func TestOrigin_From(t *testing.T) { for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { o := &Origin{Reference: tc.reference} - must.Eq(t, tc.exp, o.From()) + must.Eq(t, tc.exp, o.Anchor()) }) } }