@@ -45,6 +45,7 @@ typedef struct {
4545typedef struct {
4646 ngx_msec_t resolve_time ;
4747 ngx_msec_t connect_time ;
48+ ngx_msec_t first_byte_time ;
4849
4950 /* TODO:
5051 off_t bytes_received;
@@ -133,6 +134,8 @@ static ngx_int_t ngx_http_proxy_connect_resolve_time_variable(ngx_http_request_t
133134 ngx_http_variable_value_t * v , uintptr_t data );
134135static ngx_int_t ngx_http_proxy_connect_connect_time_variable (ngx_http_request_t * r ,
135136 ngx_http_variable_value_t * v , uintptr_t data );
137+ static ngx_int_t ngx_http_proxy_connect_first_byte_time_variable (ngx_http_request_t * r ,
138+ ngx_http_variable_value_t * v , uintptr_t data );
136139static ngx_int_t ngx_http_proxy_connect_variable_get_response (ngx_http_request_t * r ,
137140 ngx_http_variable_value_t * v , uintptr_t data );
138141static void ngx_http_proxy_connect_variable_set_response (ngx_http_request_t * r ,
@@ -277,6 +280,10 @@ static ngx_http_variable_t ngx_http_proxy_connect_vars[] = {
277280 ngx_http_proxy_connect_connect_time_variable , 0 ,
278281 NGX_HTTP_VAR_NOCACHEABLE , 0 },
279282
283+ { ngx_string ("proxy_connect_first_byte_time" ), NULL ,
284+ ngx_http_proxy_connect_first_byte_time_variable , 0 ,
285+ NGX_HTTP_VAR_NOCACHEABLE , 0 },
286+
280287 { ngx_string ("proxy_connect_response" ),
281288 ngx_http_proxy_connect_variable_set_response ,
282289 ngx_http_proxy_connect_variable_get_response ,
@@ -722,6 +729,13 @@ ngx_http_proxy_connect_tunnel(ngx_http_request_t *r,
722729 do_write = 1 ;
723730 b -> last += n ;
724731
732+ if (from_upstream ) {
733+ if (u -> state .first_byte_time == (ngx_msec_t ) - 1 ) {
734+ u -> state .first_byte_time = ngx_current_msec
735+ - u -> start_time ;
736+ }
737+ }
738+
725739 continue ;
726740 }
727741
@@ -1042,6 +1056,7 @@ ngx_http_proxy_connect_process_connect(ngx_http_request_t *r,
10421056
10431057 u -> start_time = ngx_current_msec ;
10441058 u -> state .connect_time = (ngx_msec_t ) - 1 ;
1059+ u -> state .first_byte_time = (ngx_msec_t ) - 1 ;
10451060
10461061 rc = ngx_event_connect_peer (& u -> peer );
10471062
@@ -2194,6 +2209,63 @@ ngx_http_proxy_connect_connect_time_variable(ngx_http_request_t *r,
21942209}
21952210
21962211
2212+ static ngx_int_t
2213+ ngx_http_proxy_connect_first_byte_time_variable (ngx_http_request_t * r ,
2214+ ngx_http_variable_value_t * v , uintptr_t data )
2215+ {
2216+ u_char * p ;
2217+ size_t len ;
2218+ ngx_msec_int_t ms ;
2219+ ngx_http_proxy_connect_ctx_t * ctx ;
2220+ ngx_http_proxy_connect_upstream_t * u ;
2221+
2222+ if (r -> method != NGX_HTTP_CONNECT ) {
2223+ return NGX_OK ;
2224+ }
2225+
2226+ v -> valid = 1 ;
2227+ v -> no_cacheable = 0 ;
2228+ v -> not_found = 0 ;
2229+
2230+ ctx = ngx_http_get_module_ctx (r , ngx_http_proxy_connect_module );
2231+
2232+ if (ctx == NULL ) {
2233+ v -> not_found = 1 ;
2234+ return NGX_OK ;
2235+ }
2236+
2237+ u = ctx -> u ;
2238+
2239+ if (u == NULL || !u -> connected ) {
2240+ v -> not_found = 1 ;
2241+ return NGX_OK ;
2242+ }
2243+
2244+ len = NGX_TIME_T_LEN + 4 ;
2245+
2246+ p = ngx_pnalloc (r -> pool , len );
2247+ if (p == NULL ) {
2248+ return NGX_ERROR ;
2249+ }
2250+
2251+ v -> data = p ;
2252+
2253+ ms = u -> state .first_byte_time ;
2254+
2255+ if (ms != -1 ) {
2256+ ms = ngx_max (ms , 0 );
2257+ p = ngx_sprintf (p , "%T.%03M" , (time_t ) ms / 1000 , ms % 1000 );
2258+
2259+ } else {
2260+ * p ++ = '-' ;
2261+ }
2262+
2263+ v -> len = p - v -> data ;
2264+
2265+ return NGX_OK ;
2266+ }
2267+
2268+
21972269static ngx_int_t
21982270ngx_http_proxy_connect_variable_get_response (ngx_http_request_t * r ,
21992271 ngx_http_variable_value_t * v , uintptr_t data )
0 commit comments