mirror of
https://github.com/tailscale/tailscale.git
synced 2025-04-22 08:51:41 +00:00
ipn/ipnlocal/peerapi: refactoring taildrop to just one endpoint (#9832)
Updates #14772 Signed-off-by: Rhea Ghosh <rhea@tailscale.com>
This commit is contained in:
parent
4899c2c1f4
commit
9d3c6bf52e
@ -305,12 +305,10 @@ func (h *peerAPIHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
w.Header().Set("X-Frame-Options", "DENY")
|
w.Header().Set("X-Frame-Options", "DENY")
|
||||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(r.URL.Path, "/v0/partial-files/") {
|
|
||||||
h.handlePartialFileGet(w, r)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(r.URL.Path, "/v0/put/") {
|
if strings.HasPrefix(r.URL.Path, "/v0/put/") {
|
||||||
|
if r.Method == "PUT" {
|
||||||
metricPutCalls.Add(1)
|
metricPutCalls.Add(1)
|
||||||
|
}
|
||||||
h.handlePeerPut(w, r)
|
h.handlePeerPut(w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -631,45 +629,35 @@ func (h *peerAPIHandler) peerHasCap(wantCap tailcfg.PeerCapability) bool {
|
|||||||
return h.ps.b.PeerCaps(h.remoteAddr.Addr()).HasCapability(wantCap)
|
return h.ps.b.PeerCaps(h.remoteAddr.Addr()).HasCapability(wantCap)
|
||||||
}
|
}
|
||||||
|
|
||||||
var errMisconfiguredInternals = errors.New("misconfigured internals")
|
func (h *peerAPIHandler) handlePeerPut(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !h.canPutFile() {
|
||||||
func (h *peerAPIHandler) extractBaseName(rawPath, prefix string) (ret string, err error) {
|
http.Error(w, taildrop.ErrNoTaildrop.Error(), http.StatusForbidden)
|
||||||
prefix, ok := strings.CutPrefix(rawPath, prefix)
|
return
|
||||||
if !ok {
|
|
||||||
return "", errMisconfiguredInternals
|
|
||||||
}
|
}
|
||||||
if prefix == "" {
|
|
||||||
return "", taildrop.ErrInvalidFileName
|
|
||||||
}
|
|
||||||
if strings.Contains(prefix, "/") {
|
|
||||||
return "", taildrop.ErrInvalidFileName
|
|
||||||
}
|
|
||||||
baseName, err := url.PathUnescape(prefix)
|
|
||||||
if err == errMisconfiguredInternals {
|
|
||||||
return "", errMisconfiguredInternals
|
|
||||||
} else if err != nil {
|
|
||||||
return "", taildrop.ErrInvalidFileName
|
|
||||||
}
|
|
||||||
return baseName, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *peerAPIHandler) handlePartialFileGet(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if !h.ps.b.hasCapFileSharing() {
|
if !h.ps.b.hasCapFileSharing() {
|
||||||
http.Error(w, taildrop.ErrNoTaildrop.Error(), http.StatusForbidden)
|
http.Error(w, taildrop.ErrNoTaildrop.Error(), http.StatusForbidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if r.Method != "GET" {
|
rawPath := r.URL.EscapedPath()
|
||||||
http.Error(w, "expected method GET", http.StatusMethodNotAllowed)
|
prefix, ok := strings.CutPrefix(rawPath, "/v0/put/")
|
||||||
|
if !ok {
|
||||||
|
http.Error(w, "misconfigured internals", http.StatusForbidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
baseName, err := url.PathUnescape(prefix)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, taildrop.ErrInvalidFileName.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch r.Method {
|
||||||
|
case "GET":
|
||||||
var resp any
|
var resp any
|
||||||
var err error
|
var err error
|
||||||
id := taildrop.ClientID(h.peerNode.StableID())
|
id := taildrop.ClientID(h.peerNode.StableID())
|
||||||
|
|
||||||
if r.URL.Path == "/v0/partial-files/" {
|
if r.URL.Path == "/v0/put/"+baseName {
|
||||||
resp, err = h.ps.taildrop.PartialFiles(id)
|
resp, err = h.ps.taildrop.PartialFiles(id)
|
||||||
} else {
|
} else {
|
||||||
baseName, _ := h.extractBaseName(r.URL.EscapedPath(), "/v0/partial-files/")
|
|
||||||
ranges, ok := httphdr.ParseRange(r.Header.Get("Range"))
|
ranges, ok := httphdr.ParseRange(r.Header.Get("Range"))
|
||||||
if !ok || len(ranges) != 1 || ranges[0].Length < 0 {
|
if !ok || len(ranges) != 1 || ranges[0].Length < 0 {
|
||||||
http.Error(w, "invalid Range header", http.StatusBadRequest)
|
http.Error(w, "invalid Range header", http.StatusBadRequest)
|
||||||
@ -690,27 +678,7 @@ func (h *peerAPIHandler) handlePartialFileGet(w http.ResponseWriter, r *http.Req
|
|||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
case "PUT":
|
||||||
}
|
|
||||||
|
|
||||||
func (h *peerAPIHandler) handlePeerPut(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if !h.canPutFile() {
|
|
||||||
http.Error(w, taildrop.ErrNoTaildrop.Error(), http.StatusForbidden)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !h.ps.b.hasCapFileSharing() {
|
|
||||||
http.Error(w, "file sharing not enabled by Tailscale admin", http.StatusForbidden)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if r.Method != "PUT" {
|
|
||||||
http.Error(w, "expected method PUT", http.StatusMethodNotAllowed)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
baseName, err := h.extractBaseName(r.URL.EscapedPath(), "/v0/put/")
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
t0 := h.ps.b.clock.Now()
|
t0 := h.ps.b.clock.Now()
|
||||||
id := taildrop.ClientID(h.peerNode.StableID())
|
id := taildrop.ClientID(h.peerNode.StableID())
|
||||||
|
|
||||||
@ -738,6 +706,9 @@ func (h *peerAPIHandler) handlePeerPut(w http.ResponseWriter, r *http.Request) {
|
|||||||
default:
|
default:
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
http.Error(w, "expected method GET or PUT", http.StatusMethodNotAllowed)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func approxSize(n int64) string {
|
func approxSize(n int64) string {
|
||||||
|
@ -183,7 +183,7 @@ func TestHandlePeerAPI(t *testing.T) {
|
|||||||
reqs: []*http.Request{httptest.NewRequest("PUT", "/v0/put/foo", nil)},
|
reqs: []*http.Request{httptest.NewRequest("PUT", "/v0/put/foo", nil)},
|
||||||
checks: checks(
|
checks: checks(
|
||||||
httpStatus(http.StatusForbidden),
|
httpStatus(http.StatusForbidden),
|
||||||
bodyContains("file sharing not enabled by Tailscale admin"),
|
bodyContains("Taildrop disabled"),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -204,7 +204,7 @@ func TestHandlePeerAPI(t *testing.T) {
|
|||||||
reqs: []*http.Request{httptest.NewRequest("POST", "/v0/put/foo", nil)},
|
reqs: []*http.Request{httptest.NewRequest("POST", "/v0/put/foo", nil)},
|
||||||
checks: checks(
|
checks: checks(
|
||||||
httpStatus(405),
|
httpStatus(405),
|
||||||
bodyContains("expected method PUT"),
|
bodyContains("expected method GET or PUT"),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1325,7 +1325,7 @@ func (h *Handler) serveFilePut(w http.ResponseWriter, r *http.Request) {
|
|||||||
Transport: h.b.Dialer().PeerAPITransport(),
|
Transport: h.b.Dialer().PeerAPITransport(),
|
||||||
Timeout: 10 * time.Second,
|
Timeout: 10 * time.Second,
|
||||||
}
|
}
|
||||||
req, err := http.NewRequestWithContext(r.Context(), "GET", "http://peer/v0/partial-files/"+filenameEscaped, nil)
|
req, err := http.NewRequestWithContext(r.Context(), "GET", "http://peer/v0/put/"+filenameEscaped, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return taildrop.FileChecksums{}, err
|
return taildrop.FileChecksums{}, err
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user