From a8d4cbd5c15a019a0e23fa5caac22ba85cfad885 Mon Sep 17 00:00:00 2001 From: link2xt Date: Wed, 19 Apr 2023 19:38:37 +0000 Subject: [PATCH 1/2] Add C API to get HTTP responses --- CHANGELOG.md | 1 + deltachat-ffi/deltachat.h | 59 +++++++++++++++++++++++++- deltachat-ffi/src/lib.rs | 88 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 147 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 656f583af8..88244f85da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### Changes - Add `get_http_response` JSON-RPC API. +- Add C API to get HTTP responses. ## [1.112.7] - 2023-04-17 diff --git a/deltachat-ffi/deltachat.h b/deltachat-ffi/deltachat.h index c901ab738b..b18d62296e 100644 --- a/deltachat-ffi/deltachat.h +++ b/deltachat-ffi/deltachat.h @@ -25,6 +25,7 @@ typedef struct _dc_event dc_event_t; typedef struct _dc_event_emitter dc_event_emitter_t; typedef struct _dc_jsonrpc_instance dc_jsonrpc_instance_t; typedef struct _dc_backup_provider dc_backup_provider_t; +typedef struct _dc_http_response dc_http_response_t; // Alias for backwards compatibility, use dc_event_emitter_t instead. typedef struct _dc_event_emitter dc_accounts_event_emitter_t; @@ -5057,6 +5058,63 @@ int dc_provider_get_status (const dc_provider_t* prov void dc_provider_unref (dc_provider_t* provider); +/** + * Return an HTTP(S) GET response. + * This function can be used to download remote content for HTML emails. + * + * @memberof dc_context_t + * @param context The context object to take proxy settings from. + * @param url HTTP or HTTPS URL. + * @return The response must be released using dc_http_response_unref() after usage. + * NULL is returned on errors. + */ +dc_http_response_t* dc_get_http_response (const dc_context_t* context, const char* url); + +/** + * Returns HTTP response MIME type as a string, e.g. "text/plain" or "text/html". + * + * @memberof dc_http_response_t + * @param response HTTP response as returned by dc_get_http_response(). + * @return The string which must be released using dc_str_unref() after usage. May be NULL. + */ +char* dc_http_response_get_mimetype (const dc_http_response_t* response); + +/** + * Returns HTTP response encoding, e.g. "utf-8". + * + * @memberof dc_http_response_t + * @param response HTTP response as returned by dc_get_http_response(). + * @return The string which must be released using dc_str_unref() after usage. May be NULL. + */ +char* dc_http_response_get_encoding (const dc_http_response_t* response); + +/** + * Returns HTTP response contents. + * + * @memberof dc_http_response_t + * @param response HTTP response as returned by dc_get_http_response(). + * @return The blob which must be released using dc_str_unref() after usage. NULL is never returned. + */ +uint8_t* dc_http_response_get_blob (const dc_http_response_t* response); + +/** + * Returns HTTP response content size. + * + * @memberof dc_http_response_t + * @param response HTTP response as returned by dc_get_http_response(). + * @return The blob size. + */ +size_t dc_http_response_get_size (const dc_http_response_t* response); + +/** + * Free an HTTP response object. + * + * @memberof dc_http_response_t + * @param response HTTP response as returned by dc_get_http_response(). + */ +void dc_http_response_unref (const dc_http_response_t* response); + + /** * @class dc_lot_t * @@ -5534,7 +5592,6 @@ void dc_reactions_unref (dc_reactions_t* reactions); */ - /** * @class dc_jsonrpc_instance_t * diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index 968616a5df..23dc6de5cd 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -31,6 +31,7 @@ use deltachat::ephemeral::Timer as EphemeralTimer; use deltachat::imex::BackupProvider; use deltachat::key::DcKey; use deltachat::message::MsgId; +use deltachat::net::read_url_blob; use deltachat::qr_code_generator::{generate_backup_qr, get_securejoin_qr_svg}; use deltachat::reaction::{get_msg_reactions, send_reaction, Reactions}; use deltachat::stock_str::StockMessage; @@ -4467,6 +4468,93 @@ pub unsafe extern "C" fn dc_provider_unref(provider: *mut dc_provider_t) { // this may change once we start localizing string. } +// dc_http_response_t + +pub type dc_http_response_t = net::HttpResponse; + +#[no_mangle] +pub unsafe extern "C" fn dc_get_http_response( + context: *const dc_context_t, + url: *const libc::c_char, +) -> *mut dc_http_response_t { + if context.is_null() || url.is_null() { + eprintln!("ignoring careless call to dc_get_http_response()"); + return ptr::null_mut(); + } + + let context = &*context; + let url = to_string_lossy(url); + if let Ok(response) = block_on(read_url_blob(context, &url)).log_err(context, "read_url_blob") { + Box::into_raw(Box::new(response)) + } else { + ptr::null_mut() + } +} + +#[no_mangle] +pub unsafe extern "C" fn dc_http_response_get_mimetype( + response: *const dc_http_response_t, +) -> *mut libc::c_char { + if response.is_null() { + eprintln!("ignoring careless call to dc_http_response_get_mimetype()"); + return ptr::null_mut(); + } + + let response = &*response; + response.mimetype.strdup() +} + +#[no_mangle] +pub unsafe extern "C" fn dc_http_response_get_encoding( + response: *const dc_http_response_t, +) -> *mut libc::c_char { + if response.is_null() { + eprintln!("ignoring careless call to dc_http_response_get_encoding()"); + return ptr::null_mut(); + } + + let response = &*response; + response.encoding.strdup() +} + +#[no_mangle] +pub unsafe extern "C" fn dc_http_response_get_blob( + response: *const dc_http_response_t, +) -> *mut libc::c_char { + if response.is_null() { + eprintln!("ignoring careless call to dc_http_response_get_blob()"); + return ptr::null_mut(); + } + + let response = &*response; + let blob_len = response.blob.len(); + let ptr = libc::malloc(blob_len); + libc::memcpy(ptr, response.blob.as_ptr() as *mut libc::c_void, blob_len); + ptr as *mut libc::c_char +} + +#[no_mangle] +pub unsafe extern "C" fn dc_http_response_get_size( + response: *const dc_http_response_t, +) -> libc::size_t { + if response.is_null() { + eprintln!("ignoring careless call to dc_http_response_get_size()"); + return 0; + } + + let response = &*response; + response.blob.len() +} + +#[no_mangle] +pub unsafe extern "C" fn dc_http_response_unref(response: *mut dc_http_response_t) { + if response.is_null() { + eprintln!("ignoring careless call to dc_http_response_unref()"); + return; + } + drop(Box::from_raw(response)); +} + // -- Accounts /// Reader-writer lock wrapper for accounts manager to guarantee thread safety when using From 0e9f8c47261e2084eac7b545edddca050bf28cfd Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Thu, 20 Apr 2023 15:52:54 +0200 Subject: [PATCH 2/2] describe dc_http_response_t, needed for doxygen's @memberof --- deltachat-ffi/deltachat.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/deltachat-ffi/deltachat.h b/deltachat-ffi/deltachat.h index b18d62296e..a08067b848 100644 --- a/deltachat-ffi/deltachat.h +++ b/deltachat-ffi/deltachat.h @@ -5070,6 +5070,15 @@ void dc_provider_unref (dc_provider_t* provider); */ dc_http_response_t* dc_get_http_response (const dc_context_t* context, const char* url); + +/** + * @class dc_http_response_t + * + * An object containing an HTTP(S) GET response. + * Created by dc_get_http_response(). + */ + + /** * Returns HTTP response MIME type as a string, e.g. "text/plain" or "text/html". *