]> Sergey Matveev's repositories - btrtrc.git/commitdiff
Treat 404 responses from webseed peers as fatal
authorMatt Joiner <anacrolix@gmail.com>
Thu, 18 Feb 2021 03:36:08 +0000 (14:36 +1100)
committerMatt Joiner <anacrolix@gmail.com>
Thu, 18 Feb 2021 03:36:08 +0000 (14:36 +1100)
Fixes #464.

webseed-peer.go
webseed/client.go

index e436f8aab0fd54bbf9c0ee3c1ceeaa6c60a24932..e2df582ed5cbbea02278984e917d7b79743ba336 100644 (file)
@@ -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)
index 420901ea761e678d4e8bdbc6a40c415d76d5c219..cc17b339343daa2be6ed23e11809248f6d530030 100644 (file)
@@ -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 {