]> Sergey Matveev's repositories - btrtrc.git/blob - tracker/http/server/server.go
ed08ac924ef3376cc7bcbe7b43e4e0a57b607967
[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 )
18
19 type Handler struct {
20         Announce tracker.AnnounceHandler
21         // Called to derive an announcer's IP if non-nil. If not specified, the Request.RemoteAddr is
22         // used. Necessary for instances running behind reverse proxies for example.
23         RequestHost func(r *http.Request) (netip.Addr, error)
24 }
25
26 func unmarshalQueryKeyToArray(w http.ResponseWriter, key string, query url.Values) (ret [20]byte, ok bool) {
27         str := query.Get(key)
28         if len(str) != len(ret) {
29                 http.Error(w, fmt.Sprintf("%v has wrong length", key), http.StatusBadRequest)
30                 return
31         }
32         copy(ret[:], str)
33         ok = true
34         return
35 }
36
37 // Returns false if there was an error and it was served.
38 func (me Handler) requestHostAddr(r *http.Request) (_ netip.Addr, err error) {
39         if me.RequestHost != nil {
40                 return me.RequestHost(r)
41         }
42         host, _, err := net.SplitHostPort(r.RemoteAddr)
43         if err != nil {
44                 return
45         }
46         return netip.ParseAddr(host)
47 }
48
49 var requestHeadersLogger = log.Default.WithNames("request", "headers")
50
51 func (me Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
52         vs := r.URL.Query()
53         var event tracker.AnnounceEvent
54         err := event.UnmarshalText([]byte(vs.Get("event")))
55         if err != nil {
56                 http.Error(w, err.Error(), http.StatusBadRequest)
57                 return
58         }
59         infoHash, ok := unmarshalQueryKeyToArray(w, "info_hash", vs)
60         if !ok {
61                 return
62         }
63         peerId, ok := unmarshalQueryKeyToArray(w, "peer_id", vs)
64         if !ok {
65                 return
66         }
67         requestHeadersLogger.Levelf(log.Debug, "request RemoteAddr=%q, header=%q", r.RemoteAddr, r.Header)
68         addr, err := me.requestHostAddr(r)
69         if err != nil {
70                 log.Printf("error getting requester IP: %v", err)
71                 http.Error(w, "error determining your IP", http.StatusBadGateway)
72                 return
73         }
74         portU64, err := strconv.ParseUint(vs.Get("port"), 0, 16)
75         addrPort := netip.AddrPortFrom(addr, uint16(portU64))
76         peers, err := me.Announce.Serve(r.Context(), tracker.AnnounceRequest{
77                 InfoHash: infoHash,
78                 PeerId:   peerId,
79                 Event:    event,
80                 Port:     addrPort.Port(),
81         }, addrPort)
82         if err != nil {
83                 log.Printf("error serving announce: %v", err)
84                 http.Error(w, "error handling announce", http.StatusInternalServerError)
85                 return
86         }
87         var resp httpTracker.HttpResponse
88         resp.Interval = 5 * 60
89         resp.Peers.Compact = true
90         for _, peer := range peers {
91                 if peer.Addr().Is4() {
92                         resp.Peers.List = append(resp.Peers.List, tracker.Peer{
93                                 IP:   peer.Addr().AsSlice(),
94                                 Port: int(peer.Port()),
95                         })
96                 } else if peer.Addr().Is6() {
97                         resp.Peers6 = append(resp.Peers6, krpc.NodeAddr{
98                                 IP:   peer.Addr().AsSlice(),
99                                 Port: int(peer.Port()),
100                         })
101                 }
102         }
103         err = bencode.NewEncoder(w).Encode(resp)
104         if err != nil {
105                 log.Printf("error encoding and writing response body: %v", err)
106         }
107 }