JSON-RPC: return mimetype and encoding for HTTP blobs

This commit is contained in:
link2xt
2023-04-19 23:33:19 +00:00
parent 37503dd3e8
commit f68a2fc387
8 changed files with 75 additions and 12 deletions

View File

@@ -3,7 +3,7 @@
## Unreleased ## Unreleased
### Changes ### Changes
- Add `get_http_blob` JSON-RPC API. - Add `get_http_response` JSON-RPC API.
## [1.112.7] - 2023-04-17 ## [1.112.7] - 2023-04-17

5
Cargo.lock generated
View File

@@ -1080,6 +1080,7 @@ dependencies = [
"libc", "libc",
"log", "log",
"mailparse", "mailparse",
"mime",
"num-derive", "num-derive",
"num-traits", "num-traits",
"num_cpus", "num_cpus",
@@ -2591,9 +2592,9 @@ dependencies = [
[[package]] [[package]]
name = "mime" name = "mime"
version = "0.3.16" version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]] [[package]]
name = "minimal-lexical" name = "minimal-lexical"

View File

@@ -57,6 +57,7 @@ kamadak-exif = "0.5"
lettre_email = { git = "https://github.com/deltachat/lettre", branch = "master" } lettre_email = { git = "https://github.com/deltachat/lettre", branch = "master" }
libc = "0.2" libc = "0.2"
mailparse = "0.14" mailparse = "0.14"
mime = "0.3.17"
num_cpus = "1.15" num_cpus = "1.15"
num-derive = "0.3" num-derive = "0.3"
num-traits = "0.2" num-traits = "0.2"

View File

@@ -43,6 +43,7 @@ use types::account::Account;
use types::chat::FullChat; use types::chat::FullChat;
use types::chat_list::ChatListEntry; use types::chat_list::ChatListEntry;
use types::contact::ContactObject; use types::contact::ContactObject;
use types::http::HttpResponse;
use types::message::MessageData; use types::message::MessageData;
use types::message::MessageObject; use types::message::MessageObject;
use types::provider_info::ProviderInfo; use types::provider_info::ProviderInfo;
@@ -1610,15 +1611,13 @@ impl CommandApi {
Ok(general_purpose::STANDARD_NO_PAD.encode(blob)) Ok(general_purpose::STANDARD_NO_PAD.encode(blob))
} }
/// Makes an HTTP GET request and returns base64-encoded contents. /// Makes an HTTP GET request and returns a response.
/// ///
/// `url` is the HTTP or HTTPS URL. /// `url` is the HTTP or HTTPS URL.
async fn get_http_blob(&self, account_id: u32, url: String) -> Result<String> { async fn get_http_response(&self, account_id: u32, url: String) -> Result<HttpResponse> {
let ctx = self.get_context(account_id).await?; let ctx = self.get_context(account_id).await?;
let blob = deltachat::net::read_url_blob(&ctx, &url).await?; let response = deltachat::net::read_url_blob(&ctx, &url).await?.into();
Ok(response)
use base64::{engine::general_purpose, Engine as _};
Ok(general_purpose::STANDARD_NO_PAD.encode(blob))
} }
/// Forward messages to another chat. /// Forward messages to another chat.

View File

@@ -0,0 +1,29 @@
use deltachat::net::HttpResponse as CoreHttpResponse;
use serde::Serialize;
use typescript_type_def::TypeDef;
#[derive(Serialize, TypeDef)]
pub struct HttpResponse {
/// base64-encoded response body.
blob: String,
/// MIME type, e.g. "text/plain" or "text/html".
mimetype: Option<String>,
/// Encoding, e.g. "utf-8".
encoding: Option<String>,
}
impl From<CoreHttpResponse> for HttpResponse {
fn from(response: CoreHttpResponse) -> Self {
use base64::{engine::general_purpose, Engine as _};
let blob = general_purpose::STANDARD_NO_PAD.encode(response.blob);
let mimetype = response.mimetype;
let encoding = response.encoding;
HttpResponse {
blob,
mimetype,
encoding,
}
}
}

View File

@@ -2,6 +2,7 @@ pub mod account;
pub mod chat; pub mod chat;
pub mod chat_list; pub mod chat_list;
pub mod contact; pub mod contact;
pub mod http;
pub mod location; pub mod location;
pub mod message; pub mod message;
pub mod provider_info; pub mod provider_info;

View File

@@ -16,7 +16,7 @@ pub(crate) mod http;
pub(crate) mod session; pub(crate) mod session;
pub(crate) mod tls; pub(crate) mod tls;
pub use http::{read_url, read_url_blob}; pub use http::{read_url, read_url_blob, Response as HttpResponse};
async fn connect_tcp_inner(addr: SocketAddr, timeout_val: Duration) -> Result<TcpStream> { async fn connect_tcp_inner(addr: SocketAddr, timeout_val: Duration) -> Result<TcpStream> {
let tcp_stream = timeout(timeout_val, TcpStream::connect(addr)) let tcp_stream = timeout(timeout_val, TcpStream::connect(addr))

View File

@@ -3,20 +3,52 @@
use std::time::Duration; use std::time::Duration;
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use mime::Mime;
use crate::context::Context; use crate::context::Context;
use crate::socks::Socks5Config; use crate::socks::Socks5Config;
const HTTP_TIMEOUT: Duration = Duration::from_secs(30); const HTTP_TIMEOUT: Duration = Duration::from_secs(30);
/// HTTP(S) GET response.
#[derive(Debug)]
pub struct Response {
/// Response body.
pub blob: Vec<u8>,
/// MIME type exntracted from the `Content-Type` header, if any.
pub mimetype: Option<String>,
/// Encoding extracted from the `Content-Type` header, if any.
pub encoding: Option<String>,
}
/// Retrieves the text contents of URL using HTTP GET request. /// Retrieves the text contents of URL using HTTP GET request.
pub async fn read_url(context: &Context, url: &str) -> Result<String> { pub async fn read_url(context: &Context, url: &str) -> Result<String> {
Ok(read_url_inner(context, url).await?.text().await?) Ok(read_url_inner(context, url).await?.text().await?)
} }
/// Retrieves the binary contents of URL using HTTP GET request. /// Retrieves the binary contents of URL using HTTP GET request.
pub async fn read_url_blob(context: &Context, url: &str) -> Result<Vec<u8>> { pub async fn read_url_blob(context: &Context, url: &str) -> Result<Response> {
Ok(read_url_inner(context, url).await?.bytes().await?.into()) let response = read_url_inner(context, url).await?;
let content_type = response
.headers()
.get(reqwest::header::CONTENT_TYPE)
.and_then(|value| value.to_str().ok())
.and_then(|value| value.parse::<Mime>().ok());
let mimetype = content_type
.as_ref()
.map(|mime| mime.essence_str().to_string());
let encoding = content_type.as_ref().and_then(|mime| {
mime.get_param(mime::CHARSET)
.map(|charset| charset.as_str().to_string())
});
let blob: Vec<u8> = response.bytes().await?.into();
Ok(Response {
blob,
mimetype,
encoding,
})
} }
async fn read_url_inner(context: &Context, url: &str) -> Result<reqwest::Response> { async fn read_url_inner(context: &Context, url: &str) -> Result<reqwest::Response> {