mirror of
https://github.com/Noratrieb/icefun.git
synced 2026-03-15 08:36:04 +01:00
private
This commit is contained in:
parent
25adea4103
commit
7af1274587
160 changed files with 38999 additions and 4 deletions
174
hyper/src/ffi/body.rs
Normal file
174
hyper/src/ffi/body.rs
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
use std::ffi::c_void;
|
||||
use std::mem::ManuallyDrop;
|
||||
use std::ptr;
|
||||
use std::task::{Context, Poll};
|
||||
use http::HeaderMap;
|
||||
use libc::{c_int, size_t};
|
||||
use super::task::{hyper_context, hyper_task, hyper_task_return_type, AsTaskType};
|
||||
use super::{UserDataPointer, HYPER_ITER_CONTINUE};
|
||||
use crate::body::{Body, Bytes, HttpBody as _};
|
||||
/// A streaming HTTP body.
|
||||
pub(crate) struct hyper_body(pub(super) Body);
|
||||
/// A buffer of bytes that is sent or received on a `hyper_body`.
|
||||
pub(crate) struct hyper_buf(pub(crate) Bytes);
|
||||
pub(crate) struct UserBody {
|
||||
data_func: hyper_body_data_callback,
|
||||
userdata: *mut c_void,
|
||||
}
|
||||
type hyper_body_foreach_callback = extern "C" fn(*mut c_void, *const hyper_buf) -> c_int;
|
||||
type hyper_body_data_callback = extern "C" fn(
|
||||
*mut c_void,
|
||||
*mut hyper_context<'_>,
|
||||
*mut *mut hyper_buf,
|
||||
) -> c_int;
|
||||
ffi_fn! {
|
||||
#[doc = " Create a new \"empty\" body."] #[doc = ""] #[doc =
|
||||
" If not configured, this body acts as an empty payload."] fn hyper_body_new() -> *
|
||||
mut hyper_body { Box::into_raw(Box::new(hyper_body(Body::empty()))) } ?=
|
||||
ptr::null_mut()
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Free a `hyper_body *`."] fn hyper_body_free(body : * mut hyper_body) {
|
||||
drop(non_null!(Box::from_raw(body) ?= ())); }
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Return a task that will poll the body for the next buffer of data."] #[doc
|
||||
= ""] #[doc = " The task value may have different types depending on the outcome:"]
|
||||
#[doc = ""] #[doc = " - `HYPER_TASK_BUF`: Success, and more data was received."]
|
||||
#[doc = " - `HYPER_TASK_ERROR`: An error retrieving the data."] #[doc =
|
||||
" - `HYPER_TASK_EMPTY`: The body has finished streaming data."] #[doc = ""] #[doc =
|
||||
" This does not consume the `hyper_body *`, so it may be used to again."] #[doc =
|
||||
" However, it MUST NOT be used or freed until the related task completes."] fn
|
||||
hyper_body_data(body : * mut hyper_body) -> * mut hyper_task { let mut body =
|
||||
ManuallyDrop::new(non_null!(Box::from_raw(body) ?= ptr::null_mut()));
|
||||
Box::into_raw(hyper_task::boxed(async move { body.0.data().await.map(| res | res
|
||||
.map(hyper_buf)) })) } ?= ptr::null_mut()
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Return a task that will poll the body and execute the callback with each"]
|
||||
#[doc = " body chunk that is received."] #[doc = ""] #[doc =
|
||||
" The `hyper_buf` pointer is only a borrowed reference, it cannot live outside"]
|
||||
#[doc = " the execution of the callback. You must make a copy to retain it."] #[doc =
|
||||
""] #[doc =
|
||||
" The callback should return `HYPER_ITER_CONTINUE` to continue iterating"] #[doc =
|
||||
" chunks as they are received, or `HYPER_ITER_BREAK` to cancel."] #[doc = ""] #[doc =
|
||||
" This will consume the `hyper_body *`, you shouldn't use it anymore or free it."] fn
|
||||
hyper_body_foreach(body : * mut hyper_body, func : hyper_body_foreach_callback,
|
||||
userdata : * mut c_void) -> * mut hyper_task { let mut body =
|
||||
non_null!(Box::from_raw(body) ?= ptr::null_mut()); let userdata =
|
||||
UserDataPointer(userdata); Box::into_raw(hyper_task::boxed(async move { while let
|
||||
Some(item) = body.0.data().await { let chunk = item ?; if HYPER_ITER_CONTINUE !=
|
||||
func(userdata.0, & hyper_buf(chunk)) { return Err(crate
|
||||
::Error::new_user_aborted_by_callback()); } } Ok(()) })) } ?= ptr::null_mut()
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Set userdata on this body, which will be passed to callback functions."] fn
|
||||
hyper_body_set_userdata(body : * mut hyper_body, userdata : * mut c_void) { let b =
|
||||
non_null!(& mut * body ?= ()); b.0.as_ffi_mut().userdata = userdata; }
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Set the data callback for this body."] #[doc = ""] #[doc =
|
||||
" The callback is called each time hyper needs to send more data for the"] #[doc =
|
||||
" body. It is passed the value from `hyper_body_set_userdata`."] #[doc = ""] #[doc =
|
||||
" If there is data available, the `hyper_buf **` argument should be set"] #[doc =
|
||||
" to a `hyper_buf *` containing the data, and `HYPER_POLL_READY` should"] #[doc =
|
||||
" be returned."] #[doc = ""] #[doc =
|
||||
" Returning `HYPER_POLL_READY` while the `hyper_buf **` argument points"] #[doc =
|
||||
" to `NULL` will indicate the body has completed all data."] #[doc = ""] #[doc =
|
||||
" If there is more data to send, but it isn't yet available, a"] #[doc =
|
||||
" `hyper_waker` should be saved from the `hyper_context *` argument, and"] #[doc =
|
||||
" `HYPER_POLL_PENDING` should be returned. You must wake the saved waker"] #[doc =
|
||||
" to signal the task when data is available."] #[doc = ""] #[doc =
|
||||
" If some error has occurred, you can return `HYPER_POLL_ERROR` to abort"] #[doc =
|
||||
" the body."] fn hyper_body_set_data_func(body : * mut hyper_body, func :
|
||||
hyper_body_data_callback) { let b = non_null! { & mut * body ?= () }; b.0
|
||||
.as_ffi_mut().data_func = func; }
|
||||
}
|
||||
impl UserBody {
|
||||
pub(crate) fn new() -> UserBody {
|
||||
UserBody {
|
||||
data_func: data_noop,
|
||||
userdata: std::ptr::null_mut(),
|
||||
}
|
||||
}
|
||||
pub(crate) fn poll_data(
|
||||
&mut self,
|
||||
cx: &mut Context<'_>,
|
||||
) -> Poll<Option<crate::Result<Bytes>>> {
|
||||
let mut out = std::ptr::null_mut();
|
||||
match (self.data_func)(self.userdata, hyper_context::wrap(cx), &mut out) {
|
||||
super::task::HYPER_POLL_READY => {
|
||||
if out.is_null() {
|
||||
Poll::Ready(None)
|
||||
} else {
|
||||
let buf = unsafe { Box::from_raw(out) };
|
||||
Poll::Ready(Some(Ok(buf.0)))
|
||||
}
|
||||
}
|
||||
super::task::HYPER_POLL_PENDING => Poll::Pending,
|
||||
super::task::HYPER_POLL_ERROR => {
|
||||
Poll::Ready(Some(Err(crate::Error::new_body_write_aborted())))
|
||||
}
|
||||
unexpected => {
|
||||
Poll::Ready(
|
||||
Some(
|
||||
Err(
|
||||
crate::Error::new_body_write(
|
||||
format!(
|
||||
"unexpected hyper_body_data_func return code {}", unexpected
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
pub(crate) fn poll_trailers(
|
||||
&mut self,
|
||||
_cx: &mut Context<'_>,
|
||||
) -> Poll<crate::Result<Option<HeaderMap>>> {
|
||||
Poll::Ready(Ok(None))
|
||||
}
|
||||
}
|
||||
/// cbindgen:ignore
|
||||
extern "C" fn data_noop(
|
||||
_userdata: *mut c_void,
|
||||
_: *mut hyper_context<'_>,
|
||||
_: *mut *mut hyper_buf,
|
||||
) -> c_int {
|
||||
super::task::HYPER_POLL_READY
|
||||
}
|
||||
unsafe impl Send for UserBody {}
|
||||
unsafe impl Sync for UserBody {}
|
||||
ffi_fn! {
|
||||
#[doc = " Create a new `hyper_buf *` by copying the provided bytes."] #[doc = ""]
|
||||
#[doc = " This makes an owned copy of the bytes, so the `buf` argument can be"] #[doc
|
||||
= " freed or changed afterwards."] #[doc = ""] #[doc =
|
||||
" This returns `NULL` if allocating a new buffer fails."] fn hyper_buf_copy(buf : *
|
||||
const u8, len : size_t) -> * mut hyper_buf { let slice = unsafe {
|
||||
std::slice::from_raw_parts(buf, len) };
|
||||
Box::into_raw(Box::new(hyper_buf(Bytes::copy_from_slice(slice)))) } ?=
|
||||
ptr::null_mut()
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Get a pointer to the bytes in this buffer."] #[doc = ""] #[doc =
|
||||
" This should be used in conjunction with `hyper_buf_len` to get the length"] #[doc =
|
||||
" of the bytes data."] #[doc = ""] #[doc =
|
||||
" This pointer is borrowed data, and not valid once the `hyper_buf` is"] #[doc =
|
||||
" consumed/freed."] fn hyper_buf_bytes(buf : * const hyper_buf) -> * const u8 {
|
||||
unsafe { (* buf).0.as_ptr() } } ?= ptr::null()
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Get the length of the bytes this buffer contains."] fn hyper_buf_len(buf :
|
||||
* const hyper_buf) -> size_t { unsafe { (* buf).0.len() } }
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Free this buffer."] fn hyper_buf_free(buf : * mut hyper_buf) { drop(unsafe
|
||||
{ Box::from_raw(buf) }); }
|
||||
}
|
||||
unsafe impl AsTaskType for hyper_buf {
|
||||
fn as_task_type(&self) -> hyper_task_return_type {
|
||||
hyper_task_return_type::HYPER_TASK_BUF
|
||||
}
|
||||
}
|
||||
111
hyper/src/ffi/client.rs
Normal file
111
hyper/src/ffi/client.rs
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
use std::ptr;
|
||||
use std::sync::Arc;
|
||||
use libc::c_int;
|
||||
use crate::client::conn;
|
||||
use crate::rt::Executor as _;
|
||||
use super::error::hyper_code;
|
||||
use super::http_types::{hyper_request, hyper_response};
|
||||
use super::io::hyper_io;
|
||||
use super::task::{
|
||||
hyper_executor, hyper_task, hyper_task_return_type, AsTaskType, WeakExec,
|
||||
};
|
||||
/// An options builder to configure an HTTP client connection.
|
||||
pub(crate) struct hyper_clientconn_options {
|
||||
builder: conn::Builder,
|
||||
/// Use a `Weak` to prevent cycles.
|
||||
exec: WeakExec,
|
||||
}
|
||||
/// An HTTP client connection handle.
|
||||
///
|
||||
/// These are used to send a request on a single connection. It's possible to
|
||||
/// send multiple requests on a single connection, such as when HTTP/1
|
||||
/// keep-alive or HTTP/2 is used.
|
||||
pub(crate) struct hyper_clientconn {
|
||||
tx: conn::SendRequest<crate::Body>,
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc =
|
||||
" Starts an HTTP client connection handshake using the provided IO transport"] #[doc
|
||||
= " and options."] #[doc = ""] #[doc =
|
||||
" Both the `io` and the `options` are consumed in this function call."] #[doc = ""]
|
||||
#[doc = " The returned `hyper_task *` must be polled with an executor until the"]
|
||||
#[doc = " handshake completes, at which point the value can be taken."] fn
|
||||
hyper_clientconn_handshake(io : * mut hyper_io, options : * mut
|
||||
hyper_clientconn_options) -> * mut hyper_task { let options = non_null! {
|
||||
Box::from_raw(options) ?= ptr::null_mut() }; let io = non_null! { Box::from_raw(io)
|
||||
?= ptr::null_mut() }; Box::into_raw(hyper_task::boxed(async move { options.builder
|
||||
.handshake::< _, crate ::Body > (io).await.map(| (tx, conn) | { options.exec
|
||||
.execute(Box::pin(async move { let _ = conn.await; })); hyper_clientconn { tx } })
|
||||
})) } ?= std::ptr::null_mut()
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Send a request on the client connection."] #[doc = ""] #[doc =
|
||||
" Returns a task that needs to be polled until it is ready. When ready, the"] #[doc =
|
||||
" task yields a `hyper_response *`."] fn hyper_clientconn_send(conn : * mut
|
||||
hyper_clientconn, req : * mut hyper_request) -> * mut hyper_task { let mut req =
|
||||
non_null! { Box::from_raw(req) ?= ptr::null_mut() }; req.finalize_request(); let fut
|
||||
= non_null! { & mut * conn ?= ptr::null_mut() } .tx.send_request(req.0); let fut =
|
||||
async move { fut.await.map(hyper_response::wrap) };
|
||||
Box::into_raw(hyper_task::boxed(fut)) } ?= std::ptr::null_mut()
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Free a `hyper_clientconn *`."] fn hyper_clientconn_free(conn : * mut
|
||||
hyper_clientconn) { drop(non_null! { Box::from_raw(conn) ?= () }); }
|
||||
}
|
||||
unsafe impl AsTaskType for hyper_clientconn {
|
||||
fn as_task_type(&self) -> hyper_task_return_type {
|
||||
hyper_task_return_type::HYPER_TASK_CLIENTCONN
|
||||
}
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Creates a new set of HTTP clientconn options to be used in a handshake."]
|
||||
fn hyper_clientconn_options_new() -> * mut hyper_clientconn_options { let builder =
|
||||
conn::Builder::new(); Box::into_raw(Box::new(hyper_clientconn_options { builder, exec
|
||||
: WeakExec::new(), })) } ?= std::ptr::null_mut()
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Set the whether or not header case is preserved."] #[doc = ""] #[doc =
|
||||
" Pass `0` to allow lowercase normalization (default), `1` to retain original case."]
|
||||
fn hyper_clientconn_options_set_preserve_header_case(opts : * mut
|
||||
hyper_clientconn_options, enabled : c_int) { let opts = non_null! { & mut * opts ?=
|
||||
() }; opts.builder.http1_preserve_header_case(enabled != 0); }
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Set the whether or not header order is preserved."] #[doc = ""] #[doc =
|
||||
" Pass `0` to allow reordering (default), `1` to retain original ordering."] fn
|
||||
hyper_clientconn_options_set_preserve_header_order(opts : * mut
|
||||
hyper_clientconn_options, enabled : c_int) { let opts = non_null! { & mut * opts ?=
|
||||
() }; opts.builder.http1_preserve_header_order(enabled != 0); }
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Free a `hyper_clientconn_options *`."] fn
|
||||
hyper_clientconn_options_free(opts : * mut hyper_clientconn_options) { drop(non_null!
|
||||
{ Box::from_raw(opts) ?= () }); }
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Set the client background task executor."] #[doc = ""] #[doc =
|
||||
" This does not consume the `options` or the `exec`."] fn
|
||||
hyper_clientconn_options_exec(opts : * mut hyper_clientconn_options, exec : * const
|
||||
hyper_executor) { let opts = non_null! { & mut * opts ?= () }; let exec = non_null! {
|
||||
Arc::from_raw(exec) ?= () }; let weak_exec = hyper_executor::downgrade(& exec);
|
||||
std::mem::forget(exec); opts.builder.executor(weak_exec.clone()); opts.exec =
|
||||
weak_exec; }
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Set the whether to use HTTP2."] #[doc = ""] #[doc =
|
||||
" Pass `0` to disable, `1` to enable."] fn hyper_clientconn_options_http2(opts : *
|
||||
mut hyper_clientconn_options, enabled : c_int) -> hyper_code { #[cfg(feature =
|
||||
"http2")] { let opts = non_null! { & mut * opts ?= hyper_code::HYPERE_INVALID_ARG };
|
||||
opts.builder.http2_only(enabled != 0); hyper_code::HYPERE_OK } #[cfg(not(feature =
|
||||
"http2"))] { drop(opts); drop(enabled); hyper_code::HYPERE_FEATURE_NOT_ENABLED } }
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Set the whether to include a copy of the raw headers in responses"] #[doc =
|
||||
" received on this connection."] #[doc = ""] #[doc =
|
||||
" Pass `0` to disable, `1` to enable."] #[doc = ""] #[doc =
|
||||
" If enabled, see `hyper_response_headers_raw()` for usage."] fn
|
||||
hyper_clientconn_options_headers_raw(opts : * mut hyper_clientconn_options, enabled :
|
||||
c_int) -> hyper_code { let opts = non_null! { & mut * opts ?=
|
||||
hyper_code::HYPERE_INVALID_ARG }; opts.builder.http1_headers_raw(enabled != 0);
|
||||
hyper_code::HYPERE_OK }
|
||||
}
|
||||
63
hyper/src/ffi/error.rs
Normal file
63
hyper/src/ffi/error.rs
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
use libc::size_t;
|
||||
/// A more detailed error object returned by some hyper functions.
|
||||
pub(crate) struct hyper_error(crate::Error);
|
||||
/// A return code for many of hyper's methods.
|
||||
#[repr(C)]
|
||||
pub(crate) enum hyper_code {
|
||||
/// All is well.
|
||||
HYPERE_OK,
|
||||
/// General error, details in the `hyper_error *`.
|
||||
HYPERE_ERROR,
|
||||
/// A function argument was invalid.
|
||||
HYPERE_INVALID_ARG,
|
||||
/// The IO transport returned an EOF when one wasn't expected.
|
||||
///
|
||||
/// This typically means an HTTP request or response was expected, but the
|
||||
/// connection closed cleanly without sending (all of) it.
|
||||
HYPERE_UNEXPECTED_EOF,
|
||||
/// Aborted by a user supplied callback.
|
||||
HYPERE_ABORTED_BY_CALLBACK,
|
||||
/// An optional hyper feature was not enabled.
|
||||
#[cfg_attr(feature = "http2", allow(unused))]
|
||||
HYPERE_FEATURE_NOT_ENABLED,
|
||||
/// The peer sent an HTTP message that could not be parsed.
|
||||
HYPERE_INVALID_PEER_MESSAGE,
|
||||
}
|
||||
impl hyper_error {
|
||||
fn code(&self) -> hyper_code {
|
||||
use crate::error::Kind as ErrorKind;
|
||||
use crate::error::User;
|
||||
match self.0.kind() {
|
||||
ErrorKind::Parse(_) => hyper_code::HYPERE_INVALID_PEER_MESSAGE,
|
||||
ErrorKind::IncompleteMessage => hyper_code::HYPERE_UNEXPECTED_EOF,
|
||||
ErrorKind::User(User::AbortedByCallback) => {
|
||||
hyper_code::HYPERE_ABORTED_BY_CALLBACK
|
||||
}
|
||||
_ => hyper_code::HYPERE_ERROR,
|
||||
}
|
||||
}
|
||||
fn print_to(&self, dst: &mut [u8]) -> usize {
|
||||
use std::io::Write;
|
||||
let mut dst = std::io::Cursor::new(dst);
|
||||
let _ = write!(dst, "{}", & self.0);
|
||||
dst.position() as usize
|
||||
}
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Frees a `hyper_error`."] fn hyper_error_free(err : * mut hyper_error) {
|
||||
drop(non_null!(Box::from_raw(err) ?= ())); }
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Get an equivalent `hyper_code` from this error."] fn hyper_error_code(err :
|
||||
* const hyper_error) -> hyper_code { non_null!(&* err ?=
|
||||
hyper_code::HYPERE_INVALID_ARG) .code() }
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Print the details of this error to a buffer."] #[doc = ""] #[doc =
|
||||
" The `dst_len` value must be the maximum length that the buffer can"] #[doc =
|
||||
" store."] #[doc = ""] #[doc =
|
||||
" The return value is number of bytes that were written to `dst`."] fn
|
||||
hyper_error_print(err : * const hyper_error, dst : * mut u8, dst_len : size_t) ->
|
||||
size_t { let dst = unsafe { std::slice::from_raw_parts_mut(dst, dst_len) };
|
||||
non_null!(&* err ?= 0) .print_to(dst) }
|
||||
}
|
||||
443
hyper/src/ffi/http_types.rs
Normal file
443
hyper/src/ffi/http_types.rs
Normal file
|
|
@ -0,0 +1,443 @@
|
|||
use bytes::Bytes;
|
||||
use libc::{c_int, size_t};
|
||||
use std::ffi::c_void;
|
||||
use super::body::{hyper_body, hyper_buf};
|
||||
use super::error::hyper_code;
|
||||
use super::task::{hyper_task_return_type, AsTaskType};
|
||||
use super::{UserDataPointer, HYPER_ITER_CONTINUE};
|
||||
use crate::ext::{HeaderCaseMap, OriginalHeaderOrder, ReasonPhrase};
|
||||
use crate::header::{HeaderName, HeaderValue};
|
||||
use crate::{Body, HeaderMap, Method, Request, Response, Uri};
|
||||
/// An HTTP request.
|
||||
pub(crate) struct hyper_request(pub(super) Request<Body>);
|
||||
/// An HTTP response.
|
||||
pub(crate) struct hyper_response(pub(super) Response<Body>);
|
||||
/// An HTTP header map.
|
||||
///
|
||||
/// These can be part of a request or response.
|
||||
pub(crate) struct hyper_headers {
|
||||
pub(super) headers: HeaderMap,
|
||||
orig_casing: HeaderCaseMap,
|
||||
orig_order: OriginalHeaderOrder,
|
||||
}
|
||||
pub(crate) struct RawHeaders(pub(crate) hyper_buf);
|
||||
pub(crate) struct OnInformational {
|
||||
func: hyper_request_on_informational_callback,
|
||||
data: UserDataPointer,
|
||||
}
|
||||
type hyper_request_on_informational_callback = extern "C" fn(
|
||||
*mut c_void,
|
||||
*mut hyper_response,
|
||||
);
|
||||
ffi_fn! {
|
||||
#[doc = " Construct a new HTTP request."] fn hyper_request_new() -> * mut
|
||||
hyper_request { Box::into_raw(Box::new(hyper_request(Request::new(Body::empty())))) }
|
||||
?= std::ptr::null_mut()
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Free an HTTP request if not going to send it on a client."] fn
|
||||
hyper_request_free(req : * mut hyper_request) { drop(non_null!(Box::from_raw(req) ?=
|
||||
())); }
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Set the HTTP Method of the request."] fn hyper_request_set_method(req : *
|
||||
mut hyper_request, method : * const u8, method_len : size_t) -> hyper_code { let
|
||||
bytes = unsafe { std::slice::from_raw_parts(method, method_len as usize) }; let req =
|
||||
non_null!(& mut * req ?= hyper_code::HYPERE_INVALID_ARG); match
|
||||
Method::from_bytes(bytes) { Ok(m) => { * req.0.method_mut() = m;
|
||||
hyper_code::HYPERE_OK }, Err(_) => { hyper_code::HYPERE_INVALID_ARG } } }
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Set the URI of the request."] #[doc = ""] #[doc =
|
||||
" The request's URI is best described as the `request-target` from the RFCs. So in HTTP/1,"]
|
||||
#[doc =
|
||||
" whatever is set will get sent as-is in the first line (GET $uri HTTP/1.1). It"]
|
||||
#[doc =
|
||||
" supports the 4 defined variants, origin-form, absolute-form, authority-form, and"]
|
||||
#[doc = " asterisk-form."] #[doc = ""] #[doc =
|
||||
" The underlying type was built to efficiently support HTTP/2 where the request-target is"]
|
||||
#[doc =
|
||||
" split over :scheme, :authority, and :path. As such, each part can be set explicitly, or the"]
|
||||
#[doc =
|
||||
" type can parse a single contiguous string and if a scheme is found, that slot is \"set\". If"]
|
||||
#[doc =
|
||||
" the string just starts with a path, only the path portion is set. All pseudo headers that"]
|
||||
#[doc = " have been parsed/set are sent when the connection type is HTTP/2."] #[doc =
|
||||
""] #[doc = " To set each slot explicitly, use `hyper_request_set_uri_parts`."] fn
|
||||
hyper_request_set_uri(req : * mut hyper_request, uri : * const u8, uri_len : size_t)
|
||||
-> hyper_code { let bytes = unsafe { std::slice::from_raw_parts(uri, uri_len as
|
||||
usize) }; let req = non_null!(& mut * req ?= hyper_code::HYPERE_INVALID_ARG); match
|
||||
Uri::from_maybe_shared(bytes) { Ok(u) => { * req.0.uri_mut() = u;
|
||||
hyper_code::HYPERE_OK }, Err(_) => { hyper_code::HYPERE_INVALID_ARG } } }
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Set the URI of the request with separate scheme, authority, and"] #[doc =
|
||||
" path/query strings."] #[doc = ""] #[doc =
|
||||
" Each of `scheme`, `authority`, and `path_and_query` should either be"] #[doc =
|
||||
" null, to skip providing a component, or point to a UTF-8 encoded"] #[doc =
|
||||
" string. If any string pointer argument is non-null, its corresponding"] #[doc =
|
||||
" `len` parameter must be set to the string's length."] fn
|
||||
hyper_request_set_uri_parts(req : * mut hyper_request, scheme : * const u8,
|
||||
scheme_len : size_t, authority : * const u8, authority_len : size_t, path_and_query :
|
||||
* const u8, path_and_query_len : size_t) -> hyper_code { let mut builder =
|
||||
Uri::builder(); if ! scheme.is_null() { let scheme_bytes = unsafe {
|
||||
std::slice::from_raw_parts(scheme, scheme_len as usize) }; builder = builder
|
||||
.scheme(scheme_bytes); } if ! authority.is_null() { let authority_bytes = unsafe {
|
||||
std::slice::from_raw_parts(authority, authority_len as usize) }; builder = builder
|
||||
.authority(authority_bytes); } if ! path_and_query.is_null() { let
|
||||
path_and_query_bytes = unsafe { std::slice::from_raw_parts(path_and_query,
|
||||
path_and_query_len as usize) }; builder = builder
|
||||
.path_and_query(path_and_query_bytes); } match builder.build() { Ok(u) => { * unsafe
|
||||
{ & mut * req } .0.uri_mut() = u; hyper_code::HYPERE_OK }, Err(_) => {
|
||||
hyper_code::HYPERE_INVALID_ARG } } }
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Set the preferred HTTP version of the request."] #[doc = ""] #[doc =
|
||||
" The version value should be one of the `HYPER_HTTP_VERSION_` constants."] #[doc =
|
||||
""] #[doc = " Note that this won't change the major HTTP version of the connection,"]
|
||||
#[doc = " since that is determined at the handshake step."] fn
|
||||
hyper_request_set_version(req : * mut hyper_request, version : c_int) -> hyper_code {
|
||||
use http::Version; let req = non_null!(& mut * req ?=
|
||||
hyper_code::HYPERE_INVALID_ARG); * req.0.version_mut() = match version {
|
||||
super::HYPER_HTTP_VERSION_NONE => Version::HTTP_11, super::HYPER_HTTP_VERSION_1_0 =>
|
||||
Version::HTTP_10, super::HYPER_HTTP_VERSION_1_1 => Version::HTTP_11,
|
||||
super::HYPER_HTTP_VERSION_2 => Version::HTTP_2, _ => { return
|
||||
hyper_code::HYPERE_INVALID_ARG; } }; hyper_code::HYPERE_OK }
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Gets a reference to the HTTP headers of this request"] #[doc = ""] #[doc =
|
||||
" This is not an owned reference, so it should not be accessed after the"] #[doc =
|
||||
" `hyper_request` has been consumed."] fn hyper_request_headers(req : * mut
|
||||
hyper_request) -> * mut hyper_headers { hyper_headers::get_or_default(unsafe { & mut
|
||||
* req } .0.extensions_mut()) } ?= std::ptr::null_mut()
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Set the body of the request."] #[doc = ""] #[doc =
|
||||
" The default is an empty body."] #[doc = ""] #[doc =
|
||||
" This takes ownership of the `hyper_body *`, you must not use it or"] #[doc =
|
||||
" free it after setting it on the request."] fn hyper_request_set_body(req : * mut
|
||||
hyper_request, body : * mut hyper_body) -> hyper_code { let body =
|
||||
non_null!(Box::from_raw(body) ?= hyper_code::HYPERE_INVALID_ARG); let req =
|
||||
non_null!(& mut * req ?= hyper_code::HYPERE_INVALID_ARG); * req.0.body_mut() = body
|
||||
.0; hyper_code::HYPERE_OK }
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Set an informational (1xx) response callback."] #[doc = ""] #[doc =
|
||||
" The callback is called each time hyper receives an informational (1xx)"] #[doc =
|
||||
" response for this request."] #[doc = ""] #[doc =
|
||||
" The third argument is an opaque user data pointer, which is passed to"] #[doc =
|
||||
" the callback each time."] #[doc = ""] #[doc =
|
||||
" The callback is passed the `void *` data pointer, and a"] #[doc =
|
||||
" `hyper_response *` which can be inspected as any other response. The"] #[doc =
|
||||
" body of the response will always be empty."] #[doc = ""] #[doc =
|
||||
" NOTE: The `hyper_response *` is just borrowed data, and will not"] #[doc =
|
||||
" be valid after the callback finishes. You must copy any data you wish"] #[doc =
|
||||
" to persist."] fn hyper_request_on_informational(req : * mut hyper_request, callback
|
||||
: hyper_request_on_informational_callback, data : * mut c_void) -> hyper_code { let
|
||||
ext = OnInformational { func : callback, data : UserDataPointer(data), }; let req =
|
||||
non_null!(& mut * req ?= hyper_code::HYPERE_INVALID_ARG); req.0.extensions_mut()
|
||||
.insert(ext); hyper_code::HYPERE_OK }
|
||||
}
|
||||
impl hyper_request {
|
||||
pub(super) fn finalize_request(&mut self) {
|
||||
if let Some(headers) = self.0.extensions_mut().remove::<hyper_headers>() {
|
||||
*self.0.headers_mut() = headers.headers;
|
||||
self.0.extensions_mut().insert(headers.orig_casing);
|
||||
self.0.extensions_mut().insert(headers.orig_order);
|
||||
}
|
||||
}
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Free an HTTP response after using it."] fn hyper_response_free(resp : * mut
|
||||
hyper_response) { drop(non_null!(Box::from_raw(resp) ?= ())); }
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Get the HTTP-Status code of this response."] #[doc = ""] #[doc =
|
||||
" It will always be within the range of 100-599."] fn hyper_response_status(resp : *
|
||||
const hyper_response) -> u16 { non_null!(&* resp ?= 0) .0.status().as_u16() }
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Get a pointer to the reason-phrase of this response."] #[doc = ""] #[doc =
|
||||
" This buffer is not null-terminated."] #[doc = ""] #[doc =
|
||||
" This buffer is owned by the response, and should not be used after"] #[doc =
|
||||
" the response has been freed."] #[doc = ""] #[doc =
|
||||
" Use `hyper_response_reason_phrase_len()` to get the length of this"] #[doc =
|
||||
" buffer."] fn hyper_response_reason_phrase(resp : * const hyper_response) -> * const
|
||||
u8 { non_null!(&* resp ?= std::ptr::null()) .reason_phrase().as_ptr() } ?=
|
||||
std::ptr::null()
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Get the length of the reason-phrase of this response."] #[doc = ""] #[doc =
|
||||
" Use `hyper_response_reason_phrase()` to get the buffer pointer."] fn
|
||||
hyper_response_reason_phrase_len(resp : * const hyper_response) -> size_t {
|
||||
non_null!(&* resp ?= 0) .reason_phrase().len() }
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Get a reference to the full raw headers of this response."] #[doc = ""]
|
||||
#[doc = " You must have enabled `hyper_clientconn_options_headers_raw()`, or this"]
|
||||
#[doc = " will return NULL."] #[doc = ""] #[doc =
|
||||
" The returned `hyper_buf *` is just a reference, owned by the response."] #[doc =
|
||||
" You need to make a copy if you wish to use it after freeing the"] #[doc =
|
||||
" response."] #[doc = ""] #[doc =
|
||||
" The buffer is not null-terminated, see the `hyper_buf` functions for"] #[doc =
|
||||
" getting the bytes and length."] fn hyper_response_headers_raw(resp : * const
|
||||
hyper_response) -> * const hyper_buf { let resp = non_null!(&* resp ?=
|
||||
std::ptr::null()); match resp.0.extensions().get::< RawHeaders > () { Some(raw) => &
|
||||
raw.0, None => std::ptr::null(), } } ?= std::ptr::null()
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Get the HTTP version used by this response."] #[doc = ""] #[doc =
|
||||
" The returned value could be:"] #[doc = ""] #[doc = " - `HYPER_HTTP_VERSION_1_0`"]
|
||||
#[doc = " - `HYPER_HTTP_VERSION_1_1`"] #[doc = " - `HYPER_HTTP_VERSION_2`"] #[doc =
|
||||
" - `HYPER_HTTP_VERSION_NONE` if newer (or older)."] fn hyper_response_version(resp :
|
||||
* const hyper_response) -> c_int { use http::Version; match non_null!(&* resp ?= 0)
|
||||
.0.version() { Version::HTTP_10 => super::HYPER_HTTP_VERSION_1_0, Version::HTTP_11 =>
|
||||
super::HYPER_HTTP_VERSION_1_1, Version::HTTP_2 => super::HYPER_HTTP_VERSION_2, _ =>
|
||||
super::HYPER_HTTP_VERSION_NONE, } }
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Gets a reference to the HTTP headers of this response."] #[doc = ""] #[doc
|
||||
= " This is not an owned reference, so it should not be accessed after the"] #[doc =
|
||||
" `hyper_response` has been freed."] fn hyper_response_headers(resp : * mut
|
||||
hyper_response) -> * mut hyper_headers { hyper_headers::get_or_default(unsafe { & mut
|
||||
* resp } .0.extensions_mut()) } ?= std::ptr::null_mut()
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Take ownership of the body of this response."] #[doc = ""] #[doc =
|
||||
" It is safe to free the response even after taking ownership of its body."] fn
|
||||
hyper_response_body(resp : * mut hyper_response) -> * mut hyper_body { let body =
|
||||
std::mem::take(non_null!(& mut * resp ?= std::ptr::null_mut()) .0.body_mut());
|
||||
Box::into_raw(Box::new(hyper_body(body))) } ?= std::ptr::null_mut()
|
||||
}
|
||||
impl hyper_response {
|
||||
pub(super) fn wrap(mut resp: Response<Body>) -> hyper_response {
|
||||
let headers = std::mem::take(resp.headers_mut());
|
||||
let orig_casing = resp
|
||||
.extensions_mut()
|
||||
.remove::<HeaderCaseMap>()
|
||||
.unwrap_or_else(HeaderCaseMap::default);
|
||||
let orig_order = resp
|
||||
.extensions_mut()
|
||||
.remove::<OriginalHeaderOrder>()
|
||||
.unwrap_or_else(OriginalHeaderOrder::default);
|
||||
resp.extensions_mut()
|
||||
.insert(hyper_headers {
|
||||
headers,
|
||||
orig_casing,
|
||||
orig_order,
|
||||
});
|
||||
hyper_response(resp)
|
||||
}
|
||||
fn reason_phrase(&self) -> &[u8] {
|
||||
if let Some(reason) = self.0.extensions().get::<ReasonPhrase>() {
|
||||
return reason.as_bytes();
|
||||
}
|
||||
if let Some(reason) = self.0.status().canonical_reason() {
|
||||
return reason.as_bytes();
|
||||
}
|
||||
&[]
|
||||
}
|
||||
}
|
||||
unsafe impl AsTaskType for hyper_response {
|
||||
fn as_task_type(&self) -> hyper_task_return_type {
|
||||
hyper_task_return_type::HYPER_TASK_RESPONSE
|
||||
}
|
||||
}
|
||||
type hyper_headers_foreach_callback = extern "C" fn(
|
||||
*mut c_void,
|
||||
*const u8,
|
||||
size_t,
|
||||
*const u8,
|
||||
size_t,
|
||||
) -> c_int;
|
||||
impl hyper_headers {
|
||||
pub(super) fn get_or_default(ext: &mut http::Extensions) -> &mut hyper_headers {
|
||||
if let None = ext.get_mut::<hyper_headers>() {
|
||||
ext.insert(hyper_headers::default());
|
||||
}
|
||||
ext.get_mut::<hyper_headers>().unwrap()
|
||||
}
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Iterates the headers passing each name and value pair to the callback."]
|
||||
#[doc = ""] #[doc = " The `userdata` pointer is also passed to the callback."] #[doc
|
||||
= ""] #[doc =
|
||||
" The callback should return `HYPER_ITER_CONTINUE` to keep iterating, or"] #[doc =
|
||||
" `HYPER_ITER_BREAK` to stop."] fn hyper_headers_foreach(headers : * const
|
||||
hyper_headers, func : hyper_headers_foreach_callback, userdata : * mut c_void) { let
|
||||
headers = non_null!(&* headers ?= ()); let mut ordered_iter = headers.orig_order
|
||||
.get_in_order().peekable(); if ordered_iter.peek().is_some() { for (name, idx) in
|
||||
ordered_iter { let (name_ptr, name_len) = if let Some(orig_name) = headers
|
||||
.orig_casing.get_all(name).nth(* idx) { (orig_name.as_ref().as_ptr(), orig_name
|
||||
.as_ref().len()) } else { (name.as_str().as_bytes().as_ptr(), name.as_str()
|
||||
.as_bytes().len(),) }; let val_ptr; let val_len; if let Some(value) = headers.headers
|
||||
.get_all(name).iter().nth(* idx) { val_ptr = value.as_bytes().as_ptr(); val_len =
|
||||
value.as_bytes().len(); } else { return; } if HYPER_ITER_CONTINUE != func(userdata,
|
||||
name_ptr, name_len, val_ptr, val_len) { return; } } } else { for name in headers
|
||||
.headers.keys() { let mut names = headers.orig_casing.get_all(name); for value in
|
||||
headers.headers.get_all(name) { let (name_ptr, name_len) = if let Some(orig_name) =
|
||||
names.next() { (orig_name.as_ref().as_ptr(), orig_name.as_ref().len()) } else { (name
|
||||
.as_str().as_bytes().as_ptr(), name.as_str().as_bytes().len(),) }; let val_ptr =
|
||||
value.as_bytes().as_ptr(); let val_len = value.as_bytes().len(); if
|
||||
HYPER_ITER_CONTINUE != func(userdata, name_ptr, name_len, val_ptr, val_len) { return;
|
||||
} } } } }
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Sets the header with the provided name to the provided value."] #[doc = ""]
|
||||
#[doc = " This overwrites any previous value set for the header."] fn
|
||||
hyper_headers_set(headers : * mut hyper_headers, name : * const u8, name_len :
|
||||
size_t, value : * const u8, value_len : size_t) -> hyper_code { let headers =
|
||||
non_null!(& mut * headers ?= hyper_code::HYPERE_INVALID_ARG); match unsafe {
|
||||
raw_name_value(name, name_len, value, value_len) } { Ok((name, value, orig_name)) =>
|
||||
{ headers.headers.insert(& name, value); headers.orig_casing.insert(name.clone(),
|
||||
orig_name.clone()); headers.orig_order.insert(name); hyper_code::HYPERE_OK }
|
||||
Err(code) => code, } }
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Adds the provided value to the list of the provided name."] #[doc = ""]
|
||||
#[doc = " If there were already existing values for the name, this will append the"]
|
||||
#[doc = " new value to the internal list."] fn hyper_headers_add(headers : * mut
|
||||
hyper_headers, name : * const u8, name_len : size_t, value : * const u8, value_len :
|
||||
size_t) -> hyper_code { let headers = non_null!(& mut * headers ?=
|
||||
hyper_code::HYPERE_INVALID_ARG); match unsafe { raw_name_value(name, name_len, value,
|
||||
value_len) } { Ok((name, value, orig_name)) => { headers.headers.append(& name,
|
||||
value); headers.orig_casing.append(& name, orig_name.clone()); headers.orig_order
|
||||
.append(name); hyper_code::HYPERE_OK } Err(code) => code, } }
|
||||
}
|
||||
impl Default for hyper_headers {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
headers: Default::default(),
|
||||
orig_casing: HeaderCaseMap::default(),
|
||||
orig_order: OriginalHeaderOrder::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
unsafe fn raw_name_value(
|
||||
name: *const u8,
|
||||
name_len: size_t,
|
||||
value: *const u8,
|
||||
value_len: size_t,
|
||||
) -> Result<(HeaderName, HeaderValue, Bytes), hyper_code> {
|
||||
let name = std::slice::from_raw_parts(name, name_len);
|
||||
let orig_name = Bytes::copy_from_slice(name);
|
||||
let name = match HeaderName::from_bytes(name) {
|
||||
Ok(name) => name,
|
||||
Err(_) => return Err(hyper_code::HYPERE_INVALID_ARG),
|
||||
};
|
||||
let value = std::slice::from_raw_parts(value, value_len);
|
||||
let value = match HeaderValue::from_bytes(value) {
|
||||
Ok(val) => val,
|
||||
Err(_) => return Err(hyper_code::HYPERE_INVALID_ARG),
|
||||
};
|
||||
Ok((name, value, orig_name))
|
||||
}
|
||||
impl OnInformational {
|
||||
pub(crate) fn call(&mut self, resp: Response<Body>) {
|
||||
let mut resp = hyper_response::wrap(resp);
|
||||
(self.func)(self.data.0, &mut resp);
|
||||
}
|
||||
}
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn test_headers_foreach_cases_preserved() {
|
||||
let mut headers = hyper_headers::default();
|
||||
let name1 = b"Set-CookiE";
|
||||
let value1 = b"a=b";
|
||||
hyper_headers_add(
|
||||
&mut headers,
|
||||
name1.as_ptr(),
|
||||
name1.len(),
|
||||
value1.as_ptr(),
|
||||
value1.len(),
|
||||
);
|
||||
let name2 = b"SET-COOKIE";
|
||||
let value2 = b"c=d";
|
||||
hyper_headers_add(
|
||||
&mut headers,
|
||||
name2.as_ptr(),
|
||||
name2.len(),
|
||||
value2.as_ptr(),
|
||||
value2.len(),
|
||||
);
|
||||
let mut vec = Vec::<u8>::new();
|
||||
hyper_headers_foreach(&headers, concat, &mut vec as *mut _ as *mut c_void);
|
||||
assert_eq!(vec, b"Set-CookiE: a=b\r\nSET-COOKIE: c=d\r\n");
|
||||
extern "C" fn concat(
|
||||
vec: *mut c_void,
|
||||
name: *const u8,
|
||||
name_len: usize,
|
||||
value: *const u8,
|
||||
value_len: usize,
|
||||
) -> c_int {
|
||||
unsafe {
|
||||
let vec = &mut *(vec as *mut Vec<u8>);
|
||||
let name = std::slice::from_raw_parts(name, name_len);
|
||||
let value = std::slice::from_raw_parts(value, value_len);
|
||||
vec.extend(name);
|
||||
vec.extend(b": ");
|
||||
vec.extend(value);
|
||||
vec.extend(b"\r\n");
|
||||
}
|
||||
HYPER_ITER_CONTINUE
|
||||
}
|
||||
}
|
||||
#[cfg(all(feature = "http1", feature = "ffi"))]
|
||||
#[test]
|
||||
fn test_headers_foreach_order_preserved() {
|
||||
let mut headers = hyper_headers::default();
|
||||
let name1 = b"Set-CookiE";
|
||||
let value1 = b"a=b";
|
||||
hyper_headers_add(
|
||||
&mut headers,
|
||||
name1.as_ptr(),
|
||||
name1.len(),
|
||||
value1.as_ptr(),
|
||||
value1.len(),
|
||||
);
|
||||
let name2 = b"Content-Encoding";
|
||||
let value2 = b"gzip";
|
||||
hyper_headers_add(
|
||||
&mut headers,
|
||||
name2.as_ptr(),
|
||||
name2.len(),
|
||||
value2.as_ptr(),
|
||||
value2.len(),
|
||||
);
|
||||
let name3 = b"SET-COOKIE";
|
||||
let value3 = b"c=d";
|
||||
hyper_headers_add(
|
||||
&mut headers,
|
||||
name3.as_ptr(),
|
||||
name3.len(),
|
||||
value3.as_ptr(),
|
||||
value3.len(),
|
||||
);
|
||||
let mut vec = Vec::<u8>::new();
|
||||
hyper_headers_foreach(&headers, concat, &mut vec as *mut _ as *mut c_void);
|
||||
println!("{}", std::str::from_utf8(& vec).unwrap());
|
||||
assert_eq!(
|
||||
vec, b"Set-CookiE: a=b\r\nContent-Encoding: gzip\r\nSET-COOKIE: c=d\r\n"
|
||||
);
|
||||
extern "C" fn concat(
|
||||
vec: *mut c_void,
|
||||
name: *const u8,
|
||||
name_len: usize,
|
||||
value: *const u8,
|
||||
value_len: usize,
|
||||
) -> c_int {
|
||||
unsafe {
|
||||
let vec = &mut *(vec as *mut Vec<u8>);
|
||||
let name = std::slice::from_raw_parts(name, name_len);
|
||||
let value = std::slice::from_raw_parts(value, value_len);
|
||||
vec.extend(name);
|
||||
vec.extend(b": ");
|
||||
vec.extend(value);
|
||||
vec.extend(b"\r\n");
|
||||
}
|
||||
HYPER_ITER_CONTINUE
|
||||
}
|
||||
}
|
||||
}
|
||||
153
hyper/src/ffi/io.rs
Normal file
153
hyper/src/ffi/io.rs
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
use std::ffi::c_void;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
use libc::size_t;
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
use super::task::hyper_context;
|
||||
/// Sentinel value to return from a read or write callback that the operation
|
||||
/// is pending.
|
||||
pub(crate) const HYPER_IO_PENDING: size_t = 0xFFFFFFFF;
|
||||
/// Sentinel value to return from a read or write callback that the operation
|
||||
/// has errored.
|
||||
pub(crate) const HYPER_IO_ERROR: size_t = 0xFFFFFFFE;
|
||||
type hyper_io_read_callback = extern "C" fn(
|
||||
*mut c_void,
|
||||
*mut hyper_context<'_>,
|
||||
*mut u8,
|
||||
size_t,
|
||||
) -> size_t;
|
||||
type hyper_io_write_callback = extern "C" fn(
|
||||
*mut c_void,
|
||||
*mut hyper_context<'_>,
|
||||
*const u8,
|
||||
size_t,
|
||||
) -> size_t;
|
||||
/// An IO object used to represent a socket or similar concept.
|
||||
pub(crate) struct hyper_io {
|
||||
read: hyper_io_read_callback,
|
||||
write: hyper_io_write_callback,
|
||||
userdata: *mut c_void,
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Create a new IO type used to represent a transport."] #[doc = ""] #[doc =
|
||||
" The read and write functions of this transport should be set with"] #[doc =
|
||||
" `hyper_io_set_read` and `hyper_io_set_write`."] fn hyper_io_new() -> * mut hyper_io
|
||||
{ Box::into_raw(Box::new(hyper_io { read : read_noop, write : write_noop, userdata :
|
||||
std::ptr::null_mut(), })) } ?= std::ptr::null_mut()
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Free an unused `hyper_io *`."] #[doc = ""] #[doc =
|
||||
" This is typically only useful if you aren't going to pass ownership"] #[doc =
|
||||
" of the IO handle to hyper, such as with `hyper_clientconn_handshake()`."] fn
|
||||
hyper_io_free(io : * mut hyper_io) { drop(non_null!(Box::from_raw(io) ?= ())); }
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Set the user data pointer for this IO to some value."] #[doc = ""] #[doc =
|
||||
" This value is passed as an argument to the read and write callbacks."] fn
|
||||
hyper_io_set_userdata(io : * mut hyper_io, data : * mut c_void) { non_null!(& mut *
|
||||
io ?= ()) .userdata = data; }
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Set the read function for this IO transport."] #[doc = ""] #[doc =
|
||||
" Data that is read from the transport should be put in the `buf` pointer,"] #[doc =
|
||||
" up to `buf_len` bytes. The number of bytes read should be the return value."] #[doc
|
||||
= ""] #[doc =
|
||||
" It is undefined behavior to try to access the bytes in the `buf` pointer,"] #[doc =
|
||||
" unless you have already written them yourself. It is also undefined behavior"]
|
||||
#[doc =
|
||||
" to return that more bytes have been written than actually set on the `buf`."] #[doc
|
||||
= ""] #[doc =
|
||||
" If there is no data currently available, a waker should be claimed from"] #[doc =
|
||||
" the `ctx` and registered with whatever polling mechanism is used to signal"] #[doc
|
||||
= " when data is available later on. The return value should be"] #[doc =
|
||||
" `HYPER_IO_PENDING`."] #[doc = ""] #[doc =
|
||||
" If there is an irrecoverable error reading data, then `HYPER_IO_ERROR`"] #[doc =
|
||||
" should be the return value."] fn hyper_io_set_read(io : * mut hyper_io, func :
|
||||
hyper_io_read_callback) { non_null!(& mut * io ?= ()) .read = func; }
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Set the write function for this IO transport."] #[doc = ""] #[doc =
|
||||
" Data from the `buf` pointer should be written to the transport, up to"] #[doc =
|
||||
" `buf_len` bytes. The number of bytes written should be the return value."] #[doc =
|
||||
""] #[doc = " If no data can currently be written, the `waker` should be cloned and"]
|
||||
#[doc = " registered with whatever polling mechanism is used to signal when data"]
|
||||
#[doc = " is available later on. The return value should be `HYPER_IO_PENDING`."]
|
||||
#[doc = ""] #[doc = " Yeet."] #[doc = ""] #[doc =
|
||||
" If there is an irrecoverable error reading data, then `HYPER_IO_ERROR`"] #[doc =
|
||||
" should be the return value."] fn hyper_io_set_write(io : * mut hyper_io, func :
|
||||
hyper_io_write_callback) { non_null!(& mut * io ?= ()) .write = func; }
|
||||
}
|
||||
/// cbindgen:ignore
|
||||
extern "C" fn read_noop(
|
||||
_userdata: *mut c_void,
|
||||
_: *mut hyper_context<'_>,
|
||||
_buf: *mut u8,
|
||||
_buf_len: size_t,
|
||||
) -> size_t {
|
||||
0
|
||||
}
|
||||
/// cbindgen:ignore
|
||||
extern "C" fn write_noop(
|
||||
_userdata: *mut c_void,
|
||||
_: *mut hyper_context<'_>,
|
||||
_buf: *const u8,
|
||||
_buf_len: size_t,
|
||||
) -> size_t {
|
||||
0
|
||||
}
|
||||
impl AsyncRead for hyper_io {
|
||||
fn poll_read(
|
||||
self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
buf: &mut tokio::io::ReadBuf<'_>,
|
||||
) -> Poll<std::io::Result<()>> {
|
||||
let buf_ptr = unsafe { buf.unfilled_mut() }.as_mut_ptr() as *mut u8;
|
||||
let buf_len = buf.remaining();
|
||||
match (self.read)(self.userdata, hyper_context::wrap(cx), buf_ptr, buf_len) {
|
||||
HYPER_IO_PENDING => Poll::Pending,
|
||||
HYPER_IO_ERROR => {
|
||||
Poll::Ready(
|
||||
Err(std::io::Error::new(std::io::ErrorKind::Other, "io error")),
|
||||
)
|
||||
}
|
||||
ok => {
|
||||
unsafe { buf.assume_init(ok) };
|
||||
buf.advance(ok);
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl AsyncWrite for hyper_io {
|
||||
fn poll_write(
|
||||
self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
buf: &[u8],
|
||||
) -> Poll<std::io::Result<usize>> {
|
||||
let buf_ptr = buf.as_ptr();
|
||||
let buf_len = buf.len();
|
||||
match (self.write)(self.userdata, hyper_context::wrap(cx), buf_ptr, buf_len) {
|
||||
HYPER_IO_PENDING => Poll::Pending,
|
||||
HYPER_IO_ERROR => {
|
||||
Poll::Ready(
|
||||
Err(std::io::Error::new(std::io::ErrorKind::Other, "io error")),
|
||||
)
|
||||
}
|
||||
ok => Poll::Ready(Ok(ok)),
|
||||
}
|
||||
}
|
||||
fn poll_flush(
|
||||
self: Pin<&mut Self>,
|
||||
_: &mut Context<'_>,
|
||||
) -> Poll<std::io::Result<()>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
fn poll_shutdown(
|
||||
self: Pin<&mut Self>,
|
||||
_: &mut Context<'_>,
|
||||
) -> Poll<std::io::Result<()>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
}
|
||||
unsafe impl Send for hyper_io {}
|
||||
unsafe impl Sync for hyper_io {}
|
||||
53
hyper/src/ffi/macros.rs
Normal file
53
hyper/src/ffi/macros.rs
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
macro_rules! ffi_fn {
|
||||
($(#[$doc:meta])* fn $name:ident($($arg:ident: $arg_ty:ty),*) -> $ret:ty $body:block ?= $default:expr) => {
|
||||
$(#[$doc])*
|
||||
#[no_mangle]
|
||||
pub extern fn $name($($arg: $arg_ty),*) -> $ret {
|
||||
use std::panic::{self, AssertUnwindSafe};
|
||||
|
||||
match panic::catch_unwind(AssertUnwindSafe(move || $body)) {
|
||||
Ok(v) => v,
|
||||
Err(_) => {
|
||||
$default
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
($(#[$doc:meta])* fn $name:ident($($arg:ident: $arg_ty:ty),*) -> $ret:ty $body:block) => {
|
||||
ffi_fn!($(#[$doc])* fn $name($($arg: $arg_ty),*) -> $ret $body ?= {
|
||||
eprintln!("panic unwind caught, aborting");
|
||||
std::process::abort()
|
||||
});
|
||||
};
|
||||
|
||||
($(#[$doc:meta])* fn $name:ident($($arg:ident: $arg_ty:ty),*) $body:block ?= $default:expr) => {
|
||||
ffi_fn!($(#[$doc])* fn $name($($arg: $arg_ty),*) -> () $body ?= $default);
|
||||
};
|
||||
|
||||
($(#[$doc:meta])* fn $name:ident($($arg:ident: $arg_ty:ty),*) $body:block) => {
|
||||
ffi_fn!($(#[$doc])* fn $name($($arg: $arg_ty),*) -> () $body);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! non_null {
|
||||
($ptr:ident, $eval:expr, $err:expr) => {{
|
||||
debug_assert!(!$ptr.is_null(), "{:?} must not be null", stringify!($ptr));
|
||||
if $ptr.is_null() {
|
||||
return $err;
|
||||
}
|
||||
unsafe { $eval }
|
||||
}};
|
||||
(&*$ptr:ident ?= $err:expr) => {{
|
||||
non_null!($ptr, &*$ptr, $err)
|
||||
}};
|
||||
(&mut *$ptr:ident ?= $err:expr) => {{
|
||||
non_null!($ptr, &mut *$ptr, $err)
|
||||
}};
|
||||
(Box::from_raw($ptr:ident) ?= $err:expr) => {{
|
||||
non_null!($ptr, Box::from_raw($ptr), $err)
|
||||
}};
|
||||
(Arc::from_raw($ptr:ident) ?= $err:expr) => {{
|
||||
non_null!($ptr, Arc::from_raw($ptr), $err)
|
||||
}};
|
||||
}
|
||||
73
hyper/src/ffi/mod.rs
Normal file
73
hyper/src/ffi/mod.rs
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
#![allow(non_camel_case_types)]
|
||||
#![allow(missing_debug_implementations)]
|
||||
#![allow(unreachable_pub)]
|
||||
//! # hyper C API
|
||||
//!
|
||||
//! This part of the documentation describes the C API for hyper. That is, how
|
||||
//! to *use* the hyper library in C code. This is **not** a regular Rust
|
||||
//! module, and thus it is not accessible in Rust.
|
||||
//!
|
||||
//! ## Unstable
|
||||
//!
|
||||
//! The C API of hyper is currently **unstable**, which means it's not part of
|
||||
//! the semver contract as the rest of the Rust API is. Because of that, it's
|
||||
//! only accessible if `--cfg hyper_unstable_ffi` is passed to `rustc` when
|
||||
//! compiling. The easiest way to do that is setting the `RUSTFLAGS`
|
||||
//! environment variable.
|
||||
//!
|
||||
//! ## Building
|
||||
//!
|
||||
//! The C API is part of the Rust library, but isn't compiled by default. Using
|
||||
//! `cargo`, it can be compiled with the following command:
|
||||
//!
|
||||
//! ```notrust
|
||||
//! RUSTFLAGS="--cfg hyper_unstable_ffi" cargo build --features client,http1,http2,ffi
|
||||
//! ```
|
||||
#[cfg(not(all(feature = "client", feature = "http1")))]
|
||||
compile_error!(
|
||||
"The `ffi` feature currently requires the `client` and `http1` features."
|
||||
);
|
||||
#[cfg(not(hyper_unstable_ffi))]
|
||||
compile_error!(
|
||||
"\
|
||||
The `ffi` feature is unstable, and requires the \
|
||||
`RUSTFLAGS='--cfg hyper_unstable_ffi'` environment variable to be set.\
|
||||
"
|
||||
);
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
mod body;
|
||||
mod client;
|
||||
mod error;
|
||||
mod http_types;
|
||||
mod io;
|
||||
mod task;
|
||||
pub(crate) use self::body::*;
|
||||
pub(crate) use self::client::*;
|
||||
pub(crate) use self::error::*;
|
||||
pub(crate) use self::http_types::*;
|
||||
pub(crate) use self::io::*;
|
||||
pub(crate) use self::task::*;
|
||||
/// Return in iter functions to continue iterating.
|
||||
pub(crate) const HYPER_ITER_CONTINUE: libc::c_int = 0;
|
||||
/// Return in iter functions to stop iterating.
|
||||
#[allow(unused)]
|
||||
pub(crate) const HYPER_ITER_BREAK: libc::c_int = 1;
|
||||
/// An HTTP Version that is unspecified.
|
||||
pub(crate) const HYPER_HTTP_VERSION_NONE: libc::c_int = 0;
|
||||
/// The HTTP/1.0 version.
|
||||
pub(crate) const HYPER_HTTP_VERSION_1_0: libc::c_int = 10;
|
||||
/// The HTTP/1.1 version.
|
||||
pub(crate) const HYPER_HTTP_VERSION_1_1: libc::c_int = 11;
|
||||
/// The HTTP/2 version.
|
||||
pub(crate) const HYPER_HTTP_VERSION_2: libc::c_int = 20;
|
||||
struct UserDataPointer(*mut std::ffi::c_void);
|
||||
unsafe impl Send for UserDataPointer {}
|
||||
unsafe impl Sync for UserDataPointer {}
|
||||
/// cbindgen:ignore
|
||||
static VERSION_CSTR: &str = concat!(env!("CARGO_PKG_VERSION"), "\0");
|
||||
ffi_fn! {
|
||||
#[doc = " Returns a static ASCII (null terminated) string of the hyper version."] fn
|
||||
hyper_version() -> * const libc::c_char { VERSION_CSTR.as_ptr() as _ } ?=
|
||||
std::ptr::null()
|
||||
}
|
||||
296
hyper/src/ffi/task.rs
Normal file
296
hyper/src/ffi/task.rs
Normal file
|
|
@ -0,0 +1,296 @@
|
|||
use std::ffi::c_void;
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::ptr;
|
||||
use std::sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
Arc, Mutex, Weak,
|
||||
};
|
||||
use std::task::{Context, Poll};
|
||||
use futures_util::stream::{FuturesUnordered, Stream};
|
||||
use libc::c_int;
|
||||
use super::error::hyper_code;
|
||||
use super::UserDataPointer;
|
||||
type BoxFuture<T> = Pin<Box<dyn Future<Output = T> + Send>>;
|
||||
type BoxAny = Box<dyn AsTaskType + Send + Sync>;
|
||||
/// Return in a poll function to indicate it was ready.
|
||||
pub(crate) const HYPER_POLL_READY: c_int = 0;
|
||||
/// Return in a poll function to indicate it is still pending.
|
||||
///
|
||||
/// The passed in `hyper_waker` should be registered to wake up the task at
|
||||
/// some later point.
|
||||
pub(crate) const HYPER_POLL_PENDING: c_int = 1;
|
||||
/// Return in a poll function indicate an error.
|
||||
pub(crate) const HYPER_POLL_ERROR: c_int = 3;
|
||||
/// A task executor for `hyper_task`s.
|
||||
pub(crate) struct hyper_executor {
|
||||
/// The executor of all task futures.
|
||||
///
|
||||
/// There should never be contention on the mutex, as it is only locked
|
||||
/// to drive the futures. However, we cannot guarantee proper usage from
|
||||
/// `hyper_executor_poll()`, which in C could potentially be called inside
|
||||
/// one of the stored futures. The mutex isn't re-entrant, so doing so
|
||||
/// would result in a deadlock, but that's better than data corruption.
|
||||
driver: Mutex<FuturesUnordered<TaskFuture>>,
|
||||
/// The queue of futures that need to be pushed into the `driver`.
|
||||
///
|
||||
/// This is has a separate mutex since `spawn` could be called from inside
|
||||
/// a future, which would mean the driver's mutex is already locked.
|
||||
spawn_queue: Mutex<Vec<TaskFuture>>,
|
||||
/// This is used to track when a future calls `wake` while we are within
|
||||
/// `hyper_executor::poll_next`.
|
||||
is_woken: Arc<ExecWaker>,
|
||||
}
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct WeakExec(Weak<hyper_executor>);
|
||||
struct ExecWaker(AtomicBool);
|
||||
/// An async task.
|
||||
pub(crate) struct hyper_task {
|
||||
future: BoxFuture<BoxAny>,
|
||||
output: Option<BoxAny>,
|
||||
userdata: UserDataPointer,
|
||||
}
|
||||
struct TaskFuture {
|
||||
task: Option<Box<hyper_task>>,
|
||||
}
|
||||
/// An async context for a task that contains the related waker.
|
||||
pub(crate) struct hyper_context<'a>(Context<'a>);
|
||||
/// A waker that is saved and used to waken a pending task.
|
||||
pub(crate) struct hyper_waker {
|
||||
waker: std::task::Waker,
|
||||
}
|
||||
/// A descriptor for what type a `hyper_task` value is.
|
||||
#[repr(C)]
|
||||
pub(crate) enum hyper_task_return_type {
|
||||
/// The value of this task is null (does not imply an error).
|
||||
HYPER_TASK_EMPTY,
|
||||
/// The value of this task is `hyper_error *`.
|
||||
HYPER_TASK_ERROR,
|
||||
/// The value of this task is `hyper_clientconn *`.
|
||||
HYPER_TASK_CLIENTCONN,
|
||||
/// The value of this task is `hyper_response *`.
|
||||
HYPER_TASK_RESPONSE,
|
||||
/// The value of this task is `hyper_buf *`.
|
||||
HYPER_TASK_BUF,
|
||||
}
|
||||
pub(crate) unsafe trait AsTaskType {
|
||||
fn as_task_type(&self) -> hyper_task_return_type;
|
||||
}
|
||||
pub(crate) trait IntoDynTaskType {
|
||||
fn into_dyn_task_type(self) -> BoxAny;
|
||||
}
|
||||
impl hyper_executor {
|
||||
fn new() -> Arc<hyper_executor> {
|
||||
Arc::new(hyper_executor {
|
||||
driver: Mutex::new(FuturesUnordered::new()),
|
||||
spawn_queue: Mutex::new(Vec::new()),
|
||||
is_woken: Arc::new(ExecWaker(AtomicBool::new(false))),
|
||||
})
|
||||
}
|
||||
pub(crate) fn downgrade(exec: &Arc<hyper_executor>) -> WeakExec {
|
||||
WeakExec(Arc::downgrade(exec))
|
||||
}
|
||||
fn spawn(&self, task: Box<hyper_task>) {
|
||||
self.spawn_queue.lock().unwrap().push(TaskFuture { task: Some(task) });
|
||||
}
|
||||
fn poll_next(&self) -> Option<Box<hyper_task>> {
|
||||
self.drain_queue();
|
||||
let waker = futures_util::task::waker_ref(&self.is_woken);
|
||||
let mut cx = Context::from_waker(&waker);
|
||||
loop {
|
||||
match Pin::new(&mut *self.driver.lock().unwrap()).poll_next(&mut cx) {
|
||||
Poll::Ready(val) => return val,
|
||||
Poll::Pending => {
|
||||
if self.drain_queue() {
|
||||
continue;
|
||||
}
|
||||
if self.is_woken.0.swap(false, Ordering::SeqCst) {
|
||||
continue;
|
||||
}
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fn drain_queue(&self) -> bool {
|
||||
let mut queue = self.spawn_queue.lock().unwrap();
|
||||
if queue.is_empty() {
|
||||
return false;
|
||||
}
|
||||
let driver = self.driver.lock().unwrap();
|
||||
for task in queue.drain(..) {
|
||||
driver.push(task);
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
impl futures_util::task::ArcWake for ExecWaker {
|
||||
fn wake_by_ref(me: &Arc<ExecWaker>) {
|
||||
me.0.store(true, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
impl WeakExec {
|
||||
pub(crate) fn new() -> Self {
|
||||
WeakExec(Weak::new())
|
||||
}
|
||||
}
|
||||
impl crate::rt::Executor<BoxFuture<()>> for WeakExec {
|
||||
fn execute(&self, fut: BoxFuture<()>) {
|
||||
if let Some(exec) = self.0.upgrade() {
|
||||
exec.spawn(hyper_task::boxed(fut));
|
||||
}
|
||||
}
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Creates a new task executor."] fn hyper_executor_new() -> * const
|
||||
hyper_executor { Arc::into_raw(hyper_executor::new()) } ?= ptr::null()
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Frees an executor and any incomplete tasks still part of it."] fn
|
||||
hyper_executor_free(exec : * const hyper_executor) {
|
||||
drop(non_null!(Arc::from_raw(exec) ?= ())); }
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Push a task onto the executor."] #[doc = ""] #[doc =
|
||||
" The executor takes ownership of the task, it should not be accessed"] #[doc =
|
||||
" again unless returned back to the user with `hyper_executor_poll`."] fn
|
||||
hyper_executor_push(exec : * const hyper_executor, task : * mut hyper_task) ->
|
||||
hyper_code { let exec = non_null!(&* exec ?= hyper_code::HYPERE_INVALID_ARG); let
|
||||
task = non_null!(Box::from_raw(task) ?= hyper_code::HYPERE_INVALID_ARG); exec
|
||||
.spawn(task); hyper_code::HYPERE_OK }
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc =
|
||||
" Polls the executor, trying to make progress on any tasks that have notified"] #[doc
|
||||
= " that they are ready again."] #[doc = ""] #[doc =
|
||||
" If ready, returns a task from the executor that has completed."] #[doc = ""] #[doc
|
||||
= " If there are no ready tasks, this returns `NULL`."] fn hyper_executor_poll(exec :
|
||||
* const hyper_executor) -> * mut hyper_task { let exec = non_null!(&* exec ?=
|
||||
ptr::null_mut()); match exec.poll_next() { Some(task) => Box::into_raw(task), None =>
|
||||
ptr::null_mut(), } } ?= ptr::null_mut()
|
||||
}
|
||||
impl hyper_task {
|
||||
pub(crate) fn boxed<F>(fut: F) -> Box<hyper_task>
|
||||
where
|
||||
F: Future + Send + 'static,
|
||||
F::Output: IntoDynTaskType + Send + Sync + 'static,
|
||||
{
|
||||
Box::new(hyper_task {
|
||||
future: Box::pin(async move { fut.await.into_dyn_task_type() }),
|
||||
output: None,
|
||||
userdata: UserDataPointer(ptr::null_mut()),
|
||||
})
|
||||
}
|
||||
fn output_type(&self) -> hyper_task_return_type {
|
||||
match self.output {
|
||||
None => hyper_task_return_type::HYPER_TASK_EMPTY,
|
||||
Some(ref val) => val.as_task_type(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Future for TaskFuture {
|
||||
type Output = Box<hyper_task>;
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
match Pin::new(&mut self.task.as_mut().unwrap().future).poll(cx) {
|
||||
Poll::Ready(val) => {
|
||||
let mut task = self.task.take().unwrap();
|
||||
task.output = Some(val);
|
||||
Poll::Ready(task)
|
||||
}
|
||||
Poll::Pending => Poll::Pending,
|
||||
}
|
||||
}
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Free a task."] fn hyper_task_free(task : * mut hyper_task) {
|
||||
drop(non_null!(Box::from_raw(task) ?= ())); }
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Takes the output value of this task."] #[doc = ""] #[doc =
|
||||
" This must only be called once polling the task on an executor has finished"] #[doc
|
||||
= " this task."] #[doc = ""] #[doc =
|
||||
" Use `hyper_task_type` to determine the type of the `void *` return value."] fn
|
||||
hyper_task_value(task : * mut hyper_task) -> * mut c_void { let task = non_null!(&
|
||||
mut * task ?= ptr::null_mut()); if let Some(val) = task.output.take() { let p =
|
||||
Box::into_raw(val) as * mut c_void; if p == std::ptr::NonNull::< c_void >::dangling()
|
||||
.as_ptr() { ptr::null_mut() } else { p } } else { ptr::null_mut() } } ?=
|
||||
ptr::null_mut()
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Query the return type of this task."] fn hyper_task_type(task : * mut
|
||||
hyper_task) -> hyper_task_return_type { non_null!(&* task ?=
|
||||
hyper_task_return_type::HYPER_TASK_EMPTY) .output_type() }
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Set a user data pointer to be associated with this task."] #[doc = ""]
|
||||
#[doc = " This value will be passed to task callbacks, and can be checked later"]
|
||||
#[doc = " with `hyper_task_userdata`."] fn hyper_task_set_userdata(task : * mut
|
||||
hyper_task, userdata : * mut c_void) { if task.is_null() { return; } unsafe { (*
|
||||
task).userdata = UserDataPointer(userdata) }; }
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Retrieve the userdata that has been set via `hyper_task_set_userdata`."] fn
|
||||
hyper_task_userdata(task : * mut hyper_task) -> * mut c_void { non_null!(&* task ?=
|
||||
ptr::null_mut()) .userdata.0 } ?= ptr::null_mut()
|
||||
}
|
||||
unsafe impl AsTaskType for () {
|
||||
fn as_task_type(&self) -> hyper_task_return_type {
|
||||
hyper_task_return_type::HYPER_TASK_EMPTY
|
||||
}
|
||||
}
|
||||
unsafe impl AsTaskType for crate::Error {
|
||||
fn as_task_type(&self) -> hyper_task_return_type {
|
||||
hyper_task_return_type::HYPER_TASK_ERROR
|
||||
}
|
||||
}
|
||||
impl<T> IntoDynTaskType for T
|
||||
where
|
||||
T: AsTaskType + Send + Sync + 'static,
|
||||
{
|
||||
fn into_dyn_task_type(self) -> BoxAny {
|
||||
Box::new(self)
|
||||
}
|
||||
}
|
||||
impl<T> IntoDynTaskType for crate::Result<T>
|
||||
where
|
||||
T: IntoDynTaskType + Send + Sync + 'static,
|
||||
{
|
||||
fn into_dyn_task_type(self) -> BoxAny {
|
||||
match self {
|
||||
Ok(val) => val.into_dyn_task_type(),
|
||||
Err(err) => Box::new(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T> IntoDynTaskType for Option<T>
|
||||
where
|
||||
T: IntoDynTaskType + Send + Sync + 'static,
|
||||
{
|
||||
fn into_dyn_task_type(self) -> BoxAny {
|
||||
match self {
|
||||
Some(val) => val.into_dyn_task_type(),
|
||||
None => ().into_dyn_task_type(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl hyper_context<'_> {
|
||||
pub(crate) fn wrap<'a, 'b>(cx: &'a mut Context<'b>) -> &'a mut hyper_context<'b> {
|
||||
unsafe { std::mem::transmute::<&mut Context<'_>, &mut hyper_context<'_>>(cx) }
|
||||
}
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Copies a waker out of the task context."] fn hyper_context_waker(cx : * mut
|
||||
hyper_context <'_ >) -> * mut hyper_waker { let waker = non_null!(& mut * cx ?=
|
||||
ptr::null_mut()) .0.waker().clone(); Box::into_raw(Box::new(hyper_waker { waker })) }
|
||||
?= ptr::null_mut()
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Free a waker that hasn't been woken."] fn hyper_waker_free(waker : * mut
|
||||
hyper_waker) { drop(non_null!(Box::from_raw(waker) ?= ())); }
|
||||
}
|
||||
ffi_fn! {
|
||||
#[doc = " Wake up the task associated with a waker."] #[doc = ""] #[doc =
|
||||
" NOTE: This consumes the waker. You should not use or free the waker afterwards."]
|
||||
fn hyper_waker_wake(waker : * mut hyper_waker) { let waker =
|
||||
non_null!(Box::from_raw(waker) ?= ()); waker.waker.wake(); }
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue