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 ;
@@ -1590,6 +1590,7 @@ static class H2Stream {
15901590 private final H2StreamChannelImpl channel ;
15911591 private final H2StreamHandler handler ;
15921592 private final boolean remoteInitiated ;
1593+ private final AtomicBoolean released ;
15931594
15941595 private H2Stream (
15951596 final H2StreamChannelImpl channel ,
@@ -1598,6 +1599,7 @@ private H2Stream(
15981599 this .channel = channel ;
15991600 this .handler = handler ;
16001601 this .remoteInitiated = remoteInitiated ;
1602+ this .released = new AtomicBoolean ();
16011603 }
16021604
16031605 int getId () {
@@ -1679,15 +1681,21 @@ void produceInputCapacityUpdate() throws IOException {
16791681 handler .updateInputCapacity ();
16801682 }
16811683
1682- void reset (final Exception cause ) {
1684+ void fail (final Exception cause ) {
16831685 channel .setRemoteEndStream ();
16841686 channel .setLocalEndStream ();
1685- handler .failed (cause );
1687+ if (released .compareAndSet (false , true )) {
1688+ handler .failed (cause );
1689+ handler .releaseResources ();
1690+ }
16861691 }
16871692
16881693 void localReset (final Exception cause , final int code ) throws IOException {
16891694 channel .localReset (code );
1690- handler .failed (cause );
1695+ if (released .compareAndSet (false , true )) {
1696+ handler .failed (cause );
1697+ handler .releaseResources ();
1698+ }
16911699 }
16921700
16931701 void localReset (final Exception cause , final H2Error error ) throws IOException {
@@ -1707,17 +1715,22 @@ HandlerFactory<AsyncPushConsumer> getPushHandlerFactory() {
17071715 }
17081716
17091717 void cancel () {
1710- reset (new RequestNotExecutedException ());
1718+ fail (new RequestNotExecutedException ());
17111719 }
17121720
17131721 boolean abort () {
17141722 final boolean cancelled = channel .cancel ();
1715- handler .failed (new RequestNotExecutedException ());
1723+ if (released .compareAndSet (false , true )) {
1724+ handler .failed (new RequestNotExecutedException ());
1725+ handler .releaseResources ();
1726+ }
17161727 return cancelled ;
17171728 }
17181729
17191730 void releaseResources () {
1720- handler .releaseResources ();
1731+ if (released .compareAndSet (false , true )) {
1732+ handler .releaseResources ();
1733+ }
17211734 }
17221735
17231736 void appendState (final StringBuilder buf ) {
0 commit comments