"context"
"errors"
"fmt"
+ "net/http"
"strings"
"sync"
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)
import (
"bytes"
"context"
- "errors"
"fmt"
"io"
"net/http"
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 {
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 {