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