@@ -7,6 +7,7 @@ use crate::webserver::content_security_policy::ContentSecurityPolicy;
77use crate :: webserver:: database:: execute_queries:: stop_at_first_error;
88use crate :: webserver:: database:: { execute_queries:: stream_query_results_with_conn, DbItem } ;
99use crate :: webserver:: http_request_info:: extract_request_info;
10+ use crate :: webserver:: server_timing:: ServerTiming ;
1011use crate :: webserver:: ErrorWithStatus ;
1112use crate :: { AppConfig , AppState , ParsedSqlFile , DEFAULT_404_FILE } ;
1213use actix_web:: dev:: { fn_service, ServiceFactory , ServiceRequest } ;
@@ -46,6 +47,7 @@ pub struct RequestContext {
4647 pub is_embedded : bool ,
4748 pub source_path : PathBuf ,
4849 pub content_security_policy : ContentSecurityPolicy ,
50+ pub server_timing : Arc < ServerTiming > ,
4951}
5052
5153async fn stream_response ( stream : impl Stream < Item = DbItem > , mut renderer : AnyRenderBodyContext ) {
@@ -106,7 +108,10 @@ async fn build_response_header_and_stream<S: Stream<Item = DbItem>>(
106108 let mut stream = Box :: pin ( database_entries) ;
107109 while let Some ( item) = stream. next ( ) . await {
108110 let page_context = match item {
109- DbItem :: Row ( data) => head_context. handle_row ( data) . await ?,
111+ DbItem :: Row ( data) => {
112+ head_context. request_context . server_timing . record ( "row" ) ;
113+ head_context. handle_row ( data) . await ?
114+ }
110115 DbItem :: FinishedQuery => {
111116 log:: debug!( "finished query" ) ;
112117 continue ;
@@ -163,25 +168,29 @@ enum ResponseWithWriter<S> {
163168async fn render_sql (
164169 srv_req : & mut ServiceRequest ,
165170 sql_file : Arc < ParsedSqlFile > ,
171+ server_timing : ServerTiming ,
166172) -> actix_web:: Result < HttpResponse > {
167173 let app_state = srv_req
168174 . app_data :: < web:: Data < AppState > > ( )
169175 . ok_or_else ( || ErrorInternalServerError ( "no state" ) ) ?
170- . clone ( ) // Cheap reference count increase
176+ . clone ( )
171177 . into_inner ( ) ;
172178
173- let mut req_param = extract_request_info ( srv_req, Arc :: clone ( & app_state) )
179+ let mut req_param = extract_request_info ( srv_req, Arc :: clone ( & app_state) , server_timing )
174180 . await
175181 . map_err ( |e| anyhow_err_to_actix ( e, & app_state) ) ?;
176182 log:: debug!( "Received a request with the following parameters: {req_param:?}" ) ;
177183
184+ req_param. server_timing . record ( "parse_req" ) ;
185+
178186 let ( resp_send, resp_recv) = tokio:: sync:: oneshot:: channel :: < HttpResponse > ( ) ;
179187 let source_path: PathBuf = sql_file. source_path . clone ( ) ;
180188 actix_web:: rt:: spawn ( async move {
181189 let request_context = RequestContext {
182190 is_embedded : req_param. get_variables . contains_key ( "_sqlpage_embed" ) ,
183191 source_path,
184192 content_security_policy : ContentSecurityPolicy :: with_random_nonce ( ) ,
193+ server_timing : Arc :: clone ( & req_param. server_timing ) ,
185194 } ;
186195 let mut conn = None ;
187196 let database_entries_stream =
@@ -275,13 +284,17 @@ async fn process_sql_request(
275284 sql_path : PathBuf ,
276285) -> actix_web:: Result < HttpResponse > {
277286 let app_state: & web:: Data < AppState > = req. app_data ( ) . expect ( "app_state" ) ;
287+ let server_timing = ServerTiming :: for_env ( app_state. config . environment ) ;
288+
278289 let sql_file = app_state
279290 . sql_file_cache
280291 . get_with_privilege ( app_state, & sql_path, false )
281292 . await
282293 . with_context ( || format ! ( "Unable to read SQL file \" {}\" " , sql_path. display( ) ) )
283294 . map_err ( |e| anyhow_err_to_actix ( e, app_state) ) ?;
284- render_sql ( req, sql_file) . await
295+ server_timing. record ( "sql_file" ) ;
296+
297+ render_sql ( req, sql_file, server_timing) . await
285298}
286299
287300async fn serve_file (
0 commit comments