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.ByteBuf;
19 import io.netty.util.internal.ObjectUtil;
20 import io.netty.util.internal.UnstableApi;
21
22 import static io.netty.handler.codec.http2.Http2CodecUtil.DEFAULT_HEADER_LIST_SIZE;
23 import static io.netty.handler.codec.http2.Http2Error.COMPRESSION_ERROR;
24 import static io.netty.handler.codec.http2.Http2Error.INTERNAL_ERROR;
25 import static io.netty.handler.codec.http2.Http2Exception.connectionError;
26
27 @UnstableApi
28 public class DefaultHttp2HeadersDecoder implements Http2HeadersDecoder, Http2HeadersDecoder.Configuration {
29 private static final float HEADERS_COUNT_WEIGHT_NEW = 1 / 5f;
30 private static final float HEADERS_COUNT_WEIGHT_HISTORICAL = 1 - HEADERS_COUNT_WEIGHT_NEW;
31
32 private final HpackDecoder hpackDecoder;
33 private final boolean validateHeaders;
34 private long maxHeaderListSizeGoAway;
35
36
37
38
39
40 private float headerArraySizeAccumulator = 8;
41
42 public DefaultHttp2HeadersDecoder() {
43 this(true);
44 }
45
46 public DefaultHttp2HeadersDecoder(boolean validateHeaders) {
47 this(validateHeaders, DEFAULT_HEADER_LIST_SIZE);
48 }
49
50
51
52
53
54
55
56
57
58 public DefaultHttp2HeadersDecoder(boolean validateHeaders, long maxHeaderListSize) {
59 this(validateHeaders, maxHeaderListSize, -1);
60 }
61
62
63
64
65
66
67
68
69
70
71 public DefaultHttp2HeadersDecoder(boolean validateHeaders, long maxHeaderListSize,
72 @Deprecated int initialHuffmanDecodeCapacity) {
73 this(validateHeaders, new HpackDecoder(maxHeaderListSize));
74 }
75
76
77
78
79
80 DefaultHttp2HeadersDecoder(boolean validateHeaders, HpackDecoder hpackDecoder) {
81 this.hpackDecoder = ObjectUtil.checkNotNull(hpackDecoder, "hpackDecoder");
82 this.validateHeaders = validateHeaders;
83 maxHeaderListSizeGoAway =
84 Http2CodecUtil.calculateMaxHeaderListSizeGoAway(hpackDecoder.getMaxHeaderListSize());
85 }
86
87 @Override
88 public void maxHeaderTableSize(long max) throws Http2Exception {
89 hpackDecoder.setMaxHeaderTableSize(max);
90 }
91
92 @Override
93 public long maxHeaderTableSize() {
94 return hpackDecoder.getMaxHeaderTableSize();
95 }
96
97 @Override
98 public void maxHeaderListSize(long max, long goAwayMax) throws Http2Exception {
99 if (goAwayMax < max || goAwayMax < 0) {
100 throw connectionError(INTERNAL_ERROR, "Header List Size GO_AWAY %d must be non-negative and >= %d",
101 goAwayMax, max);
102 }
103 hpackDecoder.setMaxHeaderListSize(max);
104 maxHeaderListSizeGoAway = goAwayMax;
105 }
106
107 @Override
108 public long maxHeaderListSize() {
109 return hpackDecoder.getMaxHeaderListSize();
110 }
111
112 @Override
113 public long maxHeaderListSizeGoAway() {
114 return maxHeaderListSizeGoAway;
115 }
116
117 @Override
118 public Configuration configuration() {
119 return this;
120 }
121
122 @Override
123 public Http2Headers decodeHeaders(int streamId, ByteBuf headerBlock) throws Http2Exception {
124 try {
125 final Http2Headers headers = newHeaders();
126 hpackDecoder.decode(streamId, headerBlock, headers, validateHeaders);
127 headerArraySizeAccumulator = HEADERS_COUNT_WEIGHT_NEW * headers.size() +
128 HEADERS_COUNT_WEIGHT_HISTORICAL * headerArraySizeAccumulator;
129 return headers;
130 } catch (Http2Exception e) {
131 throw e;
132 } catch (Throwable e) {
133
134
135
136 throw connectionError(COMPRESSION_ERROR, e, "Error decoding headers: %s", e.getMessage());
137 }
138 }
139
140
141
142
143
144 protected final int numberOfHeadersGuess() {
145 return (int) headerArraySizeAccumulator;
146 }
147
148
149
150
151
152 protected final boolean validateHeaders() {
153 return validateHeaders;
154 }
155
156
157
158
159
160 protected Http2Headers newHeaders() {
161 return new DefaultHttp2Headers(validateHeaders, (int) headerArraySizeAccumulator);
162 }
163 }