Show the IP information API on the home page (closes #156)
check / check (push) Canceled after 0s
check / check (push) Canceled after 0s
The home page gets an IP information API card. It shows the curl
command that looks up the visitor's own address at /ip/{addr}. The page
then makes that same request and shows the JSON answer, pretty-printed.
An error answer, such as a 404 for an address with no route, is shown
the same way. A request that fails shows an error line.
The server gives the page the visitor's address, found as /ip/ finds
it, so a trusted proxy's X-Forwarded-For is honoured. The command takes
its origin from the browser, so it names the host the visitor used.
Model: opus-5-5
This commit was merged in pull request #183.
This commit is contained in:
@@ -7,6 +7,7 @@ import (
|
||||
"html"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/netip"
|
||||
"runtime"
|
||||
"slices"
|
||||
"strconv"
|
||||
@@ -503,6 +504,64 @@ func TestPagesSayOriginZeroIsNoKnownOrigin(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestIndexShowsTheClientAddress requests the home page and checks that it has
|
||||
// the IP information API card, holding the address /ip/ would look up for the
|
||||
// same request: the TCP peer, or, when the peer is a trusted proxy, the client
|
||||
// the proxy names in X-Forwarded-For
|
||||
// (https://git.eeqj.de/sneak/routewatch/issues/156).
|
||||
func TestIndexShowsTheClientAddress(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const cardHeading = "<h2>IP Information API</h2>"
|
||||
|
||||
// Both requests carry an X-Forwarded-For naming forwardedClient; only a
|
||||
// trusted proxy's is believed.
|
||||
tests := []struct {
|
||||
name string
|
||||
trustedProxies []netip.Prefix
|
||||
peer string
|
||||
want string
|
||||
}{
|
||||
{"direct request", nil, untrustedPeer, untrustedPeerAddr},
|
||||
{
|
||||
"request through a trusted proxy",
|
||||
[]netip.Prefix{netip.MustParsePrefix(trustedProxyRange)},
|
||||
trustedPeer, forwardedClient,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
// The home page reads nothing from the database, so the server has none.
|
||||
s := New(nil, streamer.New(logger.New(), metrics.New()), logger.New(),
|
||||
&config.Config{TrustedProxies: tt.trustedProxies})
|
||||
|
||||
req := httptest.NewRequestWithContext(t.Context(), http.MethodGet, "/", nil)
|
||||
req.RemoteAddr = tt.peer
|
||||
req.Header.Set("X-Forwarded-For", forwardedClient)
|
||||
|
||||
rec := httptest.NewRecorder()
|
||||
s.router.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Errorf("%s: status %d, want %d; body %s",
|
||||
tt.name, rec.Code, http.StatusOK, rec.Body)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
page := rec.Body.String()
|
||||
|
||||
if !strings.Contains(page, cardHeading) {
|
||||
t.Errorf("%s: the page has no IP information API card", tt.name)
|
||||
}
|
||||
|
||||
want := `data-client-ip="` + tt.want + `"`
|
||||
if !strings.Contains(page, want) {
|
||||
t.Errorf("%s: the card does not hold %s", tt.name, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestPagesShowAgesInWords stores routes last updated about 5 minutes, 3 hours
|
||||
// and 15 days ago, and checks that the AS page and the prefix pages show each
|
||||
// age in words. Before the fix the ages read "5m0s ago", "3h0m0s ago" and
|
||||
|
||||
Reference in New Issue
Block a user