1 package httpTrackerServer
11 "github.com/anacrolix/dht/v2/krpc"
12 "github.com/anacrolix/generics"
13 "github.com/anacrolix/log"
14 trackerServer "github.com/anacrolix/torrent/tracker/server"
16 "github.com/anacrolix/torrent/bencode"
17 "github.com/anacrolix/torrent/tracker"
18 httpTracker "github.com/anacrolix/torrent/tracker/http"
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)
28 func unmarshalQueryKeyToArray(w http.ResponseWriter, key string, query url.Values) (ret [20]byte, ok bool) {
30 if len(str) != len(ret) {
31 http.Error(w, fmt.Sprintf("%v has wrong length", key), http.StatusBadRequest)
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)
44 host, _, err := net.SplitHostPort(r.RemoteAddr)
48 return netip.ParseAddr(host)
51 var requestHeadersLogger = log.Default.WithNames("request", "headers")
53 func (me Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
55 var event tracker.AnnounceEvent
56 err := event.UnmarshalText([]byte(vs.Get("event")))
58 http.Error(w, err.Error(), http.StatusBadRequest)
61 infoHash, ok := unmarshalQueryKeyToArray(w, "info_hash", vs)
65 peerId, ok := unmarshalQueryKeyToArray(w, "peer_id", vs)
69 requestHeadersLogger.Levelf(log.Debug, "request RemoteAddr=%q, header=%q", r.RemoteAddr, r.Header)
70 addr, err := me.requestHostAddr(r)
72 log.Printf("error getting requester IP: %v", err)
73 http.Error(w, "error determining your IP", http.StatusBadGateway)
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)
82 res := me.Announce.Serve(
84 tracker.AnnounceRequest{
88 Port: addrPort.Port(),
93 trackerServer.GetPeersOpts{
94 MaxCount: generics.Some[uint](200),
99 log.Printf("error serving announce: %v", err)
100 http.Error(w, "error handling announce", http.StatusInternalServerError)
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()),
114 } else if peer.Addr().Is6() {
115 resp.Peers6 = append(resp.Peers6, krpc.NodeAddr{
116 IP: peer.Addr().AsSlice(),
117 Port: int(peer.Port()),
121 err = bencode.NewEncoder(w).Encode(resp)
123 log.Printf("error encoding and writing response body: %v", err)