mirror of
https://github.com/tailscale/tailscale.git
synced 2025-05-06 15:46:53 +00:00
ipn/localapi: put all the LocalAPI methods into a map
Rather than a bunch of switch cases. Change-Id: Id1db813ec255bfab59cbc982bee351eb36373245 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
parent
f172fc42f7
commit
b2994568fe
@ -37,9 +37,49 @@ import (
|
|||||||
"tailscale.com/types/logger"
|
"tailscale.com/types/logger"
|
||||||
"tailscale.com/util/clientmetric"
|
"tailscale.com/util/clientmetric"
|
||||||
"tailscale.com/util/mak"
|
"tailscale.com/util/mak"
|
||||||
|
"tailscale.com/util/strs"
|
||||||
"tailscale.com/version"
|
"tailscale.com/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type localAPIHandler func(*Handler, http.ResponseWriter, *http.Request)
|
||||||
|
|
||||||
|
// handler is the set of LocalAPI handlers, keyed by the part of the
|
||||||
|
// Request.URL.Path after "/localapi/v0/". If the key ends with a trailing slash
|
||||||
|
// then it's a prefix match.
|
||||||
|
var handler = map[string]localAPIHandler{
|
||||||
|
// The prefix match handlers end with a slash:
|
||||||
|
"cert/": (*Handler).serveCert,
|
||||||
|
"file-put/": (*Handler).serveFilePut,
|
||||||
|
"files/": (*Handler).serveFiles,
|
||||||
|
|
||||||
|
// The other /localapi/v0/NAME handlers are exact matches and contain only NAME
|
||||||
|
// without a trailing slash:
|
||||||
|
"bugreport": (*Handler).serveBugReport,
|
||||||
|
"check-ip-forwarding": (*Handler).serveCheckIPForwarding,
|
||||||
|
"check-prefs": (*Handler).serveCheckPrefs,
|
||||||
|
"component-debug-logging": (*Handler).serveComponentDebugLogging,
|
||||||
|
"debug": (*Handler).serveDebug,
|
||||||
|
"derpmap": (*Handler).serveDERPMap,
|
||||||
|
"dial": (*Handler).serveDial,
|
||||||
|
"file-targets": (*Handler).serveFileTargets,
|
||||||
|
"goroutines": (*Handler).serveGoroutines,
|
||||||
|
"id-token": (*Handler).serveIDToken,
|
||||||
|
"login-interactive": (*Handler).serveLoginInteractive,
|
||||||
|
"logout": (*Handler).serveLogout,
|
||||||
|
"metrics": (*Handler).serveMetrics,
|
||||||
|
"ping": (*Handler).servePing,
|
||||||
|
"prefs": (*Handler).servePrefs,
|
||||||
|
"profile": (*Handler).serveProfile,
|
||||||
|
"set-dns": (*Handler).serveSetDNS,
|
||||||
|
"set-expiry-sooner": (*Handler).serveSetExpirySooner,
|
||||||
|
"status": (*Handler).serveStatus,
|
||||||
|
"tka/init": (*Handler).serveTKAInit,
|
||||||
|
"tka/modify": (*Handler).serveTKAModify,
|
||||||
|
"tka/status": (*Handler).serveTKAStatus,
|
||||||
|
"upload-client-metrics": (*Handler).serveUploadClientMetrics,
|
||||||
|
"whois": (*Handler).serveWhoIs,
|
||||||
|
}
|
||||||
|
|
||||||
func randHex(n int) string {
|
func randHex(n int) string {
|
||||||
b := make([]byte, n)
|
b := make([]byte, n)
|
||||||
rand.Read(b)
|
rand.Read(b)
|
||||||
@ -101,72 +141,45 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(r.URL.Path, "/localapi/v0/files/") {
|
if fn, ok := handlerForPath(r.URL.Path); ok {
|
||||||
h.serveFiles(w, r)
|
fn(h, w, r)
|
||||||
return
|
} else {
|
||||||
|
http.NotFound(w, r)
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(r.URL.Path, "/localapi/v0/file-put/") {
|
}
|
||||||
h.serveFilePut(w, r)
|
|
||||||
return
|
// handlerForPath returns the LocalAPI handler for the provided Request.URI.Path.
|
||||||
|
// (the path doesn't include any query parameters)
|
||||||
|
func handlerForPath(urlPath string) (h localAPIHandler, ok bool) {
|
||||||
|
if urlPath == "/" {
|
||||||
|
return (*Handler).serveLocalAPIRoot, true
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(r.URL.Path, "/localapi/v0/cert/") {
|
suff, ok := strs.CutPrefix(urlPath, "/localapi/v0/")
|
||||||
h.serveCert(w, r)
|
if !ok {
|
||||||
return
|
// Currently all LocalAPI methods start with "/localapi/v0/" to signal
|
||||||
|
// to people that they're not necessarily stable APIs. In practice we'll
|
||||||
|
// probably need to keep them pretty stable anyway, but for now treat
|
||||||
|
// them as an internal implementation detail.
|
||||||
|
return nil, false
|
||||||
}
|
}
|
||||||
switch r.URL.Path {
|
if fn, ok := handler[suff]; ok {
|
||||||
case "/localapi/v0/whois":
|
// Here we match exact handler suffixes like "status" or ones with a
|
||||||
h.serveWhoIs(w, r)
|
// slash already in their name, like "tka/status".
|
||||||
case "/localapi/v0/goroutines":
|
return fn, true
|
||||||
h.serveGoroutines(w, r)
|
|
||||||
case "/localapi/v0/profile":
|
|
||||||
h.serveProfile(w, r)
|
|
||||||
case "/localapi/v0/status":
|
|
||||||
h.serveStatus(w, r)
|
|
||||||
case "/localapi/v0/logout":
|
|
||||||
h.serveLogout(w, r)
|
|
||||||
case "/localapi/v0/login-interactive":
|
|
||||||
h.serveLoginInteractive(w, r)
|
|
||||||
case "/localapi/v0/prefs":
|
|
||||||
h.servePrefs(w, r)
|
|
||||||
case "/localapi/v0/ping":
|
|
||||||
h.servePing(w, r)
|
|
||||||
case "/localapi/v0/check-prefs":
|
|
||||||
h.serveCheckPrefs(w, r)
|
|
||||||
case "/localapi/v0/check-ip-forwarding":
|
|
||||||
h.serveCheckIPForwarding(w, r)
|
|
||||||
case "/localapi/v0/bugreport":
|
|
||||||
h.serveBugReport(w, r)
|
|
||||||
case "/localapi/v0/file-targets":
|
|
||||||
h.serveFileTargets(w, r)
|
|
||||||
case "/localapi/v0/set-dns":
|
|
||||||
h.serveSetDNS(w, r)
|
|
||||||
case "/localapi/v0/derpmap":
|
|
||||||
h.serveDERPMap(w, r)
|
|
||||||
case "/localapi/v0/metrics":
|
|
||||||
h.serveMetrics(w, r)
|
|
||||||
case "/localapi/v0/debug":
|
|
||||||
h.serveDebug(w, r)
|
|
||||||
case "/localapi/v0/component-debug-logging":
|
|
||||||
h.serveComponentDebugLogging(w, r)
|
|
||||||
case "/localapi/v0/set-expiry-sooner":
|
|
||||||
h.serveSetExpirySooner(w, r)
|
|
||||||
case "/localapi/v0/dial":
|
|
||||||
h.serveDial(w, r)
|
|
||||||
case "/localapi/v0/id-token":
|
|
||||||
h.serveIDToken(w, r)
|
|
||||||
case "/localapi/v0/upload-client-metrics":
|
|
||||||
h.serveUploadClientMetrics(w, r)
|
|
||||||
case "/localapi/v0/tka/status":
|
|
||||||
h.serveTkaStatus(w, r)
|
|
||||||
case "/localapi/v0/tka/init":
|
|
||||||
h.serveTkaInit(w, r)
|
|
||||||
case "/localapi/v0/tka/modify":
|
|
||||||
h.serveTkaModify(w, r)
|
|
||||||
case "/":
|
|
||||||
io.WriteString(w, "tailscaled\n")
|
|
||||||
default:
|
|
||||||
http.Error(w, "404 not found", 404)
|
|
||||||
}
|
}
|
||||||
|
// Otherwise, it might be a prefix match like "files/*" which we look up
|
||||||
|
// by the prefix including first trailing slash.
|
||||||
|
if i := strings.IndexByte(suff, '/'); i != -1 {
|
||||||
|
suff = suff[:i+1]
|
||||||
|
if fn, ok := handler[suff]; ok {
|
||||||
|
return fn, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Handler) serveLocalAPIRoot(w http.ResponseWriter, r *http.Request) {
|
||||||
|
io.WriteString(w, "tailscaled\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
// serveIDToken handles requests to get an OIDC ID token.
|
// serveIDToken handles requests to get an OIDC ID token.
|
||||||
@ -834,13 +847,13 @@ func (h *Handler) serveUploadClientMetrics(w http.ResponseWriter, r *http.Reques
|
|||||||
json.NewEncoder(w).Encode(struct{}{})
|
json.NewEncoder(w).Encode(struct{}{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) serveTkaStatus(w http.ResponseWriter, r *http.Request) {
|
func (h *Handler) serveTKAStatus(w http.ResponseWriter, r *http.Request) {
|
||||||
if !h.PermitRead {
|
if !h.PermitRead {
|
||||||
http.Error(w, "lock status access denied", http.StatusForbidden)
|
http.Error(w, "lock status access denied", http.StatusForbidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if r.Method != http.MethodGet {
|
if r.Method != http.MethodGet {
|
||||||
http.Error(w, "use Get", http.StatusMethodNotAllowed)
|
http.Error(w, "use GET", http.StatusMethodNotAllowed)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -853,7 +866,7 @@ func (h *Handler) serveTkaStatus(w http.ResponseWriter, r *http.Request) {
|
|||||||
w.Write(j)
|
w.Write(j)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) serveTkaInit(w http.ResponseWriter, r *http.Request) {
|
func (h *Handler) serveTKAInit(w http.ResponseWriter, r *http.Request) {
|
||||||
if !h.PermitWrite {
|
if !h.PermitWrite {
|
||||||
http.Error(w, "lock init access denied", http.StatusForbidden)
|
http.Error(w, "lock init access denied", http.StatusForbidden)
|
||||||
return
|
return
|
||||||
@ -886,7 +899,7 @@ func (h *Handler) serveTkaInit(w http.ResponseWriter, r *http.Request) {
|
|||||||
w.Write(j)
|
w.Write(j)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) serveTkaModify(w http.ResponseWriter, r *http.Request) {
|
func (h *Handler) serveTKAModify(w http.ResponseWriter, r *http.Request) {
|
||||||
if !h.PermitWrite {
|
if !h.PermitWrite {
|
||||||
http.Error(w, "network-lock modify access denied", http.StatusForbidden)
|
http.Error(w, "network-lock modify access denied", http.StatusForbidden)
|
||||||
return
|
return
|
||||||
|
Loading…
x
Reference in New Issue
Block a user