1 package httpTrackerServer
11 "github.com/anacrolix/dht/v2/krpc"
12 "github.com/anacrolix/log"
14 "github.com/anacrolix/torrent/bencode"
15 "github.com/anacrolix/torrent/tracker"
16 httpTracker "github.com/anacrolix/torrent/tracker/http"
17 udpTrackerServer "github.com/anacrolix/torrent/tracker/udp/server"
21 AnnounceTracker udpTrackerServer.AnnounceTracker
22 // Called to derive an announcer's IP if non-nil. If not specified, the Request.RemoteAddr is
23 // used. Necessary for instances running behind reverse proxies for example.
24 RequestHost func(r *http.Request) (netip.Addr, error)
27 func unmarshalQueryKeyToArray(w http.ResponseWriter, key string, query url.Values) (ret [20]byte, ok bool) {
29 if len(str) != len(ret) {
30 http.Error(w, fmt.Sprintf("%v has wrong length", key), http.StatusBadRequest)
38 var Logger = log.NewLogger("anacrolix", "torrent", "tracker", "http", "server")
40 // Returns false if there was an error and it was served.
41 func (me Handler) requestHostAddr(r *http.Request) (_ netip.Addr, err error) {
42 if me.RequestHost != nil {
43 return me.RequestHost(r)
45 host, _, err := net.SplitHostPort(r.RemoteAddr)
49 return netip.ParseAddr(host)
52 func (me Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
54 var event tracker.AnnounceEvent
55 err := event.UnmarshalText([]byte(vs.Get("event")))
57 http.Error(w, err.Error(), http.StatusBadRequest)
60 infoHash, ok := unmarshalQueryKeyToArray(w, "info_hash", vs)
64 peerId, ok := unmarshalQueryKeyToArray(w, "peer_id", vs)
68 Logger.WithNames("request").Levelf(log.Debug, "request RemoteAddr=%q, header=%q", r.RemoteAddr, r.Header)
69 addr, err := me.requestHostAddr(r)
71 log.Printf("error getting requester IP: %v", err)
72 http.Error(w, "error determining your IP", http.StatusBadGateway)
75 portU64, err := strconv.ParseUint(vs.Get("port"), 0, 16)
76 addrPort := netip.AddrPortFrom(addr, uint16(portU64))
77 err = me.AnnounceTracker.TrackAnnounce(r.Context(), tracker.AnnounceRequest{
81 Port: addrPort.Port(),
84 log.Printf("error tracking announce: %v", err)
85 http.Error(w, "error tracking announce", http.StatusInternalServerError)
88 peers, err := me.AnnounceTracker.GetPeers(r.Context(), infoHash, tracker.GetPeersOpts{})
90 log.Printf("error getting peers: %v", err)
91 http.Error(w, "error getting peers", http.StatusInternalServerError)
94 var resp httpTracker.HttpResponse
95 resp.Interval = 5 * 60
96 resp.Peers.Compact = true
97 for _, peer := range peers {
98 if peer.Addr().Is4() {
99 resp.Peers.List = append(resp.Peers.List, tracker.Peer{
100 IP: peer.Addr().AsSlice(),
101 Port: int(peer.Port()),
103 } else if peer.Addr().Is6() {
104 resp.Peers6 = append(resp.Peers6, krpc.NodeAddr{
105 IP: peer.Addr().AsSlice(),
106 Port: int(peer.Port()),
110 err = bencode.NewEncoder(w).Encode(resp)
112 log.Printf("error encoding and writing response body: %v", err)