@@ -1029,101 +1029,94 @@ fn run() -> Result<()> {
1029
1029
Uses [ ` reqwest::Client::head ` ] to get the content-length and validate if the server sets the header
1030
1030
[ ` reqwest::header::ContentRange ` ] , required to confirm the support of partial downloads.
1031
1031
1032
- If supported downloads the content using [ ` reqwest::get ` ] , setting the [ ` reqwest::header::Range ` ]
1033
- to do partial downloads in chunks of 100 bytes, between these writes basic progress messages.
1032
+ If supported, downloads the content using [ ` reqwest::get ` ] , setting the [ ` reqwest::header::Range ` ]
1033
+ to do partial downloads printing basic progress messages.
1034
+ in chunks of 10240 bytes
1034
1035
1035
- Range header, defined in [ RFC7233] [ HTTP Range RFC7233 ] .
1036
+ Range header is defined in [ RFC7233] [ HTTP Range RFC7233 ] .
1036
1037
1037
1038
``` rust,no_run
1038
1039
# #[macro_use]
1039
1040
# extern crate error_chain;
1040
1041
extern crate reqwest;
1041
1042
1042
- use std::io::{Read, Write};
1043
1043
use std::fs::File;
1044
-
1045
1044
use reqwest::header::{ContentRange, ContentRangeSpec, Range};
1046
-
1045
+ use reqwest::StatusCode;
1046
+ #
1047
1047
# error_chain! {
1048
1048
# foreign_links {
1049
1049
# Io(std::io::Error);
1050
1050
# Reqwest(reqwest::Error);
1051
1051
# }
1052
1052
# }
1053
-
1054
- #[derive(Debug)]
1055
- struct PartialRangeIter {
1056
- start: u64,
1057
- end: u64,
1058
- buffer_size: usize,
1059
- }
1060
-
1061
- impl PartialRangeIter {
1062
- pub fn new(content_range: &ContentRangeSpec, buffer_size: usize) -> Result<PartialRangeIter> {
1063
- if buffer_size == 0 {
1064
- Err("invalid buffer_size, give a value greater than zero.")?;
1065
- }
1066
-
1067
- match *content_range {
1068
- ContentRangeSpec::Bytes { range: Some(range), .. } => Ok(PartialRangeIter {
1069
- start: range.0,
1070
- end: range.1,
1071
- buffer_size,
1072
- }),
1073
- _ => Err("invalid range specification")?,
1074
- }
1075
- }
1076
- }
1077
-
1078
- impl Iterator for PartialRangeIter {
1079
- type Item = Range;
1080
-
1081
- fn next(&mut self) -> Option<Self::Item> {
1082
- if self.start > self.end {
1083
- None
1084
- } else {
1085
- let old_start = self.start;
1086
- self.start += std::cmp::min(self.buffer_size as u64, self.end - self.start + 1);
1087
- Some(Range::bytes(old_start, self.start - 1))
1088
- }
1089
- }
1090
- }
1091
-
1053
+ #
1054
+ # struct PartialRangeIter {
1055
+ # start: u64,
1056
+ # end: u64,
1057
+ # buffer_size: u32,
1058
+ # }
1059
+ #
1060
+ # impl PartialRangeIter {
1061
+ # pub fn new(content_range: &ContentRangeSpec, buffer_size: u32) -> Result<Self> {
1062
+ # if buffer_size == 0 {
1063
+ # Err("invalid buffer_size, give a value greater than zero.")?;
1064
+ # }
1065
+ #
1066
+ # match *content_range {
1067
+ # ContentRangeSpec::Bytes { range: Some(range), .. } => Ok(PartialRangeIter {
1068
+ # start: range.0,
1069
+ # end: range.1,
1070
+ # buffer_size,
1071
+ # }),
1072
+ # _ => Err("invalid range specification")?,
1073
+ # }
1074
+ # }
1075
+ # }
1076
+ #
1077
+ # impl Iterator for PartialRangeIter {
1078
+ # type Item = Range;
1079
+ #
1080
+ # fn next(&mut self) -> Option<Self::Item> {
1081
+ # if self.start > self.end {
1082
+ # None
1083
+ # } else {
1084
+ # let prev_start = self.start;
1085
+ # self.start += std::cmp::min(self.buffer_size as u64, self.end - self.start + 1);
1086
+ # Some(Range::bytes(prev_start, self.start - 1))
1087
+ # }
1088
+ # }
1089
+ # }
1092
1090
1093
1091
fn run() -> Result<()> {
1094
- let client = reqwest::Client::new();
1095
-
1096
- // For the purpose of this example is only a small download of 102400 bytes.
1092
+ // For the purpose of this example only a small download of 102400 bytes
1093
+ // with chunk size of 10240 bytes is used.
1097
1094
let url = "https://httpbin.org/range/102400?duration=2";
1098
- let response = client.head(url).send()? ;
1095
+ const CHUNK_SIZE: u32 = 10240 ;
1099
1096
1097
+ let client = reqwest::Client::new();
1098
+ let response = client.head(url).send()?;
1100
1099
let range = response.headers().get::<ContentRange>().ok_or(
1101
1100
"response doesn't include the expected ranges",
1102
1101
)?;
1103
1102
1104
1103
let mut output_file = File::create("download.bin")?;
1105
1104
1106
- let mut content_buffer: Vec<u8> = Vec::with_capacity(10000);
1107
- let ranges = PartialRangeIter::new(range, content_buffer.capacity())?;
1108
-
1109
1105
println!("starting download...");
1110
- for range in ranges {
1111
- println!("range {:?}", range);
1106
+ for range in PartialRangeIter::new(range, CHUNK_SIZE)? {
1112
1107
1108
+ println!("range {:?}", range);
1113
1109
let mut response = client.get(url).header(range).send()?;
1114
1110
1115
- if !(response.status() == reqwest::StatusCode::Ok ||
1116
- response.status() == reqwest::StatusCode::PartialContent)
1117
- {
1118
- bail!("Unexpected server response: {}", response.status())
1111
+ let status = response.status();
1112
+ if !(status == StatusCode::Ok || status == StatusCode::PartialContent) {
1113
+ bail!("Unexpected server response: {}", status)
1119
1114
}
1120
1115
1121
- response.read_to_end(&mut content_buffer)?;
1122
- output_file.write_all(&content_buffer)?;
1123
- content_buffer.clear();
1116
+ std::io::copy(&mut response, &mut output_file)?;
1124
1117
}
1125
1118
1126
- println!("finished with success!");
1119
+ println!("Finished with success!");
1127
1120
Ok(())
1128
1121
}
1129
1122
#
0 commit comments