@@ -47,6 +47,8 @@ static void ngx_ssl_write_handler(ngx_event_t *wev);
4747static ssize_t ngx_ssl_write_early (ngx_connection_t * c , u_char * data ,
4848 size_t size );
4949#endif
50+ static ssize_t ngx_ssl_sendfile (ngx_connection_t * c , ngx_buf_t * file ,
51+ size_t size );
5052static void ngx_ssl_read_handler (ngx_event_t * rev );
5153static void ngx_ssl_shutdown_handler (ngx_event_t * ev );
5254static void ngx_ssl_connection_error (ngx_connection_t * c , int sslerr ,
@@ -1762,6 +1764,16 @@ ngx_ssl_handshake(ngx_connection_t *c)
17621764
17631765#endif
17641766#endif
1767+ #endif
1768+
1769+ #ifdef BIO_get_ktls_send
1770+
1771+ if (BIO_get_ktls_send (SSL_get_wbio (c -> ssl -> connection )) == 1 ) {
1772+ ngx_log_debug0 (NGX_LOG_DEBUG_EVENT , c -> log , 0 ,
1773+ "BIO_get_ktls_send(): 1" );
1774+ c -> ssl -> sendfile = 1 ;
1775+ }
1776+
17651777#endif
17661778
17671779 rc = ngx_ssl_ocsp_validate (c );
@@ -1899,6 +1911,16 @@ ngx_ssl_try_early_data(ngx_connection_t *c)
18991911 c -> read -> ready = 1 ;
19001912 c -> write -> ready = 1 ;
19011913
1914+ #ifdef BIO_get_ktls_send
1915+
1916+ if (BIO_get_ktls_send (SSL_get_wbio (c -> ssl -> connection )) == 1 ) {
1917+ ngx_log_debug0 (NGX_LOG_DEBUG_EVENT , c -> log , 0 ,
1918+ "BIO_get_ktls_send(): 1" );
1919+ c -> ssl -> sendfile = 1 ;
1920+ }
1921+
1922+ #endif
1923+
19021924 rc = ngx_ssl_ocsp_validate (c );
19031925
19041926 if (rc == NGX_ERROR ) {
@@ -2502,10 +2524,11 @@ ngx_ssl_write_handler(ngx_event_t *wev)
25022524ngx_chain_t *
25032525ngx_ssl_send_chain (ngx_connection_t * c , ngx_chain_t * in , off_t limit )
25042526{
2505- int n ;
2506- ngx_uint_t flush ;
2507- ssize_t send , size ;
2508- ngx_buf_t * buf ;
2527+ int n ;
2528+ ngx_uint_t flush ;
2529+ ssize_t send , size , file_size ;
2530+ ngx_buf_t * buf ;
2531+ ngx_chain_t * cl ;
25092532
25102533 if (!c -> ssl -> buffer ) {
25112534
@@ -2579,6 +2602,11 @@ ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
25792602 continue ;
25802603 }
25812604
2605+ if (in -> buf -> in_file && c -> ssl -> sendfile ) {
2606+ flush = 1 ;
2607+ break ;
2608+ }
2609+
25822610 size = in -> buf -> last - in -> buf -> pos ;
25832611
25842612 if (size > buf -> end - buf -> last ) {
@@ -2610,8 +2638,35 @@ ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
26102638 size = buf -> last - buf -> pos ;
26112639
26122640 if (size == 0 ) {
2641+
2642+ if (in && in -> buf -> in_file && send < limit ) {
2643+
2644+ /* coalesce the neighbouring file bufs */
2645+
2646+ cl = in ;
2647+ file_size = (size_t ) ngx_chain_coalesce_file (& cl , limit - send );
2648+
2649+ n = ngx_ssl_sendfile (c , in -> buf , file_size );
2650+
2651+ if (n == NGX_ERROR ) {
2652+ return NGX_CHAIN_ERROR ;
2653+ }
2654+
2655+ if (n == NGX_AGAIN ) {
2656+ break ;
2657+ }
2658+
2659+ in = ngx_chain_update_sent (in , n );
2660+
2661+ send += n ;
2662+ flush = 0 ;
2663+
2664+ continue ;
2665+ }
2666+
26132667 buf -> flush = 0 ;
26142668 c -> buffered &= ~NGX_SSL_BUFFERED ;
2669+
26152670 return in ;
26162671 }
26172672
@@ -2636,7 +2691,7 @@ ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
26362691 buf -> pos = buf -> start ;
26372692 buf -> last = buf -> start ;
26382693
2639- if (in == NULL || send = = limit ) {
2694+ if (in == NULL || send > = limit ) {
26402695 break ;
26412696 }
26422697 }
@@ -2882,6 +2937,150 @@ ngx_ssl_write_early(ngx_connection_t *c, u_char *data, size_t size)
28822937#endif
28832938
28842939
2940+ static ssize_t
2941+ ngx_ssl_sendfile (ngx_connection_t * c , ngx_buf_t * file , size_t size )
2942+ {
2943+ #ifdef BIO_get_ktls_send
2944+
2945+ int sslerr ;
2946+ ssize_t n ;
2947+ ngx_err_t err ;
2948+
2949+ ngx_ssl_clear_error (c -> log );
2950+
2951+ ngx_log_debug2 (NGX_LOG_DEBUG_EVENT , c -> log , 0 ,
2952+ "SSL to sendfile: @%O %uz" ,
2953+ file -> file_pos , size );
2954+
2955+ ngx_set_errno (0 );
2956+
2957+ n = SSL_sendfile (c -> ssl -> connection , file -> file -> fd , file -> file_pos ,
2958+ size , 0 );
2959+
2960+ ngx_log_debug1 (NGX_LOG_DEBUG_EVENT , c -> log , 0 , "SSL_sendfile: %d" , n );
2961+
2962+ if (n > 0 ) {
2963+
2964+ if (c -> ssl -> saved_read_handler ) {
2965+
2966+ c -> read -> handler = c -> ssl -> saved_read_handler ;
2967+ c -> ssl -> saved_read_handler = NULL ;
2968+ c -> read -> ready = 1 ;
2969+
2970+ if (ngx_handle_read_event (c -> read , 0 ) != NGX_OK ) {
2971+ return NGX_ERROR ;
2972+ }
2973+
2974+ ngx_post_event (c -> read , & ngx_posted_events );
2975+ }
2976+
2977+ c -> sent += n ;
2978+
2979+ return n ;
2980+ }
2981+
2982+ if (n == 0 ) {
2983+
2984+ /*
2985+ * if sendfile returns zero, then someone has truncated the file,
2986+ * so the offset became beyond the end of the file
2987+ */
2988+
2989+ ngx_log_error (NGX_LOG_ALERT , c -> log , 0 ,
2990+ "SSL_sendfile() reported that \"%s\" was truncated at %O" ,
2991+ file -> file -> name .data , file -> file_pos );
2992+
2993+ return NGX_ERROR ;
2994+ }
2995+
2996+ sslerr = SSL_get_error (c -> ssl -> connection , n );
2997+
2998+ if (sslerr == SSL_ERROR_ZERO_RETURN ) {
2999+
3000+ /*
3001+ * OpenSSL fails to return SSL_ERROR_SYSCALL if an error
3002+ * happens during writing after close_notify alert from the
3003+ * peer, and returns SSL_ERROR_ZERO_RETURN instead
3004+ */
3005+
3006+ sslerr = SSL_ERROR_SYSCALL ;
3007+ }
3008+
3009+ if (sslerr == SSL_ERROR_SSL
3010+ && ERR_GET_REASON (ERR_peek_error ()) == SSL_R_UNINITIALIZED
3011+ && ngx_errno != 0 )
3012+ {
3013+ /*
3014+ * OpenSSL fails to return SSL_ERROR_SYSCALL if an error
3015+ * happens in sendfile(), and returns SSL_ERROR_SSL with
3016+ * SSL_R_UNINITIALIZED reason instead
3017+ */
3018+
3019+ sslerr = SSL_ERROR_SYSCALL ;
3020+ }
3021+
3022+ err = (sslerr == SSL_ERROR_SYSCALL ) ? ngx_errno : 0 ;
3023+
3024+ ngx_log_debug1 (NGX_LOG_DEBUG_EVENT , c -> log , 0 , "SSL_get_error: %d" , sslerr );
3025+
3026+ if (sslerr == SSL_ERROR_WANT_WRITE ) {
3027+
3028+ if (c -> ssl -> saved_read_handler ) {
3029+
3030+ c -> read -> handler = c -> ssl -> saved_read_handler ;
3031+ c -> ssl -> saved_read_handler = NULL ;
3032+ c -> read -> ready = 1 ;
3033+
3034+ if (ngx_handle_read_event (c -> read , 0 ) != NGX_OK ) {
3035+ return NGX_ERROR ;
3036+ }
3037+
3038+ ngx_post_event (c -> read , & ngx_posted_events );
3039+ }
3040+
3041+ c -> write -> ready = 0 ;
3042+ return NGX_AGAIN ;
3043+ }
3044+
3045+ if (sslerr == SSL_ERROR_WANT_READ ) {
3046+
3047+ ngx_log_debug0 (NGX_LOG_DEBUG_EVENT , c -> log , 0 ,
3048+ "SSL_sendfile: want read" );
3049+
3050+ c -> read -> ready = 0 ;
3051+
3052+ if (ngx_handle_read_event (c -> read , 0 ) != NGX_OK ) {
3053+ return NGX_ERROR ;
3054+ }
3055+
3056+ /*
3057+ * we do not set the timer because there is already
3058+ * the write event timer
3059+ */
3060+
3061+ if (c -> ssl -> saved_read_handler == NULL ) {
3062+ c -> ssl -> saved_read_handler = c -> read -> handler ;
3063+ c -> read -> handler = ngx_ssl_read_handler ;
3064+ }
3065+
3066+ return NGX_AGAIN ;
3067+ }
3068+
3069+ c -> ssl -> no_wait_shutdown = 1 ;
3070+ c -> ssl -> no_send_shutdown = 1 ;
3071+ c -> write -> error = 1 ;
3072+
3073+ ngx_ssl_connection_error (c , sslerr , err , "SSL_sendfile() failed" );
3074+
3075+ #else
3076+ ngx_log_error (NGX_LOG_ALERT , c -> log , 0 ,
3077+ "SSL_sendfile() not available" );
3078+ #endif
3079+
3080+ return NGX_ERROR ;
3081+ }
3082+
3083+
28853084static void
28863085ngx_ssl_read_handler (ngx_event_t * rev )
28873086{
0 commit comments