diff --git a/server/announce.go b/server/announce.go index 6df632c..84c57a2 100644 --- a/server/announce.go +++ b/server/announce.go @@ -11,12 +11,15 @@ import ( "net/http" "path" "strconv" - "time" - - "github.com/pushrax/chihaya/storage" ) func (s *Server) serveAnnounce(w http.ResponseWriter, r *http.Request) { + compact, numWant, infohash, peerID, event, ip, port, uploaded, downloaded, left, err := s.validateAnnounceQuery(r) + if err != nil { + fail(err, w, r) + return + } + passkey, _ := path.Split(r.URL.Path) user, err := s.FindUser(passkey) if err != nil { @@ -24,23 +27,16 @@ func (s *Server) serveAnnounce(w http.ResponseWriter, r *http.Request) { return } - aq, err := newAnnounceQuery(r) - if err != nil { - fail(errors.New("Malformed request"), w, r) - return - } - - peerID := aq.PeerID() - ok, err := s.dataStore.ClientWhitelisted(peerID) + whitelisted, err := s.dataStore.ClientWhitelisted(peerID) if err != nil { log.Panicf("server: %s", err) } - if !ok { + if !whitelisted { fail(errors.New("Your client is not approved"), w, r) return } - torrent, exists, err := s.dataStore.FindTorrent(aq.Infohash()) + torrent, exists, err := s.dataStore.FindTorrent(infohash) if err != nil { log.Panicf("server: %s", err) } @@ -54,7 +50,6 @@ func (s *Server) serveAnnounce(w http.ResponseWriter, r *http.Request) { log.Panicf("server: %s", err) } - left := aq.Left() if torrent.Pruned && left == 0 { err := tx.Unprune(torrent.ID) if err != nil { @@ -66,9 +61,7 @@ func (s *Server) serveAnnounce(w http.ResponseWriter, r *http.Request) { return } - _ = aq.NumWant(s.conf.DefaultNumWant) - - if s.conf.Slots && user.Slots != -1 && aq.Left() != 0 { + if s.conf.Slots && user.Slots != -1 && left != 0 { if user.UsedSlots >= user.Slots { fail(errors.New("You've run out of download slots."), w, r) return @@ -78,7 +71,6 @@ func (s *Server) serveAnnounce(w http.ResponseWriter, r *http.Request) { _, isLeecher := torrent.Leechers[peerID] _, isSeeder := torrent.Seeders[peerID] - event := aq.Event() completed := "completed" == event if event == "stopped" || event == "paused" { @@ -103,119 +95,55 @@ func (s *Server) serveAnnounce(w http.ResponseWriter, r *http.Request) { log.Panicf("server: %s", err) } } - } -// An AnnounceQuery is a parsedQuery that guarantees the existance -// of parameters required for torrent client announces. -type announceQuery struct { - pq *parsedQuery - ip string - created int64 -} - -func newAnnounceQuery(r *http.Request) (*announceQuery, error) { +func (s *Server) validateAnnounceQuery(r *http.Request) (compact bool, numWant int, infohash, peerID, event, ip string, port, uploaded, downloaded, left uint64, err error) { pq, err := parseQuery(r.URL.RawQuery) if err != nil { - return nil, err + return false, 0, "", "", "", "", 0, 0, 0, 0, err } - infohash, _ := pq.Params["info_hash"] - if infohash == "" { - return nil, errors.New("infohash does not exist") - } - peerId, _ := pq.Params["peer_id"] - if peerId == "" { - return nil, errors.New("peerId does not exist") - } - _, err = pq.getUint64("port") - if err != nil { - return nil, errors.New("port does not exist") - } - _, err = pq.getUint64("uploaded") - if err != nil { - return nil, errors.New("uploaded does not exist") - } - _, err = pq.getUint64("downloaded") - if err != nil { - return nil, errors.New("downloaded does not exist") - } - _, err = pq.getUint64("left") - if err != nil { - return nil, errors.New("left does not exist") - } + compact = pq.Params["compact"] == "1" + numWant = determineNumWant(s.conf.DefaultNumWant, pq) + infohash, _ = pq.Params["info_hash"] + peerID, _ = pq.Params["peer_id"] + event, _ = pq.Params["event"] + ip, _ = determineIP(r, pq) + port, portErr := pq.getUint64("port") + uploaded, uploadedErr := pq.getUint64("uploaded") + downloaded, downloadedErr := pq.getUint64("downloaded") + left, leftErr := pq.getUint64("left") - aq := &announceQuery{ - pq: pq, - created: time.Now().Unix(), + if infohash == "" || + peerID == "" || + ip == "" || + portErr == nil || + uploadedErr == nil || + downloadedErr == nil || + leftErr == nil { + return false, 0, "", "", "", "", 0, 0, 0, 0, errors.New("Malformed request") } - aq.ip, err = aq.determineIP(r) - if err != nil { - return nil, err - } - return aq, nil + return } -func (aq *announceQuery) Infohash() string { - infohash, _ := aq.pq.Params["info_hash"] - if infohash == "" { - panic("announceQuery missing infohash") +func determineNumWant(fallback int, pq *parsedQuery) int { + if numWantStr, exists := pq.Params["numWant"]; exists { + numWant, err := strconv.Atoi(numWantStr) + if err != nil { + return fallback + } + return numWant + } else { + return fallback } - return infohash } -func (aq *announceQuery) PeerID() string { - peerID, _ := aq.pq.Params["peer_id"] - if peerID == "" { - panic("announceQuery missing peer_id") - } - return peerID -} - -func (aq *announceQuery) Port() uint64 { - port, err := aq.pq.getUint64("port") - if err != nil { - panic("announceQuery missing port") - } - return port -} - -func (aq *announceQuery) IP() string { - return aq.ip -} - -func (aq *announceQuery) Uploaded() uint64 { - ul, err := aq.pq.getUint64("uploaded") - if err != nil { - panic("announceQuery missing uploaded") - } - return ul -} -func (aq *announceQuery) Downloaded() uint64 { - dl, err := aq.pq.getUint64("downloaded") - if err != nil { - panic("announceQuery missing downloaded") - } - return dl -} -func (aq *announceQuery) Left() uint64 { - left, err := aq.pq.getUint64("left") - if err != nil { - panic("announceQuery missing left") - } - return left -} - -func (aq *announceQuery) Event() string { - return aq.pq.Params["event"] -} - -func (aq *announceQuery) determineIP(r *http.Request) (string, error) { - if ip, ok := aq.pq.Params["ip"]; ok { +func determineIP(r *http.Request, pq *parsedQuery) (string, error) { + if ip, ok := pq.Params["ip"]; ok { return ip, nil - } else if ip, ok := aq.pq.Params["ipv4"]; ok { + } else if ip, ok := pq.Params["ipv4"]; ok { return ip, nil - } else if ips, ok := aq.pq.Params["X-Real-Ip"]; ok && len(ips) > 0 { + } else if ips, ok := pq.Params["X-Real-Ip"]; ok && len(ips) > 0 { return string(ips[0]), nil } else { portIndex := len(r.RemoteAddr) - 1 @@ -231,30 +159,3 @@ func (aq *announceQuery) determineIP(r *http.Request) (string, error) { } } } - -func (aq *announceQuery) NumWant(fallback int) int { - if numWantStr, exists := aq.pq.Params["numWant"]; exists { - numWant, err := strconv.Atoi(numWantStr) - if err != nil { - return fallback - } - return numWant - } else { - return fallback - } -} - -func (aq *announceQuery) Peer(uid, tid uint64) *storage.Peer { - return &storage.Peer{ - ID: aq.PeerID(), - UserID: uid, - TorrentID: tid, - - IP: aq.IP(), - Port: aq.Port(), - - LastAnnounce: aq.created, - Uploaded: aq.Uploaded(), - Downloaded: aq.Downloaded(), - } -}