Skip to content

Commit bea1021

Browse files
committed
Merge pull request #120 from yciabaud/client-infos
Provide IP and HTTP headers in both HTTP and Websocket server
2 parents 18de340 + af631d9 commit bea1021

File tree

6 files changed

+38
-12
lines changed

6 files changed

+38
-12
lines changed

lib/common-node.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ var querystring = require('querystring')
77

88
exports.IPV4_RE = /^[\d\.]+$/
99
exports.IPV6_RE = /^[\da-fA-F:]+$/
10+
exports.REMOVE_IPV4_MAPPED_IPV6_RE = /^::ffff:/
1011

1112
exports.CONNECTION_ID = Buffer.concat([ toUInt32(0x417), toUInt32(0x27101980) ])
1213
exports.ACTIONS = { CONNECT: 0, ANNOUNCE: 1, SCRAPE: 2, ERROR: 3 }
@@ -23,6 +24,11 @@ exports.EVENT_NAMES = {
2324
started: 'start',
2425
stopped: 'stop'
2526
}
27+
exports.PEER_TYPES = {
28+
http: 'http',
29+
udp: 'udp',
30+
websocket: 'ws'
31+
}
2632

2733
function toUInt32 (n) {
2834
var buf = new Buffer(4)

lib/server/parse-http.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,14 @@ module.exports = parseHttpRequest
22

33
var common = require('../common')
44

5-
var REMOVE_IPV4_MAPPED_IPV6_RE = /^::ffff:/
6-
75
function parseHttpRequest (req, opts) {
86
if (!opts) opts = {}
97
var s = req.url.split('?')
108
var params = common.querystringParse(s[1])
119

1210
if (opts.action === 'announce' || s[0] === '/announce') {
1311
params.action = common.ACTIONS.ANNOUNCE
12+
params.type = common.PEER_TYPES.http
1413

1514
if (typeof params.info_hash !== 'string' || params.info_hash.length !== 20) {
1615
throw new Error('invalid info_hash')
@@ -34,8 +33,10 @@ function parseHttpRequest (req, opts) {
3433

3534
params.ip = opts.trustProxy
3635
? req.headers['x-forwarded-for'] || req.connection.remoteAddress
37-
: req.connection.remoteAddress.replace(REMOVE_IPV4_MAPPED_IPV6_RE, '') // force ipv4
36+
: req.connection.remoteAddress.replace(common.REMOVE_IPV4_MAPPED_IPV6_RE, '') // force ipv4
3837
params.addr = (common.IPV6_RE.test(params.ip) ? '[' + params.ip + ']' : params.ip) + ':' + params.port
38+
39+
params.headers = req.headers
3940
} else if (opts.action === 'scrape' || s[0] === '/scrape') {
4041
params.action = common.ACTIONS.SCRAPE
4142

lib/server/parse-udp.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ function parseUdpRequest (msg, rinfo) {
1010
var params = {
1111
connectionId: msg.slice(0, 8), // 64-bit
1212
action: msg.readUInt32BE(8),
13-
transactionId: msg.readUInt32BE(12)
13+
transactionId: msg.readUInt32BE(12),
14+
type: common.PEER_TYPES.udp
1415
}
1516

1617
if (!bufferEqual(params.connectionId, common.CONNECTION_ID)) {

lib/server/parse-websocket.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ module.exports = parseWebSocketRequest
22

33
var common = require('../common')
44

5-
function parseWebSocketRequest (socket, params) {
5+
function parseWebSocketRequest (socket, opts, params) {
6+
if (!opts) opts = {}
67
params = JSON.parse(params) // may throw
78

89
params.action = common.ACTIONS.ANNOUNCE
10+
params.type = common.PEER_TYPES.websocket
911
params.socket = socket
1012

1113
if (typeof params.info_hash !== 'string' || params.info_hash.length !== 20) {
@@ -32,5 +34,15 @@ function parseWebSocketRequest (socket, params) {
3234
)
3335
params.compact = -1 // return full peer objects (used for websocket responses)
3436

37+
params.ip = opts.trustProxy
38+
? socket.upgradeReq.headers['x-forwarded-for'] || socket.upgradeReq.connection.remoteAddress
39+
: socket.upgradeReq.connection.remoteAddress.replace(common.REMOVE_IPV4_MAPPED_IPV6_RE, '') // force ipv4
40+
params.port = socket.upgradeReq.connection.remotePort
41+
if (params.port) {
42+
params.addr = (common.IPV6_RE.test(params.ip) ? '[' + params.ip + ']' : params.ip) + ':' + params.port
43+
}
44+
45+
params.headers = socket.upgradeReq.headers
46+
3547
return params
3648
}

lib/server/swarm.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ module.exports = Swarm
22

33
var debug = require('debug')('bittorrent-tracker')
44
var randomIterate = require('random-iterate')
5+
var common = require('../common')
56

67
// Regard this as the default implementation of an interface that you
78
// need to support when overriding Server.createSwarm() and Server.getSwarm()
@@ -13,7 +14,8 @@ function Swarm (infoHash, server) {
1314

1415
Swarm.prototype.announce = function (params, cb) {
1516
var self = this
16-
var peer = self.peers[params.addr || params.peer_id]
17+
var id = params.type === common.PEER_TYPES.websocket ? params.peer_id : params.addr
18+
var peer = self.peers[id]
1719

1820
if (params.event === 'started') {
1921
self._onAnnounceStarted(params, peer)
@@ -49,7 +51,8 @@ Swarm.prototype._onAnnounceStarted = function (params, peer) {
4951

5052
if (params.left === 0) this.complete += 1
5153
else this.incomplete += 1
52-
peer = this.peers[params.addr || params.peer_id] = {
54+
var id = params.type === common.PEER_TYPES.websocket ? params.peer_id : params.addr
55+
peer = this.peers[id] = {
5356
complete: params.left === 0,
5457
peerId: params.peer_id, // as hex
5558
ip: params.ip, // only http, udp
@@ -66,7 +69,8 @@ Swarm.prototype._onAnnounceStopped = function (params, peer) {
6669

6770
if (peer.complete) this.complete -= 1
6871
else this.incomplete -= 1
69-
delete this.peers[params.addr || params.peer_id]
72+
var id = params.type === common.PEER_TYPES.websocket ? params.peer_id : params.addr
73+
delete this.peers[id]
7074
}
7175

7276
Swarm.prototype._onAnnounceCompleted = function (params, peer) {

server.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -294,21 +294,23 @@ Server.prototype.onUdpRequest = function (msg, rinfo) {
294294
})
295295
}
296296

297-
Server.prototype.onWebSocketConnection = function (socket) {
297+
Server.prototype.onWebSocketConnection = function (socket, opts) {
298298
var self = this
299+
if (!opts) opts = {}
300+
opts.trustProxy = opts.trustProxy || self._trustProxy
299301
socket.peerId = null // as hex
300302
socket.infoHashes = []
301303
socket.onSend = self._onWebSocketSend.bind(self, socket)
302-
socket.on('message', self._onWebSocketRequest.bind(self, socket))
304+
socket.on('message', self._onWebSocketRequest.bind(self, socket, opts))
303305
socket.on('error', self._onWebSocketError.bind(self, socket))
304306
socket.on('close', self._onWebSocketClose.bind(self, socket))
305307
}
306308

307-
Server.prototype._onWebSocketRequest = function (socket, params) {
309+
Server.prototype._onWebSocketRequest = function (socket, opts, params) {
308310
var self = this
309311

310312
try {
311-
params = parseWebSocketRequest(socket, params)
313+
params = parseWebSocketRequest(socket, opts, params)
312314
} catch (err) {
313315
socket.send(JSON.stringify({
314316
'failure reason': err.message

0 commit comments

Comments
 (0)