parse-websocket.js
1 import { bin2hex } from 'uint8-util' 2 3 import common from '../common.js' 4 5 export default function (socket, opts, params) { 6 if (!opts) opts = {} 7 params = JSON.parse(params) // may throw 8 9 params.type = 'ws' 10 params.socket = socket 11 if (params.action === 'announce') { 12 params.action = common.ACTIONS.ANNOUNCE 13 14 if (typeof params.info_hash !== 'string' || params.info_hash.length !== 20) { 15 throw new Error('invalid info_hash') 16 } 17 params.info_hash = bin2hex(params.info_hash) 18 19 if (typeof params.peer_id !== 'string' || params.peer_id.length !== 20) { 20 throw new Error('invalid peer_id') 21 } 22 params.peer_id = bin2hex(params.peer_id) 23 24 if (params.answer) { 25 if (typeof params.to_peer_id !== 'string' || params.to_peer_id.length !== 20) { 26 throw new Error('invalid `to_peer_id` (required with `answer`)') 27 } 28 params.to_peer_id = bin2hex(params.to_peer_id) 29 } 30 31 params.left = Number(params.left) 32 if (Number.isNaN(params.left)) params.left = Infinity 33 34 params.numwant = Math.min( 35 Number(params.offers && params.offers.length) || 0, // no default - explicit only 36 common.MAX_ANNOUNCE_PEERS 37 ) 38 params.compact = -1 // return full peer objects (used for websocket responses) 39 } else if (params.action === 'scrape') { 40 params.action = common.ACTIONS.SCRAPE 41 42 if (typeof params.info_hash === 'string') params.info_hash = [params.info_hash] 43 if (Array.isArray(params.info_hash)) { 44 params.info_hash = params.info_hash.map(binaryInfoHash => { 45 if (typeof binaryInfoHash !== 'string' || binaryInfoHash.length !== 20) { 46 throw new Error('invalid info_hash') 47 } 48 return bin2hex(binaryInfoHash) 49 }) 50 } 51 } else { 52 throw new Error(`invalid action in WS request: ${params.action}`) 53 } 54 55 // On first parse, save important data from `socket.upgradeReq` and delete it 56 // to reduce memory usage. 57 if (socket.upgradeReq) { 58 if (opts.trustProxy) { 59 if (socket.upgradeReq.headers['x-forwarded-for']) { 60 const [realIp] = socket.upgradeReq.headers['x-forwarded-for'].split(',') 61 socket.ip = realIp.trim() 62 } else { 63 socket.ip = socket.upgradeReq.connection.remoteAddress 64 } 65 } else { 66 socket.ip = socket.upgradeReq.connection.remoteAddress.replace(common.REMOVE_IPV4_MAPPED_IPV6_RE, '') // force ipv4 67 } 68 69 socket.port = socket.upgradeReq.connection.remotePort 70 if (socket.port) { 71 socket.addr = `${common.IPV6_RE.test(socket.ip) ? `[${socket.ip}]` : socket.ip}:${socket.port}` 72 } 73 74 socket.headers = socket.upgradeReq.headers 75 76 // Delete `socket.upgradeReq` when it is no longer needed to reduce memory usage 77 socket.upgradeReq = null 78 } 79 80 params.ip = socket.ip 81 params.port = socket.port 82 params.addr = socket.addr 83 params.headers = socket.headers 84 85 return params 86 }