5757import org .apache .hc .core5 .http .impl .BasicEndpointDetails ;
5858import org .apache .hc .core5 .http .impl .BasicHttpConnectionMetrics ;
5959import org .apache .hc .core5 .http .impl .CharCodingSupport ;
60+ import org .apache .hc .core5 .http .nio .AsyncClientExchangeHandler ;
6061import org .apache .hc .core5 .http .nio .AsyncPushConsumer ;
6162import org .apache .hc .core5 .http .nio .AsyncPushProducer ;
6263import org .apache .hc .core5 .http .nio .HandlerFactory ;
6364import org .apache .hc .core5 .http .nio .command .CommandSupport ;
64- import org .apache .hc .core5 .http .nio .command .ExecutableCommand ;
65+ import org .apache .hc .core5 .http .nio .command .RequestExecutionCommand ;
6566import org .apache .hc .core5 .http .nio .command .ShutdownCommand ;
66- import org .apache .hc .core5 .http .protocol .HttpCoreContext ;
67+ import org .apache .hc .core5 .http .protocol .HttpContext ;
6768import org .apache .hc .core5 .http .protocol .HttpProcessor ;
6869import org .apache .hc .core5 .http2 .H2ConnectionException ;
6970import org .apache .hc .core5 .http2 .H2Error ;
@@ -172,6 +173,18 @@ public String getId() {
172173 return ioSession .getId ();
173174 }
174175
176+ BasicHttpConnectionMetrics getConnMetrics () {
177+ return connMetrics ;
178+ }
179+
180+ HttpProcessor getHttpProcessor () {
181+ return httpProcessor ;
182+ }
183+
184+ void submitCommand (final Command command ) {
185+ ioSession .enqueue (command , Command .Priority .NORMAL );
186+ }
187+
175188 abstract void validateSetting (H2Param param , int value ) throws H2ConnectionException ;
176189
177190 abstract H2Setting [] generateSettings (H2Config localConfig );
@@ -182,18 +195,18 @@ public String getId() {
182195
183196 abstract void acceptPushFrame () throws H2ConnectionException ;
184197
185- abstract H2StreamHandler createRemotelyInitiatedStream (
186- H2StreamChannel channel ,
198+ abstract H2StreamHandler incomingRequest (H2StreamChannel channel ) throws IOException ;
199+
200+ abstract H2StreamHandler incomingPushPromise (H2StreamChannel channel ,
201+ HandlerFactory <AsyncPushConsumer > pushHandlerFactory ) throws IOException ;
187202
188- HttpProcessor httpProcessor ,
189- BasicHttpConnectionMetrics connMetrics ,
190- HandlerFactory <AsyncPushConsumer > pushHandlerFactory ) throws IOException ;
203+ abstract H2StreamHandler outgoingRequest (H2StreamChannel channel ,
204+ AsyncClientExchangeHandler exchangeHandler ,
205+ HandlerFactory <AsyncPushConsumer > pushHandlerFactory ,
206+ HttpContext context ) throws IOException ;
191207
192- abstract H2StreamHandler createLocallyInitiatedStream (
193- ExecutableCommand command ,
194- H2StreamChannel channel ,
195- HttpProcessor httpProcessor ,
196- BasicHttpConnectionMetrics connMetrics ) throws IOException ;
208+ abstract H2StreamHandler outgoingPushPromise (H2StreamChannel channel ,
209+ AsyncPushProducer pushProducer ) throws IOException ;
197210
198211 abstract boolean allowGracefulAbort (H2Stream stream );
199212
@@ -495,20 +508,20 @@ public final void onOutput() throws HttpException, IOException {
495508 executeShutdown ((ShutdownCommand ) command );
496509 } else if (command instanceof PingCommand ) {
497510 executePing ((PingCommand ) command );
498- } else if (command instanceof ExecutableCommand ) {
499- executeRequest ((ExecutableCommand ) command );
500- if (! outputQueue . isEmpty ()) {
501- return ;
502- }
511+ } else if (command instanceof RequestExecutionCommand ) {
512+ executeRequest ((RequestExecutionCommand ) command );
513+ }
514+ if (! outputQueue . isEmpty ()) {
515+ return ;
503516 }
504517 }
505518 }
506519 if (connState .compareTo (ConnectionHandshake .GRACEFUL_SHUTDOWN ) == 0 ) {
507520 int liveStreams = 0 ;
508521 for (final Iterator <H2Stream > it = streams .iterator (); it .hasNext (); ) {
509522 final H2Stream stream = it .next ();
510- if (stream .isLocalClosed () && stream . isRemoteClosed ()) {
511- streams .release (stream );
523+ if (stream .isClosedPastLingerDeadline ()) {
524+ streams .dropStreamId (stream . getId () );
512525 it .remove ();
513526 } else {
514527 if (streams .isSameSide (stream .getId ()) || stream .getId () <= streams .getLastRemoteId ()) {
@@ -555,10 +568,10 @@ public final void onTimeout(final Timeout timeout) throws HttpException, IOExcep
555568 final RawFrame goAway ;
556569 if (localSettingState != SettingsHandshake .ACKED ) {
557570 goAway = frameFactory .createGoAway (streams .getLastRemoteId (), H2Error .SETTINGS_TIMEOUT ,
558- "Setting timeout (" + timeout + ")" );
571+ "Setting timeout (" + timeout + ")" );
559572 } else {
560573 goAway = frameFactory .createGoAway (streams .getLastRemoteId (), H2Error .NO_ERROR ,
561- "Timeout due to inactivity (" + timeout + ")" );
574+ "Timeout due to inactivity (" + timeout + ")" );
562575 }
563576 commitFrame (goAway );
564577 for (final Iterator <H2Stream > it = streams .iterator (); it .hasNext (); ) {
@@ -601,14 +614,13 @@ private void executePing(final PingCommand pingCommand) throws IOException {
601614 commitFrame (ping );
602615 }
603616
604- private void executeRequest (final ExecutableCommand executableCommand ) throws IOException , HttpException {
617+ private void executeRequest (final RequestExecutionCommand requestExecutionCommand ) throws IOException , HttpException {
605618 final int streamId = streams .generateStreamId ();
606- final H2StreamChannel channel = createChannel (streamId , true );
607- final H2StreamHandler streamHandler = createLocallyInitiatedStream (
608- executableCommand , channel , httpProcessor , connMetrics );
609-
610- final H2Stream stream = new H2Stream (channel , streamHandler );
611- streams .addLocallyInitiated (stream );
619+ final H2StreamChannel channel = createChannel (streamId );
620+ final H2Stream stream = streams .createActive (channel , outgoingRequest (channel ,
621+ requestExecutionCommand .getExchangeHandler (),
622+ requestExecutionCommand .getPushHandlerFactory (),
623+ requestExecutionCommand .getContext ()));
612624
613625 if (streamListener != null ) {
614626 final int initInputWindow = stream .getInputWindow ().get ();
@@ -620,23 +632,12 @@ private void executeRequest(final ExecutableCommand executableCommand) throws IO
620632 if (stream .isOutputReady ()) {
621633 stream .produceOutput ();
622634 }
623- final CancellableDependency cancellableDependency = executableCommand .getCancellableDependency ();
635+ final CancellableDependency cancellableDependency = requestExecutionCommand .getCancellableDependency ();
624636 if (cancellableDependency != null ) {
625637 cancellableDependency .setDependency (stream ::abort );
626638 }
627639 }
628640
629- public void executePush (final int promisedStreamId , final AsyncPushProducer pushProducer ) {
630- final H2StreamChannel channel = createChannel (promisedStreamId , true );
631- final HttpCoreContext context = HttpCoreContext .create ();
632- context .setSSLSession (getSSLSession ());
633- context .setEndpointDetails (getEndpointDetails ());
634- final H2StreamHandler streamHandler = new ServerPushH2StreamHandler (
635- channel , httpProcessor , connMetrics , pushProducer , context );
636- final H2Stream stream = new H2Stream (channel , streamHandler );
637- streams .addLocallyInitiated (stream );
638- }
639-
640641 public final void onException (final Exception cause ) {
641642 try {
642643 for (;;) {
@@ -702,8 +703,8 @@ private void consumeFrame(final RawFrame frame) throws HttpException, IOExceptio
702703 stream .localReset (ex , ex .getCause () != null ? H2Error .INTERNAL_ERROR : H2Error .CANCEL );
703704 }
704705
705- if (stream .isTerminated ()) {
706- streams . release ( stream );
706+ if (stream .isClosed ()) {
707+ stream . releaseResources ( );
707708 requestSessionOutput ();
708709 }
709710 }
@@ -722,26 +723,20 @@ private void consumeFrame(final RawFrame frame) throws HttpException, IOExceptio
722723 throw new H2ConnectionException (H2Error .PROTOCOL_ERROR , "GOAWAY received" );
723724 }
724725
725- final H2StreamChannel channel = createChannel (streamId , false );
726- final H2StreamHandler streamHandler ;
726+ final H2StreamChannel channel = createChannel (streamId );
727727 if (connState .compareTo (ConnectionHandshake .ACTIVE ) <= 0 ) {
728- streamHandler = createRemotelyInitiatedStream (channel , httpProcessor , connMetrics , null );
728+ stream = streams . createActive (channel , incomingRequest ( channel ) );
729729 } else {
730- streamHandler = NoopH2StreamHandler .INSTANCE ;
731- channel .markLocalClosed ();
732- }
733-
734- stream = new H2Stream (channel , streamHandler );
735- if (stream .isOutputReady ()) {
736- stream .produceOutput ();
730+ channel .localReset (H2Error .REFUSED_STREAM );
731+ stream = streams .createActive (channel , NoopH2StreamHandler .INSTANCE );
737732 }
738- streams .addRemotelyInitiated (stream );
739733 } else if (stream .isLocalClosed () && stream .isRemoteClosed ()) {
740734 throw new H2ConnectionException (H2Error .STREAM_CLOSED , "Stream closed" );
735+ } else if (stream .isReserved ()) {
736+ stream .activate ();
741737 }
742738 try {
743739 consumeHeaderFrame (frame , stream );
744-
745740 if (stream .isOutputReady ()) {
746741 stream .produceOutput ();
747742 }
@@ -753,8 +748,8 @@ private void consumeFrame(final RawFrame frame) throws HttpException, IOExceptio
753748 stream .handle (ex );
754749 }
755750
756- if (stream .isTerminated ()) {
757- streams . release ( stream );
751+ if (stream .isClosed ()) {
752+ stream . releaseResources ( );
758753 requestSessionOutput ();
759754 }
760755 }
@@ -779,8 +774,8 @@ private void consumeFrame(final RawFrame frame) throws HttpException, IOExceptio
779774 stream .localReset (ex , ex .getCause () != null ? H2Error .INTERNAL_ERROR : H2Error .CANCEL );
780775 }
781776
782- if (stream .isTerminated ()) {
783- streams . release ( stream );
777+ if (stream .isClosed ()) {
778+ stream . releaseResources ( );
784779 requestSessionOutput ();
785780 }
786781 }
@@ -829,7 +824,6 @@ private void consumeFrame(final RawFrame frame) throws HttpException, IOExceptio
829824 requestSessionOutput ();
830825 } else {
831826 stream .fail (new H2StreamResetException (errorCode , "Stream reset (" + errorCode + ")" ));
832- streams .release (stream );
833827 requestSessionOutput ();
834828 }
835829 }
@@ -900,7 +894,7 @@ private void consumeFrame(final RawFrame frame) throws HttpException, IOExceptio
900894 throw new H2ConnectionException (H2Error .PROTOCOL_ERROR , "Push is disabled" );
901895 }
902896
903- final H2Stream stream = streams .lookup (streamId );
897+ final H2Stream stream = streams .lookupValid (streamId );
904898 if (stream .isRemoteClosed ()) {
905899 stream .localReset (new H2StreamResetException (H2Error .STREAM_CLOSED , "Stream closed" ));
906900 break ;
@@ -918,19 +912,14 @@ private void consumeFrame(final RawFrame frame) throws HttpException, IOExceptio
918912 throw new H2ConnectionException (H2Error .PROTOCOL_ERROR , "Stream already open: " + promisedStreamId );
919913 }
920914
921- final H2StreamChannel channel = createChannel (promisedStreamId , false );
922- final H2StreamHandler streamHandler ;
915+ final H2StreamChannel channel = createChannel (promisedStreamId );
916+ final H2Stream promisedStream ;
923917 if (connState .compareTo (ConnectionHandshake .ACTIVE ) <= 0 ) {
924- streamHandler = createRemotelyInitiatedStream (channel , httpProcessor , connMetrics ,
925- stream .getPushHandlerFactory ());
918+ promisedStream = streams .createReserved (channel , incomingPushPromise (channel , stream .getPushHandlerFactory ()));
926919 } else {
927- streamHandler = NoopH2StreamHandler . INSTANCE ;
928- channel . markLocalClosed ( );
920+ channel . localReset ( H2Error . REFUSED_STREAM ) ;
921+ promisedStream = streams . createActive ( channel , NoopH2StreamHandler . INSTANCE );
929922 }
930-
931- final H2Stream promisedStream = new H2Stream (channel , streamHandler );
932- streams .addRemotelyInitiated (promisedStream );
933-
934923 try {
935924 consumePushPromiseFrame (frame , payload , promisedStream );
936925 } catch (final H2StreamResetException ex ) {
@@ -1133,9 +1122,10 @@ private void produceOutput() throws HttpException, IOException {
11331122 if (!stream .isLocalClosed () && stream .getOutputWindow ().get () > 0 ) {
11341123 stream .produceOutput ();
11351124 }
1136- if (stream .isTerminated ()) {
1125+ if (stream .isClosedPastLingerDeadline ()) {
1126+ streams .dropStreamId (stream .getId ());
1127+ stream .releaseResources ();
11371128 it .remove ();
1138- streams .release (stream );
11391129 requestSessionOutput ();
11401130 }
11411131 if (!outputQueue .isEmpty ()) {
@@ -1303,12 +1293,12 @@ ByteBuffer getContent() {
13031293
13041294 }
13051295
1306- H2StreamChannel createChannel (final int streamId , final boolean idle ) {
1307- return new H2StreamChannelImpl (streamId , idle , initInputWinSize , initOutputWinSize );
1296+ H2StreamChannel createChannel (final int streamId ) {
1297+ return new H2StreamChannelImpl (streamId , initInputWinSize , initOutputWinSize );
13081298 }
13091299
1310- void addStream (final H2Stream stream ) throws H2ConnectionException {
1311- streams .addLocallyInitiated ( stream );
1300+ H2Stream createStream (final H2StreamChannel channel , final H2StreamHandler streamHandler ) throws H2ConnectionException {
1301+ return streams .createActive ( channel , streamHandler );
13121302 }
13131303
13141304 class H2StreamChannelImpl implements H2StreamChannel {
@@ -1317,14 +1307,11 @@ class H2StreamChannelImpl implements H2StreamChannel {
13171307 private final AtomicInteger inputWindow ;
13181308 private final AtomicInteger outputWindow ;
13191309
1320- private volatile boolean idle ;
13211310 private volatile boolean localClosed ;
1322-
13231311 private volatile long localResetTime ;
13241312
1325- H2StreamChannelImpl (final int id , final boolean idle , final int initialInputWindowSize , final int initialOutputWindowSize ) {
1313+ H2StreamChannelImpl (final int id , final int initialInputWindowSize , final int initialOutputWindowSize ) {
13261314 this .id = id ;
1327- this .idle = idle ;
13281315 this .inputWindow = new AtomicInteger (initialInputWindowSize );
13291316 this .outputWindow = new AtomicInteger (initialOutputWindowSize );
13301317 }
@@ -1358,7 +1345,6 @@ public void submit(final List<Header> headers, final boolean endStream) throws I
13581345 throw new H2ConnectionException (H2Error .INTERNAL_ERROR , "Message headers are missing" );
13591346 }
13601347 ensureNotClosed ();
1361- idle = false ;
13621348 commitHeaders (id , headers , endStream );
13631349 if (endStream ) {
13641350 localClosed = true ;
@@ -1371,15 +1357,14 @@ public void submit(final List<Header> headers, final boolean endStream) throws I
13711357 @ Override
13721358 public void push (final List <Header > headers , final AsyncPushProducer pushProducer ) throws HttpException , IOException {
13731359 acceptPushRequest ();
1374-
13751360 ioSession .getLock ().lock ();
13761361 try {
13771362 ensureNotClosed ();
1378-
13791363 final int promisedStreamId = streams .generateStreamId ();
1380- executePush (promisedStreamId , pushProducer );
1364+ final H2StreamChannel channel = createChannel (promisedStreamId );
1365+ streams .createReserved (channel , outgoingPushPromise (channel , pushProducer ));
1366+
13811367 commitPushPromise (id , promisedStreamId , headers );
1382- idle = false ;
13831368 } finally {
13841369 ioSession .getLock ().unlock ();
13851370 }
@@ -1450,12 +1435,9 @@ public boolean localReset(final int code) throws IOException {
14501435 localClosed = true ;
14511436 localResetTime = System .currentTimeMillis ();
14521437
1453- if (!idle ) {
1454- final RawFrame resetStream = frameFactory .createResetStream (id , code );
1455- commitFrameInternal (resetStream );
1456- return true ;
1457- }
1458- return false ;
1438+ final RawFrame resetStream = frameFactory .createResetStream (id , code );
1439+ commitFrameInternal (resetStream );
1440+ return true ;
14591441 } finally {
14601442 ioSession .getLock ().unlock ();
14611443 }
@@ -1484,8 +1466,7 @@ public String toString() {
14841466 .append (", inputWindow=" ).append (inputWindow )
14851467 .append (", outputWindow=" ).append (outputWindow )
14861468 .append (", localClosed=" ).append (localClosed )
1487- .append (", idle=" ).append (idle );
1488- buf .append ("]" );
1469+ .append ("]" );
14891470 return buf .toString ();
14901471 }
14911472
0 commit comments