#[cfg(feature = "multipart")]
use crate::core::form::{FilePart, FormData};
use crate::core::path_param::PathParam;
use crate::core::remote_addr::RemoteAddr;
use crate::core::req_body::ReqBody;
#[cfg(feature = "multipart")]
use crate::core::serde::from_str_multi_val;
use crate::header::CONTENT_TYPE;
use crate::{Result, SilentError, State};
use bytes::Bytes;
use http::request::Parts;
use http::{Extensions, HeaderMap, HeaderValue, Method, Uri, Version};
use http::{Request as BaseRequest, StatusCode};
use http_body_util::BodyExt;
use mime::Mime;
use once_cell::sync::OnceCell;
use serde::Deserialize;
use serde::de::StdError;
use serde_json::Value;
use std::collections::HashMap;
use std::sync::Arc;
use url::form_urlencoded;
#[derive(Debug)]
pub struct Request {
parts: Parts,
path_params: HashMap<String, PathParam>,
params: HashMap<String, String>,
body: ReqBody,
path_source: Option<Arc<str>>,
#[cfg(feature = "multipart")]
form_data: OnceCell<FormData>,
json_data: OnceCell<Value>,
form_body_cache: OnceCell<Vec<u8>>,
pub(crate) state: State,
}
impl Request {
pub fn into_http(self) -> http::Request<ReqBody> {
http::Request::from_parts(self.parts, self.body)
}
#[doc(hidden)]
pub fn strip_to_hyper<QB>(&mut self) -> Result<hyper::Request<QB>>
where
QB: TryFrom<ReqBody>,
<QB as TryFrom<ReqBody>>::Error: StdError + Send + Sync + 'static,
{
let mut builder = http::request::Builder::new()
.method(self.method().clone())
.uri(self.uri().clone())
.version(self.version());
if let Some(headers) = builder.headers_mut() {
*headers = std::mem::take(self.headers_mut());
}
if let Some(extensions) = builder.extensions_mut() {
*extensions = std::mem::take(self.extensions_mut());
}
let body = self.take_body();
builder
.body(body.try_into().map_err(|e| {
SilentError::business_error(
StatusCode::INTERNAL_SERVER_ERROR,
format!("request strip to hyper failed: {e}"),
)
})?)
.map_err(|e| SilentError::business_error(StatusCode::BAD_REQUEST, e.to_string()))
}
#[doc(hidden)]
pub async fn strip_to_bytes_hyper(&mut self) -> Result<hyper::Request<Bytes>> {
let mut builder = http::request::Builder::new()
.method(self.method().clone())
.uri(self.uri().clone())
.version(self.version());
if let Some(headers) = builder.headers_mut() {
*headers = std::mem::take(self.headers_mut());
}
if let Some(extensions) = builder.extensions_mut() {
*extensions = std::mem::take(self.extensions_mut());
}
let mut body = self.take_body();
builder
.body(body.frame().await.unwrap()?.into_data().unwrap())
.map_err(|e| SilentError::business_error(StatusCode::BAD_REQUEST, e.to_string()))
}
}
impl Default for Request {
fn default() -> Self {
Self::empty()
}
}
impl Request {
pub fn empty() -> Self {
let (parts, _) = BaseRequest::builder()
.method("GET")
.body(())
.unwrap()
.into_parts();
Self {
parts,
path_params: HashMap::new(),
params: HashMap::new(),
body: ReqBody::Empty,
path_source: None,
#[cfg(feature = "multipart")]
form_data: OnceCell::new(),
json_data: OnceCell::new(),
form_body_cache: OnceCell::new(),
state: State::default(),
}
}
#[inline]
pub fn from_parts(parts: Parts, body: ReqBody) -> Self {
Self {
parts,
body,
path_params: HashMap::new(),
params: HashMap::new(),
path_source: None,
#[cfg(feature = "multipart")]
form_data: OnceCell::new(),
json_data: OnceCell::new(),
form_body_cache: OnceCell::new(),
state: State::default(),
}
}
#[inline]
pub fn remote(&self) -> RemoteAddr {
self.headers()
.get("x-real-ip")
.and_then(|h| h.to_str().ok())
.and_then(|s| s.parse::<RemoteAddr>().ok())
.expect("remote addr not set or invalid in x-real-ip header")
}
#[inline]
pub fn set_remote(&mut self, remote_addr: RemoteAddr) {
if self
.headers()
.get("x-real-ip")
.and_then(|h| h.to_str().ok())
.and_then(|s| s.parse::<RemoteAddr>().ok())
.is_some()
{
return;
}
if let Some(real_from_forwarded) = self
.headers()
.get("x-forwarded-for")
.and_then(|h| h.to_str().ok())
.and_then(|v| {
v.split(',')
.map(|p| p.trim())
.find(|p| !p.is_empty())
.and_then(|ip| ip.parse::<RemoteAddr>().ok())
})
{
self.headers_mut().insert(
"x-real-ip",
real_from_forwarded.to_string().parse().unwrap(),
);
return;
}
self.headers_mut()
.insert("x-real-ip", remote_addr.to_string().parse().unwrap());
}
pub(crate) fn set_path_source(&mut self, source: Arc<str>) {
self.path_source = Some(source);
}
#[inline]
pub fn method(&self) -> &Method {
&self.parts.method
}
#[inline]
pub fn method_mut(&mut self) -> &mut Method {
&mut self.parts.method
}
#[inline]
pub fn uri(&self) -> &Uri {
&self.parts.uri
}
#[inline]
pub fn uri_mut(&mut self) -> &mut Uri {
&mut self.parts.uri
}
#[inline]
pub fn version(&self) -> Version {
self.parts.version
}
#[inline]
pub fn version_mut(&mut self) -> &mut Version {
&mut self.parts.version
}
#[inline]
pub fn headers(&self) -> &HeaderMap<HeaderValue> {
&self.parts.headers
}
#[inline]
pub fn headers_mut(&mut self) -> &mut HeaderMap<HeaderValue> {
&mut self.parts.headers
}
#[inline]
pub fn extensions(&self) -> &Extensions {
&self.parts.extensions
}
#[inline]
pub fn extensions_mut(&mut self) -> &mut Extensions {
&mut self.parts.extensions
}
pub(crate) fn set_path_params(&mut self, key: String, value: PathParam) {
self.path_params.insert(key, value);
}
#[inline]
pub fn get_state<T: Send + Sync + 'static>(&self) -> Result<&T> {
self.state.get::<T>().ok_or(SilentError::ConfigNotFound)
}
#[inline]
pub fn get_state_uncheck<T: Send + Sync + 'static>(&self) -> &T {
self.state.get::<T>().unwrap()
}
#[inline]
pub fn state(&self) -> State {
self.state.clone()
}
#[inline]
pub fn state_mut(&mut self) -> &mut State {
&mut self.state
}
#[deprecated(since = "2.16.0", note = "请使用 get_state 代替")]
#[inline]
pub fn get_config<T: Send + Sync + 'static>(&self) -> Result<&T> {
self.get_state::<T>()
}
#[deprecated(since = "2.16.0", note = "请使用 get_state_uncheck 代替")]
#[inline]
pub fn get_config_uncheck<T: Send + Sync + 'static>(&self) -> &T {
self.get_state_uncheck::<T>()
}
#[deprecated(since = "2.16.0", note = "请使用 state() 代替")]
#[inline]
pub fn configs(&self) -> State {
self.state()
}
#[deprecated(since = "2.16.0", note = "请使用 state_mut() 代替")]
#[inline]
pub fn configs_mut(&mut self) -> &mut State {
self.state_mut()
}
pub fn path_params(&self) -> &HashMap<String, PathParam> {
&self.path_params
}
pub fn get_path_params<'a, T>(&'a self, key: &'a str) -> Result<T>
where
T: TryFrom<&'a PathParam, Error = SilentError>,
{
match self.path_params.get(key) {
Some(value) => value.try_into(),
None => Err(SilentError::ParamsNotFound),
}
}
pub fn params(&mut self) -> &HashMap<String, String> {
if let Some(query) = self.uri().query() {
let params = form_urlencoded::parse(query.as_bytes())
.into_owned()
.collect::<HashMap<String, String>>();
self.params = params;
};
&self.params
}
pub fn params_parse<T>(&mut self) -> Result<T>
where
for<'de> T: Deserialize<'de>,
{
let query = self.uri().query().unwrap_or("");
let params = serde_html_form::from_str(query)?;
Ok(params)
}
#[inline]
pub fn replace_body(&mut self, body: ReqBody) -> ReqBody {
std::mem::replace(&mut self.body, body)
}
#[inline]
pub fn take_body(&mut self) -> ReqBody {
self.replace_body(ReqBody::Empty)
}
#[inline]
pub fn content_type(&self) -> Option<Mime> {
self.headers()
.get(CONTENT_TYPE)
.and_then(|h| h.to_str().ok())
.and_then(|v| v.parse().ok())
}
#[cfg(feature = "multipart")]
#[inline]
pub async fn form_data(&mut self) -> Result<&FormData> {
let content_type = self
.content_type()
.ok_or(SilentError::ContentTypeMissingError)?;
if content_type.subtype() != mime::FORM_DATA {
return Err(SilentError::ContentTypeError);
}
if self.form_data.get().is_some() {
return Ok(self.form_data.get().unwrap());
}
let body = self.take_body();
let headers = self.headers();
let form_data = FormData::read(headers, body).await.map_err(|e| {
SilentError::business_error(
StatusCode::BAD_REQUEST,
format!("Failed to read form data: {}", e),
)
})?;
self.form_data.get_or_init(|| form_data);
Ok(self.form_data.get().unwrap())
}
pub async fn form_parse<T>(&mut self) -> Result<T>
where
for<'de> T: Deserialize<'de>,
{
let content_type = self
.content_type()
.ok_or(SilentError::ContentTypeMissingError)?;
match content_type.subtype() {
#[cfg(feature = "multipart")]
mime::FORM_DATA => self.multipart_form_parse().await,
mime::WWW_FORM_URLENCODED => self.urlencoded_form_parse().await,
_ => Err(SilentError::ContentTypeError),
}
}
#[cfg(feature = "multipart")]
async fn multipart_form_parse<T>(&mut self) -> Result<T>
where
for<'de> T: Deserialize<'de>,
{
let form_data = self.form_data().await?;
let value = serde_json::to_value(form_data.fields.clone()).map_err(SilentError::from)?;
serde_json::from_value(value).map_err(Into::into)
}
async fn urlencoded_form_parse<T>(&mut self) -> Result<T>
where
for<'de> T: Deserialize<'de>,
{
let bytes = if let Some(cached_bytes) = self.form_body_cache.get() {
cached_bytes.clone()
} else {
let body = self.take_body();
let bytes = match body {
ReqBody::Empty => return Err(SilentError::BodyEmpty),
other => other
.collect()
.await
.or(Err(SilentError::BodyEmpty))?
.to_bytes()
.to_vec(),
};
if bytes.is_empty() {
return Err(SilentError::BodyEmpty);
}
let _ = self.form_body_cache.set(bytes.clone());
bytes
};
let parsed_data: T = serde_html_form::from_bytes(&bytes).map_err(SilentError::from)?;
Ok(parsed_data)
}
#[cfg(feature = "multipart")]
pub async fn form_field<T>(&mut self, key: &str) -> Option<T>
where
for<'de> T: Deserialize<'de>,
{
self.form_data()
.await
.ok()
.and_then(|ps| ps.fields.get_vec(key))
.and_then(|vs| from_str_multi_val(vs).ok())
}
#[cfg(feature = "multipart")]
#[inline]
pub async fn files<'a>(&'a mut self, key: &'a str) -> Option<&'a Vec<FilePart>> {
self.form_data()
.await
.ok()
.and_then(|ps| ps.files.get_vec(key))
}
pub async fn json_parse<T>(&mut self) -> Result<T>
where
for<'de> T: Deserialize<'de>,
{
if let Some(cached_value) = self.json_data.get() {
return serde_json::from_value(cached_value.clone()).map_err(Into::into);
}
let content_type = self
.content_type()
.ok_or(SilentError::ContentTypeMissingError)?;
if content_type.subtype() != mime::JSON {
return Err(SilentError::ContentTypeError);
}
let body = self.take_body();
let bytes = match body {
ReqBody::Empty => return Err(SilentError::JsonEmpty),
other => other
.collect()
.await
.or(Err(SilentError::JsonEmpty))?
.to_bytes(),
};
if bytes.is_empty() {
return Err(SilentError::JsonEmpty);
}
let value: Value = serde_json::from_slice(&bytes).map_err(SilentError::from)?;
let _ = self.json_data.set(value.clone());
serde_json::from_value(value).map_err(Into::into)
}
pub async fn json_field<T>(&mut self, key: &str) -> Result<T>
where
for<'de> T: Deserialize<'de>,
{
let value: Value = self.json_parse().await?;
serde_json::from_value(
value
.get(key)
.ok_or(SilentError::ParamsNotFound)?
.to_owned(),
)
.map_err(Into::into)
}
#[inline]
pub fn replace_extensions(&mut self, extensions: Extensions) -> Extensions {
std::mem::replace(self.extensions_mut(), extensions)
}
#[inline]
pub fn take_extensions(&mut self) -> Extensions {
self.replace_extensions(Extensions::default())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::path_param::PathString;
use std::net::{IpAddr, Ipv4Addr, SocketAddr as StdSocketAddr};
#[test]
fn test_request_empty() {
let req = Request::empty();
assert_eq!(req.method(), Method::GET);
assert_eq!(req.uri(), &Uri::from_static("/"));
assert_eq!(req.version(), Version::HTTP_11);
assert!(req.path_params.is_empty());
assert!(req.params.is_empty());
}
#[test]
fn test_request_default() {
let req = Request::default();
assert_eq!(req.method(), Method::GET);
}
#[test]
fn test_request_from_parts() {
let (parts, _) = BaseRequest::builder()
.method("POST")
.uri("/test")
.body(())
.unwrap()
.into_parts();
let req = Request::from_parts(parts, ReqBody::Empty);
assert_eq!(req.method(), Method::POST);
assert_eq!(req.uri(), &Uri::from_static("/test"));
}
#[test]
fn test_remote_with_x_real_ip() {
let mut req = Request::empty();
req.headers_mut()
.insert("x-real-ip", "127.0.0.1:8080".parse().unwrap());
let remote = req.remote();
assert_eq!(remote.to_string(), "127.0.0.1:8080");
}
#[test]
fn test_set_remote_with_existing_x_real_ip() {
let mut req = Request::empty();
req.headers_mut()
.insert("x-real-ip", "192.168.1.1:9000".parse().unwrap());
let new_addr = RemoteAddr::from(StdSocketAddr::new(
IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)),
8080,
));
req.set_remote(new_addr);
assert_eq!(
req.headers().get("x-real-ip").unwrap(),
"192.168.1.1:9000".parse::<HeaderValue>().unwrap()
);
}
#[test]
fn test_set_remote_with_x_forwarded_for() {
let mut req = Request::empty();
req.headers_mut().insert(
"x-forwarded-for",
"203.0.113.1, 70.41.3.18, 150.172.238.178".parse().unwrap(),
);
let addr = RemoteAddr::from(StdSocketAddr::new(
IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)),
8080,
));
req.set_remote(addr);
assert_eq!(
req.headers().get("x-real-ip").unwrap(),
"203.0.113.1".parse::<HeaderValue>().unwrap()
);
}
#[test]
fn test_set_remote_without_headers() {
let mut req = Request::empty();
let addr = RemoteAddr::from(StdSocketAddr::new(
IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)),
8080,
));
req.set_remote(addr);
assert_eq!(
req.headers().get("x-real-ip").unwrap(),
"10.0.0.1:8080".parse::<HeaderValue>().unwrap()
);
}
#[test]
fn test_method_get() {
let req = Request::empty();
assert_eq!(req.method(), Method::GET);
}
#[test]
fn test_method_mut() {
let mut req = Request::empty();
*req.method_mut() = Method::POST;
assert_eq!(req.method(), Method::POST);
}
#[test]
fn test_uri_get() {
let req = Request::empty();
assert_eq!(req.uri(), &Uri::from_static("/"));
}
#[test]
fn test_uri_mut() {
let mut req = Request::empty();
*req.uri_mut() = Uri::from_static("/test/path");
assert_eq!(req.uri(), &Uri::from_static("/test/path"));
}
#[test]
fn test_version_get() {
let req = Request::empty();
assert_eq!(req.version(), Version::HTTP_11);
}
#[test]
fn test_version_mut() {
let mut req = Request::empty();
*req.version_mut() = Version::HTTP_2;
assert_eq!(req.version(), Version::HTTP_2);
}
#[test]
fn test_headers_get() {
let mut req = Request::empty();
req.headers_mut()
.insert("custom-header", "test-value".parse().unwrap());
assert_eq!(
req.headers().get("custom-header").unwrap(),
"test-value".parse::<HeaderValue>().unwrap()
);
}
#[test]
fn test_headers_mut() {
let mut req = Request::empty();
req.headers_mut()
.insert("x-test", "value1".parse().unwrap());
req.headers_mut()
.insert("x-test", "value2".parse().unwrap());
assert!(req.headers().get("x-test").is_some());
}
#[test]
fn test_extensions_get() {
let req = Request::empty();
let _ext = req.extensions();
}
#[test]
fn test_extensions_mut() {
let mut req = Request::empty();
req.extensions_mut().insert("test_key");
assert_eq!(req.extensions().get::<&'static str>(), Some(&"test_key"));
}
#[test]
fn test_state_get() {
let req = Request::empty();
let state = req.state();
assert!(state.is_empty());
}
#[test]
fn test_state_get_uncheck() {
let mut req = Request::empty();
req.state_mut().insert("test_value");
let value = req.get_state_uncheck::<&str>();
assert_eq!(*value, "test_value");
}
#[test]
fn test_state_mut() {
let mut req = Request::empty();
req.state_mut().insert(42i32);
let value = req.get_state_uncheck::<i32>();
assert_eq!(*value, 42);
}
#[test]
fn test_path_params_empty() {
let req = Request::empty();
assert!(req.path_params().is_empty());
}
#[test]
fn test_get_path_params_success() {
let mut req = Request::empty();
req.path_params.insert(
"id".to_string(),
PathParam::Str(PathString::Owned("123".to_string())),
);
let id: String = req.get_path_params("id").unwrap();
assert_eq!(id, "123");
}
#[test]
fn test_get_path_params_missing() {
let req = Request::empty();
let result: Result<String> = req.get_path_params("missing");
assert!(result.is_err());
}
#[test]
fn test_params_get() {
let mut req = Request::empty();
req.params.insert("key".to_string(), "value".to_string());
let params = req.params();
assert_eq!(params.get("key"), Some(&"value".to_string()));
}
#[test]
fn test_replace_body() {
let mut req = Request::empty();
let new_body = ReqBody::Once(Bytes::from("test data"));
let old_body = req.replace_body(new_body);
assert!(matches!(old_body, ReqBody::Empty));
}
#[test]
fn test_take_body() {
let mut req = Request::empty();
req.body = ReqBody::Once(Bytes::from("data"));
let body = req.take_body();
assert!(matches!(body, ReqBody::Once(_)));
}
#[test]
fn test_content_type_json() {
let mut req = Request::empty();
req.headers_mut()
.insert("content-type", "application/json".parse().unwrap());
let ct = req.content_type();
assert_eq!(ct.as_ref().unwrap().type_(), mime::APPLICATION);
assert_eq!(ct.as_ref().unwrap().subtype(), mime::JSON);
}
#[test]
fn test_content_type_missing() {
let req = Request::empty();
assert!(req.content_type().is_none());
}
#[test]
fn test_content_type_invalid() {
let mut req = Request::empty();
req.headers_mut()
.insert("content-type", "not-a-valid-mime".parse().unwrap());
let ct = req.content_type();
assert!(ct.is_none());
}
#[test]
fn test_into_http() {
let req = Request::empty();
let http_req = req.into_http();
assert_eq!(http_req.method(), Method::GET);
assert_eq!(http_req.uri(), &Uri::from_static("/"));
}
#[test]
fn test_replace_extensions() {
let mut req = Request::empty();
req.extensions_mut().insert("value1");
let mut new_ext = Extensions::new();
new_ext.insert("value2");
let old_ext = req.replace_extensions(new_ext);
assert_eq!(old_ext.get::<&'static str>(), Some(&"value1"));
assert_eq!(req.extensions().get::<&'static str>(), Some(&"value2"));
}
#[test]
fn test_take_extensions() {
let mut req = Request::empty();
req.extensions_mut().insert("test_value");
let ext = req.take_extensions();
assert_eq!(ext.get::<&'static str>(), Some(&"test_value"));
assert!(req.extensions().is_empty());
}
#[derive(Deserialize, Debug, PartialEq)]
struct TestStruct {
a: i32,
b: String,
#[serde(default, alias = "c[]")]
c: Vec<String>,
}
#[test]
fn test_query_parse_alias() {
let mut req = Request::empty();
*req.uri_mut() = Uri::from_static("http://localhost:8080/test?a=1&b=2&c[]=3&c[]=4");
let _ = req.params_parse::<TestStruct>().unwrap();
}
#[test]
fn test_query_parse() {
let mut req = Request::empty();
*req.uri_mut() = Uri::from_static("http://localhost:8080/test?a=1&b=2&c=3&c=4");
let _ = req.params_parse::<TestStruct>().unwrap();
}
#[tokio::test]
async fn test_methods_semantic_separation() {
#[derive(Deserialize, Debug, PartialEq)]
struct TestData {
name: String,
age: u32,
}
let test_data = TestData {
name: "Alice".to_string(),
age: 25,
};
let json_body = r#"{"name":"Alice","age":25}"#.as_bytes().to_vec();
let mut req = create_request_with_body("application/json", json_body);
let parsed_data = req
.json_parse::<TestData>()
.await
.expect("json_parse should successfully parse JSON data");
assert_eq!(parsed_data.name, test_data.name);
assert_eq!(parsed_data.age, test_data.age);
let form_body = "name=Alice&age=25".as_bytes().to_vec();
let mut req = create_request_with_body("application/x-www-form-urlencoded", form_body);
let parsed_data = req
.form_parse::<TestData>()
.await
.expect("form_parse should successfully parse form-urlencoded data");
assert_eq!(parsed_data.name, test_data.name);
assert_eq!(parsed_data.age, test_data.age);
let form_body = "name=Alice&age=25".as_bytes().to_vec();
let mut req = create_request_with_body("application/x-www-form-urlencoded", form_body);
let result = req.json_parse::<TestData>().await;
assert!(
result.is_err(),
"json_parse should reject form-urlencoded data"
);
let json_body = r#"{"name":"Alice","age":25}"#.as_bytes().to_vec();
let mut req = create_request_with_body("application/json", json_body);
let result = req.form_parse::<TestData>().await;
assert!(result.is_err(), "form_parse should reject JSON data");
}
#[tokio::test]
async fn test_form_urlencoded_caches_to_form_body_cache() {
#[derive(Deserialize, Debug, PartialEq)]
struct TestData {
name: String,
age: u32,
}
let form_body = "name=Alice&age=25".as_bytes().to_vec();
let mut req = create_request_with_body("application/x-www-form-urlencoded", form_body);
let first_result = req
.form_parse::<TestData>()
.await
.expect("First form_parse call should succeed");
assert!(
req.form_body_cache.get().is_some(),
"form_body_cache should be cached after form_parse"
);
let cached_bytes = req.form_body_cache.get().unwrap();
assert_eq!(cached_bytes, b"name=Alice&age=25");
let second_result = req
.form_parse::<TestData>()
.await
.expect("Second form_parse call should use cached data");
assert_eq!(first_result.name, second_result.name);
assert_eq!(first_result.age, second_result.age);
assert_eq!(first_result.name, "Alice");
assert_eq!(first_result.age, 25);
}
#[cfg(feature = "multipart")]
#[tokio::test]
async fn test_shared_cache_mechanism() {
let mut req = Request::empty();
req.headers_mut().insert(
"content-type",
HeaderValue::from_str("multipart/form-data; boundary=----formdata").unwrap(),
);
req.body = ReqBody::Empty;
#[derive(Deserialize, Debug)]
struct TestData {
name: String,
}
let t = TestData {
name: "placeholder".to_string(),
};
assert_eq!(t.name, "placeholder");
let result = req.form_parse::<TestData>().await;
assert!(
result.is_err(),
"Should fail due to empty body, but went through correct code path"
);
}
fn create_request_with_body(content_type: &str, body: Vec<u8>) -> Request {
let mut req = Request::empty();
req.headers_mut()
.insert("content-type", HeaderValue::from_str(content_type).unwrap());
req.body = ReqBody::Once(body.into());
req
}
}