问题描述
我正在尝试在 Bittorrent 网络中查找对等点,但收到响应“请求的下载未被授权用于此跟踪器”。我要下载的 torrent 文件是“Ubuntu 20.04.2.0 桌面(64 位)”,可以在 here 中找到。我已经检查过其他 Bittorrent 客户端,并确认 info_hash
是正确的。我倾向于认为我的错误可能是由于一些不正确的 url 编码,但我不确定。
代码的网络部分使用 reqwest 板条箱。为了对 info_hash
进行 url 编码,我使用了 urlencode 板条箱。下面是 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",("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 编码,但我仍然收到相同的错误。
解决方法
我有两个错误阻止了它的工作:
-
info_hash
被编码两次,导致“%”字符被编码为“%25”。 - 每个非数字字节都应编码为 %
,这意味着“%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 板条箱切换到 ureq 板条箱。
正确的 url 编码哈希(据我所知)是:K%A4%FB%F7%23%1A%3Af%0E%86%89%27%07%D2%5C%13U3%A1j
。