]> Sergey Matveev's repositories - btrtrc.git/blob - tracker/http/server/server.go
0840fe96cf0a205e46bd78817513381f52014de7
[btrtrc.git] / tracker / http / server / server.go
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/log"
13
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"
18 )
19
20 type Handler struct {
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)
25 }
26
27 func unmarshalQueryKeyToArray(w http.ResponseWriter, key string, query url.Values) (ret [20]byte, ok bool) {
28         str := query.Get(key)
29         if len(str) != len(ret) {
30                 http.Error(w, fmt.Sprintf("%v has wrong length", key), http.StatusBadRequest)
31                 return
32         }
33         copy(ret[:], str)
34         ok = true
35         return
36 }
37
38 var Logger = log.NewLogger("anacrolix", "torrent", "tracker", "http", "server")
39
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)
44         }
45         host, _, err := net.SplitHostPort(r.RemoteAddr)
46         if err != nil {
47                 return
48         }
49         return netip.ParseAddr(host)
50 }
51
52 func (me Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
53         vs := r.URL.Query()
54         var event tracker.AnnounceEvent
55         err := event.UnmarshalText([]byte(vs.Get("event")))
56         if err != nil {
57                 http.Error(w, err.Error(), http.StatusBadRequest)
58                 return
59         }
60         infoHash, ok := unmarshalQueryKeyToArray(w, "info_hash", vs)
61         if !ok {
62                 return
63         }
64         peerId, ok := unmarshalQueryKeyToArray(w, "peer_id", vs)
65         if !ok {
66                 return
67         }
68         Logger.WithNames("request").Levelf(log.Debug, "request RemoteAddr=%q, header=%q", r.RemoteAddr, r.Header)
69         addr, err := me.requestHostAddr(r)
70         if err != nil {
71                 log.Printf("error getting requester IP: %v", err)
72                 http.Error(w, "error determining your IP", http.StatusBadGateway)
73                 return
74         }
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{
78                 InfoHash: infoHash,
79                 PeerId:   peerId,
80                 Event:    event,
81                 Port:     addrPort.Port(),
82         }, addrPort)
83         if err != nil {
84                 log.Printf("error tracking announce: %v", err)
85                 http.Error(w, "error tracking announce", http.StatusInternalServerError)
86                 return
87         }
88         peers, err := me.AnnounceTracker.GetPeers(r.Context(), infoHash, tracker.GetPeersOpts{})
89         if err != nil {
90                 log.Printf("error getting peers: %v", err)
91                 http.Error(w, "error getting peers", http.StatusInternalServerError)
92                 return
93         }
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()),
102                         })
103                 } else if peer.Addr().Is6() {
104                         resp.Peers6 = append(resp.Peers6, krpc.NodeAddr{
105                                 IP:   peer.Addr().AsSlice(),
106                                 Port: int(peer.Port()),
107                         })
108                 }
109         }
110         err = bencode.NewEncoder(w).Encode(resp)
111         if err != nil {
112                 log.Printf("error encoding and writing response body: %v", err)
113         }
114 }