cmd/trace: listen on localhost when address omitted

Today `-http=:6060` listens on all addresses. Strictly speaking, that is
what `:6060` implies, but most users actually only care to access from
their own machine.

cmd/pprof listens only on localhost when given such an address.
Change cmd/trace to match this behavior since it is a safer default and
makes cmd/trace more consistent with our other tools.

Users that actually want to listen on all addresses can explicitly
include the unspecified address (e.g., `-http=0.0.0.0:6060`).

For #78921.

Change-Id: I47e1fbbdd5374abfeeec10916eb9d2136a6a6964
Reviewed-on: https://go-review.googlesource.com/c/go/+/770461
Reviewed-by: Damien Neil <dneil@google.com>
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Michael Pratt <mpratt@google.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
This commit is contained in:
Michael Pratt 2026-04-24 09:26:02 -04:00 committed by Gopher Robot
parent 82885449f7
commit 02d136966c
3 changed files with 96 additions and 5 deletions

View file

@ -20,3 +20,10 @@ It will no longer be able to directly fetch modules hosted on bzr servers.
### Cgo {#cgo}
### Trace
<!-- go.dev/issue/78921 -->
`go tool trace`'s `-http` argument now restricts the listen address to localhost when passed only a port (e.g., `-http=:6060`).
This change makes `go tool trace` consistent with the behavior of `go tool pprof`'s `-http` flag.
To listen on all addresses, explicitly include the specified address (e.g., `-http=0.0.0.0:6060`).

View file

@ -47,10 +47,13 @@ Supported profile types are:
- sched: scheduler latency profile
Flags:
-http=addr: HTTP service address (e.g., ':6060')
-http=addr: HTTP server listen address (e.g., ':6060')
-pprof=type: print a pprof-like profile instead
-d=mode: print debug info and exit (modes: wire, parsed, footprint)
When providing only a port to -http (e.g., ':6060'), the tool listens only on localhost.
To listen on all addresses, explicitly add the unspecified address (e.g., '0.0.0.0:6060').
Note that while the various profiles available when launching
'go tool trace' work on every browser, the trace viewer itself
(the 'view trace' page) comes from the Chrome/Chromium project
@ -58,7 +61,7 @@ and is only actively tested on that browser.
`
var (
httpFlag = flag.String("http", "localhost:0", "HTTP service address (e.g., ':6060')")
httpFlag = flag.String("http", "localhost:0", "HTTP server listen address (e.g., ':6060')")
pprofFlag = flag.String("pprof", "", "print a pprof-like profile instead")
debugFlag = flag.String("d", "", "print debug info and exit (modes: wire, parsed, footprint)")
@ -145,11 +148,16 @@ func main() {
}
}
ln, err := net.Listen("tcp", *httpFlag)
addr, err := listenAddr(*httpFlag)
if err != nil {
logAndDie(fmt.Errorf("malformed -http value %q: %v", *httpFlag, err))
}
ln, err := net.Listen("tcp", addr)
if err != nil {
logAndDie(fmt.Errorf("failed to create server socket: %w", err))
}
addr := "http://" + ln.Addr().String()
url := "http://" + ln.Addr().String()
log.Print("Preparing trace for viewer...")
parsed, err := parseTraceInteractive(tracef, traceSize)
@ -175,7 +183,7 @@ func main() {
logAndDie(err)
}
log.Printf("Opening browser. Trace viewer is listening on %s", addr)
log.Printf("Opening browser. Trace viewer is listening on %s", url)
browser.Open(addr)
mutatorUtil := func(flags trace.UtilFlags) ([][]trace.MutatorUtil, error) {
@ -237,6 +245,22 @@ func logAndDie(err error) {
os.Exit(1)
}
// listenAddr returns the address to listen on given the addr address flag.
//
// If addr does not specify a host (e.g., ":8080"), then default to listening
// only on localhost rather than all addresses. To listen on all addresses,
// explicitly set the unspecified address (e.g., "0.0.0.0:8080").
func listenAddr(addr string) (string, error) {
host, port, err := net.SplitHostPort(addr)
if err != nil {
return "", err
}
if host == "" {
host = "localhost"
}
return net.JoinHostPort(host, port), nil
}
func parseTraceInteractive(tr io.Reader, size int64) (parsed *parsedTrace, err error) {
done := make(chan struct{})
cr := countingReader{r: tr}

View file

@ -0,0 +1,60 @@
// Copyright 2026 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import "testing"
func TestListenAddr(t *testing.T) {
tests := []struct {
name string
addr string
wantAddr string
wantErr bool
}{
{
name: "empty host",
addr: ":8080",
wantAddr: "localhost:8080",
},
{
name: "with host",
addr: "localhost:8080",
wantAddr: "localhost:8080",
},
{
name: "with IP",
addr: "127.0.0.1:8080",
wantAddr: "127.0.0.1:8080",
},
{
name: "unspecified host",
addr: "0.0.0.0:8080",
wantAddr: "0.0.0.0:8080",
},
{
name: "host only",
addr: "127.0.0.1",
wantErr: true,
},
{
name: "port only",
addr: "8080",
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := listenAddr(tt.addr)
if tt.wantErr && err == nil {
t.Errorf("listenAddr(%q) got nil err want non-nil", tt.addr)
} else if !tt.wantErr && err != nil {
t.Errorf("listenAddr(%q) got err %v want nil", tt.addr, err)
} else if got != tt.wantAddr {
t.Errorf("listenAddr(%q) = %q, want %q", tt.addr, got, tt.wantAddr)
}
})
}
}