mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-08-26 00:00:16 +02:00
io: rewrite read_to_end and read_to_string (#2560)
The new implementation changes the behavior such that set_len is called after poll_read. The motivation of this change is that it makes it much more obvious that a rouge panic won't give the caller access to a vector containing exposed uninitialized memory. The new implementation also makes sure to not zero memory twice. Additionally, it makes the various implementations more consistent with each other regarding the naming of variables, and whether we store how many bytes we have read, or how many were in the container originally. Fixes: #2544
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
#![warn(rust_2018_idioms)]
|
||||
#![cfg(feature = "full")]
|
||||
|
||||
use std::io;
|
||||
use tokio::io::AsyncReadExt;
|
||||
use tokio_test::assert_ok;
|
||||
use tokio_test::io::Builder;
|
||||
|
||||
#[tokio::test]
|
||||
async fn read_to_string() {
|
||||
@@ -13,3 +15,49 @@ async fn read_to_string() {
|
||||
assert_eq!(n, 11);
|
||||
assert_eq!(buf[..], "hello world"[..]);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn to_string_does_not_truncate_on_utf8_error() {
|
||||
let data = vec![0xff, 0xff, 0xff];
|
||||
|
||||
let mut s = "abc".to_string();
|
||||
|
||||
match AsyncReadExt::read_to_string(&mut data.as_slice(), &mut s).await {
|
||||
Ok(len) => panic!("Should fail: {} bytes.", len),
|
||||
Err(err) if err.to_string() == "stream did not contain valid UTF-8" => {}
|
||||
Err(err) => panic!("Fail: {}.", err),
|
||||
}
|
||||
|
||||
assert_eq!(s, "abc");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn to_string_does_not_truncate_on_io_error() {
|
||||
let mut mock = Builder::new()
|
||||
.read(b"def")
|
||||
.read_error(io::Error::new(io::ErrorKind::Other, "whoops"))
|
||||
.build();
|
||||
let mut s = "abc".to_string();
|
||||
|
||||
match AsyncReadExt::read_to_string(&mut mock, &mut s).await {
|
||||
Ok(len) => panic!("Should fail: {} bytes.", len),
|
||||
Err(err) if err.to_string() == "whoops" => {}
|
||||
Err(err) => panic!("Fail: {}.", err),
|
||||
}
|
||||
|
||||
assert_eq!(s, "abc");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn to_string_appends() {
|
||||
let data = b"def".to_vec();
|
||||
|
||||
let mut s = "abc".to_string();
|
||||
|
||||
let len = AsyncReadExt::read_to_string(&mut data.as_slice(), &mut s)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(len, 3);
|
||||
assert_eq!(s, "abcdef");
|
||||
}
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
use std::io;
|
||||
use tokio::io::AsyncReadExt;
|
||||
use tokio_test::io::Builder;
|
||||
|
||||
#[tokio::test]
|
||||
async fn to_string_does_not_truncate_on_utf8_error() {
|
||||
let data = vec![0xff, 0xff, 0xff];
|
||||
|
||||
let mut s = "abc".to_string();
|
||||
|
||||
match AsyncReadExt::read_to_string(&mut data.as_slice(), &mut s).await {
|
||||
Ok(len) => panic!("Should fail: {} bytes.", len),
|
||||
Err(err) if err.to_string() == "stream did not contain valid UTF-8" => {}
|
||||
Err(err) => panic!("Fail: {}.", err),
|
||||
}
|
||||
|
||||
assert_eq!(s, "abc");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn to_string_does_not_truncate_on_io_error() {
|
||||
let mut mock = Builder::new()
|
||||
.read(b"def")
|
||||
.read_error(io::Error::new(io::ErrorKind::Other, "whoops"))
|
||||
.build();
|
||||
let mut s = "abc".to_string();
|
||||
|
||||
match AsyncReadExt::read_to_string(&mut mock, &mut s).await {
|
||||
Ok(len) => panic!("Should fail: {} bytes.", len),
|
||||
Err(err) if err.to_string() == "whoops" => {}
|
||||
Err(err) => panic!("Fail: {}.", err),
|
||||
}
|
||||
|
||||
assert_eq!(s, "abc");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn to_string_appends() {
|
||||
let data = b"def".to_vec();
|
||||
|
||||
let mut s = "abc".to_string();
|
||||
|
||||
let len = AsyncReadExt::read_to_string(&mut data.as_slice(), &mut s)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(len, 3);
|
||||
assert_eq!(s, "abcdef");
|
||||
}
|
||||
Reference in New Issue
Block a user