From: Matt Joiner Date: Thu, 18 Feb 2021 03:36:08 +0000 (+1100) Subject: Treat 404 responses from webseed peers as fatal X-Git-Tag: v1.26.0-alpha~19 X-Git-Url: http://www.git.stargrave.org/?a=commitdiff_plain;h=af0ade549644f77350be2cd5b4c0d8b6f680259e;p=btrtrc.git Treat 404 responses from webseed peers as fatal Fixes #464. --- diff --git a/webseed-peer.go b/webseed-peer.go index e436f8aa..e2df582e 100644 --- a/webseed-peer.go +++ b/webseed-peer.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "net/http" "strings" "sync" @@ -117,11 +118,18 @@ func (ws *webseedPeer) requestResultHandler(r Request, webseedRequest webseed.Re if !errors.Is(result.Err, context.Canceled) { ws.peer.logger.Printf("Request %v rejected: %v", r, result.Err) } - // Always close for now. We need to filter out temporary errors, but this is a nightmare in - // Go. Currently a bad webseed URL can starve out the good ones due to the chunk selection - // algorithm. + // We need to filter out temporary errors, but this is a nightmare in Go. Currently a bad + // webseed URL can starve out the good ones due to the chunk selection algorithm. const closeOnAllErrors = false - if closeOnAllErrors || strings.Contains(result.Err.Error(), "unsupported protocol scheme") { + if closeOnAllErrors || + strings.Contains(result.Err.Error(), "unsupported protocol scheme") || + func() bool { + var err webseed.ErrBadResponse + if !errors.As(result.Err, &err) { + return false + } + return err.Response.StatusCode == http.StatusNotFound + }() { ws.peer.close() } else { ws.peer.remoteRejectedRequest(r) diff --git a/webseed/client.go b/webseed/client.go index 420901ea..cc17b339 100644 --- a/webseed/client.go +++ b/webseed/client.go @@ -3,7 +3,6 @@ package webseed import ( "bytes" "context" - "errors" "fmt" "io" "net/http" @@ -86,6 +85,15 @@ func (ws *Client) NewRequest(r RequestSpec) Request { return req } +type ErrBadResponse struct { + Msg string + Response *http.Response +} + +func (me ErrBadResponse) Error() string { + return me.Msg +} + func recvPartResult(buf io.Writer, part requestPart) error { result := <-part.result if result.err != nil { @@ -96,10 +104,13 @@ func recvPartResult(buf io.Writer, part requestPart) error { case http.StatusPartialContent: case http.StatusOK: if part.e.Start != 0 { - return errors.New("got status ok but request was at offset") + return ErrBadResponse{"got status ok but request was at offset", result.resp} } default: - return fmt.Errorf("unhandled response status code (%v)", result.resp.StatusCode) + return ErrBadResponse{ + fmt.Sprintf("unhandled response status code (%v)", result.resp.StatusCode), + result.resp, + } } copied, err := io.Copy(buf, result.resp.Body) if err != nil {