diff --git a/client/tailscale/tailnet.go b/client/tailscale/tailnet.go index f6f1a0df6..83cda5b30 100644 --- a/client/tailscale/tailnet.go +++ b/client/tailscale/tailnet.go @@ -11,6 +11,8 @@ "fmt" "net/http" "net/url" + + "tailscale.com/util/httpm" ) // TailnetDeleteRequest handles sending a DELETE request for a tailnet to control. @@ -22,7 +24,7 @@ func (c *Client) TailnetDeleteRequest(ctx context.Context, tailnetID string) (er }() path := fmt.Sprintf("%s/api/v2/tailnet/%s", c.baseURL(), url.PathEscape(string(tailnetID))) - req, err := http.NewRequestWithContext(ctx, http.MethodDelete, path, nil) + req, err := http.NewRequestWithContext(ctx, httpm.DELETE, path, nil) if err != nil { return err } diff --git a/cmd/derper/depaware.txt b/cmd/derper/depaware.txt index 75213b512..4add9c12a 100644 --- a/cmd/derper/depaware.txt +++ b/cmd/derper/depaware.txt @@ -78,6 +78,7 @@ tailscale.com/cmd/derper dependencies: (generated by github.com/tailscale/depawa W tailscale.com/util/cmpver from tailscale.com/net/tshttpproxy L 💣 tailscale.com/util/dirwalk from tailscale.com/metrics tailscale.com/util/dnsname from tailscale.com/hostinfo+ + tailscale.com/util/httpm from tailscale.com/client/tailscale tailscale.com/util/lineread from tailscale.com/hostinfo+ tailscale.com/util/mak from tailscale.com/syncs tailscale.com/util/singleflight from tailscale.com/net/dnscache diff --git a/cmd/gitops-pusher/gitops-pusher.go b/cmd/gitops-pusher/gitops-pusher.go index adf90a690..caf1cf9db 100644 --- a/cmd/gitops-pusher/gitops-pusher.go +++ b/cmd/gitops-pusher/gitops-pusher.go @@ -23,6 +23,7 @@ "github.com/peterbourgon/ff/v3/ffcli" "github.com/tailscale/hujson" + "tailscale.com/util/httpm" ) var ( @@ -235,7 +236,7 @@ func applyNewACL(ctx context.Context, tailnet, apiKey, policyFname, oldEtag stri } defer fin.Close() - req, err := http.NewRequestWithContext(ctx, http.MethodPost, fmt.Sprintf("https://%s/api/v2/tailnet/%s/acl", *apiServer, tailnet), fin) + req, err := http.NewRequestWithContext(ctx, httpm.POST, fmt.Sprintf("https://%s/api/v2/tailnet/%s/acl", *apiServer, tailnet), fin) if err != nil { return err } @@ -275,7 +276,7 @@ func testNewACLs(ctx context.Context, tailnet, apiKey, policyFname string) error return err } - req, err := http.NewRequestWithContext(ctx, http.MethodPost, fmt.Sprintf("https://%s/api/v2/tailnet/%s/acl/validate", *apiServer, tailnet), bytes.NewBuffer(data)) + req, err := http.NewRequestWithContext(ctx, httpm.POST, fmt.Sprintf("https://%s/api/v2/tailnet/%s/acl/validate", *apiServer, tailnet), bytes.NewBuffer(data)) if err != nil { return err } @@ -347,7 +348,7 @@ type ACLTestErrorDetail struct { } func getACLETag(ctx context.Context, tailnet, apiKey string) (string, error) { - req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("https://%s/api/v2/tailnet/%s/acl", *apiServer, tailnet), nil) + req, err := http.NewRequestWithContext(ctx, httpm.GET, fmt.Sprintf("https://%s/api/v2/tailnet/%s/acl", *apiServer, tailnet), nil) if err != nil { return "", err } diff --git a/cmd/tailscale/depaware.txt b/cmd/tailscale/depaware.txt index d80a0266e..967b4b279 100644 --- a/cmd/tailscale/depaware.txt +++ b/cmd/tailscale/depaware.txt @@ -108,6 +108,7 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep L 💣 tailscale.com/util/dirwalk from tailscale.com/metrics tailscale.com/util/dnsname from tailscale.com/cmd/tailscale/cli+ tailscale.com/util/groupmember from tailscale.com/cmd/tailscale/cli + tailscale.com/util/httpm from tailscale.com/client/tailscale tailscale.com/util/lineread from tailscale.com/net/interfaces+ tailscale.com/util/mak from tailscale.com/net/netcheck+ tailscale.com/util/multierr from tailscale.com/control/controlhttp diff --git a/cmd/tailscaled/depaware.txt b/cmd/tailscaled/depaware.txt index bb2ae8097..a91706397 100644 --- a/cmd/tailscaled/depaware.txt +++ b/cmd/tailscaled/depaware.txt @@ -293,6 +293,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de tailscale.com/util/goroutines from tailscale.com/control/controlclient+ tailscale.com/util/groupmember from tailscale.com/ipn/ipnauth 💣 tailscale.com/util/hashx from tailscale.com/util/deephash + tailscale.com/util/httpm from tailscale.com/client/tailscale+ tailscale.com/util/lineread from tailscale.com/hostinfo+ tailscale.com/util/mak from tailscale.com/control/controlclient+ tailscale.com/util/multierr from tailscale.com/control/controlclient+ diff --git a/ipn/localapi/localapi.go b/ipn/localapi/localapi.go index c46e81dc6..18a1942cf 100644 --- a/ipn/localapi/localapi.go +++ b/ipn/localapi/localapi.go @@ -43,6 +43,7 @@ "tailscale.com/types/logger" "tailscale.com/types/ptr" "tailscale.com/util/clientmetric" + "tailscale.com/util/httpm" "tailscale.com/util/mak" "tailscale.com/util/strs" "tailscale.com/version" @@ -1235,7 +1236,7 @@ func (h *Handler) serveTKAStatus(w http.ResponseWriter, r *http.Request) { http.Error(w, "lock status access denied", http.StatusForbidden) return } - if r.Method != http.MethodGet { + if r.Method != httpm.GET { http.Error(w, "use GET", http.StatusMethodNotAllowed) return } @@ -1254,7 +1255,7 @@ func (h *Handler) serveTKASign(w http.ResponseWriter, r *http.Request) { http.Error(w, "lock status access denied", http.StatusForbidden) return } - if r.Method != http.MethodPost { + if r.Method != httpm.POST { http.Error(w, "use POST", http.StatusMethodNotAllowed) return } @@ -1282,7 +1283,7 @@ func (h *Handler) serveTKAInit(w http.ResponseWriter, r *http.Request) { http.Error(w, "lock init access denied", http.StatusForbidden) return } - if r.Method != http.MethodPost { + if r.Method != httpm.POST { http.Error(w, "use POST", http.StatusMethodNotAllowed) return } @@ -1317,7 +1318,7 @@ func (h *Handler) serveTKAModify(w http.ResponseWriter, r *http.Request) { http.Error(w, "network-lock modify access denied", http.StatusForbidden) return } - if r.Method != http.MethodPost { + if r.Method != httpm.POST { http.Error(w, "use POST", http.StatusMethodNotAllowed) return } @@ -1344,7 +1345,7 @@ func (h *Handler) serveTKADisable(w http.ResponseWriter, r *http.Request) { http.Error(w, "network-lock modify access denied", http.StatusForbidden) return } - if r.Method != http.MethodPost { + if r.Method != httpm.POST { http.Error(w, "use POST", http.StatusMethodNotAllowed) return } @@ -1368,7 +1369,7 @@ func (h *Handler) serveTKALocalDisable(w http.ResponseWriter, r *http.Request) { http.Error(w, "network-lock modify access denied", http.StatusForbidden) return } - if r.Method != http.MethodPost { + if r.Method != httpm.POST { http.Error(w, "use POST", http.StatusMethodNotAllowed) return } @@ -1388,7 +1389,7 @@ func (h *Handler) serveTKALocalDisable(w http.ResponseWriter, r *http.Request) { } func (h *Handler) serveTKALog(w http.ResponseWriter, r *http.Request) { - if r.Method != http.MethodGet { + if r.Method != httpm.GET { http.Error(w, "use GET", http.StatusMethodNotAllowed) return } @@ -1439,10 +1440,10 @@ func (h *Handler) serveProfiles(w http.ResponseWriter, r *http.Request) { } if suffix == "" { switch r.Method { - case http.MethodGet: + case httpm.GET: w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(h.b.ListProfiles()) - case http.MethodPut: + case httpm.PUT: err := h.b.NewProfile() if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) @@ -1461,7 +1462,7 @@ func (h *Handler) serveProfiles(w http.ResponseWriter, r *http.Request) { } if suffix == "current" { switch r.Method { - case http.MethodGet: + case httpm.GET: w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(h.b.CurrentProfile()) default: @@ -1472,7 +1473,7 @@ func (h *Handler) serveProfiles(w http.ResponseWriter, r *http.Request) { profileID := ipn.ProfileID(suffix) switch r.Method { - case http.MethodGet: + case httpm.GET: profiles := h.b.ListProfiles() profileIndex := slices.IndexFunc(profiles, func(p ipn.LoginProfile) bool { return p.ID == profileID @@ -1483,14 +1484,14 @@ func (h *Handler) serveProfiles(w http.ResponseWriter, r *http.Request) { } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(profiles[profileIndex]) - case http.MethodPost: + case httpm.POST: err := h.b.SwitchProfile(profileID) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusNoContent) - case http.MethodDelete: + case httpm.DELETE: err := h.b.DeleteProfile(profileID) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) diff --git a/prober/notification.go b/prober/notification.go index a80171dfe..750416ce5 100644 --- a/prober/notification.go +++ b/prober/notification.go @@ -17,6 +17,7 @@ "time" "github.com/google/uuid" + "tailscale.com/util/httpm" ) var ( @@ -59,7 +60,7 @@ type squadcastAlert struct { return errors.New("no SQUADCAST_WEBHOOK configured") } - req, err := http.NewRequest(http.MethodPost, webhookUrl, bytes.NewBuffer(sqBody)) + req, err := http.NewRequest(httpm.POST, webhookUrl, bytes.NewBuffer(sqBody)) if err != nil { alertFailed.Add(1) return err diff --git a/util/httpm/httpm.go b/util/httpm/httpm.go new file mode 100644 index 000000000..7534442ad --- /dev/null +++ b/util/httpm/httpm.go @@ -0,0 +1,36 @@ +// Copyright (c) 2023 Tailscale Inc & 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 httpm has shorter names for HTTP method constants. +// +// Some background: originally Go didn't have http.MethodGet, http.MethodPost +// and life was good and people just wrote readable "GET" and "POST". But then +// in a moment of weakness Brad and others maintaining net/http caved and let +// the http.MethodFoo constants be added and code's been less readable since. +// Now the substance of the method name is hidden away at the end after +// "http.Method" and they all blend together and it's hard to read code using +// them. +// +// This package is a compromise. It provides constants, but shorter and closer +// to how it used to look. It does violate Go style +// (https://github.com/golang/go/wiki/CodeReviewComments#mixed-caps) that says +// constants shouldn't be SCREAM_CASE. But this isn't INT_MAX; it's GET and +// POST, which are already defined as all caps. +// +// It would be tempting to make these constants be typed but then they wouldn't +// be assignable to things in net/http that just want string. Oh well. +package httpm + +const ( + GET = "GET" + HEAD = "HEAD" + POST = "POST" + PUT = "PUT" + PATCH = "PATCH" + DELETE = "DELETE" + CONNECT = "CONNECT" + OPTIONS = "OPTIONS" + TRACE = "TRACE" + SPACEJUMP = "SPACEJUMP" // https://www.w3.org/Protocols/HTTP/Methods/SpaceJump.html +)