use std::io::{Read, Write};
use std::net::TcpStream;
use crate::error::Result;
use crate::url::Url;
pub fn fetch(url: &Url) -> Result<Vec<u8>> {
let addr = format!("{}:{}", url.host, url.port);
let tcp = TcpStream::connect(&addr)?;
let selector = selector_from_path(&url.path);
let mut request = Vec::with_capacity(selector.len() + 2);
request.extend_from_slice(selector.as_bytes());
request.extend_from_slice(b"\r\n");
if url.is_tls() {
let mut tls = crate::tls::connect_over(tcp, &url.host)?;
tls.write_all(&request)?;
tls.flush()?;
let mut buf = Vec::new();
tls.read_to_end(&mut buf)?;
Ok(buf)
} else {
let mut sock = tcp;
sock.write_all(&request)?;
sock.flush()?;
let mut buf = Vec::new();
sock.read_to_end(&mut buf)?;
Ok(buf)
}
}
fn selector_from_path(path: &str) -> &str {
let without_slash = path.strip_prefix('/').unwrap_or(path);
let mut chars = without_slash.chars();
match chars.next() {
Some(_) => chars.as_str(),
None => "",
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn selector_root_slash() {
assert_eq!(selector_from_path("/"), "");
}
#[test]
fn selector_empty() {
assert_eq!(selector_from_path(""), "");
}
#[test]
fn selector_just_item_type() {
assert_eq!(selector_from_path("/1"), "");
}
#[test]
fn selector_text_file() {
assert_eq!(selector_from_path("/0foo"), "foo");
}
#[test]
fn selector_directory_with_subpath() {
assert_eq!(selector_from_path("/1docs/index"), "docs/index");
}
}