-
Notifications
You must be signed in to change notification settings - Fork 235
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add mime support (form api is deprecated according to libcurl) #537
base: main
Are you sure you want to change the base?
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
FROM ubuntu:16.04 | ||
FROM ubuntu:18.04 | ||
|
||
RUN apt-get update | ||
RUN apt-get install -y --no-install-recommends \ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
use crate::easy::Easy2; | ||
use crate::error::Error; | ||
use curl_sys::{ | ||
curl_mime_addpart, curl_mime_data, curl_mime_filename, curl_mime_free, curl_mime_init, | ||
curl_mime_name, curl_mime_type, curl_mimepart, CURLcode, CURLE_OK, | ||
}; | ||
use std::ffi::CString; | ||
use std::marker::PhantomData; | ||
use std::ptr::null_mut; | ||
|
||
#[derive(Debug)] | ||
pub struct Mime<'e, E> { | ||
handle: *mut curl_sys::curl_mime, | ||
easy: &'e mut Easy2<E>, | ||
} | ||
|
||
impl<'a, T> Mime<'a, T> { | ||
/// Create a mime handle | ||
pub(crate) fn new(easy: &'a mut Easy2<T>) -> Self { | ||
let handle = unsafe { curl_mime_init(easy.raw()) }; | ||
assert!(!handle.is_null()); | ||
|
||
Self { handle, easy } | ||
} | ||
|
||
/// Finalize creation of a mime post. | ||
pub fn post(mut self) -> Result<(), Error> { | ||
// once giving the mime handle to `Easy2` it is now their responsibility to free the handle. | ||
// so we need to make sure `Drop` below won't try to free it. | ||
let mime_handle = self.handle; | ||
self.handle = null_mut(); | ||
self.easy.mimepost(mime_handle) | ||
} | ||
|
||
/// Append a new empty part to a mime structure | ||
pub fn add_part(&mut self) -> MimePart<'a> { | ||
MimePart::new(self) | ||
} | ||
} | ||
|
||
impl<E> Drop for Mime<'_, E> { | ||
fn drop(&mut self) { | ||
// we only need to free mime handles which hadn't been given to the ownership of `Easy2`. | ||
if !self.handle.is_null() { | ||
unsafe { curl_mime_free(self.handle) } | ||
} | ||
} | ||
} | ||
|
||
#[derive(Debug)] | ||
pub struct MimePart<'a> { | ||
handle: *mut curl_mimepart, | ||
// attach to the lifetime of our [Mime] handle, but without taking ownership | ||
_lifetime: PhantomData<&'a ()>, | ||
} | ||
|
||
impl<'a> MimePart<'a> { | ||
fn new<E>(mime: &mut Mime<E>) -> Self { | ||
let handle = unsafe { curl_mime_addpart(mime.handle) }; | ||
assert!(!handle.is_null()); | ||
|
||
Self { | ||
handle, | ||
_lifetime: Default::default(), | ||
} | ||
} | ||
|
||
/// Set a mime part's body data | ||
pub fn set_data(self, data: impl AsRef<[u8]>) -> Result<Self, Error> { | ||
let data = data.as_ref(); | ||
let code = unsafe { curl_mime_data(self.handle, data.as_ptr() as *const _, data.len()) }; | ||
code_ok(code).map(|_| self) | ||
} | ||
|
||
/// Set a mime part's name | ||
/// | ||
/// # Panics | ||
/// If `name` contains nul bytes, panic will occur. | ||
pub fn set_name(self, name: &str) -> Result<Self, Error> { | ||
let data = CString::new(name).unwrap(); | ||
let code = unsafe { curl_mime_name(self.handle, data.as_ptr()) }; | ||
code_ok(code).map(|_| self) | ||
} | ||
|
||
/// Set a mime part's remote file name | ||
/// | ||
/// # Panics | ||
/// If `filename` contains nul bytes, panic will occur. | ||
pub fn set_filename(self, filename: &str) -> Result<Self, Error> { | ||
let data = CString::new(filename).unwrap(); | ||
let code = unsafe { curl_mime_filename(self.handle, data.as_ptr()) }; | ||
code_ok(code).map(|_| self) | ||
} | ||
|
||
/// Set a mime part's content type | ||
/// | ||
/// # Panics | ||
/// If `content_type` contains nul bytes, panic will occur. | ||
pub fn set_content_type(self, content_type: &str) -> Result<Self, Error> { | ||
let data = CString::new(content_type).unwrap(); | ||
let code = unsafe { curl_mime_type(self.handle, data.as_ptr()) }; | ||
code_ok(code).map(|_| self) | ||
} | ||
} | ||
|
||
fn code_ok(code: CURLcode) -> Result<(), Error> { | ||
if code == CURLE_OK { | ||
Ok(()) | ||
} else { | ||
Err(Error::new(code)) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,7 @@ mod form; | |
mod handle; | ||
mod handler; | ||
mod list; | ||
mod mime; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can see what you're saying about "kinda its own API". I don't mind extracting it, just thought it is worth double checking this before doing so. Your call though, I'll do what you ask :) |
||
mod windows; | ||
|
||
pub use self::form::{Form, Part}; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only one mime object should be attached to an easy handle at a time since
CURLOPT_MIMEPOST
replaces any previously assignedmime
, so this doesn't seem like it needs to be aVec
.This should also probably go inside
Inner
like everything else.I would also prefer to avoid a raw pointer here since that requires multiple implementations handling the calling of
curl_mime_free
in multiple places. I wonder if there is a way of keeping the drop code in theMime
struct?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok. Done.