ipn: fix localapi and peerapi protocol for taildrop resume (#9860)

Minor fixes:
* The branch for listing or hashing partial files was inverted.
* The host for peerapi call needs to be real (rather than bogus).
* Handle remote peers that don't support resuming.
* Make resume failures non-fatal (since we can still continue).

This was tested locally, end-to-end system test is future work.

Updates tailscale/corp#14772

Signed-off-by: Joe Tsai <joetsai@digital-static.net>
Co-authored-by: Rhea Ghosh <rhea@tailscale.com>
This commit is contained in:
Joe Tsai 2023-10-17 16:14:47 -07:00 committed by GitHub
parent 77127a2494
commit 7971333603
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 15 additions and 10 deletions

View File

@ -655,7 +655,7 @@ func (h *peerAPIHandler) handlePeerPut(w http.ResponseWriter, r *http.Request) {
var err error
id := taildrop.ClientID(h.peerNode.StableID())
if r.URL.Path == "/v0/put/"+baseName {
if prefix == "" {
resp, err = h.ps.taildrop.PartialFiles(id)
} else {
ranges, ok := httphdr.ParseRange(r.Header.Get("Range"))

View File

@ -1325,7 +1325,7 @@ func (h *Handler) serveFilePut(w http.ResponseWriter, r *http.Request) {
Transport: h.b.Dialer().PeerAPITransport(),
Timeout: 10 * time.Second,
}
req, err := http.NewRequestWithContext(r.Context(), "GET", "http://peer/v0/put/"+filenameEscaped, nil)
req, err := http.NewRequestWithContext(r.Context(), "GET", dstURL.String()+"/v0/put/"+filenameEscaped, nil)
if err != nil {
return taildrop.FileChecksums{}, err
}
@ -1335,18 +1335,23 @@ func (h *Handler) serveFilePut(w http.ResponseWriter, r *http.Request) {
return taildrop.FileChecksums{}, fmt.Errorf("invalid offset and length")
}
req.Header.Set("Range", rangeHdr)
resp, err := client.Do(req)
if err != nil {
switch resp, err := client.Do(req); {
case err != nil:
return taildrop.FileChecksums{}, err
case resp.StatusCode == http.StatusMethodNotAllowed || resp.StatusCode == http.StatusNotFound:
return taildrop.FileChecksums{}, nil // implies remote peer on older version
case resp.StatusCode != http.StatusOK:
return taildrop.FileChecksums{}, fmt.Errorf("unexpected status code %d", resp.StatusCode)
default:
var checksums taildrop.FileChecksums
err = json.NewDecoder(resp.Body).Decode(&checksums)
return checksums, err
}
var checksums taildrop.FileChecksums
err = json.NewDecoder(resp.Body).Decode(&checksums)
return checksums, err
})
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
// ResumeReader ensures that the returned offset and reader are consistent
// even if an error is encountered. Thus, we can still proceed.
h.logf("reader could not be fully resumed: %v", err)
}
outReq, err := http.NewRequestWithContext(r.Context(), "PUT", "http://peer/v0/put/"+filenameEscaped, remainingBody)