1818
1919package  io .undertow .conduits ;
2020
21- import  java .io .IOException ;
22- import  java .nio .ByteBuffer ;
23- import  java .nio .channels .FileChannel ;
24- import  java .util .concurrent .TimeUnit ;
25- 
2621import  io .undertow .UndertowLogger ;
2722import  io .undertow .UndertowMessages ;
2823import  io .undertow .UndertowOptions ;
4136import  org .xnio .conduits .ReadReadyHandler ;
4237import  org .xnio .conduits .StreamSourceConduit ;
4338
39+ import  java .io .IOException ;
40+ import  java .nio .ByteBuffer ;
41+ import  java .nio .channels .FileChannel ;
42+ import  java .util .concurrent .TimeUnit ;
43+ 
4444/** 
4545 * Wrapper for read timeout. This should always be the first wrapper applied to the underlying channel. 
4646 * 
4949 */ 
5050public  final  class  ReadTimeoutStreamSourceConduit  extends  AbstractStreamSourceConduit <StreamSourceConduit > {
5151
52-     private  XnioExecutor .Key  handle ;
52+     private  volatile   XnioExecutor .Key  handle ;
5353    private  final  StreamConnection  connection ;
5454    private  volatile  long  expireTime  = -1 ;
5555    private  final  OpenListener  openListener ;
@@ -60,14 +60,21 @@ public final class ReadTimeoutStreamSourceConduit extends AbstractStreamSourceCo
6060    private  final  Runnable  timeoutCommand  = new  Runnable () {
6161        @ Override 
6262        public  void  run () {
63-             handle  = null ;
64-             if  (expireTime  == -1 ) {
63+             synchronized  (ReadTimeoutStreamSourceConduit .this ) {
64+                 handle  = null ;
65+             }
66+             if  (expireTime  == -1  || !connection .isOpen ()) {
6567                return ;
6668            }
6769            long  current  = System .currentTimeMillis ();
6870            if  (current   < expireTime ) {
6971                //timeout has been bumped, re-schedule 
70-                 handle  = WorkerUtils .executeAfter (connection .getIoThread (),timeoutCommand , (expireTime  - current ) + FUZZ_FACTOR , TimeUnit .MILLISECONDS );
72+                 if  (handle  == null ) {
73+                     synchronized  (ReadTimeoutStreamSourceConduit .this ) {
74+                         if  (handle  == null )
75+                             handle  = WorkerUtils .executeAfter (connection .getIoThread (), timeoutCommand , (expireTime  - current ) + FUZZ_FACTOR , TimeUnit .MILLISECONDS );
76+                     }
77+                 }
7178                return ;
7279            }
7380            UndertowLogger .REQUEST_LOGGER .tracef ("Timing out channel %s due to inactivity" , connection .getSourceChannel ());
@@ -131,12 +138,16 @@ private void handleReadTimeout(final long ret) throws IOException {
131138            final  long  expireTimeVar  = expireTime ;
132139            if  (expireTimeVar  != -1  && currentTime  > expireTimeVar ) {
133140                IoUtils .safeClose (connection );
134-                 throw  UndertowMessages .MESSAGES .readTimedOut (this .getTimeout ());
141+                 throw  UndertowMessages .MESSAGES .readTimedOut (currentTime  - ( expireTimeVar  -  this .getTimeout () ));
135142            }
136143        }
137144        expireTime  = currentTime  + timeout ;
138145        if  (handle  == null ) {
139-             handle  = connection .getIoThread ().executeAfter (timeoutCommand , timeout , TimeUnit .MILLISECONDS );
146+             synchronized  (this ) {
147+                 if  (handle  == null )
148+                     handle  = connection .getIoThread ().executeAfter (timeoutCommand , timeout , TimeUnit .MILLISECONDS );
149+             }
150+ 
140151        }
141152    }
142153
@@ -232,9 +243,13 @@ public void terminateReads() throws IOException {
232243
233244    private  void  cleanup () {
234245        if  (handle  != null ) {
235-             handle .remove ();
236-             handle  = null ;
237-             expireTime  = -1 ;
246+             synchronized  (this ) {
247+                 if  (handle  != null ) {
248+                     handle .remove ();
249+                     handle  = null ;
250+                     expireTime  = -1 ;
251+                 }
252+             }
238253        }
239254    }
240255
@@ -247,7 +262,7 @@ public void suspendReads() {
247262    private  void  checkExpired () throws  ReadTimeoutException  {
248263        synchronized  (this ) {
249264            if  (expired ) {
250-                 throw  UndertowMessages .MESSAGES .readTimedOut (System .currentTimeMillis ());
265+                 throw  UndertowMessages .MESSAGES .readTimedOut (System .currentTimeMillis () - ( expireTime  -  getTimeout ()) );
251266            }
252267        }
253268    }
0 commit comments