/// 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. pubstruct hyper_clientconn_options {
http1_allow_obsolete_multiline_headers_in_responses: bool,
http1_preserve_header_case: bool,
http1_preserve_header_order: bool,
http2: bool, /// Use a `Weak` to prevent cycles.
exec: WeakExec,
}
/// An HTTP client connection handle. /// /// 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 *. pubstruct hyper_clientconn {
tx: Tx,
}
ffi_fn! { /// 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. /// /// The returned task must be polled with an executor until the handshake /// completes, at which point the value can be taken. /// /// 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`. 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() };
ffi_fn! { /// Creates a task to send a request on the client connection. /// /// This consumes the request. You should not use or free the request /// afterwards. /// /// Returns a task that needs to be polled until it is ready. When ready, the /// task yields a `hyper_response *`. /// /// 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`. fn hyper_clientconn_send(conn: *mut hyper_clientconn, req: *mut hyper_request) -> *mut hyper_task { letmut req = non_null! { Box::from_raw(req) ?= ptr::null_mut() };
// Update request with original-case map of headers
req.finalize_request();
let fut = match non_null! { &mut *conn ?= ptr::null_mut() }.tx {
Tx::Http1(refmut tx) => futures_util::future::Either::Left(tx.send_request(req.0)),
Tx::Http2(refmut tx) => futures_util::future::Either::Right(tx.send_request(req.0)),
};
let fut = asyncmove {
fut.await.map(hyper_response::wrap)
};
ffi_fn! { /// Free a `hyper_clientconn *`. /// /// This should be used for any connection once it is no longer needed. fn hyper_clientconn_free(conn: *mut hyper_clientconn) {
drop(non_null! { Box::from_raw(conn) ?= () });
}
}
ffi_fn! { /// Creates a new set of HTTP clientconn options to be used in a handshake. /// /// To avoid a memory leak, the options must eventually be consumed by /// `hyper_clientconn_options_free` or `hyper_clientconn_handshake`. fn hyper_clientconn_options_new() -> *mut hyper_clientconn_options { Box::into_raw(Box::new(hyper_clientconn_options {
http1_allow_obsolete_multiline_headers_in_responses: false,
http1_preserve_header_case: false,
http1_preserve_header_order: false,
http2: false,
exec: WeakExec::new(),
}))
} ?= std::ptr::null_mut()
}
ffi_fn! { /// 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) { let opts = non_null! { &mut *opts ?= () };
opts.http1_preserve_header_case = enabled != 0;
}
}
ffi_fn! { /// 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) { let opts = non_null! { &mut *opts ?= () };
opts.http1_preserve_header_order = enabled != 0;
}
}
ffi_fn! { /// Free a set of HTTP clientconn options. /// /// This should only be used if the options aren't consumed by /// `hyper_clientconn_handshake`. fn hyper_clientconn_options_free(opts: *mut hyper_clientconn_options) {
drop(non_null! { Box::from_raw(opts) ?= () });
}
}
ffi_fn! { /// Set the client background task executor. /// /// 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.exec = weak_exec;
}
}
ffi_fn! { /// 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 { #[cfg(feature = "http2")]
{ let opts = non_null! { &mut *opts ?= hyper_code::HYPERE_INVALID_ARG };
opts.http2 = enabled != 0;
hyper_code::HYPERE_OK
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.