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.channel.ChannelFuture;
18 import io.netty.channel.ChannelHandlerContext;
19 import io.netty.channel.ChannelPromise;
20 import io.netty.util.internal.logging.InternalLogger;
21 import io.netty.util.internal.logging.InternalLoggerFactory;
22
23 import java.util.concurrent.TimeUnit;
24
25
26
27
28
29
30 final class Http2MaxRstFrameLimitEncoder extends DecoratingHttp2ConnectionEncoder {
31 private static final InternalLogger logger = InternalLoggerFactory.getInstance(Http2MaxRstFrameLimitEncoder.class);
32
33 private final long nanosPerWindow;
34 private final int maxRstFramesPerWindow;
35 private long lastRstFrameNano = System.nanoTime();
36 private int sendRstInWindow;
37 private Http2LifecycleManager lifecycleManager;
38
39 Http2MaxRstFrameLimitEncoder(Http2ConnectionEncoder delegate, int maxRstFramesPerWindow, int secondsPerWindow) {
40 super(delegate);
41 this.maxRstFramesPerWindow = maxRstFramesPerWindow;
42 this.nanosPerWindow = TimeUnit.SECONDS.toNanos(secondsPerWindow);
43 }
44
45 @Override
46 public void lifecycleManager(Http2LifecycleManager lifecycleManager) {
47 this.lifecycleManager = lifecycleManager;
48 super.lifecycleManager(lifecycleManager);
49 }
50
51 @Override
52 public ChannelFuture writeRstStream(ChannelHandlerContext ctx, int streamId, long errorCode,
53 ChannelPromise promise) {
54 ChannelFuture future = super.writeRstStream(ctx, streamId, errorCode, promise);
55 if (countRstFrameErrorCode(errorCode)) {
56 long currentNano = System.nanoTime();
57 if (currentNano - lastRstFrameNano >= nanosPerWindow) {
58 lastRstFrameNano = currentNano;
59 sendRstInWindow = 1;
60 } else {
61 sendRstInWindow++;
62 if (sendRstInWindow > maxRstFramesPerWindow) {
63 Http2Exception exception = Http2Exception.connectionError(Http2Error.ENHANCE_YOUR_CALM,
64 "Maximum number %d of RST frames frames reached within %d seconds", maxRstFramesPerWindow,
65 TimeUnit.NANOSECONDS.toSeconds(nanosPerWindow));
66
67 logger.debug("{} Maximum number {} of RST frames reached within {} seconds, " +
68 "closing connection with {} error", ctx.channel(), maxRstFramesPerWindow,
69 TimeUnit.NANOSECONDS.toSeconds(nanosPerWindow), exception.error(),
70 exception);
71
72 lifecycleManager.onError(ctx, true, exception);
73 ctx.close();
74 }
75 }
76 }
77
78 return future;
79 }
80
81 private boolean countRstFrameErrorCode(long errorCode) {
82
83 return errorCode != Http2Error.CANCEL.code() && errorCode != Http2Error.NO_ERROR.code();
84 }
85 }