View Javadoc
1   /*
2    * Copyright 2014 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License, version 2.0 (the
5    * "License"); you may not use this file except in compliance with the License. You may obtain a
6    * copy of the License at:
7    *
8    * https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software distributed under the License
11   * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12   * or implied. See the License for the specific language governing permissions and limitations under
13   * the License.
14   */
15  
16  package io.netty.handler.codec.http2;
17  
18  import java.io.Closeable;
19  
20  import io.netty.buffer.ByteBuf;
21  import io.netty.buffer.Unpooled;
22  import io.netty.util.internal.UnstableApi;
23  
24  import static io.netty.handler.codec.http2.Http2Error.COMPRESSION_ERROR;
25  import static io.netty.handler.codec.http2.Http2Exception.connectionError;
26  import static io.netty.util.internal.ObjectUtil.checkNotNull;
27  
28  @UnstableApi
29  public class DefaultHttp2HeadersEncoder implements
30      Http2HeadersEncoder, Http2HeadersEncoder.Configuration, Closeable {
31  
32      private final HpackEncoder hpackEncoder;
33      private final SensitivityDetector sensitivityDetector;
34      private ByteBuf tableSizeChangeOutput;
35  
36      public DefaultHttp2HeadersEncoder() {
37          this(NEVER_SENSITIVE);
38      }
39  
40      public DefaultHttp2HeadersEncoder(SensitivityDetector sensitivityDetector) {
41          this(sensitivityDetector, new HpackEncoder());
42      }
43  
44      public DefaultHttp2HeadersEncoder(SensitivityDetector sensitivityDetector, boolean ignoreMaxHeaderListSize) {
45          this(sensitivityDetector, new HpackEncoder(ignoreMaxHeaderListSize));
46      }
47  
48      public DefaultHttp2HeadersEncoder(SensitivityDetector sensitivityDetector, boolean ignoreMaxHeaderListSize,
49                                        int dynamicTableArraySizeHint) {
50          this(sensitivityDetector, ignoreMaxHeaderListSize, dynamicTableArraySizeHint, HpackEncoder.HUFF_CODE_THRESHOLD);
51      }
52  
53      public DefaultHttp2HeadersEncoder(SensitivityDetector sensitivityDetector, boolean ignoreMaxHeaderListSize,
54                                        int dynamicTableArraySizeHint, int huffCodeThreshold) {
55          this(sensitivityDetector,
56                  new HpackEncoder(ignoreMaxHeaderListSize, dynamicTableArraySizeHint, huffCodeThreshold));
57      }
58  
59      /**
60       * Exposed Used for testing only! Default values used in the initial settings frame are overridden intentionally
61       * for testing but violate the RFC if used outside the scope of testing.
62       */
63      DefaultHttp2HeadersEncoder(SensitivityDetector sensitivityDetector, HpackEncoder hpackEncoder) {
64          this.sensitivityDetector = checkNotNull(sensitivityDetector, "sensitiveDetector");
65          this.hpackEncoder = checkNotNull(hpackEncoder, "hpackEncoder");
66      }
67  
68      @Override
69      public void encodeHeaders(int streamId, Http2Headers headers, ByteBuf buffer) throws Http2Exception {
70          try {
71              // If there was a change in the table size, serialize the output from the hpackEncoder
72              // resulting from that change.
73              if (tableSizeChangeOutput != null && tableSizeChangeOutput.isReadable()) {
74                  buffer.writeBytes(tableSizeChangeOutput);
75                  tableSizeChangeOutput.clear();
76              }
77  
78              hpackEncoder.encodeHeaders(streamId, buffer, headers, sensitivityDetector);
79          } catch (Http2Exception e) {
80              throw e;
81          } catch (Throwable t) {
82              throw connectionError(COMPRESSION_ERROR, t, "Failed encoding headers block: %s", t.getMessage());
83          }
84      }
85  
86      @Override
87      public void maxHeaderTableSize(long max) throws Http2Exception {
88          if (tableSizeChangeOutput == null) {
89              tableSizeChangeOutput = Unpooled.buffer();
90          }
91          hpackEncoder.setMaxHeaderTableSize(tableSizeChangeOutput, max);
92      }
93  
94      @Override
95      public long maxHeaderTableSize() {
96          return hpackEncoder.getMaxHeaderTableSize();
97      }
98  
99      @Override
100     public void maxHeaderListSize(long max) throws Http2Exception {
101         hpackEncoder.setMaxHeaderListSize(max);
102     }
103 
104     @Override
105     public long maxHeaderListSize() {
106         return hpackEncoder.getMaxHeaderListSize();
107     }
108 
109     @Override
110     public Configuration configuration() {
111         return this;
112     }
113 
114     /**
115      * Close the encoder and release all its associated data.
116      */
117     @Override
118     public void close() {
119         if (tableSizeChangeOutput != null) {
120             tableSizeChangeOutput.release();
121             tableSizeChangeOutput = null;
122         }
123     }
124 }