]> Sergey Matveev's repositories - btrtrc.git/blob - tracker/http/server/server.go
30be15c65c8c4719bbdcf1b173919294b09d286b
[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/generics"
13         "github.com/anacrolix/log"
14         trackerServer "github.com/anacrolix/torrent/tracker/server"
15
16         "github.com/anacrolix/torrent/bencode"
17         "github.com/anacrolix/torrent/tracker"
18         httpTracker "github.com/anacrolix/torrent/tracker/http"
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 }