@@ -14,7 +14,8 @@ use http::header::CONTENT_LENGTH;
14
14
use iron:: { headers:: ContentType , response:: Response , status:: Status , IronResult , Request } ;
15
15
use serde:: Serialize ;
16
16
use std:: { borrow:: Cow , sync:: Arc } ;
17
- use tera:: { Context , Tera } ;
17
+ use tera:: Context ;
18
+ use tokio:: task:: spawn_blocking;
18
19
19
20
/// When making using a custom status, use a closure that coerces to a `fn(&Self) -> Status`
20
21
#[ macro_export]
@@ -48,11 +49,28 @@ macro_rules! impl_webpage {
48
49
49
50
#[ macro_export]
50
51
macro_rules! impl_axum_webpage {
51
- ( $page: ty = $template: literal $( , status = $status: expr) ? $( , content_type = $content_type: expr) ? $( , ) ?) => {
52
- $crate:: impl_axum_webpage!( $page = |_| :: std:: borrow:: Cow :: Borrowed ( $template) $( , status = $status) ? $( , content_type = $content_type) ?) ;
52
+ (
53
+ $page: ty = $template: literal
54
+ $( , status = $status: expr) ?
55
+ $( , content_type = $content_type: expr) ?
56
+ $( , cpu_intensive_rendering = $cpu_intensive_rendering: expr) ?
57
+ $( , ) ?
58
+ ) => {
59
+ $crate:: impl_axum_webpage!(
60
+ $page = |_| :: std:: borrow:: Cow :: Borrowed ( $template)
61
+ $( , status = $status) ?
62
+ $( , content_type = $content_type) ?
63
+ $( , cpu_intensive_rendering = $cpu_intensive_rendering ) ?
64
+ ) ;
53
65
} ;
54
66
55
- ( $page: ty = $template: expr $( , status = $status: expr) ? $( , content_type = $content_type: expr) ? $( , ) ?) => {
67
+ (
68
+ $page: ty = $template: expr
69
+ $( , status = $status: expr) ?
70
+ $( , content_type = $content_type: expr) ?
71
+ $( , cpu_intensive_rendering = $cpu_intensive_rendering: expr) ?
72
+ $( , ) ?
73
+ ) => {
56
74
impl axum:: response:: IntoResponse for $page
57
75
{
58
76
fn into_response( self ) -> :: axum:: response:: Response {
@@ -63,6 +81,12 @@ macro_rules! impl_axum_webpage {
63
81
ct = $content_type;
64
82
) ?
65
83
84
+ #[ allow( unused_mut, unused_assignments) ]
85
+ let mut cpu_intensive_rendering = false ;
86
+ $(
87
+ cpu_intensive_rendering = $cpu_intensive_rendering;
88
+ ) ?
89
+
66
90
let mut response = :: axum:: http:: Response :: builder( )
67
91
. header( :: axum:: http:: header:: CONTENT_TYPE , ct)
68
92
$(
@@ -83,6 +107,7 @@ macro_rules! impl_axum_webpage {
83
107
let template: fn ( & Self ) -> :: std:: borrow:: Cow <' static , str > = $template;
84
108
template( & self ) . to_string( )
85
109
} ,
110
+ cpu_intensive_rendering,
86
111
} ) ;
87
112
response
88
113
}
@@ -164,14 +189,20 @@ pub trait WebPage: Serialize + Sized {
164
189
pub ( crate ) struct DelayedTemplateRender {
165
190
pub template : String ,
166
191
pub context : Context ,
192
+ pub cpu_intensive_rendering : bool ,
167
193
}
168
194
169
- fn render_response ( mut response : AxumResponse , templates : & Tera , csp_nonce : & str ) -> AxumResponse {
195
+ fn render_response (
196
+ mut response : AxumResponse ,
197
+ templates : Arc < TemplateData > ,
198
+ csp_nonce : String ,
199
+ ) -> AxumResponse {
170
200
if let Some ( render) = response. extensions ( ) . get :: < DelayedTemplateRender > ( ) {
201
+ let tera = & templates. templates ;
171
202
let mut context = render. context . clone ( ) ;
172
203
context. insert ( "csp_nonce" , & csp_nonce) ;
173
204
174
- let rendered = match templates . render ( & render. template , & context) {
205
+ let rendered = match tera . render ( & render. template , & context) {
175
206
Ok ( content) => content,
176
207
Err ( err) => {
177
208
if response. status ( ) . is_server_error ( ) {
@@ -214,5 +245,19 @@ pub(crate) async fn render_templates_middleware<B>(
214
245
. nonce ( )
215
246
. to_owned ( ) ;
216
247
217
- render_response ( next. run ( req) . await , & templates. templates , & csp_nonce)
248
+ let response = next. run ( req) . await ;
249
+
250
+ let cpu_intensive_rendering: bool = response
251
+ . extensions ( )
252
+ . get :: < DelayedTemplateRender > ( )
253
+ . map ( |render| render. cpu_intensive_rendering )
254
+ . unwrap_or ( false ) ;
255
+
256
+ if cpu_intensive_rendering {
257
+ spawn_blocking ( || render_response ( response, templates, csp_nonce) )
258
+ . await
259
+ . expect ( "tokio task join error when rendering templates" )
260
+ } else {
261
+ render_response ( response, templates, csp_nonce)
262
+ }
218
263
}
0 commit comments