use crate::tina::constant::Constants;
use crate::tina::data::http::request_log_param::RequestLogParam;
use crate::tina::data::http::request_metadata::HttpReqMetadata;
use crate::tina::data::request_ext::RequestTime;
use crate::tina::data::AppResult;
use crate::tina::i18n::ResourceBundle;
use crate::tina::server::application::Application;
use crate::tina::server::http::path::inner::Path;
use crate::tina::server::http::route::RouteBaseConfig;
use crate::tina::server::session::{Session, SessionInner};
use crate::{app_error_from, app_system_error};
use axum::extract::ConnectInfo;
use http::header::CONTENT_TYPE;
use http::request::Parts;
use http::{Method, Request, Uri};
use mime::Mime;
use std::any::Any;
use std::borrow::Cow;
use std::fmt::Debug;
use std::net::SocketAddr;
use std::sync::Arc;
pub type AnyType = dyn Any + Send + Sync + 'static;
pub trait RequestExt: crate::tina::server::http::request_ext::RequestExt2 {
fn get_attribute<T: Send + Sync + 'static>(&self) -> AppResult<Option<Arc<T>>>
where
Self: Sized;
fn set_attribute<T: Send + Sync + 'static>(&mut self, value: Arc<T>)
where
Self: Sized;
fn clean_attributes(&mut self);
fn get_request_time(&self) -> AppResult<Arc<RequestTime>>;
fn get_route_config(&self) -> AppResult<Arc<RouteBaseConfig>>;
fn set_route_config(&mut self, config: &Arc<RouteBaseConfig>);
fn get_method(&self) -> Cow<Method>;
fn get_application(&self) -> AppResult<Application>;
fn set_application(&mut self, application: &Application);
fn get_session(&self) -> Option<Session>;
fn set_session(&mut self, session: Session);
fn get_remote_ip_address(&self) -> Cow<str>;
fn get_request_path(&self) -> Cow<str>;
fn get_user_agent(&self) -> Cow<str>;
fn get_request_header(&self, name: &str) -> AppResult<Option<Cow<str>>>;
fn get_request_headers(&self, name: &str) -> AppResult<Vec<Cow<str>>>;
fn get_locale(&self) -> String;
fn get_request_log_param(&self) -> AppResult<Option<Arc<RequestLogParam>>>;
fn set_request_log_param(&mut self, param: Arc<RequestLogParam>);
}
pub trait RequestExt2: Debug + Send + Sync + 'static {
fn get_request_part(&self) -> AppResult<&Parts>;
}
pub trait HttpRequestAttribute2 {
fn mime_type(&self) -> AppResult<Option<Mime>>;
fn path(&self) -> &str;
fn query_string(&self) -> &str;
fn match_info(&self) -> Path<&Uri>;
}
impl<B> RequestExt for Request<B>
where
B: Debug + Send + Sync + 'static,
{
fn get_attribute<T: Send + Sync + 'static>(&self) -> AppResult<Option<Arc<T>>>
where
Self: Sized,
{
let ext = self.extensions();
let attr: Option<&Arc<T>> = ext.get();
match attr {
None => Ok(None),
Some(v) => Ok(Some(Arc::clone(v))),
}
}
fn set_attribute<T: Send + Sync + 'static>(&mut self, value: Arc<T>)
where
Self: Sized,
{
let ext = self.extensions_mut();
ext.insert(value);
}
fn clean_attributes(&mut self) {
let ext = self.extensions_mut();
ext.clear()
}
fn get_request_time(&self) -> AppResult<Arc<RequestTime>> {
let request_time: Option<Arc<RequestTime>> = self.get_attribute()?;
let request_time = request_time.ok_or_else(|| crate::app_system_error!("no request time found..."))?;
Ok(request_time)
}
fn get_route_config(&self) -> AppResult<Arc<RouteBaseConfig>> {
let ext = self.extensions();
let attr: Option<&Arc<RouteBaseConfig>> = ext.get();
match attr {
None => Err(app_system_error!("no route config found in request")),
Some(v) => Ok(v.clone()),
}
}
fn set_route_config(&mut self, config: &Arc<RouteBaseConfig>) {
let ext = self.extensions_mut();
ext.insert(Arc::clone(config));
}
fn get_method(&self) -> Cow<Method> {
Cow::Borrowed(self.method())
}
fn get_application(&self) -> AppResult<Application> {
let ext = self.extensions();
ext.get::<Application>().map(|o| o.to_owned()).ok_or_else(|| crate::app_system_error!("no application found in request"))
}
fn set_application(&mut self, application: &Application) {
let ext = self.extensions_mut();
ext.insert(application.to_owned());
}
fn get_session(&self) -> Option<Session> {
let ext = self.extensions();
ext.get::<Session>().cloned()
}
fn set_session(&mut self, session: Session) {
let ext = self.extensions_mut();
ext.insert(session);
}
fn get_remote_ip_address(&self) -> Cow<str> {
let headers = self.headers();
if let Some(ip) = headers.get("x-forwarded-for") {
return match ip.to_str() {
Ok(s) => Cow::Borrowed(s),
Err(e) => {
tracing::error!("{:?}", e);
Cow::Borrowed("")
}
};
}
if let Some(ip) = headers.get("Proxy-Client-IP") {
return match ip.to_str() {
Ok(s) => Cow::Borrowed(s),
Err(e) => {
tracing::error!("{:?}", e);
Cow::Borrowed("")
}
};
}
if let Some(ip) = headers.get("WL-Proxy-Client-IP") {
return match ip.to_str() {
Ok(s) => Cow::Borrowed(s),
Err(e) => {
tracing::error!("{:?}", e);
Cow::Borrowed("")
}
};
}
if let Some(ip) = headers.get("X-Real-IP") {
return match ip.to_str() {
Ok(s) => Cow::Borrowed(s),
Err(e) => {
tracing::error!("{:?}", e);
Cow::Borrowed("")
}
};
}
let ext = self.extensions();
let ip_with_port = match ext.get::<ConnectInfo<SocketAddr>>() {
None => {
tracing::error!("no ConnectInfo extension found in request");
"".to_string()
}
Some(conn) => conn.0.ip().to_string(),
};
return if ip_with_port.contains('[') && ip_with_port.contains(']') {
match ip_with_port.split(']').next() {
None => Cow::Owned(ip_with_port),
Some(s) => match !s.is_empty() {
true => Cow::Owned(s.split_at(1).1.to_string()),
false => Cow::Owned(ip_with_port),
},
}
} else {
match ip_with_port == "0:0:0:0:0:0:0:1" {
true => Cow::Borrowed("127.0.0.1"),
false => match ip_with_port.split(':').next() {
None => Cow::Owned(ip_with_port),
Some(s) => Cow::Owned(s.to_string()),
},
}
};
}
fn get_request_path(&self) -> Cow<str> {
Cow::Borrowed(self.path())
}
fn get_user_agent(&self) -> Cow<str> {
match self.get_request_header("User-Agent") {
Ok(Some(s)) => s,
_ => Cow::Borrowed(""),
}
}
fn get_request_header(&self, name: &str) -> AppResult<Option<Cow<str>>> {
let headers = self.get_request_headers(name)?;
match headers.is_empty() {
true => Ok(None),
false => Ok(headers.into_iter().next()),
}
}
fn get_request_headers(&self, name: &str) -> AppResult<Vec<Cow<str>>> {
let mut values = vec![];
let all = self.headers().get_all(name);
for value in all {
if let Ok(value) = value.to_str() {
if value.is_empty() || value == "null" {
continue;
}
values.push(Cow::Borrowed(value));
}
}
Ok(values)
}
fn get_locale(&self) -> String {
match self.headers().get(Constants::REQUEST_HEADER_LOCALE) {
None => ResourceBundle::get_default_locale(),
Some(header) => match header.to_str() {
Ok(val) => val.to_string(),
Err(_) => ResourceBundle::get_default_locale(),
},
}
}
fn get_request_log_param(&self) -> AppResult<Option<Arc<RequestLogParam>>> {
self.get_attribute()
}
fn set_request_log_param(&mut self, param: Arc<RequestLogParam>) {
self.set_attribute(param);
}
}
impl RequestExt for Parts {
fn get_attribute<T: Send + Sync + 'static>(&self) -> AppResult<Option<Arc<T>>>
where
Self: Sized,
{
let ext = &self.extensions;
let attr: Option<&Arc<T>> = ext.get();
match attr {
None => Ok(None),
Some(v) => Ok(Some(Arc::clone(v))),
}
}
fn set_attribute<T: Send + Sync + 'static>(&mut self, value: Arc<T>)
where
Self: Sized,
{
let ext = &mut self.extensions;
ext.insert(value);
}
fn clean_attributes(&mut self) {
let ext = &mut self.extensions;
ext.clear()
}
fn get_request_time(&self) -> AppResult<Arc<RequestTime>> {
let request_time: Option<Arc<RequestTime>> = self.get_attribute()?;
let request_time = request_time.ok_or_else(|| crate::app_system_error!("no request time found..."))?;
Ok(request_time)
}
fn get_route_config(&self) -> AppResult<Arc<RouteBaseConfig>> {
let ext = &self.extensions;
let attr: Option<&Arc<RouteBaseConfig>> = ext.get();
match attr {
None => Err(app_system_error!("no route config found in request")),
Some(v) => Ok(v.clone()),
}
}
fn set_route_config(&mut self, config: &Arc<RouteBaseConfig>) {
let ext = &mut self.extensions;
ext.insert(Arc::clone(config));
}
fn get_method(&self) -> Cow<Method> {
Cow::Borrowed(&self.method)
}
fn get_application(&self) -> AppResult<Application> {
let ext = &self.extensions;
ext.get::<Application>().map(|o| o.to_owned()).ok_or_else(|| crate::app_system_error!("no application found in request"))
}
fn set_application(&mut self, application: &Application) {
let ext = &mut self.extensions;
ext.insert(application.to_owned());
}
fn get_session(&self) -> Option<Session> {
let ext = &self.extensions;
ext.get::<Session>().cloned()
}
fn set_session(&mut self, session: Session) {
let ext = &mut self.extensions;
ext.insert(session);
}
fn get_remote_ip_address(&self) -> Cow<str> {
let headers = &self.headers;
if let Some(ip) = headers.get("x-forwarded-for") {
return match ip.to_str() {
Ok(s) => Cow::Borrowed(s),
Err(e) => {
tracing::error!("{:?}", e);
Cow::Borrowed("")
}
};
}
if let Some(ip) = headers.get("Proxy-Client-IP") {
return match ip.to_str() {
Ok(s) => Cow::Borrowed(s),
Err(e) => {
tracing::error!("{:?}", e);
Cow::Borrowed("")
}
};
}
if let Some(ip) = headers.get("WL-Proxy-Client-IP") {
return match ip.to_str() {
Ok(s) => Cow::Borrowed(s),
Err(e) => {
tracing::error!("{:?}", e);
Cow::Borrowed("")
}
};
}
if let Some(ip) = headers.get("X-Real-IP") {
return match ip.to_str() {
Ok(s) => Cow::Borrowed(s),
Err(e) => {
tracing::error!("{:?}", e);
Cow::Borrowed("")
}
};
}
let ext = &self.extensions;
let ip_with_port = match ext.get::<ConnectInfo<SocketAddr>>() {
None => {
tracing::error!("no ConnectInfo extension found in request");
"".to_string()
}
Some(conn) => conn.0.ip().to_string(),
};
return if ip_with_port.contains('[') && ip_with_port.contains(']') {
match ip_with_port.split(']').next() {
None => Cow::Owned(ip_with_port),
Some(s) => match !s.is_empty() {
true => Cow::Owned(s.split_at(1).1.to_string()),
false => Cow::Owned(ip_with_port),
},
}
} else {
match ip_with_port == "0:0:0:0:0:0:0:1" {
true => Cow::Borrowed("127.0.0.1"),
false => match ip_with_port.split(':').next() {
None => Cow::Owned(ip_with_port),
Some(s) => Cow::Owned(s.to_string()),
},
}
};
}
fn get_request_path(&self) -> Cow<str> {
Cow::Borrowed(self.path())
}
fn get_user_agent(&self) -> Cow<str> {
match self.get_request_header("User-Agent") {
Ok(Some(s)) => s,
_ => Cow::Borrowed(""),
}
}
fn get_request_header(&self, name: &str) -> AppResult<Option<Cow<str>>> {
let headers = self.get_request_headers(name)?;
match headers.is_empty() {
true => Ok(None),
false => Ok(headers.into_iter().next()),
}
}
fn get_request_headers(&self, name: &str) -> AppResult<Vec<Cow<str>>> {
let mut values = vec![];
let all = self.headers.get_all(name);
for value in all {
if let Ok(value) = value.to_str() {
if value.is_empty() || value == "null" {
continue;
}
values.push(Cow::Borrowed(value));
}
}
Ok(values)
}
fn get_locale(&self) -> String {
match self.headers.get(Constants::REQUEST_HEADER_LOCALE) {
None => ResourceBundle::get_default_locale(),
Some(header) => match header.to_str() {
Ok(val) => val.to_string(),
Err(_) => ResourceBundle::get_default_locale(),
},
}
}
fn get_request_log_param(&self) -> AppResult<Option<Arc<RequestLogParam>>> {
self.get_attribute()
}
fn set_request_log_param(&mut self, param: Arc<RequestLogParam>) {
self.set_attribute(param);
}
}
impl RequestExt for HttpReqMetadata {
fn get_attribute<T: Send + Sync + 'static>(&self) -> AppResult<Option<Arc<T>>>
where
Self: Sized,
{
let request = self.request.downcast_ref::<Parts>().expect("inner request type error");
request.get_attribute()
}
fn set_attribute<T: Send + Sync + 'static>(&mut self, value: Arc<T>)
where
Self: Sized,
{
let request = self.request.downcast_mut::<Parts>().expect("inner request type error");
request.set_attribute(value)
}
fn clean_attributes(&mut self) {
let request = self.request.downcast_mut::<Parts>().expect("inner request type error");
request.clean_attributes()
}
fn get_request_time(&self) -> AppResult<Arc<RequestTime>> {
let request = self.request.downcast_ref::<Parts>().expect("inner request type error");
request.get_request_time()
}
fn get_route_config(&self) -> AppResult<Arc<RouteBaseConfig>> {
let request = self.request.downcast_ref::<Parts>().expect("inner request type error");
request.get_route_config()
}
fn set_route_config(&mut self, config: &Arc<RouteBaseConfig>) {
let request = self.request.downcast_mut::<Parts>().expect("inner request type error");
request.set_route_config(config)
}
fn get_method(&self) -> Cow<Method> {
let request = self.request.downcast_ref::<Parts>().expect("inner request type error");
request.get_method()
}
fn get_application(&self) -> AppResult<Application> {
let request = self.request.downcast_ref::<Parts>().expect("inner request type error");
request.get_application()
}
fn set_application(&mut self, application: &Application) {
let request = self.request.downcast_mut::<Parts>().expect("inner request type error");
request.set_application(application)
}
fn get_session(&self) -> Option<Session> {
let request = self.request.downcast_ref::<Parts>().expect("inner request type error");
request.get_session()
}
fn set_session(&mut self, session: Session) {
let request = self.request.downcast_mut::<Parts>().expect("inner request type error");
request.set_session(session)
}
fn get_remote_ip_address(&self) -> Cow<str> {
let request = self.request.downcast_ref::<Parts>().expect("inner request type error");
request.get_remote_ip_address()
}
fn get_request_path(&self) -> Cow<str> {
let request = self.request.downcast_ref::<Parts>().expect("inner request type error");
request.get_request_path()
}
fn get_user_agent(&self) -> Cow<str> {
let request = self.request.downcast_ref::<Parts>().expect("inner request type error");
request.get_user_agent()
}
fn get_request_header(&self, name: &str) -> AppResult<Option<Cow<str>>> {
let request = self.request.downcast_ref::<Parts>().expect("inner request type error");
request.get_request_header(name)
}
fn get_request_headers(&self, name: &str) -> AppResult<Vec<Cow<str>>> {
let request = self.request.downcast_ref::<Parts>().expect("inner request type error");
request.get_request_headers(name)
}
fn get_locale(&self) -> String {
let request = self.request.downcast_ref::<Parts>().expect("inner request type error");
request.get_locale()
}
fn get_request_log_param(&self) -> AppResult<Option<Arc<RequestLogParam>>> {
let request = self.request.downcast_ref::<Parts>().expect("inner request type error");
request.get_request_log_param()
}
fn set_request_log_param(&mut self, param: Arc<RequestLogParam>) {
let request = self.request.downcast_mut::<Parts>().expect("inner request type error");
request.set_request_log_param(param)
}
}
impl RequestExt for () {
fn get_attribute<T: Send + Sync + 'static>(&self) -> AppResult<Option<Arc<T>>>
where
Self: Sized,
{
Ok(None)
}
fn set_attribute<T: Send + Sync + 'static>(&mut self, _value: Arc<T>)
where
Self: Sized,
{
}
fn clean_attributes(&mut self) {}
fn get_request_time(&self) -> AppResult<Arc<RequestTime>> {
Err(app_system_error!("unsupported"))
}
fn get_route_config(&self) -> AppResult<Arc<RouteBaseConfig>> {
Err(app_system_error!("unsupported"))
}
fn set_route_config(&mut self, _config: &Arc<RouteBaseConfig>) {}
fn get_method(&self) -> Cow<Method> {
Cow::Owned(Method::default())
}
fn get_application(&self) -> AppResult<Application> {
Err(app_system_error!("unsupported"))
}
fn set_application(&mut self, _application: &Application) {}
fn get_session(&self) -> Option<Session> {
None
}
fn set_session(&mut self, _: Session) {}
fn get_remote_ip_address(&self) -> Cow<str> {
Cow::Borrowed("")
}
fn get_request_path(&self) -> Cow<str> {
Cow::Borrowed("")
}
fn get_user_agent(&self) -> Cow<str> {
Cow::Borrowed("")
}
fn get_request_header(&self, _name: &str) -> AppResult<Option<Cow<str>>> {
Ok(None)
}
fn get_request_headers(&self, _name: &str) -> AppResult<Vec<Cow<str>>> {
Ok(vec![])
}
fn get_locale(&self) -> String {
ResourceBundle::get_default_locale()
}
fn get_request_log_param(&self) -> AppResult<Option<Arc<RequestLogParam>>> {
Ok(None)
}
fn set_request_log_param(&mut self, _param: Arc<RequestLogParam>) {}
}
impl<B> RequestExt2 for Request<B>
where
B: Debug + Send + Sync + 'static,
{
fn get_request_part(&self) -> AppResult<&Parts> {
unimplemented!()
}
}
impl RequestExt2 for Parts {
fn get_request_part(&self) -> AppResult<&Parts> {
Ok(self)
}
}
impl RequestExt2 for HttpReqMetadata {
fn get_request_part(&self) -> AppResult<&Parts> {
let request = self.request.downcast_ref::<Parts>().expect("inner request type error");
Ok(request)
}
}
impl RequestExt2 for () {
fn get_request_part(&self) -> AppResult<&Parts> {
unimplemented!()
}
}
impl RequestExt2 for SessionInner {
fn get_request_part(&self) -> AppResult<&Parts> {
Err(app_system_error!("Cannot get request parts from session, please use ReqMetadata"))
}
}
impl<B> HttpRequestAttribute2 for Request<B> {
fn mime_type(&self) -> AppResult<Option<Mime>> {
if let Some(content_type) = self.headers().get(CONTENT_TYPE) {
return if let Ok(content_type) = content_type.to_str() {
match content_type.parse() {
Ok(mt) => Ok(Some(mt)),
Err(err) => Err(app_error_from!(err)),
}
} else {
Err(app_system_error!("parse content-type failed"))
};
}
Ok(None)
}
fn path(&self) -> &str {
self.uri().path()
}
fn query_string(&self) -> &str {
match self.uri().query().as_ref() {
None => "",
Some(query) => query,
}
}
fn match_info(&self) -> Path<&Uri> {
Path::new(self.uri())
}
}
impl HttpRequestAttribute2 for Parts {
fn mime_type(&self) -> AppResult<Option<Mime>> {
if let Some(content_type) = self.headers.get(CONTENT_TYPE) {
return if let Ok(content_type) = content_type.to_str() {
match content_type.parse() {
Ok(mt) => Ok(Some(mt)),
Err(err) => Err(app_error_from!(err)),
}
} else {
Err(app_system_error!("parse content-type failed"))
};
}
Ok(None)
}
fn path(&self) -> &str {
self.uri.path()
}
fn query_string(&self) -> &str {
match self.uri.query().as_ref() {
None => "",
Some(query) => query,
}
}
fn match_info(&self) -> Path<&Uri> {
Path::new(&self.uri)
}
}