Downloads
Download a file to a temporary directory
Creates a temporary directory withtempfile::Builder
and downloadsa file over HTTP usingreqwest::get
asynchronously.
Creates a targetFile
with name obtained fromResponse::url
withintempfile::TempDir::path
and copies downloaded data to it withio::copy
.The temporary directory is automatically removed on program exit.
use anyhow::Result;use std::io::Write;use std::fs::File;use tempfile::Builder;fn main() -> Result<()> { let tmp_dir = Builder::new().prefix("example").tempdir()?; let target = "https://www.rust-lang.org/logos/rust-logo-512x512.png"; let response = reqwest::blocking::get(target)?; let mut dest = { let fname = response .url() .path_segments() .and_then(|segments| segments.last()) .and_then(|name| if name.is_empty() { None } else { Some(name) }) .unwrap_or("tmp.bin"); println!("file to download: '{}'", fname); let fname = tmp_dir.path().join(fname); println!("will be located under: '{:?}'", fname); File::create(fname)? }; let content = response.bytes()?; dest.write_all(&content)?; Ok(())}
POST a file to paste-rs
reqwest::Client
establishes a connection to https://paste.rs following thereqwest::RequestBuilder
pattern. CallingClient::post
with a URLestablishes the destination,RequestBuilder::body
sets the content to sendby reading the file, andRequestBuilder::send
blocks until the file uploadsand the response returns.read_to_string
returns the message from the serverresponse and displays in the console.
use anyhow::Result;use std::fs::File;use std::io::Read;fn main() -> Result<()> { let paste_api = "https://paste.rs"; let mut file = File::open("message")?; let mut contents = String::new(); file.read_to_string(&mut contents)?; let client = reqwest::blocking::Client::new(); let res = client.post(paste_api) .body(contents) .send()?; let response_text = res.text()?; println!("Your paste is located at: {}",response_text ); Ok(())}
Make a partial download with HTTP range headers
Usesreqwest::blocking::Client::head
to get theContent-Length of theresponse.
The code then usesreqwest::blocking::Client::get
to download the contentin chunks of 10240 bytes, while printing progress messages. This approach isuseful to control memory usage for large files and allows for resumabledownloads.
The Range header is defined inRFC7233.
use anyhow::{Result, anyhow};use reqwest::header::{HeaderValue, CONTENT_LENGTH, RANGE};use reqwest::StatusCode;use std::fs::File;use std::str::FromStr;struct PartialRangeIter { start: u64, end: u64, buffer_size: u32,}impl PartialRangeIter { pub fn new(start: u64, end: u64, buffer_size: u32) -> Result<Self> { if buffer_size == 0 { return Err(anyhow!("invalid buffer_size, give a value greater than zero.")); } Ok(PartialRangeIter { start, end, buffer_size, }) }}impl Iterator for PartialRangeIter { type Item = HeaderValue; fn next(&mut self) -> Option<Self::Item> { if self.start > self.end { None } else { let prev_start = self.start; self.start += std::cmp::min(self.buffer_size as u64, self.end - self.start + 1); Some(HeaderValue::from_str(&format!("bytes={}-{}", prev_start, self.start - 1)).expect("string provided by format!")) } }}fn main() -> Result<()> { let url = "https://httpbin.org/range/102400?duration=2"; const CHUNK_SIZE: u32 = 10240; let client = reqwest::blocking::Client::new(); let response = client.head(url).send()?; let length = response .headers() .get(CONTENT_LENGTH) .ok_or_else(|| anyhow!("response doesn't include the content length"))?; let length = u64::from_str(length.to_str()?).map_err(|_| anyhow!("invalid Content-Length header"))?; let mut output_file = File::create("download.bin")?; println!("starting download..."); for range in PartialRangeIter::new(0, length - 1, CHUNK_SIZE)? { println!("range {:?}", range); let mut response = client.get(url).header(RANGE, range).send()?; let status = response.status(); if !(status == StatusCode::OK || status == StatusCode::PARTIAL_CONTENT) { return Err(anyhow!("Unexpected server response: {}", status)); } std::io::copy(&mut response, &mut output_file)?; } let content = response.text()?; std::io::copy(&mut content.as_bytes(), &mut output_file)?; println!("Finished with success!"); Ok(())}