View Javadoc
1   /*
2    * Copyright 2019 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.handler.codec.http2;
17  
18  import io.netty.buffer.ByteBufAllocator;
19  import io.netty.channel.Channel;
20  import io.netty.channel.ChannelConfig;
21  import io.netty.channel.ChannelFuture;
22  import io.netty.channel.ChannelFutureListener;
23  import io.netty.channel.ChannelHandler;
24  import io.netty.channel.ChannelHandlerContext;
25  import io.netty.channel.ChannelId;
26  import io.netty.channel.ChannelMetadata;
27  import io.netty.channel.ChannelOption;
28  import io.netty.channel.ChannelOutboundBuffer;
29  import io.netty.channel.ChannelPipeline;
30  import io.netty.channel.ChannelProgressivePromise;
31  import io.netty.channel.ChannelPromise;
32  import io.netty.channel.DefaultChannelConfig;
33  import io.netty.channel.DefaultChannelPipeline;
34  import io.netty.channel.EventLoop;
35  import io.netty.channel.MessageSizeEstimator;
36  import io.netty.channel.RecvByteBufAllocator;
37  import io.netty.channel.VoidChannelPromise;
38  import io.netty.channel.WriteBufferWaterMark;
39  import io.netty.channel.socket.ChannelInputShutdownReadComplete;
40  import io.netty.channel.socket.ChannelOutputShutdownEvent;
41  import io.netty.handler.codec.http2.Http2FrameCodec.DefaultHttp2FrameStream;
42  import io.netty.handler.ssl.SslCloseCompletionEvent;
43  import io.netty.util.DefaultAttributeMap;
44  import io.netty.util.ReferenceCountUtil;
45  import io.netty.util.concurrent.Future;
46  import io.netty.util.internal.ObjectUtil;
47  import io.netty.util.internal.StringUtil;
48  import io.netty.util.internal.logging.InternalLogger;
49  import io.netty.util.internal.logging.InternalLoggerFactory;
50  
51  import java.io.IOException;
52  import java.net.SocketAddress;
53  import java.nio.channels.ClosedChannelException;
54  import java.util.ArrayDeque;
55  import java.util.Map;
56  import java.util.Queue;
57  import java.util.concurrent.RejectedExecutionException;
58  import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
59  import java.util.concurrent.atomic.AtomicLongFieldUpdater;
60  
61  import static io.netty.handler.codec.http2.Http2CodecUtil.isStreamIdValid;
62  import static io.netty.util.internal.ObjectUtil.checkNotNull;
63  import static java.lang.Math.min;
64  
65  abstract class AbstractHttp2StreamChannel extends DefaultAttributeMap implements Http2StreamChannel {
66  
67      static final Http2FrameStreamVisitor WRITABLE_VISITOR = new Http2FrameStreamVisitor() {
68          @Override
69          public boolean visit(Http2FrameStream stream) {
70              final AbstractHttp2StreamChannel childChannel = (AbstractHttp2StreamChannel)
71                      ((DefaultHttp2FrameStream) stream).attachment;
72              childChannel.trySetWritable();
73              return true;
74          }
75      };
76  
77      static final Http2FrameStreamVisitor CHANNEL_INPUT_SHUTDOWN_READ_COMPLETE_VISITOR =
78              new UserEventStreamVisitor(ChannelInputShutdownReadComplete.INSTANCE);
79  
80      static final Http2FrameStreamVisitor CHANNEL_OUTPUT_SHUTDOWN_EVENT_VISITOR =
81              new UserEventStreamVisitor(ChannelOutputShutdownEvent.INSTANCE);
82  
83      static final Http2FrameStreamVisitor SSL_CLOSE_COMPLETION_EVENT_VISITOR =
84              new UserEventStreamVisitor(SslCloseCompletionEvent.SUCCESS);
85  
86      private static final InternalLogger logger = InternalLoggerFactory.getInstance(AbstractHttp2StreamChannel.class);
87  
88      private static final ChannelMetadata METADATA = new ChannelMetadata(false, 16);
89  
90      /**
91       * Number of bytes to consider non-payload messages. 9 is arbitrary, but also the minimum size of an HTTP/2 frame.
92       * Primarily is non-zero.
93       */
94      private static final int MIN_HTTP2_FRAME_SIZE = 9;
95  
96      /**
97       * {@link Http2FrameStreamVisitor} that fires the user event for every active stream pipeline.
98       */
99      private static final class UserEventStreamVisitor implements Http2FrameStreamVisitor {
100 
101         private final Object event;
102 
103         UserEventStreamVisitor(Object event) {
104             this.event = checkNotNull(event, "event");
105         }
106 
107         @Override
108         public boolean visit(Http2FrameStream stream) {
109             final AbstractHttp2StreamChannel childChannel = (AbstractHttp2StreamChannel)
110                     ((DefaultHttp2FrameStream) stream).attachment;
111             childChannel.pipeline().fireUserEventTriggered(event);
112             return true;
113         }
114     }
115 
116     /**
117      * Returns the flow-control size for DATA frames, and {@value MIN_HTTP2_FRAME_SIZE} for all other frames.
118      */
119     private static final class FlowControlledFrameSizeEstimator implements MessageSizeEstimator {
120 
121         static final FlowControlledFrameSizeEstimator INSTANCE = new FlowControlledFrameSizeEstimator();
122 
123         private static final Handle HANDLE_INSTANCE = new Handle() {
124             @Override
125             public int size(Object msg) {
126                 return msg instanceof Http2DataFrame ?
127                         // Guard against overflow.
128                         (int) min(Integer.MAX_VALUE, ((Http2DataFrame) msg).initialFlowControlledBytes() +
129                                 (long) MIN_HTTP2_FRAME_SIZE) : MIN_HTTP2_FRAME_SIZE;
130             }
131         };
132 
133         @Override
134         public Handle newHandle() {
135             return HANDLE_INSTANCE;
136         }
137     }
138 
139     private static final AtomicLongFieldUpdater<AbstractHttp2StreamChannel> TOTAL_PENDING_SIZE_UPDATER =
140             AtomicLongFieldUpdater.newUpdater(AbstractHttp2StreamChannel.class, "totalPendingSize");
141 
142     private static final AtomicIntegerFieldUpdater<AbstractHttp2StreamChannel> UNWRITABLE_UPDATER =
143             AtomicIntegerFieldUpdater.newUpdater(AbstractHttp2StreamChannel.class, "unwritable");
144 
145     private static void windowUpdateFrameWriteComplete(ChannelFuture future, Channel streamChannel) {
146         Throwable cause = future.cause();
147         if (cause != null) {
148             Throwable unwrappedCause;
149             // Unwrap if needed
150             if (cause instanceof Http2FrameStreamException && (unwrappedCause = cause.getCause()) != null) {
151                 cause = unwrappedCause;
152             }
153 
154             // Notify the child-channel and close it.
155             streamChannel.pipeline().fireExceptionCaught(cause);
156             streamChannel.unsafe().close(streamChannel.unsafe().voidPromise());
157         }
158     }
159 
160     private final ChannelFutureListener windowUpdateFrameWriteListener = future ->
161             windowUpdateFrameWriteComplete(future, AbstractHttp2StreamChannel.this);
162 
163     /**
164      * The current status of the read-processing for a {@link AbstractHttp2StreamChannel}.
165      */
166     private enum ReadStatus {
167         /**
168          * No read in progress and no read was requested (yet)
169          */
170         IDLE,
171 
172         /**
173          * Reading in progress
174          */
175         IN_PROGRESS,
176 
177         /**
178          * A read operation was requested.
179          */
180         REQUESTED
181     }
182 
183     private final Http2StreamChannelConfig config = new Http2StreamChannelConfig(this);
184     private final Http2ChannelUnsafe unsafe = new Http2ChannelUnsafe();
185     private final Http2StreamChannelId channelId;
186     private final ChannelPipeline pipeline;
187     private final DefaultHttp2FrameStream stream;
188     private final ChannelPromise closePromise;
189 
190     private volatile boolean registered;
191 
192     private volatile long totalPendingSize;
193     private volatile int unwritable;
194 
195     // Cached to reduce GC
196     private Runnable fireChannelWritabilityChangedTask;
197 
198     private boolean outboundClosed;
199     private int flowControlledBytes;
200 
201     /**
202      * This variable represents if a read is in progress for the current channel or was requested.
203      * Note that depending upon the {@link RecvByteBufAllocator} behavior a read may extend beyond the
204      * {@link Http2ChannelUnsafe#beginRead()} method scope. The {@link Http2ChannelUnsafe#beginRead()} loop may
205      * drain all pending data, and then if the parent channel is reading this channel may still accept frames.
206      */
207     private ReadStatus readStatus = ReadStatus.IDLE;
208 
209     private Queue<Object> inboundBuffer;
210 
211     /** {@code true} after the first HEADERS frame has been written **/
212     private boolean firstFrameWritten;
213     private boolean readCompletePending;
214 
215     AbstractHttp2StreamChannel(DefaultHttp2FrameStream stream, int id, ChannelHandler inboundHandler) {
216         this.stream = stream;
217         stream.attachment = this;
218         pipeline = new DefaultChannelPipeline(this) {
219             @Override
220             protected void incrementPendingOutboundBytes(long size) {
221                 AbstractHttp2StreamChannel.this.incrementPendingOutboundBytes(size, true);
222             }
223 
224             @Override
225             protected void decrementPendingOutboundBytes(long size) {
226                 AbstractHttp2StreamChannel.this.decrementPendingOutboundBytes(size, true);
227             }
228 
229             @Override
230             protected void onUnhandledInboundException(Throwable cause) {
231                 // Ensure we use the correct Http2Error to close the channel.
232                 if (cause instanceof Http2FrameStreamException) {
233                     closeWithError(((Http2FrameStreamException) cause).error());
234                     return;
235                 } else {
236                     Http2Exception exception = Http2CodecUtil.getEmbeddedHttp2Exception(cause);
237                     if (exception != null) {
238                         closeWithError(exception.error());
239                         return;
240                     }
241                 }
242                 super.onUnhandledInboundException(cause);
243             }
244         };
245 
246         closePromise = pipeline.newPromise();
247         channelId = new Http2StreamChannelId(parent().id(), id);
248 
249         if (inboundHandler != null) {
250             // Add the handler to the pipeline now that we are registered.
251             pipeline.addLast(inboundHandler);
252         }
253     }
254 
255     private void incrementPendingOutboundBytes(long size, boolean invokeLater) {
256         if (size == 0) {
257             return;
258         }
259 
260         long newWriteBufferSize = TOTAL_PENDING_SIZE_UPDATER.addAndGet(this, size);
261         if (newWriteBufferSize > config().getWriteBufferHighWaterMark()) {
262             setUnwritable(invokeLater);
263         }
264     }
265 
266     private void decrementPendingOutboundBytes(long size, boolean invokeLater) {
267         if (size == 0) {
268             return;
269         }
270 
271         long newWriteBufferSize = TOTAL_PENDING_SIZE_UPDATER.addAndGet(this, -size);
272         // Once the totalPendingSize dropped below the low water-mark we can mark the child channel
273         // as writable again. Before doing so we also need to ensure the parent channel is writable to
274         // prevent excessive buffering in the parent outbound buffer. If the parent is not writable
275         // we will mark the child channel as writable once the parent becomes writable by calling
276         // trySetWritable() later.
277         if (newWriteBufferSize < config().getWriteBufferLowWaterMark() && parent().isWritable()) {
278             setWritable(invokeLater);
279         }
280     }
281 
282     final void trySetWritable() {
283         // The parent is writable again but the child channel itself may still not be writable.
284         // Lets try to set the child channel writable to match the state of the parent channel
285         // if (and only if) the totalPendingSize is smaller then the low water-mark.
286         // If this is not the case we will try again later once we drop under it.
287         if (totalPendingSize < config().getWriteBufferLowWaterMark()) {
288             setWritable(false);
289         }
290     }
291 
292     private void setWritable(boolean invokeLater) {
293         for (;;) {
294             final int oldValue = unwritable;
295             final int newValue = oldValue & ~1;
296             if (UNWRITABLE_UPDATER.compareAndSet(this, oldValue, newValue)) {
297                 if (oldValue != 0 && newValue == 0) {
298                     fireChannelWritabilityChanged(invokeLater);
299                 }
300                 break;
301             }
302         }
303     }
304 
305     private void setUnwritable(boolean invokeLater) {
306         for (;;) {
307             final int oldValue = unwritable;
308             final int newValue = oldValue | 1;
309             if (UNWRITABLE_UPDATER.compareAndSet(this, oldValue, newValue)) {
310                 if (oldValue == 0) {
311                     fireChannelWritabilityChanged(invokeLater);
312                 }
313                 break;
314             }
315         }
316     }
317 
318     private void fireChannelWritabilityChanged(boolean invokeLater) {
319         final ChannelPipeline pipeline = pipeline();
320         if (invokeLater) {
321             Runnable task = fireChannelWritabilityChangedTask;
322             if (task == null) {
323                 fireChannelWritabilityChangedTask = task = new Runnable() {
324                     @Override
325                     public void run() {
326                         pipeline.fireChannelWritabilityChanged();
327                     }
328                 };
329             }
330             eventLoop().execute(task);
331         } else {
332             pipeline.fireChannelWritabilityChanged();
333         }
334     }
335     @Override
336     public Http2FrameStream stream() {
337         return stream;
338     }
339 
340     void closeOutbound() {
341         outboundClosed = true;
342     }
343 
344     void streamClosed() {
345         unsafe.readEOS();
346         // Attempt to drain any queued data from the queue and deliver it to the application before closing this
347         // channel.
348         unsafe.doBeginRead();
349     }
350 
351     @Override
352     public ChannelMetadata metadata() {
353         return METADATA;
354     }
355 
356     @Override
357     public ChannelConfig config() {
358         return config;
359     }
360 
361     @Override
362     public boolean isOpen() {
363         return !closePromise.isDone();
364     }
365 
366     @Override
367     public boolean isActive() {
368         return isOpen();
369     }
370 
371     @Override
372     public boolean isWritable() {
373         return unwritable == 0;
374     }
375 
376     @Override
377     public ChannelId id() {
378         return channelId;
379     }
380 
381     @Override
382     public EventLoop eventLoop() {
383         return parent().eventLoop();
384     }
385 
386     @Override
387     public Channel parent() {
388         return parentContext().channel();
389     }
390 
391     @Override
392     public boolean isRegistered() {
393         return registered;
394     }
395 
396     @Override
397     public SocketAddress localAddress() {
398         return parent().localAddress();
399     }
400 
401     @Override
402     public SocketAddress remoteAddress() {
403         return parent().remoteAddress();
404     }
405 
406     @Override
407     public ChannelFuture closeFuture() {
408         return closePromise;
409     }
410 
411     @Override
412     public long bytesBeforeUnwritable() {
413         // +1 because writability doesn't change until the threshold is crossed (not equal to).
414         long bytes = config().getWriteBufferHighWaterMark() - totalPendingSize + 1;
415         // If bytes is negative we know we are not writable, but if bytes is non-negative we have to check
416         // writability. Note that totalPendingSize and isWritable() use different volatile variables that are not
417         // synchronized together. totalPendingSize will be updated before isWritable().
418         return bytes > 0 && isWritable() ? bytes : 0;
419     }
420 
421     @Override
422     public long bytesBeforeWritable() {
423         // +1 because writability doesn't change until the threshold is crossed (not equal to).
424         long bytes = totalPendingSize - config().getWriteBufferLowWaterMark() + 1;
425         // If bytes is negative we know we are writable, but if bytes is non-negative we have to check writability.
426         // Note that totalPendingSize and isWritable() use different volatile variables that are not synchronized
427         // together. totalPendingSize will be updated before isWritable().
428         return bytes <= 0 || isWritable() ? 0 : bytes;
429     }
430 
431     @Override
432     public Unsafe unsafe() {
433         return unsafe;
434     }
435 
436     @Override
437     public ChannelPipeline pipeline() {
438         return pipeline;
439     }
440 
441     @Override
442     public ByteBufAllocator alloc() {
443         return config().getAllocator();
444     }
445 
446     @Override
447     public Channel read() {
448         pipeline().read();
449         return this;
450     }
451 
452     @Override
453     public Channel flush() {
454         pipeline().flush();
455         return this;
456     }
457 
458     @Override
459     public ChannelFuture bind(SocketAddress localAddress) {
460         return pipeline().bind(localAddress);
461     }
462 
463     @Override
464     public ChannelFuture connect(SocketAddress remoteAddress) {
465         return pipeline().connect(remoteAddress);
466     }
467 
468     @Override
469     public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) {
470         return pipeline().connect(remoteAddress, localAddress);
471     }
472 
473     @Override
474     public ChannelFuture disconnect() {
475         return pipeline().disconnect();
476     }
477 
478     @Override
479     public ChannelFuture close() {
480         return pipeline().close();
481     }
482 
483     @Override
484     public ChannelFuture deregister() {
485         return pipeline().deregister();
486     }
487 
488     @Override
489     public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
490         return pipeline().bind(localAddress, promise);
491     }
492 
493     @Override
494     public ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise) {
495         return pipeline().connect(remoteAddress, promise);
496     }
497 
498     @Override
499     public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {
500         return pipeline().connect(remoteAddress, localAddress, promise);
501     }
502 
503     @Override
504     public ChannelFuture disconnect(ChannelPromise promise) {
505         return pipeline().disconnect(promise);
506     }
507 
508     @Override
509     public ChannelFuture close(ChannelPromise promise) {
510         return pipeline().close(promise);
511     }
512 
513     @Override
514     public ChannelFuture deregister(ChannelPromise promise) {
515         return pipeline().deregister(promise);
516     }
517 
518     @Override
519     public ChannelFuture write(Object msg) {
520         return pipeline().write(msg);
521     }
522 
523     @Override
524     public ChannelFuture write(Object msg, ChannelPromise promise) {
525         return pipeline().write(msg, promise);
526     }
527 
528     @Override
529     public ChannelFuture writeAndFlush(Object msg, ChannelPromise promise) {
530         return pipeline().writeAndFlush(msg, promise);
531     }
532 
533     @Override
534     public ChannelFuture writeAndFlush(Object msg) {
535         return pipeline().writeAndFlush(msg);
536     }
537 
538     @Override
539     public ChannelPromise newPromise() {
540         return pipeline().newPromise();
541     }
542 
543     @Override
544     public ChannelProgressivePromise newProgressivePromise() {
545         return pipeline().newProgressivePromise();
546     }
547 
548     @Override
549     public ChannelFuture newSucceededFuture() {
550         return pipeline().newSucceededFuture();
551     }
552 
553     @Override
554     public ChannelFuture newFailedFuture(Throwable cause) {
555         return pipeline().newFailedFuture(cause);
556     }
557 
558     @Override
559     public ChannelPromise voidPromise() {
560         return pipeline().voidPromise();
561     }
562 
563     @Override
564     public int hashCode() {
565         return id().hashCode();
566     }
567 
568     @Override
569     public boolean equals(Object o) {
570         return this == o;
571     }
572 
573     @Override
574     public int compareTo(Channel o) {
575         if (this == o) {
576             return 0;
577         }
578 
579         return id().compareTo(o.id());
580     }
581 
582     @Override
583     public String toString() {
584         return parent().toString() + '/' + channelId.getSequenceId() + " (H2 - " + stream + ')';
585     }
586 
587     void fireChildExceptionCaught(Throwable cause) {
588         pipeline().fireExceptionCaught(cause);
589     }
590 
591     void fireChildUserEventTriggered(Object evt) {
592         pipeline().fireUserEventTriggered(evt);
593     }
594 
595     /**
596      * Receive a read message. This does not notify handlers unless a read is in progress on the
597      * channel.
598      */
599     void fireChildRead(Http2Frame frame) {
600         assert eventLoop().inEventLoop();
601         if (!isActive()) {
602             ReferenceCountUtil.release(frame);
603         } else if (readStatus != ReadStatus.IDLE && isInboundBufferEmpty()) {
604             // A read is in progress or has been requested and nothing is queued, so dispatch directly. If frames are
605             // still queued (e.g. this frame was delivered re-entrantly while doBeginRead() is running pipeline
606             // callbacks after it stopped early) we must queue behind them below to preserve ordering; the read loop
607             // that is still on the stack will drain them.
608             final RecvByteBufAllocator.Handle allocHandle = unsafe.recvBufAllocHandle();
609 
610             unsafe.doRead0(frame, allocHandle);
611             // We currently don't need to check for readEOS because the parent channel and child channel are limited
612             // to the same EventLoop thread. There are a limited number of frame types that may come after EOS is
613             // read (unknown, reset) and the trade off is less conditionals for the hot path (headers/data) at the
614             // cost of additional readComplete notifications on the rare path.
615             if (allocHandle.continueReading()) {
616                 maybeAddChannelToReadCompletePendingQueue();
617             } else {
618                 unsafe.notifyReadComplete(allocHandle, true, false);
619             }
620         } else {
621             if (inboundBuffer == null) {
622                 inboundBuffer = new ArrayDeque<Object>(4);
623             }
624             inboundBuffer.add(frame);
625         }
626     }
627 
628     private boolean isInboundBufferEmpty() {
629         return inboundBuffer == null || inboundBuffer.isEmpty();
630     }
631 
632     void fireChildReadComplete() {
633         assert eventLoop().inEventLoop();
634         assert readStatus != ReadStatus.IDLE || !readCompletePending;
635         unsafe.notifyReadComplete(unsafe.recvBufAllocHandle(), false, false);
636     }
637 
638     final void closeWithError(Http2Error error) {
639         assert eventLoop().inEventLoop();
640         unsafe.close(unsafe.voidPromise(), error);
641     }
642 
643     private final class Http2ChannelUnsafe implements Unsafe {
644         private final VoidChannelPromise unsafeVoidPromise =
645                 new VoidChannelPromise(AbstractHttp2StreamChannel.this, false);
646         @SuppressWarnings("deprecation")
647         private RecvByteBufAllocator.Handle recvHandle;
648         private boolean writeDoneAndNoFlush;
649         private boolean closeInitiated;
650         private boolean readEOS;
651 
652         private boolean receivedEndOfStream;
653         private boolean sentEndOfStream;
654 
655         @Override
656         public void connect(final SocketAddress remoteAddress,
657                             SocketAddress localAddress, final ChannelPromise promise) {
658             if (!promise.setUncancellable()) {
659                 return;
660             }
661             promise.setFailure(new UnsupportedOperationException());
662         }
663 
664         @Override
665         public RecvByteBufAllocator.Handle recvBufAllocHandle() {
666             if (recvHandle == null) {
667                 recvHandle = config().getRecvByteBufAllocator().newHandle();
668                 recvHandle.reset(config());
669             }
670             return recvHandle;
671         }
672 
673         @Override
674         public SocketAddress localAddress() {
675             return parent().unsafe().localAddress();
676         }
677 
678         @Override
679         public SocketAddress remoteAddress() {
680             return parent().unsafe().remoteAddress();
681         }
682 
683         @Override
684         public void register(EventLoop eventLoop, ChannelPromise promise) {
685             if (!promise.setUncancellable()) {
686                 return;
687             }
688             if (registered) {
689                 promise.setFailure(new UnsupportedOperationException("Re-register is not supported"));
690                 return;
691             }
692 
693             registered = true;
694 
695             promise.setSuccess();
696 
697             pipeline().fireChannelRegistered();
698             if (isActive()) {
699                 pipeline().fireChannelActive();
700             }
701         }
702 
703         @Override
704         public void bind(SocketAddress localAddress, ChannelPromise promise) {
705             if (!promise.setUncancellable()) {
706                 return;
707             }
708             promise.setFailure(new UnsupportedOperationException());
709         }
710 
711         @Override
712         public void disconnect(ChannelPromise promise) {
713             close(promise);
714         }
715 
716         @Override
717         public void close(final ChannelPromise promise) {
718             close(promise, null);
719         }
720 
721         private void close(final ChannelPromise promise, Http2Error error) {
722             if (!promise.setUncancellable()) {
723                 return;
724             }
725             if (closeInitiated) {
726                 if (closePromise.isDone()) {
727                     // Closed already.
728                     promise.setSuccess();
729                 } else if (!(promise instanceof VoidChannelPromise)) { // Only needed if no VoidChannelPromise.
730                     // This means close() was called before so we just register a listener and return
731                     closePromise.addListener(future -> promise.setSuccess());
732                 }
733                 return;
734             }
735             closeInitiated = true;
736             // Just set to false as removing from an underlying queue would even be more expensive.
737             readCompletePending = false;
738 
739             final boolean wasActive = isActive();
740 
741             // There is no need to update the local window as once the stream is closed all the pending bytes will be
742             // given back to the connection window by the controller itself.
743 
744             // Only ever send a reset frame if the connection is still alive and if the stream was created before
745             // as otherwise we may send a RST on a stream in an invalid state and cause a connection error.
746             if (parent().isActive() && isStreamIdValid(stream.id())) {
747                 // If error is null we know that the close was not triggered by an error and so we should only
748                 // try to send a RST frame if we didn't signal the end of the stream before.
749                 if (error == null) {
750                     if (!readEOS && !(receivedEndOfStream && sentEndOfStream)) {
751                         Http2StreamFrame resetFrame = new DefaultHttp2ResetFrame(Http2Error.CANCEL).stream(stream());
752                         write(resetFrame, unsafe().voidPromise());
753                         flush();
754                     }
755                 } else {
756                     // Close was triggered by a stream error, in this case we always want to send a RST frame.
757                     Http2StreamFrame resetFrame = new DefaultHttp2ResetFrame(error).stream(stream());
758                     write(resetFrame, unsafe().voidPromise());
759                     flush();
760                 }
761             }
762 
763             if (inboundBuffer != null) {
764                 for (;;) {
765                     Object msg = inboundBuffer.poll();
766                     if (msg == null) {
767                         break;
768                     }
769                     ReferenceCountUtil.release(msg);
770                 }
771                 inboundBuffer = null;
772             }
773 
774             // The promise should be notified before we call fireChannelInactive().
775             outboundClosed = true;
776             closePromise.setSuccess();
777             promise.setSuccess();
778 
779             fireChannelInactiveAndDeregister(voidPromise(), wasActive);
780         }
781 
782         @Override
783         public void closeForcibly() {
784             close(unsafe().voidPromise());
785         }
786 
787         @Override
788         public void deregister(ChannelPromise promise) {
789             fireChannelInactiveAndDeregister(promise, false);
790         }
791 
792         private void fireChannelInactiveAndDeregister(final ChannelPromise promise,
793                                                       final boolean fireChannelInactive) {
794             if (!promise.setUncancellable()) {
795                 return;
796             }
797 
798             if (!registered) {
799                 promise.setSuccess();
800                 return;
801             }
802 
803             // As a user may call deregister() from within any method while doing processing in the ChannelPipeline,
804             // we need to ensure we do the actual deregister operation later. This is necessary to preserve the
805             // behavior of the AbstractChannel, which always invokes channelUnregistered and channelInactive
806             // events 'later' to ensure the current events in the handler are completed before these events.
807             //
808             // See:
809             // https://github.com/netty/netty/issues/4435
810             invokeLater(promise.channel(), new Runnable() {
811                 @Override
812                 public void run() {
813                     if (fireChannelInactive) {
814                         pipeline.fireChannelInactive();
815                     }
816                     // The user can fire `deregister` events multiple times but we only want to fire the pipeline
817                     // event if the channel was actually registered.
818                     if (registered) {
819                         registered = false;
820                         pipeline.fireChannelUnregistered();
821                     }
822                     safeSetSuccess(promise);
823                 }
824             });
825         }
826 
827         private void safeSetSuccess(ChannelPromise promise) {
828             if (!(promise instanceof VoidChannelPromise) && !promise.trySuccess()) {
829                 logger.warn("{} Failed to mark a promise as success because it is done already: {}",
830                         promise.channel(), promise);
831             }
832         }
833 
834         private void invokeLater(Channel channel, Runnable task) {
835             try {
836                 // This method is used by outbound operation implementations to trigger an inbound event later.
837                 // They do not trigger an inbound event immediately because an outbound operation might have been
838                 // triggered by another inbound event handler method.  If fired immediately, the call stack
839                 // will look like this for example:
840                 //
841                 //   handlerA.inboundBufferUpdated() - (1) an inbound handler method closes a connection.
842                 //   -> handlerA.ctx.close()
843                 //     -> channel.unsafe.close()
844                 //       -> handlerA.channelInactive() - (2) another inbound handler method called while in (1) yet
845                 //
846                 // which means the execution of two inbound handler methods of the same handler overlap undesirably.
847                 eventLoop().execute(task);
848             } catch (RejectedExecutionException e) {
849                 logger.warn("{} Can't invoke task later as EventLoop rejected it", channel, e);
850             }
851         }
852 
853         @Override
854         public void beginRead() {
855             if (!isActive()) {
856                 return;
857             }
858             final boolean windowUpdated = updateLocalWindowIfNeeded();
859 
860             switch (readStatus) {
861                 case IDLE:
862                     readStatus = ReadStatus.IN_PROGRESS;
863                     // doBeginRead() always flushes (or defers to the parent's read-complete flush).
864                     doBeginRead();
865                     return;
866                 case IN_PROGRESS:
867                     readStatus = ReadStatus.REQUESTED;
868                     break;
869                 default:
870                     break;
871             }
872             if (windowUpdated) {
873                 // A WINDOW_UPDATE was just written above, but no read loop runs in this branch to flush it, so an
874                 // unflushed frame here can stall the remote peer forever (netty/netty#17600).
875                 //
876                 // flush() alone is not enough: it no-ops while isParentReadInProgress(), since
877                 // Http2MultiplexHandler batches all children's flushes into one ctx.flush() at the end of its read
878                 // loop (processPendingReadCompleteQueue()) -- but that batched flush only runs if some channel
879                 // registered via maybeAddChannelToReadCompletePendingQueue(), which doBeginRead()/fireChildRead()
880                 // do but this branch doesn't. If a cross-thread setAutoRead(true) lands here as the only activity
881                 // in the parent's read loop, the queue stays empty, the end-of-loop flush is skipped, and this
882                 // WINDOW_UPDATE (flowControlledBytes already zeroed) is never retried -- permanent stall.
883                 //
884                 // So register into that queue while the parent is reading; otherwise flush immediately.
885                 if (isParentReadInProgress()) {
886                     maybeAddChannelToReadCompletePendingQueue();
887                 } else {
888                     flush();
889                 }
890             }
891         }
892 
893         private Object pollQueuedMessage() {
894             return inboundBuffer == null ? null : inboundBuffer.poll();
895         }
896 
897         void doBeginRead() {
898             if (readStatus == ReadStatus.IDLE) {
899                 // Don't wait for the user to request a read to notify of channel closure.
900                 if (readEOS && isInboundBufferEmpty()) {
901                     // Double check there is nothing left to flush such as a window update frame.
902                     flush();
903                     closeIfReadEOSAndDrained();
904                 }
905             } else {
906                 do { // Process messages until there are none left (or the user stopped requesting) and also handle EOS.
907                     Object message = pollQueuedMessage();
908                     if (message == null) {
909                         // Double check there is nothing left to flush such as a window update frame.
910                         flush();
911                         if (!isInboundBufferEmpty()) {
912                             // The flush re-entrantly delivered more frames which got queued; keep reading if we
913                             // still should.
914                             continue;
915                         }
916                         closeIfReadEOSAndDrained();
917                         break;
918                     }
919                     final RecvByteBufAllocator.Handle allocHandle = recvBufAllocHandle();
920                     allocHandle.reset(config());
921                     boolean continueReading = false;
922                     do {
923                         doRead0((Http2Frame) message, allocHandle);
924                     } while ((readEOS || (continueReading = allocHandle.continueReading()))
925                             && (message = pollQueuedMessage()) != null);
926 
927                     if (continueReading && isParentReadInProgress() && !readEOS) {
928                         // Currently the parent and child channel are on the same EventLoop thread. If the parent is
929                         // currently reading it is possible that more frames will be delivered to this child channel. In
930                         // the case that this child channel still wants to read we delay the channelReadComplete on this
931                         // child channel until the parent is done reading.
932                         maybeAddChannelToReadCompletePendingQueue();
933                     } else {
934                         notifyReadComplete(allocHandle, true, true);
935 
936                         // While in the read loop reset the readState AFTER calling readComplete (or other pipeline
937                         // callbacks) to prevents re-entry into this method (if autoRead is disabled and the user calls
938                         // read on each readComplete) and StackOverflowException.
939                         resetReadStatus();
940                     }
941                 } while (readStatus != ReadStatus.IDLE);
942             }
943         }
944 
945         void readEOS() {
946             readEOS = true;
947         }
948 
949         private boolean updateLocalWindowIfNeeded() {
950             if (flowControlledBytes != 0 && !parentContext().isRemoved() && config.autoStreamFlowControl) {
951                 int bytes = flowControlledBytes;
952                 flowControlledBytes = 0;
953                 writeWindowUpdateFrame(new DefaultHttp2WindowUpdateFrame(bytes).stream(stream));
954                 return true;
955             }
956             return false;
957         }
958 
959         void updateLocalWindowIfNeededAndFlush() {
960             if (updateLocalWindowIfNeeded()) {
961                 flush();
962             }
963         }
964 
965         private void resetReadStatus() {
966             readStatus = readStatus == ReadStatus.REQUESTED ? ReadStatus.IN_PROGRESS : ReadStatus.IDLE;
967         }
968 
969         void notifyReadComplete(RecvByteBufAllocator.Handle allocHandle, boolean forceReadComplete,
970                                 boolean inReadLoop) {
971             if (!readCompletePending && !forceReadComplete) {
972                 return;
973             }
974             // Set to false just in case we added the channel multiple times before.
975             readCompletePending = false;
976 
977             if (!inReadLoop) {
978                 // While in the read loop we reset the state after calling pipeline methods to prevent StackOverflow.
979                 resetReadStatus();
980             }
981 
982             allocHandle.readComplete();
983             pipeline().fireChannelReadComplete();
984             // Reading data may result in frames being written (e.g. WINDOW_UPDATE, RST, etc..). If the parent
985             // channel is not currently reading we need to force a flush at the child channel, because we cannot
986             // rely upon flush occurring in channelReadComplete on the parent channel.
987             flush();
988             closeIfReadEOSAndDrained();
989         }
990 
991         private void closeIfReadEOSAndDrained() {
992             // Pipeline callbacks and flush() can re-entrantly deliver more frames, including the one that ends the
993             // stream, and queue them if the user stopped reading. Only close once all of them have been read,
994             // otherwise the queued frames would be released and the stream silently truncated.
995             if (readEOS && isInboundBufferEmpty()) {
996                 closeForcibly();
997             }
998         }
999 
1000         @SuppressWarnings("deprecation")
1001         void doRead0(Http2Frame frame, RecvByteBufAllocator.Handle allocHandle) {
1002             final int bytes;
1003             if (frame instanceof Http2DataFrame) {
1004                 bytes = ((Http2DataFrame) frame).initialFlowControlledBytes();
1005                 // It is important that we increment the flowControlledBytes before we call fireChannelRead(...)
1006                 // as it may cause a read() that will call updateLocalWindowIfNeeded() and we need to ensure
1007                 // in this case that we accounted for it.
1008                 //
1009                 // See https://github.com/netty/netty/issues/9663
1010                 flowControlledBytes += bytes;
1011             } else {
1012                 bytes = MIN_HTTP2_FRAME_SIZE;
1013             }
1014 
1015             // Let's keep track of what we received as the stream state itself will only be updated once the frame
1016             // was dispatched for reading which might cause problems if we try to close the channel in a write future.
1017             receivedEndOfStream |= isEndOfStream(frame);
1018 
1019             // Update before firing event through the pipeline to be consistent with other Channel implementation.
1020             allocHandle.attemptedBytesRead(bytes);
1021             allocHandle.lastBytesRead(bytes);
1022             allocHandle.incMessagesRead(1);
1023 
1024             pipeline().fireChannelRead(frame);
1025         }
1026 
1027         private ChannelFuture writeWindowUpdateFrame(Http2WindowUpdateFrame windowUpdateFrame) {
1028             ChannelFuture future = write0(parentContext(), windowUpdateFrame);
1029             // window update frames are commonly swallowed by the Http2FrameCodec and the promise is synchronously
1030             // completed but the flow controller _may_ have generated a wire level WINDOW_UPDATE. Therefore we need,
1031             // to assume there was a write done that needs to be flushed or we risk flow control starvation.
1032             writeDoneAndNoFlush = true;
1033             // Add a listener which will notify and teardown the stream
1034             // when a window update fails if needed or check the result of the future directly if it was completed
1035             // already.
1036             // See https://github.com/netty/netty/issues/9663
1037             if (future.isDone()) {
1038                 windowUpdateFrameWriteComplete(future, AbstractHttp2StreamChannel.this);
1039             } else {
1040                 future.addListener(windowUpdateFrameWriteListener);
1041             }
1042             return future;
1043         }
1044 
1045         @Override
1046         public void write(Object msg, final ChannelPromise promise) {
1047             // After this point its not possible to cancel a write anymore.
1048             if (!promise.setUncancellable()) {
1049                 ReferenceCountUtil.release(msg);
1050                 return;
1051             }
1052 
1053             if (!isActive() ||
1054                     // Once the outbound side was closed we should not allow header / data frames
1055                     outboundClosed && (msg instanceof Http2HeadersFrame || msg instanceof Http2DataFrame)) {
1056                 ReferenceCountUtil.release(msg);
1057                 promise.setFailure(new ClosedChannelException());
1058                 return;
1059             }
1060 
1061             try {
1062                 if (msg instanceof Http2StreamFrame) {
1063                     Http2StreamFrame frame = validateStreamFrame((Http2StreamFrame) msg).stream(stream());
1064                     if (msg instanceof Http2WindowUpdateFrame) {
1065                         Http2WindowUpdateFrame updateFrame = (Http2WindowUpdateFrame) msg;
1066                         if (config.autoStreamFlowControl) {
1067                             ReferenceCountUtil.release(msg);
1068                             promise.setFailure(new UnsupportedOperationException(
1069                                     Http2StreamChannelOption.AUTO_STREAM_FLOW_CONTROL + " is set to false"));
1070                             return;
1071                         }
1072                         try {
1073                             ObjectUtil.checkInRange(updateFrame.windowSizeIncrement(), 0,
1074                                     flowControlledBytes, "windowSizeIncrement");
1075                         } catch (RuntimeException e) {
1076                             ReferenceCountUtil.release(updateFrame);
1077                             promise.setFailure(e);
1078                             return;
1079                         }
1080                         flowControlledBytes -= updateFrame.windowSizeIncrement();
1081                         if (parentContext().isRemoved()) {
1082                             ReferenceCountUtil.release(msg);
1083                             promise.setFailure(new ClosedChannelException());
1084                             return;
1085                         }
1086                         ChannelFuture f = writeWindowUpdateFrame(updateFrame);
1087                         if (f.isDone()) {
1088                             writeComplete(f, promise);
1089                         } else {
1090                             f.addListener(future -> writeComplete(future, promise));
1091                         }
1092                     } else {
1093                         writeHttp2StreamFrame(frame, promise);
1094                     }
1095                 } else {
1096                     String msgStr = msg.toString();
1097                     ReferenceCountUtil.release(msg);
1098                     promise.setFailure(new IllegalArgumentException(
1099                             "Message must be an " + StringUtil.simpleClassName(Http2StreamFrame.class) +
1100                                     ": " + msgStr));
1101                 }
1102             } catch (Throwable t) {
1103                 promise.tryFailure(t);
1104             }
1105         }
1106 
1107         private boolean isEndOfStream(Http2Frame frame) {
1108             if (frame instanceof Http2HeadersFrame) {
1109                 return ((Http2HeadersFrame) frame).isEndStream();
1110             }
1111             if (frame instanceof Http2DataFrame) {
1112                 return ((Http2DataFrame) frame).isEndStream();
1113             }
1114             return false;
1115         }
1116 
1117         private void writeHttp2StreamFrame(Http2StreamFrame frame, final ChannelPromise promise) {
1118             if (!firstFrameWritten && !isStreamIdValid(stream().id()) && !(frame instanceof Http2HeadersFrame)) {
1119                 ReferenceCountUtil.release(frame);
1120                 promise.setFailure(
1121                     new IllegalArgumentException("The first frame must be a headers frame. Was: "
1122                         + frame.name()));
1123                 return;
1124             }
1125 
1126             final boolean firstWrite;
1127             if (firstFrameWritten) {
1128                 firstWrite = false;
1129             } else {
1130                 firstWrite = firstFrameWritten = true;
1131             }
1132 
1133             // Let's keep track of what we send as the stream state itself will only be updated once the frame
1134             // was written which might cause problems if we try to close the channel in a write future.
1135             sentEndOfStream |= isEndOfStream(frame);
1136             ChannelFuture f = write0(parentContext(), frame);
1137             if (f.isDone()) {
1138                 if (firstWrite) {
1139                     firstWriteComplete(f, promise);
1140                 } else {
1141                     writeComplete(f, promise);
1142                 }
1143             } else {
1144                 final long bytes = FlowControlledFrameSizeEstimator.HANDLE_INSTANCE.size(frame);
1145                 incrementPendingOutboundBytes(bytes, false);
1146                 f.addListener(future -> {
1147                     if (firstWrite) {
1148                         firstWriteComplete(future, promise);
1149                     } else {
1150                         writeComplete(future, promise);
1151                     }
1152                     decrementPendingOutboundBytes(bytes, false);
1153                 });
1154                 writeDoneAndNoFlush = true;
1155             }
1156         }
1157 
1158         private void firstWriteComplete(Future<?> future, ChannelPromise promise) {
1159             Throwable cause = future.cause();
1160             if (cause == null) {
1161                 promise.setSuccess();
1162             } else {
1163                 // If the first write fails there is not much we can do, just close
1164                 closeForcibly();
1165                 promise.setFailure(wrapStreamClosedError(cause));
1166             }
1167         }
1168 
1169         private void writeComplete(Future<?> future, ChannelPromise promise) {
1170             Throwable cause = future.cause();
1171             if (cause == null) {
1172                 promise.setSuccess();
1173             } else {
1174                 Throwable error = wrapStreamClosedError(cause);
1175                 // To make it more consistent with AbstractChannel we handle all IOExceptions here.
1176                 if (error instanceof IOException) {
1177                     if (config.isAutoClose()) {
1178                         // Close channel if needed.
1179                         closeForcibly();
1180                     } else {
1181                         // TODO: Once Http2StreamChannel extends DuplexChannel we should call shutdownOutput(...)
1182                         outboundClosed = true;
1183                     }
1184                 }
1185                 promise.setFailure(error);
1186             }
1187         }
1188 
1189         private Throwable wrapStreamClosedError(Throwable cause) {
1190             // If the error was caused by STREAM_CLOSED we should use a ClosedChannelException to better
1191             // mimic other transports and make it easier to reason about what exceptions to expect.
1192             if (cause instanceof Http2Exception && ((Http2Exception) cause).error() == Http2Error.STREAM_CLOSED) {
1193                 return new ClosedChannelException().initCause(cause);
1194             }
1195             return cause;
1196         }
1197 
1198         private Http2StreamFrame validateStreamFrame(Http2StreamFrame frame) {
1199             if (frame.stream() != null && frame.stream() != stream) {
1200                 String msgString = frame.toString();
1201                 ReferenceCountUtil.release(frame);
1202                 throw new IllegalArgumentException(
1203                         "Stream " + frame.stream() + " must not be set on the frame: " + msgString);
1204             }
1205             return frame;
1206         }
1207 
1208         @Override
1209         public void flush() {
1210             // If we are currently in the parent channel's read loop we should just ignore the flush.
1211             // We will ensure we trigger ctx.flush() after we processed all Channels later on and
1212             // so aggregate the flushes. This is done as ctx.flush() is expensive when as it may trigger an
1213             // write(...) or writev(...) operation on the socket.
1214             if (!writeDoneAndNoFlush || isParentReadInProgress()) {
1215                 // There is nothing to flush so this is a NOOP.
1216                 return;
1217             }
1218             // We need to set this to false before we call flush0(...) as ChannelFutureListener may produce more data
1219             // that are explicit flushed.
1220             writeDoneAndNoFlush = false;
1221             flush0(parentContext());
1222         }
1223 
1224         @Override
1225         public ChannelPromise voidPromise() {
1226             return unsafeVoidPromise;
1227         }
1228 
1229         @Override
1230         public ChannelOutboundBuffer outboundBuffer() {
1231             // Always return null as we not use the ChannelOutboundBuffer and not even support it.
1232             return null;
1233         }
1234     }
1235 
1236     /**
1237      * {@link ChannelConfig} so that the high and low writebuffer watermarks can reflect the outbound flow control
1238      * window, without having to create a new {@link WriteBufferWaterMark} object whenever the flow control window
1239      * changes.
1240      */
1241     private static final class Http2StreamChannelConfig extends DefaultChannelConfig {
1242 
1243         volatile boolean autoStreamFlowControl = true;
1244         Http2StreamChannelConfig(Channel channel) {
1245             super(channel);
1246         }
1247 
1248         @Override
1249         public MessageSizeEstimator getMessageSizeEstimator() {
1250             return FlowControlledFrameSizeEstimator.INSTANCE;
1251         }
1252 
1253         @Override
1254         public ChannelConfig setMessageSizeEstimator(MessageSizeEstimator estimator) {
1255             throw new UnsupportedOperationException();
1256         }
1257 
1258         @Override
1259         public ChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator) {
1260             if (!(allocator.newHandle() instanceof RecvByteBufAllocator.ExtendedHandle)) {
1261                 throw new IllegalArgumentException("allocator.newHandle() must return an object of type: " +
1262                         RecvByteBufAllocator.ExtendedHandle.class);
1263             }
1264             super.setRecvByteBufAllocator(allocator);
1265             return this;
1266         }
1267 
1268         @Override
1269         public Map<ChannelOption<?>, Object> getOptions() {
1270             return getOptions(
1271                     super.getOptions(),
1272                     Http2StreamChannelOption.AUTO_STREAM_FLOW_CONTROL);
1273         }
1274 
1275         @SuppressWarnings("unchecked")
1276         @Override
1277         public <T> T getOption(ChannelOption<T> option) {
1278             if (option == Http2StreamChannelOption.AUTO_STREAM_FLOW_CONTROL) {
1279                 return (T) Boolean.valueOf(autoStreamFlowControl);
1280             }
1281             return super.getOption(option);
1282         }
1283 
1284         @Override
1285         public <T> boolean setOption(ChannelOption<T> option, T value) {
1286             validate(option, value);
1287             if (option == Http2StreamChannelOption.AUTO_STREAM_FLOW_CONTROL) {
1288                 boolean newValue = (Boolean) value;
1289                 boolean changed = newValue && !autoStreamFlowControl;
1290                 autoStreamFlowControl = (Boolean) value;
1291                 if (changed) {
1292                     if (channel.isRegistered()) {
1293                         final Http2ChannelUnsafe unsafe = (Http2ChannelUnsafe) channel.unsafe();
1294                         if (channel.eventLoop().inEventLoop()) {
1295                             unsafe.updateLocalWindowIfNeededAndFlush();
1296                         } else {
1297                             channel.eventLoop().execute(new Runnable() {
1298                                 @Override
1299                                 public void run() {
1300                                     unsafe.updateLocalWindowIfNeededAndFlush();
1301                                 }
1302                             });
1303                         }
1304                     }
1305                 }
1306                 return true;
1307             }
1308             return super.setOption(option, value);
1309         }
1310     }
1311 
1312     private void maybeAddChannelToReadCompletePendingQueue() {
1313         if (!readCompletePending) {
1314             readCompletePending = true;
1315             addChannelToReadCompletePendingQueue();
1316         }
1317     }
1318 
1319     protected void flush0(ChannelHandlerContext ctx) {
1320         ctx.flush();
1321     }
1322 
1323     protected ChannelFuture write0(ChannelHandlerContext ctx, Object msg) {
1324         ChannelPromise promise = ctx.newPromise();
1325         ctx.write(msg, promise);
1326         return promise;
1327     }
1328 
1329     protected abstract boolean isParentReadInProgress();
1330     protected abstract void addChannelToReadCompletePendingQueue();
1331     protected abstract ChannelHandlerContext parentContext();
1332 }