Rust (Bittorrent):发布失败,响应 "Requested download is not authorized for use with this tracker"

Rust (Bittorrent): Failing at announcing, with response "Requested download is not authorized for use with this tracker"

我正在尝试在 Bittorrent 网络中寻找对等点,但收到响应“请求的下载未被授权用于此跟踪器”。我要下载的 torrent 文件是“Ubuntu 20.04.2.0 Desktop (64-bit)”,可以在 here 中找到。我检查了其他 Bittorrent 客户端,并确认 info_hash 是正确的。我倾向于认为我的错误可能是因为一些不正确的 url-编码,但我不确定。

代码的网络部分正在使用 reqwest crate. To url-encode the info_hash, I'm using the urlencode crate。这是 url 编码和发送 GET 请求的代码:

let client = reqwest::blocking::Client::new();
   
let info_hash_encoded = urlencoding::encode_binary(&torrent.info_hash).into_owned().to_uppercase();
let resp = client
    .get(&torrent.announce)
    .query(&[
        ("info_hash", info_hash_encoded.as_str()),
        ("peer_id", PEER_ID),
        ("port", PORT),
        ("uploaded", "0"),
        ("downloaded", "0"),
        ("compact", "1"),
        ("left", torrent.length.to_string().as_str()),
    ])
    .send()?
    .text()?;

println!("{:?}", resp);

其中 torrent.info_hash 是作为字节向量 (Vec) 的信息散列。

下面是 reqwest 响应的实际样子:

Response { url: Url { scheme: "https", cannot_be_a_base: false, username: "", password: None, host: Some(Domain("torrent.ubuntu.com")), port: None, path: "/announce", query: Some("info_hash=K%25A4%25FB%25F7%2523%251A%253AF%250E%2586%2589%2527%2507%25D2%255C%2513U3%25A1J&peer_id=-rqbt01-jsbckj94ksj3&port=5035&uploaded=0&downloaded=0&compact=1&left=2877227008"), fragment: None }, status: 200, headers: {"date": "Sat, 17 Jul 2021 17:05:25 GMT", "server": "Apache/2.4.18 (Ubuntu)", "content-length": "85", "content-type": "text/plain", "pragma": "no-cache", "vary": "Accept-Encoding"} }

我最初认为问题可能是因为 info_hash_encoded 是小写的十六进制,但在大写后,我仍然收到同样的错误。顺便说一下,十六进制形式的信息散列是:4ba4fbf7231a3a660e86892707d25c135533a16a.

谢谢!

编辑:事实证明哈希以某种方式被编码了两次,但即使在修复之后我仍然遇到同样的问题。有谁知道什么是正确的 url 编码信息散列,以便我可以将它与我目前拥有的进行比较?我也尝试在 this spec 之后实现我自己的 url 编码,但我仍然收到同样的错误。

我有两个错误阻止了它的工作:

  1. info_hash 被编码两次,导致“%”个字符被编码为“%25”。
  2. 每个非数字字节都应编码为 %,表示“%7”应为“%07”。我缺少前导零。

以下是对我有用的方法:

use std::error::Error;
use std::fmt::Write;

pub fn url_encode_bytes(content: &[u8]) -> Result<String, Box<dyn Error>> {
    let mut out: String = String::new();

    for byte in content.iter() {
        match *byte as char {
            '0'..='9' | 'a'..='z' | 'A'..='Z' | '.' | '-' | '_' | '~' => out.push(*byte as char),
            _ => write!(&mut out, "%{:02X}", byte)?,
        };
    }

    Ok(out)
}

我还没有找到解决双重编码问题的好方法,但目前我只是像这样手动创建 info_hash 查询:

let url_builder = ureq::get(&torrent.announce)
    .query("peer_id", PEER_ID)
    .query("port", PORT)
    .query("uploaded", "0")
    .query("downloaded", "0")
    .query("compact", "1")
    .query("left", LENGTH);

let url = format!(
    "{}{}",
    url_builder.url(),
    format!("&info_hash={}", url_encode_bytes(&torrent.info_hash)?)
);

我也从 reqwest crate to the ureq crate 切换了。
正确的 url 编码哈希(据我所知)是:K%A4%FB%F7%23%1A%3Af%0E%86%89%27%07%D2%5C%13U3%A1j.