isahc_opendal_workaround/
lib.rs

1//! The practical HTTP client that is fun to use.
2//!
3//! Here are some of Isahc's key features:
4//!
5//! - Full support for HTTP/1.1 and HTTP/2.
6//! - Configurable request timeouts, redirect policies, Unix sockets, and many
7//!   more settings.
8//! - Offers an ergonomic synchronous API as well as a runtime-agnostic
9//!   asynchronous API with support for async/await.
10//! - Fully asynchronous core, with incremental reading and writing of request
11//!   and response bodies and connection multiplexing.
12//! - Sessions and cookie persistence.
13//! - Automatic request cancellation on drop.
14//!
15//! # Getting started
16//!
17//! Sending requests is as easy as calling a single function. Let's make a
18//! simple GET request to an example website:
19//!
20//! ```no_run
21//! use isahc::prelude::*;
22//!
23//! let mut response = isahc::get("https://example.org")?;
24//! println!("{}", response.text()?);
25//! # Ok::<(), isahc::Error>(())
26//! ```
27//!
28//! By default, sending a request will wait for the response, up until the
29//! response headers are received. The returned response struct includes the
30//! response body as an open stream implementing [`Read`](std::io::Read).
31//!
32//! Sending a POST request is also easy, and takes an additional argument for
33//! the request body:
34//!
35//! ```no_run
36//! let response = isahc::post("https://httpbin.org/post", "make me a salad")?;
37//! # Ok::<(), isahc::Error>(())
38//! ```
39//!
40//! Isahc provides several other simple functions for common HTTP request types:
41//!
42//! ```no_run
43//! isahc::put("https://httpbin.org/put", "have a salad")?;
44//! isahc::head("https://httpbin.org/get")?;
45//! isahc::delete("https://httpbin.org/delete")?;
46//! # Ok::<(), isahc::Error>(())
47//! ```
48//!
49//! If you want to customize the request by adding headers, setting timeouts,
50//! etc, then you can create a [`Request`][Request] using a builder-style fluent
51//! interface, then finishing it off with a [`send`][RequestExt::send]:
52//!
53//! ```no_run
54//! use isahc::{prelude::*, Request};
55//! use std::time::Duration;
56//!
57//! let response = Request::post("https://httpbin.org/post")
58//!     .header("Content-Type", "application/json")
59//!     .timeout(Duration::from_secs(5))
60//!     .body(r#"{
61//!         "speed": "fast",
62//!         "cool_name": true
63//!     }"#)?
64//!     .send()?;
65//! # Ok::<(), isahc::Error>(())
66//! ```
67//!
68//! For even more examples used in complete programs, please check out the
69//! [examples](https://github.com/sagebind/isahc/tree/master/examples) directory
70//! in the project repo.
71//!
72//! # Feature tour
73//!
74//! Below is a brief overview of some notable features of Isahc. Check out the
75//! rest of the documentation for even more guides and examples.
76//!
77//! ## Easy request functions
78//!
79//! You can start sending requests without any configuration by using the global
80//! functions in this module, including [`get`], [`post`], and [`send`]. These
81//! use a shared HTTP client instance with sane defaults, so it is easy to get
82//! up and running. They should work perfectly fine for many use-cases, so don't
83//! worry about graduating to more complex APIs if you don't need them.
84//!
85//! ## Request and response traits
86//!
87//! Isahc includes a number of traits in the [`prelude`] module that extend the
88//! [`Request`] and [`Response`] types with a plethora of extra methods that
89//! make common tasks convenient and allow you to configure more advanced
90//! connection and protocol details.
91//!
92//! Here are some of the key traits to read about:
93//!
94//! - [`Configurable`](config::Configurable): Configure request parameters.
95//! - [`RequestExt`]: Manipulate and send requests.
96//! - [`ResponseExt`]: Get information about the corresponding request or
97//!   response statistics.
98//! - [`ReadResponseExt`]: Consume a response body in a variety of ways.
99//! - [`AsyncReadResponseExt`]: Consume an asynchronous response body in a
100//!   variety of ways.
101//!
102//! ## Custom clients
103//!
104//! The free-standing functions for sending requests use a shared [`HttpClient`]
105//! instance, but you can also create your own client instances, which allows
106//! you to customize the default behavior for requests that use it.
107//!
108//! See the documentation for [`HttpClient`] and [`HttpClientBuilder`] for more
109//! information on creating custom clients.
110//!
111//! ## Asynchronous requests
112//!
113//! Requests are always executed asynchronously under the hood. This allows a
114//! single client to execute a large number of requests concurrently with
115//! minimal overhead. Even synchronous applications can benefit!
116//!
117//! If you are writing an asynchronous application, you can reap additional
118//! benefits from the async nature of the client by using the asynchronous
119//! methods available to prevent blocking threads in your code. All request
120//! methods have an asynchronous variant that ends with `_async` in the name.
121//! Here is our first example rewritten to use async/await syntax:
122//!
123//! ```no_run
124//! # async fn run() -> Result<(), isahc::Error> {
125//! use isahc::prelude::*;
126//!
127//! let mut response = isahc::get_async("https://httpbin.org/get").await?;
128//! println!("{}", response.text().await?);
129//! # Ok(()) }
130//! ```
131//!
132//! Since we sent our request using [`get_async`], no blocking will occur, and
133//! the asynchronous versions of all response methods (such as
134//! [`text`](AsyncReadResponseExt::text)) will also automatically be selected by
135//! the compiler.
136//!
137//! # Feature flags
138//!
139//! Isahc is designed to be as "pay-as-you-need" as possible using Cargo feature
140//! flags and optional dependencies. Unstable features are also initially
141//! released behind feature flags until they are stabilized. You can add the
142//! feature names below to your `Cargo.toml` file to enable them:
143//!
144//! ```toml
145//! [dependencies.isahc]
146//! version = "1.7"
147//! features = ["psl"]
148//! ```
149//!
150//! Below is a list of all available feature flags and their meanings.
151//!
152//! ## `cookies`
153//!
154//! Enable persistent HTTP cookie support. Disabled by default.
155//!
156//! ## `http2`
157//!
158//! Enable compile-time support for HTTP/2 in libcurl via libnghttp2. This does
159//! not actually affect whether HTTP/2 is used for a given request, but simply
160//! makes it available. To configure which HTTP versions to use in a request,
161//! see [`VersionNegotiation`](config::VersionNegotiation).
162//!
163//! To check which HTTP versions are supported at runtime, you can use
164//! [`is_http_version_supported`].
165//!
166//! Enabled by default.
167//!
168//! ## `json`
169//!
170//! Additional serialization and deserialization of JSON bodies via
171//! [serde](https://serde.rs). Disabled by default.
172//!
173//! ## `psl`
174//!
175//! Enable use of the Public Suffix List to filter out potentially malicious
176//! cross-domain cookies. Implies `cookies`, disabled by default.
177//!
178//! ## `spnego`
179//!
180//! Enable support for [SPNEGO-based HTTP
181//! authentication](https://tools.ietf.org/html/rfc4559) (`negotiate` auth
182//! scheme). This makes the `negotiate` scheme available in the API and, if
183//! `static-curl` is enabled, compiles libcurl with GSS-API APIs. The [MIT
184//! Kerberos](https://web.mit.edu/kerberos/) headers must be pre-installed at
185//! compile time.
186//!
187//! ## `static-curl`
188//!
189//! Use a bundled libcurl version and statically link to it. Enabled by default.
190//!
191//! ## `text-decoding`
192//!
193//! Enable support for decoding text-based responses in various charsets into
194//! strings. Enabled by default.
195//!
196//! ## Unstable APIs
197//!
198//! There are also some features that enable new incubating APIs that do not
199//! have stability guarantees:
200//!
201//! ### `unstable-interceptors`
202//!
203//! Enable the new interceptors API (replaces the old unstable middleware API).
204//! Unstable until the API is finalized. This an unstable feature whose
205//! interface may change between patch releases.
206//!
207//! ### `unstable-rustls-tls`
208//!
209//! Use [rustls](https://github.com/rustls/rustls) as the TLS backend for HTTPS
210//! requests. Currently unstable as the rustls backend in libcurl currently has
211//! some known issues and is not yet recommended for production use.
212//!
213//! # Logging and tracing
214//!
215//! Isahc logs quite a bit of useful information at various levels compatible
216//! with the [log](https://docs.rs/log) crate. For even more in-depth
217//! diagnostics, you can use a [tracing](https://docs.rs/tracing) subscriber to
218//! track log events grouped by individual requests. This can be especially
219//! useful if you are sending multiple requests concurrently.
220//!
221//! If you set the log level to `Trace` for the `isahc::wire` target, Isahc will
222//! also log all incoming and outgoing data while in flight. This may come in
223//! handy if you are debugging code and need to see the exact data being sent to
224//! the server and being received.
225
226#![doc(
227    html_logo_url = "https://raw.githubusercontent.com/sagebind/isahc/master/media/isahc.svg.png",
228    html_favicon_url = "https://raw.githubusercontent.com/sagebind/isahc/master/media/icon.png"
229)]
230#![deny(unsafe_code)]
231#![cfg_attr(feature = "nightly", feature(doc_cfg))]
232#![cfg_attr(feature = "nightly", feature(doc_auto_cfg))]
233#![warn(
234    future_incompatible,
235    missing_debug_implementations,
236    missing_docs,
237    unreachable_pub,
238    unused,
239    clippy::all
240)]
241// These lints suggest to use features not available in our MSRV.
242#![allow(clippy::manual_strip, clippy::match_like_matches_macro)]
243
244use std::convert::TryFrom;
245
246#[macro_use]
247mod macros;
248
249#[cfg(feature = "cookies")]
250pub mod cookies;
251
252mod agent;
253mod body;
254mod client;
255mod default_headers;
256mod handler;
257mod headers;
258mod info;
259mod metrics;
260mod parsing;
261mod redirect;
262mod request;
263mod response;
264mod task;
265mod text;
266mod trailer;
267
268pub mod auth;
269pub mod config;
270pub mod error;
271
272#[cfg(feature = "unstable-interceptors")]
273pub mod interceptor;
274#[cfg(not(feature = "unstable-interceptors"))]
275#[allow(unreachable_pub, unused)]
276pub(crate) mod interceptor;
277
278pub use crate::{
279    body::{AsyncBody, Body},
280    client::{HttpClient, HttpClientBuilder, ResponseFuture},
281    error::Error,
282    http::{request::Request, response::Response},
283    info::*,
284    metrics::Metrics,
285    request::RequestExt,
286    response::{AsyncReadResponseExt, ReadResponseExt, ResponseExt},
287    trailer::Trailer,
288};
289
290/// Re-export of HTTP types.
291pub use http;
292
293/// A "prelude" for importing commonly used Isahc types and traits.
294///
295/// The prelude re-exports most commonly used traits and macros from this crate.
296///
297/// # Example
298///
299/// Import the prelude with:
300///
301/// ```
302/// use isahc::prelude::*;
303/// ```
304pub mod prelude {
305    #[doc(no_inline)]
306    pub use crate::{
307        config::Configurable,
308        AsyncReadResponseExt,
309        ReadResponseExt,
310        RequestExt,
311        ResponseExt,
312    };
313}
314
315/// Send a GET request to the given URI.
316///
317/// The request is executed using a shared [`HttpClient`] instance. See
318/// [`HttpClient::get`] for details.
319pub fn get<U>(uri: U) -> Result<Response<Body>, Error>
320where
321    http::Uri: TryFrom<U>,
322    <http::Uri as TryFrom<U>>::Error: Into<http::Error>,
323{
324    HttpClient::shared().get(uri)
325}
326
327/// Send a GET request to the given URI asynchronously.
328///
329/// The request is executed using a shared [`HttpClient`] instance. See
330/// [`HttpClient::get_async`] for details.
331pub fn get_async<U>(uri: U) -> ResponseFuture<'static>
332where
333    http::Uri: TryFrom<U>,
334    <http::Uri as TryFrom<U>>::Error: Into<http::Error>,
335{
336    HttpClient::shared().get_async(uri)
337}
338
339/// Send a HEAD request to the given URI.
340///
341/// The request is executed using a shared [`HttpClient`] instance. See
342/// [`HttpClient::head`] for details.
343pub fn head<U>(uri: U) -> Result<Response<Body>, Error>
344where
345    http::Uri: TryFrom<U>,
346    <http::Uri as TryFrom<U>>::Error: Into<http::Error>,
347{
348    HttpClient::shared().head(uri)
349}
350
351/// Send a HEAD request to the given URI asynchronously.
352///
353/// The request is executed using a shared [`HttpClient`] instance. See
354/// [`HttpClient::head_async`] for details.
355pub fn head_async<U>(uri: U) -> ResponseFuture<'static>
356where
357    http::Uri: TryFrom<U>,
358    <http::Uri as TryFrom<U>>::Error: Into<http::Error>,
359{
360    HttpClient::shared().head_async(uri)
361}
362
363/// Send a POST request to the given URI with a given request body.
364///
365/// The request is executed using a shared [`HttpClient`] instance. See
366/// [`HttpClient::post`] for details.
367pub fn post<U, B>(uri: U, body: B) -> Result<Response<Body>, Error>
368where
369    http::Uri: TryFrom<U>,
370    <http::Uri as TryFrom<U>>::Error: Into<http::Error>,
371    B: Into<Body>,
372{
373    HttpClient::shared().post(uri, body)
374}
375
376/// Send a POST request to the given URI asynchronously with a given request
377/// body.
378///
379/// The request is executed using a shared [`HttpClient`] instance. See
380/// [`HttpClient::post_async`] for details.
381///
382/// # Examples
383///
384/// ```no_run
385/// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
386/// use isahc::prelude::*;
387///
388/// let mut response = isahc::post_async("https://httpbin.org/post", r#"{
389///     "speed": "fast",
390///     "cool_name": true
391/// }"#).await?;
392///
393/// let mut body: Vec<u8> = vec![];
394/// response.copy_to(&mut body).await?;
395///
396/// let msg: serde_json::Value = serde_json::from_slice(&body)?;
397/// println!("{}", msg);
398/// # Ok(()) }
399/// ```
400pub fn post_async<U, B>(uri: U, body: B) -> ResponseFuture<'static>
401where
402    http::Uri: TryFrom<U>,
403    <http::Uri as TryFrom<U>>::Error: Into<http::Error>,
404    B: Into<AsyncBody>,
405{
406    HttpClient::shared().post_async(uri, body)
407}
408
409/// Send a PUT request to the given URI with a given request body.
410///
411/// The request is executed using a shared [`HttpClient`] instance. See
412/// [`HttpClient::put`] for details.
413pub fn put<U, B>(uri: U, body: B) -> Result<Response<Body>, Error>
414where
415    http::Uri: TryFrom<U>,
416    <http::Uri as TryFrom<U>>::Error: Into<http::Error>,
417    B: Into<Body>,
418{
419    HttpClient::shared().put(uri, body)
420}
421
422/// Send a PUT request to the given URI asynchronously with a given request
423/// body.
424///
425/// The request is executed using a shared [`HttpClient`] instance. See
426/// [`HttpClient::put_async`] for details.
427pub fn put_async<U, B>(uri: U, body: B) -> ResponseFuture<'static>
428where
429    http::Uri: TryFrom<U>,
430    <http::Uri as TryFrom<U>>::Error: Into<http::Error>,
431    B: Into<AsyncBody>,
432{
433    HttpClient::shared().put_async(uri, body)
434}
435
436/// Send a DELETE request to the given URI.
437///
438/// The request is executed using a shared [`HttpClient`] instance. See
439/// [`HttpClient::delete`] for details.
440pub fn delete<U>(uri: U) -> Result<Response<Body>, Error>
441where
442    http::Uri: TryFrom<U>,
443    <http::Uri as TryFrom<U>>::Error: Into<http::Error>,
444{
445    HttpClient::shared().delete(uri)
446}
447
448/// Send a DELETE request to the given URI asynchronously.
449///
450/// The request is executed using a shared [`HttpClient`] instance. See
451/// [`HttpClient::delete_async`] for details.
452pub fn delete_async<U>(uri: U) -> ResponseFuture<'static>
453where
454    http::Uri: TryFrom<U>,
455    <http::Uri as TryFrom<U>>::Error: Into<http::Error>,
456{
457    HttpClient::shared().delete_async(uri)
458}
459
460/// Send an HTTP request and return the HTTP response.
461///
462/// The request is executed using a shared [`HttpClient`] instance. See
463/// [`HttpClient::send`] for details.
464pub fn send<B: Into<Body>>(request: Request<B>) -> Result<Response<Body>, Error> {
465    HttpClient::shared().send(request)
466}
467
468/// Send an HTTP request and return the HTTP response asynchronously.
469///
470/// The request is executed using a shared [`HttpClient`] instance. See
471/// [`HttpClient::send_async`] for details.
472pub fn send_async<B: Into<AsyncBody>>(request: Request<B>) -> ResponseFuture<'static> {
473    HttpClient::shared().send_async(request)
474}