4040import java .util .concurrent .ConcurrentHashMap ;
4141import java .util .concurrent .ConcurrentLinkedDeque ;
4242import java .util .concurrent .ConcurrentLinkedQueue ;
43+ import java .util .concurrent .atomic .AtomicBoolean ;
4344import java .util .concurrent .atomic .AtomicInteger ;
4445
4546import javax .net .ssl .SSLHandshakeException ;
@@ -556,7 +557,7 @@ public final void onTimeout(final Timeout timeout) throws HttpException, IOExcep
556557 for (final Iterator <Map .Entry <Integer , H2Stream >> it = streamMap .entrySet ().iterator (); it .hasNext (); ) {
557558 final Map .Entry <Integer , H2Stream > entry = it .next ();
558559 final H2Stream stream = entry .getValue ();
559- stream .reset (new H2StreamResetException (H2Error .NO_ERROR , "Timeout due to inactivity (" + timeout + ")" ));
560+ stream .fail (new H2StreamResetException (H2Error .NO_ERROR , "Timeout due to inactivity (" + timeout + ")" ));
560561 }
561562 streamMap .clear ();
562563 }
@@ -676,7 +677,7 @@ public final void onException(final Exception cause) {
676677 for (final Iterator <Map .Entry <Integer , H2Stream >> it = streamMap .entrySet ().iterator (); it .hasNext (); ) {
677678 final Map .Entry <Integer , H2Stream > entry = it .next ();
678679 final H2Stream stream = entry .getValue ();
679- stream .reset (cause );
680+ stream .fail (cause );
680681 }
681682 streamMap .clear ();
682683 if (!(cause instanceof ConnectionClosedException )) {
@@ -873,9 +874,8 @@ private void consumeFrame(final RawFrame frame) throws HttpException, IOExceptio
873874 throw new H2ConnectionException (H2Error .FRAME_SIZE_ERROR , "Invalid RST_STREAM frame payload" );
874875 }
875876 final int errorCode = payload .getInt ();
876- stream .reset (new H2StreamResetException (errorCode , "Stream reset (" + errorCode + ")" ));
877+ stream .fail (new H2StreamResetException (errorCode , "Stream reset (" + errorCode + ")" ));
877878 streamMap .remove (streamId );
878- stream .releaseResources ();
879879 requestSessionOutput ();
880880 }
881881 }
@@ -1013,7 +1013,7 @@ private void consumeFrame(final RawFrame frame) throws HttpException, IOExceptio
10131013 for (final Iterator <Map .Entry <Integer , H2Stream >> it = streamMap .entrySet ().iterator (); it .hasNext (); ) {
10141014 final Map .Entry <Integer , H2Stream > entry = it .next ();
10151015 final H2Stream stream = entry .getValue ();
1016- stream .reset (new H2StreamResetException (errorCode , "Connection terminated by the peer (" + errorCode + ")" ));
1016+ stream .fail (new H2StreamResetException (errorCode , "Connection terminated by the peer (" + errorCode + ")" ));
10171017 }
10181018 streamMap .clear ();
10191019 connState = ConnectionHandshake .SHUTDOWN ;
@@ -1599,6 +1599,7 @@ static class H2Stream {
15991599 private final H2StreamChannelImpl channel ;
16001600 private final H2StreamHandler handler ;
16011601 private final boolean remoteInitiated ;
1602+ private final AtomicBoolean released ;
16021603
16031604 private H2Stream (
16041605 final H2StreamChannelImpl channel ,
@@ -1607,6 +1608,7 @@ private H2Stream(
16071608 this .channel = channel ;
16081609 this .handler = handler ;
16091610 this .remoteInitiated = remoteInitiated ;
1611+ this .released = new AtomicBoolean ();
16101612 }
16111613
16121614 int getId () {
@@ -1688,15 +1690,21 @@ void produceInputCapacityUpdate() throws IOException {
16881690 handler .updateInputCapacity ();
16891691 }
16901692
1691- void reset (final Exception cause ) {
1693+ void fail (final Exception cause ) {
16921694 channel .setRemoteEndStream ();
16931695 channel .setLocalEndStream ();
1694- handler .failed (cause );
1696+ if (released .compareAndSet (false , true )) {
1697+ handler .failed (cause );
1698+ handler .releaseResources ();
1699+ }
16951700 }
16961701
16971702 void localReset (final Exception cause , final int code ) throws IOException {
16981703 channel .localReset (code );
1699- handler .failed (cause );
1704+ if (released .compareAndSet (false , true )) {
1705+ handler .failed (cause );
1706+ handler .releaseResources ();
1707+ }
17001708 }
17011709
17021710 void localReset (final Exception cause , final H2Error error ) throws IOException {
@@ -1716,17 +1724,22 @@ HandlerFactory<AsyncPushConsumer> getPushHandlerFactory() {
17161724 }
17171725
17181726 void cancel () {
1719- reset (new RequestNotExecutedException ());
1727+ fail (new RequestNotExecutedException ());
17201728 }
17211729
17221730 boolean abort () {
17231731 final boolean cancelled = channel .cancel ();
1724- handler .failed (new RequestNotExecutedException ());
1732+ if (released .compareAndSet (false , true )) {
1733+ handler .failed (new RequestNotExecutedException ());
1734+ handler .releaseResources ();
1735+ }
17251736 return cancelled ;
17261737 }
17271738
17281739 void releaseResources () {
1729- handler .releaseResources ();
1740+ if (released .compareAndSet (false , true )) {
1741+ handler .releaseResources ();
1742+ }
17301743 }
17311744
17321745 void appendState (final StringBuilder buf ) {
0 commit comments