use std::sync::Arc;
use crate::TemplateResolutionAttributes;
use crate::cache::{ICacheEntryValidity, NonCacheableCacheEntryValidity};
use crate::templateresource::UrlResourceConnectionHandler;
use crate::util::Utf16String;
use crate::{IEngineConfiguration, ITemplateResource, TemplateResourceError, UrlTemplateResource};
use super::{
AbstractConfigurableTemplateResolver, ITemplateResolver, TemplateResolution,
TemplateResolverError,
};
pub struct UrlTemplateResolver {
resolver: AbstractConfigurableTemplateResolver,
connection_handler: Option<Arc<UrlResourceConnectionHandler>>,
}
impl UrlTemplateResolver {
#[must_use]
pub fn new() -> Self {
Self {
resolver: AbstractConfigurableTemplateResolver::new(
"org.thymeleaf.templateresolver.UrlTemplateResolver",
),
connection_handler: None,
}
}
pub fn set_connection_handler(
&mut self,
connection_handler: Option<Arc<UrlResourceConnectionHandler>>,
) {
self.connection_handler = connection_handler;
}
#[must_use]
pub fn get_connection_handler(&self) -> Option<&Arc<UrlResourceConnectionHandler>> {
self.connection_handler.as_ref()
}
#[must_use]
pub fn compute_validity(&self, template: &Utf16String) -> Arc<dyn ICacheEntryValidity> {
let text = template.to_string_lossy();
let java_dot_matches_entire_template = !text.chars().any(|character| {
matches!(
character,
'\n' | '\r' | '\u{0085}' | '\u{2028}' | '\u{2029}'
)
});
if java_dot_matches_entire_template && text.to_lowercase().contains(";jsessionid") {
return Arc::new(NonCacheableCacheEntryValidity::new());
}
self.resolver.compute_validity(template)
}
}
impl Default for UrlTemplateResolver {
fn default() -> Self {
Self::new()
}
}
impl std::ops::Deref for UrlTemplateResolver {
type Target = AbstractConfigurableTemplateResolver;
fn deref(&self) -> &Self::Target {
&self.resolver
}
}
impl std::ops::DerefMut for UrlTemplateResolver {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.resolver
}
}
impl ITemplateResolver for UrlTemplateResolver {
fn get_name(&self) -> Option<&Utf16String> {
self.resolver.get_name()
}
fn get_order(&self) -> Option<i32> {
self.resolver.get_order()
}
fn resolve_template(
&self,
_configuration: &dyn IEngineConfiguration,
_owner_template: Option<&Utf16String>,
template: &Utf16String,
_template_resolution_attributes: Option<&TemplateResolutionAttributes>,
) -> Result<Option<TemplateResolution>, TemplateResolverError> {
self.resolver.resolver().resolve_template(
template,
|| {
let resource_name = self.resolver.compute_resource_name(template);
let resource_name = resource_name.to_string_lossy();
let character_encoding = self
.resolver
.get_character_encoding()
.map(Utf16String::to_string_lossy);
let resource = self.connection_handler.as_ref().map_or_else(
|| {
UrlTemplateResource::new(
Some(&resource_name),
character_encoding.as_deref(),
)
},
|handler| {
UrlTemplateResource::with_connection_handler(
Some(&resource_name),
character_encoding.as_deref(),
Arc::clone(handler),
)
},
);
match resource {
Ok(resource) => Ok(Some(Arc::new(resource) as Arc<dyn ITemplateResource>)),
Err(TemplateResourceError::MalformedUrl { .. }) => Ok(None),
Err(error) => Err(TemplateResolverError::from(error)),
}
},
|| self.resolver.compute_template_mode(template),
|| self.compute_validity(template),
)
}
}