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.internal.ObjectUtil;
46 import io.netty.util.internal.StringUtil;
47 import io.netty.util.internal.logging.InternalLogger;
48 import io.netty.util.internal.logging.InternalLoggerFactory;
49
50 import java.io.IOException;
51 import java.net.SocketAddress;
52 import java.nio.channels.ClosedChannelException;
53 import java.util.ArrayDeque;
54 import java.util.Map;
55 import java.util.Queue;
56 import java.util.concurrent.RejectedExecutionException;
57 import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
58 import java.util.concurrent.atomic.AtomicLongFieldUpdater;
59
60 import static io.netty.handler.codec.http2.Http2CodecUtil.isStreamIdValid;
61 import static io.netty.util.internal.ObjectUtil.checkNotNull;
62 import static java.lang.Math.min;
63
64 abstract class AbstractHttp2StreamChannel extends DefaultAttributeMap implements Http2StreamChannel {
65
66 static final Http2FrameStreamVisitor WRITABLE_VISITOR = new Http2FrameStreamVisitor() {
67 @Override
68 public boolean visit(Http2FrameStream stream) {
69 final AbstractHttp2StreamChannel childChannel = (AbstractHttp2StreamChannel)
70 ((DefaultHttp2FrameStream) stream).attachment;
71 childChannel.trySetWritable();
72 return true;
73 }
74 };
75
76 static final Http2FrameStreamVisitor CHANNEL_INPUT_SHUTDOWN_READ_COMPLETE_VISITOR =
77 new UserEventStreamVisitor(ChannelInputShutdownReadComplete.INSTANCE);
78
79 static final Http2FrameStreamVisitor CHANNEL_OUTPUT_SHUTDOWN_EVENT_VISITOR =
80 new UserEventStreamVisitor(ChannelOutputShutdownEvent.INSTANCE);
81
82 static final Http2FrameStreamVisitor SSL_CLOSE_COMPLETION_EVENT_VISITOR =
83 new UserEventStreamVisitor(SslCloseCompletionEvent.SUCCESS);
84
85 private static final InternalLogger logger = InternalLoggerFactory.getInstance(AbstractHttp2StreamChannel.class);
86
87 private static final ChannelMetadata METADATA = new ChannelMetadata(false, 16);
88
89
90
91
92
93 private static final int MIN_HTTP2_FRAME_SIZE = 9;
94
95
96
97
98 private static final class UserEventStreamVisitor implements Http2FrameStreamVisitor {
99
100 private final Object event;
101
102 UserEventStreamVisitor(Object event) {
103 this.event = checkNotNull(event, "event");
104 }
105
106 @Override
107 public boolean visit(Http2FrameStream stream) {
108 final AbstractHttp2StreamChannel childChannel = (AbstractHttp2StreamChannel)
109 ((DefaultHttp2FrameStream) stream).attachment;
110 childChannel.pipeline().fireUserEventTriggered(event);
111 return true;
112 }
113 }
114
115
116
117
118 private static final class FlowControlledFrameSizeEstimator implements MessageSizeEstimator {
119
120 static final FlowControlledFrameSizeEstimator INSTANCE = new FlowControlledFrameSizeEstimator();
121
122 private static final Handle HANDLE_INSTANCE = new Handle() {
123 @Override
124 public int size(Object msg) {
125 return msg instanceof Http2DataFrame ?
126
127 (int) min(Integer.MAX_VALUE, ((Http2DataFrame) msg).initialFlowControlledBytes() +
128 (long) MIN_HTTP2_FRAME_SIZE) : MIN_HTTP2_FRAME_SIZE;
129 }
130 };
131
132 @Override
133 public Handle newHandle() {
134 return HANDLE_INSTANCE;
135 }
136 }
137
138 private static final AtomicLongFieldUpdater<AbstractHttp2StreamChannel> TOTAL_PENDING_SIZE_UPDATER =
139 AtomicLongFieldUpdater.newUpdater(AbstractHttp2StreamChannel.class, "totalPendingSize");
140
141 private static final AtomicIntegerFieldUpdater<AbstractHttp2StreamChannel> UNWRITABLE_UPDATER =
142 AtomicIntegerFieldUpdater.newUpdater(AbstractHttp2StreamChannel.class, "unwritable");
143
144 private static void windowUpdateFrameWriteComplete(ChannelFuture future, Channel streamChannel) {
145 Throwable cause = future.cause();
146 if (cause != null) {
147 Throwable unwrappedCause;
148
149 if (cause instanceof Http2FrameStreamException && (unwrappedCause = cause.getCause()) != null) {
150 cause = unwrappedCause;
151 }
152
153
154 streamChannel.pipeline().fireExceptionCaught(cause);
155 streamChannel.unsafe().close(streamChannel.unsafe().voidPromise());
156 }
157 }
158
159 private final ChannelFutureListener windowUpdateFrameWriteListener = new ChannelFutureListener() {
160 @Override
161 public void operationComplete(ChannelFuture future) {
162 windowUpdateFrameWriteComplete(future, AbstractHttp2StreamChannel.this);
163 }
164 };
165
166
167
168
169 private enum ReadStatus {
170
171
172
173 IDLE,
174
175
176
177
178 IN_PROGRESS,
179
180
181
182
183 REQUESTED
184 }
185
186 private final Http2StreamChannelConfig config = new Http2StreamChannelConfig(this);
187 private final Http2ChannelUnsafe unsafe = new Http2ChannelUnsafe();
188 private final Http2StreamChannelId channelId;
189 private final ChannelPipeline pipeline;
190 private final DefaultHttp2FrameStream stream;
191 private final ChannelPromise closePromise;
192
193 private volatile boolean registered;
194
195 private volatile long totalPendingSize;
196 private volatile int unwritable;
197
198
199 private Runnable fireChannelWritabilityChangedTask;
200
201 private boolean outboundClosed;
202 private int flowControlledBytes;
203
204
205
206
207
208
209
210 private ReadStatus readStatus = ReadStatus.IDLE;
211
212 private Queue<Object> inboundBuffer;
213
214
215 private boolean firstFrameWritten;
216 private boolean readCompletePending;
217
218 AbstractHttp2StreamChannel(DefaultHttp2FrameStream stream, int id, ChannelHandler inboundHandler) {
219 this.stream = stream;
220 stream.attachment = this;
221 pipeline = new DefaultChannelPipeline(this) {
222 @Override
223 protected void incrementPendingOutboundBytes(long size) {
224 AbstractHttp2StreamChannel.this.incrementPendingOutboundBytes(size, true);
225 }
226
227 @Override
228 protected void decrementPendingOutboundBytes(long size) {
229 AbstractHttp2StreamChannel.this.decrementPendingOutboundBytes(size, true);
230 }
231
232 @Override
233 protected void onUnhandledInboundException(Throwable cause) {
234
235 if (cause instanceof Http2FrameStreamException) {
236 closeWithError(((Http2FrameStreamException) cause).error());
237 return;
238 } else {
239 Http2Exception exception = Http2CodecUtil.getEmbeddedHttp2Exception(cause);
240 if (exception != null) {
241 closeWithError(exception.error());
242 return;
243 }
244 }
245 super.onUnhandledInboundException(cause);
246 }
247 };
248
249 closePromise = pipeline.newPromise();
250 channelId = new Http2StreamChannelId(parent().id(), id);
251
252 if (inboundHandler != null) {
253
254 pipeline.addLast(inboundHandler);
255 }
256 }
257
258 private void incrementPendingOutboundBytes(long size, boolean invokeLater) {
259 if (size == 0) {
260 return;
261 }
262
263 long newWriteBufferSize = TOTAL_PENDING_SIZE_UPDATER.addAndGet(this, size);
264 if (newWriteBufferSize > config().getWriteBufferHighWaterMark()) {
265 setUnwritable(invokeLater);
266 }
267 }
268
269 private void decrementPendingOutboundBytes(long size, boolean invokeLater) {
270 if (size == 0) {
271 return;
272 }
273
274 long newWriteBufferSize = TOTAL_PENDING_SIZE_UPDATER.addAndGet(this, -size);
275
276
277
278
279
280 if (newWriteBufferSize < config().getWriteBufferLowWaterMark() && parent().isWritable()) {
281 setWritable(invokeLater);
282 }
283 }
284
285 final void trySetWritable() {
286
287
288
289
290 if (totalPendingSize < config().getWriteBufferLowWaterMark()) {
291 setWritable(false);
292 }
293 }
294
295 private void setWritable(boolean invokeLater) {
296 for (;;) {
297 final int oldValue = unwritable;
298 final int newValue = oldValue & ~1;
299 if (UNWRITABLE_UPDATER.compareAndSet(this, oldValue, newValue)) {
300 if (oldValue != 0 && newValue == 0) {
301 fireChannelWritabilityChanged(invokeLater);
302 }
303 break;
304 }
305 }
306 }
307
308 private void setUnwritable(boolean invokeLater) {
309 for (;;) {
310 final int oldValue = unwritable;
311 final int newValue = oldValue | 1;
312 if (UNWRITABLE_UPDATER.compareAndSet(this, oldValue, newValue)) {
313 if (oldValue == 0) {
314 fireChannelWritabilityChanged(invokeLater);
315 }
316 break;
317 }
318 }
319 }
320
321 private void fireChannelWritabilityChanged(boolean invokeLater) {
322 final ChannelPipeline pipeline = pipeline();
323 if (invokeLater) {
324 Runnable task = fireChannelWritabilityChangedTask;
325 if (task == null) {
326 fireChannelWritabilityChangedTask = task = new Runnable() {
327 @Override
328 public void run() {
329 pipeline.fireChannelWritabilityChanged();
330 }
331 };
332 }
333 eventLoop().execute(task);
334 } else {
335 pipeline.fireChannelWritabilityChanged();
336 }
337 }
338 @Override
339 public Http2FrameStream stream() {
340 return stream;
341 }
342
343 void closeOutbound() {
344 outboundClosed = true;
345 }
346
347 void streamClosed() {
348 unsafe.readEOS();
349
350
351 unsafe.doBeginRead();
352 }
353
354 @Override
355 public ChannelMetadata metadata() {
356 return METADATA;
357 }
358
359 @Override
360 public ChannelConfig config() {
361 return config;
362 }
363
364 @Override
365 public boolean isOpen() {
366 return !closePromise.isDone();
367 }
368
369 @Override
370 public boolean isActive() {
371 return isOpen();
372 }
373
374 @Override
375 public boolean isWritable() {
376 return unwritable == 0;
377 }
378
379 @Override
380 public ChannelId id() {
381 return channelId;
382 }
383
384 @Override
385 public EventLoop eventLoop() {
386 return parent().eventLoop();
387 }
388
389 @Override
390 public Channel parent() {
391 return parentContext().channel();
392 }
393
394 @Override
395 public boolean isRegistered() {
396 return registered;
397 }
398
399 @Override
400 public SocketAddress localAddress() {
401 return parent().localAddress();
402 }
403
404 @Override
405 public SocketAddress remoteAddress() {
406 return parent().remoteAddress();
407 }
408
409 @Override
410 public ChannelFuture closeFuture() {
411 return closePromise;
412 }
413
414 @Override
415 public long bytesBeforeUnwritable() {
416
417 long bytes = config().getWriteBufferHighWaterMark() - totalPendingSize + 1;
418
419
420
421 return bytes > 0 && isWritable() ? bytes : 0;
422 }
423
424 @Override
425 public long bytesBeforeWritable() {
426
427 long bytes = totalPendingSize - config().getWriteBufferLowWaterMark() + 1;
428
429
430
431 return bytes <= 0 || isWritable() ? 0 : bytes;
432 }
433
434 @Override
435 public Unsafe unsafe() {
436 return unsafe;
437 }
438
439 @Override
440 public ChannelPipeline pipeline() {
441 return pipeline;
442 }
443
444 @Override
445 public ByteBufAllocator alloc() {
446 return config().getAllocator();
447 }
448
449 @Override
450 public Channel read() {
451 pipeline().read();
452 return this;
453 }
454
455 @Override
456 public Channel flush() {
457 pipeline().flush();
458 return this;
459 }
460
461 @Override
462 public ChannelFuture bind(SocketAddress localAddress) {
463 return pipeline().bind(localAddress);
464 }
465
466 @Override
467 public ChannelFuture connect(SocketAddress remoteAddress) {
468 return pipeline().connect(remoteAddress);
469 }
470
471 @Override
472 public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) {
473 return pipeline().connect(remoteAddress, localAddress);
474 }
475
476 @Override
477 public ChannelFuture disconnect() {
478 return pipeline().disconnect();
479 }
480
481 @Override
482 public ChannelFuture close() {
483 return pipeline().close();
484 }
485
486 @Override
487 public ChannelFuture deregister() {
488 return pipeline().deregister();
489 }
490
491 @Override
492 public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
493 return pipeline().bind(localAddress, promise);
494 }
495
496 @Override
497 public ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise) {
498 return pipeline().connect(remoteAddress, promise);
499 }
500
501 @Override
502 public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {
503 return pipeline().connect(remoteAddress, localAddress, promise);
504 }
505
506 @Override
507 public ChannelFuture disconnect(ChannelPromise promise) {
508 return pipeline().disconnect(promise);
509 }
510
511 @Override
512 public ChannelFuture close(ChannelPromise promise) {
513 return pipeline().close(promise);
514 }
515
516 @Override
517 public ChannelFuture deregister(ChannelPromise promise) {
518 return pipeline().deregister(promise);
519 }
520
521 @Override
522 public ChannelFuture write(Object msg) {
523 return pipeline().write(msg);
524 }
525
526 @Override
527 public ChannelFuture write(Object msg, ChannelPromise promise) {
528 return pipeline().write(msg, promise);
529 }
530
531 @Override
532 public ChannelFuture writeAndFlush(Object msg, ChannelPromise promise) {
533 return pipeline().writeAndFlush(msg, promise);
534 }
535
536 @Override
537 public ChannelFuture writeAndFlush(Object msg) {
538 return pipeline().writeAndFlush(msg);
539 }
540
541 @Override
542 public ChannelPromise newPromise() {
543 return pipeline().newPromise();
544 }
545
546 @Override
547 public ChannelProgressivePromise newProgressivePromise() {
548 return pipeline().newProgressivePromise();
549 }
550
551 @Override
552 public ChannelFuture newSucceededFuture() {
553 return pipeline().newSucceededFuture();
554 }
555
556 @Override
557 public ChannelFuture newFailedFuture(Throwable cause) {
558 return pipeline().newFailedFuture(cause);
559 }
560
561 @Override
562 public ChannelPromise voidPromise() {
563 return pipeline().voidPromise();
564 }
565
566 @Override
567 public int hashCode() {
568 return id().hashCode();
569 }
570
571 @Override
572 public boolean equals(Object o) {
573 return this == o;
574 }
575
576 @Override
577 public int compareTo(Channel o) {
578 if (this == o) {
579 return 0;
580 }
581
582 return id().compareTo(o.id());
583 }
584
585 @Override
586 public String toString() {
587 return parent().toString() + '/' + channelId.getSequenceId() + " (H2 - " + stream + ')';
588 }
589
590 void fireChildExceptionCaught(Throwable cause) {
591 pipeline().fireExceptionCaught(cause);
592 }
593
594 void fireChildUserEventTriggered(Object evt) {
595 pipeline().fireUserEventTriggered(evt);
596 }
597
598
599
600
601
602 void fireChildRead(Http2Frame frame) {
603 assert eventLoop().inEventLoop();
604 if (!isActive()) {
605 ReferenceCountUtil.release(frame);
606 } else if (readStatus != ReadStatus.IDLE && isInboundBufferEmpty()) {
607
608
609
610
611 final RecvByteBufAllocator.Handle allocHandle = unsafe.recvBufAllocHandle();
612
613 unsafe.doRead0(frame, allocHandle);
614
615
616
617
618 if (allocHandle.continueReading()) {
619 maybeAddChannelToReadCompletePendingQueue();
620 } else {
621 unsafe.notifyReadComplete(allocHandle, true, false);
622 }
623 } else {
624 if (inboundBuffer == null) {
625 inboundBuffer = new ArrayDeque<Object>(4);
626 }
627 inboundBuffer.add(frame);
628 }
629 }
630
631 private boolean isInboundBufferEmpty() {
632 return inboundBuffer == null || inboundBuffer.isEmpty();
633 }
634
635 void fireChildReadComplete() {
636 assert eventLoop().inEventLoop();
637 assert readStatus != ReadStatus.IDLE || !readCompletePending;
638 unsafe.notifyReadComplete(unsafe.recvBufAllocHandle(), false, false);
639 }
640
641 final void closeWithError(Http2Error error) {
642 assert eventLoop().inEventLoop();
643 unsafe.close(unsafe.voidPromise(), error);
644 }
645
646 private final class Http2ChannelUnsafe implements Unsafe {
647 private final VoidChannelPromise unsafeVoidPromise =
648 new VoidChannelPromise(AbstractHttp2StreamChannel.this, false);
649 @SuppressWarnings("deprecation")
650 private RecvByteBufAllocator.Handle recvHandle;
651 private boolean writeDoneAndNoFlush;
652 private boolean closeInitiated;
653 private boolean readEOS;
654
655 private boolean receivedEndOfStream;
656 private boolean sentEndOfStream;
657
658 @Override
659 public void connect(final SocketAddress remoteAddress,
660 SocketAddress localAddress, final ChannelPromise promise) {
661 if (!promise.setUncancellable()) {
662 return;
663 }
664 promise.setFailure(new UnsupportedOperationException());
665 }
666
667 @Override
668 public RecvByteBufAllocator.Handle recvBufAllocHandle() {
669 if (recvHandle == null) {
670 recvHandle = config().getRecvByteBufAllocator().newHandle();
671 recvHandle.reset(config());
672 }
673 return recvHandle;
674 }
675
676 @Override
677 public SocketAddress localAddress() {
678 return parent().unsafe().localAddress();
679 }
680
681 @Override
682 public SocketAddress remoteAddress() {
683 return parent().unsafe().remoteAddress();
684 }
685
686 @Override
687 public void register(EventLoop eventLoop, ChannelPromise promise) {
688 if (!promise.setUncancellable()) {
689 return;
690 }
691 if (registered) {
692 promise.setFailure(new UnsupportedOperationException("Re-register is not supported"));
693 return;
694 }
695
696 registered = true;
697
698 promise.setSuccess();
699
700 pipeline().fireChannelRegistered();
701 if (isActive()) {
702 pipeline().fireChannelActive();
703 }
704 }
705
706 @Override
707 public void bind(SocketAddress localAddress, ChannelPromise promise) {
708 if (!promise.setUncancellable()) {
709 return;
710 }
711 promise.setFailure(new UnsupportedOperationException());
712 }
713
714 @Override
715 public void disconnect(ChannelPromise promise) {
716 close(promise);
717 }
718
719 @Override
720 public void close(final ChannelPromise promise) {
721 close(promise, null);
722 }
723
724 private void close(final ChannelPromise promise, Http2Error error) {
725 if (!promise.setUncancellable()) {
726 return;
727 }
728 if (closeInitiated) {
729 if (closePromise.isDone()) {
730
731 promise.setSuccess();
732 } else if (!(promise instanceof VoidChannelPromise)) {
733
734 closePromise.addListener(new ChannelFutureListener() {
735 @Override
736 public void operationComplete(ChannelFuture future) {
737 promise.setSuccess();
738 }
739 });
740 }
741 return;
742 }
743 closeInitiated = true;
744
745 readCompletePending = false;
746
747 final boolean wasActive = isActive();
748
749
750
751
752
753
754 if (parent().isActive() && isStreamIdValid(stream.id())) {
755
756
757 if (error == null) {
758 if (!readEOS && !(receivedEndOfStream && sentEndOfStream)) {
759 Http2StreamFrame resetFrame = new DefaultHttp2ResetFrame(Http2Error.CANCEL).stream(stream());
760 write(resetFrame, unsafe().voidPromise());
761 flush();
762 }
763 } else {
764
765 Http2StreamFrame resetFrame = new DefaultHttp2ResetFrame(error).stream(stream());
766 write(resetFrame, unsafe().voidPromise());
767 flush();
768 }
769 }
770
771 if (inboundBuffer != null) {
772 for (;;) {
773 Object msg = inboundBuffer.poll();
774 if (msg == null) {
775 break;
776 }
777 ReferenceCountUtil.release(msg);
778 }
779 inboundBuffer = null;
780 }
781
782
783 outboundClosed = true;
784 closePromise.setSuccess();
785 promise.setSuccess();
786
787 fireChannelInactiveAndDeregister(voidPromise(), wasActive);
788 }
789
790 @Override
791 public void closeForcibly() {
792 close(unsafe().voidPromise());
793 }
794
795 @Override
796 public void deregister(ChannelPromise promise) {
797 fireChannelInactiveAndDeregister(promise, false);
798 }
799
800 private void fireChannelInactiveAndDeregister(final ChannelPromise promise,
801 final boolean fireChannelInactive) {
802 if (!promise.setUncancellable()) {
803 return;
804 }
805
806 if (!registered) {
807 promise.setSuccess();
808 return;
809 }
810
811
812
813
814
815
816
817
818 invokeLater(promise.channel(), new Runnable() {
819 @Override
820 public void run() {
821 if (fireChannelInactive) {
822 pipeline.fireChannelInactive();
823 }
824
825
826 if (registered) {
827 registered = false;
828 pipeline.fireChannelUnregistered();
829 }
830 safeSetSuccess(promise);
831 }
832 });
833 }
834
835 private void safeSetSuccess(ChannelPromise promise) {
836 if (!(promise instanceof VoidChannelPromise) && !promise.trySuccess()) {
837 logger.warn("{} Failed to mark a promise as success because it is done already: {}",
838 promise.channel(), promise);
839 }
840 }
841
842 private void invokeLater(Channel channel, Runnable task) {
843 try {
844
845
846
847
848
849
850
851
852
853
854
855 eventLoop().execute(task);
856 } catch (RejectedExecutionException e) {
857 logger.warn("{} Can't invoke task later as EventLoop rejected it", channel, e);
858 }
859 }
860
861 @Override
862 public void beginRead() {
863 if (!isActive()) {
864 return;
865 }
866 final boolean windowUpdated = updateLocalWindowIfNeeded();
867
868 switch (readStatus) {
869 case IDLE:
870 readStatus = ReadStatus.IN_PROGRESS;
871
872 doBeginRead();
873 return;
874 case IN_PROGRESS:
875 readStatus = ReadStatus.REQUESTED;
876 break;
877 default:
878 break;
879 }
880 if (windowUpdated) {
881
882
883
884
885
886
887
888
889
890
891
892
893 if (isParentReadInProgress()) {
894 maybeAddChannelToReadCompletePendingQueue();
895 } else {
896 flush();
897 }
898 }
899 }
900
901 private Object pollQueuedMessage() {
902 return inboundBuffer == null ? null : inboundBuffer.poll();
903 }
904
905 void doBeginRead() {
906 if (readStatus == ReadStatus.IDLE) {
907
908 if (readEOS && isInboundBufferEmpty()) {
909
910 flush();
911 closeIfReadEOSAndDrained();
912 }
913 } else {
914 do {
915 Object message = pollQueuedMessage();
916 if (message == null) {
917
918 flush();
919 if (!isInboundBufferEmpty()) {
920
921
922 continue;
923 }
924 closeIfReadEOSAndDrained();
925 break;
926 }
927 final RecvByteBufAllocator.Handle allocHandle = recvBufAllocHandle();
928 allocHandle.reset(config());
929 boolean continueReading = false;
930 do {
931 doRead0((Http2Frame) message, allocHandle);
932 } while ((readEOS || (continueReading = allocHandle.continueReading()))
933 && (message = pollQueuedMessage()) != null);
934
935 if (continueReading && isParentReadInProgress() && !readEOS) {
936
937
938
939
940 maybeAddChannelToReadCompletePendingQueue();
941 } else {
942 notifyReadComplete(allocHandle, true, true);
943
944
945
946
947 resetReadStatus();
948 }
949 } while (readStatus != ReadStatus.IDLE);
950 }
951 }
952
953 void readEOS() {
954 readEOS = true;
955 }
956
957 private boolean updateLocalWindowIfNeeded() {
958 if (flowControlledBytes != 0 && !parentContext().isRemoved() && config.autoStreamFlowControl) {
959 int bytes = flowControlledBytes;
960 flowControlledBytes = 0;
961 writeWindowUpdateFrame(new DefaultHttp2WindowUpdateFrame(bytes).stream(stream));
962 return true;
963 }
964 return false;
965 }
966
967 void updateLocalWindowIfNeededAndFlush() {
968 if (updateLocalWindowIfNeeded()) {
969 flush();
970 }
971 }
972
973 private void resetReadStatus() {
974 readStatus = readStatus == ReadStatus.REQUESTED ? ReadStatus.IN_PROGRESS : ReadStatus.IDLE;
975 }
976
977 void notifyReadComplete(RecvByteBufAllocator.Handle allocHandle, boolean forceReadComplete,
978 boolean inReadLoop) {
979 if (!readCompletePending && !forceReadComplete) {
980 return;
981 }
982
983 readCompletePending = false;
984
985 if (!inReadLoop) {
986
987 resetReadStatus();
988 }
989
990 allocHandle.readComplete();
991 pipeline().fireChannelReadComplete();
992
993
994
995 flush();
996 closeIfReadEOSAndDrained();
997 }
998
999 private void closeIfReadEOSAndDrained() {
1000
1001
1002
1003 if (readEOS && isInboundBufferEmpty()) {
1004 closeForcibly();
1005 }
1006 }
1007
1008 @SuppressWarnings("deprecation")
1009 void doRead0(Http2Frame frame, RecvByteBufAllocator.Handle allocHandle) {
1010 final int bytes;
1011 if (frame instanceof Http2DataFrame) {
1012 bytes = ((Http2DataFrame) frame).initialFlowControlledBytes();
1013
1014
1015
1016
1017
1018 flowControlledBytes += bytes;
1019 } else {
1020 bytes = MIN_HTTP2_FRAME_SIZE;
1021 }
1022
1023
1024
1025 receivedEndOfStream |= isEndOfStream(frame);
1026
1027
1028 allocHandle.attemptedBytesRead(bytes);
1029 allocHandle.lastBytesRead(bytes);
1030 allocHandle.incMessagesRead(1);
1031
1032 pipeline().fireChannelRead(frame);
1033 }
1034
1035 private ChannelFuture writeWindowUpdateFrame(Http2WindowUpdateFrame windowUpdateFrame) {
1036 ChannelFuture future = write0(parentContext(), windowUpdateFrame);
1037
1038
1039
1040 writeDoneAndNoFlush = true;
1041
1042
1043
1044
1045 if (future.isDone()) {
1046 windowUpdateFrameWriteComplete(future, AbstractHttp2StreamChannel.this);
1047 } else {
1048 future.addListener(windowUpdateFrameWriteListener);
1049 }
1050 return future;
1051 }
1052
1053 @Override
1054 public void write(Object msg, final ChannelPromise promise) {
1055
1056 if (!promise.setUncancellable()) {
1057 ReferenceCountUtil.release(msg);
1058 return;
1059 }
1060
1061 if (!isActive() ||
1062
1063 outboundClosed && (msg instanceof Http2HeadersFrame || msg instanceof Http2DataFrame)) {
1064 ReferenceCountUtil.release(msg);
1065 promise.setFailure(new ClosedChannelException());
1066 return;
1067 }
1068
1069 try {
1070 if (msg instanceof Http2StreamFrame) {
1071 Http2StreamFrame frame = validateStreamFrame((Http2StreamFrame) msg).stream(stream());
1072 if (msg instanceof Http2WindowUpdateFrame) {
1073 Http2WindowUpdateFrame updateFrame = (Http2WindowUpdateFrame) msg;
1074 if (config.autoStreamFlowControl) {
1075 ReferenceCountUtil.release(msg);
1076 promise.setFailure(new UnsupportedOperationException(
1077 Http2StreamChannelOption.AUTO_STREAM_FLOW_CONTROL + " is set to false"));
1078 return;
1079 }
1080 try {
1081 ObjectUtil.checkInRange(updateFrame.windowSizeIncrement(), 0,
1082 flowControlledBytes, "windowSizeIncrement");
1083 } catch (RuntimeException e) {
1084 ReferenceCountUtil.release(updateFrame);
1085 promise.setFailure(e);
1086 return;
1087 }
1088 flowControlledBytes -= updateFrame.windowSizeIncrement();
1089 if (parentContext().isRemoved()) {
1090 ReferenceCountUtil.release(msg);
1091 promise.setFailure(new ClosedChannelException());
1092 return;
1093 }
1094 ChannelFuture f = writeWindowUpdateFrame(updateFrame);
1095 if (f.isDone()) {
1096 writeComplete(f, promise);
1097 } else {
1098 f.addListener(new ChannelFutureListener() {
1099 @Override
1100 public void operationComplete(ChannelFuture future) {
1101 writeComplete(future, promise);
1102 }
1103 });
1104 }
1105 } else {
1106 writeHttp2StreamFrame(frame, promise);
1107 }
1108 } else {
1109 String msgStr = msg.toString();
1110 ReferenceCountUtil.release(msg);
1111 promise.setFailure(new IllegalArgumentException(
1112 "Message must be an " + StringUtil.simpleClassName(Http2StreamFrame.class) +
1113 ": " + msgStr));
1114 }
1115 } catch (Throwable t) {
1116 promise.tryFailure(t);
1117 }
1118 }
1119
1120 private boolean isEndOfStream(Http2Frame frame) {
1121 if (frame instanceof Http2HeadersFrame) {
1122 return ((Http2HeadersFrame) frame).isEndStream();
1123 }
1124 if (frame instanceof Http2DataFrame) {
1125 return ((Http2DataFrame) frame).isEndStream();
1126 }
1127 return false;
1128 }
1129
1130 private void writeHttp2StreamFrame(Http2StreamFrame frame, final ChannelPromise promise) {
1131 if (!firstFrameWritten && !isStreamIdValid(stream().id()) && !(frame instanceof Http2HeadersFrame)) {
1132 ReferenceCountUtil.release(frame);
1133 promise.setFailure(
1134 new IllegalArgumentException("The first frame must be a headers frame. Was: "
1135 + frame.name()));
1136 return;
1137 }
1138
1139 final boolean firstWrite;
1140 if (firstFrameWritten) {
1141 firstWrite = false;
1142 } else {
1143 firstWrite = firstFrameWritten = true;
1144 }
1145
1146
1147
1148 sentEndOfStream |= isEndOfStream(frame);
1149 ChannelFuture f = write0(parentContext(), frame);
1150 if (f.isDone()) {
1151 if (firstWrite) {
1152 firstWriteComplete(f, promise);
1153 } else {
1154 writeComplete(f, promise);
1155 }
1156 } else {
1157 final long bytes = FlowControlledFrameSizeEstimator.HANDLE_INSTANCE.size(frame);
1158 incrementPendingOutboundBytes(bytes, false);
1159 f.addListener(new ChannelFutureListener() {
1160 @Override
1161 public void operationComplete(ChannelFuture future) {
1162 if (firstWrite) {
1163 firstWriteComplete(future, promise);
1164 } else {
1165 writeComplete(future, promise);
1166 }
1167 decrementPendingOutboundBytes(bytes, false);
1168 }
1169 });
1170 writeDoneAndNoFlush = true;
1171 }
1172 }
1173
1174 private void firstWriteComplete(ChannelFuture future, ChannelPromise promise) {
1175 Throwable cause = future.cause();
1176 if (cause == null) {
1177 promise.setSuccess();
1178 } else {
1179
1180 closeForcibly();
1181 promise.setFailure(wrapStreamClosedError(cause));
1182 }
1183 }
1184
1185 private void writeComplete(ChannelFuture future, ChannelPromise promise) {
1186 Throwable cause = future.cause();
1187 if (cause == null) {
1188 promise.setSuccess();
1189 } else {
1190 Throwable error = wrapStreamClosedError(cause);
1191
1192 if (error instanceof IOException) {
1193 if (config.isAutoClose()) {
1194
1195 closeForcibly();
1196 } else {
1197
1198 outboundClosed = true;
1199 }
1200 }
1201 promise.setFailure(error);
1202 }
1203 }
1204
1205 private Throwable wrapStreamClosedError(Throwable cause) {
1206
1207
1208 if (cause instanceof Http2Exception && ((Http2Exception) cause).error() == Http2Error.STREAM_CLOSED) {
1209 return new ClosedChannelException().initCause(cause);
1210 }
1211 return cause;
1212 }
1213
1214 private Http2StreamFrame validateStreamFrame(Http2StreamFrame frame) {
1215 if (frame.stream() != null && frame.stream() != stream) {
1216 String msgString = frame.toString();
1217 ReferenceCountUtil.release(frame);
1218 throw new IllegalArgumentException(
1219 "Stream " + frame.stream() + " must not be set on the frame: " + msgString);
1220 }
1221 return frame;
1222 }
1223
1224 @Override
1225 public void flush() {
1226
1227
1228
1229
1230 if (!writeDoneAndNoFlush || isParentReadInProgress()) {
1231
1232 return;
1233 }
1234
1235
1236 writeDoneAndNoFlush = false;
1237 flush0(parentContext());
1238 }
1239
1240 @Override
1241 public ChannelPromise voidPromise() {
1242 return unsafeVoidPromise;
1243 }
1244
1245 @Override
1246 public ChannelOutboundBuffer outboundBuffer() {
1247
1248 return null;
1249 }
1250 }
1251
1252
1253
1254
1255
1256
1257 private static final class Http2StreamChannelConfig extends DefaultChannelConfig {
1258
1259 volatile boolean autoStreamFlowControl = true;
1260 Http2StreamChannelConfig(Channel channel) {
1261 super(channel);
1262 }
1263
1264 @Override
1265 public MessageSizeEstimator getMessageSizeEstimator() {
1266 return FlowControlledFrameSizeEstimator.INSTANCE;
1267 }
1268
1269 @Override
1270 public ChannelConfig setMessageSizeEstimator(MessageSizeEstimator estimator) {
1271 throw new UnsupportedOperationException();
1272 }
1273
1274 @Override
1275 public ChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator) {
1276 if (!(allocator.newHandle() instanceof RecvByteBufAllocator.ExtendedHandle)) {
1277 throw new IllegalArgumentException("allocator.newHandle() must return an object of type: " +
1278 RecvByteBufAllocator.ExtendedHandle.class);
1279 }
1280 super.setRecvByteBufAllocator(allocator);
1281 return this;
1282 }
1283
1284 @Override
1285 public Map<ChannelOption<?>, Object> getOptions() {
1286 return getOptions(
1287 super.getOptions(),
1288 Http2StreamChannelOption.AUTO_STREAM_FLOW_CONTROL);
1289 }
1290
1291 @SuppressWarnings("unchecked")
1292 @Override
1293 public <T> T getOption(ChannelOption<T> option) {
1294 if (option == Http2StreamChannelOption.AUTO_STREAM_FLOW_CONTROL) {
1295 return (T) Boolean.valueOf(autoStreamFlowControl);
1296 }
1297 return super.getOption(option);
1298 }
1299
1300 @Override
1301 public <T> boolean setOption(ChannelOption<T> option, T value) {
1302 validate(option, value);
1303 if (option == Http2StreamChannelOption.AUTO_STREAM_FLOW_CONTROL) {
1304 boolean newValue = (Boolean) value;
1305 boolean changed = newValue && !autoStreamFlowControl;
1306 autoStreamFlowControl = (Boolean) value;
1307 if (changed) {
1308 if (channel.isRegistered()) {
1309 final Http2ChannelUnsafe unsafe = (Http2ChannelUnsafe) channel.unsafe();
1310 if (channel.eventLoop().inEventLoop()) {
1311 unsafe.updateLocalWindowIfNeededAndFlush();
1312 } else {
1313 channel.eventLoop().execute(new Runnable() {
1314 @Override
1315 public void run() {
1316 unsafe.updateLocalWindowIfNeededAndFlush();
1317 }
1318 });
1319 }
1320 }
1321 }
1322 return true;
1323 }
1324 return super.setOption(option, value);
1325 }
1326 }
1327
1328 private void maybeAddChannelToReadCompletePendingQueue() {
1329 if (!readCompletePending) {
1330 readCompletePending = true;
1331 addChannelToReadCompletePendingQueue();
1332 }
1333 }
1334
1335 protected void flush0(ChannelHandlerContext ctx) {
1336 ctx.flush();
1337 }
1338
1339 protected ChannelFuture write0(ChannelHandlerContext ctx, Object msg) {
1340 ChannelPromise promise = ctx.newPromise();
1341 ctx.write(msg, promise);
1342 return promise;
1343 }
1344
1345 protected abstract boolean isParentReadInProgress();
1346 protected abstract void addChannelToReadCompletePendingQueue();
1347 protected abstract ChannelHandlerContext parentContext();
1348 }