tsnet: fix bug in app capabilities forwarding

Signed-off-by: Harry Harpham <harry@tailscale.com>
hwh33/tsnet-services-support
Harry Harpham 3 weeks ago
parent 2c2b2f8cf9
commit 0d16a0bf32
No known key found for this signature in database

@ -1272,7 +1272,7 @@ func ServiceOptionAppCapabilities(capabilities ...string) ServiceOption {
return ServiceOptionAppCapabilitiesForPath("/", capabilities...)
}
// TODO: doc
// TODO: doc; include info on this overriding handlers at earlier paths
func ServiceOptionAppCapabilitiesForPath(path string, capabilities ...string) ServiceOption {
return serviceOptionAppCapabilities{path, capabilities}
}
@ -1384,8 +1384,10 @@ func (s *Server) ListenService(name string, port uint16, opts ...ServiceOption)
useTLS := false // TODO: set correctly
mds := st.CurrentTailnet.MagicDNSSuffix
setHandler := func(h ipn.HTTPHandler, path string) {
// TODO: do we need to add the path to the end of the proxy value?
h.Proxy = ln.Addr().String()
if path != "/" {
h.Proxy += path
}
srvConfig.SetWebHandler(&h, svcName, port, path, useTLS, mds)
}
// Set a web handler for every mount point in the caps map. If we don't

@ -802,7 +802,7 @@ func TestListenService(t *testing.T) {
}
}))
}
assertEchoHTTP := func(t *testing.T, hostname string, dial dialFn) {
assertEchoHTTP := func(t *testing.T, hostname, path string, dial dialFn) {
t.Helper()
c := http.Client{
Transport: &http.Transport{
@ -810,7 +810,7 @@ func TestListenService(t *testing.T) {
},
}
msg := "echo"
resp, err := c.Post("http://"+hostname, "text/plain", strings.NewReader(msg))
resp, err := c.Post("http://"+hostname+path, "text/plain", strings.NewReader(msg))
if err != nil {
t.Fatal("posting request:", err)
}
@ -877,20 +877,26 @@ func TestListenService(t *testing.T) {
t.Error("did not see expected header:", expectHeader)
}
})
assertEchoHTTP(t, serviceFQDN, peer.Dial)
assertEchoHTTP(t, serviceFQDN, "", peer.Dial)
},
},
{
name: "app_capabilities",
opts: []ServiceOption{ServiceOptionAppCapabilities("example.com/cap/want")},
opts: []ServiceOption{
ServiceOptionAppCapabilities("example.com/cap/all-paths"),
ServiceOptionAppCapabilitiesForPath("/foo", "example.com/cap/all-paths", "example.com/cap/foo"),
},
port: 80,
extraSetup: func(t *testing.T, serviceHost, peer *Server, control *testcontrol.Server) {
control.SetGlobalAppCaps(tailcfg.PeerCapMap{
"example.com/cap/want": []tailcfg.RawMessage{`true`},
"example.com/cap/all-paths": []tailcfg.RawMessage{`true`},
"example.com/cap/foo": []tailcfg.RawMessage{`true`},
})
},
run: func(t *testing.T, serviceListener net.Listener, peer *Server, serviceFQDN string) {
go checkAndEcho(t, serviceListener, func(r *http.Request) {
allPathsCap := "example.com/cap/all-paths"
fooCap := "example.com/cap/foo"
checkCaps := func(r *http.Request) {
rawCaps, ok := r.Header["Tailscale-App-Capabilities"]
if !ok {
t.Error("no app capabilities header")
@ -905,11 +911,24 @@ func TestListenService(t *testing.T) {
t.Error("error unmarshaling app caps:", err)
return
}
if _, ok := caps["example.com/cap/want"]; !ok {
t.Errorf("got app caps, but expected cap is not present; saw:\n%v", caps)
if _, ok := caps[allPathsCap]; !ok {
t.Errorf("got app caps, but %v is not present; saw:\n%v", allPathsCap, caps)
}
})
assertEchoHTTP(t, serviceFQDN, peer.Dial)
if strings.HasPrefix(r.URL.Path, "/foo") {
if _, ok := caps[fooCap]; !ok {
t.Errorf("%v should be present for /foo request; saw:\n%v", fooCap, caps)
}
} else {
if _, ok := caps[fooCap]; ok {
t.Errorf("%v should not be present for non-/foo request; saw:\n%v", fooCap, caps)
}
}
}
go checkAndEcho(t, serviceListener, checkCaps)
assertEchoHTTP(t, serviceFQDN, "", peer.Dial)
assertEchoHTTP(t, serviceFQDN, "/foo", peer.Dial)
assertEchoHTTP(t, serviceFQDN, "/foo/bar", peer.Dial)
},
},
// TODO:

Loading…
Cancel
Save