提供远程会话ID后,远程传输会话不响应

那么这将是一个相当晦涩的话题,但我会试一试,也许有人会知道答案。

我正在为传输BitTorrent客户端写一个小型的远程Node.js客户端。 通信通过使用JSON对象的RPC进行处理。

这是规范 。

而我的代码(用CoffeeScript编写,如果这是一个问题,我也可以提供相应的JavaScript代码,只是不想让这个问题太长而无法阅读),重要的部分:

runRemoteCommand: (params) -> # convert JSON object to string params = JSON.stringify params #, null, " " # set request options options = host: @config.host port: @config.port path: @config.rpcPath auth: "#{@config.username}:#{@config.password}" headers: 'Content-Type': 'application/json' 'Content-Length': params.length method: 'GET' # we don't know the session id yet sessionId = false # wrapped in a function so it could be run two times, not really a finished solution run = () => # If the session id is provided, set the header, as in 2.3.1 of the specs if sessionId options.headers["X-Transmission-Session-Id"] = sessionId # define the request object and a callback for the response request = @http.get options, (response) => # log everything for debug purposes console.log "STATUS: #{response.statusCode}" console.log "HEADERS: #{JSON.stringify response.headers}" response.setEncoding 'utf8' response.on "data", (data) => console.log "BODY: #{data}" # if status code is 409, use provided session id if response.statusCode == 409 sessionId = response.headers["x-transmission-session-id"] console.log "sessionId: #{sessionId}" # running it immediately sometimes caused the remote server to provide a 501 error, so I gave it a timeout setTimeout run, 5000 # no output here request.on "error", (e) => console.log "ERROR: #{e}" # actually send the request request.write params request.end() # run our function run() 

paramsvariables被定义为:

 params = "arguments": "filename": link "method": "torrent-add" "tag": 6667 

一切工作正常,直到我设置一个有效的会话ID。 在第一次run函数被调用时,我得到了下面的输出(格式化了一点,以使其更加人性化):

状态:409

头:

 { "server":"Transmission", "x-transmission-session-id":"io4dOLm8Q33aSCEULW0iv74SeewJ3w1tP21L7qkdS4QktIkR", "date":"Wed, 04 Apr 2012 08:37:37 GMT", "content-length":"580", "content-type":"text/html; charset=ISO-8859-1" } 

sessionId:io4dOLm8Q33aSCEULW0iv74SeewJ3w1tP21L7qkdS4QktIkR

身体:

409:冲突

您的请求有一个无效的会话标头。

要解决此问题,请按照下列步骤操作

  1. 读取响应时,获取其X-Transmission-Session-Id标题并记住它
  2. 将更新的标题添加到您的传出请求
  3. 当你得到这个409错误信息时,用更新的头重新发送你的请求

这个要求已经被添加来帮助防止CSRF攻击。

X-Transmission-Session-Id: io4dOLm8Q33aSCEULW0iv74SeewJ3w1tP21L7qkdS4QktIkR

当没有提供会话标识时,远程服务器应该返回什么。 但是,在标题中设置会话标识后,服务器不响应。 第二个run调用被触发,请求被发送(通过放置一些有用的console.log确认),但是响应callback从不被触发。 我没有收到来自远程服务器的回应,我的应用程序冻结等待。

我敢肯定,错误是在我身边,而不是在服务器上,因为一个开箱即用的android远程客户端连接到同一个远程会话时工作得很好。

我是否正确执行请求? 尤其是JSON部分?

编辑:一点testing

我已经写了一个小小的PHP脚本来testingJSON编码的请求是否正常,并将其用作“假”远程传输。 这里是:

$ headers = apache_request_headers();

 // Simulate transmission's behavior if (!isset($headers['X-Transmission-Session-Id'])) { header("HTTP/1.0 409 Conflict"); header("X-Transmission-Session-Id: test"); } print_r($headers); // Is there a nicer way to get the raw request? print_r(file_get_contents('php://input')); 

而且,我个人并没有看到这个testing输出的数据有什么问题。 在返回409状态码之后,Node.js应用程序正确地分配请求的会话ID。 第一个print_r打印一个数组:

 Array ( [Content-type] => application/json [Content-length] => 152 [X-Transmission-Session-Id] => test [Host] => tp.localhost [Connection] => keep-alive ) 

第二个打印一个string,这是一个格式正确的JSONstring(没有更多的):

 { "arguments": { "filename": "http://link-to-torrent" }, "method": "torrent-add", "tag": 6667 } 

我真的不明白我做错了什么。 我使用相同的远程服务器testing的一些第三方客户端正常工作。

遇到同样的问题,我做了这个类。 我想更好的办法做一个getData,方法。 但它的作品。

 http = require "http" _ = require "underscore" class Connect constructor: (@login, @password, @host='127.0.0.1', @port=9091, @headers={}) -> getData: (params)-> key = "x-transmission-session-id" options = { host: @host port: @port path: '/transmission/rpc', method: 'POST', headers: @headers || {}, auth: "#{ @login }:#{ @password }" } _.extend options, params || {} req = http.request(options, (res)=> if res.statusCode == 401 console.log "Auth errror" else if res.statusCode == 409 auth_header={} auth_header[key] = res.headers[key] _.extend @headers, auth_header @getData(params) else if res.statusCode == 200 res.setEncoding 'utf8' res.on('data', (chunk)-> #here should be an emmit of data console.log chunk ) else console.log "Error #{ res.statusCode }" ) req.write('data\n') req.write('data\n') req.end() connector = new Connect "transmission", "password" connector.getData() 

那么,我可以用mikeal的请求来绕开 – 但不能解决问题,这也简化了我的代码。 最新的版本是这样的:

 runRemoteCommand: (params, callback = false) => options = uri: @uri method: "POST" json: params if @sessionId options.headers = "X-Transmission-Session-Id": @sessionId request options, (error, response, body) => retVal = success: false end = true if error retVal.message = "An error occured: #{error}" else switch response.statusCode when 409 if response.headers["x-transmission-session-id"] @sessionId = response.headers["x-transmission-session-id"] end = false @.runRemoteCommand params, callback else retVal.message = "Session id not present" when 200 retVal.success = true retVal.response = body else retVal.message = "Error, code: #{response.statusCode}" callback retVal if end && callback 

我暂时不会接受这个答案,因为我仍然不知道“原始”版本有什么问题。

 #!/bin/bash #----------------------------------------------------------------------- # DEBUG=0 HOST="192.168.1.65" PORT="8181" TRURL="http://$HOST:$PORT/transmission/rpc" USER="admin" PASSWORD="password1" XTSID="" #------------------------------------- # function getSID () { local S="$1" S=${S##*X-Transmission-Session-Id: } S=${S%%</code>*} echo $S } #------------------------------------- function getData () { local REQUEST="$1" local RET=$(curl --silent -H "X-Transmission-Session-Id: $XTSID" \ -H "Content-type: application/json" \ -X POST \ -d "$REQUEST" \ --user $USER:$PASSWORD $TRURL) ((DEBUG)) && echo $XTSID if [[ "$RET" =~ "409: Conflict" ]] then XTSID=$(getSID "$RET") ((DEBUG)) && echo "XTSID $XTSID" RET=$(curl --silent -H "X-Transmission-Session-Id: $XTSID" \ -H "Content-type: application/json" \ -X POST \ -d "$REQUEST" \ --user $USER:$PASSWORD $TRURL) fi echo $RET } #------------------------------------- R='{"method":"session-stats"}' RET=$(getData "$R") echo $RET