Últimos Cambios |
||
Blog personal: El hilo del laberinto |
Última Actualización: 20 de febrero de 2008 - Miércoles
Hace unos días me bajé un torrent pero, al activarlo, el tracker me decía que no existía. Haciendo un "scrap" del tracker compruebo que hay "peers" a los que el torrent funciona sin problemas. Aparentemente se trata, pues, de un problema con BitTornado.
Tras investigar el asunto, llego a la conclusión de que BitTornado está codificando el "announce" al tracker de forma incorrecta. En particular, no está escapando el carácter "/".
BitTornado llama a la rutina "urllib.quote()", pero la emplea mal. La invoca sin darse cuenta de que, por defecto, "urllib.quote()" no escapa el carácter "/", como está claramente documentado en el manual.
El parche es largo pero trivial:
Index: BitTornado/BT1/StreamCheck.py =================================================================== --- BitTornado/BT1/StreamCheck.py (revision 5) +++ BitTornado/BT1/StreamCheck.py (working copy) @@ -40,7 +40,7 @@ def make_readable(s): if not s: return '' - if quote(s).find('%') >= 0: + if quote(s,safe="").find('%') >= 0: return tohex(s) return '"'+s+'"' Index: BitTornado/BT1/HTTPDownloader.py =================================================================== --- BitTornado/BT1/HTTPDownloader.py (revision 5) +++ BitTornado/BT1/HTTPDownloader.py (working copy) @@ -48,7 +48,7 @@ self.seedurl += '?' if query: self.seedurl += query+'&' - self.seedurl += 'info_hash='+quote(self.downloader.infohash) + self.seedurl += 'info_hash='+quote(self.downloader.infohash,safe="") self.measure = Measure(downloader.max_rate_period) self.index = None Index: BitTornado/BT1/track.py =================================================================== --- BitTornado/BT1/track.py (revision 5) +++ BitTornado/BT1/track.py (working copy) @@ -451,7 +451,7 @@ szt = sz * n # Transferred for this torrent tt = tt + szt if self.allow_get == 1: - linkname = '<a href="/file?info_hash=' + quote(hash) + '">' + name + '</a>' + linkname = '<a href="/file?info_hash=' + quote(hash,safe="") + '">' + name + '</a>' else: linkname = name s.write('<tr><td><code>%s</code></td><td>%s</td><td align="right">%s</td><td align="right">%i</td><td align="right">%i</td><td align="right">%i</td><td align="right">%s</td></tr>\n' \ @@ -906,7 +906,7 @@ def natchecklog(self, peerid, ip, port, result): year, month, day, hour, minute, second, a, b, c = localtime(time()) print '%s - %s [%02d/%3s/%04d:%02d:%02d:%02d] "!natcheck-%s:%i" %i 0 - -' % ( - ip, quote(peerid), day, months[month], year, hour, minute, second, + ip, quote(peerid,safe=""), day, months[month], year, hour, minute, second, ip, port, result) def connectback_result(self, result, downloadid, peerid, ip, port): Index: BitTornado/BT1/Rerequester.py =================================================================== --- BitTornado/BT1/Rerequester.py (revision 5) +++ BitTornado/BT1/Rerequester.py (working copy) @@ -70,7 +70,7 @@ self.rejectedmessage = 'rejected by tracker - ' self.url = ('?info_hash=%s&peer_id=%s&port=%s' % - (quote(infohash), quote(myid), str(port))) + (quote(infohash,safe=""), quote(myid,safe=""), str(port))) self.ip = ip self.interval = interval self.last = None @@ -92,7 +92,7 @@ self.downratefunc = downratefunc self.unpauseflag = unpauseflag if seed_id: - self.url += '&seed_id='+quote(seed_id) + self.url += '&seed_id='+quote(seed_id,safe="") self.seededfunc = seededfunc if seededfunc: self.url += '&check_seeded=1' @@ -160,9 +160,9 @@ (self.url, str(self.up()), str(self.down()), str(self.amount_left()))) if self.last is not None: - s += '&last=' + quote(str(self.last)) + s += '&last=' + quote(str(self.last,safe="")) if self.trackerid is not None: - s += '&trackerid=' + quote(str(self.trackerid)) + s += '&trackerid=' + quote(str(self.trackerid),safe="") if self.howmany() >= self.maxpeers: s += '&numwant=0' else: Index: BitTornado/BT1/T2T.py =================================================================== --- BitTornado/BT1/T2T.py (revision 5) +++ BitTornado/BT1/T2T.py (working copy) @@ -62,7 +62,7 @@ self.lastsuccessful = True self.newpeerdata = [] if DEBUG: - print 'contacting %s for info_hash=%s' % (self.tracker, quote(self.hash)) + print 'contacting %s for info_hash=%s' % (self.tracker, quote(self.hash,safe="")) self.rerequester.snoop(self.peers, self.callback) def callback(self): @@ -76,7 +76,7 @@ self.operatinginterval = self.rerequester.announce_interval if DEBUG: print ("%s with info_hash=%s returned %d peers" % - (self.tracker, quote(self.hash), len(self.newpeerdata))) + (self.tracker, quote(self.hash,safe=""), len(self.newpeerdata))) self.peerlists.append(self.newpeerdata) self.peerlists = self.peerlists[-10:] # keep up to the last 10 announces if self.isactive(): @@ -89,7 +89,7 @@ def errorfunc(self, r): self.lastsuccessful = False if DEBUG: - print "%s with info_hash=%s gives error: '%s'" % (self.tracker, quote(self.hash), r) + print "%s with info_hash=%s gives error: '%s'" % (self.tracker, quote(self.hash,safe=""), r) if r == self.rerequester.rejectedmessage + 'disallowed': # whoops! if DEBUG: print ' -- disallowed - deactivating' Index: BitTornado/BT1/Encrypter.py =================================================================== --- BitTornado/BT1/Encrypter.py (revision 5) +++ BitTornado/BT1/Encrypter.py (working copy) @@ -38,7 +38,7 @@ def make_readable(s): if not s: return '' - if quote(s).find('%') >= 0: + if quote(s,safe="").find('%') >= 0: return tohex(s) return '"'+s+'"'
El parche se limita a cambiar las llamadas a "urllib.quote()" para que se escape también el carácter "/". Se podría haber hecho más simple utilizando la técnica que ya expliqué hace unos meses, pero -en este caso concreto- prefiero hacerlo explícito.
Mi agradecimiento a Adriá por ayudarme a diagnosticar el problema.
Más información sobre los OpenBadges
Donación BitCoin: 19niBN42ac2pqDQFx6GJZxry2JQSFvwAfS