Skip to content
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 more documentation for the FFI API #3424

Merged
merged 1 commit into from
Nov 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
28 changes: 14 additions & 14 deletions capi/include/hyper.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ typedef struct hyper_executor hyper_executor;
typedef struct hyper_headers hyper_headers;

/*
An IO object used to represent a socket or similar concept.
A read/write handle for a specific connection.
*/
typedef struct hyper_io hyper_io;

Expand Down Expand Up @@ -214,7 +214,7 @@ extern "C" {
const char *hyper_version(void);

/*
Create a new "empty" body.
Creates a new "empty" body.
*/
struct hyper_body *hyper_body_new(void);

Expand All @@ -224,12 +224,12 @@ struct hyper_body *hyper_body_new(void);
void hyper_body_free(struct hyper_body *body);

/*
Return a task that will poll the body for the next buffer of data.
Creates a task that will poll a response body for the next buffer of data.
*/
struct hyper_task *hyper_body_data(struct hyper_body *body);

/*
Return a task that will poll the body and execute the callback with each
Creates a task to execute the callback with each body chunk received.
*/
struct hyper_task *hyper_body_foreach(struct hyper_body *body,
hyper_body_foreach_callback func,
Expand All @@ -241,7 +241,7 @@ struct hyper_task *hyper_body_foreach(struct hyper_body *body,
void hyper_body_set_userdata(struct hyper_body *body, void *userdata);

/*
Set the data callback for this body.
Set the outgoing data callback for this body.
*/
void hyper_body_set_data_func(struct hyper_body *body, hyper_body_data_callback func);

Expand All @@ -266,13 +266,13 @@ size_t hyper_buf_len(const struct hyper_buf *buf);
void hyper_buf_free(struct hyper_buf *buf);

/*
Starts an HTTP client connection handshake using the provided IO transport
Creates an HTTP client handshake task.
*/
struct hyper_task *hyper_clientconn_handshake(struct hyper_io *io,
struct hyper_clientconn_options *options);

/*
Send a request on the client connection.
Creates a task to send a request on the client connection.
*/
struct hyper_task *hyper_clientconn_send(struct hyper_clientconn *conn, struct hyper_request *req);

Expand All @@ -287,13 +287,13 @@ void hyper_clientconn_free(struct hyper_clientconn *conn);
struct hyper_clientconn_options *hyper_clientconn_options_new(void);

/*
Set the whether or not header case is preserved.
Set whether header case is preserved.
*/
void hyper_clientconn_options_set_preserve_header_case(struct hyper_clientconn_options *opts,
int enabled);

/*
Set the whether or not header order is preserved.
Set whether header order is preserved.
*/
void hyper_clientconn_options_set_preserve_header_order(struct hyper_clientconn_options *opts,
int enabled);
Expand All @@ -310,12 +310,12 @@ void hyper_clientconn_options_exec(struct hyper_clientconn_options *opts,
const struct hyper_executor *exec);

/*
Set the whether to use HTTP2.
Set whether to use HTTP2.
*/
enum hyper_code hyper_clientconn_options_http2(struct hyper_clientconn_options *opts, int enabled);

/*
Set whether HTTP/1 connections will accept obsolete line folding for header values.
Set whether HTTP/1 connections accept obsolete line folding for header values.
*/
enum hyper_code hyper_clientconn_options_http1_allow_multiline_headers(struct hyper_clientconn_options *opts,
int enabled);
Expand Down Expand Up @@ -376,7 +376,7 @@ enum hyper_code hyper_request_set_uri_parts(struct hyper_request *req,
enum hyper_code hyper_request_set_version(struct hyper_request *req, int version);

/*
Gets a reference to the HTTP headers of this request
Gets a mutable reference to the HTTP headers of this request
*/
struct hyper_headers *hyper_request_headers(struct hyper_request *req);

Expand Down Expand Up @@ -493,7 +493,7 @@ void hyper_executor_free(const struct hyper_executor *exec);
enum hyper_code hyper_executor_push(const struct hyper_executor *exec, struct hyper_task *task);

/*
Polls the executor, trying to make progress on any tasks that have notified
Polls the executor, trying to make progress on any tasks that can do so.
*/
struct hyper_task *hyper_executor_poll(const struct hyper_executor *exec);

Expand Down Expand Up @@ -523,7 +523,7 @@ void hyper_task_set_userdata(struct hyper_task *task, void *userdata);
void *hyper_task_userdata(struct hyper_task *task);

/*
Copies a waker out of the task context.
Creates a waker associated with the task context.
*/
struct hyper_waker *hyper_context_waker(struct hyper_context *cx);

Expand Down
65 changes: 54 additions & 11 deletions src/ffi/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,39 @@ use super::{UserDataPointer, HYPER_ITER_CONTINUE};
use crate::body::{Bytes, Frame, Incoming as IncomingBody};

/// A streaming HTTP body.
///
/// This is used both for sending requests (with `hyper_request_set_body`) and
/// for receiving responses (with `hyper_response_body`).
///
/// For outgoing request bodies, call `hyper_body_set_data_func` to provide the
/// data.
///
/// For incoming response bodies, call `hyper_body_data` to get a task that will
/// yield a chunk of data each time it is polled. That task must be then be
/// added to the executor with `hyper_executor_push`.
///
/// Methods:
///
/// - hyper_body_new: Create a new “empty” body.
/// - hyper_body_set_userdata: Set userdata on this body, which will be passed to callback functions.
/// - hyper_body_set_data_func: Set the data callback for this body.
/// - hyper_body_data: Creates a task that will poll a response body for the next buffer of data.
/// - hyper_body_foreach: Creates a task to execute the callback with each body chunk received.
/// - hyper_body_free: Free a body.
pub struct hyper_body(pub(super) IncomingBody);

/// A buffer of bytes that is sent or received on a `hyper_body`.
///
/// Obtain one of these in the callback of `hyper_body_foreach` or by receiving
/// a task of type `HYPER_TASK_BUF` from `hyper_executor_poll` (after calling
/// `hyper_body_data` and pushing the resulting task).
///
/// Methods:
///
/// - hyper_buf_bytes: Get a pointer to the bytes in this buffer.
/// - hyper_buf_copy: Create a new hyper_buf * by copying the provided bytes.
/// - hyper_buf_free: Free this buffer.
/// - hyper_buf_len: Get the length of the bytes this buffer contains.
pub struct hyper_buf(pub(crate) Bytes);

pub(crate) struct UserBody {
Expand All @@ -29,7 +59,7 @@ type hyper_body_data_callback =
extern "C" fn(*mut c_void, *mut hyper_context<'_>, *mut *mut hyper_buf) -> c_int;

ffi_fn! {
/// Create a new "empty" body.
/// Creates a new "empty" body.
///
/// If not configured, this body acts as an empty payload.
///
Expand All @@ -51,20 +81,31 @@ ffi_fn! {
}

ffi_fn! {
/// Return a task that will poll the body for the next buffer of data.
/// Creates a task that will poll a response body for the next buffer of data.
///
/// The task value may have different types depending on the outcome:
/// The task may have different types depending on the outcome:
///
/// - `HYPER_TASK_BUF`: Success, and more data was received.
/// - `HYPER_TASK_ERROR`: An error retrieving the data.
/// - `HYPER_TASK_EMPTY`: The body has finished streaming data.
///
/// When the application receives the task from `hyper_executor_poll`,
/// if the task type is `HYPER_TASK_BUF`, it should cast the task to
/// `hyper_buf *` and consume all the bytes in the buffer. Then
/// the application should call `hyper_body_data` again for the same
/// `hyper_body *`, to create a task for the next buffer of data.
/// Repeat until the polled task type is `HYPER_TASK_ERROR` or
/// `HYPER_TASK_EMPTY`.
///
/// To avoid a memory leak, the task must eventually be consumed by
/// `hyper_task_free`, or taken ownership of by `hyper_executor_push`
/// without subsequently being given back by `hyper_executor_poll`.
///
/// This does not consume the `hyper_body *`, so it may be used to again.
/// However, it MUST NOT be used or freed until the related task completes.
/// This does not consume the `hyper_body *`, so it may be used again.
/// However, the `hyper_body *` MUST NOT be used or freed until the
/// related task is returned from `hyper_executor_poll`.
///
/// For a more convenient method, see also `hyper_body_foreach`.
fn hyper_body_data(body: *mut hyper_body) -> *mut hyper_task {
// This doesn't take ownership of the Body, so don't allow destructor
let mut body = ManuallyDrop::new(non_null!(Box::from_raw(body) ?= ptr::null_mut()));
Expand All @@ -88,18 +129,20 @@ ffi_fn! {
}

ffi_fn! {
/// Return a task that will poll the body and execute the callback with each
/// body chunk that is received.
/// Creates a task to execute the callback with each body chunk received.
///
/// To avoid a memory leak, the task must eventually be consumed by
/// `hyper_task_free`, or taken ownership of by `hyper_executor_push`
/// without subsequently being given back by `hyper_executor_poll`.
///
/// The `hyper_buf` pointer is only a borrowed reference, it cannot live outside
/// the execution of the callback. You must make a copy to retain it.
/// The `hyper_buf` pointer is only a borrowed reference. It cannot live outside
/// the execution of the callback. You must make a copy of the bytes to retain them.
///
/// The callback should return `HYPER_ITER_CONTINUE` to continue iterating
/// chunks as they are received, or `HYPER_ITER_BREAK` to cancel.
/// chunks as they are received, or `HYPER_ITER_BREAK` to cancel. Each
/// invocation of the callback must consume all the bytes it is provided.
/// There is no mechanism to signal to Hyper that only a subset of bytes were
/// consumed.
///
/// 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 {
Expand Down Expand Up @@ -129,7 +172,7 @@ ffi_fn! {
}

ffi_fn! {
/// Set the data callback for this body.
/// Set the outgoing data callback for this body.
///
/// The callback is called each time hyper needs to send more data for the
/// body. It is passed the value from `hyper_body_set_userdata`.
Expand Down
63 changes: 53 additions & 10 deletions src/ffi/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,16 @@ 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.
///
/// Methods:
///
/// - hyper_clientconn_options_new: Creates a new set of HTTP clientconn options to be used in a handshake.
/// - hyper_clientconn_options_exec: Set the client background task executor.
/// - hyper_clientconn_options_http2: Set whether to use HTTP2.
/// - hyper_clientconn_options_set_preserve_header_case: Set whether header case is preserved.
/// - hyper_clientconn_options_set_preserve_header_order: Set whether header order is preserved.
/// - hyper_clientconn_options_http1_allow_multiline_headers: Set whether HTTP/1 connections accept obsolete line folding for header values.
/// - hyper_clientconn_options_free: Free a set of HTTP clientconn options.
pub struct hyper_clientconn_options {
http1_allow_obsolete_multiline_headers_in_responses: bool,
http1_preserve_header_case: bool,
Expand All @@ -23,9 +33,42 @@ pub struct hyper_clientconn_options {

/// 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.
/// These are used to send one or more requests 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.
///
/// To create a `hyper_clientconn`:
///
/// 1. Create a `hyper_io` with `hyper_io_new`.
/// 2. Create a `hyper_clientconn_options` with `hyper_clientconn_options_new`.
/// 3. Call `hyper_clientconn_handshake` with the `hyper_io` and `hyper_clientconn_options`.
/// This creates a `hyper_task`.
/// 5. Call `hyper_task_set_userdata` to assign an application-specific pointer to the task.
/// This allows keeping track of multiple connections that may be handshaking
/// simultaneously.
/// 4. Add the `hyper_task` to an executor with `hyper_executor_push`.
/// 5. Poll that executor until it yields a task of type `HYPER_TASK_CLIENTCONN`.
/// 6. Extract the `hyper_clientconn` from the task with `hyper_task_value`.
/// This will require a cast from `void *` to `hyper_clientconn *`.
///
/// This process results in a `hyper_clientconn` that permanently owns the
/// `hyper_io`. Because the `hyper_io` in turn owns a TCP or TLS connection, that means
/// the `hyper_clientconn` owns the connection for both the clientconn's lifetime
/// and the connection's lifetime.
///
/// In other words, each connection (`hyper_io`) must have exactly one `hyper_clientconn`
/// associated with it. That's because `hyper_clientconn_handshake` sends the
/// [HTTP/2 Connection Preface] (for HTTP/2 connections). Since that preface can't
/// be sent twice, handshake can't be called twice.
///
/// [HTTP/2 Connection Preface]: https://datatracker.ietf.org/doc/html/rfc9113#name-http-2-connection-preface
///
/// Methods:
///
/// - hyper_clientconn_handshake: Creates an HTTP client handshake task.
/// - hyper_clientconn_send: Creates a task to send a request on the client connection.
/// - hyper_clientconn_free: Free a hyper_clientconn *.
pub struct hyper_clientconn {
tx: Tx,
}
Expand All @@ -40,8 +83,7 @@ enum Tx {
// ===== impl hyper_clientconn =====

ffi_fn! {
/// Starts an HTTP client connection handshake using the provided IO transport
/// and options.
/// Creates an HTTP client handshake task.
///
/// Both the `io` and the `options` are consumed in this function call.
/// They should not be used or freed afterwards.
Expand Down Expand Up @@ -89,7 +131,7 @@ ffi_fn! {
}

ffi_fn! {
/// Send a request on the client connection.
/// Creates a task to send a request on the client connection.
///
/// This consumes the request. You should not use or free the request
/// afterwards.
Expand Down Expand Up @@ -153,7 +195,7 @@ ffi_fn! {
}

ffi_fn! {
/// Set the whether or not header case is preserved.
/// Set whether header case is preserved.
///
/// 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) {
Expand All @@ -163,7 +205,7 @@ ffi_fn! {
}

ffi_fn! {
/// Set the whether or not header order is preserved.
/// Set whether header order is preserved.
///
/// 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) {
Expand Down Expand Up @@ -198,7 +240,7 @@ ffi_fn! {
}

ffi_fn! {
/// Set the whether to use HTTP2.
/// Set whether to use HTTP2.
///
/// Pass `0` to disable, `1` to enable.
fn hyper_clientconn_options_http2(opts: *mut hyper_clientconn_options, enabled: c_int) -> hyper_code {
Expand All @@ -219,7 +261,8 @@ ffi_fn! {
}

ffi_fn! {
/// Set whether HTTP/1 connections will accept obsolete line folding for header values.
/// Set whether HTTP/1 connections accept obsolete line folding for header values.
///
/// Newline codepoints (\r and \n) will be transformed to spaces when parsing.
///
/// Pass `0` to disable, `1` to enable.
Expand Down
9 changes: 9 additions & 0 deletions src/ffi/error.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
use libc::size_t;

/// A more detailed error object returned by some hyper functions.
///
/// Compare with `hyper_code`, which is a simpler error returned from
/// some hyper functions.
///
/// Methods:
///
/// - hyper_error_code: Get an equivalent hyper_code from this error.
/// - hyper_error_print: Print the details of this error to a buffer.
/// - hyper_error_free: Frees a hyper_error.
pub struct hyper_error(crate::Error);

/// A return code for many of hyper's methods.
Expand Down