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) {
604
605
606 assert inboundBuffer == null || inboundBuffer.isEmpty();
607 final RecvByteBufAllocator.Handle allocHandle = unsafe.recvBufAllocHandle();
608
609 unsafe.doRead0(frame, allocHandle);
610
611
612
613
614 if (allocHandle.continueReading()) {
615 maybeAddChannelToReadCompletePendingQueue();
616 } else {
617 unsafe.notifyReadComplete(allocHandle, true, false);
618 }
619 } else {
620 if (inboundBuffer == null) {
621 inboundBuffer = new ArrayDeque<Object>(4);
622 }
623 inboundBuffer.add(frame);
624 }
625 }
626
627 void fireChildReadComplete() {
628 assert eventLoop().inEventLoop();
629 assert readStatus != ReadStatus.IDLE || !readCompletePending;
630 unsafe.notifyReadComplete(unsafe.recvBufAllocHandle(), false, false);
631 }
632
633 final void closeWithError(Http2Error error) {
634 assert eventLoop().inEventLoop();
635 unsafe.close(unsafe.voidPromise(), error);
636 }
637
638 private final class Http2ChannelUnsafe implements Unsafe {
639 private final VoidChannelPromise unsafeVoidPromise =
640 new VoidChannelPromise(AbstractHttp2StreamChannel.this, false);
641 @SuppressWarnings("deprecation")
642 private RecvByteBufAllocator.Handle recvHandle;
643 private boolean writeDoneAndNoFlush;
644 private boolean closeInitiated;
645 private boolean readEOS;
646
647 private boolean receivedEndOfStream;
648 private boolean sentEndOfStream;
649
650 @Override
651 public void connect(final SocketAddress remoteAddress,
652 SocketAddress localAddress, final ChannelPromise promise) {
653 if (!promise.setUncancellable()) {
654 return;
655 }
656 promise.setFailure(new UnsupportedOperationException());
657 }
658
659 @Override
660 public RecvByteBufAllocator.Handle recvBufAllocHandle() {
661 if (recvHandle == null) {
662 recvHandle = config().getRecvByteBufAllocator().newHandle();
663 recvHandle.reset(config());
664 }
665 return recvHandle;
666 }
667
668 @Override
669 public SocketAddress localAddress() {
670 return parent().unsafe().localAddress();
671 }
672
673 @Override
674 public SocketAddress remoteAddress() {
675 return parent().unsafe().remoteAddress();
676 }
677
678 @Override
679 public void register(EventLoop eventLoop, ChannelPromise promise) {
680 if (!promise.setUncancellable()) {
681 return;
682 }
683 if (registered) {
684 promise.setFailure(new UnsupportedOperationException("Re-register is not supported"));
685 return;
686 }
687
688 registered = true;
689
690 promise.setSuccess();
691
692 pipeline().fireChannelRegistered();
693 if (isActive()) {
694 pipeline().fireChannelActive();
695 }
696 }
697
698 @Override
699 public void bind(SocketAddress localAddress, ChannelPromise promise) {
700 if (!promise.setUncancellable()) {
701 return;
702 }
703 promise.setFailure(new UnsupportedOperationException());
704 }
705
706 @Override
707 public void disconnect(ChannelPromise promise) {
708 close(promise);
709 }
710
711 @Override
712 public void close(final ChannelPromise promise) {
713 close(promise, null);
714 }
715
716 private void close(final ChannelPromise promise, Http2Error error) {
717 if (!promise.setUncancellable()) {
718 return;
719 }
720 if (closeInitiated) {
721 if (closePromise.isDone()) {
722
723 promise.setSuccess();
724 } else if (!(promise instanceof VoidChannelPromise)) {
725
726 closePromise.addListener(future -> promise.setSuccess());
727 }
728 return;
729 }
730 closeInitiated = true;
731
732 readCompletePending = false;
733
734 final boolean wasActive = isActive();
735
736
737
738
739
740
741 if (parent().isActive() && isStreamIdValid(stream.id())) {
742
743
744 if (error == null) {
745 if (!readEOS && !(receivedEndOfStream && sentEndOfStream)) {
746 Http2StreamFrame resetFrame = new DefaultHttp2ResetFrame(Http2Error.CANCEL).stream(stream());
747 write(resetFrame, unsafe().voidPromise());
748 flush();
749 }
750 } else {
751
752 Http2StreamFrame resetFrame = new DefaultHttp2ResetFrame(error).stream(stream());
753 write(resetFrame, unsafe().voidPromise());
754 flush();
755 }
756 }
757
758 if (inboundBuffer != null) {
759 for (;;) {
760 Object msg = inboundBuffer.poll();
761 if (msg == null) {
762 break;
763 }
764 ReferenceCountUtil.release(msg);
765 }
766 inboundBuffer = null;
767 }
768
769
770 outboundClosed = true;
771 closePromise.setSuccess();
772 promise.setSuccess();
773
774 fireChannelInactiveAndDeregister(voidPromise(), wasActive);
775 }
776
777 @Override
778 public void closeForcibly() {
779 close(unsafe().voidPromise());
780 }
781
782 @Override
783 public void deregister(ChannelPromise promise) {
784 fireChannelInactiveAndDeregister(promise, false);
785 }
786
787 private void fireChannelInactiveAndDeregister(final ChannelPromise promise,
788 final boolean fireChannelInactive) {
789 if (!promise.setUncancellable()) {
790 return;
791 }
792
793 if (!registered) {
794 promise.setSuccess();
795 return;
796 }
797
798
799
800
801
802
803
804
805 invokeLater(promise.channel(), new Runnable() {
806 @Override
807 public void run() {
808 if (fireChannelInactive) {
809 pipeline.fireChannelInactive();
810 }
811
812
813 if (registered) {
814 registered = false;
815 pipeline.fireChannelUnregistered();
816 }
817 safeSetSuccess(promise);
818 }
819 });
820 }
821
822 private void safeSetSuccess(ChannelPromise promise) {
823 if (!(promise instanceof VoidChannelPromise) && !promise.trySuccess()) {
824 logger.warn("{} Failed to mark a promise as success because it is done already: {}",
825 promise.channel(), promise);
826 }
827 }
828
829 private void invokeLater(Channel channel, Runnable task) {
830 try {
831
832
833
834
835
836
837
838
839
840
841
842 eventLoop().execute(task);
843 } catch (RejectedExecutionException e) {
844 logger.warn("{} Can't invoke task later as EventLoop rejected it", channel, e);
845 }
846 }
847
848 @Override
849 public void beginRead() {
850 if (!isActive()) {
851 return;
852 }
853 updateLocalWindowIfNeeded();
854
855 switch (readStatus) {
856 case IDLE:
857 readStatus = ReadStatus.IN_PROGRESS;
858 doBeginRead();
859 break;
860 case IN_PROGRESS:
861 readStatus = ReadStatus.REQUESTED;
862 break;
863 default:
864 break;
865 }
866 }
867
868 private Object pollQueuedMessage() {
869 return inboundBuffer == null ? null : inboundBuffer.poll();
870 }
871
872 void doBeginRead() {
873 if (readStatus == ReadStatus.IDLE) {
874
875 if (readEOS && (inboundBuffer == null || inboundBuffer.isEmpty())) {
876
877 flush();
878 unsafe.closeForcibly();
879 }
880 } else {
881 do {
882 Object message = pollQueuedMessage();
883 if (message == null) {
884
885 flush();
886 if (readEOS) {
887 unsafe.closeForcibly();
888 }
889 break;
890 }
891 final RecvByteBufAllocator.Handle allocHandle = recvBufAllocHandle();
892 allocHandle.reset(config());
893 boolean continueReading = false;
894 do {
895 doRead0((Http2Frame) message, allocHandle);
896 } while ((readEOS || (continueReading = allocHandle.continueReading()))
897 && (message = pollQueuedMessage()) != null);
898
899 if (continueReading && isParentReadInProgress() && !readEOS) {
900
901
902
903
904 maybeAddChannelToReadCompletePendingQueue();
905 } else {
906 notifyReadComplete(allocHandle, true, true);
907
908
909
910
911 resetReadStatus();
912 }
913 } while (readStatus != ReadStatus.IDLE);
914 }
915 }
916
917 void readEOS() {
918 readEOS = true;
919 }
920
921 private boolean updateLocalWindowIfNeeded() {
922 if (flowControlledBytes != 0 && !parentContext().isRemoved() && config.autoStreamFlowControl) {
923 int bytes = flowControlledBytes;
924 flowControlledBytes = 0;
925 writeWindowUpdateFrame(new DefaultHttp2WindowUpdateFrame(bytes).stream(stream));
926 return true;
927 }
928 return false;
929 }
930
931 void updateLocalWindowIfNeededAndFlush() {
932 if (updateLocalWindowIfNeeded()) {
933 flush();
934 }
935 }
936
937 private void resetReadStatus() {
938 readStatus = readStatus == ReadStatus.REQUESTED ? ReadStatus.IN_PROGRESS : ReadStatus.IDLE;
939 }
940
941 void notifyReadComplete(RecvByteBufAllocator.Handle allocHandle, boolean forceReadComplete,
942 boolean inReadLoop) {
943 if (!readCompletePending && !forceReadComplete) {
944 return;
945 }
946
947 readCompletePending = false;
948
949 if (!inReadLoop) {
950
951 resetReadStatus();
952 }
953
954 allocHandle.readComplete();
955 pipeline().fireChannelReadComplete();
956
957
958
959 flush();
960 if (readEOS) {
961 unsafe.closeForcibly();
962 }
963 }
964
965 @SuppressWarnings("deprecation")
966 void doRead0(Http2Frame frame, RecvByteBufAllocator.Handle allocHandle) {
967 final int bytes;
968 if (frame instanceof Http2DataFrame) {
969 bytes = ((Http2DataFrame) frame).initialFlowControlledBytes();
970
971
972
973
974
975 flowControlledBytes += bytes;
976 } else {
977 bytes = MIN_HTTP2_FRAME_SIZE;
978 }
979
980
981
982 receivedEndOfStream |= isEndOfStream(frame);
983
984
985 allocHandle.attemptedBytesRead(bytes);
986 allocHandle.lastBytesRead(bytes);
987 allocHandle.incMessagesRead(1);
988
989 pipeline().fireChannelRead(frame);
990 }
991
992 private ChannelFuture writeWindowUpdateFrame(Http2WindowUpdateFrame windowUpdateFrame) {
993 ChannelFuture future = write0(parentContext(), windowUpdateFrame);
994
995
996
997 writeDoneAndNoFlush = true;
998
999
1000
1001
1002 if (future.isDone()) {
1003 windowUpdateFrameWriteComplete(future, AbstractHttp2StreamChannel.this);
1004 } else {
1005 future.addListener(windowUpdateFrameWriteListener);
1006 }
1007 return future;
1008 }
1009
1010 @Override
1011 public void write(Object msg, final ChannelPromise promise) {
1012
1013 if (!promise.setUncancellable()) {
1014 ReferenceCountUtil.release(msg);
1015 return;
1016 }
1017
1018 if (!isActive() ||
1019
1020 outboundClosed && (msg instanceof Http2HeadersFrame || msg instanceof Http2DataFrame)) {
1021 ReferenceCountUtil.release(msg);
1022 promise.setFailure(new ClosedChannelException());
1023 return;
1024 }
1025
1026 try {
1027 if (msg instanceof Http2StreamFrame) {
1028 Http2StreamFrame frame = validateStreamFrame((Http2StreamFrame) msg).stream(stream());
1029 if (msg instanceof Http2WindowUpdateFrame) {
1030 Http2WindowUpdateFrame updateFrame = (Http2WindowUpdateFrame) msg;
1031 if (config.autoStreamFlowControl) {
1032 ReferenceCountUtil.release(msg);
1033 promise.setFailure(new UnsupportedOperationException(
1034 Http2StreamChannelOption.AUTO_STREAM_FLOW_CONTROL + " is set to false"));
1035 return;
1036 }
1037 try {
1038 ObjectUtil.checkInRange(updateFrame.windowSizeIncrement(), 0,
1039 flowControlledBytes, "windowSizeIncrement");
1040 } catch (RuntimeException e) {
1041 ReferenceCountUtil.release(updateFrame);
1042 promise.setFailure(e);
1043 return;
1044 }
1045 flowControlledBytes -= updateFrame.windowSizeIncrement();
1046 if (parentContext().isRemoved()) {
1047 ReferenceCountUtil.release(msg);
1048 promise.setFailure(new ClosedChannelException());
1049 return;
1050 }
1051 ChannelFuture f = writeWindowUpdateFrame(updateFrame);
1052 if (f.isDone()) {
1053 writeComplete(f, promise);
1054 } else {
1055 f.addListener(future -> writeComplete(future, promise));
1056 }
1057 } else {
1058 writeHttp2StreamFrame(frame, promise);
1059 }
1060 } else {
1061 String msgStr = msg.toString();
1062 ReferenceCountUtil.release(msg);
1063 promise.setFailure(new IllegalArgumentException(
1064 "Message must be an " + StringUtil.simpleClassName(Http2StreamFrame.class) +
1065 ": " + msgStr));
1066 }
1067 } catch (Throwable t) {
1068 promise.tryFailure(t);
1069 }
1070 }
1071
1072 private boolean isEndOfStream(Http2Frame frame) {
1073 if (frame instanceof Http2HeadersFrame) {
1074 return ((Http2HeadersFrame) frame).isEndStream();
1075 }
1076 if (frame instanceof Http2DataFrame) {
1077 return ((Http2DataFrame) frame).isEndStream();
1078 }
1079 return false;
1080 }
1081
1082 private void writeHttp2StreamFrame(Http2StreamFrame frame, final ChannelPromise promise) {
1083 if (!firstFrameWritten && !isStreamIdValid(stream().id()) && !(frame instanceof Http2HeadersFrame)) {
1084 ReferenceCountUtil.release(frame);
1085 promise.setFailure(
1086 new IllegalArgumentException("The first frame must be a headers frame. Was: "
1087 + frame.name()));
1088 return;
1089 }
1090
1091 final boolean firstWrite;
1092 if (firstFrameWritten) {
1093 firstWrite = false;
1094 } else {
1095 firstWrite = firstFrameWritten = true;
1096 }
1097
1098
1099
1100 sentEndOfStream |= isEndOfStream(frame);
1101 ChannelFuture f = write0(parentContext(), frame);
1102 if (f.isDone()) {
1103 if (firstWrite) {
1104 firstWriteComplete(f, promise);
1105 } else {
1106 writeComplete(f, promise);
1107 }
1108 } else {
1109 final long bytes = FlowControlledFrameSizeEstimator.HANDLE_INSTANCE.size(frame);
1110 incrementPendingOutboundBytes(bytes, false);
1111 f.addListener(future -> {
1112 if (firstWrite) {
1113 firstWriteComplete(future, promise);
1114 } else {
1115 writeComplete(future, promise);
1116 }
1117 decrementPendingOutboundBytes(bytes, false);
1118 });
1119 writeDoneAndNoFlush = true;
1120 }
1121 }
1122
1123 private void firstWriteComplete(Future<?> future, ChannelPromise promise) {
1124 Throwable cause = future.cause();
1125 if (cause == null) {
1126 promise.setSuccess();
1127 } else {
1128
1129 closeForcibly();
1130 promise.setFailure(wrapStreamClosedError(cause));
1131 }
1132 }
1133
1134 private void writeComplete(Future<?> future, ChannelPromise promise) {
1135 Throwable cause = future.cause();
1136 if (cause == null) {
1137 promise.setSuccess();
1138 } else {
1139 Throwable error = wrapStreamClosedError(cause);
1140
1141 if (error instanceof IOException) {
1142 if (config.isAutoClose()) {
1143
1144 closeForcibly();
1145 } else {
1146
1147 outboundClosed = true;
1148 }
1149 }
1150 promise.setFailure(error);
1151 }
1152 }
1153
1154 private Throwable wrapStreamClosedError(Throwable cause) {
1155
1156
1157 if (cause instanceof Http2Exception && ((Http2Exception) cause).error() == Http2Error.STREAM_CLOSED) {
1158 return new ClosedChannelException().initCause(cause);
1159 }
1160 return cause;
1161 }
1162
1163 private Http2StreamFrame validateStreamFrame(Http2StreamFrame frame) {
1164 if (frame.stream() != null && frame.stream() != stream) {
1165 String msgString = frame.toString();
1166 ReferenceCountUtil.release(frame);
1167 throw new IllegalArgumentException(
1168 "Stream " + frame.stream() + " must not be set on the frame: " + msgString);
1169 }
1170 return frame;
1171 }
1172
1173 @Override
1174 public void flush() {
1175
1176
1177
1178
1179 if (!writeDoneAndNoFlush || isParentReadInProgress()) {
1180
1181 return;
1182 }
1183
1184
1185 writeDoneAndNoFlush = false;
1186 flush0(parentContext());
1187 }
1188
1189 @Override
1190 public ChannelPromise voidPromise() {
1191 return unsafeVoidPromise;
1192 }
1193
1194 @Override
1195 public ChannelOutboundBuffer outboundBuffer() {
1196
1197 return null;
1198 }
1199 }
1200
1201
1202
1203
1204
1205
1206 private static final class Http2StreamChannelConfig extends DefaultChannelConfig {
1207
1208 volatile boolean autoStreamFlowControl = true;
1209 Http2StreamChannelConfig(Channel channel) {
1210 super(channel);
1211 }
1212
1213 @Override
1214 public MessageSizeEstimator getMessageSizeEstimator() {
1215 return FlowControlledFrameSizeEstimator.INSTANCE;
1216 }
1217
1218 @Override
1219 public ChannelConfig setMessageSizeEstimator(MessageSizeEstimator estimator) {
1220 throw new UnsupportedOperationException();
1221 }
1222
1223 @Override
1224 public ChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator) {
1225 if (!(allocator.newHandle() instanceof RecvByteBufAllocator.ExtendedHandle)) {
1226 throw new IllegalArgumentException("allocator.newHandle() must return an object of type: " +
1227 RecvByteBufAllocator.ExtendedHandle.class);
1228 }
1229 super.setRecvByteBufAllocator(allocator);
1230 return this;
1231 }
1232
1233 @Override
1234 public Map<ChannelOption<?>, Object> getOptions() {
1235 return getOptions(
1236 super.getOptions(),
1237 Http2StreamChannelOption.AUTO_STREAM_FLOW_CONTROL);
1238 }
1239
1240 @SuppressWarnings("unchecked")
1241 @Override
1242 public <T> T getOption(ChannelOption<T> option) {
1243 if (option == Http2StreamChannelOption.AUTO_STREAM_FLOW_CONTROL) {
1244 return (T) Boolean.valueOf(autoStreamFlowControl);
1245 }
1246 return super.getOption(option);
1247 }
1248
1249 @Override
1250 public <T> boolean setOption(ChannelOption<T> option, T value) {
1251 validate(option, value);
1252 if (option == Http2StreamChannelOption.AUTO_STREAM_FLOW_CONTROL) {
1253 boolean newValue = (Boolean) value;
1254 boolean changed = newValue && !autoStreamFlowControl;
1255 autoStreamFlowControl = (Boolean) value;
1256 if (changed) {
1257 if (channel.isRegistered()) {
1258 final Http2ChannelUnsafe unsafe = (Http2ChannelUnsafe) channel.unsafe();
1259 if (channel.eventLoop().inEventLoop()) {
1260 unsafe.updateLocalWindowIfNeededAndFlush();
1261 } else {
1262 channel.eventLoop().execute(new Runnable() {
1263 @Override
1264 public void run() {
1265 unsafe.updateLocalWindowIfNeededAndFlush();
1266 }
1267 });
1268 }
1269 }
1270 }
1271 return true;
1272 }
1273 return super.setOption(option, value);
1274 }
1275 }
1276
1277 private void maybeAddChannelToReadCompletePendingQueue() {
1278 if (!readCompletePending) {
1279 readCompletePending = true;
1280 addChannelToReadCompletePendingQueue();
1281 }
1282 }
1283
1284 protected void flush0(ChannelHandlerContext ctx) {
1285 ctx.flush();
1286 }
1287
1288 protected ChannelFuture write0(ChannelHandlerContext ctx, Object msg) {
1289 ChannelPromise promise = ctx.newPromise();
1290 ctx.write(msg, promise);
1291 return promise;
1292 }
1293
1294 protected abstract boolean isParentReadInProgress();
1295 protected abstract void addChannelToReadCompletePendingQueue();
1296 protected abstract ChannelHandlerContext parentContext();
1297 }