まあ、それはかなりあいまいなトピックですが、試してみます。誰かが答えを知っているかもしれません。
Transmission BitTorrent Client 用の小さなリモート 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()
変数は次のparams
ように定義されます。
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" }
セッション ID: io4dOLm8Q33aSCEULW0iv74SeewJ3w1tP21L7qkdS4QktIkR
体:
409:コンフリクト
リクエストに無効なセッション ID ヘッダーが含まれていました。
これを修正するには、次の手順に従います。
- 応答を読み取るときに、その X-Transmission-Session-Id ヘッダーを取得して記憶します
- 更新されたヘッダーを発信リクエストに追加します
- この 409 エラー メッセージが表示されたら、ヘッダーを更新してリクエストを再送信してください
この要件は、CSRF 攻撃を防ぐために追加されました。
X-Transmission-Session-Id: io4dOLm8Q33aSCEULW0iv74SeewJ3w1tP21L7qkdS4QktIkR
これは、セッション ID が指定されていない場合にリモート サーバーから返されるものです。ただし、ヘッダーにセッション ID を設定した後、サーバーは応答しません。2 番目のrun
呼び出しが発生し、リクエストが送信されます (いくつかconsole.log
の有用な を配置することによって確認されます) が、応答コールバックは決して発生しません。リモート サーバーから応答がなく、アプリケーションがフリーズして待機します。
Android用のすぐに使用できるリモートクライアントは、同じリモートセッションに接続するときに問題なく動作するため、エラーはサーバーではなく自分の側にあると確信しています。
リクエストを正しく実行していますか? 特にJSON部分?
編集:ちょっとしたテスト
JSON でエンコードされたリクエストが正常かどうかをテストするための小さな php スクリプトを作成し、それを「偽の」リモート送信として使用しました。ここにあります:
$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'));
また、個人的には、このテストで出力されたデータに問題はありません。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
)
2 番目のものは、適切にフォーマットされた JSON 文字列である文字列を出力します (その中には何もありません)。
{
"arguments": {
"filename": "http://link-to-torrent"
},
"method": "torrent-add",
"tag": 6667
}
何が間違っているのか本当にわかりません。同じリモート サーバーでテストした一部のサードパーティ クライアントは、正常に動作します。