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 }