mirror of
https://github.com/YGGverse/aquatic.git
synced 2026-03-31 17:55:36 +00:00
http_protocol: split request parsing by request type
This commit is contained in:
parent
11829f98eb
commit
b9c029b5ed
1 changed files with 137 additions and 96 deletions
|
|
@ -57,6 +57,94 @@ impl AnnounceRequest {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_query_string(query_string: &str) -> anyhow::Result<Self> {
|
||||||
|
// -- Parse key-value pairs
|
||||||
|
|
||||||
|
let mut opt_info_hash= None;
|
||||||
|
let mut opt_peer_id = None;
|
||||||
|
let mut opt_port = None;
|
||||||
|
let mut opt_bytes_left = None;
|
||||||
|
let mut event = AnnounceEvent::default();
|
||||||
|
let mut opt_numwant = None;
|
||||||
|
let mut opt_key = None;
|
||||||
|
|
||||||
|
let query_string_bytes = query_string.as_bytes();
|
||||||
|
|
||||||
|
let mut ampersand_iter = ::memchr::memchr_iter(b'&', query_string_bytes);
|
||||||
|
let mut position = 0usize;
|
||||||
|
|
||||||
|
for equal_sign_index in ::memchr::memchr_iter(b'=', query_string_bytes) {
|
||||||
|
let segment_end = ampersand_iter.next().unwrap_or_else(|| query_string.len());
|
||||||
|
|
||||||
|
let key = query_string
|
||||||
|
.get(position..equal_sign_index)
|
||||||
|
.with_context(|| format!("no key at {}..{}", position, equal_sign_index))?;
|
||||||
|
let value = query_string
|
||||||
|
.get(equal_sign_index + 1..segment_end)
|
||||||
|
.with_context(|| {
|
||||||
|
format!("no value at {}..{}", equal_sign_index + 1, segment_end)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
match key {
|
||||||
|
"info_hash" => {
|
||||||
|
let value = urldecode_20_bytes(value)?;
|
||||||
|
|
||||||
|
opt_info_hash = Some(InfoHash(value));
|
||||||
|
}
|
||||||
|
"peer_id" => {
|
||||||
|
let value = urldecode_20_bytes(value)?;
|
||||||
|
|
||||||
|
opt_peer_id = Some(PeerId(value));
|
||||||
|
}
|
||||||
|
"port" => {
|
||||||
|
opt_port = Some(value.parse::<u16>().with_context(|| "parse port")?);
|
||||||
|
}
|
||||||
|
"left" => {
|
||||||
|
opt_bytes_left = Some(value.parse::<usize>().with_context(|| "parse left")?);
|
||||||
|
}
|
||||||
|
"event" => {
|
||||||
|
event = value
|
||||||
|
.parse::<AnnounceEvent>()
|
||||||
|
.map_err(|err| anyhow::anyhow!("invalid event: {}", err))?;
|
||||||
|
}
|
||||||
|
"compact" => {
|
||||||
|
if value != "1" {
|
||||||
|
return Err(anyhow::anyhow!("compact set, but not to 1"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"numwant" => {
|
||||||
|
opt_numwant = Some(value.parse::<usize>().with_context(|| "parse numwant")?);
|
||||||
|
}
|
||||||
|
"key" => {
|
||||||
|
if value.len() > 100 {
|
||||||
|
return Err(anyhow::anyhow!("'key' is too long"));
|
||||||
|
}
|
||||||
|
opt_key = Some(::urlencoding::decode(value)?.into());
|
||||||
|
}
|
||||||
|
k => {
|
||||||
|
::log::debug!("ignored unrecognized key: {}", k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if segment_end == query_string.len() {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
position = segment_end + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(AnnounceRequest {
|
||||||
|
info_hash: opt_info_hash.with_context(|| "no info_hash")?,
|
||||||
|
peer_id: opt_peer_id.with_context(|| "no peer_id")?,
|
||||||
|
port: opt_port.with_context(|| "no port")?,
|
||||||
|
bytes_left: opt_bytes_left.with_context(|| "no left")?,
|
||||||
|
event,
|
||||||
|
compact: true,
|
||||||
|
numwant: opt_numwant,
|
||||||
|
key: opt_key,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
|
@ -85,6 +173,53 @@ impl ScrapeRequest {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_query_string(query_string: &str) -> anyhow::Result<Self> {
|
||||||
|
// -- Parse key-value pairs
|
||||||
|
|
||||||
|
let mut info_hashes = Vec::new();
|
||||||
|
|
||||||
|
let query_string_bytes = query_string.as_bytes();
|
||||||
|
|
||||||
|
let mut ampersand_iter = ::memchr::memchr_iter(b'&', query_string_bytes);
|
||||||
|
let mut position = 0usize;
|
||||||
|
|
||||||
|
for equal_sign_index in ::memchr::memchr_iter(b'=', query_string_bytes) {
|
||||||
|
let segment_end = ampersand_iter.next().unwrap_or_else(|| query_string.len());
|
||||||
|
|
||||||
|
let key = query_string
|
||||||
|
.get(position..equal_sign_index)
|
||||||
|
.with_context(|| format!("no key at {}..{}", position, equal_sign_index))?;
|
||||||
|
let value = query_string
|
||||||
|
.get(equal_sign_index + 1..segment_end)
|
||||||
|
.with_context(|| {
|
||||||
|
format!("no value at {}..{}", equal_sign_index + 1, segment_end)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
match key {
|
||||||
|
"info_hash" => {
|
||||||
|
let value = urldecode_20_bytes(value)?;
|
||||||
|
|
||||||
|
info_hashes.push(InfoHash(value));
|
||||||
|
}
|
||||||
|
k => {
|
||||||
|
::log::debug!("ignored unrecognized key: {}", k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if segment_end == query_string.len() {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
position = segment_end + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if info_hashes.is_empty() {
|
||||||
|
return Err(anyhow::anyhow!("No info hashes sent"));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(ScrapeRequest { info_hashes })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -147,104 +282,10 @@ impl Request {
|
||||||
let location = split_parts.next().with_context(|| "no location")?;
|
let location = split_parts.next().with_context(|| "no location")?;
|
||||||
let query_string = split_parts.next().with_context(|| "no query string")?;
|
let query_string = split_parts.next().with_context(|| "no query string")?;
|
||||||
|
|
||||||
// -- Parse key-value pairs
|
|
||||||
|
|
||||||
let mut info_hashes = Vec::new();
|
|
||||||
let mut opt_peer_id = None;
|
|
||||||
let mut opt_port = None;
|
|
||||||
let mut opt_bytes_left = None;
|
|
||||||
let mut event = AnnounceEvent::default();
|
|
||||||
let mut opt_numwant = None;
|
|
||||||
let mut opt_key = None;
|
|
||||||
|
|
||||||
let query_string_bytes = query_string.as_bytes();
|
|
||||||
|
|
||||||
let mut ampersand_iter = ::memchr::memchr_iter(b'&', query_string_bytes);
|
|
||||||
let mut position = 0usize;
|
|
||||||
|
|
||||||
for equal_sign_index in ::memchr::memchr_iter(b'=', query_string_bytes) {
|
|
||||||
let segment_end = ampersand_iter.next().unwrap_or_else(|| query_string.len());
|
|
||||||
|
|
||||||
let key = query_string
|
|
||||||
.get(position..equal_sign_index)
|
|
||||||
.with_context(|| format!("no key at {}..{}", position, equal_sign_index))?;
|
|
||||||
let value = query_string
|
|
||||||
.get(equal_sign_index + 1..segment_end)
|
|
||||||
.with_context(|| {
|
|
||||||
format!("no value at {}..{}", equal_sign_index + 1, segment_end)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
match key {
|
|
||||||
"info_hash" => {
|
|
||||||
let value = urldecode_20_bytes(value)?;
|
|
||||||
|
|
||||||
info_hashes.push(InfoHash(value));
|
|
||||||
}
|
|
||||||
"peer_id" => {
|
|
||||||
let value = urldecode_20_bytes(value)?;
|
|
||||||
|
|
||||||
opt_peer_id = Some(PeerId(value));
|
|
||||||
}
|
|
||||||
"port" => {
|
|
||||||
opt_port = Some(value.parse::<u16>().with_context(|| "parse port")?);
|
|
||||||
}
|
|
||||||
"left" => {
|
|
||||||
opt_bytes_left = Some(value.parse::<usize>().with_context(|| "parse left")?);
|
|
||||||
}
|
|
||||||
"event" => {
|
|
||||||
event = value
|
|
||||||
.parse::<AnnounceEvent>()
|
|
||||||
.map_err(|err| anyhow::anyhow!("invalid event: {}", err))?;
|
|
||||||
}
|
|
||||||
"compact" => {
|
|
||||||
if value != "1" {
|
|
||||||
return Err(anyhow::anyhow!("compact set, but not to 1"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"numwant" => {
|
|
||||||
opt_numwant = Some(value.parse::<usize>().with_context(|| "parse numwant")?);
|
|
||||||
}
|
|
||||||
"key" => {
|
|
||||||
if value.len() > 100 {
|
|
||||||
return Err(anyhow::anyhow!("'key' is too long"));
|
|
||||||
}
|
|
||||||
opt_key = Some(::urlencoding::decode(value)?.into());
|
|
||||||
}
|
|
||||||
k => {
|
|
||||||
::log::debug!("ignored unrecognized key: {}", k)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if segment_end == query_string.len() {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
position = segment_end + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- Put together request
|
|
||||||
|
|
||||||
if location == "/announce" {
|
if location == "/announce" {
|
||||||
let request = AnnounceRequest {
|
Ok(Request::Announce(AnnounceRequest::from_query_string(query_string)?))
|
||||||
info_hash: info_hashes.pop().with_context(|| "no info_hash")?,
|
|
||||||
peer_id: opt_peer_id.with_context(|| "no peer_id")?,
|
|
||||||
port: opt_port.with_context(|| "no port")?,
|
|
||||||
bytes_left: opt_bytes_left.with_context(|| "no left")?,
|
|
||||||
event,
|
|
||||||
compact: true,
|
|
||||||
numwant: opt_numwant,
|
|
||||||
key: opt_key,
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Request::Announce(request))
|
|
||||||
} else {
|
} else {
|
||||||
if info_hashes.is_empty() {
|
Ok(Request::Scrape(ScrapeRequest::from_query_string(query_string)?))
|
||||||
return Err(anyhow::anyhow!("No info hashes sent"));
|
|
||||||
}
|
|
||||||
|
|
||||||
let request = ScrapeRequest { info_hashes };
|
|
||||||
|
|
||||||
Ok(Request::Scrape(request))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue