mirror of
https://github.com/webtorrent/bittorrent-tracker.git
synced 2024-12-14 11:26:25 +00:00
Merge pull request #120 from yciabaud/client-infos
Provide IP and HTTP headers in both HTTP and Websocket server
This commit is contained in:
commit
bea1021ec6
@ -7,6 +7,7 @@ var querystring = require('querystring')
|
|||||||
|
|
||||||
exports.IPV4_RE = /^[\d\.]+$/
|
exports.IPV4_RE = /^[\d\.]+$/
|
||||||
exports.IPV6_RE = /^[\da-fA-F:]+$/
|
exports.IPV6_RE = /^[\da-fA-F:]+$/
|
||||||
|
exports.REMOVE_IPV4_MAPPED_IPV6_RE = /^::ffff:/
|
||||||
|
|
||||||
exports.CONNECTION_ID = Buffer.concat([ toUInt32(0x417), toUInt32(0x27101980) ])
|
exports.CONNECTION_ID = Buffer.concat([ toUInt32(0x417), toUInt32(0x27101980) ])
|
||||||
exports.ACTIONS = { CONNECT: 0, ANNOUNCE: 1, SCRAPE: 2, ERROR: 3 }
|
exports.ACTIONS = { CONNECT: 0, ANNOUNCE: 1, SCRAPE: 2, ERROR: 3 }
|
||||||
@ -23,6 +24,11 @@ exports.EVENT_NAMES = {
|
|||||||
started: 'start',
|
started: 'start',
|
||||||
stopped: 'stop'
|
stopped: 'stop'
|
||||||
}
|
}
|
||||||
|
exports.PEER_TYPES = {
|
||||||
|
http: 'http',
|
||||||
|
udp: 'udp',
|
||||||
|
websocket: 'ws'
|
||||||
|
}
|
||||||
|
|
||||||
function toUInt32 (n) {
|
function toUInt32 (n) {
|
||||||
var buf = new Buffer(4)
|
var buf = new Buffer(4)
|
||||||
|
@ -2,8 +2,6 @@ module.exports = parseHttpRequest
|
|||||||
|
|
||||||
var common = require('../common')
|
var common = require('../common')
|
||||||
|
|
||||||
var REMOVE_IPV4_MAPPED_IPV6_RE = /^::ffff:/
|
|
||||||
|
|
||||||
function parseHttpRequest (req, opts) {
|
function parseHttpRequest (req, opts) {
|
||||||
if (!opts) opts = {}
|
if (!opts) opts = {}
|
||||||
var s = req.url.split('?')
|
var s = req.url.split('?')
|
||||||
@ -11,6 +9,7 @@ function parseHttpRequest (req, opts) {
|
|||||||
|
|
||||||
if (opts.action === 'announce' || s[0] === '/announce') {
|
if (opts.action === 'announce' || s[0] === '/announce') {
|
||||||
params.action = common.ACTIONS.ANNOUNCE
|
params.action = common.ACTIONS.ANNOUNCE
|
||||||
|
params.type = common.PEER_TYPES.http
|
||||||
|
|
||||||
if (typeof params.info_hash !== 'string' || params.info_hash.length !== 20) {
|
if (typeof params.info_hash !== 'string' || params.info_hash.length !== 20) {
|
||||||
throw new Error('invalid info_hash')
|
throw new Error('invalid info_hash')
|
||||||
@ -34,8 +33,10 @@ function parseHttpRequest (req, opts) {
|
|||||||
|
|
||||||
params.ip = opts.trustProxy
|
params.ip = opts.trustProxy
|
||||||
? req.headers['x-forwarded-for'] || req.connection.remoteAddress
|
? req.headers['x-forwarded-for'] || req.connection.remoteAddress
|
||||||
: req.connection.remoteAddress.replace(REMOVE_IPV4_MAPPED_IPV6_RE, '') // force ipv4
|
: req.connection.remoteAddress.replace(common.REMOVE_IPV4_MAPPED_IPV6_RE, '') // force ipv4
|
||||||
params.addr = (common.IPV6_RE.test(params.ip) ? '[' + params.ip + ']' : params.ip) + ':' + params.port
|
params.addr = (common.IPV6_RE.test(params.ip) ? '[' + params.ip + ']' : params.ip) + ':' + params.port
|
||||||
|
|
||||||
|
params.headers = req.headers
|
||||||
} else if (opts.action === 'scrape' || s[0] === '/scrape') {
|
} else if (opts.action === 'scrape' || s[0] === '/scrape') {
|
||||||
params.action = common.ACTIONS.SCRAPE
|
params.action = common.ACTIONS.SCRAPE
|
||||||
|
|
||||||
|
@ -10,7 +10,8 @@ function parseUdpRequest (msg, rinfo) {
|
|||||||
var params = {
|
var params = {
|
||||||
connectionId: msg.slice(0, 8), // 64-bit
|
connectionId: msg.slice(0, 8), // 64-bit
|
||||||
action: msg.readUInt32BE(8),
|
action: msg.readUInt32BE(8),
|
||||||
transactionId: msg.readUInt32BE(12)
|
transactionId: msg.readUInt32BE(12),
|
||||||
|
type: common.PEER_TYPES.udp
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bufferEqual(params.connectionId, common.CONNECTION_ID)) {
|
if (!bufferEqual(params.connectionId, common.CONNECTION_ID)) {
|
||||||
|
@ -2,10 +2,12 @@ module.exports = parseWebSocketRequest
|
|||||||
|
|
||||||
var common = require('../common')
|
var common = require('../common')
|
||||||
|
|
||||||
function parseWebSocketRequest (socket, params) {
|
function parseWebSocketRequest (socket, opts, params) {
|
||||||
|
if (!opts) opts = {}
|
||||||
params = JSON.parse(params) // may throw
|
params = JSON.parse(params) // may throw
|
||||||
|
|
||||||
params.action = common.ACTIONS.ANNOUNCE
|
params.action = common.ACTIONS.ANNOUNCE
|
||||||
|
params.type = common.PEER_TYPES.websocket
|
||||||
params.socket = socket
|
params.socket = socket
|
||||||
|
|
||||||
if (typeof params.info_hash !== 'string' || params.info_hash.length !== 20) {
|
if (typeof params.info_hash !== 'string' || params.info_hash.length !== 20) {
|
||||||
@ -32,5 +34,15 @@ function parseWebSocketRequest (socket, params) {
|
|||||||
)
|
)
|
||||||
params.compact = -1 // return full peer objects (used for websocket responses)
|
params.compact = -1 // return full peer objects (used for websocket responses)
|
||||||
|
|
||||||
|
params.ip = opts.trustProxy
|
||||||
|
? socket.upgradeReq.headers['x-forwarded-for'] || socket.upgradeReq.connection.remoteAddress
|
||||||
|
: socket.upgradeReq.connection.remoteAddress.replace(common.REMOVE_IPV4_MAPPED_IPV6_RE, '') // force ipv4
|
||||||
|
params.port = socket.upgradeReq.connection.remotePort
|
||||||
|
if (params.port) {
|
||||||
|
params.addr = (common.IPV6_RE.test(params.ip) ? '[' + params.ip + ']' : params.ip) + ':' + params.port
|
||||||
|
}
|
||||||
|
|
||||||
|
params.headers = socket.upgradeReq.headers
|
||||||
|
|
||||||
return params
|
return params
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ module.exports = Swarm
|
|||||||
|
|
||||||
var debug = require('debug')('bittorrent-tracker')
|
var debug = require('debug')('bittorrent-tracker')
|
||||||
var randomIterate = require('random-iterate')
|
var randomIterate = require('random-iterate')
|
||||||
|
var common = require('../common')
|
||||||
|
|
||||||
// Regard this as the default implementation of an interface that you
|
// Regard this as the default implementation of an interface that you
|
||||||
// need to support when overriding Server.createSwarm() and Server.getSwarm()
|
// need to support when overriding Server.createSwarm() and Server.getSwarm()
|
||||||
@ -13,7 +14,8 @@ function Swarm (infoHash, server) {
|
|||||||
|
|
||||||
Swarm.prototype.announce = function (params, cb) {
|
Swarm.prototype.announce = function (params, cb) {
|
||||||
var self = this
|
var self = this
|
||||||
var peer = self.peers[params.addr || params.peer_id]
|
var id = params.type === common.PEER_TYPES.websocket ? params.peer_id : params.addr
|
||||||
|
var peer = self.peers[id]
|
||||||
|
|
||||||
if (params.event === 'started') {
|
if (params.event === 'started') {
|
||||||
self._onAnnounceStarted(params, peer)
|
self._onAnnounceStarted(params, peer)
|
||||||
@ -49,7 +51,8 @@ Swarm.prototype._onAnnounceStarted = function (params, peer) {
|
|||||||
|
|
||||||
if (params.left === 0) this.complete += 1
|
if (params.left === 0) this.complete += 1
|
||||||
else this.incomplete += 1
|
else this.incomplete += 1
|
||||||
peer = this.peers[params.addr || params.peer_id] = {
|
var id = params.type === common.PEER_TYPES.websocket ? params.peer_id : params.addr
|
||||||
|
peer = this.peers[id] = {
|
||||||
complete: params.left === 0,
|
complete: params.left === 0,
|
||||||
peerId: params.peer_id, // as hex
|
peerId: params.peer_id, // as hex
|
||||||
ip: params.ip, // only http, udp
|
ip: params.ip, // only http, udp
|
||||||
@ -66,7 +69,8 @@ Swarm.prototype._onAnnounceStopped = function (params, peer) {
|
|||||||
|
|
||||||
if (peer.complete) this.complete -= 1
|
if (peer.complete) this.complete -= 1
|
||||||
else this.incomplete -= 1
|
else this.incomplete -= 1
|
||||||
delete this.peers[params.addr || params.peer_id]
|
var id = params.type === common.PEER_TYPES.websocket ? params.peer_id : params.addr
|
||||||
|
delete this.peers[id]
|
||||||
}
|
}
|
||||||
|
|
||||||
Swarm.prototype._onAnnounceCompleted = function (params, peer) {
|
Swarm.prototype._onAnnounceCompleted = function (params, peer) {
|
||||||
|
10
server.js
10
server.js
@ -294,21 +294,23 @@ Server.prototype.onUdpRequest = function (msg, rinfo) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
Server.prototype.onWebSocketConnection = function (socket) {
|
Server.prototype.onWebSocketConnection = function (socket, opts) {
|
||||||
var self = this
|
var self = this
|
||||||
|
if (!opts) opts = {}
|
||||||
|
opts.trustProxy = opts.trustProxy || self._trustProxy
|
||||||
socket.peerId = null // as hex
|
socket.peerId = null // as hex
|
||||||
socket.infoHashes = []
|
socket.infoHashes = []
|
||||||
socket.onSend = self._onWebSocketSend.bind(self, socket)
|
socket.onSend = self._onWebSocketSend.bind(self, socket)
|
||||||
socket.on('message', self._onWebSocketRequest.bind(self, socket))
|
socket.on('message', self._onWebSocketRequest.bind(self, socket, opts))
|
||||||
socket.on('error', self._onWebSocketError.bind(self, socket))
|
socket.on('error', self._onWebSocketError.bind(self, socket))
|
||||||
socket.on('close', self._onWebSocketClose.bind(self, socket))
|
socket.on('close', self._onWebSocketClose.bind(self, socket))
|
||||||
}
|
}
|
||||||
|
|
||||||
Server.prototype._onWebSocketRequest = function (socket, params) {
|
Server.prototype._onWebSocketRequest = function (socket, opts, params) {
|
||||||
var self = this
|
var self = this
|
||||||
|
|
||||||
try {
|
try {
|
||||||
params = parseWebSocketRequest(socket, params)
|
params = parseWebSocketRequest(socket, opts, params)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
socket.send(JSON.stringify({
|
socket.send(JSON.stringify({
|
||||||
'failure reason': err.message
|
'failure reason': err.message
|
||||||
|
Loading…
Reference in New Issue
Block a user