1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
92
93
94 private static final int MIN_HTTP2_FRAME_SIZE = 9;
95
96
97
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
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
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
150 if (cause instanceof Http2FrameStreamException && (unwrappedCause = cause.getCause()) != null) {
151 cause = unwrappedCause;
152 }
153
154
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
165
166 private enum ReadStatus {
167
168
169
170 IDLE,
171
172
173
174
175 IN_PROGRESS,
176
177
178
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
196 private Runnable fireChannelWritabilityChangedTask;
197
198 private boolean outboundClosed;
199 private int flowControlledBytes;
200
201
202
203
204
205
206
207 private ReadStatus readStatus = ReadStatus.IDLE;
208
209 private Queue<Object> inboundBuffer;
210
211
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
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
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
273
274
275
276
277 if (newWriteBufferSize < config().getWriteBufferLowWaterMark() && parent().isWritable()) {
278 setWritable(invokeLater);
279 }
280 }
281
282 final void trySetWritable() {
283
284
285
286
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
347
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
414 long bytes = config().getWriteBufferHighWaterMark() - totalPendingSize + 1;
415
416
417
418 return bytes > 0 && isWritable() ? bytes : 0;
419 }
420
421 @Override
422 public long bytesBeforeWritable() {
423
424 long bytes = totalPendingSize - config().getWriteBufferLowWaterMark() + 1;
425
426
427
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
597
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
605
606
607
608 final RecvByteBufAllocator.Handle allocHandle = unsafe.recvBufAllocHandle();
609
610 unsafe.doRead0(frame, allocHandle);
611
612
613
614
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
728 promise.setSuccess();
729 } else if (!(promise instanceof VoidChannelPromise)) {
730
731 closePromise.addListener(future -> promise.setSuccess());
732 }
733 return;
734 }
735 closeInitiated = true;
736
737 readCompletePending = false;
738
739 final boolean wasActive = isActive();
740
741
742
743
744
745
746 if (parent().isActive() && isStreamIdValid(stream.id())) {
747
748
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
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
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
804
805
806
807
808
809
810 invokeLater(promise.channel(), new Runnable() {
811 @Override
812 public void run() {
813 if (fireChannelInactive) {
814 pipeline.fireChannelInactive();
815 }
816
817
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
837
838
839
840
841
842
843
844
845
846
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
864 doBeginRead();
865 return;
866 case IN_PROGRESS:
867 readStatus = ReadStatus.REQUESTED;
868 break;
869 default:
870 break;
871 }
872 if (windowUpdated) {
873
874
875
876
877
878
879
880
881
882
883
884
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
900 if (readEOS && isInboundBufferEmpty()) {
901
902 flush();
903 closeIfReadEOSAndDrained();
904 }
905 } else {
906 do {
907 Object message = pollQueuedMessage();
908 if (message == null) {
909
910 flush();
911 if (!isInboundBufferEmpty()) {
912
913
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
929
930
931
932 maybeAddChannelToReadCompletePendingQueue();
933 } else {
934 notifyReadComplete(allocHandle, true, true);
935
936
937
938
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
975 readCompletePending = false;
976
977 if (!inReadLoop) {
978
979 resetReadStatus();
980 }
981
982 allocHandle.readComplete();
983 pipeline().fireChannelReadComplete();
984
985
986
987 flush();
988 closeIfReadEOSAndDrained();
989 }
990
991 private void closeIfReadEOSAndDrained() {
992
993
994
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
1006
1007
1008
1009
1010 flowControlledBytes += bytes;
1011 } else {
1012 bytes = MIN_HTTP2_FRAME_SIZE;
1013 }
1014
1015
1016
1017 receivedEndOfStream |= isEndOfStream(frame);
1018
1019
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
1030
1031
1032 writeDoneAndNoFlush = true;
1033
1034
1035
1036
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
1048 if (!promise.setUncancellable()) {
1049 ReferenceCountUtil.release(msg);
1050 return;
1051 }
1052
1053 if (!isActive() ||
1054
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
1134
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
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
1176 if (error instanceof IOException) {
1177 if (config.isAutoClose()) {
1178
1179 closeForcibly();
1180 } else {
1181
1182 outboundClosed = true;
1183 }
1184 }
1185 promise.setFailure(error);
1186 }
1187 }
1188
1189 private Throwable wrapStreamClosedError(Throwable cause) {
1190
1191
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
1211
1212
1213
1214 if (!writeDoneAndNoFlush || isParentReadInProgress()) {
1215
1216 return;
1217 }
1218
1219
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
1232 return null;
1233 }
1234 }
1235
1236
1237
1238
1239
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 }