feat: migrate from async-std to tokio

This commit is contained in:
Friedel Ziegelmayer
2022-06-27 14:05:21 +02:00
committed by GitHub
parent 997fb4061a
commit 290ee20e63
69 changed files with 1781 additions and 2231 deletions

View File

@@ -1,26 +1,27 @@
//! # Handle webxdc messages.
use std::convert::TryFrom;
use std::path::PathBuf;
use anyhow::{anyhow, bail, ensure, format_err, Result};
use deltachat_derive::FromSql;
use lettre_email::mime;
use lettre_email::PartBuilder;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use tokio::io::AsyncReadExt;
use crate::chat::Chat;
use crate::contact::ContactId;
use crate::context::Context;
use crate::dc_tools::{dc_create_smeared_timestamp, dc_open_file_std};
use crate::dc_tools::dc_create_smeared_timestamp;
use crate::dc_tools::dc_get_abs_path;
use crate::message::{Message, MessageState, MsgId, Viewtype};
use crate::mimeparser::SystemMessage;
use crate::param::Param;
use crate::param::Params;
use crate::scheduler::InterruptInfo;
use crate::{chat, EventType};
use anyhow::{bail, ensure, format_err, Result};
use async_std::path::PathBuf;
use deltachat_derive::FromSql;
use lettre_email::mime;
use lettre_email::PartBuilder;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::convert::TryFrom;
use std::fs::File;
use std::io::{Read, Seek, SeekFrom};
use zip::ZipArchive;
/// The current API version.
/// If `min_api` in manifest.toml is set to a larger value,
@@ -139,16 +140,12 @@ pub(crate) struct StatusUpdateItemAndSerial {
impl Context {
/// check if a file is an acceptable webxdc for sending or receiving.
pub(crate) async fn is_webxdc_file<R>(&self, filename: &str, mut reader: R) -> Result<bool>
where
R: Read + Seek,
{
pub(crate) async fn is_webxdc_file(&self, filename: &str, file: &[u8]) -> Result<bool> {
if !filename.ends_with(WEBXDC_SUFFIX) {
return Ok(false);
}
let size = reader.seek(SeekFrom::End(0))?;
if size > WEBXDC_RECEIVING_LIMIT {
if file.len() as u64 > WEBXDC_RECEIVING_LIMIT {
info!(
self,
"{} exceeds receiving limit of {} bytes", &filename, WEBXDC_RECEIVING_LIMIT
@@ -156,8 +153,7 @@ impl Context {
return Ok(false);
}
reader.seek(SeekFrom::Start(0))?;
let mut archive = match zip::ZipArchive::new(reader) {
let archive = match async_zip::read::mem::ZipFileReader::new(file).await {
Ok(archive) => archive,
Err(_) => {
info!(self, "{} cannot be opened as zip-file", &filename);
@@ -165,7 +161,7 @@ impl Context {
}
};
if archive.by_name("index.html").is_err() {
if archive.entry("index.html").is_none() {
info!(self, "{} misses index.html", &filename);
return Ok(false);
}
@@ -176,18 +172,12 @@ impl Context {
/// ensure that a file is an acceptable webxdc for sending
/// (sending has more strict size limits).
pub(crate) async fn ensure_sendable_webxdc_file(&self, path: &PathBuf) -> Result<()> {
let mut file = std::fs::File::open(path)?;
if !self
.is_webxdc_file(path.to_str().unwrap_or_default(), &mut file)
.await?
{
bail!(
"{} is not a valid webxdc file",
path.to_str().unwrap_or_default()
);
let filename = path.to_str().unwrap_or_default();
if !filename.ends_with(WEBXDC_SUFFIX) {
bail!("{} is not a valid webxdc file", filename);
}
let size = file.seek(SeekFrom::End(0))?;
let size = tokio::fs::metadata(path).await?.len();
if size > WEBXDC_SENDING_LIMIT {
bail!(
"webxdc {} exceeds acceptable size of {} bytes",
@@ -195,6 +185,26 @@ impl Context {
WEBXDC_SENDING_LIMIT
);
}
let valid = match async_zip::read::fs::ZipFileReader::new(path).await {
Ok(archive) => {
if archive.entry("index.html").is_none() {
info!(self, "{} misses index.html", filename);
false
} else {
true
}
}
Err(_) => {
info!(self, "{} cannot be opened as zip-file", filename);
false
}
};
if !valid {
bail!("{} is not a valid webxdc file", filename);
}
Ok(())
}
@@ -588,22 +598,28 @@ fn parse_webxdc_manifest(bytes: &[u8]) -> Result<WebxdcManifest> {
Ok(manifest)
}
fn get_blob(archive: &mut ZipArchive<File>, name: &str) -> Result<Vec<u8>> {
let mut file = archive.by_name(name)?;
async fn get_blob(archive: &mut async_zip::read::fs::ZipFileReader, name: &str) -> Result<Vec<u8>> {
let (i, _) = archive
.entry(name)
.ok_or_else(|| anyhow!("no entry found for {}", name))?;
let mut reader = archive.entry_reader(i).await?;
let mut buf = Vec::new();
file.read_to_end(&mut buf)?;
reader.read_to_end(&mut buf).await?;
Ok(buf)
}
impl Message {
/// Get handle to a webxdc ZIP-archive.
/// To check for file existance use archive.by_name(), to read a file, use get_blob(archive).
async fn get_webxdc_archive(&self, context: &Context) -> Result<ZipArchive<File>> {
async fn get_webxdc_archive(
&self,
context: &Context,
) -> Result<async_zip::read::fs::ZipFileReader> {
let path = self
.get_file(context)
.ok_or_else(|| format_err!("No webxdc instance file."))?;
let file = dc_open_file_std(context, path)?;
let archive = zip::ZipArchive::new(file)?;
let path_abs = dc_get_abs_path(context, &path);
let archive = async_zip::read::fs::ZipFileReader::new(path_abs).await?;
Ok(archive)
}
@@ -627,7 +643,7 @@ impl Message {
let mut archive = self.get_webxdc_archive(context).await?;
if name == "index.html" {
if let Ok(bytes) = get_blob(&mut archive, "manifest.toml") {
if let Ok(bytes) = get_blob(&mut archive, "manifest.toml").await {
if let Ok(manifest) = parse_webxdc_manifest(&bytes) {
if let Some(min_api) = manifest.min_api {
if min_api > WEBXDC_API_VERSION {
@@ -640,7 +656,7 @@ impl Message {
}
}
get_blob(&mut archive, name)
get_blob(&mut archive, name).await
}
/// Return info from manifest.toml or from fallbacks.
@@ -648,7 +664,7 @@ impl Message {
ensure!(self.viewtype == Viewtype::Webxdc, "No webxdc instance.");
let mut archive = self.get_webxdc_archive(context).await?;
let mut manifest = if let Ok(bytes) = get_blob(&mut archive, "manifest.toml") {
let mut manifest = if let Ok(bytes) = get_blob(&mut archive, "manifest.toml").await {
if let Ok(manifest) = parse_webxdc_manifest(&bytes) {
manifest
} else {
@@ -680,9 +696,9 @@ impl Message {
} else {
self.get_filename().unwrap_or_default()
},
icon: if archive.by_name("icon.png").is_ok() {
icon: if archive.entry("icon.png").is_some() {
"icon.png".to_string()
} else if archive.by_name("icon.jpg").is_ok() {
} else if archive.entry("icon.jpg").is_some() {
"icon.jpg".to_string()
} else {
WEBXDC_DEFAULT_ICON.to_string()
@@ -708,10 +724,8 @@ impl Message {
#[cfg(test)]
mod tests {
use std::io::Cursor;
use async_std::fs::File;
use async_std::io::WriteExt;
use tokio::fs::File;
use tokio::io::AsyncWriteExt;
use crate::chat::{
add_contact_to_chat, create_group_chat, forward_msgs, resend_msgs, send_msg, send_text_msg,
@@ -726,7 +740,7 @@ mod tests {
use super::*;
#[allow(clippy::assertions_on_constants)]
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_webxdc_file_limits() -> Result<()> {
assert!(WEBXDC_SENDING_LIMIT >= 32768);
assert!(WEBXDC_SENDING_LIMIT < 16777216);
@@ -735,41 +749,41 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_is_webxdc_file() -> Result<()> {
let t = TestContext::new().await;
assert!(
!t.is_webxdc_file(
"bad-ext-no-zip.txt",
Cursor::new(include_bytes!("../test-data/message/issue_523.txt"))
include_bytes!("../test-data/message/issue_523.txt")
)
.await?
);
assert!(
!t.is_webxdc_file(
"bad-ext-good-zip.txt",
Cursor::new(include_bytes!("../test-data/webxdc/minimal.xdc"))
include_bytes!("../test-data/webxdc/minimal.xdc")
)
.await?
);
assert!(
!t.is_webxdc_file(
"good-ext-no-zip.xdc",
Cursor::new(include_bytes!("../test-data/message/issue_523.txt"))
include_bytes!("../test-data/message/issue_523.txt")
)
.await?
);
assert!(
!t.is_webxdc_file(
"good-ext-no-index-html.xdc",
Cursor::new(include_bytes!("../test-data/webxdc/no-index-html.xdc"))
include_bytes!("../test-data/webxdc/no-index-html.xdc")
)
.await?
);
assert!(
t.is_webxdc_file(
"good-ext-good-zip.xdc",
Cursor::new(include_bytes!("../test-data/webxdc/minimal.xdc"))
include_bytes!("../test-data/webxdc/minimal.xdc")
)
.await?
);
@@ -796,7 +810,7 @@ mod tests {
Message::load_from_db(t, instance_msg_id).await
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_send_webxdc_instance() -> Result<()> {
let t = TestContext::new_alice().await;
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?;
@@ -820,7 +834,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_send_invalid_webxdc() -> Result<()> {
let t = TestContext::new_alice().await;
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?;
@@ -852,7 +866,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_forward_webxdc_instance() -> Result<()> {
let t = TestContext::new_alice().await;
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?;
@@ -895,7 +909,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_resend_webxdc_instance_and_info() -> Result<()> {
// Alice uses webxdc in a group
let alice = TestContext::new_alice().await;
@@ -940,7 +954,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_receive_webxdc_instance() -> Result<()> {
let t = TestContext::new_alice().await;
dc_receive_imf(
@@ -966,7 +980,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_webxdc_contact_request() -> Result<()> {
let alice = TestContext::new_alice().await;
let bob = TestContext::new_bob().await;
@@ -1010,7 +1024,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_delete_webxdc_instance() -> Result<()> {
let t = TestContext::new_alice().await;
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?;
@@ -1048,7 +1062,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_create_status_update_record() -> Result<()> {
let t = TestContext::new_alice().await;
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?;
@@ -1142,7 +1156,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_receive_status_update() -> Result<()> {
let t = TestContext::new_alice().await;
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?;
@@ -1238,7 +1252,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_send_webxdc_status_update() -> Result<()> {
let alice = TestContext::new_alice().await;
alice.set_config_bool(Config::BccSelf, true).await?;
@@ -1338,7 +1352,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_render_webxdc_status_update_object() -> Result<()> {
let t = TestContext::new_alice().await;
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "a chat").await?;
@@ -1364,7 +1378,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_render_webxdc_status_update_object_range() -> Result<()> {
let t = TestContext::new_alice().await;
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "a chat").await?;
@@ -1402,7 +1416,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_pop_status_update() -> Result<()> {
let t = TestContext::new_alice().await;
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "a chat").await?;
@@ -1462,7 +1476,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_draft_and_send_webxdc_status_update() -> Result<()> {
let alice = TestContext::new_alice().await;
let bob = TestContext::new_bob().await;
@@ -1529,7 +1543,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_send_webxdc_status_update_to_non_webxdc() -> Result<()> {
let t = TestContext::new_alice().await;
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?;
@@ -1541,7 +1555,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_webxdc_blob() -> Result<()> {
let t = TestContext::new_alice().await;
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?;
@@ -1558,7 +1572,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_webxdc_blob_default_icon() -> Result<()> {
let t = TestContext::new_alice().await;
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?;
@@ -1570,7 +1584,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_webxdc_blob_with_absolute_paths() -> Result<()> {
let t = TestContext::new_alice().await;
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?;
@@ -1583,7 +1597,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_webxdc_blob_with_subdirs() -> Result<()> {
let t = TestContext::new_alice().await;
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?;
@@ -1624,7 +1638,7 @@ mod tests {
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_parse_webxdc_manifest() -> Result<()> {
let result = parse_webxdc_manifest(r#"key = syntax error"#.as_bytes());
assert!(result.is_err());
@@ -1655,7 +1669,7 @@ sth_for_the = "future""#
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_parse_webxdc_manifest_min_api() -> Result<()> {
let manifest = parse_webxdc_manifest(r#"min_api = 3"#.as_bytes())?;
assert_eq!(manifest.min_api, Some(3));
@@ -1669,7 +1683,7 @@ sth_for_the = "future""#
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_parse_webxdc_manifest_source_code_url() -> Result<()> {
let result = parse_webxdc_manifest(r#"source_code_url = 3"#.as_bytes());
assert!(result.is_err());
@@ -1683,7 +1697,7 @@ sth_for_the = "future""#
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_webxdc_min_api_too_large() -> Result<()> {
let t = TestContext::new_alice().await;
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "chat").await?;
@@ -1702,7 +1716,7 @@ sth_for_the = "future""#
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_get_webxdc_info() -> Result<()> {
let t = TestContext::new_alice().await;
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?;
@@ -1786,7 +1800,7 @@ sth_for_the = "future""#
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_webxdc_info_summary() -> Result<()> {
let alice = TestContext::new_alice().await;
let bob = TestContext::new_bob().await;
@@ -1852,7 +1866,7 @@ sth_for_the = "future""#
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_webxdc_document_name() -> Result<()> {
let alice = TestContext::new_alice().await;
let bob = TestContext::new_bob().await;
@@ -1894,7 +1908,7 @@ sth_for_the = "future""#
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_webxdc_info_msg() -> Result<()> {
let alice = TestContext::new_alice().await;
let bob = TestContext::new_bob().await;
@@ -1985,7 +1999,7 @@ sth_for_the = "future""#
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_webxdc_info_msg_cleanup_series() -> Result<()> {
let alice = TestContext::new_alice().await;
let bob = TestContext::new_bob().await;
@@ -2023,7 +2037,7 @@ sth_for_the = "future""#
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_webxdc_info_msg_no_cleanup_on_interrupted_series() -> Result<()> {
let t = TestContext::new_alice().await;
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "c").await?;
@@ -2041,7 +2055,7 @@ sth_for_the = "future""#
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_webxdc_opportunistic_encryption() -> Result<()> {
let alice = TestContext::new_alice().await;
let bob = TestContext::new_bob().await;
@@ -2093,7 +2107,7 @@ sth_for_the = "future""#
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_webxdc_chatlist_summary() -> Result<()> {
let t = TestContext::new_alice().await;
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "chat").await?;
@@ -2113,7 +2127,7 @@ sth_for_the = "future""#
Ok(())
}
#[async_std::test]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_webxdc_and_text() -> Result<()> {
let alice = TestContext::new_alice().await;
let bob = TestContext::new_bob().await;