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  
23  import static io.netty.handler.codec.http2.Http2Error.COMPRESSION_ERROR;
24  import static io.netty.handler.codec.http2.Http2Exception.connectionError;
25  import static io.netty.util.internal.ObjectUtil.checkNotNull;
26  
27  public class DefaultHttp2HeadersEncoder implements
28      Http2HeadersEncoder, Http2HeadersEncoder.Configuration, Closeable {
29  
30      private final HpackEncoder hpackEncoder;
31      private final SensitivityDetector sensitivityDetector;
32      private ByteBuf tableSizeChangeOutput;
33  
34      public DefaultHttp2HeadersEncoder() {
35          this(NEVER_SENSITIVE);
36      }
37  
38      public DefaultHttp2HeadersEncoder(SensitivityDetector sensitivityDetector) {
39          this(sensitivityDetector, new HpackEncoder());
40      }
41  
42      public DefaultHttp2HeadersEncoder(SensitivityDetector sensitivityDetector, boolean ignoreMaxHeaderListSize) {
43          this(sensitivityDetector, new HpackEncoder(ignoreMaxHeaderListSize));
44      }
45  
46      public DefaultHttp2HeadersEncoder(SensitivityDetector sensitivityDetector, boolean ignoreMaxHeaderListSize,
47                                        int dynamicTableArraySizeHint) {
48          this(sensitivityDetector, ignoreMaxHeaderListSize, dynamicTableArraySizeHint, HpackEncoder.HUFF_CODE_THRESHOLD);
49      }
50  
51      public DefaultHttp2HeadersEncoder(SensitivityDetector sensitivityDetector, boolean ignoreMaxHeaderListSize,
52                                        int dynamicTableArraySizeHint, int huffCodeThreshold) {
53          this(sensitivityDetector,
54                  new HpackEncoder(ignoreMaxHeaderListSize, dynamicTableArraySizeHint, huffCodeThreshold));
55      }
56  
57      /**
58       * Exposed Used for testing only! Default values used in the initial settings frame are overridden intentionally
59       * for testing but violate the RFC if used outside the scope of testing.
60       */
61      DefaultHttp2HeadersEncoder(SensitivityDetector sensitivityDetector, HpackEncoder hpackEncoder) {
62          this.sensitivityDetector = checkNotNull(sensitivityDetector, "sensitiveDetector");
63          this.hpackEncoder = checkNotNull(hpackEncoder, "hpackEncoder");
64      }
65  
66      @Override
67      public void encodeHeaders(int streamId, Http2Headers headers, ByteBuf buffer) throws Http2Exception {
68          try {
69              // If there was a change in the table size, serialize the output from the hpackEncoder
70              // resulting from that change.
71              if (tableSizeChangeOutput != null && tableSizeChangeOutput.isReadable()) {
72                  buffer.writeBytes(tableSizeChangeOutput);
73                  tableSizeChangeOutput.clear();
74              }
75  
76              hpackEncoder.encodeHeaders(streamId, buffer, headers, sensitivityDetector);
77          } catch (Http2Exception e) {
78              throw e;
79          } catch (Throwable t) {
80              throw connectionError(COMPRESSION_ERROR, t, "Failed encoding headers block: %s", t.getMessage());
81          }
82      }
83  
84      @Override
85      public void maxHeaderTableSize(long max) throws Http2Exception {
86          if (tableSizeChangeOutput == null) {
87              tableSizeChangeOutput = Unpooled.buffer();
88          }
89          hpackEncoder.setMaxHeaderTableSize(tableSizeChangeOutput, max);
90      }
91  
92      @Override
93      public long maxHeaderTableSize() {
94          return hpackEncoder.getMaxHeaderTableSize();
95      }
96  
97      @Override
98      public void maxHeaderListSize(long max) throws Http2Exception {
99          hpackEncoder.setMaxHeaderListSize(max);
100     }
101 
102     @Override
103     public long maxHeaderListSize() {
104         return hpackEncoder.getMaxHeaderListSize();
105     }
106 
107     @Override
108     public Configuration configuration() {
109         return this;
110     }
111 
112     /**
113      * Close the encoder and release all its associated data.
114      */
115     @Override
116     public void close() {
117         if (tableSizeChangeOutput != null) {
118             tableSizeChangeOutput.release();
119             tableSizeChangeOutput = null;
120         }
121     }
122 }