-
-
Notifications
You must be signed in to change notification settings - Fork 335
Use hex info_hash and peer_id throughout #47
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,48 +11,44 @@ function parseHttpRequest (req, options) { | |
| if (s[0] === '/announce') { | ||
| params.action = common.ACTIONS.ANNOUNCE | ||
|
|
||
| params.peer_id = typeof params.peer_id === 'string' && common.binaryToUtf8(params.peer_id) | ||
| params.port = Number(params.port) | ||
| if (typeof params.info_hash !== 'string' || params.info_hash.length !== 20) | ||
| throw new Error('invalid info_hash') | ||
| params.info_hash = common.binaryToHex(params.info_hash) | ||
| if (typeof params.peer_id !== 'string' || params.peer_id.length !== 20) | ||
| throw new Error('invalid peer_id') | ||
| params.peer_id = common.binaryToHex(params.peer_id) | ||
|
|
||
| if (typeof params.info_hash !== 'string') throw new Error('invalid info_hash') | ||
| if (params.info_hash.length !== 20) throw new Error('invalid info_hash length') | ||
| if (typeof params.peer_id !== 'string') throw new Error('invalid peer_id') | ||
| if (params.peer_id.length !== 20) throw new Error('invalid peer_id length') | ||
| params.port = Number(params.port) | ||
| if (!params.port) throw new Error('invalid port') | ||
|
|
||
| params.left = Number(params.left) | ||
| params.compact = Number(params.compact) | ||
| params.numwant = Math.min( | ||
| Number(params.numwant) || common.NUM_ANNOUNCE_PEERS, | ||
| common.MAX_ANNOUNCE_PEERS | ||
| ) | ||
|
|
||
| params.ip = options.trustProxy | ||
| ? req.headers['x-forwarded-for'] || req.connection.remoteAddress | ||
| : req.connection.remoteAddress.replace(REMOVE_IPV6_RE, '') // force ipv4 | ||
| params.addr = params.ip + ':' + params.port // TODO: ipv6 brackets? | ||
|
|
||
| params.numwant = Math.min( | ||
| Number(params.numwant) || common.NUM_ANNOUNCE_PEERS, | ||
| common.MAX_ANNOUNCE_PEERS | ||
| ) | ||
|
|
||
| return params | ||
| } else if (s[0] === '/scrape') { // unofficial scrape message | ||
| params.action = common.ACTIONS.SCRAPE | ||
|
|
||
| if (typeof params.info_hash === 'string') { | ||
| if (typeof params.info_hash === 'string') | ||
| params.info_hash = [ params.info_hash ] | ||
| } | ||
|
|
||
| if (params.info_hash) { | ||
| if (!Array.isArray(params.info_hash)) throw new Error('invalid info_hash array') | ||
|
|
||
| params.info_hash.forEach(function (infoHash) { | ||
| if (infoHash.length !== 20) { | ||
| if (Array.isArray(params.info_hash)) { | ||
| params.info_hash = params.info_hash.map(function (binaryInfoHash) { | ||
| if (typeof binaryInfoHash !== 'string' || binaryInfoHash.length !== 20) | ||
| throw new Error('invalid info_hash') | ||
| } | ||
| return common.binaryToHex(binaryInfoHash) | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's the job of the parse functions to convert info_hash and peer_id into hex. |
||
| }) | ||
| } | ||
|
|
||
| return params | ||
| } else { | ||
| return null | ||
| throw new Error('Invalid action in HTTP request: ' + params.action) | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. made this consistent with udp parsing where we throw on invalid action |
||
| } | ||
|
|
||
| return params | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,13 +5,11 @@ var ipLib = require('ip') | |
| var common = require('./common') | ||
|
|
||
| function parseUdpRequest (msg, rinfo) { | ||
| if (msg.length < 16) { | ||
| if (msg.length < 16) | ||
| throw new Error('received packet is too short') | ||
| } | ||
|
|
||
| if (rinfo.family !== 'IPv4') { | ||
| if (rinfo.family !== 'IPv4') | ||
| throw new Error('udp tracker does not support IPv6') | ||
| } | ||
|
|
||
| var params = { | ||
| connectionId: msg.slice(0, 8), // 64-bit | ||
|
|
@@ -20,41 +18,46 @@ function parseUdpRequest (msg, rinfo) { | |
| } | ||
|
|
||
| // TODO: randomize | ||
| if (!bufferEqual(params.connectionId, common.CONNECTION_ID)) { | ||
| if (!bufferEqual(params.connectionId, common.CONNECTION_ID)) | ||
| throw new Error('received packet with invalid connection id') | ||
| } | ||
|
|
||
| if (params.action === common.ACTIONS.CONNECT) { | ||
| // No further params | ||
|
|
||
| } else if (params.action === common.ACTIONS.ANNOUNCE) { | ||
| params.info_hash = msg.slice(16, 36).toString('binary') // 20 bytes | ||
| params.peer_id = msg.slice(36, 56).toString('utf8') // 20 bytes | ||
| params.info_hash = msg.slice(16, 36).toString('hex') // 20 bytes | ||
| params.peer_id = msg.slice(36, 56).toString('hex') // 20 bytes | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's the job of the parse functions to convert info_hash and peer_id into hex. |
||
| params.downloaded = fromUInt64(msg.slice(56, 64)) // TODO: track this? | ||
| params.left = fromUInt64(msg.slice(64, 72)) | ||
| params.uploaded = fromUInt64(msg.slice(72, 80)) // TODO: track this? | ||
| params.event = msg.readUInt32BE(80) | ||
| params.event = common.EVENT_IDS[params.event] | ||
|
|
||
| params.event = common.EVENT_IDS[msg.readUInt32BE(80)] | ||
| if (!params.event) throw new Error('invalid event') // early return | ||
| params.ip = msg.readUInt32BE(84) // optional | ||
| params.ip = params.ip ? | ||
| ipLib.toString(params.ip) : | ||
| rinfo.address | ||
|
|
||
| var ip = msg.readUInt32BE(84) // optional | ||
| params.ip = ip | ||
| ? ipLib.toString(ip) | ||
| : rinfo.address | ||
|
|
||
| params.key = msg.readUInt32BE(88) // TODO: what is this for? | ||
| params.numwant = msg.readUInt32BE(92) // optional | ||
|
|
||
| // never send more than MAX_ANNOUNCE_PEERS or else the UDP packet will get bigger than | ||
| // 512 bytes which is not safe | ||
| params.numwant = Math.min(params.numwant || common.NUM_ANNOUNCE_PEERS, common.MAX_ANNOUNCE_PEERS) | ||
| params.numwant = Math.min( | ||
| msg.readUInt32BE(92) || common.NUM_ANNOUNCE_PEERS, // optional | ||
| common.MAX_ANNOUNCE_PEERS | ||
| ) | ||
|
|
||
| params.port = msg.readUInt16BE(96) || rinfo.port // optional | ||
| params.addr = params.ip + ':' + params.port // TODO: ipv6 brackets | ||
| params.compact = 1 // udp is always compact | ||
|
|
||
| } else if (params.action === common.ACTIONS.SCRAPE) { // scrape message | ||
| params.info_hash = msg.slice(16, 36).toString('binary') // 20 bytes | ||
|
|
||
| // TODO: support multiple info_hash scrape | ||
| if (msg.length > 36) { | ||
| throw new Error('multiple info_hash scrape not supported') | ||
| } | ||
| if (msg.length > 36) throw new Error('multiple info_hash scrape not supported') | ||
|
|
||
| params.info_hash = [ msg.slice(16, 36).toString('hex') ] // 20 bytes | ||
|
|
||
| } else { | ||
| throw new Error('Invalid action in UDP packet: ' + params.action) | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -115,13 +115,11 @@ Server.prototype.close = function (cb) { | |
| } | ||
| } | ||
|
|
||
| Server.prototype.getSwarm = function (binaryInfoHash) { | ||
| Server.prototype.getSwarm = function (infoHash) { | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a breaking change. I propose this only accept hex strings and buffers now. No one wants to work with binary strings and none of the other webtorrent modules do. |
||
| var self = this | ||
| if (Buffer.isBuffer(binaryInfoHash)) binaryInfoHash = binaryInfoHash.toString('binary') | ||
| var swarm = self.torrents[binaryInfoHash] | ||
| if (!swarm) { | ||
| swarm = self.torrents[binaryInfoHash] = new Swarm(binaryInfoHash, this) | ||
| } | ||
| if (Buffer.isBuffer(infoHash)) infoHash = infoHash.toString('hex') | ||
| var swarm = self.torrents[infoHash] | ||
| if (!swarm) swarm = self.torrents[infoHash] = new Swarm(infoHash, this) | ||
| return swarm | ||
| } | ||
|
|
||
|
|
@@ -130,9 +128,7 @@ Server.prototype._onHttpRequest = function (req, res) { | |
|
|
||
| var params | ||
| try { | ||
| params = parseHttpRequest(req, { | ||
| trustProxy: self._trustProxy | ||
| }) | ||
| params = parseHttpRequest(req, { trustProxy: self._trustProxy }) | ||
| } catch (err) { | ||
| debug('sent error %s', err.message) | ||
| res.end(bencode.encode({ | ||
|
|
@@ -142,7 +138,7 @@ Server.prototype._onHttpRequest = function (req, res) { | |
| // even though it's an error for the client, it's just a warning for the server. | ||
| // don't crash the server because a client sent bad data :) | ||
| self.emit('warning', err) | ||
|
|
||
| return | ||
| } | ||
|
|
||
|
|
@@ -225,28 +221,12 @@ Server.prototype._onAnnounce = function (params, cb) { | |
| Server.prototype._onScrape = function (params, cb) { | ||
| var self = this | ||
|
|
||
| if (typeof params.info_hash === 'string') { | ||
| params.info_hash = [ params.info_hash ] | ||
| } else if (params.info_hash == null) { | ||
| if (params.info_hash == null) { | ||
| // if info_hash param is omitted, stats for all torrents are returned | ||
| // TODO: make this configurable! | ||
| params.info_hash = Object.keys(self.torrents) | ||
| } | ||
|
|
||
| if (!Array.isArray(params.info_hash)) { | ||
| var err = new Error('invalid info_hash') | ||
| self.emit('warning', err) | ||
| return cb(err) | ||
| } | ||
|
|
||
| var response = { | ||
| action: common.ACTIONS.SCRAPE, | ||
| files: {}, | ||
| flags: { | ||
| min_request_interval: self._intervalMs | ||
| } | ||
| } | ||
|
|
||
| series(params.info_hash.map(function (infoHash) { | ||
| var swarm = self.getSwarm(infoHash) | ||
| return function (cb) { | ||
|
|
@@ -261,8 +241,14 @@ Server.prototype._onScrape = function (params, cb) { | |
| }), function (err, results) { | ||
| if (err) return cb(err) | ||
|
|
||
| var response = { | ||
| action: common.ACTIONS.SCRAPE, | ||
| files: {}, | ||
| flags: { min_request_interval: self._intervalMs } | ||
| } | ||
|
|
||
| results.forEach(function (result) { | ||
| response.files[result.infoHash] = { | ||
| response.files[common.hexToBinary(result.infoHash)] = { | ||
| complete: result.complete, | ||
| incomplete: result.incomplete, | ||
| downloaded: result.complete // TODO: this only provides a lower-bound | ||
|
|
@@ -273,7 +259,6 @@ Server.prototype._onScrape = function (params, cb) { | |
| }) | ||
| } | ||
|
|
||
|
|
||
| function makeUdpPacket (params) { | ||
| switch (params.action) { | ||
| case common.ACTIONS.CONNECT: | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: this is a breaking change