1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
use std::{collections::HashMap, time::Duration};
use reqwest::{header::HeaderMap, Method, StatusCode};
/// `type RequestInterceptor` is the alias for the closure that can be passed through
/// one of several methods that will be executed every time a request is being made.
pub type RequestInterceptor = Box<dyn FnMut(&Request) -> RequestOptions>;
/// # Request
/// Request is an internal struct that is used by each OIDC protocol methods.
#[derive(Debug)]
pub struct Request {
/// Url of the request without query params
pub url: String,
/// Expected status code from the server
pub expected: StatusCode,
/// Http method of the request
pub method: Method,
/// Whether or not to expect body with the response
pub expect_body: bool,
/// Specifies if the request is using bearer auth, and checks for bearer token related errors
pub bearer: bool,
/// Headers that are sent in the request
pub headers: HeaderMap,
/// Query Params that are send with the request
pub search_params: HashMap<String, Vec<String>>,
/// The request body to be sent
pub json: Option<serde_json::Value>,
/// Expected response type
pub response_type: Option<String>,
}
impl Default for Request {
fn default() -> Self {
Self {
expect_body: true,
bearer: false,
expected: StatusCode::OK,
headers: HeaderMap::default(),
method: Method::GET,
url: "".to_string(),
search_params: HashMap::new(),
json: None,
response_type: None,
}
}
}
impl Request {
/// Converts `search_params` to a [reqwest] compatible query params format
pub(crate) fn get_reqwest_query(&self) -> Vec<(String, String)> {
let mut query_list: Vec<(String, String)> = vec![];
for (k, v) in &self.search_params {
for val in v {
query_list.push((k.clone(), val.to_string()))
}
}
query_list
}
}
/// # Response
/// Response is the abstracted version of the [reqwest] Response (async and blocking).
#[derive(Debug, Clone)]
pub struct Response {
/// Body from the response
pub body: Option<String>,
/// Status code of the response
pub status: StatusCode,
/// Response headers from the server
pub headers: HeaderMap,
}
impl Response {
/// Creates a new instance of Response from [reqwest::blocking::Response]
pub fn from(response: reqwest::blocking::Response) -> Self {
let status = response.status();
let headers = response.headers().clone();
let body_result = response.text();
let mut body: Option<String> = None;
if let Ok(body_string) = body_result {
if !body_string.is_empty() {
body = Some(body_string);
}
}
Self {
body,
status,
headers,
}
}
/// Creates a new instance of Response from [reqwest::Response]
pub async fn from_async(response: reqwest::Response) -> Self {
let status = response.status();
let headers = response.headers().clone();
let body_result = response.text().await;
let mut body: Option<String> = None;
if let Ok(body_string) = body_result {
if !body_string.is_empty() {
body = Some(body_string);
}
}
Self {
body,
status,
headers,
}
}
}
/// # RequestOptions
/// This struct is the return type of the request interceptor that can be passed to various methods
/// such as:
/// 1. [`Issuer::webfinger_with_interceptor_async()`]
/// 2. [`Issuer::webfinger_with_interceptor()`]
/// 3. [`Issuer::discover_with_interceptor_async()`]
/// 4. [`Issuer::discover_with_interceptor()`]
#[derive(Debug)]
pub struct RequestOptions {
/// Headers that are tobe appended with the request that is going to be made
pub headers: HeaderMap,
/// Request timeout
pub timeout: Duration,
}