util: refactor HTTP request API
This commit is contained in:
parent
20b5cc32cc
commit
605a7caa2c
1 changed files with 42 additions and 22 deletions
|
@ -1,18 +1,30 @@
|
||||||
use reqwest::header::{HeaderName, HeaderValue, AUTHORIZATION, USER_AGENT};
|
use reqwest::header::{HeaderName, AUTHORIZATION, USER_AGENT};
|
||||||
use reqwest::{header::HeaderMap, RequestBuilder, Response};
|
use reqwest::{RequestBuilder, Response};
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use crate::core::*;
|
use crate::core::*;
|
||||||
use crate::middle::AuthData;
|
|
||||||
use crate::state::AppState;
|
use crate::state::AppState;
|
||||||
use crate::util::bear::Bearcap;
|
use crate::util::bear::Bearcap;
|
||||||
|
|
||||||
/// Perform an HTTP GET request to the specified URL (supports bearcaps).
|
/// Perform an HTTP GET request to the specified URL (supports bearcaps).
|
||||||
/// Use the [`headers!`] macro for the `headers` parameter.
|
/// Use the [`crate::headers`] macro for the `headers` parameter.
|
||||||
|
///
|
||||||
|
/// If `url` starts with `"bear:"`, it will be parsed as a bearcap URI
|
||||||
|
/// and automatically append an `Authorization` header to the request,
|
||||||
|
/// overwriting an authorization header that was passed explicitly as an
|
||||||
|
/// argument. The request will fail if parsing the bearcap failed.
|
||||||
|
///
|
||||||
|
/// ## Default Headers
|
||||||
|
///
|
||||||
|
/// By default, the API injects the following headers:
|
||||||
|
///
|
||||||
|
/// - `User-Agent`
|
||||||
|
/// - `Authorization` (only when passing a bearcap URI)
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
/// use reqwest::header::ACCEPT;
|
||||||
|
///
|
||||||
/// let response = get(
|
/// let response = get(
|
||||||
/// &state,
|
/// &state,
|
||||||
/// "https://www.example.com",
|
/// "https://www.example.com",
|
||||||
|
@ -24,12 +36,12 @@ use crate::util::bear::Bearcap;
|
||||||
/// .await?;
|
/// .await?;
|
||||||
///
|
///
|
||||||
/// // automatically injects an "Authorization: Bearer b4dc0ffee" header
|
/// // automatically injects an "Authorization: Bearer b4dc0ffee" header
|
||||||
/// let response = get(&state, "bear:?t=b4dc0ffee&u=https://www.example.com", headers! {}).await?;
|
/// let response = get(&state, "bear:?t=b4dc0ffee&u=https://www.example.com", None).await?;
|
||||||
/// ```
|
/// ```
|
||||||
pub async fn get(
|
pub async fn get(
|
||||||
state: &AppState,
|
state: &AppState,
|
||||||
url: &str,
|
url: &str,
|
||||||
headers: &[(GenericHeaderName, String)],
|
headers: Option<&[(GenericHeaderName<'_>, String)]>,
|
||||||
) -> Result<Response> {
|
) -> Result<Response> {
|
||||||
let client = reqwest::Client::new();
|
let client = reqwest::Client::new();
|
||||||
let builder = if url.starts_with("bear:") {
|
let builder = if url.starts_with("bear:") {
|
||||||
|
@ -40,49 +52,57 @@ pub async fn get(
|
||||||
} else {
|
} else {
|
||||||
client.get(url)
|
client.get(url)
|
||||||
};
|
};
|
||||||
perform_request(state, builder, headers).await
|
perform_request(state, builder, headers.unwrap_or(&[])).await
|
||||||
}
|
}
|
||||||
|
|
||||||
// the state reference will be used for caching
|
// the state reference will be used for caching
|
||||||
async fn perform_request(
|
async fn perform_request(
|
||||||
_state: &AppState,
|
_state: &AppState,
|
||||||
mut builder: RequestBuilder,
|
mut builder: RequestBuilder,
|
||||||
headers: &[(GenericHeaderName, String)],
|
headers: &[(GenericHeaderName<'_>, String)],
|
||||||
) -> Result<Response> {
|
) -> Result<Response> {
|
||||||
builder = headers.into_iter().fold(builder, |b, (k, v)| match k {
|
builder = headers.iter().fold(builder, |b, (k, v)| match k {
|
||||||
GenericHeaderName::Standard(hdr) => b.header(hdr, v),
|
GenericHeaderName::Standard(hdr) => b.header(hdr, v),
|
||||||
GenericHeaderName::Custom(hdr) => b.header(hdr, v),
|
GenericHeaderName::CustomOwned(hdr) => b.header(hdr, v),
|
||||||
|
GenericHeaderName::CustomBorrow(hdr) => b.header(*hdr, v),
|
||||||
});
|
});
|
||||||
builder = builder.header(USER_AGENT, "nyano");
|
builder = builder.header(USER_AGENT, "nyano");
|
||||||
Ok(builder.send().await?)
|
Ok(builder.send().await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generate a list of HTTP request headers for passing to [`get`].
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! headers {
|
macro_rules! headers {
|
||||||
($($k:expr => $v:expr),* $(,)?) => {{
|
($($k:expr => $v:expr),* $(,)?) => {{
|
||||||
&[$((crate::util::http::GenericHeaderName::from($k), ::std::string::String::from($v)),)*]
|
// The [..] is required because of a bug in the IntelliJ Rust plugin:
|
||||||
|
// https://github.com/intellij-rust/intellij-rust/issues/10005
|
||||||
|
::core::option::Option::Some(&[
|
||||||
|
$(($crate::util::http::GenericHeaderName::from($k), ::std::string::String::from($v)),)*
|
||||||
|
][..])
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum GenericHeaderName {
|
/// Only used within this module, use [`crate::headers`] to generate headers.
|
||||||
Custom(String),
|
pub enum GenericHeaderName<'a> {
|
||||||
|
CustomOwned(String),
|
||||||
|
CustomBorrow(&'a str),
|
||||||
Standard(HeaderName),
|
Standard(HeaderName),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<String> for GenericHeaderName {
|
impl<'a> From<String> for GenericHeaderName<'a> {
|
||||||
fn from(val: String) -> GenericHeaderName {
|
fn from(val: String) -> GenericHeaderName<'a> {
|
||||||
GenericHeaderName::Custom(val)
|
GenericHeaderName::CustomOwned(val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&str> for GenericHeaderName {
|
impl<'a> From<&'a str> for GenericHeaderName<'a> {
|
||||||
fn from(val: &str) -> GenericHeaderName {
|
fn from(val: &'a str) -> GenericHeaderName<'a> {
|
||||||
GenericHeaderName::Custom(String::from(val))
|
GenericHeaderName::CustomBorrow(val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<HeaderName> for GenericHeaderName {
|
impl<'a> From<HeaderName> for GenericHeaderName<'a> {
|
||||||
fn from(val: HeaderName) -> GenericHeaderName {
|
fn from(val: HeaderName) -> GenericHeaderName<'a> {
|
||||||
GenericHeaderName::Standard(val)
|
GenericHeaderName::Standard(val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue