github.com/anacrolix/torrent@v1.61.0/tracker/http/server/server.go (about)

     1  package httpTrackerServer
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"net/http"
     7  	"net/netip"
     8  	"net/url"
     9  	"strconv"
    10  
    11  	"github.com/anacrolix/dht/v2/krpc"
    12  	"github.com/anacrolix/generics"
    13  	"github.com/anacrolix/log"
    14  
    15  	"github.com/anacrolix/torrent/bencode"
    16  	"github.com/anacrolix/torrent/tracker"
    17  	httpTracker "github.com/anacrolix/torrent/tracker/http"
    18  	trackerServer "github.com/anacrolix/torrent/tracker/server"
    19  )
    20  
    21  type Handler struct {
    22  	Announce *trackerServer.AnnounceHandler
    23  	// Called to derive an announcer's IP if non-nil. If not specified, the Request.RemoteAddr is
    24  	// used. Necessary for instances running behind reverse proxies for example.
    25  	RequestHost func(r *http.Request) (netip.Addr, error)
    26  }
    27  
    28  func unmarshalQueryKeyToArray(w http.ResponseWriter, key string, query url.Values) (ret [20]byte, ok bool) {
    29  	str := query.Get(key)
    30  	if len(str) != len(ret) {
    31  		http.Error(w, fmt.Sprintf("%v has wrong length", key), http.StatusBadRequest)
    32  		return
    33  	}
    34  	copy(ret[:], str)
    35  	ok = true
    36  	return
    37  }
    38  
    39  // Returns false if there was an error and it was served.
    40  func (me Handler) requestHostAddr(r *http.Request) (_ netip.Addr, err error) {
    41  	if me.RequestHost != nil {
    42  		return me.RequestHost(r)
    43  	}
    44  	host, _, err := net.SplitHostPort(r.RemoteAddr)
    45  	if err != nil {
    46  		return
    47  	}
    48  	return netip.ParseAddr(host)
    49  }
    50  
    51  var requestHeadersLogger = log.Default.WithNames("request", "headers")
    52  
    53  func (me Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    54  	vs := r.URL.Query()
    55  	var event tracker.AnnounceEvent
    56  	err := event.UnmarshalText([]byte(vs.Get("event")))
    57  	if err != nil {
    58  		http.Error(w, err.Error(), http.StatusBadRequest)
    59  		return
    60  	}
    61  	infoHash, ok := unmarshalQueryKeyToArray(w, "info_hash", vs)
    62  	if !ok {
    63  		return
    64  	}
    65  	peerId, ok := unmarshalQueryKeyToArray(w, "peer_id", vs)
    66  	if !ok {
    67  		return
    68  	}
    69  	requestHeadersLogger.Levelf(log.Debug, "request RemoteAddr=%q, header=%q", r.RemoteAddr, r.Header)
    70  	addr, err := me.requestHostAddr(r)
    71  	if err != nil {
    72  		log.Printf("error getting requester IP: %v", err)
    73  		http.Error(w, "error determining your IP", http.StatusBadGateway)
    74  		return
    75  	}
    76  	portU64, _ := strconv.ParseUint(vs.Get("port"), 0, 16)
    77  	addrPort := netip.AddrPortFrom(addr, uint16(portU64))
    78  	left, err := strconv.ParseInt(vs.Get("left"), 0, 64)
    79  	if err != nil {
    80  		left = -1
    81  	}
    82  	res := me.Announce.Serve(
    83  		r.Context(),
    84  		tracker.AnnounceRequest{
    85  			InfoHash: infoHash,
    86  			PeerId:   peerId,
    87  			Event:    event,
    88  			Port:     addrPort.Port(),
    89  			NumWant:  -1,
    90  			Left:     left,
    91  		},
    92  		addrPort,
    93  		trackerServer.GetPeersOpts{
    94  			MaxCount: generics.Some[uint](200),
    95  		},
    96  	)
    97  	err = res.Err
    98  	if err != nil {
    99  		log.Printf("error serving announce: %v", err)
   100  		http.Error(w, "error handling announce", http.StatusInternalServerError)
   101  		return
   102  	}
   103  	var resp httpTracker.HttpResponse
   104  	resp.Incomplete = res.Leechers.Value
   105  	resp.Complete = res.Seeders.Value
   106  	resp.Interval = res.Interval.UnwrapOr(5 * 60)
   107  	resp.Peers.Compact = true
   108  	for _, peer := range res.Peers {
   109  		if peer.Addr().Is4() {
   110  			resp.Peers.List = append(resp.Peers.List, tracker.Peer{
   111  				IP:   peer.Addr().AsSlice(),
   112  				Port: int(peer.Port()),
   113  			})
   114  		} else if peer.Addr().Is6() {
   115  			resp.Peers6 = append(resp.Peers6, krpc.NodeAddr{
   116  				IP:   peer.Addr().AsSlice(),
   117  				Port: int(peer.Port()),
   118  			})
   119  		}
   120  	}
   121  	err = bencode.NewEncoder(w).Encode(resp)
   122  	if err != nil {
   123  		log.Printf("error encoding and writing response body: %v", err)
   124  	}
   125  }