Issue #470 AsyncContextState NPE if called after reset

Added a NOT_ASYNC state to the enum to avoid the null value.
This commit is contained in:
Greg Wilkins 2016-03-31 18:23:18 +11:00
parent 86f3947378
commit 08b528e960
2 changed files with 91 additions and 96 deletions

View File

@ -51,7 +51,7 @@ public class AsyncContextState implements AsyncContext
{
HttpChannelState state=_state;
if (state==null)
throw new IllegalStateException("AsyncContext completed");
throw new IllegalStateException("AsyncContext completed and/or Request lifecycle recycled");
return state;
}

View File

@ -82,6 +82,7 @@ public class HttpChannelState
*/
public enum Async
{
NOT_ASYNC,
STARTED, // AsyncContext.startAsync() has been called
DISPATCH, //
COMPLETE, // AsyncContext.complete() has been called
@ -109,7 +110,7 @@ public class HttpChannelState
{
_channel=channel;
_state=State.IDLE;
_async=null;
_async=Async.NOT_ASYNC;
_initial=true;
}
@ -216,33 +217,30 @@ public class HttpChannelState
return Action.WRITE_CALLBACK;
}
if (_async!=null)
switch(_async)
{
Async async=_async;
switch(async)
{
case COMPLETE:
_state=State.COMPLETING;
return Action.COMPLETE;
case DISPATCH:
_state=State.DISPATCHED;
_async=null;
return Action.ASYNC_DISPATCH;
case EXPIRING:
break;
case EXPIRED:
_state=State.DISPATCHED;
_async=null;
return Action.ERROR_DISPATCH;
case STARTED:
return Action.WAIT;
case ERRORING:
_state=State.DISPATCHED;
return Action.ASYNC_ERROR;
default:
throw new IllegalStateException(getStatusStringLocked());
}
case COMPLETE:
_state=State.COMPLETING;
return Action.COMPLETE;
case DISPATCH:
_state=State.DISPATCHED;
_async=Async.NOT_ASYNC;
return Action.ASYNC_DISPATCH;
case EXPIRING:
break;
case EXPIRED:
_state=State.DISPATCHED;
_async=Async.NOT_ASYNC;
return Action.ERROR_DISPATCH;
case STARTED:
return Action.WAIT;
case ERRORING:
_state=State.DISPATCHED;
return Action.ASYNC_ERROR;
case NOT_ASYNC:
break;
default:
throw new IllegalStateException(getStatusStringLocked());
}
return Action.WAIT;
@ -264,7 +262,7 @@ public class HttpChannelState
try(Locker.Lock lock= _locker.lock())
{
if (_state!=State.DISPATCHED || _async!=null)
if (_state!=State.DISPATCHED || _async!=Async.NOT_ASYNC)
throw new IllegalStateException(this.getStatusStringLocked());
_async=Async.STARTED;
@ -346,78 +344,75 @@ public class HttpChannelState
throw new IllegalStateException(this.getStatusStringLocked());
}
if (_async!=null)
_initial=false;
switch(_async)
{
_initial=false;
switch(_async)
{
case COMPLETE:
_state=State.COMPLETING;
_async=null;
action=Action.COMPLETE;
break;
case COMPLETE:
_state=State.COMPLETING;
_async=Async.NOT_ASYNC;
action=Action.COMPLETE;
break;
case DISPATCH:
_state=State.DISPATCHED;
_async=null;
action=Action.ASYNC_DISPATCH;
break;
case DISPATCH:
_state=State.DISPATCHED;
_async=Async.NOT_ASYNC;
action=Action.ASYNC_DISPATCH;
break;
case EXPIRED:
_state=State.DISPATCHED;
_async=null;
action = Action.ERROR_DISPATCH;
break;
case EXPIRED:
_state=State.DISPATCHED;
_async=Async.NOT_ASYNC;
action = Action.ERROR_DISPATCH;
break;
case STARTED:
if (_asyncReadUnready && _asyncReadPossible)
{
_state=State.ASYNC_IO;
_asyncReadUnready=false;
action = Action.READ_CALLBACK;
}
else if (_asyncWrite) // TODO refactor same as read
{
_asyncWrite=false;
_state=State.ASYNC_IO;
action=Action.WRITE_CALLBACK;
}
else
{
schedule_event=_event;
read_interested=_asyncReadUnready;
_state=State.ASYNC_WAIT;
action=Action.WAIT;
}
break;
case EXPIRING:
case STARTED:
if (_asyncReadUnready && _asyncReadPossible)
{
_state=State.ASYNC_IO;
_asyncReadUnready=false;
action = Action.READ_CALLBACK;
}
else if (_asyncWrite) // TODO refactor same as read
{
_asyncWrite=false;
_state=State.ASYNC_IO;
action=Action.WRITE_CALLBACK;
}
else
{
schedule_event=_event;
read_interested=_asyncReadUnready;
_state=State.ASYNC_WAIT;
action=Action.WAIT;
break;
}
break;
case ERRORING:
_state=State.DISPATCHED;
action=Action.ASYNC_ERROR;
break;
case EXPIRING:
schedule_event=_event;
_state=State.ASYNC_WAIT;
action=Action.WAIT;
break;
case ERRORED:
_state=State.DISPATCHED;
action=Action.ERROR_DISPATCH;
_async=null;
break;
case ERRORING:
_state=State.DISPATCHED;
action=Action.ASYNC_ERROR;
break;
default:
_state=State.COMPLETING;
action=Action.COMPLETE;
break;
}
}
else
{
_state=State.COMPLETING;
action=Action.COMPLETE;
case ERRORED:
_state=State.DISPATCHED;
action=Action.ERROR_DISPATCH;
_async=Async.NOT_ASYNC;
break;
case NOT_ASYNC:
_state=State.COMPLETING;
action=Action.COMPLETE;
break;
default:
_state=State.COMPLETING;
action=Action.COMPLETE;
break;
}
}
@ -661,7 +656,7 @@ public class HttpChannelState
aListeners=_asyncListeners;
event=_event;
_state=State.COMPLETED;
_async=null;
_async=Async.NOT_ASYNC;
break;
default:
@ -720,7 +715,7 @@ public class HttpChannelState
}
_asyncListeners=null;
_state=State.IDLE;
_async=null;
_async=Async.NOT_ASYNC;
_initial=true;
_asyncReadPossible=_asyncReadUnready=false;
_asyncWrite=false;
@ -744,7 +739,7 @@ public class HttpChannelState
}
_asyncListeners=null;
_state=State.UPGRADED;
_async=null;
_async=Async.NOT_ASYNC;
_initial=true;
_asyncReadPossible=_asyncReadUnready=false;
_asyncWrite=false;
@ -834,7 +829,7 @@ public class HttpChannelState
try(Locker.Lock lock= _locker.lock())
{
if (_state==State.DISPATCHED)
return _async!=null;
return _async!=Async.NOT_ASYNC;
return _async==Async.STARTED || _async==Async.EXPIRING;
}
}
@ -843,7 +838,7 @@ public class HttpChannelState
{
try(Locker.Lock lock= _locker.lock())
{
return !_initial || _async!=null;
return !_initial || _async!=Async.NOT_ASYNC;
}
}