1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package io.netty.handler.codec.http2;
16
17 import io.netty.buffer.ByteBuf;
18 import io.netty.buffer.ByteBufUtil;
19 import io.netty.buffer.Unpooled;
20 import io.netty.channel.ChannelFuture;
21 import io.netty.channel.ChannelFutureListener;
22 import io.netty.channel.ChannelHandlerContext;
23 import io.netty.channel.ChannelOutboundHandler;
24 import io.netty.channel.ChannelPromise;
25 import io.netty.handler.codec.ByteToMessageDecoder;
26 import io.netty.handler.codec.http.HttpResponseStatus;
27 import io.netty.handler.codec.http2.Http2Exception.CompositeStreamException;
28 import io.netty.handler.codec.http2.Http2Exception.StreamException;
29 import io.netty.util.CharsetUtil;
30 import io.netty.util.concurrent.Future;
31 import io.netty.util.internal.logging.InternalLogger;
32 import io.netty.util.internal.logging.InternalLoggerFactory;
33
34 import java.net.SocketAddress;
35 import java.util.List;
36 import java.util.concurrent.TimeUnit;
37
38 import static io.netty.buffer.ByteBufUtil.hexDump;
39 import static io.netty.buffer.Unpooled.EMPTY_BUFFER;
40 import static io.netty.handler.codec.http2.Http2CodecUtil.HTTP_UPGRADE_STREAM_ID;
41 import static io.netty.handler.codec.http2.Http2CodecUtil.connectionPrefaceBuf;
42 import static io.netty.handler.codec.http2.Http2CodecUtil.getEmbeddedHttp2Exception;
43 import static io.netty.handler.codec.http2.Http2Error.INTERNAL_ERROR;
44 import static io.netty.handler.codec.http2.Http2Error.NO_ERROR;
45 import static io.netty.handler.codec.http2.Http2Error.PROTOCOL_ERROR;
46 import static io.netty.handler.codec.http2.Http2Exception.connectionError;
47 import static io.netty.handler.codec.http2.Http2Exception.isStreamError;
48 import static io.netty.handler.codec.http2.Http2FrameTypes.SETTINGS;
49 import static io.netty.handler.codec.http2.Http2Stream.State.IDLE;
50 import static io.netty.util.CharsetUtil.UTF_8;
51 import static io.netty.util.internal.ObjectUtil.checkNotNull;
52 import static java.lang.Math.min;
53 import static java.util.concurrent.TimeUnit.MILLISECONDS;
54
55
56
57
58
59
60
61
62
63
64 public class Http2ConnectionHandler extends ByteToMessageDecoder implements Http2LifecycleManager,
65 ChannelOutboundHandler {
66
67 private static final InternalLogger logger = InternalLoggerFactory.getInstance(Http2ConnectionHandler.class);
68
69 private static final Http2Headers HEADERS_TOO_LARGE_HEADERS = ReadOnlyHttp2Headers.serverHeaders(false,
70 HttpResponseStatus.REQUEST_HEADER_FIELDS_TOO_LARGE.codeAsText());
71 private static final ByteBuf HTTP_1_X_BUF = Unpooled.unreleasableBuffer(
72 Unpooled.wrappedBuffer(new byte[] {'H', 'T', 'T', 'P', '/', '1', '.'})).asReadOnly();
73
74 private final Http2ConnectionDecoder decoder;
75 private final Http2ConnectionEncoder encoder;
76 private final Http2Settings initialSettings;
77 private final boolean decoupleCloseAndGoAway;
78 private final boolean flushPreface;
79 private ChannelFutureListener closeListener;
80 private BaseDecoder byteDecoder;
81 private long gracefulShutdownTimeoutMillis;
82 private boolean inFlush;
83 private boolean flushAgain;
84
85 protected Http2ConnectionHandler(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder,
86 Http2Settings initialSettings) {
87 this(decoder, encoder, initialSettings, false);
88 }
89
90 protected Http2ConnectionHandler(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder,
91 Http2Settings initialSettings, boolean decoupleCloseAndGoAway) {
92 this(decoder, encoder, initialSettings, decoupleCloseAndGoAway, true);
93 }
94
95 protected Http2ConnectionHandler(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder,
96 Http2Settings initialSettings, boolean decoupleCloseAndGoAway,
97 boolean flushPreface) {
98 this.initialSettings = checkNotNull(initialSettings, "initialSettings");
99 this.decoder = checkNotNull(decoder, "decoder");
100 this.encoder = checkNotNull(encoder, "encoder");
101 this.decoupleCloseAndGoAway = decoupleCloseAndGoAway;
102 this.flushPreface = flushPreface;
103 if (encoder.connection() != decoder.connection()) {
104 throw new IllegalArgumentException("Encoder and Decoder do not share the same connection object");
105 }
106 }
107
108
109
110
111
112
113 public long gracefulShutdownTimeoutMillis() {
114 return gracefulShutdownTimeoutMillis;
115 }
116
117
118
119
120
121
122
123 public void gracefulShutdownTimeoutMillis(long gracefulShutdownTimeoutMillis) {
124 if (gracefulShutdownTimeoutMillis < -1) {
125 throw new IllegalArgumentException("gracefulShutdownTimeoutMillis: " + gracefulShutdownTimeoutMillis +
126 " (expected: -1 for indefinite or >= 0)");
127 }
128 this.gracefulShutdownTimeoutMillis = gracefulShutdownTimeoutMillis;
129 }
130
131 public Http2Connection connection() {
132 return encoder.connection();
133 }
134
135 public Http2ConnectionDecoder decoder() {
136 return decoder;
137 }
138
139 public Http2ConnectionEncoder encoder() {
140 return encoder;
141 }
142
143 private boolean prefaceSent() {
144 return byteDecoder != null && byteDecoder.prefaceSent();
145 }
146
147
148
149
150
151 public void onHttpClientUpgrade() throws Http2Exception {
152 if (connection().isServer()) {
153 throw connectionError(PROTOCOL_ERROR, "Client-side HTTP upgrade requested for a server");
154 }
155 if (!prefaceSent()) {
156
157
158 throw connectionError(INTERNAL_ERROR, "HTTP upgrade must occur after preface was sent");
159 }
160 if (decoder.prefaceReceived()) {
161 throw connectionError(PROTOCOL_ERROR, "HTTP upgrade must occur before HTTP/2 preface is received");
162 }
163
164
165 connection().local().createStream(HTTP_UPGRADE_STREAM_ID, true);
166 }
167
168
169
170
171
172 public void onHttpServerUpgrade(Http2Settings settings) throws Http2Exception {
173 if (!connection().isServer()) {
174 throw connectionError(PROTOCOL_ERROR, "Server-side HTTP upgrade requested for a client");
175 }
176 if (!prefaceSent()) {
177
178
179 throw connectionError(INTERNAL_ERROR, "HTTP upgrade must occur after preface was sent");
180 }
181 if (decoder.prefaceReceived()) {
182 throw connectionError(PROTOCOL_ERROR, "HTTP upgrade must occur before HTTP/2 preface is received");
183 }
184
185
186 encoder.remoteSettings(settings);
187
188
189 connection().remote().createStream(HTTP_UPGRADE_STREAM_ID, true);
190 }
191
192 @Override
193 public void flush(ChannelHandlerContext ctx) {
194 if (inFlush) {
195
196
197 flushAgain = true;
198 return;
199 }
200 inFlush = true;
201 try {
202 do {
203 flushAgain = false;
204
205 encoder.flowController().writePendingBytes();
206 ctx.flush();
207
208
209
210 } while (flushAgain);
211 } catch (Http2Exception e) {
212 onError(ctx, true, e);
213 } catch (Throwable cause) {
214 onError(ctx, true, connectionError(INTERNAL_ERROR, cause, "Error flushing"));
215 } finally {
216 inFlush = false;
217 }
218 }
219
220 private boolean hasPendingData() {
221 final Http2RemoteFlowController flowController = encoder.flowController();
222 try {
223
224
225 return connection().forEachActiveStream(new Http2StreamVisitor() {
226 @Override
227 public boolean visit(Http2Stream stream) {
228 return !flowController.hasFlowControlled(stream);
229 }
230 }) != null;
231 } catch (Http2Exception e) {
232 return false;
233 }
234 }
235
236 private abstract class BaseDecoder {
237 public abstract void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception;
238 public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { }
239 public void channelActive(ChannelHandlerContext ctx) throws Exception { }
240
241 public void channelInactive(ChannelHandlerContext ctx) throws Exception {
242
243 encoder().close();
244 decoder().close();
245
246
247
248 connection().close(ctx.voidPromise());
249 }
250
251
252
253
254 public boolean prefaceSent() {
255 return true;
256 }
257
258
259
260
261
262
263
264 public void sendPrefaceIfNeeded(ChannelHandlerContext ctx) throws Exception {
265
266 }
267 }
268
269 private final class PrefaceDecoder extends BaseDecoder {
270 private ByteBuf clientPrefaceString;
271 private boolean prefaceSent;
272
273 PrefaceDecoder(ChannelHandlerContext ctx) throws Exception {
274 clientPrefaceString = clientPrefaceString(encoder.connection());
275
276
277 sendPrefaceIfNeeded(ctx);
278 }
279
280 @Override
281 public boolean prefaceSent() {
282 return prefaceSent;
283 }
284
285 @Override
286 public void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
287 try {
288 if (ctx.channel().isActive() && readClientPrefaceString(in) && verifyFirstFrameIsSettings(in)) {
289
290 byteDecoder = new FrameDecoder();
291 byteDecoder.decode(ctx, in, out);
292 }
293 } catch (Throwable e) {
294 if (byteDecoder != null) {
295
296 in.skipBytes(in.readableBytes());
297 }
298 onError(ctx, false, e);
299 }
300 }
301
302 @Override
303 public void channelActive(ChannelHandlerContext ctx) throws Exception {
304
305 sendPrefaceIfNeeded(ctx);
306 }
307
308 @Override
309 public void channelInactive(ChannelHandlerContext ctx) throws Exception {
310 cleanup();
311 super.channelInactive(ctx);
312 }
313
314
315
316
317 @Override
318 public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
319 cleanup();
320 }
321
322
323
324
325 private void cleanup() {
326 if (clientPrefaceString != null) {
327 clientPrefaceString.release();
328 clientPrefaceString = null;
329 }
330 }
331
332
333
334
335
336
337
338 private boolean readClientPrefaceString(ByteBuf in) throws Http2Exception {
339 if (clientPrefaceString == null) {
340 return true;
341 }
342
343 int prefaceRemaining = clientPrefaceString.readableBytes();
344 int bytesRead = min(in.readableBytes(), prefaceRemaining);
345
346
347 if (bytesRead == 0 || !ByteBufUtil.equals(in, in.readerIndex(),
348 clientPrefaceString, clientPrefaceString.readerIndex(),
349 bytesRead)) {
350 int maxSearch = 1024;
351 int http1Index =
352 ByteBufUtil.indexOf(HTTP_1_X_BUF, in.slice(in.readerIndex(), min(in.readableBytes(), maxSearch)));
353 if (http1Index != -1) {
354 String chunk = in.toString(in.readerIndex(), http1Index - in.readerIndex(), CharsetUtil.US_ASCII);
355 throw connectionError(PROTOCOL_ERROR, "Unexpected HTTP/1.x request: %s", chunk);
356 }
357 String receivedBytes = hexDump(in, in.readerIndex(),
358 min(in.readableBytes(), clientPrefaceString.readableBytes()));
359 throw connectionError(PROTOCOL_ERROR, "HTTP/2 client preface string missing or corrupt. " +
360 "Hex dump for received bytes: %s", receivedBytes);
361 }
362 in.skipBytes(bytesRead);
363 clientPrefaceString.skipBytes(bytesRead);
364
365 if (!clientPrefaceString.isReadable()) {
366
367 clientPrefaceString.release();
368 clientPrefaceString = null;
369 return true;
370 }
371 return false;
372 }
373
374
375
376
377
378
379
380
381
382 private boolean verifyFirstFrameIsSettings(ByteBuf in) throws Http2Exception {
383 if (in.readableBytes() < 5) {
384
385 return false;
386 }
387
388 short frameType = in.getUnsignedByte(in.readerIndex() + 3);
389 if (frameType != SETTINGS) {
390 throw connectionError(PROTOCOL_ERROR, "First received frame was not SETTINGS. " +
391 "Hex dump for first 5 bytes: %s",
392 hexDump(in, in.readerIndex(), 5));
393 }
394 short flags = in.getUnsignedByte(in.readerIndex() + 4);
395 if ((flags & Http2Flags.ACK) != 0) {
396 throw connectionError(PROTOCOL_ERROR, "First received frame was SETTINGS frame but had ACK flag set. " +
397 "Hex dump for first 5 bytes: %s",
398 hexDump(in, in.readerIndex(), 5));
399 }
400 return true;
401 }
402
403
404
405
406 @Override
407 public void sendPrefaceIfNeeded(ChannelHandlerContext ctx) throws Exception {
408 if (prefaceSent || !ctx.channel().isActive()) {
409 return;
410 }
411
412 prefaceSent = true;
413
414 final boolean isClient = !connection().isServer();
415 if (isClient) {
416
417 ctx.write(connectionPrefaceBuf()).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
418 }
419
420
421 encoder.writeSettings(ctx, initialSettings, ctx.newPromise()).addListener(
422 ChannelFutureListener.CLOSE_ON_FAILURE);
423
424 try {
425 if (isClient) {
426
427
428
429 userEventTriggered(ctx, Http2ConnectionPrefaceAndSettingsFrameWrittenEvent.INSTANCE);
430 }
431 } finally {
432 if (flushPreface) {
433
434
435
436 ctx.flush();
437 }
438 }
439 }
440 }
441
442 private final class FrameDecoder extends BaseDecoder {
443 @Override
444 public void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
445 try {
446 decoder.decodeFrame(ctx, in, out);
447 } catch (Throwable e) {
448 onError(ctx, false, e);
449 }
450 }
451 }
452
453 @Override
454 public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
455
456 encoder.lifecycleManager(this);
457 decoder.lifecycleManager(this);
458 encoder.flowController().channelHandlerContext(ctx);
459 decoder.flowController().channelHandlerContext(ctx);
460 byteDecoder = new PrefaceDecoder(ctx);
461 }
462
463 @Override
464 protected void handlerRemoved0(ChannelHandlerContext ctx) throws Exception {
465 if (byteDecoder != null) {
466 byteDecoder.handlerRemoved(ctx);
467 byteDecoder = null;
468 }
469 }
470
471 @Override
472 public void channelActive(ChannelHandlerContext ctx) throws Exception {
473 if (byteDecoder == null) {
474 byteDecoder = new PrefaceDecoder(ctx);
475 }
476 byteDecoder.channelActive(ctx);
477 super.channelActive(ctx);
478 }
479
480 @Override
481 public void channelInactive(ChannelHandlerContext ctx) throws Exception {
482
483 super.channelInactive(ctx);
484 if (byteDecoder != null) {
485 byteDecoder.channelInactive(ctx);
486 byteDecoder = null;
487 }
488 }
489
490 @Override
491 public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
492 try {
493
494
495
496 if (ctx.channel().isWritable() && hasPendingData()) {
497 flush(ctx);
498 }
499 encoder.flowController().channelWritabilityChanged();
500 } finally {
501 super.channelWritabilityChanged(ctx);
502 }
503 }
504
505 @Override
506 protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
507 byteDecoder.decode(ctx, in, out);
508 }
509
510 @Override
511 public void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception {
512
513
514
515 ctx.bind(localAddress, ctx.newPromise()).addListener(new PrefaceSendListener(ctx, promise));
516 }
517
518 @Override
519 public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress,
520 ChannelPromise promise) throws Exception {
521
522
523
524 ctx.connect(remoteAddress, localAddress, ctx.newPromise()).addListener(new PrefaceSendListener(ctx, promise));
525 }
526
527 @Override
528 public void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
529 ctx.disconnect(promise);
530 }
531
532 @Override
533 public void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
534 if (decoupleCloseAndGoAway) {
535 ctx.close(promise);
536 return;
537 }
538 promise = promise.unvoid();
539
540 if (!ctx.channel().isActive() || !prefaceSent()) {
541 ctx.close(promise);
542 return;
543 }
544
545
546
547
548
549
550 ChannelFuture f = connection().goAwaySent() ? ctx.write(EMPTY_BUFFER) : goAway(ctx, null, ctx.newPromise());
551 ctx.flush();
552 doGracefulShutdown(ctx, f, promise);
553 }
554
555 private ChannelFutureListener newClosingChannelFutureListener(
556 ChannelHandlerContext ctx, ChannelPromise promise) {
557 long gracefulShutdownTimeoutMillis = this.gracefulShutdownTimeoutMillis;
558 return gracefulShutdownTimeoutMillis < 0 ?
559 new ClosingChannelFutureListener(ctx, promise) :
560 new ClosingChannelFutureListener(ctx, promise, gracefulShutdownTimeoutMillis, MILLISECONDS);
561 }
562
563 private void doGracefulShutdown(ChannelHandlerContext ctx, ChannelFuture future, final ChannelPromise promise) {
564 final ChannelFutureListener listener = newClosingChannelFutureListener(ctx, promise);
565 if (isGracefulShutdownComplete()) {
566
567
568 future.addListener(listener);
569 } else {
570
571
572
573
574 if (closeListener == null) {
575 closeListener = listener;
576 } else if (promise != null) {
577 final ChannelFutureListener oldCloseListener = closeListener;
578 closeListener = new ChannelFutureListener() {
579 @Override
580 public void operationComplete(ChannelFuture future) throws Exception {
581 try {
582 oldCloseListener.operationComplete(future);
583 } finally {
584 listener.operationComplete(future);
585 }
586 }
587 };
588 }
589 }
590 }
591
592 @Override
593 public void deregister(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
594 ctx.deregister(promise);
595 }
596
597 @Override
598 public void read(ChannelHandlerContext ctx) throws Exception {
599 ctx.read();
600 }
601
602 @Override
603 public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
604 ctx.write(msg, promise);
605 }
606
607 @Override
608 public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
609
610
611 try {
612
613 channelReadComplete0(ctx);
614 } finally {
615 flush(ctx);
616 }
617 }
618
619 final void channelReadComplete0(ChannelHandlerContext ctx) {
620
621 discardSomeReadBytes();
622
623
624
625
626 if (!ctx.channel().config().isAutoRead()) {
627 ctx.read();
628 }
629
630 ctx.fireChannelReadComplete();
631 }
632
633
634
635
636 @Override
637 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
638 if (getEmbeddedHttp2Exception(cause) != null) {
639
640 onError(ctx, false, cause);
641 } else {
642 super.exceptionCaught(ctx, cause);
643 }
644 }
645
646
647
648
649
650
651
652
653 @Override
654 public void closeStreamLocal(Http2Stream stream, ChannelFuture future) {
655 switch (stream.state()) {
656 case HALF_CLOSED_LOCAL:
657 case OPEN:
658 stream.closeLocalSide();
659 break;
660 default:
661 closeStream(stream, future);
662 break;
663 }
664 }
665
666
667
668
669
670
671
672
673 @Override
674 public void closeStreamRemote(Http2Stream stream, ChannelFuture future) {
675 switch (stream.state()) {
676 case HALF_CLOSED_REMOTE:
677 case OPEN:
678 stream.closeRemoteSide();
679 break;
680 default:
681 closeStream(stream, future);
682 break;
683 }
684 }
685
686 @Override
687 public void closeStream(final Http2Stream stream, ChannelFuture future) {
688 if (future.isDone()) {
689 doCloseStream(stream, future);
690 } else {
691 future.addListener(new ChannelFutureListener() {
692 @Override
693 public void operationComplete(ChannelFuture future) {
694 doCloseStream(stream, future);
695 }
696 });
697 }
698 }
699
700
701
702
703 @Override
704 public void onError(ChannelHandlerContext ctx, boolean outbound, Throwable cause) {
705 Http2Exception embedded = getEmbeddedHttp2Exception(cause);
706 if (isStreamError(embedded)) {
707 onStreamError(ctx, outbound, cause, (StreamException) embedded);
708 } else if (embedded instanceof CompositeStreamException) {
709 CompositeStreamException compositException = (CompositeStreamException) embedded;
710 for (StreamException streamException : compositException) {
711 onStreamError(ctx, outbound, cause, streamException);
712 }
713 } else {
714 onConnectionError(ctx, outbound, cause, embedded);
715 }
716 ctx.flush();
717 }
718
719
720
721
722
723
724 protected boolean isGracefulShutdownComplete() {
725 return connection().numActiveStreams() == 0;
726 }
727
728
729
730
731
732
733
734
735
736
737
738 protected void onConnectionError(ChannelHandlerContext ctx, boolean outbound,
739 Throwable cause, Http2Exception http2Ex) {
740 if (http2Ex == null) {
741 http2Ex = new Http2Exception(INTERNAL_ERROR, cause.getMessage(), cause);
742 }
743
744 ChannelPromise promise = ctx.newPromise();
745 ChannelFuture future = goAway(ctx, http2Ex, ctx.newPromise());
746 if (http2Ex.shutdownHint() == Http2Exception.ShutdownHint.GRACEFUL_SHUTDOWN) {
747 doGracefulShutdown(ctx, future, promise);
748 } else {
749 future.addListener(newClosingChannelFutureListener(ctx, promise));
750 }
751 }
752
753
754
755
756
757
758
759
760
761
762 protected void onStreamError(ChannelHandlerContext ctx, boolean outbound,
763 @SuppressWarnings("unused") Throwable cause, StreamException http2Ex) {
764 final int streamId = http2Ex.streamId();
765 Http2Stream stream = connection().stream(streamId);
766
767
768 if (http2Ex instanceof Http2Exception.HeaderListSizeException &&
769 ((Http2Exception.HeaderListSizeException) http2Ex).duringDecode() &&
770 connection().isServer()) {
771
772
773
774
775
776
777
778 if (stream == null) {
779 try {
780 stream = encoder.connection().remote().createStream(streamId, true);
781 } catch (Http2Exception e) {
782 encoder().writeRstStream(ctx, streamId, http2Ex.error().code(), ctx.newPromise());
783 return;
784 }
785 }
786
787
788 if (stream != null && !stream.isHeadersSent()) {
789 try {
790 handleServerHeaderDecodeSizeError(ctx, stream);
791 } catch (Throwable cause2) {
792 onError(ctx, outbound, connectionError(INTERNAL_ERROR, cause2, "Error DecodeSizeError"));
793 }
794 }
795 }
796
797 if (stream == null) {
798 if (!outbound || connection().local().mayHaveCreatedStream(streamId)) {
799 encoder().writeRstStream(ctx, streamId, http2Ex.error().code(), ctx.newPromise());
800 }
801 } else {
802 encoder().writeRstStream(ctx, streamId, http2Ex.error().code(), ctx.newPromise());
803 }
804 }
805
806
807
808
809
810
811
812
813 protected void handleServerHeaderDecodeSizeError(ChannelHandlerContext ctx, Http2Stream stream) {
814 encoder().writeHeaders(ctx, stream.id(), HEADERS_TOO_LARGE_HEADERS, 0, true, ctx.newPromise());
815 }
816
817 protected Http2FrameWriter frameWriter() {
818 return encoder().frameWriter();
819 }
820
821
822
823
824
825
826 private ChannelFuture resetUnknownStream(final ChannelHandlerContext ctx, int streamId, long errorCode,
827 ChannelPromise promise) {
828 ChannelFuture future = frameWriter().writeRstStream(ctx, streamId, errorCode, promise);
829 if (future.isDone()) {
830 closeConnectionOnError(ctx, future);
831 } else {
832 future.addListener(new ChannelFutureListener() {
833 @Override
834 public void operationComplete(ChannelFuture future) throws Exception {
835 closeConnectionOnError(ctx, future);
836 }
837 });
838 }
839 return future;
840 }
841
842 @Override
843 public ChannelFuture resetStream(final ChannelHandlerContext ctx, int streamId, long errorCode,
844 ChannelPromise promise) {
845 final Http2Stream stream = connection().stream(streamId);
846 if (stream == null) {
847 return resetUnknownStream(ctx, streamId, errorCode, promise.unvoid());
848 }
849
850 return resetStream(ctx, stream, errorCode, promise);
851 }
852
853 private ChannelFuture resetStream(final ChannelHandlerContext ctx, final Http2Stream stream,
854 long errorCode, ChannelPromise promise) {
855 promise = promise.unvoid();
856 if (stream.isResetSent()) {
857
858 return promise.setSuccess();
859 }
860
861
862
863
864
865 stream.resetSent();
866
867 final ChannelFuture future;
868
869
870 if (stream.state() == IDLE ||
871 connection().local().created(stream) && !stream.isHeadersSent() && !stream.isPushPromiseSent()) {
872 future = promise.setSuccess();
873 } else {
874 future = frameWriter().writeRstStream(ctx, stream.id(), errorCode, promise);
875 }
876 if (future.isDone()) {
877 processRstStreamWriteResult(ctx, stream, future);
878 } else {
879 future.addListener(new ChannelFutureListener() {
880 @Override
881 public void operationComplete(ChannelFuture future) throws Exception {
882 processRstStreamWriteResult(ctx, stream, future);
883 }
884 });
885 }
886
887 return future;
888 }
889
890 @Override
891 public ChannelFuture goAway(final ChannelHandlerContext ctx, final int lastStreamId, final long errorCode,
892 final ByteBuf debugData, ChannelPromise promise) {
893 promise = promise.unvoid();
894 final Http2Connection connection = connection();
895 try {
896 if (!connection.goAwaySent(lastStreamId, errorCode, debugData)) {
897 debugData.release();
898 promise.trySuccess();
899 return promise;
900 }
901 } catch (Throwable cause) {
902 debugData.release();
903 promise.tryFailure(cause);
904 return promise;
905 }
906
907
908
909 debugData.retain();
910 ChannelFuture future = frameWriter().writeGoAway(ctx, lastStreamId, errorCode, debugData, promise);
911
912 if (future.isDone()) {
913 processGoAwayWriteResult(ctx, lastStreamId, errorCode, debugData, future);
914 } else {
915 future.addListener(new ChannelFutureListener() {
916 @Override
917 public void operationComplete(ChannelFuture future) throws Exception {
918 processGoAwayWriteResult(ctx, lastStreamId, errorCode, debugData, future);
919 }
920 });
921 }
922
923 return future;
924 }
925
926
927
928
929
930 private void checkCloseConnection(ChannelFuture future) {
931
932
933 if (closeListener != null && isGracefulShutdownComplete()) {
934 ChannelFutureListener closeListener = this.closeListener;
935
936
937 this.closeListener = null;
938 try {
939 closeListener.operationComplete(future);
940 } catch (Exception e) {
941 throw new IllegalStateException("Close listener threw an unexpected exception", e);
942 }
943 }
944 }
945
946
947
948
949
950 private ChannelFuture goAway(ChannelHandlerContext ctx, Http2Exception cause, ChannelPromise promise) {
951 long errorCode = cause != null ? cause.error().code() : NO_ERROR.code();
952 int lastKnownStream;
953 if (cause != null && cause.shutdownHint() == Http2Exception.ShutdownHint.HARD_SHUTDOWN) {
954
955
956
957
958 lastKnownStream = Integer.MAX_VALUE;
959 } else {
960 lastKnownStream = connection().remote().lastStreamCreated();
961 }
962 return goAway(ctx, lastKnownStream, errorCode, Http2CodecUtil.toByteBuf(ctx, cause), promise);
963 }
964
965 private void processRstStreamWriteResult(ChannelHandlerContext ctx, Http2Stream stream, ChannelFuture future) {
966 if (future.isSuccess()) {
967 closeStream(stream, future);
968 } else {
969
970 onConnectionError(ctx, true, future.cause(), null);
971 }
972 }
973
974 private void closeConnectionOnError(ChannelHandlerContext ctx, ChannelFuture future) {
975 if (!future.isSuccess()) {
976 onConnectionError(ctx, true, future.cause(), null);
977 }
978 }
979
980 private void doCloseStream(final Http2Stream stream, ChannelFuture future) {
981 stream.close();
982 checkCloseConnection(future);
983 }
984
985
986
987
988 private static ByteBuf clientPrefaceString(Http2Connection connection) {
989 return connection.isServer() ? connectionPrefaceBuf() : null;
990 }
991
992 private static void processGoAwayWriteResult(final ChannelHandlerContext ctx, final int lastStreamId,
993 final long errorCode, final ByteBuf debugData, ChannelFuture future) {
994 try {
995 if (future.isSuccess()) {
996 if (errorCode != NO_ERROR.code()) {
997 if (logger.isDebugEnabled()) {
998 logger.debug("{} Sent GOAWAY: lastStreamId '{}', errorCode '{}', " +
999 "debugData '{}'. Forcing shutdown of the connection.",
1000 ctx.channel(), lastStreamId, errorCode, debugData.toString(UTF_8));
1001 }
1002 ctx.close();
1003 }
1004 } else {
1005 if (logger.isDebugEnabled()) {
1006 logger.debug("{} Sending GOAWAY failed: lastStreamId '{}', errorCode '{}', " +
1007 "debugData '{}'. Forcing shutdown of the connection.",
1008 ctx.channel(), lastStreamId, errorCode, debugData.toString(UTF_8), future.cause());
1009 }
1010 ctx.close();
1011 }
1012 } finally {
1013
1014 debugData.release();
1015 }
1016 }
1017
1018
1019
1020
1021 private static final class ClosingChannelFutureListener implements ChannelFutureListener {
1022 private final ChannelHandlerContext ctx;
1023 private final ChannelPromise promise;
1024 private final Future<?> timeoutTask;
1025 private boolean closed;
1026
1027 ClosingChannelFutureListener(ChannelHandlerContext ctx, ChannelPromise promise) {
1028 this.ctx = ctx;
1029 this.promise = promise;
1030 timeoutTask = null;
1031 }
1032
1033 ClosingChannelFutureListener(final ChannelHandlerContext ctx, final ChannelPromise promise,
1034 long timeout, TimeUnit unit) {
1035 this.ctx = ctx;
1036 this.promise = promise;
1037 timeoutTask = ctx.executor().schedule(new Runnable() {
1038 @Override
1039 public void run() {
1040 doClose();
1041 }
1042 }, timeout, unit);
1043 }
1044
1045 @Override
1046 public void operationComplete(ChannelFuture sentGoAwayFuture) {
1047 if (timeoutTask != null) {
1048 timeoutTask.cancel(false);
1049 }
1050 doClose();
1051 }
1052
1053 private void doClose() {
1054
1055
1056 if (closed) {
1057
1058 assert timeoutTask != null;
1059 return;
1060 }
1061 closed = true;
1062 if (promise == null) {
1063 ctx.close();
1064 } else {
1065 ctx.close(promise);
1066 }
1067 }
1068 }
1069
1070 private final class PrefaceSendListener implements ChannelFutureListener {
1071 private final ChannelHandlerContext ctx;
1072 private final ChannelPromise promise;
1073
1074 PrefaceSendListener(ChannelHandlerContext ctx, ChannelPromise promise) {
1075 this.ctx = ctx;
1076 this.promise = promise;
1077 }
1078
1079 @Override
1080 public void operationComplete(ChannelFuture f) {
1081 if (f.isSuccess()) {
1082 try {
1083 if (byteDecoder != null) {
1084 byteDecoder.sendPrefaceIfNeeded(ctx);
1085 }
1086 } catch (Throwable e) {
1087 promise.setFailure(e);
1088 return;
1089 }
1090 promise.setSuccess();
1091 } else {
1092 promise.setFailure(f.cause());
1093 }
1094 }
1095 }
1096 }